X-Git-Url: http://git.tremily.us/?a=blobdiff_plain;f=bin%2Febuild;h=2138aed33c4e22ce278ab03787178cb1b1363667;hb=08cd954a46def397ca7aa62e5f738cd2fa77a228;hp=b4ec8701482b41f540e18362dbbe12d12d35fa22;hpb=076a38005c19efaad184048a21d084428ebcd63f;p=portage.git diff --git a/bin/ebuild b/bin/ebuild index b4ec87014..2138aed33 100755 --- a/bin/ebuild +++ b/bin/ebuild @@ -1,90 +1,138 @@ -#!/usr/bin/python -O -# Copyright 1999-2006 Gentoo Foundation +#!/usr/bin/python -bbO +# Copyright 1999-2014 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 -# $Header: /var/cvsroot/gentoo-src/portage/bin/ebuild,v 1.18.2.3 2005/05/07 04:32:59 ferringb Exp $ +from __future__ import print_function + +import platform +import signal import sys # This block ensures that ^C interrupts are handled quietly. try: - import signal - def exithandler(signum,frame): + def exithandler(signum, _frame): signal.signal(signal.SIGINT, signal.SIG_IGN) signal.signal(signal.SIGTERM, signal.SIG_IGN) - sys.exit(1) + 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(1) + 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 optparse +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 [command] ..." -parser = optparse.OptionParser(description=description, usage=usage) +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_option("--force", help=force_help, action="store_true", dest="force") -parser.add_option("--debug", help="show debug output", - action="store_true", dest="debug") -parser.add_option("--ignore-default-opts", +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_option("--skip-manifest", help="skip all manifest checks", - action="store_true", dest="skip_manifest") +parser.add_argument("--skip-manifest", help="skip all manifest checks", + action="store_true") -opts, pargs = parser.parse_args(args=sys.argv[1:]) +opts, pargs = parser.parse_known_args(args=sys.argv[1:]) -if len(pargs) < 2: - parser.error("missing required args") +def err(txt): + portage.writemsg('ebuild: %s\n' % (txt,), noiselevel=-1) + sys.exit(1) -if "merge" in pargs: - print "Disabling noauto in features... merge disables it. (qmerge doesn't)" - os.environ["FEATURES"] = os.environ.get("FEATURES", "") + " -noauto" +if opts.version: + print("Portage", portage.VERSION) + sys.exit(os.EX_OK) -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 +if len(pargs) < 2: + parser.error("missing required args") 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:]) + 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 -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 portage.settings["NOCOLOR"] in ("yes","true") or not sys.stdout.isatty(): +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. - 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"]) + 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 @@ -92,51 +140,64 @@ ebuild = portage.normalize_path(ebuild) 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 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() - reload(portage) -del portage.portdb.porttrees[1:] -if ebuild_portdir != portage.portdb.porttree_root: - portage.portdb.porttrees.append(ebuild_portdir) +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): - print "'%s' does not exist." % ebuild - sys.exit(1) + err('%s: does not exist' % (ebuild,)) ebuild_split = ebuild.split("/") -del ebuild_split[-2] -cpv = "/".join(ebuild_split[-2:])[:-7] +cpv = "%s/%s" % (ebuild_split[-3], pf) -if not portage.catpkgsplit(cpv): - print "!!! %s does not follow correct package syntax." % (cpv) - sys.exit(1) +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(portage.root + portage.const.VDB_PATH): +if ebuild.startswith(vdb_path): mytree = "vartree" + pkg_type = "installed" - portage_ebuild = portage.db[portage.root][mytree].dbapi.findname(cpv) + 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) + 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) + 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) + err('%s: does not seem to have a valid PORTDIR structure' % (ebuild,)) 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) + 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 @@ -147,11 +208,10 @@ def discard_digests(myebuild, mysettings, mydbapi): portage._doebuild_manifest_exempt_depend += 1 pkgdir = os.path.dirname(myebuild) fetchlist_dict = portage.FetchlistDict(pkgdir, mysettings, mydbapi) - cat, pkg = pkgdir.split(os.sep)[-2:] - cpv = cat + "/" + os.path.basename(myebuild)[:-7] - from portage.manifest import Manifest - mf = Manifest(pkgdir, mysettings["DISTDIR"], - fetchlist_dict=fetchlist_dict, manifest1_compat=False) + 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] @@ -164,31 +224,73 @@ def discard_digests(myebuild, mysettings, mydbapi): 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") - if "test" not in tmpsettings.features: - tmpsettings.features.append("test") - tmpsettings.features.sort() - tmpsettings["FEATURES"] = " ".join(tmpsettings.features) - tmpsettings.backup_changes("FEATURES") + tmpsettings.features.add("test") -if opts.skip_manifest: - tmpsettings["EBUILD_SKIP_MANIFEST"] = "1" - tmpsettings.backup_changes("EBUILD_SKIP_MANIFEST") - portage._doebuild_manifest_exempt_depend += 1 +tmpsettings.features.discard("fail-clean") -build_dir_phases = set(["setup", "unpack", "configure", "compile", - "test", "install", "package", "rpm"]) +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 \ - tmpsettings.get("PORTAGE_QUIET") != "1" and \ build_dir_phases.intersection(pargs): portage.doebuild_environment(ebuild, "setup", portage.root, tmpsettings, debug, 1, portage.portdb) @@ -202,7 +304,19 @@ def stale_env_warning(): for x in msg: portage.writemsg(">>> %s\n" % x) -from portage.exception import PermissionDenied, UnsupportedAPIException + 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: @@ -215,26 +329,30 @@ for arg in pargs: 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) + a = portage.doebuild(ebuild, arg, settings=tmpsettings, + debug=debug, tree=mytree, + vartree=portage.db[portage.root]['vartree']) except KeyboardInterrupt: - print "Interrupted." + print("Interrupted.") a = 1 except KeyError: # aux_get error a = 1 - except UnsupportedAPIException, e: + 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 PermissionDenied, e: + 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?" + print("Could not run the required binary?") a = 127 if a: sys.exit(a)