| #!/usr/bin/python -O |
| # Copyright 1999-2011 Gentoo Foundation |
| # Distributed under the terms of the GNU General Public License v2 |
| |
| from __future__ import print_function |
| |
| 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() |
| signal.signal(signal.SIGUSR1, debug_signal) |
| |
| import imp |
| import optparse |
| import os |
| |
| description = "See the ebuild(1) man page for more info" |
| usage = "Usage: ebuild <ebuild file> <command> [command] ..." |
| parser = optparse.OptionParser(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_option("--force", help=force_help, action="store_true", dest="force") |
| parser.add_option("--color", help="enable or disable color output", |
| type="choice", choices=("y", "n")) |
| parser.add_option("--debug", help="show debug output", |
| action="store_true", dest="debug") |
| parser.add_option("--ignore-default-opts", |
| action="store_true", |
| help="do not use the EBUILD_DEFAULT_OPTS environment variable") |
| parser.add_option("--skip-manifest", help="skip all manifest checks", |
| action="store_true", dest="skip_manifest") |
| |
| opts, pargs = parser.parse_args(args=sys.argv[1:]) |
| |
| if len(pargs) < 2: |
| parser.error("missing required args") |
| |
| os.environ["PORTAGE_CALLER"]="ebuild" |
| try: |
| import portage |
| except ImportError: |
| from os import path as osp |
| sys.path.insert(0, osp.join(osp.dirname(osp.dirname(osp.realpath(__file__))), "pym")) |
| import portage |
| |
| portage.dep._internal_warnings = 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 _emerge.Package import Package |
| from _emerge.RootConfig import RootConfig |
| |
| if not opts.ignore_default_opts: |
| default_opts = portage.settings.get("EBUILD_DEFAULT_OPTS", "").split() |
| opts, pargs = parser.parse_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: |
| portage.writemsg("'%s' does not end with '.ebuild'.\n" % \ |
| (ebuild,), noiselevel=-1) |
| sys.exit(1) |
| |
| 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) |
| imp.reload(portage) |
| |
| myrepo = None |
| if ebuild_portdir != vdb_path: |
| myrepo = portage.portdb.getRepositoryName(ebuild_portdir) |
| |
| if not os.path.exists(ebuild): |
| print("'%s' does not exist." % ebuild) |
| sys.exit(1) |
| |
| ebuild_split = ebuild.split("/") |
| cpv = "%s/%s" % (ebuild_split[-3], pf) |
| |
| if not portage.catpkgsplit(cpv): |
| print("!!! %s does not follow correct package syntax." % (cpv)) |
| sys.exit(1) |
| |
| 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: |
| print("!!! Portage seems to think that %s is at %s" % (cpv, portage_ebuild)) |
| sys.exit(1) |
| |
| else: |
| mytree = "porttree" |
| pkg_type = "ebuild" |
| |
| portage_ebuild = portage.portdb.findname(cpv, myrepo=myrepo) |
| |
| if not portage_ebuild or portage_ebuild != ebuild: |
| print("!!! %s does not seem to have a valid PORTDIR structure." % ebuild) |
| sys.exit(1) |
| |
| if len(pargs) > 1 and "config" in pargs: |
| print("config must be called on it's own, not combined with any other phase") |
| sys.exit(1) |
| |
| 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): |
| metadata, st, emtime = \ |
| portage.portdb._pull_valid_cache(cpv, ebuild, ebuild_portdir) |
| if metadata is None: |
| ebuild_changed = True |
| |
| 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["ROOT"]][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["ROOT"]], 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') |
| |
| from portage.exception import PermissionDenied, \ |
| PortagePackageException, UnsupportedAPIException |
| |
| if 'digest' in tmpsettings.features and \ |
| not set(["digest", "manifest"]).intersection(pargs): |
| pargs = ['digest'] + pargs |
| |
| 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, portage.root, 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) |