From: Fabian Groffen Date: Mon, 17 Dec 2007 18:02:15 +0000 (-0000) Subject: Merged from trunk 8873:8896 X-Git-Url: http://git.tremily.us/gitweb.cgi?a=commitdiff_plain;h=38913889bb9014b53c9f0506f0101f30b5fee6df;p=portage.git Merged from trunk 8873:8896 | 8874 | Do an EBUILD_EXIT_STATUS_FILE sanity check in spawnebuild() | | zmedico | where it spawns misc-functions.sh after the install phase. | | 8876 | Add some documentation for ebuild phases and pre/post phase | | zmedico | hooks that can be defined via bashrc. | | 8877 | Add a "Quality Assurance" tag so that all chapters are | | zmedico | consistently nested inside tags. | | 8878 | * When installing a binary package, export the file name of | | zmedico | the package as PORTAGE_BINPKG_FILE in order to give bashrc | | | users an opportunity to do various things such as remove | | | binary packages after they're installed. * Add a note in | | | ebuild.sh explaining why hardcoded bash lists are needed for | | | backward compatibility with Configuration +&config_bashrc; &config_set; diff --git a/doc/config/bashrc.docbook b/doc/config/bashrc.docbook new file mode 100644 index 000000000..2f0626215 --- /dev/null +++ b/doc/config/bashrc.docbook @@ -0,0 +1,22 @@ + + Bashrc Configuration + + bashrc locations + + If a bashrc file is located at /etc/portage/bashrc + then it will be sourced before an ebuild is executed. + + + + Ebuild Phase Hooks + + A phase hook function name begins with a pre_ or post_ + prefix to indicate that it will be called before or after + one of the ebuild phases. + The prefix is followed by the name of the ebuild function that the hook + will be associated with. For example, a hook named pre_src_compile + will be called before src_compile, and a hook named post_src_compile + will be called after src_compile. + + + diff --git a/doc/package.docbook b/doc/package.docbook new file mode 100644 index 000000000..d37e6d525 --- /dev/null +++ b/doc/package.docbook @@ -0,0 +1,4 @@ + +Package Formats +&package_ebuild; + diff --git a/doc/package/ebuild.docbook b/doc/package/ebuild.docbook new file mode 100644 index 000000000..5466f99db --- /dev/null +++ b/doc/package/ebuild.docbook @@ -0,0 +1,4 @@ + +Ebuild +&package_ebuild_phases; + diff --git a/doc/package/ebuild/phases.docbook b/doc/package/ebuild/phases.docbook new file mode 100644 index 000000000..5c7f04969 --- /dev/null +++ b/doc/package/ebuild/phases.docbook @@ -0,0 +1,43 @@ + + Ebuild Phases + + Ebuild execution is divided into a series of phases. In order + to implement a phase, an ebuild defines a function to serve as + an entry point for execution of that phase. + This design is similar to the template method pattern that + is commonly used in object oriented programming languages. An ebuild + can inherit or override a template method from an eclass. + + + The function names for the ebuild phases, listed in order of execution: + + + pkg_setup + + + src_unpack + + + src_compile + + + src_test + + + src_install + + + pkg_preinst + + + pkg_postinst + + + pkg_prerm + + + pkg_postrm + + + + diff --git a/doc/portage.docbook b/doc/portage.docbook index ac1061310..5417bb73e 100644 --- a/doc/portage.docbook +++ b/doc/portage.docbook @@ -7,8 +7,12 @@ + + + + ]> @@ -30,6 +34,7 @@ &config; +&package; &qa; diff --git a/doc/qa.docbook b/doc/qa.docbook index a8178d5b7..cb9b242d6 100644 --- a/doc/qa.docbook +++ b/doc/qa.docbook @@ -1,3 +1,5 @@ + +Quality Assurance QA Notices @@ -359,3 +361,4 @@ + diff --git a/pym/_emerge/__init__.py b/pym/_emerge/__init__.py index 57b5f429b..87514ab51 100644 --- a/pym/_emerge/__init__.py +++ b/pym/_emerge/__init__.py @@ -869,6 +869,8 @@ def visible(pkgsettings, cpv, metadata, built=False, installed=False): @rtype: Boolean @returns: True if the package is visible, False otherwise. """ + if not metadata["SLOT"]: + return False if built and not installed and \ metadata["CHOST"] != pkgsettings["CHOST"]: return False @@ -2216,6 +2218,8 @@ class depgraph(object): mreasons.append("EPREFIX: '%s' too small" % metadata["EPREFIX"]) missing_licenses = [] if metadata: + if not metadata["SLOT"]: + mreasons.append("invalid: SLOT is undefined") if not portage.eapi_is_supported(metadata["EAPI"]): have_eapi_mask = True try: @@ -4124,19 +4128,6 @@ class MergeTask(object): ldpath_mtimes = mtimedb["ldpath"] xterm_titles = "notitles" not in self.settings.features - #check for blocking dependencies - if "--fetchonly" not in self.myopts and \ - "--fetch-all-uri" not in self.myopts and \ - "--buildpkgonly" not in self.myopts: - for x in mylist: - if x[0]=="blocks": - print "\n!!! Error: the "+x[2]+" package conflicts with another package;" - print "!!! the two packages cannot be installed on the same system together." - print "!!! Please use 'emerge --pretend' to determine blockers." - if "--quiet" not in self.myopts: - show_blocker_docs_link() - return 1 - if "--resume" in self.myopts: # We're resuming. print colorize("GOOD", "*** Resuming merge...") @@ -6609,13 +6600,27 @@ def action_build(settings, trees, mtimedb, ("--pretend" in myopts), mydbapi=trees[pkgline[1]]["porttree"].dbapi, tree="porttree") - if "--fetchonly" in myopts or "--fetch-all-uri" in myopts: - pkglist = [] - for pkg in mydepgraph.altlist(): - if pkg[0] != "blocks": - pkglist.append(pkg) + + pkglist = mydepgraph.altlist() + + if fetchonly or "--buildpkgonly" in myopts: + pkglist = [pkg for pkg in pkglist if pkg[0] != "blocks"] else: - pkglist = mydepgraph.altlist() + for x in pkglist: + if x[0] != "blocks": + continue + msg = "Error: the " + x[2] + " package conflicts " + \ + "with another package; the two packages cannot " + \ + "be installed on the same system together. " + \ + "Please use 'emerge --pretend' to determine blockers." + prefix = red(" * ") + from textwrap import wrap + for line in wrap(msg, 70): + print prefix + line + if "--quiet" not in myopts: + show_blocker_docs_link() + return 1 + mydepgraph.saveNomergeFavorites() del mydepgraph mergetask = MergeTask(settings, trees, myopts) @@ -7263,7 +7268,3 @@ def emerge_main(): if "--pretend" in myopts: display_news_notification(trees) return retval - -if __name__ == "__main__": - retval = emerge_main() - sys.exit(retval) diff --git a/pym/portage/__init__.py b/pym/portage/__init__.py index baf7403cb..9c776f1a0 100644 --- a/pym/portage/__init__.py +++ b/pym/portage/__init__.py @@ -880,7 +880,9 @@ class config(object): "FEATURES", "FILESDIR", "HOME", "PATH", "PKGUSE", "PKG_LOGDIR", "PKG_TMPDIR", "PORTAGE_ACTUAL_DISTDIR", "PORTAGE_ARCHLIST", - "PORTAGE_BASHRC", "PORTAGE_BINPKG_TMPFILE", "PORTAGE_BIN_PATH", + "PORTAGE_BASHRC", + "PORTAGE_BINPKG_FILE", "PORTAGE_BINPKG_TMPFILE", + "PORTAGE_BIN_PATH", "PORTAGE_BUILDDIR", "PORTAGE_COLORMAP", "PORTAGE_CONFIGROOT", "PORTAGE_DEBUG", "PORTAGE_DEPCACHEDIR", "PORTAGE_GID", "PORTAGE_INST_GID", "PORTAGE_INST_UID", @@ -1222,74 +1224,36 @@ class config(object): # make.globals should not be relative to config_root # because it only contains constants. - try: - self.mygcfg = getconfig(os.path.join(BPREFIX, "etc", "make.globals")) + self.mygcfg = getconfig(os.path.join(BPREFIX, "etc", "make.globals")) + + if self.mygcfg is None: + self.mygcfg = {} - if self.mygcfg is None: - self.mygcfg = {} - except SystemExit, e: - raise - except Exception, e: - if debug: - raise - writemsg("!!! %s\n" % (e), noiselevel=-1) - if not isinstance(e, EnvironmentError): - writemsg("!!! Incorrect multiline literals can cause " + \ - "this. Do not use them.\n", noiselevel=-1) - sys.exit(1) self.configlist.append(self.mygcfg) self.configdict["globals"]=self.configlist[-1] self.make_defaults_use = [] self.mygcfg = {} if self.profiles: - try: - mygcfg_dlists = [getconfig(os.path.join(x, "make.defaults")) for x in self.profiles] - for cfg in mygcfg_dlists: - if cfg: - self.make_defaults_use.append(cfg.get("USE", "")) - else: - self.make_defaults_use.append("") - self.mygcfg = stack_dicts(mygcfg_dlists, incrementals=portage.const.INCREMENTALS, ignore_none=1) - #self.mygcfg = grab_stacked("make.defaults", self.profiles, getconfig) - if self.mygcfg is None: - self.mygcfg = {} - except SystemExit, e: - raise - except Exception, e: - if debug: - raise - writemsg("!!! %s\n" % (e), noiselevel=-1) - if not isinstance(e, EnvironmentError): - writemsg("!!! 'rm -Rf %s/usr/portage/profiles; " + \ - "emerge sync' may fix this. If it does\n" % EPREFIX, - noiselevel=-1) - writemsg("!!! not then please report this to " + \ - "bugs.gentoo.org and, if possible, a dev\n", - noiselevel=-1) - writemsg("!!! on #gentoo (irc.freenode.org)\n", - noiselevel=-1) - sys.exit(1) - self.configlist.append(self.mygcfg) - self.configdict["defaults"]=self.configlist[-1] - - try: - self.mygcfg = getconfig( - os.path.join(config_root, MAKE_CONF_FILE.lstrip(os.path.sep)), - allow_sourcing=True) + mygcfg_dlists = [getconfig(os.path.join(x, "make.defaults")) \ + for x in self.profiles] + for cfg in mygcfg_dlists: + if cfg: + self.make_defaults_use.append(cfg.get("USE", "")) + else: + self.make_defaults_use.append("") + self.mygcfg = stack_dicts(mygcfg_dlists, + incrementals=portage.const.INCREMENTALS, ignore_none=1) if self.mygcfg is None: self.mygcfg = {} - except SystemExit, e: - raise - except Exception, e: - if debug: - raise - writemsg("!!! %s\n" % (e), noiselevel=-1) - if not isinstance(e, EnvironmentError): - writemsg("!!! Incorrect multiline literals can cause " + \ - "this. Do not use them.\n", noiselevel=-1) - sys.exit(1) + self.configlist.append(self.mygcfg) + self.configdict["defaults"]=self.configlist[-1] + self.mygcfg = getconfig( + os.path.join(config_root, MAKE_CONF_FILE.lstrip(os.path.sep)), + allow_sourcing=True) + if self.mygcfg is None: + self.mygcfg = {} # Don't allow the user to override certain variables in make.conf profile_only_variables = self.configdict["defaults"].get( @@ -3754,6 +3718,8 @@ def spawnebuild(mydo,actionmap,mysettings,debug,alwaysdep=0,logfile=None): os.path.basename(MISC_SH_BINARY)) mycommand = " ".join([_shell_quote(misc_sh_binary), "install_qa_check", "install_symlink_html_docs"]) + _doebuild_exit_status_unlink( + mysettings.get("EBUILD_EXIT_STATUS_FILE")) filter_calling_env_state = mysettings._filter_calling_env if os.path.exists(os.path.join(mysettings["T"], "environment")): mysettings._filter_calling_env = True @@ -3762,7 +3728,14 @@ def spawnebuild(mydo,actionmap,mysettings,debug,alwaysdep=0,logfile=None): logfile=logfile, **kwargs) finally: mysettings._filter_calling_env = filter_calling_env_state - if qa_retval: + msg = _doebuild_exit_status_check(mydo, mysettings) + if msg: + qa_retval = 1 + from textwrap import wrap + from portage.elog.messages import eerror + for l in wrap(msg, 72): + eerror(l, phase=mydo, key=mysettings.mycpv) + if qa_retval != os.EX_OK: writemsg("!!! install_qa_check failed; exiting.\n", noiselevel=-1) return qa_retval @@ -4414,7 +4387,8 @@ def doebuild(myebuild, mydo, myroot, mysettings, debug=0, listonly=0, mycpv = mysettings["CATEGORY"] + "/" + mysettings["PF"] dep_keys = ["DEPEND", "RDEPEND", "PDEPEND"] misc_keys = ["LICENSE", "PROVIDE", "RESTRICT", "SRC_URI"] - all_keys = dep_keys + misc_keys + other_keys = ["SLOT"] + all_keys = dep_keys + misc_keys + other_keys metadata = dict(izip(all_keys, mydbapi.aux_get(mycpv, all_keys))) class FakeTree(object): def __init__(self, mydb): @@ -4442,6 +4416,10 @@ def doebuild(myebuild, mydo, myroot, mysettings, debug=0, listonly=0, if mydo not in invalid_dep_exempt_phases: return 1 del k + if not metadata["SLOT"]: + writemsg("SLOT is undefined\n", noiselevel=-1) + if mydo not in invalid_dep_exempt_phases: + return 1 del mycpv, dep_keys, metadata, misc_keys, FakeTree, dep_check_trees if "PORTAGE_TMPDIR" not in mysettings or \ @@ -5865,6 +5843,10 @@ def pkgmerge(mytbz2, myroot, mysettings, mydbapi=None, vartree=None, prev_mtimes fp.write(str(portage.checksum.perform_md5(mytbz2))+"\n") fp.close() + # This gives bashrc users an opportunity to do various things + # such as remove binary packages after they're installed. + mysettings["PORTAGE_BINPKG_FILE"] = mytbz2 + mysettings.backup_changes("PORTAGE_BINPKG_FILE") debug = mysettings.get("PORTAGE_DEBUG", "") == "1" # We want to install in "our" prefix, not the binary one @@ -5913,6 +5895,7 @@ def pkgmerge(mytbz2, myroot, mysettings, mydbapi=None, vartree=None, prev_mtimes did_merge_phase = True return retval finally: + mysettings.pop("PORTAGE_BINPKG_FILE", None) if tbz2_lock: portage.locks.unlockfile(tbz2_lock) if builddir_lock: diff --git a/pym/portage/util.py b/pym/portage/util.py index 1f83cdbdf..9cf7fff7d 100644 --- a/pym/portage/util.py +++ b/pym/portage/util.py @@ -309,6 +309,8 @@ def getconfig(mycfg, tolerant=0, allow_sourcing=False, expand=True): try: f=open(mycfg,'r') except IOError, e: + if e.errno == PermissionDenied.errno: + raise PermissionDenied(mycfg) if e.errno != errno.ENOENT: raise return None @@ -339,9 +341,9 @@ def getconfig(mycfg, tolerant=0, allow_sourcing=False, expand=True): #invalid token #lex.error_leader(self.filename,lex.lineno) if not tolerant: - writemsg("!!! Invalid token (not \"=\") "+str(equ)+"\n", - noiselevel=-1) - raise Exception("ParseError: Invalid token (not '='): "+str(mycfg)+": line "+str(lex.lineno)) + raise Exception("ParseError: Invalid token " + \ + "'%s' (not '='): %s: line %s" % \ + (equ, mycfg, lex.lineno)) else: return mykeys val=lex.get_token()