From 6cbef943ac1b9a2aede1cb8f1626e0ca0222feab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20P=C3=B6hn?= Date: Wed, 1 Oct 2025 15:03:41 +0200 Subject: [PATCH] set up new mechanism for unlisted subcommands For the build automation, there will be lots of subcommands that are meant to run in scripted environments. They are not intended for interactive use. Although they sometimes might be useful interactively, they might also sometimes be dangerous to run interactively because they rely on the presense of a VM/container, modify the local environment, or even run things as root. --- fdroidserver/__main__.py | 21 +++++++++++++++++++-- fdroidserver/common.py | 21 +++++++++++++++++++++ 2 files changed, 40 insertions(+), 2 deletions(-) diff --git a/fdroidserver/__main__.py b/fdroidserver/__main__.py index 83a0c81c..5a2241f3 100755 --- a/fdroidserver/__main__.py +++ b/fdroidserver/__main__.py @@ -55,6 +55,18 @@ COMMANDS = OrderedDict([ ("mirror", _("Download complete mirrors of small repos")), ]) +# The list of subcommands that are not advertised as public api, +# intended for the use-case of breaking down builds into atomic steps. +# +# For the build automation, there will be lots of subcommands that are +# meant to run in scripted environments. They are not intended for +# interactive use. Although they sometimes might be useful +# interactively, they might also sometimes be dangerous to run +# interactively because they rely on the presense of a VM/container, +# modify the local environment, or even run things as root. +COMMANDS_INTERNAL = [ +] + def print_help(available_plugins=None): print(_("usage: ") + _("fdroid [] [-h|--help|--version|]")) @@ -136,7 +148,12 @@ def main(): sys.exit(0) command = sys.argv[1] - if command not in COMMANDS and command not in available_plugins: + command_not_found = ( + command not in COMMANDS + and command not in COMMANDS_INTERNAL + and command not in available_plugins + ) + if command_not_found: if command in ('-h', '--help'): print_help(available_plugins=available_plugins) sys.exit(0) @@ -186,7 +203,7 @@ def main(): sys.argv[0] += ' ' + command del sys.argv[1] - if command in COMMANDS.keys(): + if command in COMMANDS.keys() or command in COMMANDS_INTERNAL: # import is named import_subcommand internally b/c import is reserved by Python command = 'import_subcommand' if command == 'import' else command mod = __import__('fdroidserver.' + command, None, None, [command]) diff --git a/fdroidserver/common.py b/fdroidserver/common.py index e3062129..247ee733 100644 --- a/fdroidserver/common.py +++ b/fdroidserver/common.py @@ -1046,6 +1046,27 @@ def get_local_metadata_files(): return glob.glob('.fdroid.[a-jl-z]*[a-rt-z]') +def split_pkg_arg(appid_versionCode_pair): + """Split 'appid:versionCode' pair into 2 separate values safely. + + :raises ValueError: if argument is not parseable + :return: (appid, versionCode) tuple with the 2 parsed values + """ + tokens = appid_versionCode_pair.split(":") + if len(tokens) != 2: + raise ValueError( + _("'{}' is not a valid pair of the form appId:versionCode pair").format( + appid_versionCode_pair + ) + ) + if not is_valid_package_name(tokens[0]): + raise ValueError( + _("'{}' does not start with a valid appId").format(appid_versionCode_pair) + ) + versionCode = version_code_string_to_int(tokens[1]) + return tokens[0], versionCode + + def read_pkg_args(appid_versionCode_pairs, allow_version_codes=False): """No summary.