diff --git a/osc/build.py b/osc/build.py index ffc3a5956..95a2164b3 100644 --- a/osc/build.py +++ b/osc/build.py @@ -4,6 +4,7 @@ # either version 2, or (at your option) any later version. import fnmatch +import getpass import glob import os import re @@ -605,20 +606,35 @@ def calculate_prj_pac(store, opts, descr): return project, package -def calculate_build_root(apihost, prj, pac, repo, arch): - buildroot = os.environ.get('OSC_BUILD_ROOT', conf.config['build-root']) \ - % {'repo': repo, 'arch': arch, 'project': prj, 'package': pac, 'apihost': apihost} +def calculate_build_root_user(vm_type): + if vm_type in ("kvm", "podman"): + return getpass.getuser() + return None + + +def calculate_build_root(apihost, prj, pac, repo, arch, user=None): + user = user or "" + dash_user = f"-{user:s}" if user else "" + buildroot = conf.config["build-root"] % { + 'apihost': apihost, + 'project': prj, + 'package': pac, + 'repo': repo, + 'arch': arch, + "user": user, + "dash_user": dash_user, + } return buildroot def build_as_user(): - if os.environ.get('OSC_SU_WRAPPER', conf.config['su-wrapper']).split(): + if conf.config["su-wrapper"]: return False return True def su_wrapper(cmd): - sucmd = os.environ.get('OSC_SU_WRAPPER', conf.config['su-wrapper']).split() + sucmd = conf.config['su-wrapper'].split() if sucmd: if sucmd[0] == 'su': if sucmd[-1] == '-c': @@ -633,7 +649,12 @@ def run_build(opts, *args): cmd = [conf.config['build-cmd']] cmd += args - cmd = su_wrapper(cmd) + if opts.vm_type: + cmd.extend(["--vm-type", opts.vm_type]) + + user = calculate_build_root_user(opts.vm_type) + if not user: + cmd = su_wrapper(cmd) if not opts.userootforbuild: cmd.append('--norootforbuild') @@ -782,18 +803,6 @@ def main(apiurl, store, opts, argv): if opts.wipe: buildargs.append("--wipe") - orig_build_root = config['build-root'] - # make it possible to override configuration of the rc file - for var in ['OSC_PACKAGECACHEDIR', 'OSC_SU_WRAPPER', 'OSC_BUILD_ROOT']: - val = os.getenv(var) - if val: - if var.startswith('OSC_'): - var = var[4:] - var = var.lower().replace('_', '-') - if var in config: - print('Overriding config value for %s=\'%s\' with \'%s\'' % (var, config[var], val)) - config[var] = val - pacname = pac if pacname == '_repository': if not opts.local_package: @@ -805,15 +814,8 @@ def main(apiurl, store, opts, argv): pacname = os.path.splitext(os.path.basename(build_descr))[0] apihost = urlsplit(apiurl)[1] if not build_root: - build_root = config['build-root'] - if build_root == orig_build_root: - # ENV var was not set - build_root = config['api_host_options'][apiurl].get('build-root', build_root) - try: - build_root = build_root % {'repo': repo, 'arch': arch, - 'project': prj, 'package': pacname, 'apihost': apihost} - except KeyError: - pass + user = calculate_build_root_user(vm_type) + build_root = calculate_build_root(apihost, prj, pacname, repo, arch, user) # We configure sccache after pacname, so that in default cases we can have an sccache for each # package to prevent cross-cache polutions. It helps to make the local-use case a bit nicer. @@ -1492,7 +1494,9 @@ def __str__(self): cmd += specialcmdopts + vm_options + buildargs cmd += [build_descr] - cmd = su_wrapper(cmd) + # determine if we're building under root (user == None) and use su_wrapper accordingly + if calculate_build_root_user(vm_type) is None: + cmd = su_wrapper(cmd) # change personality, if needed if hostarch != bi.buildarch and bi.buildarch in change_personality: @@ -1506,7 +1510,12 @@ def __str__(self): rc = run_external(cmd[0], *cmd[1:]) if rc: print() - print('The buildroot was:', build_root) + print(f"Build failed with exit code {rc}") + print(f"The buildroot was: {build_root}") + print() + print("Cleaning the build root may fix the problem or allow you to start debugging from a well-defined state:") + print(" - add '--clean' option to your 'osc build' command") + print(" - run 'osc wipe [--vm-type=...]' prior running your 'osc build' command again") sys.exit(rc) except KeyboardInterrupt as keyboard_interrupt_exception: print("keyboard interrupt, killing build ...") diff --git a/osc/commandline.py b/osc/commandline.py index d500ab879..883ced1fc 100644 --- a/osc/commandline.py +++ b/osc/commandline.py @@ -6423,10 +6423,9 @@ def do_localbuildlog(self, subcmd, opts, *args): raise oscerr.WrongArgs('Wrong number of arguments.') # TODO: refactor/unify buildroot calculation and move it to core.py - buildroot = os.environ.get('OSC_BUILD_ROOT', conf.config['build-root']) apihost = urlsplit(self.get_api_url())[1] - buildroot = buildroot % {'project': project, 'package': package, - 'repo': repo, 'arch': arch, 'apihost': apihost} + buildroot = osc_build.calculate_build_root(apihost, project, package, repo, arch) + offset = 0 if opts.offset: offset = int(opts.offset) @@ -7272,7 +7271,8 @@ def do_build(self, subcmd, opts, *args): repo, arch, build_descr = args prj, pac = osc_build.calculate_prj_pac(store, opts, build_descr) apihost = urlsplit(self.get_api_url())[1] - build_root = osc_build.calculate_build_root(apihost, prj, pac, repo, arch) + user = osc_build.calculate_build_root_user(opts.vm_type) + build_root = osc_build.calculate_build_root(apihost, prj, pac, repo, arch, user) print(build_root) return @@ -7285,11 +7285,11 @@ def do_build(self, subcmd, opts, *args): repo, arch, build_descr = args prj, pac = osc_build.calculate_prj_pac(store, opts, build_descr) apihost = urlsplit(self.get_api_url())[1] - build_root = osc_build.calculate_build_root(apihost, prj, pac, repo, - arch) + user = osc_build.calculate_build_root_user(opts.vm_type) + build_root = osc_build.calculate_build_root(apihost, prj, pac, repo, arch, user) if opts.wipe and not opts.force: # Confirm delete - print("Really wipe '%s'? [y/N]: " % build_root) + print("Really wipe '%s'? [y/N]: " % build_root, end="") choice = raw_input().lower() if choice != 'y': print('Aborting') diff --git a/osc/conf.py b/osc/conf.py index 9d1dd48f9..c18b876e3 100644 --- a/osc/conf.py +++ b/osc/conf.py @@ -970,17 +970,27 @@ def apiurl_aliases(self): ini_key="build-jobs", ) # type: ignore[assignment] - build_type: Optional[str] = Field( + vm_type: Optional[str] = Field( default=None, description=textwrap.dedent( """ Type of the build environment passed the build tool as the ``--vm-type`` option: - - : chroot build - - kvm: KVM VM build (needs build-device, build-swap, build-memory) - - xen: XEN VM build (needs build-device, build-swap, build-memory) - - qemu: [EXPERIMENTAL] QEMU VM build - - lxc: [EXPERIMENTAL] LXC build + - chroot build + - kvm KVM VM build (rootless, needs build-device, build-swap, build-memory) + - xen XEN VM build (needs build-device, build-swap, build-memory) + - qemu [EXPERIMENTAL] QEMU VM build + - lxc [EXPERIMENTAL] LXC build + - uml + - zvm + - openstack + - ec2 + - docker + - podman (rootless) + - pvm + - nspawn + + See ``build --help`` for more details about supported options. """ ), ini_key="build-type", @@ -997,13 +1007,18 @@ def apiurl_aliases(self): ) # type: ignore[assignment] build_root: str = Field( - default="/var/tmp/build-root/%(repo)s-%(arch)s", + default="/var/tmp/build-root%(dash_user)s/%(repo)s-%(arch)s", description=textwrap.dedent( """ Path to the build root directory. - Supported substitutions: ``%(repo)s``, ``%(arch)s``, ``%(project)s``, ``%(package)s`` and ``%(apihost)s`` - where ``apihost`` is the hostname extracted from the currently used ``apiurl``. + Supported substitutions: ``%(repo)s``, ``%(arch)s``, ``%(project)s``, ``%(package)s``, ``%(apihost)s``, ``%(user)s``, ``%(dash_user)s`` + where:: + + - ``apihost`` is the hostname extracted from the currently used ``apiurl``. + - ``dash_user`` is the username prefixed with a dash. If ``user`` is empty, ``dash_user`` is also empty. + + NOTE: The configuration holds the original unexpanded string. Call ``osc.build.get_build_root()`` with proper arguments to retrieve an actual path. Passed as ``--root `` to the build tool. """ @@ -1745,7 +1760,7 @@ def get_config(override_conffile=None, Configure osc. The configuration options are loaded with the following priority: - 1. environment variables: OSC_ + 1. environment variables: OSC_ 2. override arguments provided to get_config() 3. oscrc config file """ @@ -1854,7 +1869,7 @@ def get_config(override_conffile=None, # priority: env, overrides, config if env_key in os.environ: - value = os.environ["env_key"] + value = os.environ[env_key] elif name in overrides: value = overrides.pop(name) elif ini_key in overrides: