mirror of
https://github.com/StuffAnThings/qbit_manage.git
synced 2025-10-09 13:29:15 +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" --run (QBT_RUN): {self.args['run']}")
|
||||||
logger.debug(f" --schedule (QBT_SCHEDULE): {self.args['sch']}")
|
logger.debug(f" --schedule (QBT_SCHEDULE): {self.args['sch']}")
|
||||||
logger.debug(f" --startup-delay (QBT_STARTUP_DELAY): {self.args['startupDelay']}")
|
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-file (QBT_LOGFILE): {self.args['log_file']}")
|
||||||
logger.debug(f" --log-level (QBT_LOG_LEVEL): {self.args['log_level']}")
|
logger.debug(f" --log-level (QBT_LOG_LEVEL): {self.args['log_level']}")
|
||||||
logger.debug(f" --log-size (QBT_LOG_SIZE): {self.args['log_size']}")
|
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"
|
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.
|
Determine the default persistent config directory, leveraging a provided config path/pattern first.
|
||||||
|
|
||||||
Resolution order:
|
Resolution order:
|
||||||
1) If config_hint is an absolute path or contains a directory component, use its parent directory
|
1) If config_dir is provided, use it directly (takes precedence over config_hint)
|
||||||
2) Otherwise, if config_hint is a name/pattern (e.g. 'config.yml'), search common bases for:
|
2) If config_hint is an absolute path or contains a directory component, use its parent directory
|
||||||
- A direct match to that filename/pattern
|
3) Otherwise, if config_hint is a name/pattern (e.g. 'config.yml'), search common bases for:
|
||||||
- OR a persisted scheduler file 'schedule.yml' (so we don't lose an existing schedule when config.yml is absent)
|
- A direct match to that filename/pattern
|
||||||
Common bases (in order):
|
- OR a persisted scheduler file 'schedule.yml' (so we don't lose an existing schedule when config.yml is absent)
|
||||||
- /config (container volume)
|
Common bases (in order):
|
||||||
- repository ./config
|
- /config (container volume)
|
||||||
- user OS config directory
|
- repository ./config
|
||||||
Return the first base containing either.
|
- user OS config directory
|
||||||
3) Fallback to legacy-ish behavior:
|
Return the first base containing either.
|
||||||
- /config if it contains any *.yml.sample / *.yaml.sample
|
4) Fallback to legacy-ish behavior:
|
||||||
- otherwise user OS config directory
|
- /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:
|
if config_hint:
|
||||||
primary = str(config_hint).split(",")[0].strip() # take first if comma-separated
|
primary = str(config_hint).split(",")[0].strip() # take first if comma-separated
|
||||||
if primary:
|
if primary:
|
||||||
|
@ -1470,12 +1476,14 @@ class EnvStr(str):
|
||||||
return super().__repr__()
|
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.
|
"""Get list of config files matching a pattern.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
config_pattern (str): Config file pattern (e.g. "config.yml" or "config*.yml")
|
config_pattern (str): Config file pattern (e.g. "config.yml" or "config*.yml")
|
||||||
default_dir (str): Default directory to look for configs
|
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:
|
Returns:
|
||||||
list: List of matching config file names
|
list: List of matching config file names
|
||||||
|
@ -1489,16 +1497,39 @@ def get_matching_config_files(config_pattern: str, default_dir: str) -> list:
|
||||||
else:
|
else:
|
||||||
search_dir = default_dir
|
search_dir = default_dir
|
||||||
|
|
||||||
# Handle single file vs pattern
|
if use_config_dir_mode:
|
||||||
if "*" not in config_pattern:
|
# New --config-dir approach: find all .yml and .yaml files, excluding reserved files
|
||||||
return [config_pattern]
|
config_files = []
|
||||||
else:
|
for pattern in ["*.yml", "*.yaml"]:
|
||||||
glob_configs = glob.glob(os.path.join(search_dir, config_pattern))
|
glob_configs = glob.glob(os.path.join(search_dir, pattern))
|
||||||
if glob_configs:
|
for config_file in glob_configs:
|
||||||
# Return just the filenames without paths
|
filename = os.path.basename(config_file)
|
||||||
return [os.path.split(x)[-1] for x in glob_configs]
|
# 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:
|
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):
|
def execute_qbit_commands(qbit_manager, commands, stats, hashes=None):
|
||||||
|
|
|
@ -108,9 +108,18 @@ parser.add_argument(
|
||||||
action="store",
|
action="store",
|
||||||
default="config.yml",
|
default="config.yml",
|
||||||
type=str,
|
type=str,
|
||||||
|
help=argparse.SUPPRESS,
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"-cd",
|
||||||
|
"--config-dir",
|
||||||
|
dest="config_dir",
|
||||||
|
action="store",
|
||||||
|
default=None,
|
||||||
|
type=str,
|
||||||
help=(
|
help=(
|
||||||
"This is used if you want to use a different name for your config.yml or if you want to load multiple"
|
"This is used to specify a custom configuration directory. "
|
||||||
"config files using *. Example: tv.yml or config*.yml"
|
"Takes precedence over --config-file. If not specified, falls back to --config-file logic."
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
|
@ -265,6 +274,7 @@ run = get_arg("QBT_RUN", args.run, arg_bool=True)
|
||||||
sch = get_arg("QBT_SCHEDULE", args.schedule)
|
sch = get_arg("QBT_SCHEDULE", args.schedule)
|
||||||
startupDelay = get_arg("QBT_STARTUP_DELAY", args.startupDelay)
|
startupDelay = get_arg("QBT_STARTUP_DELAY", args.startupDelay)
|
||||||
config_files = get_arg("QBT_CONFIG", args.configfiles)
|
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)
|
log_file = get_arg("QBT_LOGFILE", args.logfile)
|
||||||
recheck = get_arg("QBT_RECHECK", args.recheck, arg_bool=True)
|
recheck = get_arg("QBT_RECHECK", args.recheck, arg_bool=True)
|
||||||
cat_update = get_arg("QBT_CAT_UPDATE", args.cat_update, arg_bool=True)
|
cat_update = get_arg("QBT_CAT_UPDATE", args.cat_update, arg_bool=True)
|
||||||
|
@ -294,10 +304,13 @@ stats = {}
|
||||||
args = {}
|
args = {}
|
||||||
scheduler = None # Global scheduler instance
|
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"] = 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 [
|
for v in [
|
||||||
|
|
Loading…
Add table
Reference in a new issue