From 5ea00e0862ce2e53f73abb7452797611d71c5bad Mon Sep 17 00:00:00 2001 From: Oliver Smith Date: Thu, 15 Mar 2018 21:42:34 +0000 Subject: [PATCH] pmbootstrap newapkbuild: Properly parse arguments (#1320) * pmbootstrap newapkbuild: Properly parse arguments The `pmbootstrap newapkbuild` action wraps Alpine's `newapkbuild`. We used to directly pass all arguments to `newapkbuild` without verifying in Python whether they make sense or not. However, as `newpakbuild` doesn't do strict sanity checks on the arguments, it is easy to end up with unexpected behavior when using the command for the first time. For example, `newapkbuild` allows either specifying a PKGNAME or SRCURL as last parameter, and also allows setting a PKGNAME with the `-n` parameter. It only makes sense to use that option when passing a SRCURL. With this commit, we duplicate the optins that should be passed through to `newapkbuild` and use argparse to fully sanitize the options and display a help page (`pmbootstrap newapkbuild -h`) that is consistent with the other help pages. Details: * The `-f` (force) flag does not get passed through anymore. Instead we use it in Python to skip asking if an existing aport should be overwritten (the aports are outside of the chroot, so `newapkbuild` can't handle it in a way that makes sense for pmbootstrap). * Output of `newapkbuild` gets redirected to the log file now, as we don't need it to display a help page. * Don't verify the pkgver while creating the new APKBUILD. When passing a SRCURL, the pkgver gets extracted from the end of the URL and may not have a valid format yet (but we want the APKBUILD anyway). * Stored options passed through in `pmb/config/__init__.py` and use it in both `pmb/parse/arguments.py` and `pmb/helpers/frontend.py`. * Only allow `-n` with SRCURL * The postmarketOS aports folder gets specified with `--folder` now. That way the generated help page is much closer to the original one from `newapkbuild`. The default is `main`. * Made the package type flags (CMake, autotools, ...) exclusive so only one of them can be specified --- pmb/build/newapkbuild.py | 13 ++++++------ pmb/config/__init__.py | 26 ++++++++++++++++++++++++ pmb/helpers/frontend.py | 32 ++++++++++++++++++++++++++---- pmb/parse/arguments.py | 43 ++++++++++++++++++++++++++++++++++------ 4 files changed, 97 insertions(+), 17 deletions(-) diff --git a/pmb/build/newapkbuild.py b/pmb/build/newapkbuild.py index d0862a0e..ab150a19 100644 --- a/pmb/build/newapkbuild.py +++ b/pmb/build/newapkbuild.py @@ -1,5 +1,5 @@ """ -Copyright 2017 Oliver Smith +Copyright 2018 Oliver Smith This file is part of pmbootstrap. @@ -24,7 +24,7 @@ import pmb.helpers.cli import pmb.parse -def newapkbuild(args, folder, args_passed): +def newapkbuild(args, folder, args_passed, force=False): # Initialize build environment and build folder pmb.build.init(args) build = "/home/pmos/build" @@ -34,15 +34,14 @@ def newapkbuild(args, folder, args_passed): pmb.chroot.user(args, ["mkdir", "-p", build]) # Run newapkbuild - pmb.chroot.user(args, ["newapkbuild"] + args_passed, log=False, - working_dir=build) + pmb.chroot.user(args, ["newapkbuild"] + args_passed, working_dir=build) glob_result = glob.glob(build_outside + "/*/APKBUILD") if not len(glob_result): return # Paths for copying source_apkbuild = glob_result[0] - pkgname = pmb.parse.apkbuild(args, source_apkbuild)["pkgname"] + pkgname = pmb.parse.apkbuild(args, source_apkbuild, False)["pkgname"] target = args.aports + "/" + folder + "/" + pkgname # Move /home/pmos/build/$pkgname/* to /home/pmos/build/* @@ -54,8 +53,8 @@ def newapkbuild(args, folder, args_passed): # Overwrite confirmation if os.path.exists(target): logging.warning("WARNING: Folder already exists: " + target) - if not pmb.helpers.cli.confirm(args, "Continue and delete its" - " contents?"): + question = "Continue and delete its contents?" + if not force and not pmb.helpers.cli.confirm(args, question): raise RuntimeError("Aborted.") pmb.helpers.run.user(args, ["rm", "-r", target]) diff --git a/pmb/config/__init__.py b/pmb/config/__init__.py index ca97ad36..f7fdb3d2 100644 --- a/pmb/config/__init__.py +++ b/pmb/config/__init__.py @@ -399,3 +399,29 @@ aportgen = { # QEMU # qemu_native_mesa_drivers = ["dri-swrast", "dri-virtio"] + +# +# NEWAPKBUILD +# Options passed through to the "newapkbuild" command from Alpine Linux. They +# are duplicated here, so we can use Python's argparse for argument parsing and +# help page display. The -f (force) flag is not defined here, as we use that in +# the Python code only and don't pass it through. +# +newapkbuild_arguments_strings = [ + ["-n", "pkgname", "set package name (only use with SRCURL)"], + ["-d", "pkgdesc", "set package description"], + ["-l", "license", "set package license identifier from" + " "], + ["-u", "url", "set package URL"], +] +newapkbuild_arguments_switches_pkgtypes = [ + ["-a", "autotools", "create autotools package (use ./configure ...)"], + ["-C", "cmake", "create CMake package (assume cmake/ is there)"], + ["-m", "meson", "create meson package (assume meson.build is there)"], + ["-p", "perl", "create perl package (assume Makefile.PL is there)"], + ["-y", "python", "create python package (assume setup.py is there)"], +] +newapkbuild_arguments_switches_other = [ + ["-s", "sourceforge", "use sourceforge source URL"], + ["-c", "copy_samples", "copy a sample init.d, conf.d and install script"], +] diff --git a/pmb/helpers/frontend.py b/pmb/helpers/frontend.py index fd5b4615..45a684da 100644 --- a/pmb/helpers/frontend.py +++ b/pmb/helpers/frontend.py @@ -232,10 +232,34 @@ def update(args): def newapkbuild(args): - if not len(args.args_passed): - logging.info("See 'pmbootstrap newapkbuild -h' for usage information.") - raise RuntimeError("No arguments to pass to newapkbuild specified!") - pmb.build.newapkbuild(args, args.folder, args.args_passed) + # Check for SRCURL usage + is_url = False + for prefix in ["http://", "https://", "ftp://"]: + if args.pkgname_pkgver_srcurl.startswith(prefix): + is_url = True + break + + # Sanity check: -n is only allowed with SRCURL + if args.pkgname and not is_url: + raise RuntimeError("You can only specify a pkgname (-n) when using" + " SRCURL as last parameter.") + + # Passthrough: Strings (e.g. -d "my description") + pass_through = [] + for entry in pmb.config.newapkbuild_arguments_strings: + value = getattr(args, entry[1]) + if value: + pass_through += [entry[0], value] + + # Passthrough: Switches (e.g. -C for CMake) + for entry in (pmb.config.newapkbuild_arguments_switches_pkgtypes + + pmb.config.newapkbuild_arguments_switches_other): + if getattr(args, entry[1]) is True: + pass_through.append(entry[0]) + + # Passthrough: PKGNAME[-PKGVER] | SRCURL + pass_through.append(args.pkgname_pkgver_srcurl) + pmb.build.newapkbuild(args, args.folder, pass_through, args.force) def kconfig_check(args): diff --git a/pmb/parse/arguments.py b/pmb/parse/arguments.py index 804e2358..b0d4ea00 100644 --- a/pmb/parse/arguments.py +++ b/pmb/parse/arguments.py @@ -143,13 +143,44 @@ def arguments_pkgrel_bump(subparser): def arguments_newapkbuild(subparser): - ret = subparser.add_parser("newapkbuild", help="get a template to package" + """ + Wrapper for Alpine's "newapkbuild" command. + + Most parameters will get directly passed through, and they are defined in + "pmb/config/__init__.py". That way they can be used here and when passing + them through in "pmb/helpers/frontend.py". The order of the parameters is + kept the same as in "newapkbuild -h". + """ + sub = subparser.add_parser("newapkbuild", help="get a template to package" " new software") - ret.add_argument("folder", help="aports subfolder, where the new aport will" - " be located (main, cross, device, ...)") - ret.add_argument("args_passed", nargs=argparse.REMAINDER, - help="arguments directly passed to Alpine's newapkbuild," - " more information: 'pmbootstrap newapkbuild main -h'") + sub.add_argument("--folder", help="set postmarketOS aports folder" + " (default: main)", default="main") + + # Passthrough: Strings (e.g. -d "my description") + for entry in pmb.config.newapkbuild_arguments_strings: + sub.add_argument(entry[0], dest=entry[1], help=entry[2]) + + # Passthrough: Package type switches (e.g. -C for CMake) + group = sub.add_mutually_exclusive_group() + for entry in pmb.config.newapkbuild_arguments_switches_pkgtypes: + group.add_argument(entry[0], dest=entry[1], help=entry[2], + action="store_true") + + # Passthrough: Other switches (e.g. -c for copying sample files) + for entry in pmb.config.newapkbuild_arguments_switches_other: + sub.add_argument(entry[0], dest=entry[1], help=entry[2], + action="store_true") + + # Force switch + sub.add_argument("-f", dest="force", action="store_true", + help="force even if directory already exists") + + # Passthrough: PKGNAME[-PKGVER] | SRCURL + sub.add_argument("pkgname_pkgver_srcurl", + metavar="PKGNAME[-PKGVER] | SRCURL", + help="set either the package name (optionally with the" + " PKGVER at the end, e.g. 'hello-world-1.0') or the" + " download link to the source archive") def arguments():