mirror of
https://github.com/StuffAnThings/qbit_manage.git
synced 2025-10-09 21:36:52 +08:00
feat(config): add --config-dir argument for directory-based config discovery
Add support for specifying a configuration directory using the new --config-dir argument. When provided, this option takes precedence over --config-file and automatically discovers all .yml and .yaml files in the specified directory (excluding schedule.yml). Falls back to legacy --config-file behavior when not specified, maintaining backward compatibility.
This commit is contained in:
parent
19aa766094
commit
f393414599
4 changed files with 78 additions and 30 deletions
2
VERSION
2
VERSION
|
@ -1 +1 @@
|
|||
4.5.6-develop9
|
||||
4.5.6-develop10
|
||||
|
|
|
@ -130,7 +130,11 @@ class Config:
|
|||
logger.debug(f" --run (QBT_RUN): {self.args['run']}")
|
||||
logger.debug(f" --schedule (QBT_SCHEDULE): {self.args['sch']}")
|
||||
logger.debug(f" --startup-delay (QBT_STARTUP_DELAY): {self.args['startupDelay']}")
|
||||
logger.debug(f" --config-file (QBT_CONFIG): {self.args['config_files']}")
|
||||
logger.debug(f" --config-dir (QBT_CONFIG_DIR): {self.args['config_dir_args']}")
|
||||
if self.args["config_dir_args"] is None:
|
||||
logger.debug(f" --config-file (QBT_CONFIG): {self.args['config_files']} (legacy)")
|
||||
else:
|
||||
logger.debug(f" Configs found from QBT_CONFIG_DIR: {self.args['config_files']}")
|
||||
logger.debug(f" --log-file (QBT_LOGFILE): {self.args['log_file']}")
|
||||
logger.debug(f" --log-level (QBT_LOG_LEVEL): {self.args['log_level']}")
|
||||
logger.debug(f" --log-size (QBT_LOG_SIZE): {self.args['log_size']}")
|
||||
|
|
|
@ -243,25 +243,31 @@ def _platform_config_base() -> Path:
|
|||
return base / "qbit-manage"
|
||||
|
||||
|
||||
def get_default_config_dir(config_hint: str = None) -> str:
|
||||
def get_default_config_dir(config_hint: str = None, config_dir: str = None) -> str:
|
||||
"""
|
||||
Determine the default persistent config directory, leveraging a provided config path/pattern first.
|
||||
|
||||
Resolution order:
|
||||
1) If config_hint is an absolute path or contains a directory component, use its parent directory
|
||||
2) Otherwise, if config_hint is a name/pattern (e.g. 'config.yml'), search common bases for:
|
||||
- A direct match to that filename/pattern
|
||||
- OR a persisted scheduler file 'schedule.yml' (so we don't lose an existing schedule when config.yml is absent)
|
||||
Common bases (in order):
|
||||
- /config (container volume)
|
||||
- repository ./config
|
||||
- user OS config directory
|
||||
Return the first base containing either.
|
||||
3) Fallback to legacy-ish behavior:
|
||||
- /config if it contains any *.yml.sample / *.yaml.sample
|
||||
- otherwise user OS config directory
|
||||
1) If config_dir is provided, use it directly (takes precedence over config_hint)
|
||||
2) If config_hint is an absolute path or contains a directory component, use its parent directory
|
||||
3) Otherwise, if config_hint is a name/pattern (e.g. 'config.yml'), search common bases for:
|
||||
- A direct match to that filename/pattern
|
||||
- OR a persisted scheduler file 'schedule.yml' (so we don't lose an existing schedule when config.yml is absent)
|
||||
Common bases (in order):
|
||||
- /config (container volume)
|
||||
- repository ./config
|
||||
- user OS config directory
|
||||
Return the first base containing either.
|
||||
4) Fallback to legacy-ish behavior:
|
||||
- /config if it contains any *.yml.sample / *.yaml.sample
|
||||
- otherwise user OS config directory
|
||||
"""
|
||||
# 1) If a direct path is provided, prefer its parent directory
|
||||
# 1) If config_dir is provided, use it directly (takes precedence)
|
||||
if config_dir:
|
||||
p = Path(config_dir).expanduser()
|
||||
return str(p.resolve())
|
||||
|
||||
# 2) If a direct path is provided, prefer its parent directory
|
||||
if config_hint:
|
||||
primary = str(config_hint).split(",")[0].strip() # take first if comma-separated
|
||||
if primary:
|
||||
|
@ -1470,12 +1476,14 @@ class EnvStr(str):
|
|||
return super().__repr__()
|
||||
|
||||
|
||||
def get_matching_config_files(config_pattern: str, default_dir: str) -> list:
|
||||
def get_matching_config_files(config_pattern: str, default_dir: str, use_config_dir_mode: bool = False) -> list:
|
||||
"""Get list of config files matching a pattern.
|
||||
|
||||
Args:
|
||||
config_pattern (str): Config file pattern (e.g. "config.yml" or "config*.yml")
|
||||
default_dir (str): Default directory to look for configs
|
||||
use_config_dir_mode (bool): If True, use new config-dir approach (find all .yml/.yaml files)
|
||||
If False, use legacy config-file approach (pattern matching)
|
||||
|
||||
Returns:
|
||||
list: List of matching config file names
|
||||
|
@ -1489,16 +1497,39 @@ def get_matching_config_files(config_pattern: str, default_dir: str) -> list:
|
|||
else:
|
||||
search_dir = default_dir
|
||||
|
||||
# Handle single file vs pattern
|
||||
if "*" not in config_pattern:
|
||||
return [config_pattern]
|
||||
else:
|
||||
glob_configs = glob.glob(os.path.join(search_dir, config_pattern))
|
||||
if glob_configs:
|
||||
# Return just the filenames without paths
|
||||
return [os.path.split(x)[-1] for x in glob_configs]
|
||||
if use_config_dir_mode:
|
||||
# New --config-dir approach: find all .yml and .yaml files, excluding reserved files
|
||||
config_files = []
|
||||
for pattern in ["*.yml", "*.yaml"]:
|
||||
glob_configs = glob.glob(os.path.join(search_dir, pattern))
|
||||
for config_file in glob_configs:
|
||||
filename = os.path.basename(config_file)
|
||||
# Exclude reserved files
|
||||
if filename != "schedule.yml":
|
||||
config_files.append(filename)
|
||||
|
||||
if config_files:
|
||||
# Return just the filenames without paths, sorted for consistency
|
||||
return sorted(config_files)
|
||||
else:
|
||||
raise Failed(f"Config Error: Unable to find any config files in the pattern '{config_pattern}'")
|
||||
raise Failed(f"Config Error: Unable to find any config files in '{search_dir}'")
|
||||
else:
|
||||
# Legacy --config-file approach: pattern matching
|
||||
# Handle single file vs pattern
|
||||
if "*" not in config_pattern:
|
||||
# For single file, check if it exists
|
||||
if os.path.exists(os.path.join(search_dir, config_pattern)):
|
||||
return [config_pattern]
|
||||
else:
|
||||
raise Failed(f"Config Error: Unable to find config file '{config_pattern}' in '{search_dir}'")
|
||||
else:
|
||||
# For patterns, use glob matching
|
||||
glob_configs = glob.glob(os.path.join(search_dir, config_pattern))
|
||||
if glob_configs:
|
||||
# Return just the filenames without paths
|
||||
return [os.path.basename(x) for x in glob_configs]
|
||||
else:
|
||||
raise Failed(f"Config Error: Unable to find any config files in the pattern '{config_pattern}' in '{search_dir}'")
|
||||
|
||||
|
||||
def execute_qbit_commands(qbit_manager, commands, stats, hashes=None):
|
||||
|
|
|
@ -108,9 +108,18 @@ parser.add_argument(
|
|||
action="store",
|
||||
default="config.yml",
|
||||
type=str,
|
||||
help=argparse.SUPPRESS,
|
||||
)
|
||||
parser.add_argument(
|
||||
"-cd",
|
||||
"--config-dir",
|
||||
dest="config_dir",
|
||||
action="store",
|
||||
default=None,
|
||||
type=str,
|
||||
help=(
|
||||
"This is used if you want to use a different name for your config.yml or if you want to load multiple"
|
||||
"config files using *. Example: tv.yml or config*.yml"
|
||||
"This is used to specify a custom configuration directory. "
|
||||
"Takes precedence over --config-file. If not specified, falls back to --config-file logic."
|
||||
),
|
||||
)
|
||||
parser.add_argument(
|
||||
|
@ -265,6 +274,7 @@ run = get_arg("QBT_RUN", args.run, arg_bool=True)
|
|||
sch = get_arg("QBT_SCHEDULE", args.schedule)
|
||||
startupDelay = get_arg("QBT_STARTUP_DELAY", args.startupDelay)
|
||||
config_files = get_arg("QBT_CONFIG", args.configfiles)
|
||||
config_dir = get_arg("QBT_CONFIG_DIR", args.config_dir)
|
||||
log_file = get_arg("QBT_LOGFILE", args.logfile)
|
||||
recheck = get_arg("QBT_RECHECK", args.recheck, arg_bool=True)
|
||||
cat_update = get_arg("QBT_CAT_UPDATE", args.cat_update, arg_bool=True)
|
||||
|
@ -294,10 +304,13 @@ stats = {}
|
|||
args = {}
|
||||
scheduler = None # Global scheduler instance
|
||||
|
||||
default_dir = ensure_config_dir_initialized(get_default_config_dir(config_files))
|
||||
default_dir = ensure_config_dir_initialized(get_default_config_dir(config_files, config_dir))
|
||||
args["config_dir"] = default_dir
|
||||
args["config_dir_args"] = config_dir
|
||||
|
||||
config_files = get_matching_config_files(config_files, default_dir)
|
||||
# Use config_dir_mode if --config-dir was provided, otherwise use legacy mode
|
||||
use_config_dir_mode = config_dir is not None
|
||||
config_files = get_matching_config_files(config_files, default_dir, use_config_dir_mode)
|
||||
|
||||
|
||||
for v in [
|
||||
|
|
Loading…
Add table
Reference in a new issue