| #!/usr/bin/python -O |
| # Copyright 1999-2006 Gentoo Foundation |
| # Distributed under the terms of the GNU General Public License v2 |
| # $Id$ |
| |
| from __future__ import print_function |
| |
| import sys |
| # This block ensures that ^C interrupts are handled quietly. |
| try: |
| import signal |
| |
| def exithandler(signum,frame): |
| signal.signal(signal.SIGINT, signal.SIG_IGN) |
| signal.signal(signal.SIGTERM, signal.SIG_IGN) |
| sys.exit(1) |
| |
| signal.signal(signal.SIGINT, exithandler) |
| signal.signal(signal.SIGTERM, exithandler) |
| |
| except KeyboardInterrupt: |
| sys.exit(1) |
| |
| 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") |
| |
| if "merge" in pargs: |
| print("Disabling noauto in features... merge disables it. (qmerge doesn't)") |
| os.environ["FEATURES"] = os.environ.get("FEATURES", "") + " -noauto" |
| |
| 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 |
| |
| from portage import os |
| |
| 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 |
| import portage.dep |
| portage.dep._dep_check_strict = True |
| |
| # 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 \ |
| not sys.stdout.isatty()): |
| portage.output.nocolor() |
| portage.settings.unlock() |
| portage.settings['NOCOLOR'] = 'true' |
| portage.settings.lock() |
| |
| ebuild = pargs.pop(0) |
| |
| pf = None |
| if 'parse-eapi-glep-55' in portage.settings.features: |
| pf, eapi = portage._split_ebuild_name_glep55( |
| os.path.basename(ebuild)) |
| elif 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. |
| if "PWD" in os.environ and os.environ["PWD"] != mycwd and \ |
| os.path.realpath(os.environ["PWD"]) == mycwd: |
| mycwd = portage.normalize_path(os.environ["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:]) |
| |
| # Make sure that portdb.findname() returns the correct ebuild. |
| if ebuild_portdir not in portage.portdb.porttrees: |
| os.environ["PORTDIR_OVERLAY"] = \ |
| os.environ.get("PORTDIR_OVERLAY","") + " " + ebuild_portdir |
| print("Appending %s to PORTDIR_OVERLAY..." % ebuild_portdir) |
| portage.close_portdbapi_caches() |
| imp.reload(portage) |
| del portage.portdb.porttrees[1:] |
| if ebuild_portdir != portage.portdb.porttree_root: |
| portage.portdb.porttrees.append(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(os.path.join(portage.root, portage.const.VDB_PATH)): |
| mytree = "vartree" |
| |
| portage_ebuild = portage.db[portage.root][mytree].dbapi.findname(cpv) |
| |
| 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" |
| |
| portage_ebuild = portage.portdb.findname(cpv) |
| |
| 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) |
| from portage.manifest import Manifest |
| mf = Manifest(pkgdir, mysettings["DISTDIR"], |
| fetchlist_dict=fetchlist_dict, manifest1_compat=False) |
| 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 |
| tmpsettings = portage.config(clone=portage.settings) |
| tmpsettings["PORTAGE_VERBOSE"] = "1" |
| tmpsettings.backup_changes("PORTAGE_VERBOSE") |
| 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") |
| if "test" not in tmpsettings.features: |
| tmpsettings.features.add("test") |
| tmpsettings["FEATURES"] = " ".join(sorted(tmpsettings.features)) |
| tmpsettings.backup_changes("FEATURES") |
| |
| if 'fail-clean' in tmpsettings.features: |
| tmpsettings.features.remove('fail-clean') |
| tmpsettings["FEATURES"] = " ".join(sorted(tmpsettings.features)) |
| tmpsettings.backup_changes("FEATURES") |
| |
| if opts.skip_manifest: |
| tmpsettings["EBUILD_SKIP_MANIFEST"] = "1" |
| tmpsettings.backup_changes("EBUILD_SKIP_MANIFEST") |
| portage._doebuild_manifest_exempt_depend += 1 |
| |
| 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 build_dir_phases.intersection(pargs): |
| metadata, st, emtime = \ |
| portage.portdb._pull_valid_cache(cpv, ebuild, ebuild_portdir) |
| if metadata is None: |
| ebuild_changed = True |
| |
| 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 |
| 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) |
| 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) |