| #!/usr/bin/python -bO |
| # Copyright 1999-2014 Gentoo Foundation |
| # Distributed under the terms of the GNU General Public License v2 |
| |
| from __future__ import print_function |
| |
| import platform |
| import signal |
| import sys |
| # This block ensures that ^C interrupts are handled quietly. |
| try: |
| |
| def exithandler(signum, _frame): |
| signal.signal(signal.SIGINT, signal.SIG_IGN) |
| signal.signal(signal.SIGTERM, signal.SIG_IGN) |
| sys.exit(128 + signum) |
| |
| signal.signal(signal.SIGINT, exithandler) |
| signal.signal(signal.SIGTERM, exithandler) |
| # Prevent "[Errno 32] Broken pipe" exceptions when |
| # writing to a pipe. |
| signal.signal(signal.SIGPIPE, signal.SIG_DFL) |
| |
| except KeyboardInterrupt: |
| sys.exit(128 + signal.SIGINT) |
| |
| def debug_signal(_signum, _frame): |
| import pdb |
| pdb.set_trace() |
| |
| if platform.python_implementation() == 'Jython': |
| debug_signum = signal.SIGUSR2 # bug #424259 |
| else: |
| debug_signum = signal.SIGUSR1 |
| |
| signal.signal(debug_signum, debug_signal) |
| |
| import io |
| import os |
| from os import path as osp |
| pym_path = osp.join(osp.dirname(osp.dirname(osp.realpath(__file__))), "pym") |
| sys.path.insert(0, pym_path) |
| import portage |
| portage._internal_caller = True |
| from portage import os |
| from portage import _encodings |
| from portage import _shell_quote |
| from portage import _unicode_decode |
| from portage import _unicode_encode |
| from portage.const import VDB_PATH |
| from portage.util._argparse import ArgumentParser |
| from _emerge.Package import Package |
| from _emerge.RootConfig import RootConfig |
| |
| description = "See the ebuild(1) man page for more info" |
| usage = "Usage: ebuild <ebuild file> <command> [command] ..." |
| parser = ArgumentParser(description=description, usage=usage) |
| |
| force_help = "When used together with the digest or manifest " + \ |
| "command, this option forces regeneration of digests for all " + \ |
| "distfiles associated with the current ebuild. Any distfiles " + \ |
| "that do not already exist in ${DISTDIR} will be automatically fetched." |
| |
| parser.add_argument("--force", help=force_help, action="store_true") |
| parser.add_argument("--color", help="enable or disable color output", |
| choices=("y", "n")) |
| parser.add_argument("--debug", help="show debug output", |
| action="store_true") |
| parser.add_argument("--version", help="show version and exit", |
| action="store_true") |
| parser.add_argument("--ignore-default-opts", |
| action="store_true", |
| help="do not use the EBUILD_DEFAULT_OPTS environment variable") |
| parser.add_argument("--skip-manifest", help="skip all manifest checks", |
| action="store_true") |
| |
| opts, pargs = parser.parse_known_args(args=sys.argv[1:]) |
| |
| def err(txt): |
| portage.writemsg('ebuild: %s\n' % (txt,), noiselevel=-1) |
| sys.exit(1) |
| |
| if opts.version: |
| print("Portage", portage.VERSION) |
| sys.exit(os.EX_OK) |
| |
| if len(pargs) < 2: |
| parser.error("missing required args") |
| |
| if not opts.ignore_default_opts: |
| default_opts = portage.util.shlex_split( |
| portage.settings.get("EBUILD_DEFAULT_OPTS", "")) |
| opts, pargs = parser.parse_known_args(default_opts + sys.argv[1:]) |
| |
| debug = opts.debug |
| force = opts.force |
| |
| import portage.util, portage.const |
| |
| # do this _after_ 'import portage' to prevent unnecessary tracing |
| if debug and "python-trace" in portage.features: |
| import portage.debug |
| portage.debug.set_trace(True) |
| |
| if not opts.color == 'y' and \ |
| (opts.color == 'n' or \ |
| portage.settings.get('NOCOLOR') in ('yes', 'true') or \ |
| portage.settings.get('TERM') == 'dumb' or \ |
| not sys.stdout.isatty()): |
| portage.output.nocolor() |
| portage.settings.unlock() |
| portage.settings['NOCOLOR'] = 'true' |
| portage.settings.lock() |
| |
| ebuild = pargs.pop(0) |
| |
| pf = None |
| if ebuild.endswith(".ebuild"): |
| pf = os.path.basename(ebuild)[:-7] |
| |
| if pf is None: |
| err("%s: does not end with '.ebuild'" % (ebuild,)) |
| |
| if not os.path.isabs(ebuild): |
| mycwd = os.getcwd() |
| # Try to get the non-canonical path from the PWD evironment variable, since |
| # the canonical path returned from os.getcwd() may may be unusable in |
| # cases where the directory stucture is built from symlinks. |
| pwd = os.environ.get('PWD', '') |
| if sys.hexversion < 0x3000000: |
| pwd = _unicode_decode(pwd, encoding=_encodings['content'], |
| errors='strict') |
| if pwd and pwd != mycwd and \ |
| os.path.realpath(pwd) == mycwd: |
| mycwd = portage.normalize_path(pwd) |
| ebuild = os.path.join(mycwd, ebuild) |
| ebuild = portage.normalize_path(ebuild) |
| # portdbapi uses the canonical path for the base of the portage tree, but |
| # subdirectories of the base can be built from symlinks (like crossdev does). |
| ebuild_portdir = os.path.realpath( |
| os.path.dirname(os.path.dirname(os.path.dirname(ebuild)))) |
| ebuild = os.path.join(ebuild_portdir, *ebuild.split(os.path.sep)[-3:]) |
| vdb_path = os.path.realpath(os.path.join(portage.settings['EROOT'], VDB_PATH)) |
| |
| # Make sure that portdb.findname() returns the correct ebuild. |
| if ebuild_portdir != vdb_path and \ |
| ebuild_portdir not in portage.portdb.porttrees: |
| portdir_overlay = portage.settings.get("PORTDIR_OVERLAY", "") |
| if sys.hexversion >= 0x3000000: |
| os.environ["PORTDIR_OVERLAY"] = \ |
| portdir_overlay + \ |
| " " + _shell_quote(ebuild_portdir) |
| else: |
| os.environ["PORTDIR_OVERLAY"] = \ |
| _unicode_encode(portdir_overlay, |
| encoding=_encodings['content'], errors='strict') + \ |
| " " + _unicode_encode(_shell_quote(ebuild_portdir), |
| encoding=_encodings['content'], errors='strict') |
| |
| print("Appending %s to PORTDIR_OVERLAY..." % ebuild_portdir) |
| portage._reset_legacy_globals() |
| |
| myrepo = None |
| if ebuild_portdir != vdb_path: |
| myrepo = portage.portdb.getRepositoryName(ebuild_portdir) |
| |
| if not os.path.exists(ebuild): |
| err('%s: does not exist' % (ebuild,)) |
| |
| ebuild_split = ebuild.split("/") |
| cpv = "%s/%s" % (ebuild_split[-3], pf) |
| |
| with io.open(_unicode_encode(ebuild, encoding=_encodings['fs'], errors='strict'), |
| mode='r', encoding=_encodings['repo.content'], errors='replace') as f: |
| eapi = portage._parse_eapi_ebuild_head(f)[0] |
| if eapi is None: |
| eapi = "0" |
| if not portage.catpkgsplit(cpv, eapi=eapi): |
| err('%s: %s: does not follow correct package syntax' % (ebuild, cpv)) |
| |
| if ebuild.startswith(vdb_path): |
| mytree = "vartree" |
| pkg_type = "installed" |
| |
| portage_ebuild = portage.db[portage.root][mytree].dbapi.findname(cpv, myrepo=myrepo) |
| |
| if os.path.realpath(portage_ebuild) != ebuild: |
| err('Portage seems to think that %s is at %s' % (cpv, portage_ebuild)) |
| |
| else: |
| mytree = "porttree" |
| pkg_type = "ebuild" |
| |
| portage_ebuild = portage.portdb.findname(cpv, myrepo=myrepo) |
| |
| if not portage_ebuild or portage_ebuild != ebuild: |
| err('%s: does not seem to have a valid PORTDIR structure' % (ebuild,)) |
| |
| if len(pargs) > 1 and "config" in pargs: |
| err('"config" must not be called with any other phase') |
| |
| def discard_digests(myebuild, mysettings, mydbapi): |
| """Discard all distfiles digests for the given ebuild. This is useful when |
| upstream has changed the identity of the distfiles and the user would |
| otherwise have to manually remove the Manifest and files/digest-* files in |
| order to ensure correct results.""" |
| try: |
| portage._doebuild_manifest_exempt_depend += 1 |
| pkgdir = os.path.dirname(myebuild) |
| fetchlist_dict = portage.FetchlistDict(pkgdir, mysettings, mydbapi) |
| mf = mysettings.repositories.get_repo_for_location( |
| os.path.dirname(os.path.dirname(pkgdir))) |
| mf = mf.load_manifest(pkgdir, mysettings["DISTDIR"], |
| fetchlist_dict=fetchlist_dict) |
| mf.create(requiredDistfiles=None, |
| assumeDistHashesSometimes=True, assumeDistHashesAlways=True) |
| distfiles = fetchlist_dict[cpv] |
| for myfile in distfiles: |
| try: |
| del mf.fhashdict["DIST"][myfile] |
| except KeyError: |
| pass |
| mf.write() |
| finally: |
| portage._doebuild_manifest_exempt_depend -= 1 |
| |
| portage.settings.validate() # generate warning messages if necessary |
| |
| build_dir_phases = set(["setup", "unpack", "prepare", "configure", "compile", |
| "test", "install", "package", "rpm", "merge", "qmerge"]) |
| |
| # If the current metadata is invalid then force the ebuild to be |
| # sourced again even if $T/environment already exists. |
| ebuild_changed = False |
| if mytree == "porttree" and build_dir_phases.intersection(pargs): |
| ebuild_changed = \ |
| portage.portdb._pull_valid_cache(cpv, ebuild, ebuild_portdir)[0] is None |
| |
| tmpsettings = portage.config(clone=portage.settings) |
| tmpsettings["PORTAGE_VERBOSE"] = "1" |
| tmpsettings.backup_changes("PORTAGE_VERBOSE") |
| |
| if opts.skip_manifest: |
| tmpsettings["EBUILD_SKIP_MANIFEST"] = "1" |
| tmpsettings.backup_changes("EBUILD_SKIP_MANIFEST") |
| |
| if opts.skip_manifest or \ |
| "digest" in tmpsettings.features or \ |
| "digest" in pargs or \ |
| "manifest" in pargs: |
| portage._doebuild_manifest_exempt_depend += 1 |
| |
| if "test" in pargs: |
| # This variable is a signal to config.regenerate() to |
| # indicate that the test phase should be enabled regardless |
| # of problems such as masked "test" USE flag. |
| tmpsettings["EBUILD_FORCE_TEST"] = "1" |
| tmpsettings.backup_changes("EBUILD_FORCE_TEST") |
| tmpsettings.features.add("test") |
| |
| tmpsettings.features.discard("fail-clean") |
| |
| if "merge" in pargs and "noauto" in tmpsettings.features: |
| print("Disabling noauto in features... merge disables it. (qmerge doesn't)") |
| tmpsettings.features.discard("noauto") |
| |
| try: |
| metadata = dict(zip(Package.metadata_keys, |
| portage.db[portage.settings['EROOT']][mytree].dbapi.aux_get( |
| cpv, Package.metadata_keys, myrepo=myrepo))) |
| except KeyError: |
| # aux_get failure, message should have been shown on stderr. |
| sys.exit(1) |
| |
| root_config = RootConfig(portage.settings, |
| portage.db[portage.settings['EROOT']], None) |
| |
| pkg = Package(built=(pkg_type != "ebuild"), cpv=cpv, |
| installed=(pkg_type=="installed"), |
| metadata=metadata, root_config=root_config, |
| type_name=pkg_type) |
| |
| # Apply package.env and repo-level settings. This allows per-package |
| # FEATURES and other variables (possibly PORTAGE_TMPDIR) to be |
| # available as soon as possible. Also, note that the only way to ensure |
| # that setcpv gets metadata from the correct repository is to pass in |
| # a Package instance, as we do here (previously we had to modify |
| # portdb.porttrees in order to accomplish this). |
| tmpsettings.setcpv(pkg) |
| |
| def stale_env_warning(): |
| if "clean" not in pargs and \ |
| "noauto" not in tmpsettings.features and \ |
| build_dir_phases.intersection(pargs): |
| portage.doebuild_environment(ebuild, "setup", portage.root, |
| tmpsettings, debug, 1, portage.portdb) |
| env_filename = os.path.join(tmpsettings["T"], "environment") |
| if os.path.exists(env_filename): |
| msg = ("Existing ${T}/environment for '%s' will be sourced. " + \ |
| "Run 'clean' to start with a fresh environment.") % \ |
| (tmpsettings["PF"], ) |
| from textwrap import wrap |
| msg = wrap(msg, 70) |
| for x in msg: |
| portage.writemsg(">>> %s\n" % x) |
| |
| if ebuild_changed: |
| open(os.path.join(tmpsettings['PORTAGE_BUILDDIR'], |
| '.ebuild_changed'), 'w').close() |
| |
| from portage.exception import PermissionDenied, \ |
| PortagePackageException, UnsupportedAPIException |
| |
| if 'digest' in tmpsettings.features: |
| if pargs and pargs[0] not in ("digest", "manifest"): |
| pargs = ['digest'] + pargs |
| # We only need to build digests on the first pass. |
| tmpsettings.features.discard('digest') |
| |
| checked_for_stale_env = False |
| |
| for arg in pargs: |
| try: |
| if not checked_for_stale_env and arg not in ("digest","manifest"): |
| # This has to go after manifest generation since otherwise |
| # aux_get() might fail due to invalid ebuild digests. |
| stale_env_warning() |
| checked_for_stale_env = True |
| |
| if arg in ("digest", "manifest") and force: |
| discard_digests(ebuild, tmpsettings, portage.portdb) |
| a = portage.doebuild(ebuild, arg, settings=tmpsettings, |
| debug=debug, tree=mytree, |
| vartree=portage.db[portage.root]['vartree']) |
| except KeyboardInterrupt: |
| print("Interrupted.") |
| a = 1 |
| except KeyError: |
| # aux_get error |
| a = 1 |
| except UnsupportedAPIException as e: |
| from textwrap import wrap |
| msg = wrap(str(e), 70) |
| del e |
| for x in msg: |
| portage.writemsg("!!! %s\n" % x, noiselevel=-1) |
| a = 1 |
| except PortagePackageException as e: |
| portage.writemsg("!!! %s\n" % (e,), noiselevel=-1) |
| a = 1 |
| except PermissionDenied as e: |
| portage.writemsg("!!! Permission Denied: %s\n" % (e,), noiselevel=-1) |
| a = 1 |
| if a == None: |
| print("Could not run the required binary?") |
| a = 127 |
| if a: |
| sys.exit(a) |