diff options
author | 2014-02-17 17:57:05 +0600 | |
---|---|---|
committer | 2014-02-17 17:57:05 +0600 | |
commit | 6563293d18daed502ccdb663f3c72b4bae5fe23a (patch) | |
tree | d0a7d53a7c137feb4073c963408829f88ea75c92 | |
parent | updated portage to 2.2.8-r1 (diff) | |
download | autodep-6563293d18daed502ccdb663f3c72b4bae5fe23a.tar.gz autodep-6563293d18daed502ccdb663f3c72b4bae5fe23a.tar.bz2 autodep-6563293d18daed502ccdb663f3c72b4bae5fe23a.zip |
474 files changed, 17134 insertions, 11557 deletions
@@ -1 +1,2 @@ *.pyc +*.pyo diff --git a/integration_with_portage.patch b/integration_with_portage.patch index a74beed..ff8f487 100644 --- a/integration_with_portage.patch +++ b/integration_with_portage.patch @@ -1,17 +1,16 @@ -diff --git a/pym/_emerge/EbuildBuild.py b/pym/_emerge/EbuildBuild.py -index 0144cfc..1c423a3 100644 ---- a/pym/_emerge/EbuildBuild.py -+++ b/pym/_emerge/EbuildBuild.py -@@ -9,6 +9,8 @@ from _emerge.CompositeTask import CompositeTask +diff -urN /usr/lib/portage/pym/_emerge/EbuildBuild.py ./pym/_emerge/EbuildBuild.py +--- /usr/lib/portage/pym/_emerge/EbuildBuild.py 2014-01-23 14:09:03.647948532 +0600 ++++ ./pym/_emerge/EbuildBuild.py 2014-02-17 17:25:59.335376529 +0600 +@@ -9,6 +9,8 @@ from _emerge.EbuildMerge import EbuildMerge from _emerge.EbuildFetchonly import EbuildFetchonly from _emerge.EbuildBuildDir import EbuildBuildDir +from _emerge.EventsAnalyser import EventsAnalyser, FilterProcGenerator +from _emerge.EventsLogger import EventsLogger from _emerge.MiscFunctionsProcess import MiscFunctionsProcess - from portage.util import writemsg - import portage -@@ -21,7 +23,7 @@ from portage.package.ebuild._spawn_nofetch import spawn_nofetch + from _emerge.TaskSequence import TaskSequence + +@@ -24,7 +26,7 @@ class EbuildBuild(CompositeTask): __slots__ = ("args_set", "config_pool", "find_blockers", @@ -20,7 +19,7 @@ index 0144cfc..1c423a3 100644 "prefetcher", "settings", "world_atom") + \ ("_build_dir", "_buildpkg", "_ebuild_path", "_issyspkg", "_tree") -@@ -244,8 +246,54 @@ class EbuildBuild(CompositeTask): +@@ -259,8 +261,52 @@ build = EbuildExecuter(background=self.background, pkg=pkg, scheduler=scheduler, settings=settings) @@ -35,7 +34,7 @@ index 0144cfc..1c423a3 100644 + "depcheckstrict" in self.settings["FEATURES"]: + # Lets start a log listening server + temp_path=self.settings.get("T",self.settings["PORTAGE_TMPDIR"]) -+ ++ + if "depcheckstrict" not in self.settings["FEATURES"]: + # use default filter_proc + self.logserver=EventsLogger(socket_dir=temp_path) @@ -44,11 +43,11 @@ index 0144cfc..1c423a3 100644 + "This may take some time\n") + filter_gen=FilterProcGenerator(self.pkg.cpv, self.settings) + filter_proc=filter_gen.get_filter_proc() -+ self.logserver=EventsLogger(socket_dir=temp_path, ++ self.logserver=EventsLogger(socket_dir=temp_path, + filter_proc=filter_proc) -+ ++ + self.logserver.start() -+ ++ + # Copy socket path to LOG_SOCKET environment variable + env=self.settings.configdict["pkg"] + env['LOG_SOCKET'] = self.logserver.socket_name @@ -62,39 +61,34 @@ index 0144cfc..1c423a3 100644 + env=self.settings.configdict["pkg"] + if 'LOG_SOCKET' in env: + del env['LOG_SOCKET'] -+ ++ + events=self.logserver.stop() + self.logserver=None + analyser=EventsAnalyser(self.pkg.cpv, events, self.settings) + analyser.display() # show the analyse + + #import pdb; pdb.set_trace() -+ -+ + def _fetch_failed(self): # We only call the pkg_nofetch phase if either RESTRICT=fetch # is set or the package has explicitly overridden the default -diff --git a/pym/_emerge/EbuildPhase.py b/pym/_emerge/EbuildPhase.py -index f53570a..82c165d 100644 ---- a/pym/_emerge/EbuildPhase.py -+++ b/pym/_emerge/EbuildPhase.py -@@ -33,7 +33,8 @@ class EbuildPhase(CompositeTask): - ("_ebuild_lock",) +diff -urN /usr/lib/portage/pym/_emerge/EbuildPhase.py ./pym/_emerge/EbuildPhase.py +--- /usr/lib/portage/pym/_emerge/EbuildPhase.py 2014-01-23 14:09:03.648948532 +0600 ++++ ./pym/_emerge/EbuildPhase.py 2014-02-17 17:27:57.509371559 +0600 +@@ -44,7 +44,8 @@ # FEATURES displayed prior to setup phase -- _features_display = ("ccache", "distcc", "distcc-pump", "fakeroot", -+ _features_display = ("ccache", "depcheck", "depcheckstrict" "distcc", -+ "distcc-pump", "fakeroot", + _features_display = ( +- "ccache", "compressdebug", "distcc", "distcc-pump", "fakeroot", ++ "ccache", "compressdebug", "depcheck", "depcheckstrict", ++ "distcc", "distcc-pump", "fakeroot", "installsources", "keeptemp", "keepwork", "nostrip", "preserve-libs", "sandbox", "selinux", "sesandbox", "splitdebug", "suidctl", "test", "userpriv", -diff --git a/pym/_emerge/EventsAnalyser.py b/pym/_emerge/EventsAnalyser.py -new file mode 100644 -index 0000000..65ece7b ---- /dev/null -+++ b/pym/_emerge/EventsAnalyser.py -@@ -0,0 +1,511 @@ +diff -urN /usr/lib/portage/pym/_emerge/EventsAnalyser.py ./pym/_emerge/EventsAnalyser.py +--- /usr/lib/portage/pym/_emerge/EventsAnalyser.py 1970-01-01 05:00:00.000000000 +0500 ++++ ./pym/_emerge/EventsAnalyser.py 2014-02-17 17:34:27.954355139 +0600 +@@ -0,0 +1,514 @@ +# Distributed under the terms of the GNU General Public License v2 + +import portage @@ -131,36 +125,36 @@ index 0000000..65ece7b + def get_dep(self,pkg,dep_type=["RDEPEND","DEPEND"]): + """ + Gets current dependencies of a package. Looks in portage db -+ ++ + :param pkg: name of package -+ :param dep_type: type of dependencies to recurse. Can be ["DEPEND"] or ++ :param dep_type: type of dependencies to recurse. Can be ["DEPEND"] or + ["RDEPEND", "DEPEND"] + :returns: **set** of packages names + """ + ret=set() -+ -+ pkg = self.get_best_visible_pkg(pkg) ++ ++ pkg = self.get_best_visible_pkg(pkg) + if not pkg: + return ret -+ ++ + # we found the best visible match in common tree + + -+ metadata = dict(zip(self.metadata_keys, ++ metadata = dict(zip(self.metadata_keys, + self.portdbapi.aux_get(pkg, self.metadata_keys))) + dep_str = " ".join(metadata[k] for k in dep_type) + + # the IUSE default are very important for us + iuse_defaults=[ + u[1:] for u in metadata.get("IUSE",'').split() if u.startswith("+")] -+ ++ + use=self.use.split() -+ ++ + for u in iuse_defaults: + if u not in use: + use.append(u) + -+ success, atoms = portage.dep_check(dep_str, None, self.settings, ++ success, atoms = portage.dep_check(dep_str, None, self.settings, + myuse=use, myroot=self.settings["ROOT"], + trees={self.settings["ROOT"]:{"vartree":self.vartree, "porttree": self.vartree}}) + if not success: @@ -171,7 +165,7 @@ index 0000000..65ece7b + + if not atomname: + continue -+ ++ + for unvirt_pkg in expand_new_virt(self.vardbapi,'='+atomname): + for pkg in self.vartree.dep_match(unvirt_pkg): + ret.add(pkg) @@ -180,12 +174,12 @@ index 0000000..65ece7b + + # recursive dependency getter + def get_deps(self,pkg,dep_type=["RDEPEND","DEPEND"]): -+ """ -+ Gets current dependencies of a package on any depth ++ """ ++ Gets current dependencies of a package on any depth + All dependencies **must** be installed -+ ++ + :param pkg: name of package -+ :param dep_type: type of dependencies to recurse. Can be ["DEPEND"] or ++ :param dep_type: type of dependencies to recurse. Can be ["DEPEND"] or + ["RDEPEND", "DEPEND"] + :returns: **set** of packages names + """ @@ -194,14 +188,14 @@ index 0000000..65ece7b + + # get porttree dependencies on the first package + -+ pkg = self.portdbapi.xmatch("bestmatch-visible", pkg) ++ pkg = self.portdbapi.xmatch("bestmatch-visible", pkg) + if not pkg: + return ret + + known_packages=set() + unknown_packages=self.get_dep(pkg,dep_type) + ret=ret.union(unknown_packages) -+ ++ + while unknown_packages: + p=unknown_packages.pop() + if p in known_packages: @@ -211,18 +205,18 @@ index 0000000..65ece7b + metadata = dict(zip(self.metadata_keys, self.vardbapi.aux_get(p, self.metadata_keys))) + + dep_str = " ".join(metadata[k] for k in dep_type) -+ ++ + # the IUSE default are very important for us + iuse_defaults=[ + u[1:] for u in metadata.get("IUSE",'').split() if u.startswith("+")] -+ ++ + use=self.use.split() -+ ++ + for u in iuse_defaults: + if u not in use: + use.append(u) -+ -+ success, atoms = portage.dep_check(dep_str, None, self.settings, ++ ++ success, atoms = portage.dep_check(dep_str, None, self.settings, + myuse=use, myroot=self.settings["ROOT"], + trees={self.settings["ROOT"]:{"vartree":self.vartree,"porttree": self.vartree}}) + @@ -233,7 +227,7 @@ index 0000000..65ece7b + atomname = self.vartree.dep_bestmatch(atom) + if not atomname: + continue -+ ++ + for unvirt_pkg in expand_new_virt(self.vardbapi,'='+atomname): + for pkg in self.vartree.dep_match(unvirt_pkg): + ret.add(pkg) @@ -241,8 +235,8 @@ index 0000000..65ece7b + return ret + + def get_deps_for_package_building(self, pkg): -+ """ -+ returns buildtime dependencies of current package and ++ """ ++ returns buildtime dependencies of current package and + all runtime dependencies of that buildtime dependencies + """ + buildtime_deps=self.get_dep(pkg, ["DEPEND"]) @@ -254,9 +248,9 @@ index 0000000..65ece7b + return ret + + def get_system_packages_list(self): -+ """ ++ """ + returns all packages from system set. They are always implicit dependencies -+ ++ + :returns: **list** of package names + """ + ret=[] @@ -269,11 +263,12 @@ index 0000000..65ece7b + + +class GentoolkitUtils: -+ """ -+ Interface with qfile and qlist utils. They are much faster than ++ """ ++ Interface with qfile and qlist utils. They are much faster than + internals. + """ + ++ @staticmethod + def getpackagesbyfiles(files): + """ + :param files: list of filenames @@ -287,14 +282,14 @@ index 0000000..65ece7b + ret[f]="directory" + else: + listtocheck.append(f) -+ ++ + try: + proc=subprocess.Popen(['qfile']+['--nocolor','--exact','','--from','-'], -+ stdin=subprocess.PIPE, stdout=subprocess.PIPE,stderr=subprocess.PIPE, ++ stdin=subprocess.PIPE, stdout=subprocess.PIPE,stderr=subprocess.PIPE, + bufsize=4096) -+ ++ + out,err=proc.communicate("\n".join(listtocheck).encode("utf8")) -+ ++ + lines=out.decode("utf8").split("\n") + #print lines + line_re=re.compile(r"^([^ ]+)\s+\(([^)]+)\)$") @@ -309,24 +304,25 @@ index 0000000..65ece7b + + except OSError as e: + portage.util.writemsg("Error while launching qfile: %s\n" % e) -+ -+ ++ ++ + return ret -+ ++ ++ @staticmethod + def getfilesbypackages(packagenames): + """ -+ ++ + :param packagename: name of package + :returns: **list** of files in package with name *packagename* + """ + ret=[] + try: + proc=subprocess.Popen(['qlist']+['--nocolor',"--obj"]+packagenames, -+ stdout=subprocess.PIPE,stderr=subprocess.PIPE, ++ stdout=subprocess.PIPE,stderr=subprocess.PIPE, + bufsize=4096) -+ ++ + out,err=proc.communicate() -+ ++ + ret=out.decode("utf8").split("\n") + if ret==['']: + ret=[] @@ -334,34 +330,35 @@ index 0000000..65ece7b + portage.util.writemsg("Error while launching qfile: %s\n" % e) + + return ret -+ -+ def get_all_packages_files(): ++ ++ @staticmethod ++ def get_all_packages_files(): + """ + Memory-hungry operation -+ ++ + :returns: **set** of all files that belongs to package + """ + ret=[] + try: + proc=subprocess.Popen(['qlist']+['--all',"--obj"], -+ stdout=subprocess.PIPE,stderr=subprocess.PIPE, ++ stdout=subprocess.PIPE,stderr=subprocess.PIPE, + bufsize=4096) -+ ++ + out,err=proc.communicate() -+ ++ + ret=out.decode("utf8").split("\n") + except OSError as e: + portage.util.writemsg("Error while launching qfile: %s\n" % e) + + return set(ret) -+ ++ +class FilterProcGenerator: + def __init__(self, pkgname, settings): + portageutils=PortageUtils(settings=settings) + + deps_all=portageutils.get_deps_for_package_building(pkgname) + deps_portage=portageutils.get_dep('portage',["RDEPEND"]) -+ ++ + system_packages=portageutils.get_system_packages_list() + + allfiles=GentoolkitUtils.get_all_packages_files() @@ -369,8 +366,8 @@ index 0000000..65ece7b + "a list of allowed files\n") + + -+ allowedpkgs=system_packages+list(deps_portage)+list(deps_all) -+ ++ allowedpkgs=system_packages+list(deps_portage)+list(deps_all) ++ + allowedfiles=GentoolkitUtils.getfilesbypackages(allowedpkgs) + #for pkg in allowedpkgs: + # allowedfiles+=GentoolkitUtils.getfilesbypackage(pkg) @@ -380,14 +377,14 @@ index 0000000..65ece7b + # manually add all python interpreters to this list + allowedfiles+=GentoolkitUtils.getfilesbypackages(['python']) + allowedfiles=set(allowedfiles) -+ ++ + deniedfiles=allfiles-allowedfiles + + def filter_proc(eventname,filename,stage): + if filename in deniedfiles: + return False + return True -+ ++ + self.filter_proc=filter_proc + def get_filter_proc(self): + return self.filter_proc @@ -402,10 +399,10 @@ index 0000000..65ece7b + self.deps_all=self.portageutils.get_deps_for_package_building(pkgname) + self.deps_direct=self.portageutils.get_dep(pkgname,["DEPEND"]) + self.deps_portage=self.portageutils.get_dep('portage',["RDEPEND"]) -+ ++ + self.system_packages=self.portageutils.get_system_packages_list() + # All analyse work is here -+ ++ + # get unique filenames + filenames=set() + for stage in events: @@ -416,7 +413,7 @@ index 0000000..65ece7b + filenames=list(filenames) + + file_to_package=GentoolkitUtils.getpackagesbyfiles(filenames) -+ # This part is completly unreadable. ++ # This part is completly unreadable. + # It converting one complex struct(returned by getfsevents) to another complex + # struct which good for generating output. + # @@ -427,24 +424,24 @@ index 0000000..65ece7b + for stage in sorted(events): + succ_events=events[stage][0] + fail_events=events[stage][1] -+ ++ + for filename in succ_events: + if filename in file_to_package: + package=file_to_package[filename] + else: + package="unknown" -+ ++ + if not package in packagesinfo: + packagesinfo[package]={} + stageinfo=packagesinfo[package] + if not stage in stageinfo: + stageinfo[stage]={} -+ ++ + filesinfo=stageinfo[stage] + if not filename in filesinfo: + filesinfo[filename]={"found":[],"notfound":[]} + filesinfo[filename]["found"]=succ_events[filename] -+ ++ + for filename in fail_events: + if filename in file_to_package: + package=file_to_package[filename] @@ -455,13 +452,13 @@ index 0000000..65ece7b + stageinfo=packagesinfo[package] + if not stage in stageinfo: + stageinfo[stage]={} -+ ++ + filesinfo=stageinfo[stage] + if not filename in filesinfo: + filesinfo[filename]={"found":[],"notfound":[]} + filesinfo[filename]["notfound"]=fail_events[filename] + self.packagesinfo=packagesinfo -+ ++ + def display(self): + portage.util.writemsg( + portage.output.colorize( @@ -470,12 +467,12 @@ index 0000000..65ece7b + stagesorder={"clean":1,"setup":2,"unpack":3,"prepare":4,"configure":5,"compile":6,"test":7, + "install":8,"preinst":9,"postinst":10,"prerm":11,"postrm":12,"unknown":13} + packagesinfo=self.packagesinfo -+ # print information grouped by package ++ # print information grouped by package + for package in sorted(packagesinfo): + # not showing special directory package + if package=="directory": + continue -+ ++ + if package=="unknown": + continue + @@ -492,7 +489,7 @@ index 0000000..65ece7b + + if len(stages)==0: + continue -+ ++ + filenames={} + for stage in stages: + for filename in packagesinfo[package][stage]: @@ -503,7 +500,7 @@ index 0000000..65ece7b + else: + status, old_was_readed, old_was_writed=filenames[filename] + filenames[filename]=[ -+ 'ok',old_was_readed | was_readed, old_was_writed | was_writed ++ 'ok',old_was_readed | was_readed, old_was_writed | was_writed + ] + if len(packagesinfo[package][stage][filename]["notfound"])!=0: + was_notfound,was_blocked=packagesinfo[package][stage][filename]["notfound"] @@ -512,9 +509,9 @@ index 0000000..65ece7b + else: + status, old_was_notfound, old_was_blocked=filenames[filename] + filenames[filename]=[ -+ 'err',old_was_notfound | was_notfound, old_was_blocked | was_blocked ++ 'err',old_was_notfound | was_notfound, old_was_blocked | was_blocked + ] -+ ++ + + if is_pkg_in_dep: + portage.util.writemsg("[OK]") @@ -543,9 +540,9 @@ index 0000000..65ece7b + ('err',False,True):"blocked", + ('err',True,True):"not found and blocked" + } -+ ++ + filescounter=0 -+ ++ + for filename in filenames: + event_info=tuple(filenames[filename]) + portage.util.writemsg(" %-56s %-21s\n" % (filename,action[event_info])) @@ -553,7 +550,7 @@ index 0000000..65ece7b + if filescounter>10: + portage.util.writemsg(" ... and %d more ...\n" % (len(filenames)-10)) + break -+ # ... and one more check. Making sure that direct build time ++ # ... and one more check. Making sure that direct build time + # dependencies were accessed + #import pdb; pdb.set_trace() + not_accessed_deps=set(self.deps_direct)-set(self.packagesinfo.keys()) @@ -562,7 +559,7 @@ index 0000000..65ece7b + portage.util.writemsg("Warning! Some build time dependencies " + \ + "of packages were not accessed: " + \ + " ".join(not_accessed_deps) + "\n") -+ ++ + def is_package_useful(self,pkg,stages,files): + """ some basic heuristics here to cut part of packages """ + @@ -596,22 +593,19 @@ index 0000000..65ece7b + for f in files: + if is_file_excluded(f): + continue -+ -+ # test 1: package is not useful if all files are *.desktop or *.xml or *.m4 ++ ++ # test 1: package is not useful if all files are *.desktop or *.xml or *.m4 + if not (f.endswith(".desktop") or f.endswith(".xml") or f.endswith(".m4") or f.endswith(".pc")): + break + else: + return False # we get here if cycle ends not with break -+ ++ + return True -+ -+ -\ No newline at end of file -diff --git a/pym/_emerge/EventsLogger.py b/pym/_emerge/EventsLogger.py -new file mode 100644 -index 0000000..68b3c67 ---- /dev/null -+++ b/pym/_emerge/EventsLogger.py ++ ++ +diff -urN /usr/lib/portage/pym/_emerge/EventsLogger.py ./pym/_emerge/EventsLogger.py +--- /usr/lib/portage/pym/_emerge/EventsLogger.py 1970-01-01 05:00:00.000000000 +0500 ++++ ./pym/_emerge/EventsLogger.py 2014-02-17 17:36:42.034349501 +0600 @@ -0,0 +1,180 @@ +# Distributed under the terms of the GNU General Public License v2 + @@ -629,17 +623,17 @@ index 0000000..68b3c67 +class EventsLogger(threading.Thread): + def default_filter(eventname, filename, stage): + return True -+ ++ + def __init__(self, socket_dir="/tmp/", filter_proc=default_filter): + threading.Thread.__init__(self) # init the Thread -+ ++ + self.alive=False -+ ++ + self.main_thread=threading.currentThread() -+ ++ + self.socket_dir=socket_dir + self.filter_proc=filter_proc -+ ++ + self.socket_name=None + self.socket_logger=None + @@ -648,16 +642,16 @@ index 0000000..68b3c67 + try: + socket_dir_name = tempfile.mkdtemp(dir=self.socket_dir, + prefix="log_socket_") -+ ++ + socket_name = os.path.join(socket_dir_name, 'socket') + + except OSError as e: + return -+ ++ + self.socket_name=socket_name -+ ++ + #print(self.socket_name) -+ ++ + try: + socket_logger=socket.socket(socket.AF_UNIX, socket.SOCK_SEQPACKET) + socket_logger.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) @@ -680,21 +674,21 @@ index 0000000..68b3c67 + stat.S_IROTH|stat.S_IWOTH|stat.S_IXOTH) + except OSError as e: + return -+ ++ + def run(self): + """ Starts the log server """ + + self.alive=True + self.listen_thread=threading.currentThread() + clients={} -+ ++ + epoll=select.epoll() + epoll.register(self.socket_logger.fileno(), select.EPOLLIN) + + while self.alive: + try: + sock_events = epoll.poll(3) -+ ++ + for fileno, sock_event in sock_events: + if fileno == self.socket_logger.fileno(): + ret = self.socket_logger.accept() @@ -707,13 +701,13 @@ index 0000000..68b3c67 + elif sock_event & select.EPOLLIN: + s=clients[fileno] + record=s.recv(8192) -+ ++ + if not record: # if connection was closed + epoll.unregister(fileno) + clients[fileno].close() + del clients[fileno] + continue -+ ++ + #import pdb; pdb.set_trace() + try: + message=record.decode("utf8").split("\0") @@ -724,7 +718,7 @@ index 0000000..68b3c67 + # continue + + #print(message) -+ ++ + try: + if message[4]=="ASKING": + if self.filter_proc(message[1],message[2],message[3]): @@ -738,7 +732,7 @@ index 0000000..68b3c67 + + if not stage in self.events: + self.events[stage]=[{},{}] -+ ++ + hashofsucesses=self.events[stage][0] + hashoffailures=self.events[stage][1] + @@ -748,19 +742,19 @@ index 0000000..68b3c67 + if result=="OK": + if not filename in hashofsucesses: + hashofsucesses[filename]=[False,False] -+ ++ + readed_or_writed=hashofsucesses[filename] -+ ++ + if eventname=="read": + readed_or_writed[0]=True + elif eventname=="write": + readed_or_writed[1]=True -+ ++ + elif result[0:3]=="ERR" or result=="DENIED": + if not filename in hashoffailures: + hashoffailures[filename]=[False,False] + notfound_or_blocked=hashoffailures[filename] -+ ++ + if result=="ERR/2": + notfound_or_blocked[0]=True + elif result=="DENIED": @@ -768,74 +762,122 @@ index 0000000..68b3c67 + + else: + print("Error in logger module<->analyser protocol") -+ ++ + except IndexError: + print("IndexError while parsing %s" % record) + except IOError as e: + if e.errno!=4: # handling "Interrupted system call" errors + raise -+ -+ # if main thread doesnt exists then exit ++ ++ # if main thread doesnt exists then exit + if not self.main_thread.is_alive(): + break + epoll.unregister(self.socket_logger.fileno()) + epoll.close() + self.socket_logger.close() -+ ++ + def stop(self): + """ Stops the log server. Returns all events """ + + self.alive=False -+ ++ + # Block the main thread until listener exists + self.listen_thread.join() -+ ++ + # We assume portage clears tmp folder, so no deleting a socket file + # We assume that no new socket data will arrive after this moment + return self.events -diff --git a/pym/portage/const.py b/pym/portage/const.py -index ecaa8f1..f34398d 100644 ---- a/pym/portage/const.py -+++ b/pym/portage/const.py -@@ -67,6 +67,8 @@ FAKEROOT_BINARY = "/usr/bin/fakeroot" +diff -urN /usr/lib/portage/pym/portage/const.py ./pym/portage/const.py +--- /usr/lib/portage/pym/portage/const.py 2014-01-23 14:09:04.077948503 +0600 ++++ ./pym/portage/const.py 2014-02-17 17:38:12.197345709 +0600 +@@ -72,6 +72,7 @@ BASH_BINARY = "/bin/bash" MOVE_BINARY = "/bin/mv" PRELINK_BINARY = "/usr/sbin/prelink" -+AUTODEP_LIBRARY = "/usr/lib/file_hook.so" -+ ++AUTODEP_LIBRARY = "/usr/lib/file_hook.so" INVALID_ENV_FILE = "/etc/spork/is/not/valid/profile.env" REPO_NAME_FILE = "repo_name" -@@ -88,7 +90,8 @@ EBUILD_PHASES = ("pretend", "setup", "unpack", "prepare", "configure" - SUPPORTED_FEATURES = frozenset([ - "allow-missing-manifests", - "assume-digests", "binpkg-logs", "buildpkg", "buildsyspkg", "candy", -- "ccache", "chflags", "collision-protect", "compress-build-logs", -+ "ccache", "chflags", "collision-protect", "compress-build-logs", -+ "depcheck", "depcheckstrict", - "digest", "distcc", "distcc-pump", "distlocks", "ebuild-locks", "fakeroot", - "fail-clean", "fixpackages", "force-mirror", "getbinpkg", - "installsources", "keeptemp", "keepwork", "fixlafiles", "lmirror", -diff --git a/pym/portage/package/ebuild/_config/special_env_vars.py b/pym/portage/package/ebuild/_config/special_env_vars.py -index 87aa606..6d42809 100644 ---- a/pym/portage/package/ebuild/_config/special_env_vars.py -+++ b/pym/portage/package/ebuild/_config/special_env_vars.py -@@ -101,8 +101,8 @@ environ_whitelist += [ +@@ -133,6 +134,8 @@ + "compressdebug", + "compress-index", + "config-protect-if-modified", ++ "depcheck", ++ "depcheckstrict", + "digest", + "distcc", + "distcc-pump", +diff -urN /usr/lib/portage/pym/portage/package/ebuild/_config/special_env_vars.py ./pym/portage/package/ebuild/_config/special_env_vars.py +--- /usr/lib/portage/pym/portage/package/ebuild/_config/special_env_vars.py 2014-01-23 14:09:06.463948342 +0600 ++++ ./pym/portage/package/ebuild/_config/special_env_vars.py 2014-02-17 17:40:56.800338787 +0600 +@@ -113,7 +113,7 @@ # other variables inherited from the calling environment environ_whitelist += [ "CVS_RSH", "ECHANGELOG_USER", - "GPG_AGENT_INFO", -- "SSH_AGENT_PID", "SSH_AUTH_SOCK", + "GPG_AGENT_INFO", "LOG_SOCKET", -+ "SSH_AGENT_PID", "SSH_AUTH_SOCK" + "SSH_AGENT_PID", "SSH_AUTH_SOCK", "STY", "WINDOW", "XAUTHORITY", ] +diff -urN /usr/lib/portage/pym/portage/package/ebuild/doebuild.py ./pym/portage/package/ebuild/doebuild.py +--- /usr/lib/portage/pym/portage/package/ebuild/doebuild.py 2014-01-23 14:09:06.183948361 +0600 ++++ ./pym/portage/package/ebuild/doebuild.py 2014-02-17 17:43:25.387332538 +0600 +@@ -66,7 +66,7 @@ + from portage.util import apply_recursive_permissions, \ + apply_secpass_permissions, noiselimit, normalize_path, \ + writemsg, writemsg_stdout, write_atomic +-from portage.util.lafilefixer import rewrite_lafile ++from portage.util.lafilefixer import rewrite_lafile + from portage.versions import _pkgsplit + from _emerge.BinpkgEnvExtractor import BinpkgEnvExtractor + from _emerge.EbuildBuildDir import EbuildBuildDir +@@ -492,7 +492,7 @@ + """ + Wrapper function that invokes specific ebuild phases through the spawning + of ebuild.sh +- ++ + @param myebuild: name of the ebuild to invoke the phase on (CPV) + @type myebuild: String + @param mydo: Phase to run +@@ -535,13 +535,13 @@ + @return: + 1. 0 for success + 2. 1 for error +- ++ + Most errors have an accompanying error message. +- ++ + listonly and fetchonly are only really necessary for operations involving 'fetch' + prev_mtimes are only necessary for merge operations. + Other variables may not be strictly required, many have defaults that are set inside of doebuild. +- ++ + """ -diff --git a/pym/portage/package/ebuild/doebuild.py b/pym/portage/package/ebuild/doebuild.py -index 49b67ac..c76c1ed 100644 ---- a/pym/portage/package/ebuild/doebuild.py -+++ b/pym/portage/package/ebuild/doebuild.py -@@ -1038,6 +1038,9 @@ def _spawn_actionmap(settings): + if settings is None: +@@ -563,8 +563,8 @@ + if not tree: + writemsg("Warning: tree not specified to doebuild\n") + tree = "porttree" +- +- # chunked out deps for each phase, so that ebuild binary can use it ++ ++ # chunked out deps for each phase, so that ebuild binary can use it + # to collapse targets down. + actionmap_deps={ + "pretend" : [], +@@ -579,7 +579,7 @@ + "package":["install"], + "merge" :["install"], + } +- ++ + if mydbapi is None: + mydbapi = portage.db[myroot][tree].dbapi + +@@ -1306,6 +1306,9 @@ nosandbox = ("sandbox" not in features and \ "usersandbox" not in features) @@ -845,7 +887,7 @@ index 49b67ac..c76c1ed 100644 if not portage.process.sandbox_capable: nosandbox = True -@@ -1215,7 +1218,10 @@ def spawn(mystring, mysettings, debug=0, free=0, droppriv=0, sesandbox=0, fakero +@@ -1551,7 +1554,10 @@ keywords["opt_name"] = "[%s/%s]" % \ (mysettings.get("CATEGORY",""), mysettings.get("PF","")) @@ -857,20 +899,19 @@ index 49b67ac..c76c1ed 100644 keywords["opt_name"] += " bash" spawn_func = portage.process.spawn_bash elif fakeroot: -diff --git a/pym/portage/process.py b/pym/portage/process.py -index 3c15370..6866a2f 100644 ---- a/pym/portage/process.py -+++ b/pym/portage/process.py -@@ -16,7 +16,7 @@ portage.proxy.lazyimport.lazyimport(globals(), - 'portage.util:dump_traceback', +diff -urN /usr/lib/portage/pym/portage/process.py ./pym/portage/process.py +--- /usr/lib/portage/pym/portage/process.py 2014-01-23 14:09:04.079948503 +0600 ++++ ./pym/portage/process.py 2014-02-17 17:45:29.526327317 +0600 +@@ -22,7 +22,7 @@ + 'portage.util:dump_traceback,writemsg', ) -from portage.const import BASH_BINARY, SANDBOX_BINARY, FAKEROOT_BINARY +from portage.const import BASH_BINARY, SANDBOX_BINARY, FAKEROOT_BINARY, AUTODEP_LIBRARY from portage.exception import CommandNotFound + from portage.util._ctypes import find_library, LoadLibrary, ctypes - try: -@@ -39,6 +39,9 @@ else: +@@ -87,13 +87,16 @@ sandbox_capable = (os.path.isfile(SANDBOX_BINARY) and os.access(SANDBOX_BINARY, os.X_OK)) @@ -880,7 +921,15 @@ index 3c15370..6866a2f 100644 fakeroot_capable = (os.path.isfile(FAKEROOT_BINARY) and os.access(FAKEROOT_BINARY, os.X_OK)) -@@ -66,6 +69,16 @@ def spawn_bash(mycommand, debug=False, opt_name=None, **keywords): + def spawn_bash(mycommand, debug=False, opt_name=None, **keywords): + """ + Spawns a bash shell running a specific commands +- ++ + @param mycommand: The command for bash to run + @type mycommand: String + @param debug: Turn bash debugging on (set -x) +@@ -114,6 +117,16 @@ args.append(mycommand) return spawn(args, opt_name=opt_name, **keywords) @@ -892,8 +941,44 @@ index 3c15370..6866a2f 100644 + + # Core part: tell the loader to preload logging library + keywords["env"]["LD_PRELOAD"]=AUTODEP_LIBRARY -+ return spawn_bash(mycommand, opt_name=opt_name, **keywords) ++ return spawn_bash(mycommand, opt_name=opt_name, **keywords) + def spawn_sandbox(mycommand, opt_name=None, **keywords): if not sandbox_capable: return spawn_bash(mycommand, opt_name=opt_name, **keywords) +@@ -199,7 +212,7 @@ + unshare_ipc=False, cgroup=None): + """ + Spawns a given command. +- ++ + @param mycommand: the command to execute + @type mycommand: String or List (Popen style list) + @param env: A dict of Key=Value pairs for env variables +@@ -238,7 +251,7 @@ + + logfile requires stdout and stderr to be assigned to this process (ie not pointed + somewhere else.) +- ++ + """ + + # mycommand is either a str or a list +@@ -387,7 +400,7 @@ + + """ + Execute a given binary with options +- ++ + @param binary: Name of program to execute + @type binary: String + @param mycommand: Options for program +@@ -627,7 +640,7 @@ + def find_binary(binary): + """ + Given a binary name, find the binary in PATH +- ++ + @param binary: Name of the binary to find + @type string + @rtype: None or string diff --git a/portage_with_autodep/bin/archive-conf b/portage_with_autodep/bin/archive-conf index 7978668..2c34588 100755 --- a/portage_with_autodep/bin/archive-conf +++ b/portage_with_autodep/bin/archive-conf @@ -1,5 +1,5 @@ #!/usr/bin/python -# Copyright 1999-2006 Gentoo Foundation +# Copyright 1999-2013 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 # @@ -12,43 +12,21 @@ from __future__ import print_function import sys -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 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 + +import portage.dispatch_conf from portage import os -from portage import dispatch_conf +from portage.checksum import perform_md5 FIND_EXTANT_CONTENTS = "find %s -name CONTENTS" MANDATORY_OPTS = [ 'archive-dir' ] -try: - import fchksum - def perform_checksum(filename): return fchksum.fmd5t(filename) -except ImportError: - import md5 - def md5_to_hex(md5sum): - hexform = "" - for ix in range(len(md5sum)): - hexform = hexform + "%02x" % ord(md5sum[ix]) - return hexform.lower() - - def perform_checksum(filename): - f = open(filename, 'rb') - blocksize=32768 - data = f.read(blocksize) - size = 0 - sum = md5.new() - while data: - sum.update(data) - size = size + len(data) - data = f.read(blocksize) - return (md5_to_hex(sum.digest()),size) - def archive_conf(): args = [] content_files = [] @@ -63,19 +41,19 @@ def archive_conf(): md5_match_hash[conf] = '' # Find all the CONTENT files in VDB_PATH. - content_files += os.popen(FIND_EXTANT_CONTENTS % - (os.path.join(portage.settings['EROOT'], portage.VDB_PATH))).readlines() + with os.popen(FIND_EXTANT_CONTENTS % (os.path.join(portage.settings['EROOT'], portage.VDB_PATH))) as f: + content_files += f.readlines() # Search for the saved md5 checksum of all the specified config files # and see if the current file is unmodified or not. try: todo_cnt = len(args) - for file in content_files: - file = file.rstrip() + for filename in content_files: + filename = filename.rstrip() try: - contents = open(file, "r") + contents = open(filename, "r") except IOError as e: - print('archive-conf: Unable to open %s: %s' % (file, e), file=sys.stderr) + print('archive-conf: Unable to open %s: %s' % (filename, e), file=sys.stderr) sys.exit(1) lines = contents.readlines() for line in lines: @@ -84,7 +62,7 @@ def archive_conf(): for conf in args: if items[1] == conf: stored = items[2].lower() - real = perform_checksum(conf)[0].lower() + real = perform_md5(conf).lower() if stored == real: md5_match_hash[conf] = conf todo_cnt -= 1 diff --git a/portage_with_autodep/bin/banned-helper b/portage_with_autodep/bin/banned-helper deleted file mode 100755 index 17ea991..0000000 --- a/portage_with_autodep/bin/banned-helper +++ /dev/null @@ -1,6 +0,0 @@ -#!/bin/bash -# Copyright 2009 Gentoo Foundation -# Distributed under the terms of the GNU General Public License v2 - -die "'${0##*/}' has been banned for EAPI '$EAPI'" -exit 1 diff --git a/portage_with_autodep/bin/bashrc-functions.sh b/portage_with_autodep/bin/bashrc-functions.sh index 4da5585..503b172 100755 --- a/portage_with_autodep/bin/bashrc-functions.sh +++ b/portage_with_autodep/bin/bashrc-functions.sh @@ -1,9 +1,9 @@ #!/bin/bash -# Copyright 1999-2011 Gentoo Foundation +# Copyright 1999-2013 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 portageq() { - PYTHONPATH=${PORTAGE_PYM_PATH}${PYTHONPATH:+:}${PYTHONPATH} \ + PYTHONPATH=${PORTAGE_PYTHONPATH:-${PORTAGE_PYM_PATH}}\ "${PORTAGE_PYTHON:-/usr/bin/python}" "${PORTAGE_BIN_PATH}/portageq" "$@" } @@ -23,71 +23,16 @@ register_success_hook() { done } -strip_duplicate_slashes() { +__strip_duplicate_slashes() { if [[ -n $1 ]] ; then local removed=$1 while [[ ${removed} == *//* ]] ; do removed=${removed//\/\///} done - echo ${removed} + echo "${removed}" fi } -# this is a function for removing any directory matching a passed in pattern from -# PATH -remove_path_entry() { - save_IFS - IFS=":" - stripped_path="${PATH}" - while [ -n "$1" ]; do - cur_path="" - for p in ${stripped_path}; do - if [ "${p/${1}}" == "${p}" ]; then - cur_path="${cur_path}:${p}" - fi - done - stripped_path="${cur_path#:*}" - shift - done - restore_IFS - PATH="${stripped_path}" -} - -# Set given variables unless these variable have been already set (e.g. during emerge -# invocation) to values different than values set in make.conf. -set_unless_changed() { - if [[ $# -lt 1 ]]; then - die "${FUNCNAME}() requires at least 1 argument: VARIABLE=VALUE" - fi - - local argument value variable - for argument in "$@"; do - if [[ ${argument} != *=* ]]; then - die "${FUNCNAME}(): Argument '${argument}' has incorrect syntax" - fi - variable="${argument%%=*}" - value="${argument#*=}" - if eval "[[ \${${variable}} == \$(env -u ${variable} portageq envvar ${variable}) ]]"; then - eval "${variable}=\"\${value}\"" - fi - done -} - -# Unset given variables unless these variable have been set (e.g. during emerge -# invocation) to values different than values set in make.conf. -unset_unless_changed() { - if [[ $# -lt 1 ]]; then - die "${FUNCNAME}() requires at least 1 argument: VARIABLE" - fi - - local variable - for variable in "$@"; do - if eval "[[ \${${variable}} == \$(env -u ${variable} portageq envvar ${variable}) ]]"; then - unset ${variable} - fi - done -} - KV_major() { [[ -z $1 ]] && return 1 diff --git a/portage_with_autodep/bin/binhost-snapshot b/portage_with_autodep/bin/binhost-snapshot index 9d2697d..376080c 100755 --- a/portage_with_autodep/bin/binhost-snapshot +++ b/portage_with_autodep/bin/binhost-snapshot @@ -1,9 +1,8 @@ #!/usr/bin/python -# Copyright 2010-2011 Gentoo Foundation +# Copyright 2010-2013 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 import io -import optparse import os import sys import textwrap @@ -13,13 +12,12 @@ try: except ImportError: from urlparse import urlparse -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 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.util._argparse import ArgumentParser def parse_args(argv): prog_name = os.path.basename(argv[0]) @@ -47,11 +45,12 @@ def parse_args(argv): "write Packages index with\n" + \ " snapshot_uri" - parser = optparse.OptionParser(usage=usage) - parser.add_option('--hardlinks', help='create hardlinks (y or n, default is y)', - choices=('y', 'n')) - parser.set_defaults(hardlinks='y') - options, args = parser.parse_args(argv[1:]) + parser = ArgumentParser(usage=usage) + parser.add_argument('--hardlinks', + help='create hardlinks (y or n, default is y)', + choices=('y', 'n'), + default='y') + options, args = parser.parse_known_args(argv[1:]) if len(args) != 4: parser.error("Required 4 arguments, got %d" % (len(args),)) diff --git a/portage_with_autodep/bin/chpathtool.py b/portage_with_autodep/bin/chpathtool.py index d0d49cb..0cb5d64 100755 --- a/portage_with_autodep/bin/chpathtool.py +++ b/portage_with_autodep/bin/chpathtool.py @@ -1,15 +1,26 @@ #!/usr/bin/python -# Copyright 2011 Gentoo Foundation +# Copyright 2011-2013 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 +"""Helper tool for converting installed files to custom prefixes. + +In other words, eprefixy $D for Gentoo/Prefix.""" + import io -import optparse import os import stat import sys -CONTENT_ENCODING = "utf_8" -FS_ENCODING = "utf_8" +from portage.util._argparse import ArgumentParser + +# Argument parsing compatibility for Python 2.6 using optparse. +if sys.hexversion < 0x2070000: + from optparse import OptionParser + +from optparse import OptionError + +CONTENT_ENCODING = 'utf_8' +FS_ENCODING = 'utf_8' try: import magic @@ -41,7 +52,9 @@ class IsTextFile(object): def _is_text_magic(self, filename): mime_type = self._m.file(filename) - return mime_type.startswith("text/") + if isinstance(mime_type, bytes): + mime_type = mime_type.decode('ascii', 'replace') + return mime_type.startswith('text/') def _is_text_encoding(self, filename): try: @@ -64,7 +77,7 @@ def chpath_inplace(filename, is_text_file, old, new): try: orig_mode = stat.S_IMODE(os.lstat(filename).st_mode) except OSError as e: - sys.stderr.write("%s: %s\n" % (e, filename)) + sys.stderr.write('%s: %s\n' % (e, filename)) return temp_mode = 0o200 | orig_mode os.chmod(filename, temp_mode) @@ -121,8 +134,12 @@ def chpath_inplace(filename, is_text_file, old, new): f.close() if modified: - orig_mtime = orig_stat[stat.ST_MTIME] - os.utime(filename, (orig_mtime, orig_mtime)) + if sys.hexversion >= 0x3030000: + orig_mtime = orig_stat.st_mtime_ns + os.utime(filename, ns=(orig_mtime, orig_mtime)) + else: + orig_mtime = orig_stat[stat.ST_MTIME] + os.utime(filename, (orig_mtime, orig_mtime)) return modified def chpath_inplace_symlink(filename, st, old, new): @@ -135,14 +152,37 @@ def chpath_inplace_symlink(filename, st, old, new): def main(argv): - usage = "%s [options] <location> <old> <new>" % (os.path.basename(argv[0],)) - parser = optparse.OptionParser(usage=usage) - options, args = parser.parse_args(argv[1:]) - - if len(args) != 3: - parser.error("3 args required, got %s" % (len(args),)) - - location, old, new = args + parser = ArgumentParser(description=__doc__) + try: + parser.add_argument('location', default=None, + help='root directory (e.g. $D)') + parser.add_argument('old', default=None, + help='original build prefix (e.g. /)') + parser.add_argument('new', default=None, + help='new install prefix (e.g. $EPREFIX)') + opts = parser.parse_args(argv) + + location, old, new = opts.location, opts.old, opts.new + except OptionError: + # Argument parsing compatibility for Python 2.6 using optparse. + if sys.hexversion < 0x2070000: + parser = OptionParser(description=__doc__, + usage="usage: %prog [-h] location old new\n\n" + \ + " location: root directory (e.g. $D)\n" + \ + " old: original build prefix (e.g. /)\n" + \ + " new: new install prefix (e.g. $EPREFIX)") + + (opts, args) = parser.parse_args() + + if len(args) != 3: + parser.print_usage() + print("%s: error: expected 3 arguments, got %i" + % (__file__, len(args))) + return + + location, old, new = args[0:3] + else: + raise is_text_file = IsTextFile() @@ -178,5 +218,5 @@ def main(argv): return os.EX_OK -if __name__ == "__main__": - sys.exit(main(sys.argv)) +if __name__ == '__main__': + sys.exit(main(sys.argv[1:])) diff --git a/portage_with_autodep/bin/clean_locks b/portage_with_autodep/bin/clean_locks index 8c4299c..184e80c 100755 --- a/portage_with_autodep/bin/clean_locks +++ b/portage_with_autodep/bin/clean_locks @@ -1,21 +1,17 @@ #!/usr/bin/python -O -# Copyright 1999-2006 Gentoo Foundation +# Copyright 1999-2013 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 from __future__ import print_function import sys, errno -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 +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 if not sys.argv[1:] or "--help" in sys.argv or "-h" in sys.argv: - import portage print() print("You must specify directories with hardlink-locks to clean.") print("You may optionally specify --force, which will remove all") diff --git a/portage_with_autodep/bin/dispatch-conf b/portage_with_autodep/bin/dispatch-conf index 139a001..10455f4 100755 --- a/portage_with_autodep/bin/dispatch-conf +++ b/portage_with_autodep/bin/dispatch-conf @@ -1,5 +1,5 @@ #!/usr/bin/python -O -# Copyright 1999-2011 Gentoo Foundation +# Copyright 1999-2013 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 # @@ -16,19 +16,15 @@ from __future__ import print_function from stat import ST_GID, ST_MODE, ST_UID from random import random import atexit, re, shutil, stat, sys - -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 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 dispatch_conf from portage import _unicode_decode from portage.dispatch_conf import diffstatusoutput -from portage.process import find_binary +from portage.process import find_binary, spawn FIND_EXTANT_CONFIGS = "find '%s' %s -name '._cfg????_%s' ! -name '.*~' ! -iname '.*.bak' -print" DIFF_CONTENTS = "diff -Nu '%s' '%s'" @@ -83,7 +79,7 @@ class dispatch: confs = [] count = 0 - config_root = portage.const.EPREFIX or os.sep + config_root = portage.settings["EPREFIX"] or os.sep self.options = portage.dispatch_conf.read_config(MANDATORY_OPTS) if "log-file" in self.options: @@ -411,7 +407,8 @@ class dispatch: def do_help (self): - print(); print + print() + print() print(' u -- update current config with new config and continue') print(' z -- zap (delete) new config and continue') @@ -431,7 +428,7 @@ class dispatch: def getch (): # from ASPN - Danny Yoo # - import sys, tty, termios + import tty, termios fd = sys.stdin.fileno() old_settings = termios.tcgetattr(fd) @@ -456,17 +453,18 @@ def clear_screen(): pass os.system("clear 2>/dev/null") -from portage.process import find_binary, spawn shell = os.environ.get("SHELL") if not shell or not os.access(shell, os.EX_OK): shell = find_binary("sh") def spawn_shell(cmd): if shell: + sys.__stdout__.flush() + sys.__stderr__.flush() spawn([shell, "-c", cmd], env=os.environ, - fd_pipes = { 0 : sys.stdin.fileno(), - 1 : sys.stdout.fileno(), - 2 : sys.stderr.fileno()}) + fd_pipes = { 0 : portage._get_stdin().fileno(), + 1 : sys.__stdout__.fileno(), + 2 : sys.__stderr__.fileno()}) else: os.system(cmd) diff --git a/portage_with_autodep/bin/dohtml.py b/portage_with_autodep/bin/dohtml.py index f0a7f2c..f98557f 100755 --- a/portage_with_autodep/bin/dohtml.py +++ b/portage_with_autodep/bin/dohtml.py @@ -1,5 +1,5 @@ #!/usr/bin/python -# Copyright 1999-2006 Gentoo Foundation +# Copyright 1999-2013 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 # @@ -11,18 +11,18 @@ # # # Detailed usage: -# dohtml <list-of-files> -# - will install the files in the list of files (space-separated list) into -# /usr/share/doc/${PF}/html, provided the file ends in .htm, .html, .css, -# .js, ,gif, .jpeg, .jpg, or .png. +# dohtml <list-of-files> +# - will install the files in the list of files (space-separated list) into +# /usr/share/doc/${PF}/html, provided the file ends in .css, .gif, .htm, +# .html, .jpeg, .jpg, .js or .png. # dohtml -r <list-of-files-and-directories> -# - will do as 'dohtml', but recurse into all directories, as long as the +# - will do as 'dohtml', but recurse into all directories, as long as the # directory name is not CVS # dohtml -A jpe,java [-r] <list-of-files[-and-directories]> # - will do as 'dohtml' but add .jpe,.java (default filter list is # added to your list) # dohtml -a png,gif,html,htm [-r] <list-of-files[-and-directories]> -# - will do as 'dohtml' but filter on .png,.gif,.html,.htm (default filter +# - will do as 'dohtml' but filter on .png,.gif,.html,.htm (default filter # list is ignored) # dohtml -x CVS,SCCS,RCS -r <list-of-files-and-directories> # - will do as 'dohtml -r', but ignore directories named CVS, SCCS, RCS @@ -31,13 +31,25 @@ from __future__ import print_function import os +import shutil import sys +from portage.util import normalize_path + +# Change back to original cwd _after_ all imports (bug #469338). +os.chdir(os.environ["__PORTAGE_HELPER_CWD"]) + def dodir(path): - os.spawnlp(os.P_WAIT, "install", "install", "-d", path) + try: + os.makedirs(path, 0o755) + except OSError: + if not os.path.isdir(path): + raise + os.chmod(path, 0o755) def dofile(src,dst): - os.spawnlp(os.P_WAIT, "install", "install", "-m0644", src, dst) + shutil.copy(src, dst) + os.chmod(dst, 0o644) def eqawarn(lines): cmd = "source '%s/isolated-functions.sh' ; " % \ @@ -47,32 +59,43 @@ def eqawarn(lines): os.spawnlp(os.P_WAIT, "bash", "bash", "-c", cmd) skipped_directories = [] +skipped_files = [] +warn_on_skipped_files = os.environ.get("PORTAGE_DOHTML_WARN_ON_SKIPPED_FILES") is not None +unwarned_skipped_extensions = os.environ.get("PORTAGE_DOHTML_UNWARNED_SKIPPED_EXTENSIONS", "").split() +unwarned_skipped_files = os.environ.get("PORTAGE_DOHTML_UNWARNED_SKIPPED_FILES", "").split() def install(basename, dirname, options, prefix=""): fullpath = basename if prefix: - fullpath = prefix + "/" + fullpath + fullpath = os.path.join(prefix, fullpath) if dirname: - fullpath = dirname + "/" + fullpath + fullpath = os.path.join(dirname, fullpath) if options.DOCDESTTREE: - destdir = options.ED + "usr/share/doc/" + options.PF + "/" + options.DOCDESTTREE + "/" + options.doc_prefix + "/" + prefix + desttree = options.DOCDESTTREE else: - destdir = options.ED + "usr/share/doc/" + options.PF + "/html/" + options.doc_prefix + "/" + prefix + desttree = "html" + + destdir = os.path.join(options.ED, "usr", "share", "doc", + options.PF.lstrip(os.sep), desttree.lstrip(os.sep), + options.doc_prefix.lstrip(os.sep), prefix).rstrip(os.sep) if not os.path.exists(fullpath): sys.stderr.write("!!! dohtml: %s does not exist\n" % fullpath) return False elif os.path.isfile(fullpath): - ext = os.path.splitext(basename)[1] - if (len(ext) and ext[1:] in options.allowed_exts) or basename in options.allowed_files: + ext = os.path.splitext(basename)[1][1:] + if ext in options.allowed_exts or basename in options.allowed_files: dodir(destdir) - dofile(fullpath, destdir + "/" + basename) + dofile(fullpath, os.path.join(destdir, basename)) + elif warn_on_skipped_files and ext not in unwarned_skipped_extensions and basename not in unwarned_skipped_files: + skipped_files.append(fullpath) elif options.recurse and os.path.isdir(fullpath) and \ basename not in options.disallowed_dirs: for i in os.listdir(fullpath): pfx = basename - if prefix: pfx = prefix + "/" + pfx + if prefix: + pfx = os.path.join(prefix, pfx) install(i, dirname, options, pfx) elif not options.recurse and os.path.isdir(fullpath): global skipped_directories @@ -88,21 +111,28 @@ class OptionsClass: self.PF = "" self.ED = "" self.DOCDESTTREE = "" - + if "PF" in os.environ: self.PF = os.environ["PF"] + if self.PF: + self.PF = normalize_path(self.PF) if "force-prefix" not in os.environ.get("FEATURES", "").split() and \ os.environ.get("EAPI", "0") in ("0", "1", "2"): self.ED = os.environ.get("D", "") else: self.ED = os.environ.get("ED", "") + if self.ED: + self.ED = normalize_path(self.ED) if "_E_DOCDESTTREE_" in os.environ: self.DOCDESTTREE = os.environ["_E_DOCDESTTREE_"] - - self.allowed_exts = [ 'htm', 'html', 'css', 'js', - 'gif', 'jpeg', 'jpg', 'png' ] + if self.DOCDESTTREE: + self.DOCDESTTREE = normalize_path(self.DOCDESTTREE) + + self.allowed_exts = ['css', 'gif', 'htm', 'html', 'jpeg', 'jpg', 'js', 'png'] + if os.environ.get("EAPI", "0") in ("4-python", "5-progress"): + self.allowed_exts += ['ico', 'svg', 'xhtml', 'xml'] self.allowed_files = [] - self.disallowed_dirs = [ 'CVS' ] + self.disallowed_dirs = ['CVS'] self.recurse = False self.verbose = False self.doc_prefix = "" @@ -127,7 +157,7 @@ def print_help(): def parse_args(): options = OptionsClass() args = [] - + x = 1 while x < len(sys.argv): arg = sys.argv[x] @@ -146,6 +176,8 @@ def parse_args(): sys.exit(0) elif arg == "-p": options.doc_prefix = sys.argv[x] + if options.doc_prefix: + options.doc_prefix = normalize_path(options.doc_prefix) else: values = sys.argv[x].split(",") if arg == "-A": @@ -159,7 +191,7 @@ def parse_args(): else: args.append(sys.argv[x]) x += 1 - + return (options, args) def main(): @@ -168,20 +200,29 @@ def main(): if options.verbose: print("Allowed extensions:", options.allowed_exts) - print("Document prefix : '" + options.doc_prefix + "'") + print("Document prefix : '" + options.doc_prefix + "'") print("Allowed files :", options.allowed_files) success = False - + endswith_slash = (os.sep, os.sep + ".") + for x in args: + trailing_slash = x.endswith(endswith_slash) + x = normalize_path(x) + if trailing_slash: + # Modify behavior of basename and dirname + # as noted in bug #425214, causing foo/ to + # behave similarly to the way that foo/* + # behaves. + x += os.sep basename = os.path.basename(x) dirname = os.path.dirname(x) success |= install(basename, dirname, options) - global skipped_directories for x in skipped_directories: - eqawarn(["QA Notice: dohtml on directory " + \ - "'%s' without recursion option" % x]) + eqawarn(["QA Notice: dohtml on directory '%s' without recursion option" % x]) + for x in skipped_files: + eqawarn(["dohtml: skipped file '%s'" % x]) if success: retcode = 0 diff --git a/portage_with_autodep/bin/ebuild b/portage_with_autodep/bin/ebuild index 35cdc14..262dab6 100755 --- a/portage_with_autodep/bin/ebuild +++ b/portage_with_autodep/bin/ebuild @@ -1,15 +1,16 @@ #!/usr/bin/python -O -# Copyright 1999-2012 Gentoo Foundation +# Copyright 1999-2013 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): + def exithandler(signum, _frame): signal.signal(signal.SIGINT, signal.SIG_IGN) signal.signal(signal.SIGTERM, signal.SIG_IGN) sys.exit(128 + signum) @@ -23,56 +24,61 @@ try: except KeyboardInterrupt: sys.exit(128 + signal.SIGINT) -def debug_signal(signum, frame): +def debug_signal(_signum, _frame): import pdb pdb.set_trace() -signal.signal(signal.SIGUSR1, debug_signal) -import imp +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 optparse 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 = 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("--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("--version", help="show version and exit", - action="store_true", dest="version") -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") - -opts, pargs = parser.parse_args(args=sys.argv[1:]) +parser.add_argument("--skip-manifest", help="skip all manifest checks", + action="store_true") -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 +opts, pargs = parser.parse_known_args(args=sys.argv[1:]) -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 +def err(txt): + portage.writemsg('ebuild: %s\n' % (txt,), noiselevel=-1) + sys.exit(1) if opts.version: print("Portage", portage.VERSION) @@ -82,8 +88,9 @@ 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 @@ -112,9 +119,7 @@ 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) + err("%s: does not end with '.ebuild'" % (ebuild,)) if not os.path.isabs(ebuild): mycwd = os.getcwd() @@ -153,15 +158,14 @@ if ebuild_portdir != vdb_path and \ encoding=_encodings['content'], errors='strict') print("Appending %s to PORTDIR_OVERLAY..." % ebuild_portdir) - imp.reload(portage) + 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("/") cpv = "%s/%s" % (ebuild_split[-3], pf) @@ -172,8 +176,7 @@ with io.open(_unicode_encode(ebuild, encoding=_encodings['fs'], errors='strict') if eapi is None: eapi = "0" if not portage.catpkgsplit(cpv, eapi=eapi): - print("!!! %s does not follow correct package syntax." % (cpv)) - sys.exit(1) + err('%s: %s: does not follow correct package syntax' % (ebuild, cpv)) if ebuild.startswith(vdb_path): mytree = "vartree" @@ -182,8 +185,7 @@ if ebuild.startswith(vdb_path): 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" @@ -192,12 +194,10 @@ else: 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 @@ -306,14 +306,16 @@ def stale_env_warning(): if ebuild_changed: open(os.path.join(tmpsettings['PORTAGE_BUILDDIR'], - '.ebuild_changed'), 'w') + '.ebuild_changed'), 'w').close() from portage.exception import PermissionDenied, \ PortagePackageException, UnsupportedAPIException -if 'digest' in tmpsettings.features and \ - not set(["digest", "manifest"]).intersection(pargs): - pargs = ['digest'] + pargs +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 @@ -327,7 +329,7 @@ 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, + a = portage.doebuild(ebuild, arg, settings=tmpsettings, debug=debug, tree=mytree, vartree=portage.db[portage.root]['vartree']) except KeyboardInterrupt: diff --git a/portage_with_autodep/bin/ebuild-helpers/4/dodoc b/portage_with_autodep/bin/ebuild-helpers/4/dodoc deleted file mode 120000 index 35080ad..0000000 --- a/portage_with_autodep/bin/ebuild-helpers/4/dodoc +++ /dev/null @@ -1 +0,0 @@ -../doins
\ No newline at end of file diff --git a/portage_with_autodep/bin/ebuild-helpers/4/dohard b/portage_with_autodep/bin/ebuild-helpers/4/dohard deleted file mode 120000 index 1a6b57a..0000000 --- a/portage_with_autodep/bin/ebuild-helpers/4/dohard +++ /dev/null @@ -1 +0,0 @@ -../../banned-helper
\ No newline at end of file diff --git a/portage_with_autodep/bin/ebuild-helpers/4/dosed b/portage_with_autodep/bin/ebuild-helpers/4/dosed deleted file mode 120000 index 1a6b57a..0000000 --- a/portage_with_autodep/bin/ebuild-helpers/4/dosed +++ /dev/null @@ -1 +0,0 @@ -../../banned-helper
\ No newline at end of file diff --git a/portage_with_autodep/bin/ebuild-helpers/4/prepalldocs b/portage_with_autodep/bin/ebuild-helpers/4/prepalldocs deleted file mode 120000 index 1a6b57a..0000000 --- a/portage_with_autodep/bin/ebuild-helpers/4/prepalldocs +++ /dev/null @@ -1 +0,0 @@ -../../banned-helper
\ No newline at end of file diff --git a/portage_with_autodep/bin/ebuild-helpers/dobin b/portage_with_autodep/bin/ebuild-helpers/dobin index f90d893..0ba1eb0 100755 --- a/portage_with_autodep/bin/ebuild-helpers/dobin +++ b/portage_with_autodep/bin/ebuild-helpers/dobin @@ -1,19 +1,20 @@ #!/bin/bash -# Copyright 1999-2011 Gentoo Foundation +# Copyright 1999-2012 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 source "${PORTAGE_BIN_PATH:-/usr/lib/portage/bin}"/isolated-functions.sh if [[ $# -lt 1 ]] ; then - helpers_die "${0##*/}: at least one argument needed" + __helpers_die "${0##*/}: at least one argument needed" exit 1 fi -[[ " ${FEATURES} " == *" force-prefix "* ]] || \ - case "$EAPI" in 0|1|2) ED=${D} ;; esac +if ! ___eapi_has_prefix_variables; then + ED=${D} +fi if [[ ! -d ${ED}${DESTTREE}/bin ]] ; then - install -d "${ED}${DESTTREE}/bin" || { helpers_die "${0##*/}: failed to install ${ED}${DESTTREE}/bin"; exit 2; } + install -d "${ED}${DESTTREE}/bin" || { __helpers_die "${0##*/}: failed to install ${ED}${DESTTREE}/bin"; exit 2; } fi ret=0 @@ -28,5 +29,5 @@ for x in "$@" ; do ((ret|=$?)) done -[[ $ret -ne 0 ]] && helpers_die "${0##*/} failed" +[[ $ret -ne 0 ]] && __helpers_die "${0##*/} failed" exit ${ret} diff --git a/portage_with_autodep/bin/ebuild-helpers/doconfd b/portage_with_autodep/bin/ebuild-helpers/doconfd index e146000..a3c09a5 100755 --- a/portage_with_autodep/bin/ebuild-helpers/doconfd +++ b/portage_with_autodep/bin/ebuild-helpers/doconfd @@ -4,7 +4,7 @@ if [[ $# -lt 1 ]] ; then source "${PORTAGE_BIN_PATH:-/usr/lib/portage/bin}"/isolated-functions.sh - helpers_die "${0##*/}: at least one argument needed" + __helpers_die "${0##*/}: at least one argument needed" exit 1 fi diff --git a/portage_with_autodep/bin/ebuild-helpers/dodir b/portage_with_autodep/bin/ebuild-helpers/dodir index 90a3efe..e03ba9a 100755 --- a/portage_with_autodep/bin/ebuild-helpers/dodir +++ b/portage_with_autodep/bin/ebuild-helpers/dodir @@ -1,13 +1,14 @@ #!/bin/bash -# Copyright 1999-2011 Gentoo Foundation +# Copyright 1999-2012 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 source "${PORTAGE_BIN_PATH:-/usr/lib/portage/bin}"/isolated-functions.sh -[[ " ${FEATURES} " == *" force-prefix "* ]] || \ - case "$EAPI" in 0|1|2) ED=${D} ;; esac +if ! ___eapi_has_prefix_variables; then + ED=${D} +fi install -d ${DIROPTIONS} "${@/#/${ED}/}" ret=$? -[[ $ret -ne 0 ]] && helpers_die "${0##*/} failed" +[[ $ret -ne 0 ]] && __helpers_die "${0##*/} failed" exit $ret diff --git a/portage_with_autodep/bin/ebuild-helpers/dodoc b/portage_with_autodep/bin/ebuild-helpers/dodoc index 1f333a6..99122c4 100755 --- a/portage_with_autodep/bin/ebuild-helpers/dodoc +++ b/portage_with_autodep/bin/ebuild-helpers/dodoc @@ -1,16 +1,24 @@ #!/bin/bash -# Copyright 1999-2011 Gentoo Foundation +# Copyright 1999-2012 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 source "${PORTAGE_BIN_PATH:-/usr/lib/portage/bin}"/isolated-functions.sh +if ___eapi_dodoc_supports_-r; then + exec \ + env \ + __PORTAGE_HELPER="dodoc" \ + doins "$@" +fi + if [ $# -lt 1 ] ; then - helpers_die "${0##*/}: at least one argument needed" - exit 1 + __helpers_die "${0##*/}: at least one argument needed" + exit 1 fi -[[ " ${FEATURES} " == *" force-prefix "* ]] || \ - case "$EAPI" in 0|1|2) ED=${D} ;; esac +if ! ___eapi_has_prefix_variables; then + ED=${D} +fi dir="${ED}usr/share/doc/${PF}/${_E_DOCDESTTREE_}" if [ ! -d "${dir}" ] ; then @@ -30,5 +38,5 @@ for x in "$@" ; do fi done -[[ $ret -ne 0 ]] && helpers_die "${0##*/} failed" +[[ $ret -ne 0 ]] && __helpers_die "${0##*/} failed" exit ${ret} diff --git a/portage_with_autodep/bin/ebuild-helpers/doenvd b/portage_with_autodep/bin/ebuild-helpers/doenvd index 28ab5d2..9287933 100755 --- a/portage_with_autodep/bin/ebuild-helpers/doenvd +++ b/portage_with_autodep/bin/ebuild-helpers/doenvd @@ -4,7 +4,7 @@ if [[ $# -lt 1 ]] ; then source "${PORTAGE_BIN_PATH:-/usr/lib/portage/bin}"/isolated-functions.sh - helpers_die "${0##*/}: at least one argument needed" + __helpers_die "${0##*/}: at least one argument needed" exit 1 fi diff --git a/portage_with_autodep/bin/ebuild-helpers/doexe b/portage_with_autodep/bin/ebuild-helpers/doexe index fb228f9..c34fcae 100755 --- a/portage_with_autodep/bin/ebuild-helpers/doexe +++ b/portage_with_autodep/bin/ebuild-helpers/doexe @@ -1,23 +1,23 @@ #!/bin/bash -# Copyright 1999-2011 Gentoo Foundation +# Copyright 1999-2012 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 source "${PORTAGE_BIN_PATH:-/usr/lib/portage/bin}"/isolated-functions.sh if [[ $# -lt 1 ]] ; then - helpers_die "${0##*/}: at least one argument needed" + __helpers_die "${0##*/}: at least one argument needed" exit 1 fi -[[ " ${FEATURES} " == *" force-prefix "* ]] || \ - case "$EAPI" in 0|1|2) ED=${D} ;; esac +if ! ___eapi_has_prefix_variables; then + ED=${D} +fi if [[ ! -d ${ED}${_E_EXEDESTTREE_} ]] ; then install -d "${ED}${_E_EXEDESTTREE_}" fi -TMP=$T/.doexe_tmp -mkdir "$TMP" +TMP=$(mktemp -d "${T}/.doexe_tmp_XXXXXX") ret=0 @@ -26,7 +26,7 @@ for x in "$@" ; do cp "$x" "$TMP" mysrc=$TMP/${x##*/} elif [ -d "${x}" ] ; then - vecho "doexe: warning, skipping directory ${x}" + __vecho "doexe: warning, skipping directory ${x}" continue else mysrc="${x}" @@ -42,5 +42,5 @@ done rm -rf "$TMP" -[[ $ret -ne 0 ]] && helpers_die "${0##*/} failed" +[[ $ret -ne 0 ]] && __helpers_die "${0##*/} failed" exit $ret diff --git a/portage_with_autodep/bin/ebuild-helpers/dohard b/portage_with_autodep/bin/ebuild-helpers/dohard index b52fd7c..e0a44fa 100755 --- a/portage_with_autodep/bin/ebuild-helpers/dohard +++ b/portage_with_autodep/bin/ebuild-helpers/dohard @@ -1,14 +1,22 @@ #!/bin/bash -# Copyright 1999-2011 Gentoo Foundation +# Copyright 1999-2012 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 +source "${PORTAGE_BIN_PATH:-/usr/lib/portage/bin}"/isolated-functions.sh + +if ! ___eapi_has_dohard; then + die "'${0##*/}' has been banned for EAPI '$EAPI'" + exit 1 +fi + if [[ $# -ne 2 ]] ; then echo "$0: two arguments needed" 1>&2 exit 1 fi -[[ " ${FEATURES} " == *" force-prefix "* ]] || \ - case "$EAPI" in 0|1|2) ED=${D} ;; esac +if ! ___eapi_has_prefix_variables; then + ED=${D} +fi destdir=${2%/*} [[ ! -d ${ED}${destdir} ]] && dodir "${destdir}" diff --git a/portage_with_autodep/bin/ebuild-helpers/dohtml b/portage_with_autodep/bin/ebuild-helpers/dohtml index 630629a..75d3d00 100755 --- a/portage_with_autodep/bin/ebuild-helpers/dohtml +++ b/portage_with_autodep/bin/ebuild-helpers/dohtml @@ -1,14 +1,19 @@ #!/bin/bash -# Copyright 2009-2010 Gentoo Foundation +# Copyright 2009-2013 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 source "${PORTAGE_BIN_PATH:-/usr/lib/portage/bin}"/isolated-functions.sh PORTAGE_BIN_PATH=${PORTAGE_BIN_PATH:-/usr/lib/portage/bin} PORTAGE_PYM_PATH=${PORTAGE_PYM_PATH:-/usr/lib/portage/pym} -PYTHONPATH=$PORTAGE_PYM_PATH${PYTHONPATH:+:}$PYTHONPATH \ +# Use safe cwd, avoiding unsafe import for bug #469338. +export __PORTAGE_HELPER_CWD=${PWD} +cd "${PORTAGE_PYM_PATH}" +PYTHONPATH=${PORTAGE_PYTHONPATH:-${PORTAGE_PYM_PATH}} \ "${PORTAGE_PYTHON:-/usr/bin/python}" "$PORTAGE_BIN_PATH/dohtml.py" "$@" ret=$? -[[ $ret -ne 0 ]] && helpers_die "${0##*/} failed" +# Restore cwd for display by __helpers_die +cd "${__PORTAGE_HELPER_CWD}" +[[ $ret -ne 0 ]] && __helpers_die "${0##*/} failed" exit $ret diff --git a/portage_with_autodep/bin/ebuild-helpers/doinfo b/portage_with_autodep/bin/ebuild-helpers/doinfo index 8fd7d45..2edbdc5 100755 --- a/portage_with_autodep/bin/ebuild-helpers/doinfo +++ b/portage_with_autodep/bin/ebuild-helpers/doinfo @@ -1,19 +1,20 @@ #!/bin/bash -# Copyright 1999-2011 Gentoo Foundation +# Copyright 1999-2012 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 source "${PORTAGE_BIN_PATH:-/usr/lib/portage/bin}"/isolated-functions.sh if [[ -z $1 ]] ; then - helpers_die "${0##*/}: at least one argument needed" - exit 1 + __helpers_die "${0##*/}: at least one argument needed" + exit 1 fi -[[ " ${FEATURES} " == *" force-prefix "* ]] || \ - case "$EAPI" in 0|1|2) ED=${D} ;; esac +if ! ___eapi_has_prefix_variables; then + ED=${D} +fi if [[ ! -d ${ED}usr/share/info ]] ; then - install -d "${ED}usr/share/info" || { helpers_die "${0##*/}: failed to install ${ED}usr/share/info"; exit 1; } + install -d "${ED}usr/share/info" || { __helpers_die "${0##*/}: failed to install ${ED}usr/share/info"; exit 1; } fi install -m0644 "$@" "${ED}usr/share/info" @@ -22,6 +23,6 @@ if [ $rval -ne 0 ] ; then for x in "$@" ; do [ -e "$x" ] || echo "!!! ${0##*/}: $x does not exist" 1>&2 done - helpers_die "${0##*/} failed" + __helpers_die "${0##*/} failed" fi exit $rval diff --git a/portage_with_autodep/bin/ebuild-helpers/doinitd b/portage_with_autodep/bin/ebuild-helpers/doinitd index b711e19..476b858 100755 --- a/portage_with_autodep/bin/ebuild-helpers/doinitd +++ b/portage_with_autodep/bin/ebuild-helpers/doinitd @@ -4,7 +4,7 @@ if [[ $# -lt 1 ]] ; then source "${PORTAGE_BIN_PATH:-/usr/lib/portage/bin}"/isolated-functions.sh - helpers_die "${0##*/}: at least one argument needed" + __helpers_die "${0##*/}: at least one argument needed" exit 1 fi diff --git a/portage_with_autodep/bin/ebuild-helpers/doins b/portage_with_autodep/bin/ebuild-helpers/doins index 443bfdb..c60e057 100755 --- a/portage_with_autodep/bin/ebuild-helpers/doins +++ b/portage_with_autodep/bin/ebuild-helpers/doins @@ -1,14 +1,17 @@ #!/bin/bash -# Copyright 1999-2011 Gentoo Foundation +# Copyright 1999-2012 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 source "${PORTAGE_BIN_PATH:-/usr/lib/portage/bin}"/isolated-functions.sh -if [[ ${0##*/} == dodoc ]] ; then +helper=${__PORTAGE_HELPER:-${0##*/}} + +if [[ ${helper} == dodoc ]] ; then if [ $# -eq 0 ] ; then # default_src_install may call dodoc with no arguments # when DOC is defined but empty, so simply return # sucessfully in this case. + eqawarn "QA Notice: dodoc called with no arguments" exit 0 fi export INSOPTIONS=-m0644 @@ -16,7 +19,7 @@ if [[ ${0##*/} == dodoc ]] ; then fi if [ $# -lt 1 ] ; then - helpers_die "${0##*/}: at least one argument needed" + __helpers_die "${helper}: at least one argument needed" exit 1 fi @@ -27,28 +30,26 @@ else DOINSRECUR=n fi -[[ " ${FEATURES} " == *" force-prefix "* ]] || \ - case "$EAPI" in 0|1|2) export ED="${D}" ;; esac +if ! ___eapi_has_prefix_variables; then + export ED="${D}" +fi if [[ ${INSDESTTREE#${ED}} != "${INSDESTTREE}" ]]; then - vecho "-------------------------------------------------------" 1>&2 - vecho "You should not use \${D} or \${ED} with helpers." 1>&2 - vecho " --> ${INSDESTTREE}" 1>&2 - vecho "-------------------------------------------------------" 1>&2 - helpers_die "${0##*/} used with \${D} or \${ED}" + __vecho "-------------------------------------------------------" 1>&2 + __vecho "You should not use \${D} or \${ED} with helpers." 1>&2 + __vecho " --> ${INSDESTTREE}" 1>&2 + __vecho "-------------------------------------------------------" 1>&2 + __helpers_die "${helper} used with \${D} or \${ED}" exit 1 fi -case "$EAPI" in - 0|1|2|3|3_pre2) - PRESERVE_SYMLINKS=n - ;; - *) - PRESERVE_SYMLINKS=y - ;; -esac +if ___eapi_doins_and_newins_preserve_symlinks; then + PRESERVE_SYMLINKS=y +else + PRESERVE_SYMLINKS=n +fi -export TMP=$T/.doins_tmp +export TMP=$(mktemp -d "${T}/.doins_tmp_XXXXXX") # Use separate directories to avoid potential name collisions. mkdir -p "$TMP"/{1,2} @@ -79,7 +80,7 @@ _doins() { install ${INSOPTIONS} "${mysrc}" "${ED}${INSDESTTREE}/${mydir}" rval=$? [[ -n ${cleanup} ]] && rm -f "${cleanup}" - [ $rval -ne 0 ] && echo "!!! ${0##*/}: $mysrc does not exist" 1>&2 + [ $rval -ne 0 ] && echo "!!! ${helper}: $mysrc does not exist" 1>&2 return $rval } @@ -99,8 +100,8 @@ for x in "$@" ; do if [[ $PRESERVE_SYMLINKS = n && -d $x ]] || \ [[ $PRESERVE_SYMLINKS = y && -d $x && ! -L $x ]] ; then if [ "${DOINSRECUR}" == "n" ] ; then - if [[ ${0##*/} == dodoc ]] ; then - echo "!!! ${0##*/}: $x is a directory" 1>&2 + if [[ ${helper} == dodoc ]] ; then + echo "!!! ${helper}: $x is a directory" 1>&2 ((failed|=1)) fi continue @@ -155,4 +156,4 @@ for x in "$@" ; do fi done rm -rf "$TMP" -[[ $failed -ne 0 || $success -eq 0 ]] && { helpers_die "${0##*/} failed"; exit 1; } || exit 0 +[[ $failed -ne 0 || $success -eq 0 ]] && { __helpers_die "${helper} failed"; exit 1; } || exit 0 diff --git a/portage_with_autodep/bin/ebuild-helpers/dolib b/portage_with_autodep/bin/ebuild-helpers/dolib index 9af5418..fd92d7f 100755 --- a/portage_with_autodep/bin/ebuild-helpers/dolib +++ b/portage_with_autodep/bin/ebuild-helpers/dolib @@ -1,11 +1,12 @@ #!/bin/bash -# Copyright 1999-2011 Gentoo Foundation +# Copyright 1999-2012 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 source "${PORTAGE_BIN_PATH:-/usr/lib/portage/bin}"/isolated-functions.sh -[[ " ${FEATURES} " == *" force-prefix "* ]] || \ - case "$EAPI" in 0|1|2) ED=${D} ;; esac +if ! ___eapi_has_prefix_variables; then + ED=${D} +fi # Setup ABI cruft LIBDIR_VAR="LIBDIR_${ABI}" @@ -19,11 +20,11 @@ libdir="${ED}${DESTTREE}/${CONF_LIBDIR}" if [[ $# -lt 1 ]] ; then - helpers_die "${0##*/}: at least one argument needed" + __helpers_die "${0##*/}: at least one argument needed" exit 1 fi if [[ ! -d ${libdir} ]] ; then - install -d "${libdir}" || { helpers_die "${0##*/}: failed to install ${libdir}"; exit 1; } + install -d "${libdir}" || { __helpers_die "${0##*/}: failed to install ${libdir}"; exit 1; } fi ret=0 @@ -42,5 +43,5 @@ for x in "$@" ; do ((ret|=$?)) done -[[ $ret -ne 0 ]] && helpers_die "${0##*/} failed" +[[ $ret -ne 0 ]] && __helpers_die "${0##*/} failed" exit ${ret} diff --git a/portage_with_autodep/bin/ebuild-helpers/doman b/portage_with_autodep/bin/ebuild-helpers/doman index b4047ce..d680859 100755 --- a/portage_with_autodep/bin/ebuild-helpers/doman +++ b/portage_with_autodep/bin/ebuild-helpers/doman @@ -1,16 +1,17 @@ #!/bin/bash -# Copyright 1999-2011 Gentoo Foundation +# Copyright 1999-2012 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 source "${PORTAGE_BIN_PATH:-/usr/lib/portage/bin}"/isolated-functions.sh if [[ $# -lt 1 ]] ; then - helpers_die "${0##*/}: at least one argument needed" + __helpers_die "${0##*/}: at least one argument needed" exit 1 fi -[[ " ${FEATURES} " == *" force-prefix "* ]] || \ - case "$EAPI" in 0|1|2) ED=${D} ;; esac +if ! ___eapi_has_prefix_variables; then + ED=${D} +fi i18n="" @@ -58,10 +59,10 @@ for x in "$@" ; do ((ret|=1)) fi else - vecho "doman: '${x}' is probably not a man page; skipping" 1>&2 + __vecho "doman: '${x}' is probably not a man page; skipping" 1>&2 ((ret|=1)) fi done -[[ $ret -ne 0 ]] && helpers_die "${0##*/} failed" +[[ $ret -ne 0 ]] && __helpers_die "${0##*/} failed" exit ${ret} diff --git a/portage_with_autodep/bin/ebuild-helpers/domo b/portage_with_autodep/bin/ebuild-helpers/domo index d994343..9a8dda3 100755 --- a/portage_with_autodep/bin/ebuild-helpers/domo +++ b/portage_with_autodep/bin/ebuild-helpers/domo @@ -1,17 +1,18 @@ #!/bin/bash -# Copyright 1999-2011 Gentoo Foundation +# Copyright 1999-2012 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 source "${PORTAGE_BIN_PATH:-/usr/lib/portage/bin}"/isolated-functions.sh mynum=${#} if [ ${mynum} -lt 1 ] ; then - helpers_die "${0}: at least one argument needed" + __helpers_die "${0}: at least one argument needed" exit 1 fi -[[ " ${FEATURES} " == *" force-prefix "* ]] || \ - case "$EAPI" in 0|1|2) ED=${D} ;; esac +if ! ___eapi_has_prefix_variables; then + ED=${D} +fi if [ ! -d "${ED}${DESTTREE}/share/locale" ] ; then install -d "${ED}${DESTTREE}/share/locale/" @@ -34,5 +35,5 @@ for x in "$@" ; do ((ret|=$?)) done -[[ $ret -ne 0 ]] && helpers_die "${0##*/} failed" +[[ $ret -ne 0 ]] && __helpers_die "${0##*/} failed" exit $ret diff --git a/portage_with_autodep/bin/ebuild-helpers/dosbin b/portage_with_autodep/bin/ebuild-helpers/dosbin index d101c8a..361ca83 100755 --- a/portage_with_autodep/bin/ebuild-helpers/dosbin +++ b/portage_with_autodep/bin/ebuild-helpers/dosbin @@ -1,19 +1,20 @@ #!/bin/bash -# Copyright 1999-2011 Gentoo Foundation +# Copyright 1999-2012 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 source "${PORTAGE_BIN_PATH:-/usr/lib/portage/bin}"/isolated-functions.sh if [[ $# -lt 1 ]] ; then - helpers_die "${0##*/}: at least one argument needed" + __helpers_die "${0##*/}: at least one argument needed" exit 1 fi -[[ " ${FEATURES} " == *" force-prefix "* ]] || \ - case "$EAPI" in 0|1|2) ED=${D} ;; esac +if ! ___eapi_has_prefix_variables; then + ED=${D} +fi if [[ ! -d ${ED}${DESTTREE}/sbin ]] ; then - install -d "${ED}${DESTTREE}/sbin" || { helpers_die "${0##*/}: failed to install ${ED}${DESTTREE}/sbin"; exit 2; } + install -d "${ED}${DESTTREE}/sbin" || { __helpers_die "${0##*/}: failed to install ${ED}${DESTTREE}/sbin"; exit 2; } fi ret=0 @@ -28,5 +29,5 @@ for x in "$@" ; do ((ret|=$?)) done -[[ $ret -ne 0 ]] && helpers_die "${0##*/} failed" +[[ $ret -ne 0 ]] && __helpers_die "${0##*/} failed" exit ${ret} diff --git a/portage_with_autodep/bin/ebuild-helpers/dosed b/portage_with_autodep/bin/ebuild-helpers/dosed index f202df7..7db0629 100755 --- a/portage_with_autodep/bin/ebuild-helpers/dosed +++ b/portage_with_autodep/bin/ebuild-helpers/dosed @@ -1,14 +1,22 @@ #!/bin/bash -# Copyright 1999-2011 Gentoo Foundation +# Copyright 1999-2012 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 +source "${PORTAGE_BIN_PATH:-/usr/lib/portage/bin}"/isolated-functions.sh + +if ! ___eapi_has_dosed; then + die "'${0##*/}' has been banned for EAPI '$EAPI'" + exit 1 +fi + if [[ $# -lt 1 ]] ; then echo "!!! ${0##*/}: at least one argument needed" >&2 exit 1 fi -[[ " ${FEATURES} " == *" force-prefix "* ]] || \ - case "$EAPI" in 0|1|2) ED=${D} ;; esac +if ! ___eapi_has_prefix_variables; then + ED=${D} +fi ret=0 file_found=0 diff --git a/portage_with_autodep/bin/ebuild-helpers/dosym b/portage_with_autodep/bin/ebuild-helpers/dosym index 2489e22..649b100 100755 --- a/portage_with_autodep/bin/ebuild-helpers/dosym +++ b/portage_with_autodep/bin/ebuild-helpers/dosym @@ -5,12 +5,13 @@ source "${PORTAGE_BIN_PATH:-/usr/lib/portage/bin}"/isolated-functions.sh if [[ $# -ne 2 ]] ; then - helpers_die "${0##*/}: two arguments needed" + __helpers_die "${0##*/}: two arguments needed" exit 1 fi -[[ " ${FEATURES} " == *" force-prefix "* ]] || \ - case "$EAPI" in 0|1|2) ED=${D} ;; esac +if ! ___eapi_has_prefix_variables; then + ED=${D} +fi if [[ ${2} == */ ]] || \ [[ -d ${ED}${2} && ! -L ${ED}${2} ]] ; then @@ -26,5 +27,5 @@ target="${1}" ln -snf "${target}" "${ED}${2}" ret=$? -[[ $ret -ne 0 ]] && helpers_die "${0##*/} failed" +[[ $ret -ne 0 ]] && __helpers_die "${0##*/} failed" exit $ret diff --git a/portage_with_autodep/bin/ebuild-helpers/ecompress b/portage_with_autodep/bin/ebuild-helpers/ecompress index b61421b..71287b4 100755 --- a/portage_with_autodep/bin/ebuild-helpers/ecompress +++ b/portage_with_autodep/bin/ebuild-helpers/ecompress @@ -5,7 +5,7 @@ source "${PORTAGE_BIN_PATH:-/usr/lib/portage/bin}"/isolated-functions.sh if [[ -z $1 ]] ; then - helpers_die "${0##*/}: at least one argument needed" + __helpers_die "${0##*/}: at least one argument needed" exit 1 fi @@ -68,7 +68,7 @@ decompress_args() { case $1 in --suffix) - [[ -n $2 ]] && vecho "${0##*/}: --suffix takes no additional arguments" 1>&2 + [[ -n $2 ]] && __vecho "${0##*/}: --suffix takes no additional arguments" 1>&2 if [[ ! -e ${T}/.ecompress.suffix ]] ; then set -e @@ -93,7 +93,7 @@ case $1 in cat "${T}/.ecompress.suffix" ;; --bin) - [[ -n $2 ]] && vecho "${0##*/}: --bin takes no additional arguments" 1>&2 + [[ -n $2 ]] && __vecho "${0##*/}: --bin takes no additional arguments" 1>&2 echo "${PORTAGE_COMPRESS} ${PORTAGE_COMPRESS_FLAGS}" ;; @@ -104,18 +104,18 @@ case $1 in >> "$x" ((ret|=$?)) done - [[ $ret -ne 0 ]] && helpers_die "${0##*/} failed" + [[ $ret -ne 0 ]] && __helpers_die "${0##*/} failed" exit $ret ;; --dequeue) - [[ -n $2 ]] && vecho "${0##*/}: --dequeue takes no additional arguments" 1>&2 + [[ -n $2 ]] && __vecho "${0##*/}: --dequeue takes no additional arguments" 1>&2 find "${D}" -name '*.ecompress.file' -print0 \ | sed -e 's:\.ecompress\.file::g' \ | ${XARGS} -0 ecompress find "${D}" -name '*.ecompress.file' -print0 | ${XARGS} -0 rm -f ;; --*) - helpers_die "${0##*/}: unknown arguments '$*'" + __helpers_die "${0##*/}: unknown arguments '$*'" exit 1 ;; *) @@ -155,7 +155,7 @@ case $1 in # Finally, let's actually do some real work "${PORTAGE_COMPRESS}" ${PORTAGE_COMPRESS_FLAGS} "$@" ret=$? - [[ $ret -ne 0 ]] && helpers_die "${0##*/} failed" + [[ $ret -ne 0 ]] && __helpers_die "${0##*/} failed" exit $ret ;; esac diff --git a/portage_with_autodep/bin/ebuild-helpers/ecompressdir b/portage_with_autodep/bin/ebuild-helpers/ecompressdir index a2c9e52..eca5888 100755 --- a/portage_with_autodep/bin/ebuild-helpers/ecompressdir +++ b/portage_with_autodep/bin/ebuild-helpers/ecompressdir @@ -1,18 +1,21 @@ #!/bin/bash -# Copyright 1999-2011 Gentoo Foundation +# Copyright 1999-2013 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 source "${PORTAGE_BIN_PATH:-/usr/lib/portage/bin}"/helper-functions.sh if [[ -z $1 ]] ; then - helpers_die "${0##*/}: at least one argument needed" + __helpers_die "${0##*/}: at least one argument needed" exit 1 fi -[[ " ${FEATURES} " == *" force-prefix "* ]] || \ - case "$EAPI" in 0|1|2) ED=${D} EPREFIX= ;; esac +if ! ___eapi_has_prefix_variables; then + ED=${D} EPREFIX= +fi -case $1 in +SIZE_LIMIT='' +while [[ $# -gt 0 ]] ; do + case $1 in --ignore) shift for skip in "$@" ; do @@ -27,45 +30,66 @@ case $1 in set -- "${@/#/${ED}}" ret=0 for x in "$@" ; do - >> "$x" + # Stash the limit in the .dir file so we can reload it later. + printf "${SIZE_LIMIT}" > "${x}" ((ret|=$?)) done - [[ $ret -ne 0 ]] && helpers_die "${0##*/} failed" + [[ $ret -ne 0 ]] && __helpers_die "${0##*/} failed" exit $ret ;; --dequeue) - [[ -n $2 ]] && vecho "${0##*/}: --dequeue takes no additional arguments" 1>&2 + [[ -n $2 ]] && __vecho "${0##*/}: --dequeue takes no additional arguments" 1>&2 find "${ED}" -name '*.ecompress.dir' -print0 \ | sed -e 's:\.ecompress\.dir::g' -e "s:${ED}:/:g" \ | ${XARGS} -0 ecompressdir find "${ED}" -name '*.ecompress.skip' -print0 | ${XARGS} -0 rm -f exit 0 ;; + --limit) + SIZE_LIMIT=$2 + shift + ;; --*) - helpers_die "${0##*/}: unknown arguments '$*'" + __helpers_die "${0##*/}: unknown arguments '$*'" exit 1 ;; -esac + *) + break + ;; + esac + shift +done # figure out the new suffix suffix=$(ecompress --suffix) -# funk_up_dir(action, suffix, binary) +# funk_up_dir(action, suffix, binary, [size_limit]) # - action: compress or decompress # - suffix: the compression suffix to work with # - binary: the program to execute that'll compress/decompress +# - size_limit: if compressing, skip files smaller than this # The directory we act on is implied in the ${dir} variable funk_up_dir() { - local act=$1 suffix=$2 binary=$3 + local act=$1 suffix=$2 binary=$3 size_limit=$4 local negate="" [[ ${act} == "compress" ]] && negate="!" + local ret=0 # first we act on all the files - find "${dir}" -type f ${negate} -iname '*'${suffix} -print0 | ${XARGS} -0 ${binary} + local args=( + -type f + ${negate} -iname "*${suffix}" + ) + [[ -n ${size_limit} ]] && args+=( -size "+${size_limit}c" ) + find "${dir}" "${args[@]}" -print0 | ${XARGS} -0 ${binary} ((ret|=$?)) - find "${dir}" -type l -print0 | \ + # Repeat until nothing changes, in order to handle multiple + # levels of indirection (see bug #470916). + local -i indirection=0 + while true ; do + local something_changed= while read -r -d $'\0' brokenlink ; do [[ -e ${brokenlink} ]] && continue olddest=$(readlink "${brokenlink}") @@ -80,15 +104,34 @@ funk_up_dir() { skip_dir_dest=${T}/ecompress-skip/${actual_dir#${ED}}/${brokenlink%/*}/${olddest} fi [[ -e ${skip_dir_dest} ]] && continue - [[ ${act} == "compress" ]] \ - && newdest="${olddest}${suffix}" \ - || newdest="${olddest%${suffix}}" + if [[ ${act} == "compress" ]] ; then + newdest=${olddest}${suffix} + else + [[ ${olddest} == *${suffix} ]] || continue + newdest=${olddest%${suffix}} + fi + if [[ "${newdest}" == /* ]] ; then + [[ -f "${D}${newdest}" ]] || continue + else + [[ -f "${dir}/${brokenlink%/*}/${newdest}" ]] || continue + fi + something_changed=${brokenlink} rm -f "${brokenlink}" [[ ${act} == "compress" ]] \ && ln -snf "${newdest}" "${brokenlink}${suffix}" \ || ln -snf "${newdest}" "${brokenlink%${suffix}}" ((ret|=$?)) + done < <(find "${dir}" -type l -print0) + [[ -n ${something_changed} ]] || break + (( indirection++ )) + if (( indirection >= 100 )) ; then + # Protect against possibility of a bug triggering an endless loop. + eerror "ecompressdir: too many levels of indirection for" \ + "'${actual_dir#${ED}}/${something_changed#./}'" + break + fi done + return ${ret} } # _relocate_skip_dirs(srctree, dsttree) @@ -124,13 +167,13 @@ decompressors=( ".lzma" "unxz -f" ) -multijob_init +__multijob_init for dir in "$@" ; do dir=${dir#/} dir="${ED}${dir}" if [[ ! -d ${dir} ]] ; then - vecho "${0##*/}: /${dir#${ED}} does not exist!" + __vecho "${0##*/}: /${dir#${ED}} does not exist!" continue fi cd "${dir}" @@ -142,39 +185,41 @@ for dir in "$@" ; do # since we've been requested to compress the whole dir, # delete any individual queued requests + size_limit=${SIZE_LIMIT:-$(<"${actual_dir}.ecompress.dir")} rm -f "${actual_dir}.ecompress.dir" find "${dir}" -type f -name '*.ecompress.file' -print0 | ${XARGS} -0 rm -f # not uncommon for packages to compress doc files themselves - for (( d = 0; d < ${#decompressors[@]}; d += 2 )) ; do + for (( i = 0; i < ${#decompressors[@]}; i += 2 )) ; do # It's faster to parallelize at this stage than to try to # parallelize the compressors. This is because the find|xargs # ends up launching less compressors overall, so the overhead # of forking children ends up dominating. ( - multijob_child_init + __multijob_child_init funk_up_dir "decompress" "${decompressors[i]}" "${decompressors[i+1]}" ) & - multijob_post_fork + __multijob_post_fork : $(( ret |= $? )) done + __multijob_finish + : $(( ret |= $? )) + # forcibly break all hard links as some compressors whine about it find "${dir}" -type f -links +1 -exec env file="{}" sh -c \ 'cp -p "${file}" "${file}.ecompress.break" ; mv -f "${file}.ecompress.break" "${file}"' \; - multijob_finish - : $(( ret |= $? )) - # now lets do our work if [[ -n ${suffix} ]] ; then - vecho "${0##*/}: $(ecompress --bin) /${actual_dir#${ED}}" - funk_up_dir "compress" "${suffix}" "ecompress" + __vecho "${0##*/}: $(ecompress --bin) /${actual_dir#${ED}}" + funk_up_dir "compress" "${suffix}" "ecompress" "${size_limit}" + : $(( ret |= $? )) fi # finally, restore the skipped stuff restore_skip_dirs done -[[ $ret -ne 0 ]] && helpers_die "${0##*/} failed" +[[ $ret -ne 0 ]] && __helpers_die "${0##*/} failed" exit ${ret} diff --git a/portage_with_autodep/bin/ebuild-helpers/emake b/portage_with_autodep/bin/ebuild-helpers/emake index d842781..69d836f 100755 --- a/portage_with_autodep/bin/ebuild-helpers/emake +++ b/portage_with_autodep/bin/ebuild-helpers/emake @@ -24,5 +24,5 @@ fi ${MAKE:-make} ${MAKEOPTS} ${EXTRA_EMAKE} "$@" ret=$? -[[ $ret -ne 0 ]] && helpers_die "${0##*/} failed" +[[ $ret -ne 0 ]] && __helpers_die "${0##*/} failed" exit $ret diff --git a/portage_with_autodep/bin/ebuild-helpers/fowners b/portage_with_autodep/bin/ebuild-helpers/fowners index a213c9e..cee4108 100755 --- a/portage_with_autodep/bin/ebuild-helpers/fowners +++ b/portage_with_autodep/bin/ebuild-helpers/fowners @@ -4,8 +4,9 @@ source "${PORTAGE_BIN_PATH:-/usr/lib/portage/bin}"/isolated-functions.sh -[[ " ${FEATURES} " == *" force-prefix "* ]] || \ - case "$EAPI" in 0|1|2) EPREFIX= ED=${D} ;; esac +if ! ___eapi_has_prefix_variables; then + EPREFIX= ED=${D} +fi # we can't prefix all arguments because # chown takes random options @@ -13,10 +14,5 @@ slash="/" chown "${@/#${slash}/${ED}${slash}}" ret=$? -if [[ ${ret} != 0 && -n ${EPREFIX} && ${EUID} != 0 ]] ; then - ewarn "fowners failure ignored in Prefix with non-privileged user" - exit 0 -fi - -[[ $ret -ne 0 ]] && helpers_die "${0##*/} failed" +[[ $ret -ne 0 ]] && __helpers_die "${0##*/} failed" exit $ret diff --git a/portage_with_autodep/bin/ebuild-helpers/fperms b/portage_with_autodep/bin/ebuild-helpers/fperms index a2f77ea..d854ebb 100755 --- a/portage_with_autodep/bin/ebuild-helpers/fperms +++ b/portage_with_autodep/bin/ebuild-helpers/fperms @@ -1,16 +1,17 @@ #!/bin/bash -# Copyright 1999-2011 Gentoo Foundation +# Copyright 1999-2012 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 source "${PORTAGE_BIN_PATH:-/usr/lib/portage/bin}"/isolated-functions.sh -[[ " ${FEATURES} " == *" force-prefix "* ]] || \ - case "$EAPI" in 0|1|2) ED=${D} ;; esac +if ! ___eapi_has_prefix_variables; then + ED=${D} +fi # we can't prefix all arguments because # chmod takes random options slash="/" chmod "${@/#${slash}/${ED}${slash}}" ret=$? -[[ $ret -ne 0 ]] && helpers_die "${0##*/} failed" +[[ $ret -ne 0 ]] && __helpers_die "${0##*/} failed" exit $ret diff --git a/portage_with_autodep/bin/ebuild-helpers/newbin b/portage_with_autodep/bin/ebuild-helpers/newbin index bf98744..59a0db2 100755..120000 --- a/portage_with_autodep/bin/ebuild-helpers/newbin +++ b/portage_with_autodep/bin/ebuild-helpers/newbin @@ -1,22 +1 @@ -#!/bin/bash -# Copyright 1999-2011 Gentoo Foundation -# Distributed under the terms of the GNU General Public License v2 - -source "${PORTAGE_BIN_PATH:-/usr/lib/portage/bin}"/isolated-functions.sh - -if [[ -z ${T} ]] || [[ -z ${2} ]] ; then - helpers_die "${0##*/}: Need two arguments, old file and new file" - exit 1 -fi - -if [ ! -e "$1" ] ; then - helpers_die "!!! ${0##*/}: $1 does not exist" - exit 1 -fi - -(($#>2)) && \ - eqawarn "QA Notice: ${0##*/} called with more than 2 arguments: ${@:3}" - -rm -rf "${T}/${2}" && \ -cp -f "${1}" "${T}/${2}" && \ -exec dobin "${T}/${2}" +newins
\ No newline at end of file diff --git a/portage_with_autodep/bin/ebuild-helpers/newconfd b/portage_with_autodep/bin/ebuild-helpers/newconfd index fa3710d..59a0db2 100755..120000 --- a/portage_with_autodep/bin/ebuild-helpers/newconfd +++ b/portage_with_autodep/bin/ebuild-helpers/newconfd @@ -1,22 +1 @@ -#!/bin/bash -# Copyright 1999-2011 Gentoo Foundation -# Distributed under the terms of the GNU General Public License v2 - -source "${PORTAGE_BIN_PATH:-/usr/lib/portage/bin}"/isolated-functions.sh - -if [[ -z ${T} ]] || [[ -z ${2} ]] ; then - helpers_die "${0##*/}: Need two arguments, old file and new file" - exit 1 -fi - -if [ ! -e "$1" ] ; then - helpers_die "!!! ${0##*/}: $1 does not exist" - exit 1 -fi - -(($#>2)) && \ - eqawarn "QA Notice: ${0##*/} called with more than 2 arguments: ${@:3}" - -rm -rf "${T}/${2}" && \ -cp -f "${1}" "${T}/${2}" && \ -exec doconfd "${T}/${2}" +newins
\ No newline at end of file diff --git a/portage_with_autodep/bin/ebuild-helpers/newdoc b/portage_with_autodep/bin/ebuild-helpers/newdoc index df6fb1d..59a0db2 100755..120000 --- a/portage_with_autodep/bin/ebuild-helpers/newdoc +++ b/portage_with_autodep/bin/ebuild-helpers/newdoc @@ -1,22 +1 @@ -#!/bin/bash -# Copyright 1999-2011 Gentoo Foundation -# Distributed under the terms of the GNU General Public License v2 - -source "${PORTAGE_BIN_PATH:-/usr/lib/portage/bin}"/isolated-functions.sh - -if [[ -z ${T} ]] || [[ -z ${2} ]] ; then - helpers_die "${0##*/}: Need two arguments, old file and new file" - exit 1 -fi - -if [ ! -e "$1" ] ; then - helpers_die "!!! ${0##*/}: $1 does not exist" - exit 1 -fi - -(($#>2)) && \ - eqawarn "QA Notice: ${0##*/} called with more than 2 arguments: ${@:3}" - -rm -rf "${T}/${2}" && \ -cp -f "${1}" "${T}/${2}" && \ -exec dodoc "${T}/${2}" +newins
\ No newline at end of file diff --git a/portage_with_autodep/bin/ebuild-helpers/newenvd b/portage_with_autodep/bin/ebuild-helpers/newenvd index c54af05..59a0db2 100755..120000 --- a/portage_with_autodep/bin/ebuild-helpers/newenvd +++ b/portage_with_autodep/bin/ebuild-helpers/newenvd @@ -1,22 +1 @@ -#!/bin/bash -# Copyright 1999-2011 Gentoo Foundation -# Distributed under the terms of the GNU General Public License v2 - -source "${PORTAGE_BIN_PATH:-/usr/lib/portage/bin}"/isolated-functions.sh - -if [[ -z ${T} ]] || [[ -z ${2} ]] ; then - helpers_die "${0##*/}: Need two arguments, old file and new file" - exit 1 -fi - -if [ ! -e "$1" ] ; then - helpers_die "!!! ${0##*/}: $1 does not exist" - exit 1 -fi - -(($#>2)) && \ - eqawarn "QA Notice: ${0##*/} called with more than 2 arguments: ${@:3}" - -rm -rf "${T}/${2}" && \ -cp -f "${1}" "${T}/${2}" && \ -exec doenvd "${T}/${2}" +newins
\ No newline at end of file diff --git a/portage_with_autodep/bin/ebuild-helpers/newexe b/portage_with_autodep/bin/ebuild-helpers/newexe index 9bcf64b..59a0db2 100755..120000 --- a/portage_with_autodep/bin/ebuild-helpers/newexe +++ b/portage_with_autodep/bin/ebuild-helpers/newexe @@ -1,22 +1 @@ -#!/bin/bash -# Copyright 1999-2011 Gentoo Foundation -# Distributed under the terms of the GNU General Public License v2 - -source "${PORTAGE_BIN_PATH:-/usr/lib/portage/bin}"/isolated-functions.sh - -if [[ -z ${T} ]] || [[ -z ${2} ]] ; then - helpers_die "${0##*/}: Need two arguments, old file and new file" - exit 1 -fi - -if [ ! -e "$1" ] ; then - helpers_die "!!! ${0##*/}: $1 does not exist" - exit 1 -fi - -(($#>2)) && \ - eqawarn "QA Notice: ${0##*/} called with more than 2 arguments: ${@:3}" - -rm -rf "${T}/${2}" && \ -cp -f "${1}" "${T}/${2}" && \ -exec doexe "${T}/${2}" +newins
\ No newline at end of file diff --git a/portage_with_autodep/bin/ebuild-helpers/newinitd b/portage_with_autodep/bin/ebuild-helpers/newinitd index 03bbe68..59a0db2 100755..120000 --- a/portage_with_autodep/bin/ebuild-helpers/newinitd +++ b/portage_with_autodep/bin/ebuild-helpers/newinitd @@ -1,22 +1 @@ -#!/bin/bash -# Copyright 1999-2011 Gentoo Foundation -# Distributed under the terms of the GNU General Public License v2 - -source "${PORTAGE_BIN_PATH:-/usr/lib/portage/bin}"/isolated-functions.sh - -if [[ -z ${T} ]] || [[ -z ${2} ]] ; then - helpers_die "${0##*/}: Need two arguments, old file and new file" - exit 1 -fi - -if [ ! -e "$1" ] ; then - helpers_die "!!! ${0##*/}: $1 does not exist" - exit 1 -fi - -(($#>2)) && \ - eqawarn "QA Notice: ${0##*/} called with more than 2 arguments: ${@:3}" - -rm -rf "${T}/${2}" && \ -cp -f "${1}" "${T}/${2}" && \ -exec doinitd "${T}/${2}" +newins
\ No newline at end of file diff --git a/portage_with_autodep/bin/ebuild-helpers/newins b/portage_with_autodep/bin/ebuild-helpers/newins index adf2d80..0335985 100755 --- a/portage_with_autodep/bin/ebuild-helpers/newins +++ b/portage_with_autodep/bin/ebuild-helpers/newins @@ -1,38 +1,57 @@ #!/bin/bash -# Copyright 1999-2011 Gentoo Foundation +# Copyright 1999-2012 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 source "${PORTAGE_BIN_PATH:-/usr/lib/portage/bin}"/isolated-functions.sh +helper=${0##*/} + if [[ -z ${T} ]] || [[ -z ${2} ]] ; then - helpers_die "${0##*/}: Need two arguments, old file and new file" + __helpers_die "${helper}: Need two arguments, old file and new file" exit 1 fi -if [ ! -e "$1" ] ; then - helpers_die "!!! ${0##*/}: $1 does not exist" - exit 1 +(($#>2)) && \ + eqawarn "QA Notice: ${helper} called with more than 2 arguments: ${@:3}" + +stdin= +if ___eapi_newins_supports_reading_from_standard_input && [[ $1 == "-" ]]; then + stdin=yes fi -(($#>2)) && \ - eqawarn "QA Notice: ${0##*/} called with more than 2 arguments: ${@:3}" - -rm -rf "${T}/${2}" || exit $? -case "$EAPI" in - 0|1|2|3|3_pre2) - cp "$1" "$T/$2" || exit $? - ;; - *) - cp -P "$1" "$T/$2" - ret=$? - if [[ $ret -ne 0 ]] ; then - helpers_die "${0##*/} failed" - exit $ret +TMP=$(mktemp -d "${T}/.newins_tmp_XXXXXX") +trap 'rm -rf "${TMP}"' EXIT + +if [[ ${stdin} ]] ; then + if [[ -t 0 ]] ; then + __helpers_die "!!! ${helper}: Input is from a terminal" + exit 1 + fi + cat > "${TMP}/$2" + ret=$? +else + if [[ ! -e $1 ]] ; then + __helpers_die "!!! ${helper}: $1 does not exist" + exit 1 + fi + + cp_args="-f" + if [[ ${helper} == newins ]] ; then + if ___eapi_doins_and_newins_preserve_symlinks; then + cp_args+=" -P" fi - ;; -esac -doins "${T}/${2}" + fi + + cp ${cp_args} "$1" "${TMP}/$2" + ret=$? +fi + +if [[ ${ret} -ne 0 ]] ; then + __helpers_die "${0##*/} failed" + exit ${ret} +fi + +do${helper#new} "${TMP}/$2" ret=$? -rm -rf "${T}/${2}" -[[ $ret -ne 0 ]] && helpers_die "${0##*/} failed" +[[ $ret -ne 0 ]] && __helpers_die "${helper} failed" exit $ret diff --git a/portage_with_autodep/bin/ebuild-helpers/newlib.a b/portage_with_autodep/bin/ebuild-helpers/newlib.a index 7ff8195..59a0db2 100755..120000 --- a/portage_with_autodep/bin/ebuild-helpers/newlib.a +++ b/portage_with_autodep/bin/ebuild-helpers/newlib.a @@ -1,22 +1 @@ -#!/bin/bash -# Copyright 1999-2011 Gentoo Foundation -# Distributed under the terms of the GNU General Public License v2 - -source "${PORTAGE_BIN_PATH:-/usr/lib/portage/bin}"/isolated-functions.sh - -if [[ -z ${T} ]] || [[ -z ${2} ]] ; then - helpers_die "${0##*/}: Need two arguments, old file and new file" - exit 1 -fi - -if [ ! -e "$1" ] ; then - helpers_die "!!! ${0##*/}: $1 does not exist" - exit 1 -fi - -(($#>2)) && \ - eqawarn "QA Notice: ${0##*/} called with more than 2 arguments: ${@:3}" - -rm -rf "${T}/${2}" && \ -cp -f "${1}" "${T}/${2}" && \ -exec dolib.a "${T}/${2}" +newins
\ No newline at end of file diff --git a/portage_with_autodep/bin/ebuild-helpers/newlib.so b/portage_with_autodep/bin/ebuild-helpers/newlib.so index fd4c097..59a0db2 100755..120000 --- a/portage_with_autodep/bin/ebuild-helpers/newlib.so +++ b/portage_with_autodep/bin/ebuild-helpers/newlib.so @@ -1,22 +1 @@ -#!/bin/bash -# Copyright 1999-2011 Gentoo Foundation -# Distributed under the terms of the GNU General Public License v2 - -source "${PORTAGE_BIN_PATH:-/usr/lib/portage/bin}"/isolated-functions.sh - -if [[ -z ${T} ]] || [[ -z ${2} ]] ; then - helpers_die "${0##*/}: Need two arguments, old file and new file" - exit 1 -fi - -if [ ! -e "$1" ] ; then - helpers_die "!!! ${0##*/}: $1 does not exist" - exit 1 -fi - -(($#>2)) && \ - eqawarn "QA Notice: ${0##*/} called with more than 2 arguments: ${@:3}" - -rm -rf "${T}/${2}" && \ -cp -f "${1}" "${T}/${2}" && \ -exec dolib.so "${T}/${2}" +newins
\ No newline at end of file diff --git a/portage_with_autodep/bin/ebuild-helpers/newman b/portage_with_autodep/bin/ebuild-helpers/newman index 889e0f9..59a0db2 100755..120000 --- a/portage_with_autodep/bin/ebuild-helpers/newman +++ b/portage_with_autodep/bin/ebuild-helpers/newman @@ -1,22 +1 @@ -#!/bin/bash -# Copyright 1999-2011 Gentoo Foundation -# Distributed under the terms of the GNU General Public License v2 - -source "${PORTAGE_BIN_PATH:-/usr/lib/portage/bin}"/isolated-functions.sh - -if [[ -z ${T} ]] || [[ -z ${2} ]] ; then - helpers_die "${0##*/}: Need two arguments, old file and new file" - exit 1 -fi - -if [ ! -e "$1" ] ; then - helpers_die "!!! ${0##*/}: $1 does not exist" - exit 1 -fi - -(($#>2)) && \ - eqawarn "QA Notice: ${0##*/} called with more than 2 arguments: ${@:3}" - -rm -rf "${T}/${2}" && \ -cp -f "${1}" "${T}/${2}" && \ -exec doman "${T}/${2}" +newins
\ No newline at end of file diff --git a/portage_with_autodep/bin/ebuild-helpers/newsbin b/portage_with_autodep/bin/ebuild-helpers/newsbin index 9df0af2..59a0db2 100755..120000 --- a/portage_with_autodep/bin/ebuild-helpers/newsbin +++ b/portage_with_autodep/bin/ebuild-helpers/newsbin @@ -1,22 +1 @@ -#!/bin/bash -# Copyright 1999-2011 Gentoo Foundation -# Distributed under the terms of the GNU General Public License v2 - -source "${PORTAGE_BIN_PATH:-/usr/lib/portage/bin}"/isolated-functions.sh - -if [[ -z ${T} ]] || [[ -z ${2} ]] ; then - helpers_die "${0##*/}: Need two arguments, old file and new file" - exit 1 -fi - -if [ ! -e "$1" ] ; then - helpers_die "!!! ${0##*/}: $1 does not exist" - exit 1 -fi - -(($#>2)) && \ - eqawarn "QA Notice: ${0##*/} called with more than 2 arguments: ${@:3}" - -rm -rf "${T}/${2}" && \ -cp -f "${1}" "${T}/${2}" && \ -exec dosbin "${T}/${2}" +newins
\ No newline at end of file diff --git a/portage_with_autodep/bin/ebuild-helpers/portageq b/portage_with_autodep/bin/ebuild-helpers/portageq index ec30b66..b67b03f 100755 --- a/portage_with_autodep/bin/ebuild-helpers/portageq +++ b/portage_with_autodep/bin/ebuild-helpers/portageq @@ -1,8 +1,10 @@ #!/bin/bash -# Copyright 2009-2010 Gentoo Foundation +# Copyright 2009-2013 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 PORTAGE_BIN_PATH=${PORTAGE_BIN_PATH:-/usr/lib/portage/bin} PORTAGE_PYM_PATH=${PORTAGE_PYM_PATH:-/usr/lib/portage/pym} -PYTHONPATH=$PORTAGE_PYM_PATH${PYTHONPATH:+:}$PYTHONPATH \ +# Use safe cwd, avoiding unsafe import for bug #469338. +cd "${PORTAGE_PYM_PATH}" +PYTHONPATH=${PORTAGE_PYTHONPATH:-${PORTAGE_PYM_PATH}} \ exec "${PORTAGE_PYTHON:-/usr/bin/python}" "$PORTAGE_BIN_PATH/portageq" "$@" diff --git a/portage_with_autodep/bin/ebuild-helpers/prepall b/portage_with_autodep/bin/ebuild-helpers/prepall index 49e646c..fb5c2db 100755 --- a/portage_with_autodep/bin/ebuild-helpers/prepall +++ b/portage_with_autodep/bin/ebuild-helpers/prepall @@ -1,11 +1,12 @@ #!/bin/bash -# Copyright 1999-2011 Gentoo Foundation +# Copyright 1999-2012 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 source "${PORTAGE_BIN_PATH:-/usr/lib/portage/bin}"/isolated-functions.sh -[[ " ${FEATURES} " == *" force-prefix "* ]] || \ - case "$EAPI" in 0|1|2) ED=${D} ;; esac +if ! ___eapi_has_prefix_variables; then + ED=${D} +fi if has chflags $FEATURES ; then # Save all the file flags for restoration at the end of prepall. diff --git a/portage_with_autodep/bin/ebuild-helpers/prepalldocs b/portage_with_autodep/bin/ebuild-helpers/prepalldocs index 560a02b..3094661 100755 --- a/portage_with_autodep/bin/ebuild-helpers/prepalldocs +++ b/portage_with_autodep/bin/ebuild-helpers/prepalldocs @@ -1,15 +1,21 @@ #!/bin/bash -# Copyright 1999-2011 Gentoo Foundation +# Copyright 1999-2012 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 source "${PORTAGE_BIN_PATH:-/usr/lib/portage/bin}"/isolated-functions.sh +if ___eapi_has_docompress; then + die "'${0##*/}' has been banned for EAPI '$EAPI'" + exit 1 +fi + if [[ -n $1 ]] ; then - vecho "${0##*/}: invalid usage; takes no arguments" 1>&2 + __vecho "${0##*/}: invalid usage; takes no arguments" 1>&2 fi -[[ " ${FEATURES} " == *" force-prefix "* ]] || \ - case "$EAPI" in 0|1|2) ED=${D} ;; esac +if ! ___eapi_has_prefix_variables; then + ED=${D} +fi [[ -d ${ED}usr/share/doc ]] || exit 0 diff --git a/portage_with_autodep/bin/ebuild-helpers/prepallinfo b/portage_with_autodep/bin/ebuild-helpers/prepallinfo index db9bbfa..1a20275 100755 --- a/portage_with_autodep/bin/ebuild-helpers/prepallinfo +++ b/portage_with_autodep/bin/ebuild-helpers/prepallinfo @@ -1,11 +1,12 @@ #!/bin/bash -# Copyright 1999-2011 Gentoo Foundation +# Copyright 1999-2012 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 source "${PORTAGE_BIN_PATH:-/usr/lib/portage/bin}"/isolated-functions.sh -[[ " ${FEATURES} " == *" force-prefix "* ]] || \ - case "$EAPI" in 0|1|2) ED=${D} ;; esac +if ! ___eapi_has_prefix_variables; then + ED=${D} +fi [[ -d ${ED}usr/share/info ]] || exit 0 diff --git a/portage_with_autodep/bin/ebuild-helpers/prepallman b/portage_with_autodep/bin/ebuild-helpers/prepallman index dee1c72..5331eaf 100755 --- a/portage_with_autodep/bin/ebuild-helpers/prepallman +++ b/portage_with_autodep/bin/ebuild-helpers/prepallman @@ -1,22 +1,22 @@ #!/bin/bash -# Copyright 1999-2011 Gentoo Foundation +# Copyright 1999-2012 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 source "${PORTAGE_BIN_PATH:-/usr/lib/portage/bin}"/isolated-functions.sh # replaced by controllable compression in EAPI 4 -has "${EAPI}" 0 1 2 3 || exit 0 +___eapi_has_docompress && exit 0 -[[ " ${FEATURES} " == *" force-prefix "* ]] || \ - case "$EAPI" in 0|1|2) ED=${D} ;; esac +if ! ___eapi_has_prefix_variables; then + ED=${D} +fi ret=0 -find "${ED}" -type d -name man > "${T}"/prepallman.filelist -while read -r mandir ; do +while IFS= read -r -d '' mandir ; do mandir=${mandir#${ED}} prepman "${mandir%/man}" ((ret|=$?)) -done < "${T}"/prepallman.filelist +done < <(find "${ED}" -type d -name man -print0) exit ${ret} diff --git a/portage_with_autodep/bin/ebuild-helpers/prepallstrip b/portage_with_autodep/bin/ebuild-helpers/prepallstrip index 28320d9..1aa6686 100755 --- a/portage_with_autodep/bin/ebuild-helpers/prepallstrip +++ b/portage_with_autodep/bin/ebuild-helpers/prepallstrip @@ -1,8 +1,11 @@ #!/bin/bash -# Copyright 1999-2011 Gentoo Foundation +# Copyright 1999-2012 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 -[[ " ${FEATURES} " == *" force-prefix "* ]] || \ - case "$EAPI" in 0|1|2) ED=${D} ;; esac +source "${PORTAGE_BIN_PATH:-/usr/lib/portage/bin}"/isolated-functions.sh + +if ! ___eapi_has_prefix_variables; then + ED=${D} +fi exec prepstrip "${ED}" diff --git a/portage_with_autodep/bin/ebuild-helpers/prepinfo b/portage_with_autodep/bin/ebuild-helpers/prepinfo index ffe2ece..5afc18a 100755 --- a/portage_with_autodep/bin/ebuild-helpers/prepinfo +++ b/portage_with_autodep/bin/ebuild-helpers/prepinfo @@ -1,11 +1,12 @@ #!/bin/bash -# Copyright 1999-2011 Gentoo Foundation +# Copyright 1999-2012 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 source "${PORTAGE_BIN_PATH:-/usr/lib/portage/bin}"/isolated-functions.sh -[[ " ${FEATURES} " == *" force-prefix "* ]] || \ - case "$EAPI" in 0|1|2) ED=${D} ;; esac +if ! ___eapi_has_prefix_variables; then + ED=${D} +fi if [[ -z $1 ]] ; then infodir="/usr/share/info" @@ -19,7 +20,7 @@ fi if [[ ! -d ${ED}${infodir} ]] ; then if [[ -n $1 ]] ; then - vecho "${0##*/}: '${infodir}' does not exist!" + __vecho "${0##*/}: '${infodir}' does not exist!" exit 1 else exit 0 @@ -33,5 +34,5 @@ find "${ED}${infodir}" -type d -print0 | while read -r -d $'\0' x ; do rm -f "${x}"/dir{,.info}{,.gz,.bz2} done -has "${EAPI}" 0 1 2 3 || exit 0 +___eapi_has_docompress && exit 0 exec ecompressdir --queue "${infodir}" diff --git a/portage_with_autodep/bin/ebuild-helpers/preplib b/portage_with_autodep/bin/ebuild-helpers/preplib deleted file mode 100755 index 6e91cf3..0000000 --- a/portage_with_autodep/bin/ebuild-helpers/preplib +++ /dev/null @@ -1,31 +0,0 @@ -#!/bin/bash -# Copyright 1999-2011 Gentoo Foundation -# Distributed under the terms of the GNU General Public License v2 - -source "${PORTAGE_BIN_PATH:-/usr/lib/portage/bin}"/isolated-functions.sh - -eqawarn "QA Notice: Deprecated call to 'preplib'" - -[[ " ${FEATURES} " == *" force-prefix "* ]] || \ - case "$EAPI" in 0|1|2) ED=${D} ;; esac - -LIBDIR_VAR="LIBDIR_${ABI}" -if [ -n "${ABI}" -a -n "${!LIBDIR_VAR}" ]; then - CONF_LIBDIR="${!LIBDIR_VAR}" -fi -unset LIBDIR_VAR - -if [ -z "${CONF_LIBDIR}" ]; then - # we need this to default to lib so that things dont break - CONF_LIBDIR="lib" -fi - -if [ -z "$1" ] ; then - z="${ED}usr/${CONF_LIBDIR}" -else - z="${ED}$1/${CONF_LIBDIR}" -fi - -if [ -d "${z}" ] ; then - ldconfig -n -N "${z}" -fi diff --git a/portage_with_autodep/bin/ebuild-helpers/prepman b/portage_with_autodep/bin/ebuild-helpers/prepman index f96b641..fb5dcb4 100755 --- a/portage_with_autodep/bin/ebuild-helpers/prepman +++ b/portage_with_autodep/bin/ebuild-helpers/prepman @@ -1,13 +1,17 @@ #!/bin/bash -# Copyright 1999-2011 Gentoo Foundation +# Copyright 1999-2012 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 +# Do not compress man pages which are smaller than this (in bytes). #169260 +SIZE_LIMIT='128' + source "${PORTAGE_BIN_PATH:-/usr/lib/portage/bin}"/isolated-functions.sh -[[ " ${FEATURES} " == *" force-prefix "* ]] || \ - case "$EAPI" in 0|1|2) ED=${D} ;; esac +if ! ___eapi_has_prefix_variables; then + ED=${D} +fi -if [[ -z $1 ]] ; then +if [[ -z $1 ]] ; then mandir="${ED}usr/share/man" else mandir="${ED}$1/man" @@ -19,7 +23,7 @@ if [[ ! -d ${mandir} ]] ; then fi # replaced by controllable compression in EAPI 4 -has "${EAPI}" 0 1 2 3 || exit 0 +___eapi_has_docompress && exit 0 shopt -s nullglob @@ -30,6 +34,6 @@ for subdir in "${mandir}"/man* "${mandir}"/*/man* ; do [[ -d ${subdir} ]] && really_is_mandir=1 && break done -[[ ${really_is_mandir} == 1 ]] && exec ecompressdir --queue "${mandir#${ED}}" +[[ ${really_is_mandir} == 1 ]] && exec ecompressdir --limit ${SIZE_LIMIT} --queue "${mandir#${ED}}" exit 0 diff --git a/portage_with_autodep/bin/ebuild-helpers/prepstrip b/portage_with_autodep/bin/ebuild-helpers/prepstrip index 85d5d6a..2332388 100755 --- a/portage_with_autodep/bin/ebuild-helpers/prepstrip +++ b/portage_with_autodep/bin/ebuild-helpers/prepstrip @@ -1,7 +1,8 @@ #!/bin/bash -# Copyright 1999-2012 Gentoo Foundation +# Copyright 1999-2013 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 +PORTAGE_PYM_PATH=${PORTAGE_PYM_PATH:-/usr/lib/portage/pym} source "${PORTAGE_BIN_PATH:-/usr/lib/portage/bin}"/helper-functions.sh # avoid multiple calls to `has`. this creates things like: @@ -15,11 +16,12 @@ exp_tf() { eval ${var}_${flag}=$(tf has ${flag} ${!var}) done } -exp_tf FEATURES compressdebug installsources nostrip splitdebug -exp_tf RESTRICT binchecks installsources strip +exp_tf FEATURES compressdebug installsources nostrip splitdebug xattr +exp_tf RESTRICT binchecks installsources splitdebug strip -[[ " ${FEATURES} " == *" force-prefix "* ]] || \ - case "${EAPI}" in 0|1|2) EPREFIX= ED=${D} ;; esac +if ! ___eapi_has_prefix_variables; then + EPREFIX= ED=${D} +fi banner=false SKIP_STRIP=false @@ -29,6 +31,30 @@ if ${RESTRICT_strip} || ${FEATURES_nostrip} ; then ${FEATURES_installsources} || exit 0 fi +PRESERVE_XATTR=false +if [[ ${KERNEL} == linux ]] && ${FEATURES_xattr} ; then + PRESERVE_XATTR=true + if type -P getfattr >/dev/null && type -P setfattr >/dev/null ; then + dump_xattrs() { + getfattr -d --absolute-names "$1" + } + restore_xattrs() { + setfattr --restore=- + } + else + dump_xattrs() { + PYTHONPATH=${PORTAGE_PYTHONPATH:-${PORTAGE_PYM_PATH}} \ + "${PORTAGE_PYTHON:-/usr/bin/python}" \ + "${PORTAGE_BIN_PATH}/xattr-helper.py" --dump < <(echo -n "$1") + } + restore_xattrs() { + PYTHONPATH=${PORTAGE_PYTHONPATH:-${PORTAGE_PYM_PATH}} \ + "${PORTAGE_PYTHON:-/usr/bin/python}" \ + "${PORTAGE_BIN_PATH}/xattr-helper.py" --restore + } + fi +fi + # look up the tools we might be using for t in STRIP:strip OBJCOPY:objcopy READELF:readelf ; do v=${t%:*} # STRIP @@ -51,7 +77,7 @@ case $(${STRIP} --version 2>/dev/null) in # We'll leave out -R .note for now until we can check out the relevance # of the section when it has the ALLOC flag set on it ... SAFE_STRIP_FLAGS="--strip-unneeded" - DEF_STRIP_FLAGS="-R .comment -R .GCC.command.line" + DEF_STRIP_FLAGS="-R .comment -R .GCC.command.line -R .note.gnu.gold-version" SPLIT_STRIP_FLAGS= ;; esac @@ -62,23 +88,13 @@ prepstrip_sources_dir=${EPREFIX}/usr/src/debug/${CATEGORY}/${PF} type -P debugedit >/dev/null && debugedit_found=true || debugedit_found=false debugedit_warned=false -multijob_init +__multijob_init # Setup $T filesystem layout that we care about. tmpdir="${T}/prepstrip" rm -rf "${tmpdir}" mkdir -p "${tmpdir}"/{inodes,splitdebug,sources} -# Usage: inode_var_name: <file> -inode_file_link() { - echo -n "${tmpdir}/inodes/" - if [[ ${USERLAND} == "BSD" ]] ; then - stat -f '%i' "$1" - else - stat -c '%i' "$1" - fi -} - # Usage: save_elf_sources <elf> save_elf_sources() { ${FEATURES_installsources} || return 0 @@ -93,7 +109,6 @@ save_elf_sources() { fi local x=$1 - [[ -f $(inode_file_link "${x}") ]] && return 0 # since we're editing the ELF here, we should recompute the build-id # (the -i flag below). save that output so we don't need to recompute @@ -101,20 +116,22 @@ save_elf_sources() { buildid=$(debugedit -i \ -b "${WORKDIR}" \ -d "${prepstrip_sources_dir}" \ - -l "${tmpdir}/sources/${x##*/}.${BASHPID}" \ + -l "${tmpdir}/sources/${x##*/}.${BASHPID:-$(__bashpid)}" \ "${x}") } # Usage: save_elf_debug <elf> [splitdebug file] save_elf_debug() { ${FEATURES_splitdebug} || return 0 + ${RESTRICT_splitdebug} && return 0 # NOTE: Debug files must be installed in # ${EPREFIX}/usr/lib/debug/${EPREFIX} (note that ${EPREFIX} occurs # twice in this path) in order for gdb's debug-file-directory # lookup to work correctly. local x=$1 - local splitdebug=$2 + local inode_debug=$2 + local splitdebug=$3 local y=${ED}usr/lib/debug/${x:${#D}}.debug # dont save debug info twice @@ -122,9 +139,8 @@ save_elf_debug() { mkdir -p "${y%/*}" - local inode=$(inode_file_link "${x}") - if [[ -f ${inode} ]] ; then - ln "${inode}" "${y}" + if [ -f "${inode_debug}" ] ; then + ln "${inode_debug}" "${y}" || die "ln failed unexpectedly" else if [[ -n ${splitdebug} ]] ; then mv "${splitdebug}" "${y}" @@ -134,64 +150,89 @@ save_elf_debug() { ${OBJCOPY} ${objcopy_flags} "${x}" "${y}" ${OBJCOPY} --add-gnu-debuglink="${y}" "${x}" fi - local args="a-x,o-w" - [[ -g ${x} || -u ${x} ]] && args+=",go-r" - chmod ${args} "${y}" - ln "${y}" "${inode}" + # Only do the following if the debug file was + # successfully created (see bug #446774). + if [ $? -eq 0 ] ; then + local args="a-x,o-w" + [[ -g ${x} || -u ${x} ]] && args+=",go-r" + chmod ${args} "${y}" + ln "${y}" "${inode_debug}" || die "ln failed unexpectedly" + fi fi # if we don't already have build-id from debugedit, look it up if [[ -z ${buildid} ]] ; then # convert the readelf output to something useful - buildid=$(${READELF} -x .note.gnu.build-id "${x}" 2>/dev/null \ - | awk '$NF ~ /GNU/ { getline; printf $2$3$4$5; getline; print $2 }') + buildid=$(${READELF} -n "${x}" 2>/dev/null | awk '/Build ID:/{ print $NF; exit }') fi if [[ -n ${buildid} ]] ; then local buildid_dir="${ED}usr/lib/debug/.build-id/${buildid:0:2}" local buildid_file="${buildid_dir}/${buildid:2}" mkdir -p "${buildid_dir}" - ln -s "../../${x:${#D}}.debug" "${buildid_file}.debug" - ln -s "/${x:${#D}}" "${buildid_file}" + [ -L "${buildid_file}".debug ] || ln -s "../../${x:${#D}}.debug" "${buildid_file}.debug" + [ -L "${buildid_file}" ] || ln -s "/${x:${#D}}" "${buildid_file}" fi } # Usage: process_elf <elf> process_elf() { - local x=$1 strip_flags=${*:2} - - vecho " ${x:${#ED}}" - save_elf_sources "${x}" + local x=$1 inode_link=$2 strip_flags=${*:3} + local already_stripped lockfile xt_data + + __vecho " ${x:${#ED}}" + + # If two processes try to debugedit or strip the same hardlink at the + # same time, it may corrupt files or cause loss of splitdebug info. + # So, use a lockfile to prevent interference (easily observed with + # dev-vcs/git which creates ~111 hardlinks to one file in + # /usr/libexec/git-core). + lockfile=${inode_link}_lockfile + if ! ln "${inode_link}" "${lockfile}" 2>/dev/null ; then + while [[ -f ${lockfile} ]] ; do + sleep 1 + done + unset lockfile + fi - if ${strip_this} ; then + [ -f "${inode_link}_stripped" ] && already_stripped=true || already_stripped=false - # If two processes try to strip the same hardlink at the same - # time, it will cause one of them to lose the splitdebug info. - # So, use a lockfile to prevent interference (easily observed - # with dev-vcs/git which creates ~109 hardlinks to one file in - # /usr/libexec/git-core). - local lockfile=$(inode_file_link "${x}")_lockfile - if ! ln "${x}" "${lockfile}" ; then - while [[ -f ${lockfile} ]] ; do - sleep 1 - done - unset lockfile + if ! ${already_stripped} ; then + if ${PRESERVE_XATTR} ; then + xt_data=$(dump_xattrs "${x}") fi + save_elf_sources "${x}" + fi + + if ${strip_this} ; then # see if we can split & strip at the same time if [[ -n ${SPLIT_STRIP_FLAGS} ]] ; then local shortname="${x##*/}.debug" - local splitdebug="${tmpdir}/splitdebug/${shortname}.${BASHPID}" + local splitdebug="${tmpdir}/splitdebug/${shortname}.${BASHPID:-$(__bashpid)}" + ${already_stripped} || \ ${STRIP} ${strip_flags} \ -f "${splitdebug}" \ -F "${shortname}" \ "${x}" - save_elf_debug "${x}" "${splitdebug}" + save_elf_debug "${x}" "${inode_link}_debug" "${splitdebug}" else - save_elf_debug "${x}" + save_elf_debug "${x}" "${inode_link}_debug" + ${already_stripped} || \ ${STRIP} ${strip_flags} "${x}" fi - [[ -n ${lockfile} ]] && rm -f "${lockfile}" fi + + if ${already_stripped} ; then + rm -f "${x}" || die "rm failed unexpectedly" + ln "${inode_link}_stripped" "${x}" || die "ln failed unexpectedly" + else + ln "${x}" "${inode_link}_stripped" || die "ln failed unexpectedly" + if [[ ${xt_data} ]] ; then + restore_xattrs <<< "${xt_data}" + fi + fi + + [[ -n ${lockfile} ]] && rm -f "${lockfile}" } # The existance of the section .symtab tells us that a binary is stripped. @@ -204,7 +245,7 @@ if ! ${RESTRICT_binchecks} && ! ${RESTRICT_strip} ; then log=${tmpdir}/scanelf-already-stripped.log scanelf -yqRBF '#k%F' -k '!.symtab' "$@" | sed -e "s#^${ED}##" > "${log}" ( - multijob_child_init + __multijob_child_init qa_var="QA_PRESTRIPPED_${ARCH/-/_}" [[ -n ${!qa_var} ]] && QA_PRESTRIPPED="${!qa_var}" if [[ -n ${QA_PRESTRIPPED} && -s ${log} && \ @@ -219,28 +260,49 @@ if ! ${RESTRICT_binchecks} && ! ${RESTRICT_strip} ; then fi sed -e "/^\$/d" -e "s#^#/#" -i "${log}" if [[ -s ${log} ]] ; then - vecho -e "\n" + __vecho -e "\n" eqawarn "QA Notice: Pre-stripped files found:" eqawarn "$(<"${log}")" else rm -f "${log}" fi ) & - multijob_post_fork + __multijob_post_fork +fi + +# Since strip creates a new inode, we need to know the initial set of +# inodes in advance, so that we can avoid interference due to trying +# to strip the same (hardlinked) file multiple times in parallel. +# See bug #421099. +if [[ ${USERLAND} == BSD ]] ; then + get_inode_number() { stat -f '%i' "$1"; } +else + get_inode_number() { stat -c '%i' "$1"; } fi +cd "${tmpdir}/inodes" || die "cd failed unexpectedly" +while read -r x ; do + inode_link=$(get_inode_number "${x}") || die "stat failed unexpectedly" + echo "${x}" >> "${inode_link}" || die "echo failed unexpectedly" +done < <( + # Use sort -u to eliminate duplicates for bug #445336. + ( + scanelf -yqRBF '#k%F' -k '.symtab' "$@" + find "$@" -type f ! -type l -name '*.a' + ) | LC_ALL=C sort -u +) # Now we look for unstripped binaries. -for x in \ - $(scanelf -yqRBF '#k%F' -k '.symtab' "$@") \ - $(find "$@" -type f -name '*.a') +for inode_link in $(shopt -s nullglob; echo *) ; do +while read -r x do + if ! ${banner} ; then - vecho "strip: ${STRIP} ${PORTAGE_STRIP_FLAGS}" + __vecho "strip: ${STRIP} ${PORTAGE_STRIP_FLAGS}" banner=true fi ( - multijob_child_init + __multijob_child_init f=$(file "${x}") || exit 0 [[ -z ${f} ]] && exit 0 @@ -275,27 +337,34 @@ do buildid= if [[ ${f} == *"current ar archive"* ]] ; then - vecho " ${x:${#ED}}" + __vecho " ${x:${#ED}}" if ${strip_this} ; then - # hmm, can we split debug/sources for .a ? - ${STRIP} -g "${x}" + # If we have split debug enabled, then do not strip this. + # There is no concept of splitdebug for objects not yet + # linked in (only for finally linked ELFs), so we have to + # retain the debug info in the archive itself. + if ! ${FEATURES_splitdebug} || ${RESTRICT_splitdebug} ; then + ${STRIP} -g "${x}" + fi fi elif [[ ${f} == *"SB executable"* || ${f} == *"SB shared object"* ]] ; then - process_elf "${x}" ${PORTAGE_STRIP_FLAGS} + process_elf "${x}" "${inode_link}" ${PORTAGE_STRIP_FLAGS} elif [[ ${f} == *"SB relocatable"* ]] ; then - process_elf "${x}" ${SAFE_STRIP_FLAGS} + process_elf "${x}" "${inode_link}" ${SAFE_STRIP_FLAGS} fi if ${was_not_writable} ; then chmod u-w "${x}" fi ) & - multijob_post_fork + __multijob_post_fork + +done < "${inode_link}" done # With a bit more work, we could run the rsync processes below in # parallel, but not sure that'd be an overall improvement. -multijob_finish +__multijob_finish cd "${tmpdir}"/sources/ && cat * > "${tmpdir}/debug.sources" 2>/dev/null if [[ -s ${tmpdir}/debug.sources ]] && \ @@ -303,11 +372,11 @@ if [[ -s ${tmpdir}/debug.sources ]] && \ ! ${RESTRICT_installsources} && \ ${debugedit_found} then - vecho "installsources: rsyncing source files" + __vecho "installsources: rsyncing source files" [[ -d ${D}${prepstrip_sources_dir} ]] || mkdir -p "${D}${prepstrip_sources_dir}" grep -zv '/<[^/>]*>$' "${tmpdir}"/debug.sources | \ (cd "${WORKDIR}"; LANG=C sort -z -u | \ - rsync -tL0 --files-from=- "${WORKDIR}/" "${D}${prepstrip_sources_dir}/" ) + rsync -tL0 --chmod=ugo-st,a+r,go-w,Da+x,Fa-x --files-from=- "${WORKDIR}/" "${D}${prepstrip_sources_dir}/" ) # Preserve directory structure. # Needed after running save_elf_sources. @@ -318,4 +387,5 @@ then done < <(find "${D}${prepstrip_sources_dir}/" -type d -empty -print0) fi +cd "${T}" rm -rf "${tmpdir}" diff --git a/portage_with_autodep/bin/ebuild-ipc b/portage_with_autodep/bin/ebuild-ipc index 43e4a02..820005f 100755 --- a/portage_with_autodep/bin/ebuild-ipc +++ b/portage_with_autodep/bin/ebuild-ipc @@ -1,8 +1,10 @@ #!/bin/bash -# Copyright 2010 Gentoo Foundation +# Copyright 2010-2013 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 PORTAGE_BIN_PATH=${PORTAGE_BIN_PATH:-/usr/lib/portage/bin} PORTAGE_PYM_PATH=${PORTAGE_PYM_PATH:-/usr/lib/portage/pym} -PYTHONPATH=$PORTAGE_PYM_PATH${PYTHONPATH:+:}$PYTHONPATH \ +# Use safe cwd, avoiding unsafe import for bug #469338. +cd "${PORTAGE_PYM_PATH}" +PYTHONPATH=${PORTAGE_PYTHONPATH:-${PORTAGE_PYM_PATH}} \ exec "${PORTAGE_PYTHON:-/usr/bin/python}" "$PORTAGE_BIN_PATH/ebuild-ipc.py" "$@" diff --git a/portage_with_autodep/bin/ebuild-ipc.py b/portage_with_autodep/bin/ebuild-ipc.py index 29d4c23..d351e94 100755 --- a/portage_with_autodep/bin/ebuild-ipc.py +++ b/portage_with_autodep/bin/ebuild-ipc.py @@ -1,24 +1,28 @@ #!/usr/bin/python -# Copyright 2010-2011 Gentoo Foundation +# Copyright 2010-2013 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 # # This is a helper which ebuild processes can use # to communicate with portage's main python process. -import errno import logging import os import pickle -import select +import platform import signal import sys import time -import traceback def debug_signal(signum, frame): import pdb pdb.set_trace() -signal.signal(signal.SIGUSR1, debug_signal) + +if platform.python_implementation() == 'Jython': + debug_signum = signal.SIGUSR2 # bug #424259 +else: + debug_signum = signal.SIGUSR1 + +signal.signal(debug_signum, debug_signal) # Avoid sandbox violations after python upgrade. pym_path = os.path.join(os.path.dirname( @@ -31,14 +35,28 @@ if os.environ.get("SANDBOX_ON") == "1": ":".join(filter(None, sandbox_write)) import portage +portage._internal_caller = True portage._disable_legacy_globals() +from portage.util._async.ForkProcess import ForkProcess +from portage.util._eventloop.global_event_loop import global_event_loop +from _emerge.PipeReader import PipeReader + +class FifoWriter(ForkProcess): + + __slots__ = ('buf', 'fifo',) + + def _run(self): + # Atomically write the whole buffer into the fifo. + with open(self.fifo, 'wb', 0) as f: + f.write(self.buf) + return os.EX_OK + class EbuildIpc(object): # Timeout for each individual communication attempt (we retry # as long as the daemon process appears to be alive). - _COMMUNICATE_RETRY_TIMEOUT_SECONDS = 15 - _BUFSIZE = 4096 + _COMMUNICATE_RETRY_TIMEOUT_MS = 15000 def __init__(self): self.fifo_dir = os.environ['PORTAGE_BUILDDIR'] @@ -82,7 +100,7 @@ class EbuildIpc(object): 'ebuild-ipc: daemon process not detected\n'), level=logging.ERROR, noiselevel=-1) - def _wait(self, pid, pr, msg): + def _run_writer(self, fifo_writer, msg): """ Wait on pid and return an appropriate exit code. This may return unsuccessfully due to timeout if the daemon @@ -91,88 +109,48 @@ class EbuildIpc(object): start_time = time.time() - while True: - try: - events = select.select([pr], [], [], - self._COMMUNICATE_RETRY_TIMEOUT_SECONDS) - except select.error as e: - portage.util.writemsg_level( - "ebuild-ipc: %s: %s\n" % \ - (portage.localization._('during select'), e), - level=logging.ERROR, noiselevel=-1) - continue + fifo_writer.start() + eof = fifo_writer.poll() is not None - if events[0]: - break + while not eof: + fifo_writer._wait_loop(timeout=self._COMMUNICATE_RETRY_TIMEOUT_MS) - if self._daemon_is_alive(): + eof = fifo_writer.poll() is not None + if eof: + break + elif self._daemon_is_alive(): self._timeout_retry_msg(start_time, msg) else: + fifo_writer.cancel() self._no_daemon_msg() - try: - os.kill(pid, signal.SIGKILL) - os.waitpid(pid, 0) - except OSError as e: - portage.util.writemsg_level( - "ebuild-ipc: %s\n" % (e,), - level=logging.ERROR, noiselevel=-1) + fifo_writer.wait() return 2 - try: - wait_retval = os.waitpid(pid, 0) - except OSError as e: - portage.util.writemsg_level( - "ebuild-ipc: %s: %s\n" % (msg, e), - level=logging.ERROR, noiselevel=-1) - return 2 + return fifo_writer.wait() - if not os.WIFEXITED(wait_retval[1]): - portage.util.writemsg_level( - "ebuild-ipc: %s: %s\n" % (msg, - portage.localization._('subprocess failure: %s') % \ - wait_retval[1]), - level=logging.ERROR, noiselevel=-1) - return 2 + def _receive_reply(self, input_fd): - return os.WEXITSTATUS(wait_retval[1]) + start_time = time.time() - def _receive_reply(self, input_fd): + pipe_reader = PipeReader(input_files={"input_fd":input_fd}, + scheduler=global_event_loop()) + pipe_reader.start() - # Timeouts are handled by the parent process, so just - # block until input is available. For maximum portability, - # use a single atomic read. - buf = None - while True: - try: - events = select.select([input_fd], [], []) - except select.error as e: - portage.util.writemsg_level( - "ebuild-ipc: %s: %s\n" % \ - (portage.localization._('during select for read'), e), - level=logging.ERROR, noiselevel=-1) - continue - - if events[0]: - # For maximum portability, use os.read() here since - # array.fromfile() and file.read() are both known to - # erroneously return an empty string from this - # non-blocking fifo stream on FreeBSD (bug #337465). - try: - buf = os.read(input_fd, self._BUFSIZE) - except OSError as e: - if e.errno != errno.EAGAIN: - portage.util.writemsg_level( - "ebuild-ipc: %s: %s\n" % \ - (portage.localization._('read error'), e), - level=logging.ERROR, noiselevel=-1) - break - # Assume that another event will be generated - # if there's any relevant data. - continue - - # Only one (atomic) read should be necessary. - if buf: - break + eof = pipe_reader.poll() is not None + + while not eof: + pipe_reader._wait_loop(timeout=self._COMMUNICATE_RETRY_TIMEOUT_MS) + eof = pipe_reader.poll() is not None + if not eof: + if self._daemon_is_alive(): + self._timeout_retry_msg(start_time, + portage.localization._('during read')) + else: + pipe_reader.cancel() + self._no_daemon_msg() + return 2 + + buf = pipe_reader.getvalue() retval = 2 @@ -225,32 +203,9 @@ class EbuildIpc(object): # un-interrupted, while the parent handles all timeout # considerations. This helps to avoid possible race conditions # from interference between timeouts and blocking IO operations. - pr, pw = os.pipe() - pid = os.fork() - - if pid == 0: - retval = 2 - try: - os.close(pr) - - # File streams are in unbuffered mode since we do atomic - # read and write of whole pickles. - output_file = open(self.ipc_in_fifo, 'wb', 0) - output_file.write(pickle.dumps(args)) - output_file.close() - retval = os.EX_OK - except SystemExit: - raise - except: - traceback.print_exc() - finally: - os._exit(retval) - - os.close(pw) - msg = portage.localization._('during write') - retval = self._wait(pid, pr, msg) - os.close(pr) + retval = self._run_writer(FifoWriter(buf=pickle.dumps(args), + fifo=self.ipc_in_fifo, scheduler=global_event_loop()), msg) if retval != os.EX_OK: portage.util.writemsg_level( @@ -263,26 +218,7 @@ class EbuildIpc(object): self._no_daemon_msg() return 2 - pr, pw = os.pipe() - pid = os.fork() - - if pid == 0: - retval = 2 - try: - os.close(pr) - retval = self._receive_reply(input_fd) - except SystemExit: - raise - except: - traceback.print_exc() - finally: - os._exit(retval) - - os.close(pw) - retval = self._wait(pid, pr, portage.localization._('during read')) - os.close(pr) - os.close(input_fd) - return retval + return self._receive_reply(input_fd) def ebuild_ipc_main(args): ebuild_ipc = EbuildIpc() diff --git a/portage_with_autodep/bin/ebuild.sh b/portage_with_autodep/bin/ebuild.sh index 2589113..be044e0 100755 --- a/portage_with_autodep/bin/ebuild.sh +++ b/portage_with_autodep/bin/ebuild.sh @@ -1,5 +1,5 @@ #!/bin/bash -# Copyright 1999-2012 Gentoo Foundation +# Copyright 1999-2013 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 PORTAGE_BIN_PATH="${PORTAGE_BIN_PATH:-/usr/lib/portage/bin}" @@ -21,21 +21,23 @@ else # in global scope, even though they are completely useless during # the "depend" phase. for x in diropts docompress exeopts get_KV insopts \ - keepdir KV_major KV_micro KV_minor KV_to_int \ + KV_major KV_micro KV_minor KV_to_int \ libopts register_die_hook register_success_hook \ - remove_path_entry set_unless_changed strip_duplicate_slashes \ - unset_unless_changed use_with use_enable ; do + __strip_duplicate_slashes \ + use_with use_enable ; do eval "${x}() { - if has \"\${EAPI:-0}\" 4-python; then + if ___eapi_disallows_helpers_in_global_scope; then die \"\${FUNCNAME}() calls are not allowed in global scope\" fi }" done - # These dummy functions return false in older EAPIs, in order to ensure that + # These dummy functions return false in non-strict EAPIs, in order to ensure that # `use multislot` is false for the "depend" phase. - for x in use useq usev ; do + funcs="use useq usev" + ___eapi_has_usex && funcs+=" usex" + for x in ${funcs} ; do eval "${x}() { - if has \"\${EAPI:-0}\" 4-python; then + if ___eapi_disallows_helpers_in_global_scope; then die \"\${FUNCNAME}() calls are not allowed in global scope\" else return 1 @@ -44,10 +46,16 @@ else done # These functions die because calls to them during the "depend" phase # are considered to be severe QA violations. - for x in best_version has_version portageq ; do + funcs="best_version has_version portageq" + ___eapi_has_master_repositories && funcs+=" master_repositories" + ___eapi_has_repository_path && funcs+=" repository_path" + ___eapi_has_available_eclasses && funcs+=" available_eclasses" + ___eapi_has_eclass_path && funcs+=" eclass_path" + ___eapi_has_license_path && funcs+=" license_path" + for x in ${funcs} ; do eval "${x}() { die \"\${FUNCNAME}() calls are not allowed in global scope\"; }" done - unset x + unset funcs x fi # Don't use sandbox's BASH_ENV for new shells because it does @@ -66,7 +74,7 @@ export PORTAGE_BZIP2_COMMAND=${PORTAGE_BZIP2_COMMAND:-bzip2} # with shell opts (shopts). Ebuilds/eclasses changing shopts should reset them # when they are done. -qa_source() { +__qa_source() { local shopts=$(shopt) OLDIFS="$IFS" local retval source "$@" @@ -79,7 +87,7 @@ qa_source() { return $retval } -qa_call() { +__qa_call() { local shopts=$(shopt) OLDIFS="$IFS" local retval "$@" @@ -102,20 +110,19 @@ unset GZIP BZIP BZIP2 CDPATH GREP_OPTIONS GREP_COLOR GLOBIGNORE [[ $PORTAGE_QUIET != "" ]] && export PORTAGE_QUIET # sandbox support functions; defined prior to profile.bashrc srcing, since the profile might need to add a default exception (/usr/lib64/conftest fex) -_sb_append_var() { +__sb_append_var() { local _v=$1 ; shift local var="SANDBOX_${_v}" - [[ -z $1 || -n $2 ]] && die "Usage: add$(echo ${_v} | \ - LC_ALL=C tr [:upper:] [:lower:]) <colon-delimited list of paths>" + [[ -z $1 || -n $2 ]] && die "Usage: add$(LC_ALL=C tr "[:upper:]" "[:lower:]" <<< "${_v}") <colon-delimited list of paths>" export ${var}="${!var:+${!var}:}$1" } # bash-4 version: # local var="SANDBOX_${1^^}" -# addread() { _sb_append_var ${0#add} "$@" ; } -addread() { _sb_append_var READ "$@" ; } -addwrite() { _sb_append_var WRITE "$@" ; } -adddeny() { _sb_append_var DENY "$@" ; } -addpredict() { _sb_append_var PREDICT "$@" ; } +# addread() { __sb_append_var ${0#add} "$@" ; } +addread() { __sb_append_var READ "$@" ; } +addwrite() { __sb_append_var WRITE "$@" ; } +adddeny() { __sb_append_var DENY "$@" ; } +addpredict() { __sb_append_var PREDICT "$@" ; } addwrite "${PORTAGE_TMPDIR}" addread "/:${PORTAGE_TMPDIR}" @@ -136,19 +143,11 @@ fi # the sandbox is disabled by default except when overridden in the relevant stages export SANDBOX_ON=0 -esyslog() { - # Custom version of esyslog() to take care of the "Red Star" bug. - # MUST follow functions.sh to override the "" parameter problem. - return 0 -} - # Ensure that $PWD is sane whenever possible, to protect against # exploitation of insecure search path for python -c in ebuilds. -# See bug #239560. -if ! has "$EBUILD_PHASE" clean cleanrm depend help ; then - cd "$PORTAGE_BUILDDIR" || \ - die "PORTAGE_BUILDDIR does not exist: '$PORTAGE_BUILDDIR'" -fi +# See bug #239560 and bug #469338. +cd "${PORTAGE_PYM_PATH}" || \ + die "PORTAGE_PYM_PATH does not exist: '${PORTAGE_PYM_PATH}'" #if no perms are specified, dirs/files will have decent defaults #(not secretive, but not stupid) @@ -178,8 +177,8 @@ debug-print() { # default target printf '%s\n' "${@}" >> "${T}/eclass-debug.log" # let the portage user own/write to this file - chgrp portage "${T}/eclass-debug.log" &>/dev/null - chmod g+w "${T}/eclass-debug.log" &>/dev/null + chgrp "${PORTAGE_GRPNAME:-portage}" "${T}/eclass-debug.log" + chmod g+w "${T}/eclass-debug.log" fi } @@ -208,8 +207,9 @@ inherit() { | fmt -w 75 | while read -r ; do eqawarn "$REPLY" ; done fi + local repo_location local location - local olocation + local potential_location local x # These variables must be restored before returning. @@ -221,9 +221,10 @@ inherit() { local B_DEPEND local B_RDEPEND local B_PDEPEND + local B_HDEPEND while [ "$1" ]; do - location="${ECLASSDIR}/${1}.eclass" - olocation="" + location="" + potential_location="" export ECLASS="$1" __export_funcs_var=__export_functions_$ECLASS_DEPTH @@ -244,43 +245,36 @@ inherit() { fi fi - # any future resolution code goes here - if [ -n "$PORTDIR_OVERLAY" ]; then - local overlay - for overlay in ${PORTDIR_OVERLAY}; do - olocation="${overlay}/eclass/${1}.eclass" - if [ -e "$olocation" ]; then - location="${olocation}" - debug-print " eclass exists: ${location}" - fi - done - fi + for repo_location in "${PORTAGE_ECLASS_LOCATIONS[@]}"; do + potential_location="${repo_location}/eclass/${1}.eclass" + if [[ -f ${potential_location} ]]; then + location="${potential_location}" + debug-print " eclass exists: ${location}" + break + fi + done debug-print "inherit: $1 -> $location" - [ ! -e "$location" ] && die "${1}.eclass could not be found by inherit()" + [[ -z ${location} ]] && die "${1}.eclass could not be found by inherit()" - if [ "${location}" == "${olocation}" ] && \ - ! has "${location}" ${EBUILD_OVERLAY_ECLASSES} ; then - EBUILD_OVERLAY_ECLASSES="${EBUILD_OVERLAY_ECLASSES} ${location}" - fi - - #We need to back up the value of DEPEND and RDEPEND to B_DEPEND and B_RDEPEND + #We need to back up the values of *DEPEND to B_*DEPEND #(if set).. and then restore them after the inherit call. #turn off glob expansion set -f # Retain the old data and restore it later. - unset B_IUSE B_REQUIRED_USE B_DEPEND B_RDEPEND B_PDEPEND + unset B_IUSE B_REQUIRED_USE B_DEPEND B_RDEPEND B_PDEPEND B_HDEPEND [ "${IUSE+set}" = set ] && B_IUSE="${IUSE}" [ "${REQUIRED_USE+set}" = set ] && B_REQUIRED_USE="${REQUIRED_USE}" [ "${DEPEND+set}" = set ] && B_DEPEND="${DEPEND}" [ "${RDEPEND+set}" = set ] && B_RDEPEND="${RDEPEND}" [ "${PDEPEND+set}" = set ] && B_PDEPEND="${PDEPEND}" - unset IUSE REQUIRED_USE DEPEND RDEPEND PDEPEND + [ "${HDEPEND+set}" = set ] && B_HDEPEND="${HDEPEND}" + unset IUSE REQUIRED_USE DEPEND RDEPEND PDEPEND HDEPEND #turn on glob expansion set +f - qa_source "$location" || die "died sourcing $location in inherit()" + __qa_source "$location" || die "died sourcing $location in inherit()" #turn off glob expansion set -f @@ -292,6 +286,7 @@ inherit() { [ "${DEPEND+set}" = set ] && E_DEPEND+="${E_DEPEND:+ }${DEPEND}" [ "${RDEPEND+set}" = set ] && E_RDEPEND+="${E_RDEPEND:+ }${RDEPEND}" [ "${PDEPEND+set}" = set ] && E_PDEPEND+="${E_PDEPEND:+ }${PDEPEND}" + [ "${HDEPEND+set}" = set ] && E_HDEPEND+="${E_HDEPEND:+ }${HDEPEND}" [ "${B_IUSE+set}" = set ] && IUSE="${B_IUSE}" [ "${B_IUSE+set}" = set ] || unset IUSE @@ -308,6 +303,9 @@ inherit() { [ "${B_PDEPEND+set}" = set ] && PDEPEND="${B_PDEPEND}" [ "${B_PDEPEND+set}" = set ] || unset PDEPEND + [ "${B_HDEPEND+set}" = set ] && HDEPEND="${B_HDEPEND}" + [ "${B_HDEPEND+set}" = set ] || unset HDEPEND + #turn on glob expansion set +f @@ -348,7 +346,7 @@ EXPORT_FUNCTIONS() { PORTAGE_BASHRCS_SOURCED=0 -# @FUNCTION: source_all_bashrcs +# @FUNCTION: __source_all_bashrcs # @DESCRIPTION: # Source a relevant bashrc files and perform other miscellaneous # environment initialization when appropriate. @@ -359,7 +357,7 @@ PORTAGE_BASHRCS_SOURCED=0 # * A "default" function which is an alias for the default phase # function for the current phase. # -source_all_bashrcs() { +__source_all_bashrcs() { [[ $PORTAGE_BASHRCS_SOURCED = 1 ]] && return 0 PORTAGE_BASHRCS_SOURCED=1 local x @@ -373,7 +371,7 @@ source_all_bashrcs() { local path_array=($PROFILE_PATHS) restore_IFS for x in "${path_array[@]}" ; do - [ -f "$x/profile.bashrc" ] && qa_source "$x/profile.bashrc" + [ -f "$x/profile.bashrc" ] && __qa_source "$x/profile.bashrc" done fi @@ -390,7 +388,7 @@ source_all_bashrcs() { if [[ $EBUILD_PHASE != depend ]] ; then # The user's bashrc is the ONLY non-portage bit of code that can # change shopts without a QA violation. - for x in "${PM_EBUILD_HOOK_DIR}"/${CATEGORY}/{${PN},${PN}:${SLOT},${P},${PF}}; do + for x in "${PM_EBUILD_HOOK_DIR}"/${CATEGORY}/{${PN},${PN}:${SLOT%/*},${P},${PF}}; do if [ -r "${x}" ]; then # If $- contains x, then tracing has already been enabled # elsewhere for some reason. We preserve it's state so as @@ -470,7 +468,7 @@ if [[ -n ${QA_INTERCEPTORS} ]] ; then fi # Subshell/helper die support (must export for the die helper). -export EBUILD_MASTER_PID=$BASHPID +export EBUILD_MASTER_PID=${BASHPID:-$(__bashpid)} trap 'exit 1' SIGTERM if ! has "$EBUILD_PHASE" clean cleanrm depend && \ @@ -479,7 +477,7 @@ if ! has "$EBUILD_PHASE" clean cleanrm depend && \ # may have come from another version of ebuild.sh or something. # In any case, preprocess it to prevent any potential interference. # NOTE: export ${FOO}=... requires quoting, unlike normal exports - preprocess_ebuild_env || \ + __preprocess_ebuild_env || \ die "error processing environment" # Colon separated SANDBOX_* variables need to be cumulative. for x in SANDBOX_DENY SANDBOX_READ SANDBOX_PREDICT SANDBOX_WRITE ; do @@ -512,17 +510,22 @@ if ! has "$EBUILD_PHASE" clean cleanrm depend && \ [[ -n $EAPI ]] || EAPI=0 fi -if has "${EAPI:-0}" 4-python; then +if ___eapi_enables_globstar; then shopt -s globstar fi +# Convert quoted paths to array. +eval "PORTAGE_ECLASS_LOCATIONS=(${PORTAGE_ECLASS_LOCATIONS})" + +# Source the ebuild every time for FEATURES=noauto, so that ebuild +# modifications take effect immediately. if ! has "$EBUILD_PHASE" clean cleanrm ; then if [[ $EBUILD_PHASE = depend || ! -f $T/environment || \ - -f $PORTAGE_BUILDDIR/.ebuild_changed ]] || \ - has noauto $FEATURES ; then + -f $PORTAGE_BUILDDIR/.ebuild_changed || \ + " ${FEATURES} " == *" noauto "* ]] ; then # The bashrcs get an opportunity here to set aliases that will be expanded # during sourcing of ebuilds and eclasses. - source_all_bashrcs + __source_all_bashrcs # When EBUILD_PHASE != depend, INHERITED comes pre-initialized # from cache. In order to make INHERITED content independent of @@ -534,8 +537,9 @@ if ! has "$EBUILD_PHASE" clean cleanrm ; then # In order to ensure correct interaction between ebuilds and # eclasses, they need to be unset before this process of # interaction begins. - unset EAPI DEPEND RDEPEND PDEPEND INHERITED IUSE REQUIRED_USE \ - ECLASS E_IUSE E_REQUIRED_USE E_DEPEND E_RDEPEND E_PDEPEND + unset EAPI DEPEND RDEPEND PDEPEND HDEPEND INHERITED IUSE REQUIRED_USE \ + ECLASS E_IUSE E_REQUIRED_USE E_DEPEND E_RDEPEND E_PDEPEND \ + E_HDEPEND if [[ $PORTAGE_DEBUG != 1 || ${-/x/} != $- ]] ; then source "$EBUILD" || die "error sourcing ebuild" @@ -553,7 +557,10 @@ if ! has "$EBUILD_PHASE" clean cleanrm ; then [ "${EAPI+set}" = set ] || EAPI=0 - if has "$EAPI" 0 1 2 3 3_pre2 ; then + # export EAPI for helpers (especially since we unset it above) + export EAPI + + if ___eapi_has_RDEPEND_DEPEND_fallback; then export RDEPEND=${RDEPEND-${DEPEND}} debug-print "RDEPEND: not set... Setting to: ${DEPEND}" fi @@ -563,19 +570,20 @@ if ! has "$EBUILD_PHASE" clean cleanrm ; then DEPEND+="${DEPEND:+ }${E_DEPEND}" RDEPEND+="${RDEPEND:+ }${E_RDEPEND}" PDEPEND+="${PDEPEND:+ }${E_PDEPEND}" + HDEPEND+="${HDEPEND:+ }${E_HDEPEND}" REQUIRED_USE+="${REQUIRED_USE:+ }${E_REQUIRED_USE}" - unset ECLASS E_IUSE E_REQUIRED_USE E_DEPEND E_RDEPEND E_PDEPEND \ + unset ECLASS E_IUSE E_REQUIRED_USE E_DEPEND E_RDEPEND E_PDEPEND E_HDEPEND \ __INHERITED_QA_CACHE # alphabetically ordered by $EBUILD_PHASE value - case "$EAPI" in + case ${EAPI} in 0|1) _valid_phases="src_compile pkg_config pkg_info src_install pkg_nofetch pkg_postinst pkg_postrm pkg_preinst pkg_prerm pkg_setup src_test src_unpack" ;; - 2|3|3_pre2) + 2|3) _valid_phases="src_compile pkg_config src_configure pkg_info src_install pkg_nofetch pkg_postinst pkg_postrm pkg_preinst src_prepare pkg_prerm pkg_setup src_test src_unpack" @@ -667,9 +675,13 @@ if [[ $EBUILD_PHASE = depend ]] ; then auxdbkeys="DEPEND RDEPEND SLOT SRC_URI RESTRICT HOMEPAGE LICENSE DESCRIPTION KEYWORDS INHERITED IUSE REQUIRED_USE PDEPEND PROVIDE EAPI - PROPERTIES DEFINED_PHASES UNUSED_05 UNUSED_04 + PROPERTIES DEFINED_PHASES HDEPEND UNUSED_04 UNUSED_03 UNUSED_02 UNUSED_01" + if ! ___eapi_has_HDEPEND; then + unset HDEPEND + fi + # The extra $(echo) commands remove newlines. if [ -n "${dbkey}" ] ; then > "${dbkey}" @@ -678,31 +690,28 @@ if [[ $EBUILD_PHASE = depend ]] ; then done else for f in ${auxdbkeys} ; do - echo $(echo ${!f}) 1>&9 || exit $? + eval "echo \$(echo \${!f}) 1>&${PORTAGE_PIPE_FD}" || exit $? done - exec 9>&- + eval "exec ${PORTAGE_PIPE_FD}>&-" fi set +f else - # Note: readonly variables interfere with preprocess_ebuild_env(), so + # Note: readonly variables interfere with __preprocess_ebuild_env(), so # declare them only after it has already run. declare -r $PORTAGE_READONLY_METADATA $PORTAGE_READONLY_VARS - case "$EAPI" in - 0|1|2) - [[ " ${FEATURES} " == *" force-prefix "* ]] && \ - declare -r ED EPREFIX EROOT - ;; - *) - declare -r ED EPREFIX EROOT - ;; - esac + if ___eapi_has_prefix_variables; then + declare -r ED EPREFIX EROOT + fi if [[ -n $EBUILD_SH_ARGS ]] ; then ( # Don't allow subprocesses to inherit the pipe which # emerge uses to monitor ebuild.sh. - exec 9>&- - ebuild_main ${EBUILD_SH_ARGS} + if [[ -n ${PORTAGE_PIPE_FD} ]] ; then + eval "exec ${PORTAGE_PIPE_FD}>&-" + unset PORTAGE_PIPE_FD + fi + __ebuild_main ${EBUILD_SH_ARGS} exit 0 ) exit $? diff --git a/portage_with_autodep/bin/egencache b/portage_with_autodep/bin/egencache index 2f53b40..9b22363 100755 --- a/portage_with_autodep/bin/egencache +++ b/portage_with_autodep/bin/egencache @@ -1,15 +1,17 @@ #!/usr/bin/python -# Copyright 2009-2012 Gentoo Foundation +# Copyright 2009-2013 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 -from __future__ import print_function +# unicode_literals for compat with TextIOWrapper in Python 2 +from __future__ import print_function, unicode_literals +import platform import signal import sys # This block ensures that ^C interrupts are handled quietly. try: - def exithandler(signum,frame): + def exithandler(signum, _frame): signal.signal(signal.SIGINT, signal.SIG_IGN) signal.signal(signal.SIGTERM, signal.SIG_IGN) sys.exit(128 + signum) @@ -20,26 +22,39 @@ try: 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 logging -import optparse import subprocess import time import textwrap import re -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 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, _encodings, _unicode_encode, _unicode_decode from _emerge.MetadataRegen import MetadataRegen from portage.cache.cache_errors import CacheError, StatCollision +from portage.const import TIMESTAMP_FORMAT from portage.manifest import guessManifestFileType +from portage.package.ebuild._parallel_manifest.ManifestScheduler import ManifestScheduler from portage.util import cmp_sort_key, writemsg_level +from portage.util._argparse import ArgumentParser +from portage.util._async.run_main_scheduler import run_main_scheduler +from portage.util._eventloop.global_event_loop import global_event_loop from portage import cpv_getkey from portage.dep import Atom, isjustname from portage.versions import pkgsplit, vercmp @@ -59,72 +74,98 @@ else: from repoman.utilities import FindVCS if sys.hexversion >= 0x3000000: + # pylint: disable=W0622 long = int def parse_args(args): usage = "egencache [options] <action> ... [atom] ..." - parser = optparse.OptionParser(usage=usage) + parser = ArgumentParser(usage=usage) - actions = optparse.OptionGroup(parser, 'Actions') - actions.add_option("--update", + actions = parser.add_argument_group('Actions') + actions.add_argument("--update", action="store_true", - help="update metadata/cache/ (generate as necessary)") - actions.add_option("--update-use-local-desc", + help="update metadata/md5-cache/ (generate as necessary)") + actions.add_argument("--update-use-local-desc", action="store_true", help="update the use.local.desc file from metadata.xml") - actions.add_option("--update-changelogs", + actions.add_argument("--update-changelogs", action="store_true", help="update the ChangeLog files from SCM logs") - parser.add_option_group(actions) + actions.add_argument("--update-manifests", + action="store_true", + help="update manifests") - common = optparse.OptionGroup(parser, 'Common options') - common.add_option("--repo", + common = parser.add_argument_group('Common options') + common.add_argument("--repo", action="store", - help="name of repo to operate on (default repo is located at $PORTDIR)") - common.add_option("--config-root", + help="name of repo to operate on") + common.add_argument("--config-root", help="location of portage config files", dest="portage_configroot") - common.add_option("--portdir", - help="override the portage tree location", + common.add_argument("--gpg-dir", + help="override the PORTAGE_GPG_DIR variable", + dest="gpg_dir") + common.add_argument("--gpg-key", + help="override the PORTAGE_GPG_KEY variable", + dest="gpg_key") + common.add_argument("--portdir", + help="override the PORTDIR variable (deprecated in favor of --repositories-configuration)", dest="portdir") - common.add_option("--portdir-overlay", - help="override the PORTDIR_OVERLAY variable (requires that --repo is also specified)", + common.add_argument("--portdir-overlay", + help="override the PORTDIR_OVERLAY variable (deprecated in favor of --repositories-configuration)", dest="portdir_overlay") - common.add_option("--tolerant", + common.add_argument("--repositories-configuration", + help="override configuration of repositories (in format of repos.conf)", + dest="repositories_configuration") + common.add_argument("--sign-manifests", + choices=('y', 'n'), + metavar="<y|n>", + help="manually override layout.conf sign-manifests setting") + common.add_argument("--strict-manifests", + choices=('y', 'n'), + metavar="<y|n>", + help="manually override \"strict\" FEATURES setting") + common.add_argument("--thin-manifests", + choices=('y', 'n'), + metavar="<y|n>", + help="manually override layout.conf thin-manifests setting") + common.add_argument("--tolerant", action="store_true", help="exit successfully if only minor errors occurred") - common.add_option("--ignore-default-opts", + common.add_argument("--ignore-default-opts", action="store_true", help="do not use the EGENCACHE_DEFAULT_OPTS environment variable") - parser.add_option_group(common) + common.add_argument("--write-timestamp", + action="store_true", + help="write metadata/timestamp.chk as required for rsync repositories") - update = optparse.OptionGroup(parser, '--update options') - update.add_option("--cache-dir", + update = parser.add_argument_group('--update options') + update.add_argument("--cache-dir", help="location of the metadata cache", dest="cache_dir") - update.add_option("--jobs", + update.add_argument("-j", "--jobs", + type=int, action="store", help="max ebuild processes to spawn") - update.add_option("--load-average", + update.add_argument("--load-average", + type=float, action="store", help="max load allowed when spawning multiple jobs", dest="load_average") - update.add_option("--rsync", + update.add_argument("--rsync", action="store_true", help="enable rsync stat collision workaround " + \ "for bug 139134 (use with --update)") - parser.add_option_group(update) - uld = optparse.OptionGroup(parser, '--update-use-local-desc options') - uld.add_option("--preserve-comments", + uld = parser.add_argument_group('--update-use-local-desc options') + uld.add_argument("--preserve-comments", action="store_true", help="preserve the comments from the existing use.local.desc file") - uld.add_option("--use-local-desc-output", + uld.add_argument("--use-local-desc-output", help="output file for use.local.desc data (or '-' for stdout)", dest="uld_output") - parser.add_option_group(uld) - options, args = parser.parse_args(args) + options, args = parser.parse_known_args(args) if options.jobs: jobs = None @@ -171,9 +212,12 @@ def parse_args(args): parser.error("Write access denied: --cache-dir='%s'" % \ (options.cache_dir,)) - if options.portdir_overlay is not None and \ - options.repo is None: - parser.error("--portdir-overlay option requires --repo option") + if options.portdir is not None: + writemsg_level("egencache: warning: --portdir option is deprecated in favor of --repositories-configuration option\n", + level=logging.WARNING, noiselevel=-1) + if options.portdir_overlay is not None: + writemsg_level("egencache: warning: --portdir-overlay option is deprecated in favor of --repositories-configuration option\n", + level=logging.WARNING, noiselevel=-1) for atom in args: try: @@ -215,9 +259,11 @@ class GenCache(object): else: self._cp_set = None self._cp_missing = set() + write_auxdb = "metadata-transfer" in portdb.settings.features self._regen = MetadataRegen(portdb, cp_iter=cp_iter, consumer=self._metadata_callback, - max_jobs=max_jobs, max_load=max_load) + max_jobs=max_jobs, max_load=max_load, + write_auxdb=write_auxdb, main=True) self.returncode = os.EX_OK conf = portdb.repositories.get_repo_for_location(tree) self._trg_caches = tuple(conf.iter_pregenerated_caches( @@ -255,98 +301,74 @@ class GenCache(object): def _write_cache(self, trg_cache, cpv, repo_path, metadata, ebuild_hash): - if not hasattr(trg_cache, 'raise_stat_collision'): - # This cache does not avoid redundant writes automatically, - # so check for an identical existing entry before writing. - # This prevents unnecessary disk writes and can also prevent - # unnecessary rsync transfers. - try: - dest = trg_cache[cpv] - except (KeyError, CacheError): - pass - else: - if trg_cache.validate_entry(dest, - ebuild_hash, self._eclass_db): - identical = True - for k in self._auxdbkeys: - if dest.get(k, '') != metadata.get(k, ''): - identical = False - break - if identical: - return + if not hasattr(trg_cache, 'raise_stat_collision'): + # This cache does not avoid redundant writes automatically, + # so check for an identical existing entry before writing. + # This prevents unnecessary disk writes and can also prevent + # unnecessary rsync transfers. + try: + dest = trg_cache[cpv] + except (KeyError, CacheError): + pass + else: + if trg_cache.validate_entry(dest, + ebuild_hash, self._eclass_db): + identical = True + for k in self._auxdbkeys: + if dest.get(k, '') != metadata.get(k, ''): + identical = False + break + if identical: + return + try: + chf = trg_cache.validation_chf + metadata['_%s_' % chf] = getattr(ebuild_hash, chf) try: - chf = trg_cache.validation_chf - metadata['_%s_' % chf] = getattr(ebuild_hash, chf) + trg_cache[cpv] = metadata + except StatCollision as sc: + # If the content of a cache entry changes and neither the + # file mtime nor size changes, it will prevent rsync from + # detecting changes. Cache backends may raise this + # exception from _setitem() if they detect this type of stat + # collision. These exceptions are handled by bumping the + # mtime on the ebuild (and the corresponding cache entry). + # See bug #139134. It is convenient to include checks for + # redundant writes along with the internal StatCollision + # detection code, so for caches with the + # raise_stat_collision attribute, we do not need to + # explicitly check for redundant writes like we do for the + # other cache types above. + max_mtime = sc.mtime + for _ec, ec_hash in metadata['_eclasses_'].items(): + if max_mtime < ec_hash.mtime: + max_mtime = ec_hash.mtime + if max_mtime == sc.mtime: + max_mtime += 1 + max_mtime = long(max_mtime) try: + os.utime(ebuild_hash.location, (max_mtime, max_mtime)) + except OSError as e: + self.returncode |= 1 + writemsg_level( + "%s writing target: %s\n" % (cpv, e), + level=logging.ERROR, noiselevel=-1) + else: + ebuild_hash.mtime = max_mtime + metadata['_mtime_'] = max_mtime trg_cache[cpv] = metadata - except StatCollision as sc: - # If the content of a cache entry changes and neither the - # file mtime nor size changes, it will prevent rsync from - # detecting changes. Cache backends may raise this - # exception from _setitem() if they detect this type of stat - # collision. These exceptions are handled by bumping the - # mtime on the ebuild (and the corresponding cache entry). - # See bug #139134. It is convenient to include checks for - # redundant writes along with the internal StatCollision - # detection code, so for caches with the - # raise_stat_collision attribute, we do not need to - # explicitly check for redundant writes like we do for the - # other cache types above. - max_mtime = sc.mtime - for ec, ec_hash in metadata['_eclasses_'].items(): - if max_mtime < ec_hash.mtime: - max_mtime = ec_hash.mtime - if max_mtime == sc.mtime: - max_mtime += 1 - max_mtime = long(max_mtime) - try: - os.utime(ebuild_hash.location, (max_mtime, max_mtime)) - except OSError as e: - self.returncode |= 1 - writemsg_level( - "%s writing target: %s\n" % (cpv, e), - level=logging.ERROR, noiselevel=-1) - else: - ebuild_hash.mtime = max_mtime - metadata['_mtime_'] = max_mtime - trg_cache[cpv] = metadata - self._portdb.auxdb[repo_path][cpv] = metadata + self._portdb.auxdb[repo_path][cpv] = metadata - except CacheError as ce: - self.returncode |= 1 - writemsg_level( - "%s writing target: %s\n" % (cpv, ce), - level=logging.ERROR, noiselevel=-1) + except CacheError as ce: + self.returncode |= 1 + writemsg_level( + "%s writing target: %s\n" % (cpv, ce), + level=logging.ERROR, noiselevel=-1) def run(self): - - received_signal = [] - - def sighandler(signum, frame): - signal.signal(signal.SIGINT, signal.SIG_IGN) - signal.signal(signal.SIGTERM, signal.SIG_IGN) - self._regen.terminate() - received_signal.append(128 + signum) - - earlier_sigint_handler = signal.signal(signal.SIGINT, sighandler) - earlier_sigterm_handler = signal.signal(signal.SIGTERM, sighandler) - - try: - self._regen.run() - finally: - # Restore previous handlers - if earlier_sigint_handler is not None: - signal.signal(signal.SIGINT, earlier_sigint_handler) - else: - signal.signal(signal.SIGINT, signal.SIG_DFL) - if earlier_sigterm_handler is not None: - signal.signal(signal.SIGTERM, earlier_sigterm_handler) - else: - signal.signal(signal.SIGTERM, signal.SIG_DFL) - - if received_signal: - sys.exit(received_signal[0]) + signum = run_main_scheduler(self._regen) + if signum is not None: + sys.exit(128 + signum) self.returncode |= self._regen.returncode @@ -371,8 +393,8 @@ class GenCache(object): self.returncode |= 1 writemsg_level( "Error listing cache entries for " + \ - "'%s/metadata/cache': %s, continuing...\n" % \ - (self._portdb.porttree_root, ce), + "'%s': %s, continuing...\n" % \ + (trg_cache.location, ce), level=logging.ERROR, noiselevel=-1) else: @@ -393,8 +415,8 @@ class GenCache(object): self.returncode |= 1 writemsg_level( "Error listing cache entries for " + \ - "'%s/metadata/cache': %s, continuing...\n" % \ - (self._portdb.porttree_root, ce), + "'%s': %s, continuing...\n" % \ + (trg_cache.location, ce), level=logging.ERROR, noiselevel=-1) if cp_missing: @@ -426,6 +448,9 @@ class GenCache(object): "committing target: %s\n" % (ce,), level=logging.ERROR, noiselevel=-1) + if hasattr(trg_cache, '_prune_empty_dirs'): + trg_cache._prune_empty_dirs() + class GenUseLocalDesc(object): def __init__(self, portdb, output=None, preserve_comments=False): @@ -433,7 +458,7 @@ class GenUseLocalDesc(object): self._portdb = portdb self._output = output self._preserve_comments = preserve_comments - + def run(self): repo_path = self._portdb.porttrees[0] ops = {'<':0, '<=':1, '=':2, '>=':3, '>':4} @@ -506,14 +531,14 @@ class GenUseLocalDesc(object): encoding=_encodings['fs'], errors='strict'), mode='a', encoding=_encodings['repo.content'], errors='backslashreplace') - output.write(_unicode_decode('\n')) + output.write('\n') else: - output.write(textwrap.dedent(_unicode_decode('''\ + output.write(textwrap.dedent('''\ # This file is deprecated as per GLEP 56 in favor of metadata.xml. Please add # your descriptions to your package's metadata.xml ONLY. # * generated automatically using egencache * - '''))) + ''')) # The cmp function no longer exists in python3, so we'll # implement our own here under a slightly different name @@ -541,7 +566,8 @@ class GenUseLocalDesc(object): for cp in self._portdb.cp_all(): metadata_path = os.path.join(repo_path, cp, 'metadata.xml') try: - metadata = ElementTree.parse(metadata_path, + metadata = ElementTree.parse(_unicode_encode(metadata_path, + encoding=_encodings['fs'], errors='strict'), parser=ElementTree.XMLParser( target=_MetadataTreeBuilder())) except IOError: @@ -597,8 +623,7 @@ class GenUseLocalDesc(object): resatoms = sorted(reskeys, key=cmp_sort_key(atomcmp)) resdesc = resdict[reskeys[resatoms[-1]]] - output.write(_unicode_decode( - '%s:%s - %s\n' % (cp, flag, resdesc))) + output.write('%s:%s - %s\n' % (cp, flag, resdesc)) output.close() @@ -620,7 +645,8 @@ class _special_filename(_filename_base): self.file_name = file_name self.file_type = guessManifestFileType(file_name) - def file_type_lt(self, a, b): + @staticmethod + def file_type_lt(a, b): """ Defines an ordering between file types. """ @@ -695,12 +721,12 @@ class GenChangeLogs(object): self.returncode |= 2 return - output.write(textwrap.dedent(_unicode_decode('''\ + output.write(textwrap.dedent('''\ # ChangeLog for %s # Copyright 1999-%s Gentoo Foundation; Distributed under the GPL v2 # $Header: $ - ''' % (cp, time.strftime('%Y'))))) + ''' % (cp, time.strftime('%Y')))) # now grab all the commits commits = self.grab(['git', 'rev-list', 'HEAD', '--', '.']).split() @@ -764,11 +790,10 @@ class GenChangeLogs(object): # Reverse the sort order for headers. for c in reversed(changed): if c.startswith('+') and c.endswith('.ebuild'): - output.write(_unicode_decode( - '*%s (%s)\n' % (c[1:-7], date))) + output.write('*%s (%s)\n' % (c[1:-7], date)) wroteheader = True if wroteheader: - output.write(_unicode_decode('\n')) + output.write('\n') # strip '<cp>: ', '[<cp>] ', and similar body[0] = re.sub(r'^\W*' + re.escape(cp) + r'\W+', '', body[0]) @@ -788,13 +813,12 @@ class GenChangeLogs(object): # don't break filenames on hyphens self._wrapper.break_on_hyphens = False - output.write(_unicode_decode( - self._wrapper.fill( - '%s; %s %s:' % (date, author, ', '.join(changed))))) + output.write(self._wrapper.fill( + '%s; %s %s:' % (date, author, ', '.join(changed)))) # but feel free to break commit messages there self._wrapper.break_on_hyphens = True - output.write(_unicode_decode( - '\n%s\n\n' % '\n'.join(self._wrapper.fill(x) for x in body))) + output.write( + '\n%s\n\n' % '\n'.join(self._wrapper.fill(x) for x in body)) output.close() @@ -827,17 +851,22 @@ class GenChangeLogs(object): self.generate_changelog(cp) def egencache_main(args): - parser, options, atoms = parse_args(args) - - config_root = options.config_root # The calling environment is ignored, so the program is # completely controlled by commandline arguments. env = {} - if options.repo is None: - env['PORTDIR_OVERLAY'] = '' - elif options.portdir_overlay: + if not sys.stdout.isatty(): + portage.output.nocolor() + env['NOCOLOR'] = 'true' + + parser, options, atoms = parse_args(args) + + config_root = options.config_root + + if options.repositories_configuration is not None: + env['PORTAGE_REPOSITORIES'] = options.repositories_configuration + elif options.portdir_overlay is not None: env['PORTDIR_OVERLAY'] = options.portdir_overlay if options.cache_dir is not None: @@ -851,7 +880,8 @@ def egencache_main(args): default_opts = None if not options.ignore_default_opts: - default_opts = settings.get('EGENCACHE_DEFAULT_OPTS', '').split() + default_opts = portage.util.shlex_split( + settings.get('EGENCACHE_DEFAULT_OPTS', '')) if default_opts: parser, options, args = parse_args(default_opts + args) @@ -862,18 +892,50 @@ def egencache_main(args): settings = portage.config(config_root=config_root, local_config=False, env=env) - if not options.update and not options.update_use_local_desc \ - and not options.update_changelogs: + if not (options.update or options.update_use_local_desc or + options.update_changelogs or options.update_manifests): parser.error('No action specified') return 1 + if options.repo is None: + if len(settings.repositories.prepos) == 2: + for repo in settings.repositories: + if repo.name != "DEFAULT": + options.repo = repo.name + break + + if options.repo is None: + parser.error("--repo option is required") + + repo_path = settings.repositories.treemap.get(options.repo) + if repo_path is None: + parser.error("Unable to locate repository named '%s'" % (options.repo,)) + return 1 + + repo_config = settings.repositories.get_repo_for_location(repo_path) + + if options.strict_manifests is not None: + if options.strict_manifests == "y": + settings.features.add("strict") + else: + settings.features.discard("strict") + if options.update and 'metadata-transfer' not in settings.features: - settings.features.add('metadata-transfer') + # Forcibly enable metadata-transfer if portdbapi has a pregenerated + # cache that does not support eclass validation. + cache = repo_config.get_pregenerated_cache( + portage.dbapi.dbapi._known_keys, readonly=True) + if cache is not None and not cache.complete_eclass_entries: + settings.features.add('metadata-transfer') + cache = None settings.lock() portdb = portage.portdbapi(mysettings=settings) + # Limit ebuilds to the specified repo. + portdb.porttrees = [repo_path] + if options.update: if options.cache_dir is not None: # already validated earlier @@ -889,17 +951,71 @@ def egencache_main(args): level=logging.ERROR, noiselevel=-1) return 1 - if options.repo is not None: - repo_path = portdb.getRepositoryPath(options.repo) - if repo_path is None: - parser.error("Unable to locate repository named '%s'" % \ - (options.repo,)) - return 1 + if options.sign_manifests is not None: + repo_config.sign_manifest = options.sign_manifests == 'y' - # Limit ebuilds to the specified repo. - portdb.porttrees = [repo_path] - else: - portdb.porttrees = [portdb.porttree_root] + if options.thin_manifests is not None: + repo_config.thin_manifest = options.thin_manifests == 'y' + + gpg_cmd = None + gpg_vars = None + force_sign_key = None + + if options.update_manifests: + if repo_config.sign_manifest: + + sign_problem = False + gpg_dir = None + gpg_cmd = settings.get("PORTAGE_GPG_SIGNING_COMMAND") + if gpg_cmd is None: + writemsg_level("egencache: error: " + "PORTAGE_GPG_SIGNING_COMMAND is unset! " + "Is make.globals missing?\n", + level=logging.ERROR, noiselevel=-1) + sign_problem = True + elif "${PORTAGE_GPG_KEY}" in gpg_cmd and \ + options.gpg_key is None and \ + "PORTAGE_GPG_KEY" not in settings: + writemsg_level("egencache: error: " + "PORTAGE_GPG_KEY is unset!\n", + level=logging.ERROR, noiselevel=-1) + sign_problem = True + elif "${PORTAGE_GPG_DIR}" in gpg_cmd: + if options.gpg_dir is not None: + gpg_dir = options.gpg_dir + elif "PORTAGE_GPG_DIR" not in settings: + gpg_dir = os.path.expanduser("~/.gnupg") + else: + gpg_dir = os.path.expanduser(settings["PORTAGE_GPG_DIR"]) + if not os.access(gpg_dir, os.X_OK): + writemsg_level(("egencache: error: " + "Unable to access directory: " + "PORTAGE_GPG_DIR='%s'\n") % gpg_dir, + level=logging.ERROR, noiselevel=-1) + sign_problem = True + + if sign_problem: + writemsg_level("egencache: You may disable manifest " + "signatures with --sign-manifests=n or by setting " + "\"sign-manifests = false\" in metadata/layout.conf\n", + level=logging.ERROR, noiselevel=-1) + return 1 + + gpg_vars = {} + if gpg_dir is not None: + gpg_vars["PORTAGE_GPG_DIR"] = gpg_dir + gpg_var_names = [] + if options.gpg_key is None: + gpg_var_names.append("PORTAGE_GPG_KEY") + else: + gpg_vars["PORTAGE_GPG_KEY"] = options.gpg_key + + for k in gpg_var_names: + v = settings.get(k) + if v is not None: + gpg_vars[k] = v + + force_sign_key = gpg_vars.get("PORTAGE_GPG_KEY") ret = [os.EX_OK] @@ -918,6 +1034,29 @@ def egencache_main(args): else: ret.append(gen_cache.returncode) + if options.update_manifests: + + cp_iter = None + if atoms: + cp_iter = iter(atoms) + + event_loop = global_event_loop() + scheduler = ManifestScheduler(portdb, cp_iter=cp_iter, + gpg_cmd=gpg_cmd, gpg_vars=gpg_vars, + force_sign_key=force_sign_key, + max_jobs=options.jobs, + max_load=options.load_average, + event_loop=event_loop) + + signum = run_main_scheduler(scheduler) + if signum is not None: + sys.exit(128 + signum) + + if options.tolerant: + ret.append(os.EX_OK) + else: + ret.append(scheduler.returncode) + if options.update_use_local_desc: gen_desc = GenUseLocalDesc(portdb, output=options.uld_output, @@ -930,6 +1069,16 @@ def egencache_main(args): gen_clogs.run() ret.append(gen_clogs.returncode) + if options.write_timestamp: + timestamp_path = os.path.join(repo_path, 'metadata', 'timestamp.chk') + try: + with open(timestamp_path, 'w') as f: + f.write(time.strftime('%s\n' % TIMESTAMP_FORMAT, time.gmtime())) + except IOError: + ret.append(os.EX_IOERR) + else: + ret.append(os.EX_OK) + return max(ret) if __name__ == "__main__": diff --git a/portage_with_autodep/bin/emaint b/portage_with_autodep/bin/emaint index 1bee0fe..adf44d0 100755 --- a/portage_with_autodep/bin/emaint +++ b/portage_with_autodep/bin/emaint @@ -1,654 +1,42 @@ #!/usr/bin/python -O -# vim: noet : +# Copyright 2005-2013 Gentoo Foundation +# Distributed under the terms of the GNU General Public License v2 + +"""System health checks and maintenance utilities. +""" from __future__ import print_function -import errno -import re -import signal -import stat import sys -import textwrap -import time -from optparse import OptionParser, OptionValueError - +import errno +# This block ensures that ^C interrupts are handled quietly. 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 -from portage.util import writemsg - -if sys.hexversion >= 0x3000000: - long = int - -class WorldHandler(object): - - short_desc = "Fix problems in the world file" - - def name(): - return "world" - name = staticmethod(name) - - def __init__(self): - self.invalid = [] - self.not_installed = [] - self.invalid_category = [] - self.okay = [] - from portage._sets import load_default_config - setconfig = load_default_config(portage.settings, - portage.db[portage.settings['EROOT']]) - self._sets = setconfig.getSets() - - def _check_world(self, onProgress): - categories = set(portage.settings.categories) - eroot = portage.settings['EROOT'] - self.world_file = os.path.join(eroot, portage.const.WORLD_FILE) - self.found = os.access(self.world_file, os.R_OK) - vardb = portage.db[eroot]["vartree"].dbapi - - from portage._sets import SETPREFIX - sets = self._sets - world_atoms = list(sets["selected"]) - maxval = len(world_atoms) - if onProgress: - onProgress(maxval, 0) - for i, atom in enumerate(world_atoms): - if not isinstance(atom, portage.dep.Atom): - if atom.startswith(SETPREFIX): - s = atom[len(SETPREFIX):] - if s in sets: - self.okay.append(atom) - else: - self.not_installed.append(atom) - else: - self.invalid.append(atom) - if onProgress: - onProgress(maxval, i+1) - continue - okay = True - if not vardb.match(atom): - self.not_installed.append(atom) - okay = False - if portage.catsplit(atom.cp)[0] not in categories: - self.invalid_category.append(atom) - okay = False - if okay: - self.okay.append(atom) - if onProgress: - onProgress(maxval, i+1) - - def check(self, onProgress=None): - self._check_world(onProgress) - errors = [] - if self.found: - errors += ["'%s' is not a valid atom" % x for x in self.invalid] - errors += ["'%s' is not installed" % x for x in self.not_installed] - errors += ["'%s' has a category that is not listed in /etc/portage/categories" % x for x in self.invalid_category] - else: - errors.append(self.world_file + " could not be opened for reading") - return errors - - def fix(self, onProgress=None): - world_set = self._sets["selected"] - world_set.lock() - try: - world_set.load() # maybe it's changed on disk - before = set(world_set) - self._check_world(onProgress) - after = set(self.okay) - errors = [] - if before != after: - try: - world_set.replace(self.okay) - except portage.exception.PortageException: - errors.append("%s could not be opened for writing" % \ - self.world_file) - return errors - finally: - world_set.unlock() - -class BinhostHandler(object): - - short_desc = "Generate a metadata index for binary packages" - - def name(): - return "binhost" - name = staticmethod(name) - - def __init__(self): - eroot = portage.settings['EROOT'] - self._bintree = portage.db[eroot]["bintree"] - self._bintree.populate() - self._pkgindex_file = self._bintree._pkgindex_file - self._pkgindex = self._bintree._load_pkgindex() - - def _need_update(self, cpv, data): - - if "MD5" not in data: - return True - - size = data.get("SIZE") - if size is None: - return True - - mtime = data.get("MTIME") - if mtime is None: - return True - - pkg_path = self._bintree.getname(cpv) - try: - s = os.lstat(pkg_path) - except OSError as e: - if e.errno not in (errno.ENOENT, errno.ESTALE): - raise - # We can't update the index for this one because - # it disappeared. - return False - - try: - if long(mtime) != s[stat.ST_MTIME]: - return True - if long(size) != long(s.st_size): - return True - except ValueError: - return True - - return False - - def check(self, onProgress=None): - missing = [] - cpv_all = self._bintree.dbapi.cpv_all() - cpv_all.sort() - maxval = len(cpv_all) - if onProgress: - onProgress(maxval, 0) - pkgindex = self._pkgindex - missing = [] - metadata = {} - for d in pkgindex.packages: - metadata[d["CPV"]] = d - for i, cpv in enumerate(cpv_all): - d = metadata.get(cpv) - if not d or self._need_update(cpv, d): - missing.append(cpv) - if onProgress: - onProgress(maxval, i+1) - errors = ["'%s' is not in Packages" % cpv for cpv in missing] - stale = set(metadata).difference(cpv_all) - for cpv in stale: - errors.append("'%s' is not in the repository" % cpv) - return errors - - def fix(self, onProgress=None): - bintree = self._bintree - cpv_all = self._bintree.dbapi.cpv_all() - cpv_all.sort() - missing = [] - maxval = 0 - if onProgress: - onProgress(maxval, 0) - pkgindex = self._pkgindex - missing = [] - metadata = {} - for d in pkgindex.packages: - metadata[d["CPV"]] = d - - for i, cpv in enumerate(cpv_all): - d = metadata.get(cpv) - if not d or self._need_update(cpv, d): - missing.append(cpv) - - stale = set(metadata).difference(cpv_all) - if missing or stale: - from portage import locks - pkgindex_lock = locks.lockfile( - self._pkgindex_file, wantnewlockfile=1) - try: - # Repopulate with lock held. - bintree._populate() - cpv_all = self._bintree.dbapi.cpv_all() - cpv_all.sort() - - pkgindex = bintree._load_pkgindex() - self._pkgindex = pkgindex - - metadata = {} - for d in pkgindex.packages: - metadata[d["CPV"]] = d - - # Recount missing packages, with lock held. - del missing[:] - for i, cpv in enumerate(cpv_all): - d = metadata.get(cpv) - if not d or self._need_update(cpv, d): - missing.append(cpv) - - maxval = len(missing) - for i, cpv in enumerate(missing): - try: - metadata[cpv] = bintree._pkgindex_entry(cpv) - except portage.exception.InvalidDependString: - writemsg("!!! Invalid binary package: '%s'\n" % \ - bintree.getname(cpv), noiselevel=-1) - - if onProgress: - onProgress(maxval, i+1) - - for cpv in set(metadata).difference( - self._bintree.dbapi.cpv_all()): - del metadata[cpv] - - # We've updated the pkgindex, so set it to - # repopulate when necessary. - bintree.populated = False - - del pkgindex.packages[:] - pkgindex.packages.extend(metadata.values()) - from portage.util import atomic_ofstream - f = atomic_ofstream(self._pkgindex_file) - try: - self._pkgindex.write(f) - finally: - f.close() - finally: - locks.unlockfile(pkgindex_lock) - - if onProgress: - if maxval == 0: - maxval = 1 - onProgress(maxval, maxval) - return None - -class MoveHandler(object): - - def __init__(self, tree, porttree): - self._tree = tree - self._portdb = porttree.dbapi - self._update_keys = ["DEPEND", "RDEPEND", "PDEPEND", "PROVIDE"] - self._master_repo = \ - self._portdb.getRepositoryName(self._portdb.porttree_root) - - def _grab_global_updates(self): - from portage.update import grab_updates, parse_updates - retupdates = {} - errors = [] - - for repo_name in self._portdb.getRepositories(): - repo = self._portdb.getRepositoryPath(repo_name) - updpath = os.path.join(repo, "profiles", "updates") - if not os.path.isdir(updpath): - continue - - try: - rawupdates = grab_updates(updpath) - except portage.exception.DirectoryNotFound: - rawupdates = [] - upd_commands = [] - for mykey, mystat, mycontent in rawupdates: - commands, errors = parse_updates(mycontent) - upd_commands.extend(commands) - errors.extend(errors) - retupdates[repo_name] = upd_commands - - if self._master_repo in retupdates: - retupdates['DEFAULT'] = retupdates[self._master_repo] + import signal - return retupdates, errors + def exithandler(signum, _frame): + signal.signal(signal.SIGINT, signal.SIG_IGN) + signal.signal(signal.SIGTERM, signal.SIG_IGN) + sys.exit(128 + signum) - def check(self, onProgress=None): - allupdates, errors = self._grab_global_updates() - # Matching packages and moving them is relatively fast, so the - # progress bar is updated in indeterminate mode. - match = self._tree.dbapi.match - aux_get = self._tree.dbapi.aux_get - if onProgress: - onProgress(0, 0) - for repo, updates in allupdates.items(): - if repo == 'DEFAULT': - continue - if not updates: - continue + signal.signal(signal.SIGINT, exithandler) + signal.signal(signal.SIGTERM, exithandler) + signal.signal(signal.SIGPIPE, signal.SIG_DFL) - def repo_match(repository): - return repository == repo or \ - (repo == self._master_repo and \ - repository not in allupdates) +except KeyboardInterrupt: + sys.exit(1) - for i, update_cmd in enumerate(updates): - if update_cmd[0] == "move": - origcp, newcp = update_cmd[1:] - for cpv in match(origcp): - if repo_match(aux_get(cpv, ["repository"])[0]): - errors.append("'%s' moved to '%s'" % (cpv, newcp)) - elif update_cmd[0] == "slotmove": - pkg, origslot, newslot = update_cmd[1:] - for cpv in match(pkg): - slot, prepo = aux_get(cpv, ["SLOT", "repository"]) - if slot == origslot and repo_match(prepo): - errors.append("'%s' slot moved from '%s' to '%s'" % \ - (cpv, origslot, newslot)) - if onProgress: - onProgress(0, 0) +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.emaint.main import emaint_main - # Searching for updates in all the metadata is relatively slow, so this - # is where the progress bar comes out of indeterminate mode. - cpv_all = self._tree.dbapi.cpv_all() - cpv_all.sort() - maxval = len(cpv_all) - aux_update = self._tree.dbapi.aux_update - meta_keys = self._update_keys + ['repository'] - from portage.update import update_dbentries - if onProgress: - onProgress(maxval, 0) - for i, cpv in enumerate(cpv_all): - metadata = dict(zip(meta_keys, aux_get(cpv, meta_keys))) - repository = metadata.pop('repository') - try: - updates = allupdates[repository] - except KeyError: - try: - updates = allupdates['DEFAULT'] - except KeyError: - continue - if not updates: - continue - metadata_updates = update_dbentries(updates, metadata) - if metadata_updates: - errors.append("'%s' has outdated metadata" % cpv) - if onProgress: - onProgress(maxval, i+1) - return errors - - def fix(self, onProgress=None): - allupdates, errors = self._grab_global_updates() - # Matching packages and moving them is relatively fast, so the - # progress bar is updated in indeterminate mode. - move = self._tree.dbapi.move_ent - slotmove = self._tree.dbapi.move_slot_ent - if onProgress: - onProgress(0, 0) - for repo, updates in allupdates.items(): - if repo == 'DEFAULT': - continue - if not updates: - continue - - def repo_match(repository): - return repository == repo or \ - (repo == self._master_repo and \ - repository not in allupdates) - - for i, update_cmd in enumerate(updates): - if update_cmd[0] == "move": - move(update_cmd, repo_match=repo_match) - elif update_cmd[0] == "slotmove": - slotmove(update_cmd, repo_match=repo_match) - if onProgress: - onProgress(0, 0) - - # Searching for updates in all the metadata is relatively slow, so this - # is where the progress bar comes out of indeterminate mode. - self._tree.dbapi.update_ents(allupdates, onProgress=onProgress) - return errors - -class MoveInstalled(MoveHandler): - - short_desc = "Perform package move updates for installed packages" - - def name(): - return "moveinst" - name = staticmethod(name) - def __init__(self): - eroot = portage.settings['EROOT'] - MoveHandler.__init__(self, portage.db[eroot]["vartree"], portage.db[eroot]["porttree"]) - -class MoveBinary(MoveHandler): - - short_desc = "Perform package move updates for binary packages" - - def name(): - return "movebin" - name = staticmethod(name) - def __init__(self): - eroot = portage.settings['EROOT'] - MoveHandler.__init__(self, portage.db[eroot]["bintree"], portage.db[eroot]['porttree']) - -class VdbKeyHandler(object): - def name(): - return "vdbkeys" - name = staticmethod(name) - - def __init__(self): - self.list = portage.db[portage.settings["EROOT"]]["vartree"].dbapi.cpv_all() - self.missing = [] - self.keys = ["HOMEPAGE", "SRC_URI", "KEYWORDS", "DESCRIPTION"] - - for p in self.list: - mydir = os.path.join(portage.settings["EROOT"], portage.const.VDB_PATH, p)+os.sep - ismissing = True - for k in self.keys: - if os.path.exists(mydir+k): - ismissing = False - break - if ismissing: - self.missing.append(p) - - def check(self): - return ["%s has missing keys" % x for x in self.missing] - - def fix(self): - - errors = [] - - for p in self.missing: - mydir = os.path.join(portage.settings["EROOT"], portage.const.VDB_PATH, p)+os.sep - if not os.access(mydir+"environment.bz2", os.R_OK): - errors.append("Can't access %s" % (mydir+"environment.bz2")) - elif not os.access(mydir, os.W_OK): - errors.append("Can't create files in %s" % mydir) - else: - env = os.popen("bzip2 -dcq "+mydir+"environment.bz2", "r") - envlines = env.read().split("\n") - env.close() - for k in self.keys: - s = [l for l in envlines if l.startswith(k+"=")] - if len(s) > 1: - errors.append("multiple matches for %s found in %senvironment.bz2" % (k, mydir)) - elif len(s) == 0: - s = "" - else: - s = s[0].split("=",1)[1] - s = s.lstrip("$").strip("\'\"") - s = re.sub("(\\\\[nrt])+", " ", s) - s = " ".join(s.split()).strip() - if s != "": - try: - keyfile = open(mydir+os.sep+k, "w") - keyfile.write(s+"\n") - keyfile.close() - except (IOError, OSError) as e: - errors.append("Could not write %s, reason was: %s" % (mydir+k, e)) - - return errors - -class ProgressHandler(object): - def __init__(self): - self.curval = 0 - self.maxval = 0 - self.last_update = 0 - self.min_display_latency = 0.2 - - def onProgress(self, maxval, curval): - self.maxval = maxval - self.curval = curval - cur_time = time.time() - if cur_time - self.last_update >= self.min_display_latency: - self.last_update = cur_time - self.display() - - def display(self): - raise NotImplementedError(self) - -class CleanResume(object): - - short_desc = "Discard emerge --resume merge lists" - - def name(): - return "cleanresume" - name = staticmethod(name) - - def check(self, onProgress=None): - messages = [] - mtimedb = portage.mtimedb - resume_keys = ("resume", "resume_backup") - maxval = len(resume_keys) - if onProgress: - onProgress(maxval, 0) - for i, k in enumerate(resume_keys): - try: - d = mtimedb.get(k) - if d is None: - continue - if not isinstance(d, dict): - messages.append("unrecognized resume list: '%s'" % k) - continue - mergelist = d.get("mergelist") - if mergelist is None or not hasattr(mergelist, "__len__"): - messages.append("unrecognized resume list: '%s'" % k) - continue - messages.append("resume list '%s' contains %d packages" % \ - (k, len(mergelist))) - finally: - if onProgress: - onProgress(maxval, i+1) - return messages - - def fix(self, onProgress=None): - delete_count = 0 - mtimedb = portage.mtimedb - resume_keys = ("resume", "resume_backup") - maxval = len(resume_keys) - if onProgress: - onProgress(maxval, 0) - for i, k in enumerate(resume_keys): - try: - if mtimedb.pop(k, None) is not None: - delete_count += 1 - finally: - if onProgress: - onProgress(maxval, i+1) - if delete_count: - mtimedb.commit() - -def emaint_main(myargv): - - # Similar to emerge, emaint needs a default umask so that created - # files (such as the world file) have sane permissions. - os.umask(0o22) - - # TODO: Create a system that allows external modules to be added without - # the need for hard coding. - modules = { - "world" : WorldHandler, - "binhost":BinhostHandler, - "moveinst":MoveInstalled, - "movebin":MoveBinary, - "cleanresume":CleanResume - } - - module_names = list(modules) - module_names.sort() - module_names.insert(0, "all") - - def exclusive(option, *args, **kw): - var = kw.get("var", None) - if var is None: - raise ValueError("var not specified to exclusive()") - if getattr(parser, var, ""): - raise OptionValueError("%s and %s are exclusive options" % (getattr(parser, var), option)) - setattr(parser, var, str(option)) - - - usage = "usage: emaint [options] COMMAND" - - desc = "The emaint program provides an interface to system health " + \ - "checks and maintenance. See the emaint(1) man page " + \ - "for additional information about the following commands:" - - usage += "\n\n" - for line in textwrap.wrap(desc, 65): - usage += "%s\n" % line - usage += "\n" - usage += " %s" % "all".ljust(15) + \ - "Perform all supported commands\n" - for m in module_names[1:]: - usage += " %s%s\n" % (m.ljust(15), modules[m].short_desc) - - parser = OptionParser(usage=usage, version=portage.VERSION) - parser.add_option("-c", "--check", help="check for problems", - action="callback", callback=exclusive, callback_kwargs={"var":"action"}) - parser.add_option("-f", "--fix", help="attempt to fix problems", - action="callback", callback=exclusive, callback_kwargs={"var":"action"}) - parser.action = None - - - (options, args) = parser.parse_args(args=myargv) - if len(args) != 1: - parser.error("Incorrect number of arguments") - if args[0] not in module_names: - parser.error("%s target is not a known target" % args[0]) - - if parser.action: - action = parser.action - else: - print("Defaulting to --check") - action = "-c/--check" - - if args[0] == "all": - tasks = modules.values() - else: - tasks = [modules[args[0]]] - - - if action == "-c/--check": - status = "Checking %s for problems" - func = "check" - else: - status = "Attempting to fix %s" - func = "fix" - - isatty = os.environ.get('TERM') != 'dumb' and sys.stdout.isatty() - for task in tasks: - print(status % task.name()) - inst = task() - onProgress = None - if isatty: - progressBar = portage.output.TermProgressBar() - progressHandler = ProgressHandler() - onProgress = progressHandler.onProgress - def display(): - progressBar.set(progressHandler.curval, progressHandler.maxval) - progressHandler.display = display - def sigwinch_handler(signum, frame): - lines, progressBar.term_columns = \ - portage.output.get_term_size() - signal.signal(signal.SIGWINCH, sigwinch_handler) - result = getattr(inst, func)(onProgress=onProgress) - if isatty: - # make sure the final progress is displayed - progressHandler.display() - print() - signal.signal(signal.SIGWINCH, signal.SIG_DFL) - if result: - print() - print("\n".join(result)) - print("\n") - - print("Finished") - -if __name__ == "__main__": +try: emaint_main(sys.argv[1:]) +except IOError as e: + if e.errno == errno.EACCES: + print("\nemaint: Need superuser access") + sys.exit(1) + else: + raise diff --git a/portage_with_autodep/bin/emerge b/portage_with_autodep/bin/emerge index 6f69244..4d9ea5a 100755 --- a/portage_with_autodep/bin/emerge +++ b/portage_with_autodep/bin/emerge @@ -1,66 +1,79 @@ #!/usr/bin/python -# Copyright 2006-2011 Gentoo Foundation +# Copyright 2006-2013 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. + +# This block ensures that ^C interrupts are handled quietly. We handle +# KeyboardInterrupt instead of installing a SIGINT handler, since +# exiting from signal handlers intermittently causes python to ignore +# the SystemExit exception with a message like this: +# Exception SystemExit: 130 in <function remove at 0x7fd2146c1320> ignored try: - def exithandler(signum,frame): - signal.signal(signal.SIGINT, signal.SIG_IGN) + def exithandler(signum, _frame): 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() -def debug_signal(signum, frame): - import pdb - pdb.set_trace() -signal.signal(signal.SIGUSR1, debug_signal) + if platform.python_implementation() == 'Jython': + debug_signum = signal.SIGUSR2 # bug #424259 + else: + debug_signum = signal.SIGUSR1 + + signal.signal(debug_signum, debug_signal) -try: - from _emerge.main import emerge_main -except ImportError: from os import path as osp - import sys - sys.path.insert(0, osp.join(osp.dirname(osp.dirname(osp.realpath(__file__))), "pym")) + pym_path = osp.join(osp.dirname(osp.dirname( + osp.realpath(__file__))), "pym") + sys.path.insert(0, pym_path) + import portage + portage._internal_caller = True + portage._disable_legacy_globals() from _emerge.main import emerge_main -if __name__ == "__main__": - import sys - from portage.exception import ParseError, PermissionDenied - try: - retval = emerge_main() - except PermissionDenied as e: - sys.stderr.write("Permission denied: '%s'\n" % str(e)) - sys.exit(e.errno) - except ParseError as e: - sys.stderr.write("%s\n" % str(e)) - sys.exit(1) - except SystemExit: - raise - except Exception: - # If an unexpected exception occurs then we don't want the mod_echo - # output to obscure the traceback, so dump the mod_echo output before - # showing the traceback. - import traceback - tb_str = traceback.format_exc() + if __name__ == "__main__": + from portage.exception import ParseError, PermissionDenied try: - from portage.elog import mod_echo - except ImportError: - pass - else: - mod_echo.finalize() - sys.stderr.write(tb_str) - sys.exit(1) - sys.exit(retval) + retval = emerge_main() + except PermissionDenied as e: + sys.stderr.write("Permission denied: '%s'\n" % str(e)) + sys.exit(e.errno) + except ParseError as e: + sys.stderr.write("%s\n" % str(e)) + sys.exit(1) + except (KeyboardInterrupt, SystemExit): + raise + except Exception: + # If an unexpected exception occurs then we don't want the + # mod_echo output to obscure the traceback, so dump the + # mod_echo output before showing the traceback. + import traceback + tb_str = traceback.format_exc() + try: + from portage.elog import mod_echo + except ImportError: + pass + else: + mod_echo.finalize() + sys.stderr.write(tb_str) + sys.exit(1) + sys.exit(retval) + +except KeyboardInterrupt: + sys.stderr.write("\n\nExiting on signal %(signal)s\n" % + {"signal": signal.SIGINT}) + sys.stderr.flush() + sys.exit(128 + signal.SIGINT) diff --git a/portage_with_autodep/bin/emerge-webrsync b/portage_with_autodep/bin/emerge-webrsync index bfd9aa2..85730a2 100755 --- a/portage_with_autodep/bin/emerge-webrsync +++ b/portage_with_autodep/bin/emerge-webrsync @@ -1,5 +1,5 @@ #!/bin/bash -# Copyright 1999-2011 Gentoo Foundation +# Copyright 1999-2013 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 # Author: Karl Trygve Kalleberg <karltk@gentoo.org> # Rewritten from the old, Perl-based emerge-webrsync script @@ -22,9 +22,9 @@ vvecho() { [[ ${do_verbose} -eq 1 ]] && echo "$@" ; } # Only echo if not in verbose mode nvecho() { [[ ${do_verbose} -eq 0 ]] && echo "$@" ; } # warning echos -wecho() { echo "${argv0}: warning: $*" 1>&2 ; } +wecho() { echo "${argv0##*/}: warning: $*" 1>&2 ; } # error echos -eecho() { echo "${argv0}: error: $*" 1>&2 ; } +eecho() { echo "${argv0##*/}: error: $*" 1>&2 ; } argv0=$0 @@ -39,23 +39,33 @@ else eecho "could not find 'portageq'; aborting" exit 1 fi -eval $("${portageq}" envvar -v FEATURES FETCHCOMMAND GENTOO_MIRRORS \ - PORTAGE_BIN_PATH PORTAGE_GPG_DIR \ - PORTAGE_NICENESS PORTAGE_RSYNC_EXTRA_OPTS PORTAGE_TMPDIR PORTDIR \ - SYNC http_proxy ftp_proxy) -DISTDIR="${PORTAGE_TMPDIR}/emerge-webrsync" +eval "$("${portageq}" envvar -v DISTDIR EPREFIX FEATURES \ + FETCHCOMMAND GENTOO_MIRRORS \ + PORTAGE_BIN_PATH PORTAGE_CONFIGROOT PORTAGE_GPG_DIR \ + PORTAGE_NICENESS PORTAGE_REPOSITORIES PORTAGE_RSYNC_EXTRA_OPTS \ + PORTAGE_RSYNC_OPTS PORTAGE_TMPDIR \ + USERLAND http_proxy ftp_proxy)" export http_proxy ftp_proxy +source "${PORTAGE_BIN_PATH}"/isolated-functions.sh || exit 1 + +repo_name=gentoo +repo_location=$(__repo_key "${repo_name}" location) +if [[ -z ${repo_location} ]]; then + eecho "Repository '${repo_name}' not found" + exit 1 +fi +repo_sync_type=$(__repo_key "${repo_name}" sync-type) + # If PORTAGE_NICENESS is overriden via the env then it will # still pass through the portageq call and override properly. if [ -n "${PORTAGE_NICENESS}" ]; then renice $PORTAGE_NICENESS $$ > /dev/null fi -source "${PORTAGE_BIN_PATH}"/isolated-functions.sh || exit 1 - do_verbose=0 do_debug=0 +keep=false if has webrsync-gpg ${FEATURES} ; then WEBSYNC_VERIFY_SIGNATURE=1 @@ -99,7 +109,9 @@ get_date_part() { get_utc_second_from_string() { local s="$1" if [[ ${USERLAND} == BSD ]] ; then - date -juf "%Y%m%d" "$s" +"%s" + # Specify zeros for the least significant digits, or else those + # digits are inherited from the current system clock time. + date -juf "%Y%m%d%H%M.%S" "${s}0000.00" +"%s" else date -d "${s:0:4}-${s:4:2}-${s:6:2}" -u +"%s" fi @@ -108,8 +120,8 @@ get_utc_second_from_string() { get_portage_timestamp() { local portage_current_timestamp=0 - if [ -f "${PORTDIR}/metadata/timestamp.x" ]; then - portage_current_timestamp=$(cut -f 1 -d " " "${PORTDIR}/metadata/timestamp.x" ) + if [ -f "${repo_location}/metadata/timestamp.x" ]; then + portage_current_timestamp=$(cut -f 1 -d " " "${repo_location}/metadata/timestamp.x" ) fi echo "${portage_current_timestamp}" @@ -125,13 +137,18 @@ fetch_file() { elif [ "${FETCHCOMMAND/curl/}" != "${FETCHCOMMAND}" ]; then opts="--continue-at - $(nvecho -s -f)" else - rm -f "${FILE}" + rm -f "${DISTDIR}/${FILE}" fi - vecho "Fetching file ${FILE} ..." + __vecho "Fetching file ${FILE} ..." # already set DISTDIR= - eval "${FETCHCOMMAND}" ${opts} - [ -s "${FILE}" ] + eval "${FETCHCOMMAND} ${opts}" + if [[ $? -eq 0 && -s ${DISTDIR}/${FILE} ]] ; then + return 0 + else + rm -f "${DISTDIR}/${FILE}" + return 1 + fi } check_file_digest() { @@ -139,10 +156,12 @@ check_file_digest() { local file="$2" local r=1 - vecho "Checking digest ..." + __vecho "Checking digest ..." if type -P md5sum > /dev/null; then - md5sum -c $digest && r=0 + local md5sum_output=$(md5sum "${file}") + local digest_content=$(< "${digest}") + [ "${md5sum_output%%[[:space:]]*}" = "${digest_content%%[[:space:]]*}" ] && r=0 elif type -P md5 > /dev/null; then [ "$(md5 -q "${file}")" == "$(cut -d ' ' -f 1 "${digest}")" ] && r=0 else @@ -159,7 +178,7 @@ check_file_signature() { if [ ${WEBSYNC_VERIFY_SIGNATURE} != 0 ]; then - vecho "Checking signature ..." + __vecho "Checking signature ..." if type -P gpg > /dev/null; then gpg --homedir "${PORTAGE_GPG_DIR}" --verify "$signature" "$file" && r=0 @@ -183,13 +202,25 @@ get_snapshot_timestamp() { sync_local() { local file="$1" - vecho "Syncing local tree ..." + __vecho "Syncing local tree ..." + + local ownership="portage:portage" + if has usersync ${FEATURES} ; then + case "${USERLAND}" in + BSD) + ownership=$(stat -f '%Su:%Sg' "${repo_location}") + ;; + *) + ownership=$(stat -c '%U:%G' "${repo_location}") + ;; + esac + fi if type -P tarsync > /dev/null ; then - local chown_opts="-o portage -g portage" - chown portage:portage portage > /dev/null 2>&1 || chown_opts="" + local chown_opts="-o ${ownership%:*} -g ${ownership#*:}" + chown ${ownership} "${repo_location}" > /dev/null 2>&1 || chown_opts="" if ! tarsync $(vvecho -v) -s 1 ${chown_opts} \ - -e /distfiles -e /packages -e /local "${file}" "${PORTDIR}"; then + -e /distfiles -e /packages -e /local "${file}" "${repo_location}"; then eecho "tarsync failed; tarball is corrupt? (${file})" return 1 fi @@ -201,27 +232,29 @@ sync_local() { fi # Free disk space - rm -f "${file}" + ${keep} || rm -f "${file}" - chown portage:portage portage > /dev/null 2>&1 && \ - chown -R portage:portage portage + local rsync_opts="${PORTAGE_RSYNC_OPTS} ${PORTAGE_RSYNC_EXTRA_OPTS}" + if chown ${ownership} portage > /dev/null 2>&1; then + chown -R ${ownership} portage + rsync_opts+=" --owner --group" + fi cd portage - rsync -av --progress --stats --delete --delete-after \ - --exclude='/distfiles' --exclude='/packages' \ - --exclude='/local' ${PORTAGE_RSYNC_EXTRA_OPTS} . "${PORTDIR%%/}" + rsync ${rsync_opts} . "${repo_location%%/}" cd .. - vecho "Cleaning up ..." + __vecho "Cleaning up ..." rm -fr portage fi if has metadata-transfer ${FEATURES} ; then - vecho "Updating cache ..." - emerge --metadata + __vecho "Updating cache ..." + "${PORTAGE_BIN_PATH}/emerge" --metadata fi - [ -x /etc/portage/bin/post_sync ] && /etc/portage/bin/post_sync + local post_sync=${PORTAGE_CONFIGROOT}etc/portage/bin/post_sync + [ -x "${post_sync}" ] && "${post_sync}" # --quiet suppresses output if there are no relevant news items - has news ${FEATURES} && emerge --check-news --quiet + has news ${FEATURES} && "${PORTAGE_BIN_PATH}/emerge" --check-news --quiet return 0 } @@ -251,14 +284,15 @@ do_snapshot() { for mirror in ${GENTOO_MIRRORS} ; do - vecho "Trying to retrieve ${date} snapshot from ${mirror} ..." + mirror=${mirror%/} + __vecho "Trying to retrieve ${date} snapshot from ${mirror} ..." for compression in ${compressions} ; do local file="portage-${date}.tar.${compression}" local digest="${file}.md5sum" local signature="${file}.gpgsig" - if [ -s "${file}" -a -s "${digest}" -a -s "${signature}" ] ; then + if [ -s "${DISTDIR}/${file}" -a -s "${DISTDIR}/${digest}" -a -s "${DISTDIR}/${signature}" ] ; then check_file_digest "${DISTDIR}/${digest}" "${DISTDIR}/${file}" && \ check_file_signature "${DISTDIR}/${signature}" "${DISTDIR}/${file}" && \ have_files=1 @@ -280,8 +314,8 @@ do_snapshot() { # if [ ${have_files} -eq 1 ]; then - vecho "Getting snapshot timestamp ..." - local snapshot_timestamp=$(get_snapshot_timestamp "${file}") + __vecho "Getting snapshot timestamp ..." + local snapshot_timestamp=$(get_snapshot_timestamp "${DISTDIR}/${file}") if [ ${ignore_timestamp} == 0 ]; then if [ ${snapshot_timestamp} -lt $(get_portage_timestamp) ]; then @@ -310,7 +344,7 @@ do_snapshot() { # # Remove files and use a different mirror # - rm -f "${file}" "${digest}" "${signature}" + rm -f "${DISTDIR}/${file}" "${DISTDIR}/${digest}" "${DISTDIR}/${signature}" fi done @@ -318,12 +352,12 @@ do_snapshot() { done if [ ${have_files} -eq 1 ]; then - sync_local "${file}" && r=0 + sync_local "${DISTDIR}/${file}" && r=0 else - vecho "${date} snapshot was not found" + __vecho "${date} snapshot was not found" fi - - rm -f "${file}" "${digest}" "${signature}" + + ${keep} || rm -f "${DISTDIR}/${file}" "${DISTDIR}/${digest}" "${DISTDIR}/${signature}" return "${r}" } @@ -331,9 +365,9 @@ do_latest_snapshot() { local attempts=0 local r=1 - vecho "Fetching most recent snapshot ..." + __vecho "Fetching most recent snapshot ..." - # The snapshot for a given day is generated at 01:45 UTC on the following + # The snapshot for a given day is generated at 00:45 UTC on the following # day, so the current day's snapshot (going by UTC time) hasn't been # generated yet. Therefore, always start by looking for the previous day's # snapshot (for attempts=1, subtract 1 day from the current UTC time). @@ -349,10 +383,10 @@ do_latest_snapshot() { local start_time=$(get_utc_date_in_seconds) local start_hour=$(get_date_part ${start_time} "%H") - # Daily snapshots are created at 1:45 AM and are not - # available until after 2 AM. Don't waste time trying + # Daily snapshots are created at 00:45 and are not + # available until after 01:00. Don't waste time trying # to fetch a snapshot before it's been created. - if [ ${start_hour} -lt 2 ] ; then + if [ ${start_hour} -lt 1 ] ; then (( start_time -= 86400 )) fi local snapshot_date=$(get_date_part ${start_time} "%Y%m%d") @@ -361,8 +395,8 @@ do_latest_snapshot() { while (( ${attempts} < 40 )) ; do (( attempts++ )) (( snapshot_date_seconds -= 86400 )) - # snapshots are created at 1:45 AM - (( approx_snapshot_time = snapshot_date_seconds + 86400 + 6300 )) + # snapshots are created at 00:45 + (( approx_snapshot_time = snapshot_date_seconds + 86400 + 2700 )) (( timestamp_difference = existing_timestamp - approx_snapshot_time )) [ ${timestamp_difference} -lt 0 ] && (( timestamp_difference = -1 * timestamp_difference )) snapshot_date=$(get_date_part ${snapshot_date_seconds} "%Y%m%d") @@ -388,7 +422,7 @@ do_latest_snapshot() { "snapshot. In order to force sync," \ "use the --revert option or remove" \ "the timestamp file located at" \ - "'${PORTDIR}/metadata/timestamp.x'." | fmt -w 70 | \ + "'${repo_location}/metadata/timestamp.x'." | fmt -w 70 | \ while read -r line ; do ewarn "${line}" done @@ -408,9 +442,10 @@ do_latest_snapshot() { usage() { cat <<-EOF Usage: $0 [options] - + Options: --revert=yyyymmdd Revert to snapshot + -k, --keep Keep snapshots in DISTDIR (don't delete) -q, --quiet Only output errors -v, --verbose Enable verbose output -x, --debug Enable debug output @@ -427,14 +462,12 @@ usage() { main() { local arg local revert_date - - [ ! -d "${DISTDIR}" ] && mkdir -p "${DISTDIR}" - cd "${DISTDIR}" for arg in "$@" ; do local v=${arg#*=} case ${arg} in -h|--help) usage ;; + -k|--keep) keep=true ;; -q|--quiet) PORTAGE_QUIET=1 ;; -v|--verbose) do_verbose=1 ;; -x|--debug) do_debug=1 ;; @@ -443,16 +476,39 @@ main() { esac done + [[ -d ${repo_location} ]] || mkdir -p "${repo_location}" + if [[ ! -w ${repo_location} ]] ; then + eecho "Repository '${repo_name}' is not writable: ${repo_location}" + exit 1 + fi + + [[ -d ${PORTAGE_TMPDIR}/portage ]] || mkdir -p "${PORTAGE_TMPDIR}/portage" + TMPDIR=$(mktemp -d "${PORTAGE_TMPDIR}/portage/webrsync-XXXXXX") + if [[ ! -w ${TMPDIR} ]] ; then + eecho "TMPDIR is not writable: ${TMPDIR}" + exit 1 + fi + trap 'cd / ; rm -rf "${TMPDIR}"' EXIT + cd "${TMPDIR}" || exit 1 + + ${keep} || DISTDIR=${TMPDIR} + [ ! -d "${DISTDIR}" ] && mkdir -p "${DISTDIR}" + + if ${keep} && [[ ! -w ${DISTDIR} ]] ; then + eecho "DISTDIR is not writable: ${DISTDIR}" + exit 1 + fi + # This is a sanity check to help prevent people like funtoo users # from accidentally wiping out their git tree. - if [[ -n $SYNC && ${SYNC#rsync:} = $SYNC ]] ; then - echo "The current SYNC variable setting does not refer to an rsync URI:" >&2 + if [[ -n ${repo_sync_type} && ${repo_sync_type} != rsync ]] ; then + echo "The current sync-type attribute of repository 'gentoo' is not set to 'rsync':" >&2 echo >&2 - echo " SYNC=$SYNC" >&2 + echo " sync-type=${repo_sync_type}" >&2 echo >&2 echo "If you intend to use emerge-webrsync then please" >&2 - echo "adjust SYNC to refer to an rsync URI." >&2 - echo "emerge-webrsync exiting due to abnormal SYNC setting." >&2 + echo "adjust sync-type and sync-uri attributes to refer to rsync." >&2 + echo "emerge-webrsync exiting due to abnormal sync-type setting." >&2 exit 1 fi diff --git a/portage_with_autodep/bin/env-update b/portage_with_autodep/bin/env-update index 8a69f2b..b500c54 100755 --- a/portage_with_autodep/bin/env-update +++ b/portage_with_autodep/bin/env-update @@ -1,5 +1,5 @@ #!/usr/bin/python -O -# Copyright 1999-2006 Gentoo Foundation +# Copyright 1999-2013 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 from __future__ import print_function @@ -25,12 +25,12 @@ if len(sys.argv) > 1: print("!!! Invalid command line options!\n") usage(1) -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 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 + try: portage.env_update(makelinks) except IOError as e: diff --git a/portage_with_autodep/bin/etc-update b/portage_with_autodep/bin/etc-update index 1edc91f..1a99231 100755 --- a/portage_with_autodep/bin/etc-update +++ b/portage_with_autodep/bin/etc-update @@ -62,7 +62,7 @@ do_mv_ln() { } scan() { - echo "Scanning Configuration files..." + ${QUIET} || echo "Scanning Configuration files..." rm -rf "${TMP}"/files > /dev/null 2>&1 mkdir "${TMP}"/files || die "Failed mkdir command!" count=0 @@ -107,13 +107,13 @@ scan() { for mpath in ${CONFIG_PROTECT_MASK}; do mpath="${EROOT%/}${mpath}" if [[ "${rpath}" == "${mpath}"* ]] ; then - echo "Updating masked file: ${live_file}" + ${QUIET} || echo "Updating masked file: ${live_file}" mv "${cfg_file}" "${live_file}" continue 2 fi done if [[ ! -f ${file} ]] ; then - echo "Skipping non-file ${file} ..." + ${QUIET} || echo "Skipping non-file ${file} ..." continue fi @@ -140,7 +140,7 @@ scan() { fi if [[ ${MATCHES} == 1 ]] ; then - echo "Automerging trivial changes in: ${live_file}" + ${QUIET} || echo "Automerging trivial changes in: ${live_file}" do_mv_ln "${cfg_file}" "${live_file}" continue else @@ -190,6 +190,7 @@ parse_automode_flag() { parse_automode_flag -3 export mv_opts=" ${mv_opts} " mv_opts="${mv_opts// -i / }" + NONINTERACTIVE_MV=true ;; -3) input=0 @@ -547,9 +548,9 @@ die() { local msg=$1 exitcode=${2:-1} if [ ${exitcode} -eq 0 ] ; then - printf 'Exiting: %b\n' "${msg}" + ${QUIET} || printf 'Exiting: %b\n' "${msg}" scan > /dev/null - [ ${count} -gt 0 ] && echo "NOTE: ${count} updates remaining" + ! ${QUIET} && [ ${count} -gt 0 ] && echo "NOTE: ${count} updates remaining" else error "${msg}" fi @@ -574,6 +575,7 @@ usage() { -d, --debug Enable shell debugging -h, --help Show help and run away -p, --preen Automerge trivial changes only and quit + -q, --quiet Show only essential output -v, --verbose Show settings and such along the way -V, --version Show version and trundle away @@ -599,12 +601,15 @@ declare title="Gentoo's etc-update tool!" PREEN=false SET_X=false +QUIET=false VERBOSE=false +NONINTERACTIVE_MV=false while [[ -n $1 ]] ; do case $1 in -d|--debug) SET_X=true;; -h|--help) usage;; -p|--preen) PREEN=true;; + -q|--quiet) QUIET=true;; -v|--verbose) VERBOSE=true;; -V|--version) emerge --version; exit 0;; --automode) parse_automode_flag $2 && shift || usage 1 "Invalid mode '$2'";; @@ -615,7 +620,7 @@ while [[ -n $1 ]] ; do done ${SET_X} && set -x -type portageq >/dev/null || die "missing portageq" +type -P portageq >/dev/null || die "missing portageq" portage_vars=( CONFIG_PROTECT{,_MASK} PORTAGE_CONFIGROOT @@ -625,7 +630,7 @@ portage_vars=( USERLAND NOCOLOR ) -eval $(portageq envvar -v ${portage_vars[@]}) +eval $(${PORTAGE_PYTHON:+"${PORTAGE_PYTHON}"} "$(type -P portageq)" envvar -v ${portage_vars[@]}) export PORTAGE_TMPDIR SCAN_PATHS=${*:-${CONFIG_PROTECT}} @@ -692,6 +697,11 @@ else fi fi +if ${NONINTERACTIVE_MV} ; then + export mv_opts=" ${mv_opts} " + mv_opts="${mv_opts// -i / }" +fi + if ${VERBOSE} ; then for v in ${portage_vars[@]} ${cfg_vars[@]} TMP SCAN_PATHS ; do echo "${v}=${!v}" diff --git a/portage_with_autodep/bin/filter-bash-environment.py b/portage_with_autodep/bin/filter-bash-environment.py index b9aec96..3d4b3ec 100755 --- a/portage_with_autodep/bin/filter-bash-environment.py +++ b/portage_with_autodep/bin/filter-bash-environment.py @@ -1,10 +1,9 @@ #!/usr/bin/python -# Copyright 1999-2011 Gentoo Foundation +# Copyright 1999-2013 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 import codecs import io -import optparse import os import re import sys @@ -126,10 +125,19 @@ if __name__ == "__main__": "intact. The PATTERN is a space separated list of variable names" + \ " and it supports python regular expression syntax." usage = "usage: %s PATTERN" % os.path.basename(sys.argv[0]) - parser = optparse.OptionParser(description=description, usage=usage) - options, args = parser.parse_args(sys.argv[1:]) + args = sys.argv[1:] + + if '-h' in args or '--help' in args: + sys.stdout.write(usage + "\n") + sys.stdout.flush() + sys.exit(os.EX_OK) + if len(args) != 1: - parser.error("Missing required PATTERN argument.") + sys.stderr.write(usage + "\n") + sys.stderr.write("Exactly one PATTERN argument required.\n") + sys.stderr.flush() + sys.exit(2) + file_in = sys.stdin file_out = sys.stdout if sys.hexversion >= 0x3000000: diff --git a/portage_with_autodep/bin/fixpackages b/portage_with_autodep/bin/fixpackages index dc43ed2..e29d6ee 100755 --- a/portage_with_autodep/bin/fixpackages +++ b/portage_with_autodep/bin/fixpackages @@ -1,5 +1,5 @@ #!/usr/bin/python -# Copyright 1999-2011 Gentoo Foundation +# Copyright 1999-2013 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 from __future__ import print_function @@ -7,21 +7,27 @@ from __future__ import print_function import os import sys -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 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.output import EOutput +from portage.util._argparse import ArgumentParser from textwrap import wrap from portage._global_updates import _global_updates mysettings = portage.settings mytrees = portage.db mtimedb = portage.mtimedb +description = """The fixpackages program performs package move updates on + configuration files, installed packages, and binary packages.""" +description = " ".join(description.split()) + +parser = ArgumentParser(description=description) +parser.parse_args() + if mysettings['ROOT'] != "/": out = EOutput() msg = "The fixpackages program is not intended for use with " + \ diff --git a/portage_with_autodep/bin/glsa-check b/portage_with_autodep/bin/glsa-check index a840c32..7fa3688 100755 --- a/portage_with_autodep/bin/glsa-check +++ b/portage_with_autodep/bin/glsa-check @@ -1,81 +1,79 @@ #!/usr/bin/python -# Copyright 2008-2011 Gentoo Foundation +# Copyright 2008-2013 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 from __future__ import print_function import sys +import codecs -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 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.output import * - -from optparse import OptionGroup, OptionParser +from portage.output import green, red, nocolor, white +from portage.util._argparse import ArgumentParser __program__ = "glsa-check" __author__ = "Marius Mauch <genone@gentoo.org>" __version__ = "1.0" -def cb_version(*args, **kwargs): - """Callback for --version""" - sys.stderr.write("\n"+ __program__ + ", version " + __version__ + "\n") - sys.stderr.write("Author: " + __author__ + "\n") - sys.stderr.write("This program is licensed under the GPL, version 2\n\n") - sys.exit(0) - # option parsing -parser = OptionParser(usage="%prog <option> [glsa-list]", - version="%prog "+ __version__) -parser.epilog = "glsa-list can contain an arbitrary number of GLSA ids," \ +epilog = "glsa-list can contain an arbitrary number of GLSA ids," \ " filenames containing GLSAs or the special identifiers" \ " 'all', 'new' and 'affected'" +parser = ArgumentParser(usage=__program__ + " <option> [glsa-list]", + epilog=epilog) -modes = OptionGroup(parser, "Modes") -modes.add_option("-l", "--list", action="store_const", +modes = parser.add_argument_group("Modes") +modes.add_argument("-l", "--list", action="store_const", const="list", dest="mode", help="List all unapplied GLSA") -modes.add_option("-d", "--dump", action="store_const", +modes.add_argument("-d", "--dump", action="store_const", const="dump", dest="mode", help="Show all information about the given GLSA") -modes.add_option("", "--print", action="store_const", +modes.add_argument("--print", action="store_const", const="dump", dest="mode", help="Alias for --dump") -modes.add_option("-t", "--test", action="store_const", +modes.add_argument("-t", "--test", action="store_const", const="test", dest="mode", help="Test if this system is affected by the given GLSA") -modes.add_option("-p", "--pretend", action="store_const", +modes.add_argument("-p", "--pretend", action="store_const", const="pretend", dest="mode", help="Show the necessary commands to apply this GLSA") -modes.add_option("-f", "--fix", action="store_const", +modes.add_argument("-f", "--fix", action="store_const", const="fix", dest="mode", help="Try to auto-apply this GLSA (experimental)") -modes.add_option("-i", "--inject", action="store_const", dest="mode", - help="Inject the given GLSA into the checkfile") -modes.add_option("-m", "--mail", action="store_const", +modes.add_argument("-i", "--inject", action="store_const", + const="inject", dest="mode", + help="inject the given GLSA into the glsa_injected file") +modes.add_argument("-m", "--mail", action="store_const", const="mail", dest="mode", help="Send a mail with the given GLSAs to the administrator") -parser.add_option_group(modes) -parser.remove_option("--version") -parser.add_option("-V", "--version", action="callback", - callback=cb_version, help="Some information about this tool") -parser.add_option("-v", "--verbose", action="store_true", dest="verbose", +parser.add_argument("-V", "--version", action="store_true", + help="Some information about this tool") +parser.add_argument("-v", "--verbose", action="store_true", dest="verbose", help="Print more information") -parser.add_option("-n", "--nocolor", action="callback", - callback=lambda *args, **kwargs: nocolor(), +parser.add_argument("-n", "--nocolor", action="store_true", help="Disable colors") -parser.add_option("-e", "--emergelike", action="store_false", dest="least_change", +parser.add_argument("-e", "--emergelike", action="store_false", dest="least_change", help="Do not use a least-change algorithm") -parser.add_option("-c", "--cve", action="store_true", dest="list_cve", +parser.add_argument("-c", "--cve", action="store_true", dest="list_cve", help="Show CAN ids in listing mode") -options, params = parser.parse_args() +options, params = parser.parse_known_args() + +if options.nocolor: + nocolor() + +if options.version: + sys.stderr.write("\n"+ __program__ + ", version " + __version__ + "\n") + sys.stderr.write("Author: " + __author__ + "\n") + sys.stderr.write("This program is licensed under the GPL, version 2\n\n") + sys.exit(0) mode = options.mode least_change = options.least_change @@ -101,7 +99,8 @@ elif mode == "list" and not params: params.append("new") # delay this for speed increase -from portage.glsa import * +from portage.glsa import (Glsa, GlsaTypeException, GlsaFormatException, + get_applied_glsas, get_glsa_list) eroot = portage.settings['EROOT'] vardb = portage.db[eroot]["vartree"].dbapi @@ -117,7 +116,7 @@ glsalist = [] if "new" in params: glsalist = todolist params.remove("new") - + if "all" in params: glsalist = completelist params.remove("all") @@ -142,8 +141,17 @@ for p in params[:]: glsalist.extend([g for g in params if g not in glsalist]) -def summarylist(myglsalist, fd1=sys.stdout, fd2=sys.stderr): - fd2.write(white("[A]")+" means this GLSA was already applied,\n") +def summarylist(myglsalist, fd1=sys.stdout, fd2=sys.stderr, encoding="utf-8"): + # Get to the raw streams in py3k before wrapping them with an encoded writer + # to avoid writing bytes to a text stream (stdout/stderr are text streams + # by default in py3k) + if hasattr(fd1, "buffer"): + fd1 = fd1.buffer + if hasattr(fd2, "buffer"): + fd2 = fd2.buffer + fd1 = codecs.getwriter(encoding)(fd1) + fd2 = codecs.getwriter(encoding)(fd2) + fd2.write(white("[A]")+" means this GLSA was marked as applied (injected),\n") fd2.write(green("[U]")+" means the system is not affected and\n") fd2.write(red("[N]")+" indicates that the system might be affected.\n\n") @@ -155,7 +163,7 @@ def summarylist(myglsalist, fd1=sys.stdout, fd2=sys.stderr): if verbose: fd2.write(("invalid GLSA: %s (error message was: %s)\n" % (myid, e))) continue - if myglsa.isApplied(): + if myglsa.isInjected(): status = "[A]" color = white elif myglsa.isVulnerable(): @@ -186,7 +194,7 @@ def summarylist(myglsalist, fd1=sys.stdout, fd2=sys.stderr): fd1.write(")") if list_cve: fd1.write(" "+(",".join([r[:13] for r in myglsa.references if r[:4] in ["CAN-", "CVE-"]]))) - fd1.write("\n") + fd1.write("\n") return 0 if mode == "list": @@ -204,39 +212,46 @@ if mode in ["dump", "fix", "inject", "pretend"]: if mode == "dump": myglsa.dump() elif mode == "fix": - sys.stdout.write("fixing "+myid+"\n") - mergelist = myglsa.getMergeList(least_change=least_change) - for pkg in mergelist: - sys.stdout.write(">>> merging "+pkg+"\n") - # using emerge for the actual merging as it contains the dependency - # code and we want to be consistent in behaviour. Also this functionality - # will be integrated in emerge later, so it shouldn't hurt much. - emergecmd = "emerge --oneshot " + portage.settings["EMERGE_OPTS"] + " =" + pkg - if verbose: - sys.stderr.write(emergecmd+"\n") - exitcode = os.system(emergecmd) - # system() returns the exitcode in the high byte of a 16bit integer - if exitcode >= 1<<8: - exitcode >>= 8 - if exitcode: - sys.exit(exitcode) - myglsa.inject() + sys.stdout.write("Fixing GLSA "+myid+"\n") + if not myglsa.isVulnerable(): + sys.stdout.write(">>> no vulnerable packages installed\n") + else: + mergelist = myglsa.getMergeList(least_change=least_change) + if mergelist == []: + sys.stdout.write(">>> cannot fix GLSA, no unaffected packages available\n") + sys.exit(2) + for pkg in mergelist: + sys.stdout.write(">>> merging "+pkg+"\n") + # using emerge for the actual merging as it contains the dependency + # code and we want to be consistent in behaviour. Also this functionality + # will be integrated in emerge later, so it shouldn't hurt much. + emergecmd = "emerge --oneshot " + " =" + pkg + if verbose: + sys.stderr.write(emergecmd+"\n") + exitcode = os.system(emergecmd) + # system() returns the exitcode in the high byte of a 16bit integer + if exitcode >= 1<<8: + exitcode >>= 8 + if exitcode: + sys.exit(exitcode) + if len(mergelist): + sys.stdout.write("\n") elif mode == "pretend": sys.stdout.write("Checking GLSA "+myid+"\n") - mergelist = myglsa.getMergeList(least_change=least_change) - if mergelist: - sys.stdout.write("The following updates will be performed for this GLSA:\n") - for pkg in mergelist: - oldver = None - for x in vardb.match(portage.cpv_getkey(pkg)): - if vardb.aux_get(x, ["SLOT"]) == portdb.aux_get(pkg, ["SLOT"]): - oldver = x - if oldver == None: - raise ValueError("could not find old version for package %s" % pkg) - oldver = oldver[len(portage.cpv_getkey(oldver))+1:] - sys.stdout.write(" " + pkg + " (" + oldver + ")\n") + if not myglsa.isVulnerable(): + sys.stdout.write(">>> no vulnerable packages installed\n") else: - sys.stdout.write("Nothing to do for this GLSA\n") + mergedict = {} + for (vuln, update) in myglsa.getAffectionTable(least_change=least_change): + mergedict.setdefault(update, []).append(vuln) + + sys.stdout.write(">>> The following updates will be performed for this GLSA:\n") + for pkg in mergedict: + if pkg != "": + sys.stdout.write(" " + pkg + " (vulnerable: " + ", ".join(mergedict[pkg]) + ")\n") + if "" in mergedict: + sys.stdout.write("\n>>> For the following packages, no upgrade path exists:\n") + sys.stdout.write(" " + ", ".join(mergedict[""])) elif mode == "inject": sys.stdout.write("injecting " + myid + "\n") myglsa.inject() @@ -268,9 +283,9 @@ if mode == "test": # mail mode as requested by solar if mode == "mail": import portage.mail, socket - from io import StringIO + from io import BytesIO from email.mime.text import MIMEText - + # color doesn't make any sense for mail nocolor() @@ -278,7 +293,7 @@ if mode == "mail": myrecipient = portage.settings["PORTAGE_ELOG_MAILURI"].split()[0] else: myrecipient = "root@localhost" - + if "PORTAGE_ELOG_MAILFROM" in portage.settings: myfrom = portage.settings["PORTAGE_ELOG_MAILFROM"] else: @@ -287,11 +302,13 @@ if mode == "mail": mysubject = "[glsa-check] Summary for %s" % socket.getfqdn() # need a file object for summarylist() - myfd = StringIO() - myfd.write("GLSA Summary report for host %s\n" % socket.getfqdn()) - myfd.write("(Command was: %s)\n\n" % " ".join(sys.argv)) + myfd = BytesIO() + line = "GLSA Summary report for host %s\n" % socket.getfqdn() + myfd.write(line.encode("utf-8")) + line = "(Command was: %s)\n\n" % " ".join(sys.argv) + myfd.write(line.encode("utf-8")) summarylist(glsalist, fd1=myfd, fd2=myfd) - summary = str(myfd.getvalue()) + summary = myfd.getvalue().decode("utf-8") myfd.close() myattachments = [] @@ -302,16 +319,17 @@ if mode == "mail": if verbose: sys.stderr.write(("invalid GLSA: %s (error message was: %s)\n" % (myid, e))) continue - myfd = StringIO() + myfd = BytesIO() myglsa.dump(outstream=myfd) - myattachments.append(MIMEText(str(myfd.getvalue()), _charset="utf8")) + attachment = myfd.getvalue().decode("utf-8") + myattachments.append(MIMEText(attachment, _charset="utf8")) myfd.close() - + mymessage = portage.mail.create_message(myfrom, myrecipient, mysubject, summary, myattachments) portage.mail.send_mail(portage.settings, mymessage) - + sys.exit(0) - + # something wrong here, all valid paths are covered with sys.exit() sys.stderr.write("nothing more to do\n") sys.exit(2) diff --git a/portage_with_autodep/bin/helper-functions.sh b/portage_with_autodep/bin/helper-functions.sh index afe14af..b9bc74a 100755 --- a/portage_with_autodep/bin/helper-functions.sh +++ b/portage_with_autodep/bin/helper-functions.sh @@ -10,42 +10,45 @@ source "${PORTAGE_BIN_PATH:-/usr/lib/portage/bin}"/isolated-functions.sh # # API functions for doing parallel processing # -numjobs() { +makeopts_jobs() { # Copied from eutils.eclass:makeopts_jobs() local jobs=$(echo " ${MAKEOPTS} " | \ sed -r -n 's:.*[[:space:]](-j|--jobs[=[:space:]])[[:space:]]*([0-9]+).*:\2:p') echo ${jobs:-1} } -multijob_init() { +__multijob_init() { # Setup a pipe for children to write their pids to when they finish. - mj_control_pipe=$(mktemp -t multijob.XXXXXX) - rm "${mj_control_pipe}" - mkfifo "${mj_control_pipe}" - exec {mj_control_fd}<>${mj_control_pipe} - rm -f "${mj_control_pipe}" + # We have to allocate two fd's because POSIX has undefined behavior + # when you open a FIFO for simultaneous read/write. #487056 + local pipe=$(mktemp -t multijob.XXXXXX) + rm -f "${pipe}" + mkfifo -m 600 "${pipe}" + __redirect_alloc_fd mj_write_fd "${pipe}" + __redirect_alloc_fd mj_read_fd "${pipe}" + rm -f "${pipe}" # See how many children we can fork based on the user's settings. - mj_max_jobs=$(numjobs) + mj_max_jobs=$(makeopts_jobs "$@") mj_num_jobs=0 } -multijob_child_init() { - trap 'echo ${BASHPID} $? >&'${mj_control_fd} EXIT +__multijob_child_init() { + trap 'echo ${BASHPID:-$(__bashpid)} $? >&'${mj_write_fd} EXIT trap 'exit 1' INT TERM } -multijob_finish_one() { +__multijob_finish_one() { local pid ret - read -r -u ${mj_control_fd} pid ret + read -r -u ${mj_read_fd} pid ret : $(( --mj_num_jobs )) return ${ret} } -multijob_finish() { +__multijob_finish() { local ret=0 while [[ ${mj_num_jobs} -gt 0 ]] ; do - multijob_finish_one + __multijob_finish_one : $(( ret |= $? )) done # Let bash clean up its internal child tracking state. @@ -53,10 +56,42 @@ multijob_finish() { return ${ret} } -multijob_post_fork() { +__multijob_post_fork() { : $(( ++mj_num_jobs )) if [[ ${mj_num_jobs} -ge ${mj_max_jobs} ]] ; then - multijob_finish_one + __multijob_finish_one fi return $? } + +# @FUNCTION: __redirect_alloc_fd +# @USAGE: <var> <file> [redirection] +# @DESCRIPTION: +# Find a free fd and redirect the specified file via it. Store the new +# fd in the specified variable. Useful for the cases where we don't care +# about the exact fd #. +__redirect_alloc_fd() { + local var=$1 file=$2 redir=${3:-"<>"} + + if [[ $(( (BASH_VERSINFO[0] << 8) + BASH_VERSINFO[1] )) -ge $(( (4 << 8) + 1 )) ]] ; then + # Newer bash provides this functionality. + eval "exec {${var}}${redir}'${file}'" + else + # Need to provide the functionality ourselves. + local fd=10 + local fddir=/dev/fd + # Prefer /proc/self/fd if available (/dev/fd + # doesn't work on solaris, see bug #474536). + [[ -d /proc/self/fd ]] && fddir=/proc/self/fd + while :; do + # Make sure the fd isn't open. It could be a char device, + # or a symlink (possibly broken) to something else. + if [[ ! -e ${fddir}/${fd} ]] && [[ ! -L ${fddir}/${fd} ]] ; then + eval "exec ${fd}${redir}'${file}'" && break + fi + [[ ${fd} -gt 1024 ]] && die 'could not locate a free temp fd !?' + : $(( ++fd )) + done + : $(( ${var} = fd )) + fi +} diff --git a/portage_with_autodep/bin/isolated-functions.sh b/portage_with_autodep/bin/isolated-functions.sh index dbf988b..b99aec7 100755 --- a/portage_with_autodep/bin/isolated-functions.sh +++ b/portage_with_autodep/bin/isolated-functions.sh @@ -1,7 +1,9 @@ #!/bin/bash -# Copyright 1999-2011 Gentoo Foundation +# Copyright 1999-2013 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 +source "${PORTAGE_BIN_PATH:-/usr/lib/portage/bin}/eapi.sh" + # We need this next line for "die" and "assert". It expands # It _must_ preceed all the calls to die and assert. shopt -s expand_aliases @@ -15,7 +17,7 @@ assert() { done } -assert_sigpipe_ok() { +__assert_sigpipe_ok() { # When extracting a tar file like this: # # bzip2 -dc foo.tar.bz2 | tar xof - @@ -43,21 +45,21 @@ assert_sigpipe_ok() { shopt -s extdebug -# dump_trace([number of funcs on stack to skip], +# __dump_trace([number of funcs on stack to skip], # [whitespacing for filenames], # [whitespacing for line numbers]) -dump_trace() { +__dump_trace() { local funcname="" sourcefile="" lineno="" s="yes" n p declare -i strip=${1:-1} local filespacing=$2 linespacing=$3 - # The qa_call() function and anything before it are portage internals + # The __qa_call() function and anything before it are portage internals # that the user will not be interested in. Therefore, the stack trace - # should only show calls that come after qa_call(). + # should only show calls that come after __qa_call(). (( n = ${#FUNCNAME[@]} - 1 )) (( p = ${#BASH_ARGV[@]} )) while (( n > 0 )) ; do - [ "${FUNCNAME[${n}]}" == "qa_call" ] && break + [ "${FUNCNAME[${n}]}" == "__qa_call" ] && break (( p -= ${BASH_ARGC[${n}]} )) (( n-- )) done @@ -86,7 +88,7 @@ dump_trace() { } nonfatal() { - if has "${EAPI:-0}" 0 1 2 3 3_pre2 ; then + if ! ___eapi_has_nonfatal; then die "$FUNCNAME() not supported in this EAPI" fi if [[ $# -lt 1 ]]; then @@ -96,18 +98,24 @@ nonfatal() { PORTAGE_NONFATAL=1 "$@" } -helpers_die() { - case "${EAPI:-0}" in - 0|1|2|3) - echo -e "$@" >&2 - ;; - *) - die "$@" - ;; - esac +__bashpid() { + # The BASHPID variable is new to bash-4.0, so add a hack for older + # versions. This must be used like so: + # ${BASHPID:-$(__bashpid)} + sh -c 'echo ${PPID}' +} + +__helpers_die() { + if ___eapi_helpers_can_die; then + die "$@" + else + echo -e "$@" >&2 + fi } die() { + local IFS=$' \t\n' + if [[ $PORTAGE_NONFATAL -eq 1 ]]; then echo -e " $WARN*$NORMAL ${FUNCNAME[1]}: WARNING: $@" >&2 return 1 @@ -124,7 +132,7 @@ die() { # setup spacing to make output easier to read (( n = ${#FUNCNAME[@]} - 1 )) while (( n > 0 )) ; do - [ "${FUNCNAME[${n}]}" == "qa_call" ] && break + [ "${FUNCNAME[${n}]}" == "__qa_call" ] && break (( n-- )) done (( n == 0 )) && (( n = ${#FUNCNAME[@]} - 1 )) @@ -140,14 +148,14 @@ die() { # get a stack trace, so at least report the phase that failed. local phase_str= [[ -n $EBUILD_PHASE ]] && phase_str=" ($EBUILD_PHASE phase)" - eerror "ERROR: $CATEGORY/$PF failed${phase_str}:" + eerror "ERROR: ${CATEGORY}/${PF}::${PORTAGE_REPO_NAME} failed${phase_str}:" eerror " ${*:-(no error message)}" eerror - # dump_trace is useless when the main script is a helper binary + # __dump_trace is useless when the main script is a helper binary local main_index (( main_index = ${#BASH_SOURCE[@]} - 1 )) if has ${BASH_SOURCE[$main_index]##*/} ebuild.sh misc-functions.sh ; then - dump_trace 2 ${filespacing} ${linespacing} + __dump_trace 2 ${filespacing} ${linespacing} eerror " $(printf "%${filespacing}s" "${BASH_SOURCE[1]##*/}"), line $(printf "%${linespacing}s" "${BASH_LINENO[0]}"): Called die" eerror "The specific snippet of code:" # This scans the file that called die and prints out the logic that @@ -173,39 +181,12 @@ die() { | while read -r n ; do eerror " ${n#RETAIN-LEADING-SPACE}" ; done eerror fi - eerror "If you need support, post the output of \`emerge --info '=$CATEGORY/$PF'\`," - eerror "the complete build log and the output of \`emerge -pqv '=$CATEGORY/$PF'\`." - if [[ -n ${EBUILD_OVERLAY_ECLASSES} ]] ; then - eerror "This ebuild used the following eclasses from overlays:" - local x - for x in ${EBUILD_OVERLAY_ECLASSES} ; do - eerror " ${x}" - done - fi - if [ "${EMERGE_FROM}" != "binary" ] && \ - ! has ${EBUILD_PHASE} prerm postrm && \ - [ "${EBUILD#${PORTDIR}/}" == "${EBUILD}" ] ; then - local overlay=${EBUILD%/*} - overlay=${overlay%/*} - overlay=${overlay%/*} - if [[ -n $PORTAGE_REPO_NAME ]] ; then - eerror "This ebuild is from an overlay named" \ - "'$PORTAGE_REPO_NAME': '${overlay}/'" - else - eerror "This ebuild is from an overlay: '${overlay}/'" - fi - elif [[ -n $PORTAGE_REPO_NAME && -f "$PORTDIR"/profiles/repo_name ]] ; then - local portdir_repo_name=$(<"$PORTDIR"/profiles/repo_name) - if [[ -n $portdir_repo_name && \ - $portdir_repo_name != $PORTAGE_REPO_NAME ]] ; then - eerror "This ebuild is from a repository" \ - "named '$PORTAGE_REPO_NAME'" - fi - fi + eerror "If you need support, post the output of \`emerge --info '=${CATEGORY}/${PF}::${PORTAGE_REPO_NAME}'\`," + eerror "the complete build log and the output of \`emerge -pqv '=${CATEGORY}/${PF}::${PORTAGE_REPO_NAME}'\`." # Only call die hooks here if we are executed via ebuild.sh or # misc-functions.sh, since those are the only cases where the environment - # contains the hook functions. When necessary (like for helpers_die), die + # contains the hook functions. When necessary (like for __helpers_die), die # hooks are automatically called later by a misc-functions.sh invocation. if has ${BASH_SOURCE[$main_index]##*/} ebuild.sh misc-functions.sh && \ [[ ${EBUILD_PHASE} != depend ]] ; then @@ -218,7 +199,8 @@ die() { if [[ -n ${PORTAGE_LOG_FILE} ]] ; then eerror "The complete build log is located at '${PORTAGE_LOG_FILE}'." - if [[ ${PORTAGE_LOG_FILE} != ${T}/* ]] ; then + if [[ ${PORTAGE_LOG_FILE} != ${T}/* ]] && \ + ! has fail-clean ${FEATURES} ; then # Display path to symlink in ${T}, as requested in bug #412865. local log_ext=log [[ ${PORTAGE_LOG_FILE} != *.log ]] && log_ext+=.${PORTAGE_LOG_FILE##*.} @@ -241,26 +223,20 @@ die() { [[ -n $PORTAGE_IPC_DAEMON ]] && "$PORTAGE_BIN_PATH"/ebuild-ipc exit 1 # subshell die support - [[ $BASHPID = $EBUILD_MASTER_PID ]] || kill -s SIGTERM $EBUILD_MASTER_PID + [[ ${BASHPID:-$(__bashpid)} == ${EBUILD_MASTER_PID} ]] || kill -s SIGTERM ${EBUILD_MASTER_PID} exit 1 } -# We need to implement diefunc() since environment.bz2 files contain -# calls to it (due to alias expansion). -diefunc() { - die "${@}" -} - -quiet_mode() { +__quiet_mode() { [[ ${PORTAGE_QUIET} -eq 1 ]] } -vecho() { - quiet_mode || echo "$@" +__vecho() { + __quiet_mode || echo "$@" } # Internal logging function, don't use this in ebuilds -elog_base() { +__elog_base() { local messagetype [ -z "${1}" -o -z "${T}" -o ! -d "${T}/logging" ] && return 1 case "${1}" in @@ -269,7 +245,7 @@ elog_base() { shift ;; *) - vecho -e " ${BAD}*${NORMAL} Invalid use of internal function elog_base(), next message will not be logged" + __vecho -e " ${BAD}*${NORMAL} Invalid use of internal function __elog_base(), next message will not be logged" return 1 ;; esac @@ -281,17 +257,17 @@ elog_base() { } eqawarn() { - elog_base QA "$*" + __elog_base QA "$*" [[ ${RC_ENDCOL} != "yes" && ${LAST_E_CMD} == "ebegin" ]] && echo echo -e "$@" | while read -r ; do - vecho " $WARN*$NORMAL $REPLY" >&2 + __vecho " $WARN*$NORMAL $REPLY" >&2 done LAST_E_CMD="eqawarn" return 0 } elog() { - elog_base LOG "$*" + __elog_base LOG "$*" [[ ${RC_ENDCOL} != "yes" && ${LAST_E_CMD} == "ebegin" ]] && echo echo -e "$@" | while read -r ; do echo " $GOOD*$NORMAL $REPLY" @@ -300,26 +276,8 @@ elog() { return 0 } -esyslog() { - local pri= - local tag= - - if [ -x /usr/bin/logger ] - then - pri="$1" - tag="$2" - - shift 2 - [ -z "$*" ] && return 0 - - /usr/bin/logger -p "${pri}" -t "${tag}" -- "$*" - fi - - return 0 -} - einfo() { - elog_base INFO "$*" + __elog_base INFO "$*" [[ ${RC_ENDCOL} != "yes" && ${LAST_E_CMD} == "ebegin" ]] && echo echo -e "$@" | while read -r ; do echo " $GOOD*$NORMAL $REPLY" @@ -329,7 +287,7 @@ einfo() { } einfon() { - elog_base INFO "$*" + __elog_base INFO "$*" [[ ${RC_ENDCOL} != "yes" && ${LAST_E_CMD} == "ebegin" ]] && echo echo -ne " ${GOOD}*${NORMAL} $*" LAST_E_CMD="einfon" @@ -337,7 +295,7 @@ einfon() { } ewarn() { - elog_base WARN "$*" + __elog_base WARN "$*" [[ ${RC_ENDCOL} != "yes" && ${LAST_E_CMD} == "ebegin" ]] && echo echo -e "$@" | while read -r ; do echo " $WARN*$NORMAL $RC_INDENTATION$REPLY" >&2 @@ -347,7 +305,7 @@ ewarn() { } eerror() { - elog_base ERROR "$*" + __elog_base ERROR "$*" [[ ${RC_ENDCOL} != "yes" && ${LAST_E_CMD} == "ebegin" ]] && echo echo -e "$@" | while read -r ; do echo " $BAD*$NORMAL $RC_INDENTATION$REPLY" >&2 @@ -372,7 +330,7 @@ ebegin() { return 0 } -_eend() { +__eend() { local retval=${1:-0} efunc=${2:-eerror} msg shift 2 @@ -399,13 +357,13 @@ eend() { local retval=${1:-0} shift - _eend ${retval} eerror "$*" + __eend ${retval} eerror "$*" LAST_E_CMD="eend" return ${retval} } -unset_colors() { +__unset_colors() { COLS=80 ENDCOL= @@ -417,7 +375,7 @@ unset_colors() { BRACKET= } -set_colors() { +__set_colors() { COLS=${COLUMNS:-0} # bash's internal COLUMNS variable # Avoid wasteful stty calls during the "depend" phases. # If stdout is a pipe, the parent process can export COLUMNS @@ -450,10 +408,10 @@ RC_DOT_PATTERN='' case "${NOCOLOR:-false}" in yes|true) - unset_colors + __unset_colors ;; no|false) - set_colors + __set_colors ;; esac @@ -504,4 +462,24 @@ has() { return 1 } +__repo_key() { + local appropriate_section=0 exit_status=1 line saved_extglob_shopt=$(shopt -p extglob) + shopt -s extglob + while read line; do + [[ ${appropriate_section} == 0 && ${line} == "[$1]" ]] && appropriate_section=1 && continue + [[ ${appropriate_section} == 1 && ${line} == "["*"]" ]] && appropriate_section=0 && continue + # If a conditional expression like [[ ${line} == $2*( )=* ]] is used + # then bash-3.2 produces an error like the following when the file is + # sourced: syntax error in conditional expression: unexpected token `(' + # Therefore, use a regular expression for compatibility. + if [[ ${appropriate_section} == 1 && ${line} =~ ^${2}[[:space:]]*= ]]; then + echo "${line##$2*( )=*( )}" + exit_status=0 + break + fi + done <<< "${PORTAGE_REPOSITORIES}" + eval "${saved_extglob_shopt}" + return ${exit_status} +} + true diff --git a/portage_with_autodep/bin/lock-helper.py b/portage_with_autodep/bin/lock-helper.py index dfb8876..128e4dd 100755 --- a/portage_with_autodep/bin/lock-helper.py +++ b/portage_with_autodep/bin/lock-helper.py @@ -1,11 +1,12 @@ #!/usr/bin/python -# Copyright 2010-2011 Gentoo Foundation +# Copyright 2010-2013 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 import os import sys sys.path.insert(0, os.environ['PORTAGE_PYM_PATH']) import portage +portage._internal_caller = True portage._disable_legacy_globals() def main(args): diff --git a/portage_with_autodep/bin/misc-functions.sh b/portage_with_autodep/bin/misc-functions.sh index 564af85..5ccf7c2 100755 --- a/portage_with_autodep/bin/misc-functions.sh +++ b/portage_with_autodep/bin/misc-functions.sh @@ -1,5 +1,5 @@ #!/bin/bash -# Copyright 1999-2011 Gentoo Foundation +# Copyright 1999-2013 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 # # Miscellaneous shell functions that make use of the ebuild env but don't need @@ -17,8 +17,9 @@ shift $# source "${PORTAGE_BIN_PATH:-/usr/lib/portage/bin}/ebuild.sh" install_symlink_html_docs() { - [[ " ${FEATURES} " == *" force-prefix "* ]] || \ - case "$EAPI" in 0|1|2) local ED=${D} ;; esac + if ! ___eapi_has_prefix_variables; then + local ED=${D} + fi cd "${ED}" || die "cd failed" #symlink the html documentation (if DOC_SYMLINKS_DIR is set in make.conf) if [ -n "${DOC_SYMLINKS_DIR}" ] ; then @@ -30,10 +31,10 @@ install_symlink_html_docs() { done if [ -n "${mydocdir}" ] ; then local mysympath - if [ -z "${SLOT}" -o "${SLOT}" = "0" ] ; then + if [ -z "${SLOT}" -o "${SLOT%/*}" = "0" ] ; then mysympath="${DOC_SYMLINKS_DIR}/${CATEGORY}/${PN}" else - mysympath="${DOC_SYMLINKS_DIR}/${CATEGORY}/${PN}-${SLOT}" + mysympath="${DOC_SYMLINKS_DIR}/${CATEGORY}/${PN}-${SLOT%/*}" fi einfo "Symlinking ${mysympath} to the HTML documentation" dodir "${DOC_SYMLINKS_DIR}/${CATEGORY}" @@ -43,7 +44,20 @@ install_symlink_html_docs() { } # replacement for "readlink -f" or "realpath" +READLINK_F_WORKS="" canonicalize() { + if [[ -z ${READLINK_F_WORKS} ]] ; then + if [[ $(readlink -f -- /../ 2>/dev/null) == "/" ]] ; then + READLINK_F_WORKS=true + else + READLINK_F_WORKS=false + fi + fi + if ${READLINK_F_WORKS} ; then + readlink -f -- "$@" + return + fi + local f=$1 b n=10 wd=$(pwd) while (( n-- > 0 )); do while [[ ${f: -1} = / && ${#f} -gt 1 ]]; do @@ -66,8 +80,9 @@ canonicalize() { prepcompress() { local -a include exclude incl_d incl_f local f g i real_f real_d - [[ " ${FEATURES} " == *" force-prefix "* ]] || \ - case "$EAPI" in 0|1|2) local ED=${D} ;; esac + if ! ___eapi_has_prefix_variables; then + local ED=${D} + fi # Canonicalize path names and check for their existence. real_d=$(canonicalize "${ED}") @@ -141,7 +156,7 @@ prepcompress() { # Queue up for compression. # ecompress{,dir} doesn't like to be called with empty argument lists. - [[ ${#incl_d[@]} -gt 0 ]] && ecompressdir --queue "${incl_d[@]}" + [[ ${#incl_d[@]} -gt 0 ]] && ecompressdir --limit ${PORTAGE_DOCOMPRESS_SIZE_LIMIT:-0} --queue "${incl_d[@]}" [[ ${#incl_f[@]} -gt 0 ]] && ecompress --queue "${incl_f[@]/#/${ED}}" [[ ${#exclude[@]} -gt 0 ]] && ecompressdir --ignore "${exclude[@]}" return 0 @@ -149,13 +164,12 @@ prepcompress() { install_qa_check() { local f i qa_var x - [[ " ${FEATURES} " == *" force-prefix "* ]] || \ - case "$EAPI" in 0|1|2) local EPREFIX= ED=${D} ;; esac + if ! ___eapi_has_prefix_variables; then + local EPREFIX= ED=${D} + fi cd "${ED}" || die "cd failed" - # Merge QA_FLAGS_IGNORED and QA_DT_HASH into a single array, since - # QA_DT_HASH is deprecated. qa_var="QA_FLAGS_IGNORED_${ARCH/-/_}" eval "[[ -n \${!qa_var} ]] && QA_FLAGS_IGNORED=(\"\${${qa_var}[@]}\")" if [[ ${#QA_FLAGS_IGNORED[@]} -eq 1 ]] ; then @@ -166,29 +180,6 @@ install_qa_check() { set -${shopts} fi - qa_var="QA_DT_HASH_${ARCH/-/_}" - eval "[[ -n \${!qa_var} ]] && QA_DT_HASH=(\"\${${qa_var}[@]}\")" - if [[ ${#QA_DT_HASH[@]} -eq 1 ]] ; then - local shopts=$- - set -o noglob - QA_DT_HASH=(${QA_DT_HASH}) - set +o noglob - set -${shopts} - fi - - if [[ -n ${QA_DT_HASH} ]] ; then - QA_FLAGS_IGNORED=("${QA_FLAGS_IGNORED[@]}" "${QA_DT_HASH[@]}") - unset QA_DT_HASH - fi - - # Merge QA_STRICT_FLAGS_IGNORED and QA_STRICT_DT_HASH, since - # QA_STRICT_DT_HASH is deprecated - if [ "${QA_STRICT_FLAGS_IGNORED-unset}" = unset ] && \ - [ "${QA_STRICT_DT_HASH-unset}" != unset ] ; then - QA_STRICT_FLAGS_IGNORED=1 - unset QA_STRICT_DT_HASH - fi - # Check for files built without respecting *FLAGS. Note that # -frecord-gcc-switches must be in all *FLAGS variables, in # order to avoid false positive results here. @@ -200,8 +191,7 @@ install_qa_check() { [[ "${FFLAGS}" == *-frecord-gcc-switches* ]] && \ [[ "${FCFLAGS}" == *-frecord-gcc-switches* ]] ; then rm -f "${T}"/scanelf-ignored-CFLAGS.log - for x in $(scanelf -qyRF '%k %p' -k \!.GCC.command.line "${ED}" | \ - sed -e "s:\!.GCC.command.line ::") ; do + for x in $(scanelf -qyRF '#k%p' -k '!.GCC.command.line' "${ED}") ; do # Separate out file types that are known to support # .GCC.command.line sections, using the `file` command # similar to how prepstrip uses it. @@ -226,11 +216,11 @@ install_qa_check() { -i "${T}"/scanelf-ignored-CFLAGS.log f=$(<"${T}"/scanelf-ignored-CFLAGS.log) if [[ -n ${f} ]] ; then - vecho -ne '\n' + __vecho -ne '\n' eqawarn "${BAD}QA Notice: Files built without respecting CFLAGS have been detected${NORMAL}" eqawarn " Please include the following list of files in your report:" eqawarn "${f}" - vecho -ne '\n' + __vecho -ne '\n' sleep 1 else rm -f "${T}"/scanelf-ignored-CFLAGS.log @@ -240,7 +230,7 @@ install_qa_check() { export STRIP_MASK prepall - has "${EAPI}" 0 1 2 3 || prepcompress + ___eapi_has_docompress && prepcompress ecompressdir --dequeue ecompress --dequeue @@ -251,32 +241,50 @@ install_qa_check() { for x in etc/app-defaults usr/man usr/info usr/X11R6 usr/doc usr/locale ; do [[ -d ${ED}/$x ]] && f+=" $x\n" done - if [[ -n $f ]] ; then eqawarn "QA Notice: This ebuild installs into the following deprecated directories:" eqawarn eqawarn "$f" fi - if [[ -d ${ED}/etc/udev/rules.d ]] ; then - f= - for x in $(ls "${ED}/etc/udev/rules.d") ; do - f+=" etc/udev/rules.d/$x\n" - done - if [[ -n $f ]] ; then - eqawarn "QA Notice: udev rules should be installed in /lib/udev/rules.d:" - eqawarn - eqawarn "$f" + # It's ok create these directories, but not to install into them. #493154 + # TODO: We should add var/lib to this list. + f= + for x in var/cache var/lock var/run run ; do + if [[ ! -L ${ED}/${x} && -d ${ED}/${x} ]] ; then + if [[ -z $(find "${ED}/${x}" -prune -empty) ]] ; then + f+=$(cd "${ED}"; find "${x}" -printf ' %p\n') + fi fi + done + if [[ -n ${f} ]] ; then + eqawarn "QA Notice: This ebuild installs into paths that should be created at runtime." + eqawarn " To fix, simply do not install into these directories. Instead, your package" + eqawarn " should create dirs on the fly at runtime as needed via init scripts/etc..." + eqawarn + eqawarn "${f}" + fi + + set +f + f= + for x in "${ED}etc/udev/rules.d/"* "${ED}lib"*"/udev/rules.d/"* ; do + [[ -e ${x} ]] || continue + [[ ${x} == ${ED}lib/udev/rules.d/* ]] && continue + f+=" ${x#${ED}}\n" + done + if [[ -n $f ]] ; then + eqawarn "QA Notice: udev rules should be installed in /lib/udev/rules.d:" + eqawarn + eqawarn "$f" fi # Now we look for all world writable files. local unsafe_files=$(find "${ED}" -type f -perm -2 | sed -e "s:^${ED}:- :") if [[ -n ${unsafe_files} ]] ; then - vecho "QA Security Notice: world writable file(s):" - vecho "${unsafe_files}" - vecho "- This may or may not be a security problem, most of the time it is one." - vecho "- Please double check that $PF really needs a world writeable bit and file bugs accordingly." + __vecho "QA Security Notice: world writable file(s):" + __vecho "${unsafe_files}" + __vecho "- This may or may not be a security problem, most of the time it is one." + __vecho "- Please double check that $PF really needs a world writeable bit and file bugs accordingly." sleep 1 fi @@ -307,7 +315,7 @@ install_qa_check() { for l in $(echo "${rpath_files}" | grep -E ":${dir}|::|: "); do f+=" ${l%%:*}\n" if ! has stricter ${FEATURES}; then - vecho "Auto fixing rpaths for ${l%%:*}" + __vecho "Auto fixing rpaths for ${l%%:*}" TMPDIR="${dir}" scanelf -BXr "${l%%:*}" -o /dev/null fi done @@ -321,12 +329,12 @@ install_qa_check() { # Print QA notice. if [[ -n ${f}${x} ]] ; then - vecho -ne '\n' + __vecho -ne '\n' eqawarn "QA Notice: The following files contain insecure RUNPATHs" eqawarn " Please file a bug about this at http://bugs.gentoo.org/" eqawarn " with the maintaining herd of the package." eqawarn "${f}${f:+${x:+\n}}${x}" - vecho -ne '\n' + __vecho -ne '\n' if [[ -n ${x} ]] || has stricter ${FEATURES} ; then insecure_rpath=1 fi @@ -344,7 +352,7 @@ install_qa_check() { f=$(scanelf -qyRF '%t %p' "${ED}" | grep -v 'usr/lib/debug/') if [[ -n ${f} ]] ; then scanelf -qyRAF '%T %p' "${PORTAGE_BUILDDIR}"/ &> "${T}"/scanelf-textrel.log - vecho -ne '\n' + __vecho -ne '\n' eqawarn "QA Notice: The following files contain runtime text relocations" eqawarn " Text relocations force the dynamic linker to perform extra" eqawarn " work at startup, waste system resources, and may pose a security" @@ -353,7 +361,7 @@ install_qa_check() { eqawarn " For more information, see http://hardened.gentoo.org/pic-fix-guide.xml" eqawarn " Please include the following list of files in your report:" eqawarn "${f}" - vecho -ne '\n' + __vecho -ne '\n' die_msg="${die_msg} textrels," sleep 1 fi @@ -364,7 +372,7 @@ install_qa_check() { *-linux-gnu*) # Check for files with executable stacks, but only on arches which # are supported at the moment. Keep this list in sync with - # http://hardened.gentoo.org/gnu-stack.xml (Arch Status) + # http://www.gentoo.org/proj/en/hardened/gnu-stack.xml (Arch Status) case ${CTARGET:-${CHOST}} in arm*|i?86*|ia64*|m68k*|s390*|sh*|x86_64*) # Allow devs to mark things as ignorable ... e.g. things @@ -389,7 +397,7 @@ install_qa_check() { if [[ -n ${f} ]] ; then # One more pass to help devs track down the source scanelf -qyRAF '%e %p' "${PORTAGE_BUILDDIR}"/ &> "${T}"/scanelf-execstack.log - vecho -ne '\n' + __vecho -ne '\n' eqawarn "QA Notice: The following files contain writable and executable sections" eqawarn " Files with such sections will not work properly (or at all!) on some" eqawarn " architectures/operating systems. A bug should be filed at" @@ -399,15 +407,15 @@ install_qa_check() { eqawarn " Note: Bugs should be filed for the respective maintainers" eqawarn " of the package in question and not hardened@g.o." eqawarn "${f}" - vecho -ne '\n' + __vecho -ne '\n' die_msg="${die_msg} execstacks" sleep 1 fi # Check for files built without respecting LDFLAGS if [[ "${LDFLAGS}" == *,--hash-style=gnu* ]] && \ - ! has binchecks ${RESTRICT} ; then - f=$(scanelf -qyRF '%k %p' -k .hash "${ED}" | sed -e "s:\.hash ::") + ! has binchecks ${RESTRICT} ; then + f=$(scanelf -qyRF '#k%p' -k .hash "${ED}") if [[ -n ${f} ]] ; then echo "${f}" > "${T}"/scanelf-ignored-LDFLAGS.log if [ "${QA_STRICT_FLAGS_IGNORED-unset}" = unset ] ; then @@ -421,11 +429,11 @@ install_qa_check() { -i "${T}"/scanelf-ignored-LDFLAGS.log f=$(<"${T}"/scanelf-ignored-LDFLAGS.log) if [[ -n ${f} ]] ; then - vecho -ne '\n' + __vecho -ne '\n' eqawarn "${BAD}QA Notice: Files built without respecting LDFLAGS have been detected${NORMAL}" eqawarn " Please include the following list of files in your report:" eqawarn "${f}" - vecho -ne '\n' + __vecho -ne '\n' sleep 1 else rm -f "${T}"/scanelf-ignored-LDFLAGS.log @@ -442,7 +450,7 @@ install_qa_check() { # Check for shared libraries lacking SONAMEs qa_var="QA_SONAME_${ARCH/-/_}" eval "[[ -n \${!qa_var} ]] && QA_SONAME=(\"\${${qa_var}[@]}\")" - f=$(scanelf -ByF '%S %p' "${ED}"{,usr/}lib*/lib*.so* | gawk '$2 == "" { print }' | sed -e "s:^[[:space:]]${ED}:/:") + f=$(scanelf -ByF '%S %p' "${ED}"{,usr/}lib*/lib*.so* | awk '$2 == "" { print }' | sed -e "s:^[[:space:]]${ED}:/:") if [[ -n ${f} ]] ; then echo "${f}" > "${T}"/scanelf-missing-SONAME.log if [[ "${QA_STRICT_SONAME-unset}" == unset ]] ; then @@ -463,10 +471,10 @@ install_qa_check() { sed -e "/^\$/d" -i "${T}"/scanelf-missing-SONAME.log f=$(<"${T}"/scanelf-missing-SONAME.log) if [[ -n ${f} ]] ; then - vecho -ne '\n' + __vecho -ne '\n' eqawarn "QA Notice: The following shared libraries lack a SONAME" eqawarn "${f}" - vecho -ne '\n' + __vecho -ne '\n' sleep 1 else rm -f "${T}"/scanelf-missing-SONAME.log @@ -476,7 +484,7 @@ install_qa_check() { # Check for shared libraries lacking NEEDED entries qa_var="QA_DT_NEEDED_${ARCH/-/_}" eval "[[ -n \${!qa_var} ]] && QA_DT_NEEDED=(\"\${${qa_var}[@]}\")" - f=$(scanelf -ByF '%n %p' "${ED}"{,usr/}lib*/lib*.so* | gawk '$2 == "" { print }' | sed -e "s:^[[:space:]]${ED}:/:") + f=$(scanelf -ByF '%n %p' "${ED}"{,usr/}lib*/lib*.so* | awk '$2 == "" { print }' | sed -e "s:^[[:space:]]${ED}:/:") if [[ -n ${f} ]] ; then echo "${f}" > "${T}"/scanelf-missing-NEEDED.log if [[ "${QA_STRICT_DT_NEEDED-unset}" == unset ]] ; then @@ -497,10 +505,10 @@ install_qa_check() { sed -e "/^\$/d" -i "${T}"/scanelf-missing-NEEDED.log f=$(<"${T}"/scanelf-missing-NEEDED.log) if [[ -n ${f} ]] ; then - vecho -ne '\n' + __vecho -ne '\n' eqawarn "QA Notice: The following shared libraries lack NEEDED entries" eqawarn "${f}" - vecho -ne '\n' + __vecho -ne '\n' sleep 1 else rm -f "${T}"/scanelf-missing-NEEDED.log @@ -545,14 +553,13 @@ install_qa_check() { die "Unsafe files found in \${D}. Portage will not install them." fi - if [[ -d ${D}/${D} ]] ; then - declare -i INSTALLTOD=0 - for i in $(find "${D}/${D}/"); do - eqawarn "QA Notice: /${i##${D}/${D}} installed in \${D}/\${D}" + if [[ -d ${D%/}${D} ]] ; then + local -i INSTALLTOD=0 + while read -r -d $'\0' i ; do + eqawarn "QA Notice: /${i##${D%/}${D}} installed in \${D}/\${D}" ((INSTALLTOD++)) - done - die "Aborting due to QA concerns: ${INSTALLTOD} files installed in ${D}/${D}" - unset INSTALLTOD + done < <(find "${D%/}${D}" -print0) + die "Aborting due to QA concerns: ${INSTALLTOD} files installed in ${D%/}${D}" fi # Sanity check syntax errors in init.d scripts @@ -563,10 +570,31 @@ install_qa_check() { [[ -L ${i} ]] && continue # if empty conf.d/init.d dir exists (baselayout), then i will be "/etc/conf.d/*" and not exist [[ ! -e ${i} ]] && continue + if [[ ${d} == /etc/init.d && ${i} != *.sh ]] ; then + # skip non-shell-script for bug #451386 + [[ $(head -n1 "${i}") =~ ^#!.*[[:space:]/](runscript|sh)$ ]] || continue + fi bash -n "${i}" || die "The init.d file has syntax errors: ${i}" done done + local checkbashisms=$(type -P checkbashisms) + if [[ -n ${checkbashisms} ]] ; then + for d in /etc/init.d ; do + [[ -d ${ED}${d} ]] || continue + for i in "${ED}${d}"/* ; do + [[ -e ${i} ]] || continue + [[ -L ${i} ]] && continue + f=$("${checkbashisms}" -f "${i}" 2>&1) + [[ $? != 0 && -n ${f} ]] || continue + eqawarn "QA Notice: shell script appears to use non-POSIX feature(s):" + while read -r ; + do eqawarn " ${REPLY}" + done <<< "${f//${ED}}" + done + done + fi + # Look for leaking LDFLAGS into pkg-config files f=$(egrep -sH '^Libs.*-Wl,(-O[012]|--hash-style)' "${ED}"/usr/*/pkgconfig/*.pc) if [[ -n ${f} ]] ; then @@ -577,17 +605,16 @@ install_qa_check() { # this should help to ensure that all (most?) shared libraries are executable # and that all libtool scripts / static libraries are not executable local j - for i in "${ED}"opt/*/lib{,32,64} \ - "${ED}"lib{,32,64} \ - "${ED}"usr/lib{,32,64} \ - "${ED}"usr/X11R6/lib{,32,64} ; do + for i in "${ED}"opt/*/lib* \ + "${ED}"lib* \ + "${ED}"usr/lib* ; do [[ ! -d ${i} ]] && continue for j in "${i}"/*.so.* "${i}"/*.so ; do [[ ! -e ${j} ]] && continue [[ -L ${j} ]] && continue [[ -x ${j} ]] && continue - vecho "making executable: ${j#${ED}}" + __vecho "making executable: ${j#${ED}}" chmod +x "${j}" done @@ -595,7 +622,7 @@ install_qa_check() { [[ ! -e ${j} ]] && continue [[ -L ${j} ]] && continue [[ ! -x ${j} ]] && continue - vecho "removing executable bit: ${j#${ED}}" + __vecho "removing executable bit: ${j#${ED}}" chmod -x "${j}" done @@ -604,7 +631,7 @@ install_qa_check() { [[ ! -L ${j} ]] && continue linkdest=$(readlink "${j}") if [[ ${linkdest} == /* ]] ; then - vecho -ne '\n' + __vecho -ne '\n' eqawarn "QA Notice: Found an absolute symlink in a library directory:" eqawarn " ${j#${D}} -> ${linkdest}" eqawarn " It should be a relative symlink if in the same directory" @@ -613,8 +640,8 @@ install_qa_check() { done done - # When installing static libraries into /usr/lib and shared libraries into - # /lib, we have to make sure we have a linker script in /usr/lib along side + # When installing static libraries into /usr/lib and shared libraries into + # /lib, we have to make sure we have a linker script in /usr/lib along side # the static library, or gcc will utilize the static lib when linking :(. # http://bugs.gentoo.org/4411 abort="no" @@ -624,7 +651,7 @@ install_qa_check() { if [[ ! -e ${s} ]] ; then s=${s%usr/*}${s##*/usr/} if [[ -e ${s} ]] ; then - vecho -ne '\n' + __vecho -ne '\n' eqawarn "QA Notice: Missing gen_usr_ldscript for ${s##*/}" abort="yes" fi @@ -635,11 +662,11 @@ install_qa_check() { # Make sure people don't store libtool files or static libs in /lib f=$(ls "${ED}"lib*/*.{a,la} 2>/dev/null) if [[ -n ${f} ]] ; then - vecho -ne '\n' + __vecho -ne '\n' eqawarn "QA Notice: Excessive files found in the / partition" eqawarn "${f}" - vecho -ne '\n' - die "static archives (*.a) and libtool library files (*.la) do not belong in /" + __vecho -ne '\n' + die "static archives (*.a) and libtool library files (*.la) belong in /usr/lib*, not /lib*" fi # Verify that the libtool files don't contain bogus $D entries. @@ -647,7 +674,7 @@ install_qa_check() { for a in "${ED}"usr/lib*/*.la ; do s=${a##*/} if grep -qs "${ED}" "${a}" ; then - vecho -ne '\n' + __vecho -ne '\n' eqawarn "QA Notice: ${s} appears to contain PORTAGE_TMPDIR paths" abort="yes" fi @@ -688,6 +715,8 @@ install_qa_check() { ": warning: reference to local variable .* returned" ": warning: returning reference to temporary" ": warning: function returns address of local variable" + ": warning: .*\\[-Wsizeof-pointer-memaccess\\]" + ": warning: .*\\[-Waggressive-loop-optimizations\\]" # this may be valid code :/ #": warning: multi-character character constant" # need to check these two ... @@ -726,18 +755,19 @@ install_qa_check() { eerror " with the maintaining herd of the package." eerror else - vecho -ne '\n' + __vecho -ne '\n' eqawarn "QA Notice: Package triggers severe warnings which indicate that it" eqawarn " may exhibit random runtime failures." eqawarn "${f}" - vecho -ne '\n' + __vecho -ne '\n' fi fi done local cat_cmd=cat [[ $PORTAGE_LOG_FILE = *.gz ]] && cat_cmd=zcat [[ $reset_debug = 1 ]] && set -x - f=$($cat_cmd "${PORTAGE_LOG_FILE}" | \ + # Use safe cwd, avoiding unsafe import for bug #469338. + f=$(cd "${PORTAGE_PYM_PATH}" ; $cat_cmd "${PORTAGE_LOG_FILE}" | \ "${PORTAGE_PYTHON:-/usr/bin/python}" "$PORTAGE_BIN_PATH"/check-implicit-pointer-usage.py || die "check-implicit-pointer-usage.py failed") if [[ -n ${f} ]] ; then @@ -763,26 +793,25 @@ install_qa_check() { eerror " with the maintaining herd of the package." eerror else - vecho -ne '\n' + __vecho -ne '\n' eqawarn "QA Notice: Package triggers severe warnings which indicate that it" eqawarn " will almost certainly crash on 64bit architectures." eqawarn "${f}" - vecho -ne '\n' + __vecho -ne '\n' fi fi if [[ ${abort} == "yes" ]] ; then if [[ $gentoo_bug = yes || $always_overflow = yes ]] ; then - die "install aborted due to" \ - "severe warnings shown above" + die "install aborted due to severe warnings shown above" else echo "Please do not file a Gentoo bug and instead" \ "report the above QA issues directly to the upstream" \ "developers of this software." | fmt -w 70 | \ while read -r line ; do eqawarn "${line}" ; done eqawarn "Homepage: ${HOMEPAGE}" - has stricter ${FEATURES} && die "install aborted due to" \ - "severe warnings shown above" + has stricter ${FEATURES} && \ + die "install aborted due to severe warnings shown above" fi fi fi @@ -794,32 +823,42 @@ install_qa_check() { [[ -x /usr/bin/file && -x /usr/bin/find ]] && \ [[ -n ${MULTILIB_STRICT_DIRS} && -n ${MULTILIB_STRICT_DENY} ]] then - local abort=no dir file firstrun=yes + rm -f "${T}/multilib-strict.log" + local abort=no dir file MULTILIB_STRICT_EXEMPT=$(echo ${MULTILIB_STRICT_EXEMPT} | sed -e 's:\([(|)]\):\\\1:g') for dir in ${MULTILIB_STRICT_DIRS} ; do [[ -d ${ED}/${dir} ]] || continue for file in $(find ${ED}/${dir} -type f | grep -v "^${ED}/${dir}/${MULTILIB_STRICT_EXEMPT}"); do if file ${file} | egrep -q "${MULTILIB_STRICT_DENY}" ; then - if [[ ${firstrun} == yes ]] ; then - echo "Files matching a file type that is not allowed:" - firstrun=no - fi - abort=yes - echo " ${file#${ED}//}" + echo "${file#${ED}//}" >> "${T}/multilib-strict.log" fi done done - [[ ${abort} == yes ]] && die "multilib-strict check failed!" - fi - # ensure packages don't install systemd units automagically - if ! has systemd ${INHERITED} && \ - [[ -d "${ED}"/lib/systemd/system ]] - then - eqawarn "QA Notice: package installs systemd unit files (/lib/systemd/system)" - eqawarn " but does not inherit systemd.eclass." - has stricter ${FEATURES} \ - && die "install aborted due to missing inherit of systemd.eclass" + if [[ -s ${T}/multilib-strict.log ]] ; then + if [[ ${#QA_MULTILIB_PATHS[@]} -eq 1 ]] ; then + local shopts=$- + set -o noglob + QA_MULTILIB_PATHS=(${QA_MULTILIB_PATHS}) + set +o noglob + set -${shopts} + fi + if [ "${QA_STRICT_MULTILIB_PATHS-unset}" = unset ] ; then + for x in "${QA_MULTILIB_PATHS[@]}" ; do + sed -e "s#^${x#/}\$##" -i "${T}/multilib-strict.log" + done + sed -e "/^\$/d" -i "${T}/multilib-strict.log" + fi + if [[ -s ${T}/multilib-strict.log ]] ; then + abort=yes + echo "Files matching a file type that is not allowed:" + while read -r ; do + echo " ${REPLY}" + done < "${T}/multilib-strict.log" + fi + fi + + [[ ${abort} == yes ]] && die "multilib-strict check failed!" fi } @@ -852,16 +891,6 @@ install_qa_check_prefix() { # all further checks rely on ${ED} existing [[ -d ${ED} ]] || return - # this does not really belong here, but it's closely tied to - # the code below; many runscripts generate positives here, and we - # know they don't work (bug #196294) so as long as that one - # remains an issue, simply remove them as they won't work - # anyway, avoid etc/init.d/functions.sh from being thrown away - if [[ ( -d "${ED}"/etc/conf.d || -d "${ED}"/etc/init.d ) && ! -f "${ED}"/etc/init.d/functions.sh ]] ; then - ewarn "removed /etc/init.d and /etc/conf.d directories until bug #196294 has been resolved" - rm -Rf "${ED}"/etc/{conf,init}.d - fi - # check shebangs, bug #282539 rm -f "${T}"/non-prefix-shebangs-errs local WHITELIST=" /usr/bin/env " @@ -953,7 +982,7 @@ install_mask() { local no_inst for no_inst in ${install_mask}; do set +o noglob - quiet_mode || einfo "Removing ${no_inst}" + __quiet_mode || einfo "Removing ${no_inst}" # normal stuff rm -Rf "${root}"/${no_inst} >&/dev/null @@ -972,8 +1001,9 @@ preinst_mask() { return 1 fi - [[ " ${FEATURES} " == *" force-prefix "* ]] || \ - case "$EAPI" in 0|1|2) local ED=${D} ;; esac + if ! ___eapi_has_prefix_variables; then + local ED=${D} + fi # Make sure $PWD is not ${D} so that we don't leave gmon.out files # in there in case any tools were built with -pg in CFLAGS. @@ -1001,8 +1031,9 @@ preinst_sfperms() { return 1 fi - [[ " ${FEATURES} " == *" force-prefix "* ]] || \ - case "$EAPI" in 0|1|2) local ED=${D} ;; esac + if ! ___eapi_has_prefix_variables; then + local ED=${D} + fi # Smart FileSystem Permissions if has sfperms $FEATURES; then @@ -1040,8 +1071,9 @@ preinst_suid_scan() { return 1 fi - [[ " ${FEATURES} " == *" force-prefix "* ]] || \ - case "$EAPI" in 0|1|2) local ED=${D} ;; esac + if ! ___eapi_has_prefix_variables; then + local ED=${D} + fi # total suid control. if has suidctl $FEATURES; then @@ -1051,19 +1083,19 @@ preinst_suid_scan() { # to files outside of the sandbox, but this # can easly be bypassed using the addwrite() function addwrite "${sfconf}" - vecho ">>> Performing suid scan in ${ED}" + __vecho ">>> Performing suid scan in ${ED}" for i in $(find "${ED}" -type f \( -perm -4000 -o -perm -2000 \) ); do if [ -s "${sfconf}" ]; then install_path=/${i#${ED}} if grep -q "^${install_path}\$" "${sfconf}" ; then - vecho "- ${install_path} is an approved suid file" + __vecho "- ${install_path} is an approved suid file" else - vecho ">>> Removing sbit on non registered ${install_path}" + __vecho ">>> Removing sbit on non registered ${install_path}" for x in 5 4 3 2 1 0; do sleep 0.25 ; done ls_ret=$(ls -ldh "${i}") chmod ugo-s "${i}" grep "^#${install_path}$" "${sfconf}" > /dev/null || { - vecho ">>> Appending commented out entry to ${sfconf} for ${PF}" + __vecho ">>> Appending commented out entry to ${sfconf} for ${PF}" echo "## ${ls_ret%${ED}*}${install_path}" >> "${sfconf}" echo "#${install_path}" >> "${sfconf}" # no delwrite() eh? @@ -1071,7 +1103,7 @@ preinst_suid_scan() { } fi else - vecho "suidctl feature set but you are lacking a ${sfconf}" + __vecho "suidctl feature set but you are lacking a ${sfconf}" fi done fi @@ -1083,34 +1115,35 @@ preinst_selinux_labels() { return 1 fi if has selinux ${FEATURES}; then - # SELinux file labeling (needs to always be last in dyn_preinst) + # SELinux file labeling (needs to execute after preinst) # only attempt to label if setfiles is executable # and 'context' is available on selinuxfs. if [ -f /selinux/context -o -f /sys/fs/selinux/context ] && \ [ -x /usr/sbin/setfiles -a -x /usr/sbin/selinuxconfig ]; then - vecho ">>> Setting SELinux security labels" + __vecho ">>> Setting SELinux security labels" ( eval "$(/usr/sbin/selinuxconfig)" || \ die "Failed to determine SELinux policy paths."; - + addwrite /selinux/context addwrite /sys/fs/selinux/context - + /usr/sbin/setfiles "${file_contexts_path}" -r "${D}" "${D}" ) || die "Failed to set SELinux security labels." else # nonfatal, since merging can happen outside a SE kernel # like during a recovery situation - vecho "!!! Unable to set SELinux security labels" + __vecho "!!! Unable to set SELinux security labels" fi fi } -dyn_package() { +__dyn_package() { local PROOT - [[ " ${FEATURES} " == *" force-prefix "* ]] || \ - case "$EAPI" in 0|1|2) local EPREFIX= ED=${D} ;; esac + if ! ___eapi_has_prefix_variables; then + local EPREFIX= ED=${D} + fi # Make sure $PWD is not ${D} so that we don't leave gmon.out files # in there in case any tools were built with -pg in CFLAGS. @@ -1133,6 +1166,7 @@ dyn_package() { local tar_options="" [[ $PORTAGE_VERBOSE = 1 ]] && tar_options+=" -v" + has xattr ${FEATURES} && [[ $(tar --help 2> /dev/null) == *--xattrs* ]] && tar_options+=" --xattrs" # Sandbox is disabled in case the user wants to use a symlink # for $PKGDIR and/or $PKGDIR/All. export SANDBOX_ON="0" @@ -1142,7 +1176,7 @@ dyn_package() { tar $tar_options -cf - $PORTAGE_BINPKG_TAR_OPTS -C "${PROOT}" . | \ $PORTAGE_BZIP2_COMMAND -c > "$PORTAGE_BINPKG_TMPFILE" assert "failed to pack binary package: '$PORTAGE_BINPKG_TMPFILE'" - PYTHONPATH=${PORTAGE_PYM_PATH}${PYTHONPATH:+:}${PYTHONPATH} \ + PYTHONPATH=${PORTAGE_PYTHONPATH:-${PORTAGE_PYM_PATH}} \ "${PORTAGE_PYTHON:-/usr/bin/python}" "$PORTAGE_BIN_PATH"/xpak-helper.py recompose \ "$PORTAGE_BINPKG_TMPFILE" "$PORTAGE_BUILDDIR/build-info" if [ $? -ne 0 ]; then @@ -1159,7 +1193,7 @@ dyn_package() { fi [ -n "${md5_hash}" ] && \ echo ${md5_hash} > "${PORTAGE_BUILDDIR}"/build-info/BINPKGMD5 - vecho ">>> Done." + __vecho ">>> Done." # cleanup our temp tree [[ -n ${PKG_INSTALL_MASK} ]] && rm -rf "${PROOT}" @@ -1168,8 +1202,8 @@ dyn_package() { die "Failed to create $PORTAGE_BUILDDIR/.packaged" } -dyn_spec() { - local sources_dir=/usr/src/rpm/SOURCES +__dyn_spec() { + local sources_dir=${T}/rpmbuild/SOURCES mkdir -p "${sources_dir}" declare -a tar_args=("${EBUILD}") [[ -d ${FILESDIR} ]] && tar_args=("${EBUILD}" "${FILESDIR}") @@ -1182,10 +1216,9 @@ Summary: ${DESCRIPTION} Name: ${PN} Version: ${PV} Release: ${PR} -Copyright: GPL +License: GPL Group: portage/${CATEGORY} Source: ${PF}.tar.gz -Buildroot: ${D} %description ${DESCRIPTION} @@ -1206,18 +1239,18 @@ __END1__ } -dyn_rpm() { - - [[ " ${FEATURES} " == *" force-prefix "* ]] || \ - case "$EAPI" in 0|1|2) local EPREFIX= ;; esac +__dyn_rpm() { + if ! ___eapi_has_prefix_variables; then + local EPREFIX= + fi cd "${T}" || die "cd failed" - local machine_name=$(uname -m) - local dest_dir=${EPREFIX}/usr/src/rpm/RPMS/${machine_name} - addwrite ${EPREFIX}/usr/src/rpm + local machine_name=${CHOST%%-*} + local dest_dir=${T}/rpmbuild/RPMS/${machine_name} addwrite "${RPMDIR}" - dyn_spec - rpmbuild -bb --clean --rmsource "${PF}.spec" || die "Failed to integrate rpm spec file" + __dyn_spec + HOME=${T} \ + rpmbuild -bb --clean --nodeps --rmsource "${PF}.spec" --buildroot "${D}" --target "${CHOST}" || die "Failed to integrate rpm spec file" install -D "${dest_dir}/${PN}-${PV}-${PR}.${machine_name}.rpm" \ "${RPMDIR}/${CATEGORY}/${PN}-${PV}-${PR}.rpm" || \ die "Failed to move rpm" @@ -1255,7 +1288,7 @@ install_hooks() { } if [ -n "${MISC_FUNCTIONS_ARGS}" ]; then - source_all_bashrcs + __source_all_bashrcs [ "$PORTAGE_DEBUG" == "1" ] && set -x for x in ${MISC_FUNCTIONS_ARGS}; do ${x} diff --git a/portage_with_autodep/bin/phase-functions.sh b/portage_with_autodep/bin/phase-functions.sh index ce251ce..f39a024 100755 --- a/portage_with_autodep/bin/phase-functions.sh +++ b/portage_with_autodep/bin/phase-functions.sh @@ -1,5 +1,5 @@ #!/bin/bash -# Copyright 1999-2012 Gentoo Foundation +# Copyright 1999-2013 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 # Hardcoded bash lists are needed for backward compatibility with @@ -8,28 +8,31 @@ # when portage is upgrading itself. PORTAGE_READONLY_METADATA="DEFINED_PHASES DEPEND DESCRIPTION - EAPI HOMEPAGE INHERITED IUSE REQUIRED_USE KEYWORDS LICENSE + EAPI HDEPEND HOMEPAGE INHERITED IUSE REQUIRED_USE KEYWORDS LICENSE PDEPEND PROVIDE RDEPEND REPOSITORY RESTRICT SLOT SRC_URI" -PORTAGE_READONLY_VARS="D EBUILD EBUILD_PHASE \ +PORTAGE_READONLY_VARS="D EBUILD EBUILD_PHASE EBUILD_PHASE_FUNC \ EBUILD_SH_ARGS ECLASSDIR EMERGE_FROM FILESDIR MERGE_TYPE \ PM_EBUILD_HOOK_DIR \ PORTAGE_ACTUAL_DISTDIR PORTAGE_ARCHLIST PORTAGE_BASHRC \ PORTAGE_BINPKG_FILE PORTAGE_BINPKG_TAR_OPTS PORTAGE_BINPKG_TMPFILE \ - PORTAGE_BIN_PATH PORTAGE_BUILDDIR PORTAGE_BUNZIP2_COMMAND \ + PORTAGE_BIN_PATH PORTAGE_BUILDDIR PORTAGE_BUILD_GROUP \ + PORTAGE_BUILD_USER PORTAGE_BUNZIP2_COMMAND \ PORTAGE_BZIP2_COMMAND PORTAGE_COLORMAP PORTAGE_CONFIGROOT \ PORTAGE_DEBUG PORTAGE_DEPCACHEDIR PORTAGE_EBUILD_EXIT_FILE \ + PORTAGE_ECLASS_LOCATIONS \ PORTAGE_GID PORTAGE_GRPNAME PORTAGE_INST_GID PORTAGE_INST_UID \ - PORTAGE_IPC_DAEMON PORTAGE_IUSE PORTAGE_LOG_FILE \ + PORTAGE_INTERNAL_CALLER PORTAGE_IPC_DAEMON PORTAGE_IUSE PORTAGE_LOG_FILE \ PORTAGE_MUTABLE_FILTERED_VARS PORTAGE_OVERRIDE_EPREFIX \ - PORTAGE_PYM_PATH PORTAGE_PYTHON \ + PORTAGE_PYM_PATH PORTAGE_PYTHON PORTAGE_PYTHONPATH \ PORTAGE_READONLY_METADATA PORTAGE_READONLY_VARS \ - PORTAGE_REPO_NAME PORTAGE_RESTRICT \ + PORTAGE_REPO_NAME PORTAGE_REPOSITORIES PORTAGE_RESTRICT \ PORTAGE_SAVED_READONLY_VARS PORTAGE_SIGPIPE_STATUS \ PORTAGE_TMPDIR PORTAGE_UPDATE_ENV PORTAGE_USERNAME \ - PORTAGE_VERBOSE PORTAGE_WORKDIR_MODE PORTDIR PORTDIR_OVERLAY \ + PORTAGE_VERBOSE PORTAGE_WORKDIR_MODE PORTAGE_XATTR_EXCLUDE \ + PORTDIR \ PROFILE_PATHS REPLACING_VERSIONS REPLACED_BY_VERSION T WORKDIR \ - __PORTAGE_TEST_HARDLINK_LOCKS" + __PORTAGE_HELPER __PORTAGE_TEST_HARDLINK_LOCKS" PORTAGE_SAVED_READONLY_VARS="A CATEGORY P PF PN PR PV PVR" @@ -39,7 +42,7 @@ PORTAGE_SAVED_READONLY_VARS="A CATEGORY P PF PN PR PV PVR" # it is saved or loaded (any mutations do not persist). PORTAGE_MUTABLE_FILTERED_VARS="AA HOSTNAME" -# @FUNCTION: filter_readonly_variables +# @FUNCTION: __filter_readonly_variables # @DESCRIPTION: [--filter-sandbox] [--allow-extra-vars] # Read an environment from stdin and echo to stdout while filtering variables # with names that are known to cause interference: @@ -81,14 +84,14 @@ PORTAGE_MUTABLE_FILTERED_VARS="AA HOSTNAME" # readonly variable cause the shell to exit while executing the "source" # builtin command. To avoid this problem, this function filters those # variables out and discards them. See bug #190128. -filter_readonly_variables() { +__filter_readonly_variables() { local x filtered_vars local readonly_bash_vars="BASHOPTS BASHPID DIRSTACK EUID FUNCNAME GROUPS PIPESTATUS PPID SHELLOPTS UID" local bash_misc_vars="BASH BASH_.* COLUMNS COMP_WORDBREAKS HISTCMD HISTFILE HOSTNAME HOSTTYPE IFS LINENO MACHTYPE OLDPWD OPTERR OPTIND OSTYPE POSIXLY_CORRECT PS4 PWD RANDOM - SECONDS SHELL SHLVL _" + SECONDS SHLVL _" local filtered_sandbox_vars="SANDBOX_ACTIVE SANDBOX_BASHRC SANDBOX_DEBUG_LOG SANDBOX_DISABLED SANDBOX_LIB SANDBOX_LOG SANDBOX_ON" @@ -100,15 +103,9 @@ filter_readonly_variables() { # Don't filter/interfere with prefix variables unless they are # supported by the current EAPI. - case "${EAPI:-0}" in - 0|1|2) - [[ " ${FEATURES} " == *" force-prefix "* ]] && \ - filtered_vars+=" ED EPREFIX EROOT" - ;; - *) - filtered_vars+=" ED EPREFIX EROOT" - ;; - esac + if ___eapi_has_prefix_variables; then + filtered_vars+=" ED EPREFIX EROOT" + fi if has --filter-sandbox $* ; then filtered_vars="${filtered_vars} SANDBOX_.*" @@ -140,14 +137,14 @@ filter_readonly_variables() { "${PORTAGE_PYTHON:-/usr/bin/python}" "${PORTAGE_BIN_PATH}"/filter-bash-environment.py "${filtered_vars}" || die "filter-bash-environment.py failed" } -# @FUNCTION: preprocess_ebuild_env +# @FUNCTION: __preprocess_ebuild_env # @DESCRIPTION: # Filter any readonly variables from ${T}/environment, source it, and then -# save it via save_ebuild_env(). This process should be sufficient to prevent +# save it via __save_ebuild_env(). This process should be sufficient to prevent # any stale variables or functions from an arbitrary environment from # interfering with the current environment. This is useful when an existing # environment needs to be loaded from a binary or installed package. -preprocess_ebuild_env() { +__preprocess_ebuild_env() { local _portage_filter_opts="--filter-features --filter-locale --filter-path --filter-sandbox" # If environment.raw is present, this is a signal from the python side, @@ -156,7 +153,7 @@ preprocess_ebuild_env() { # Otherwise, we don't need to filter the environment. [ -f "${T}/environment.raw" ] || return 0 - filter_readonly_variables $_portage_filter_opts < "${T}"/environment \ + __filter_readonly_variables $_portage_filter_opts < "${T}"/environment \ >> "$T/environment.filtered" || return $? unset _portage_filter_opts mv "${T}"/environment.filtered "${T}"/environment || return $? @@ -174,20 +171,20 @@ preprocess_ebuild_env() { # until we've merged them with our current values. export SANDBOX_ON=0 - # It's remotely possible that save_ebuild_env() has been overridden + # It's remotely possible that __save_ebuild_env() has been overridden # by the above source command. To protect ourselves, we override it # here with our own version. ${PORTAGE_BIN_PATH} is safe to use here # because it's already filtered above. source "${PORTAGE_BIN_PATH}/save-ebuild-env.sh" || exit $? - # Rely on save_ebuild_env() to filter out any remaining variables + # Rely on __save_ebuild_env() to filter out any remaining variables # and functions that could interfere with the current environment. - save_ebuild_env || exit $? + __save_ebuild_env || exit $? >> "$T/environment.success" || exit $? ) > "${T}/environment.filtered" local retval if [ -e "${T}/environment.success" ] ; then - filter_readonly_variables --filter-features < \ + __filter_readonly_variables --filter-features < \ "${T}/environment.filtered" > "${T}/environment" retval=$? else @@ -197,62 +194,62 @@ preprocess_ebuild_env() { return ${retval} } -ebuild_phase() { - declare -F "$1" >/dev/null && qa_call $1 +__ebuild_phase() { + declare -F "$1" >/dev/null && __qa_call $1 } -ebuild_phase_with_hooks() { +__ebuild_phase_with_hooks() { local x phase_name=${1} for x in {pre_,,post_}${phase_name} ; do - ebuild_phase ${x} + __ebuild_phase ${x} done } -dyn_pretend() { +__dyn_pretend() { if [[ -e $PORTAGE_BUILDDIR/.pretended ]] ; then - vecho ">>> It appears that '$PF' is already pretended; skipping." - vecho ">>> Remove '$PORTAGE_BUILDDIR/.pretended' to force pretend." + __vecho ">>> It appears that '$PF' is already pretended; skipping." + __vecho ">>> Remove '$PORTAGE_BUILDDIR/.pretended' to force pretend." return 0 fi - ebuild_phase pre_pkg_pretend - ebuild_phase pkg_pretend + __ebuild_phase pre_pkg_pretend + __ebuild_phase pkg_pretend >> "$PORTAGE_BUILDDIR/.pretended" || \ die "Failed to create $PORTAGE_BUILDDIR/.pretended" - ebuild_phase post_pkg_pretend + __ebuild_phase post_pkg_pretend } -dyn_setup() { +__dyn_setup() { if [[ -e $PORTAGE_BUILDDIR/.setuped ]] ; then - vecho ">>> It appears that '$PF' is already setup; skipping." - vecho ">>> Remove '$PORTAGE_BUILDDIR/.setuped' to force setup." + __vecho ">>> It appears that '$PF' is already setup; skipping." + __vecho ">>> Remove '$PORTAGE_BUILDDIR/.setuped' to force setup." return 0 fi - ebuild_phase pre_pkg_setup - ebuild_phase pkg_setup + __ebuild_phase pre_pkg_setup + __ebuild_phase pkg_setup >> "$PORTAGE_BUILDDIR/.setuped" || \ die "Failed to create $PORTAGE_BUILDDIR/.setuped" - ebuild_phase post_pkg_setup + __ebuild_phase post_pkg_setup } -dyn_unpack() { +__dyn_unpack() { if [[ -f ${PORTAGE_BUILDDIR}/.unpacked ]] ; then - vecho ">>> WORKDIR is up-to-date, keeping..." + __vecho ">>> WORKDIR is up-to-date, keeping..." return 0 fi if [ ! -d "${WORKDIR}" ]; then install -m${PORTAGE_WORKDIR_MODE:-0700} -d "${WORKDIR}" || die "Failed to create dir '${WORKDIR}'" fi cd "${WORKDIR}" || die "Directory change failed: \`cd '${WORKDIR}'\`" - ebuild_phase pre_src_unpack - vecho ">>> Unpacking source..." - ebuild_phase src_unpack + __ebuild_phase pre_src_unpack + __vecho ">>> Unpacking source..." + __ebuild_phase src_unpack >> "$PORTAGE_BUILDDIR/.unpacked" || \ die "Failed to create $PORTAGE_BUILDDIR/.unpacked" - vecho ">>> Source unpacked in ${WORKDIR}" - ebuild_phase post_src_unpack + __vecho ">>> Source unpacked in ${WORKDIR}" + __ebuild_phase post_src_unpack } -dyn_clean() { +__dyn_clean() { if [ -z "${PORTAGE_BUILDDIR}" ]; then echo "Aborting clean phase because PORTAGE_BUILDDIR is unset!" return 1 @@ -299,7 +296,7 @@ dyn_clean() { true } -abort_handler() { +__abort_handler() { local msg if [ "$2" != "fail" ]; then msg="${EBUILD}: ${1} aborted; exiting." @@ -314,37 +311,37 @@ abort_handler() { trap - SIGINT SIGQUIT } -abort_prepare() { - abort_handler src_prepare $1 +__abort_prepare() { + __abort_handler src_prepare $1 rm -f "$PORTAGE_BUILDDIR/.prepared" exit 1 } -abort_configure() { - abort_handler src_configure $1 +__abort_configure() { + __abort_handler src_configure $1 rm -f "$PORTAGE_BUILDDIR/.configured" exit 1 } -abort_compile() { - abort_handler "src_compile" $1 +__abort_compile() { + __abort_handler "src_compile" $1 rm -f "${PORTAGE_BUILDDIR}/.compiled" exit 1 } -abort_test() { - abort_handler "dyn_test" $1 +__abort_test() { + __abort_handler "__dyn_test" $1 rm -f "${PORTAGE_BUILDDIR}/.tested" exit 1 } -abort_install() { - abort_handler "src_install" $1 +__abort_install() { + __abort_handler "src_install" $1 rm -rf "${PORTAGE_BUILDDIR}/image" exit 1 } -has_phase_defined_up_to() { +__has_phase_defined_up_to() { local phase for phase in unpack prepare configure compile install; do has ${phase} ${DEFINED_PHASES} && return 0 @@ -354,89 +351,89 @@ has_phase_defined_up_to() { return 1 } -dyn_prepare() { +__dyn_prepare() { if [[ -e $PORTAGE_BUILDDIR/.prepared ]] ; then - vecho ">>> It appears that '$PF' is already prepared; skipping." - vecho ">>> Remove '$PORTAGE_BUILDDIR/.prepared' to force prepare." + __vecho ">>> It appears that '$PF' is already prepared; skipping." + __vecho ">>> Remove '$PORTAGE_BUILDDIR/.prepared' to force prepare." return 0 fi if [[ -d $S ]] ; then cd "${S}" - elif has $EAPI 0 1 2 3 3_pre2 ; then + elif ___eapi_has_S_WORKDIR_fallback; then cd "${WORKDIR}" - elif [[ -z ${A} ]] && ! has_phase_defined_up_to prepare; then + elif [[ -z ${A} ]] && ! __has_phase_defined_up_to prepare; then cd "${WORKDIR}" else die "The source directory '${S}' doesn't exist" fi - trap abort_prepare SIGINT SIGQUIT + trap __abort_prepare SIGINT SIGQUIT - ebuild_phase pre_src_prepare - vecho ">>> Preparing source in $PWD ..." - ebuild_phase src_prepare + __ebuild_phase pre_src_prepare + __vecho ">>> Preparing source in $PWD ..." + __ebuild_phase src_prepare >> "$PORTAGE_BUILDDIR/.prepared" || \ die "Failed to create $PORTAGE_BUILDDIR/.prepared" - vecho ">>> Source prepared." - ebuild_phase post_src_prepare + __vecho ">>> Source prepared." + __ebuild_phase post_src_prepare trap - SIGINT SIGQUIT } -dyn_configure() { +__dyn_configure() { if [[ -e $PORTAGE_BUILDDIR/.configured ]] ; then - vecho ">>> It appears that '$PF' is already configured; skipping." - vecho ">>> Remove '$PORTAGE_BUILDDIR/.configured' to force configuration." + __vecho ">>> It appears that '$PF' is already configured; skipping." + __vecho ">>> Remove '$PORTAGE_BUILDDIR/.configured' to force configuration." return 0 fi if [[ -d $S ]] ; then cd "${S}" - elif has $EAPI 0 1 2 3 3_pre2 ; then + elif ___eapi_has_S_WORKDIR_fallback; then cd "${WORKDIR}" - elif [[ -z ${A} ]] && ! has_phase_defined_up_to configure; then + elif [[ -z ${A} ]] && ! __has_phase_defined_up_to configure; then cd "${WORKDIR}" else die "The source directory '${S}' doesn't exist" fi - trap abort_configure SIGINT SIGQUIT + trap __abort_configure SIGINT SIGQUIT - ebuild_phase pre_src_configure + __ebuild_phase pre_src_configure - vecho ">>> Configuring source in $PWD ..." - ebuild_phase src_configure + __vecho ">>> Configuring source in $PWD ..." + __ebuild_phase src_configure >> "$PORTAGE_BUILDDIR/.configured" || \ die "Failed to create $PORTAGE_BUILDDIR/.configured" - vecho ">>> Source configured." + __vecho ">>> Source configured." - ebuild_phase post_src_configure + __ebuild_phase post_src_configure trap - SIGINT SIGQUIT } -dyn_compile() { +__dyn_compile() { if [[ -e $PORTAGE_BUILDDIR/.compiled ]] ; then - vecho ">>> It appears that '${PF}' is already compiled; skipping." - vecho ">>> Remove '$PORTAGE_BUILDDIR/.compiled' to force compilation." + __vecho ">>> It appears that '${PF}' is already compiled; skipping." + __vecho ">>> Remove '$PORTAGE_BUILDDIR/.compiled' to force compilation." return 0 fi if [[ -d $S ]] ; then cd "${S}" - elif has $EAPI 0 1 2 3 3_pre2 ; then + elif ___eapi_has_S_WORKDIR_fallback; then cd "${WORKDIR}" - elif [[ -z ${A} ]] && ! has_phase_defined_up_to compile; then + elif [[ -z ${A} ]] && ! __has_phase_defined_up_to compile; then cd "${WORKDIR}" else die "The source directory '${S}' doesn't exist" fi - trap abort_compile SIGINT SIGQUIT + trap __abort_compile SIGINT SIGQUIT if has distcc $FEATURES && has distcc-pump $FEATURES ; then if [[ -z $INCLUDE_SERVER_PORT ]] || [[ ! -w $INCLUDE_SERVER_PORT ]] ; then @@ -445,90 +442,96 @@ dyn_compile() { fi fi - ebuild_phase pre_src_compile + __ebuild_phase pre_src_compile - vecho ">>> Compiling source in $PWD ..." - ebuild_phase src_compile + __vecho ">>> Compiling source in $PWD ..." + __ebuild_phase src_compile >> "$PORTAGE_BUILDDIR/.compiled" || \ die "Failed to create $PORTAGE_BUILDDIR/.compiled" - vecho ">>> Source compiled." + __vecho ">>> Source compiled." - ebuild_phase post_src_compile + __ebuild_phase post_src_compile trap - SIGINT SIGQUIT } -dyn_test() { +__dyn_test() { if [[ -e $PORTAGE_BUILDDIR/.tested ]] ; then - vecho ">>> It appears that ${PN} has already been tested; skipping." - vecho ">>> Remove '${PORTAGE_BUILDDIR}/.tested' to force test." + __vecho ">>> It appears that ${PN} has already been tested; skipping." + __vecho ">>> Remove '${PORTAGE_BUILDDIR}/.tested' to force test." return fi - if [ "${EBUILD_FORCE_TEST}" == "1" ] ; then - # If USE came from ${T}/environment then it might not have USE=test - # like it's supposed to here. - ! has test ${USE} && export USE="${USE} test" - fi - - trap "abort_test" SIGINT SIGQUIT + trap "__abort_test" SIGINT SIGQUIT if [ -d "${S}" ]; then cd "${S}" else cd "${WORKDIR}" fi - if ! has test $FEATURES && [ "${EBUILD_FORCE_TEST}" != "1" ]; then - vecho ">>> Test phase [not enabled]: ${CATEGORY}/${PF}" - elif has test $RESTRICT; then + if has test ${RESTRICT} ; then einfo "Skipping make test/check due to ebuild restriction." - vecho ">>> Test phase [explicitly disabled]: ${CATEGORY}/${PF}" + __vecho ">>> Test phase [disabled because of RESTRICT=test]: ${CATEGORY}/${PF}" + + # If ${EBUILD_FORCE_TEST} == 1 and FEATURES came from ${T}/environment + # then it might not have FEATURES=test like it's supposed to here. + elif [[ ${EBUILD_FORCE_TEST} != 1 ]] && ! has test ${FEATURES} ; then + __vecho ">>> Test phase [not enabled]: ${CATEGORY}/${PF}" else + # If ${EBUILD_FORCE_TEST} == 1 and USE came from ${T}/environment + # then it might not have USE=test like it's supposed to here. + if [[ ${EBUILD_FORCE_TEST} == 1 && test =~ ${PORTAGE_IUSE} ]] && \ + ! has test ${USE} ; then + export USE="${USE} test" + fi + local save_sp=${SANDBOX_PREDICT} addpredict / - ebuild_phase pre_src_test - ebuild_phase src_test + __ebuild_phase pre_src_test + __ebuild_phase src_test >> "$PORTAGE_BUILDDIR/.tested" || \ die "Failed to create $PORTAGE_BUILDDIR/.tested" - ebuild_phase post_src_test + __ebuild_phase post_src_test SANDBOX_PREDICT=${save_sp} fi trap - SIGINT SIGQUIT } -dyn_install() { +__dyn_install() { [ -z "$PORTAGE_BUILDDIR" ] && die "${FUNCNAME}: PORTAGE_BUILDDIR is unset" if has noauto $FEATURES ; then rm -f "${PORTAGE_BUILDDIR}/.installed" elif [[ -e $PORTAGE_BUILDDIR/.installed ]] ; then - vecho ">>> It appears that '${PF}' is already installed; skipping." - vecho ">>> Remove '${PORTAGE_BUILDDIR}/.installed' to force install." + __vecho ">>> It appears that '${PF}' is already installed; skipping." + __vecho ">>> Remove '${PORTAGE_BUILDDIR}/.installed' to force install." return 0 fi - trap "abort_install" SIGINT SIGQUIT - ebuild_phase pre_src_install + trap "__abort_install" SIGINT SIGQUIT + __ebuild_phase pre_src_install - _x=${ED} - [[ " ${FEATURES} " == *" force-prefix "* ]] || \ - case "$EAPI" in 0|1|2) _x=${D} ;; esac + if ___eapi_has_prefix_variables; then + _x=${ED} + else + _x=${D} + fi rm -rf "${D}" mkdir -p "${_x}" unset _x if [[ -d $S ]] ; then cd "${S}" - elif has $EAPI 0 1 2 3 3_pre2 ; then + elif ___eapi_has_S_WORKDIR_fallback; then cd "${WORKDIR}" - elif [[ -z ${A} ]] && ! has_phase_defined_up_to install; then + elif [[ -z ${A} ]] && ! __has_phase_defined_up_to install; then cd "${WORKDIR}" else die "The source directory '${S}' doesn't exist" fi - vecho - vecho ">>> Install ${PF} into ${D} category ${CATEGORY}" + __vecho + __vecho ">>> Install ${PF} into ${D} category ${CATEGORY}" #our custom version of libtool uses $S and $D to fix #invalid paths in .la files export S D @@ -541,12 +544,12 @@ dyn_install() { export _E_EXEDESTTREE_="" export _E_DOCDESTTREE_="" - ebuild_phase src_install + __ebuild_phase src_install >> "$PORTAGE_BUILDDIR/.installed" || \ die "Failed to create $PORTAGE_BUILDDIR/.installed" - vecho ">>> Completed installing ${PF} into ${D}" - vecho - ebuild_phase post_src_install + __vecho ">>> Completed installing ${PF} into ${D}" + __vecho + __ebuild_phase post_src_install cd "${PORTAGE_BUILDDIR}"/build-info set -f @@ -560,10 +563,15 @@ dyn_install() { if [[ $CATEGORY != virtual ]] ; then for f in ASFLAGS CBUILD CC CFLAGS CHOST CTARGET CXX \ CXXFLAGS EXTRA_ECONF EXTRA_EINSTALL EXTRA_MAKE \ - LDFLAGS LIBCFLAGS LIBCXXFLAGS ; do + LDFLAGS LIBCFLAGS LIBCXXFLAGS QA_CONFIGURE_OPTIONS \ + QA_DESKTOP_FILE ; do x=$(echo -n ${!f}) [[ -n $x ]] && echo "$x" > $f done + # whitespace preserved + for f in QA_AM_MAINTAINER_MODE ; do + [[ -n ${!f} ]] && echo "${!f}" > $f + done fi echo "${USE}" > USE echo "${EAPI:-0}" > EAPI @@ -571,24 +579,22 @@ dyn_install() { # Save EPREFIX, since it makes it easy to use chpathtool to # adjust the content of a binary package so that it will # work in a different EPREFIX from the one is was built for. - case "${EAPI:-0}" in - 0|1|2) - [[ " ${FEATURES} " == *" force-prefix "* ]] && \ - [ -n "${EPREFIX}" ] && echo "${EPREFIX}" > EPREFIX - ;; - *) - [ -n "${EPREFIX}" ] && echo "${EPREFIX}" > EPREFIX - ;; - esac + if ___eapi_has_prefix_variables && [[ -n ${EPREFIX} ]]; then + echo "${EPREFIX}" > EPREFIX + fi set +f # local variables can leak into the saved environment. unset f - save_ebuild_env --exclude-init-phases | filter_readonly_variables \ - --filter-path --filter-sandbox --allow-extra-vars > environment - assert "save_ebuild_env failed" + # Use safe cwd, avoiding unsafe import for bug #469338. + cd "${PORTAGE_PYM_PATH}" + __save_ebuild_env --exclude-init-phases | __filter_readonly_variables \ + --filter-path --filter-sandbox --allow-extra-vars > \ + "${PORTAGE_BUILDDIR}"/build-info/environment + assert "__save_ebuild_env failed" + cd "${PORTAGE_BUILDDIR}"/build-info || die ${PORTAGE_BZIP2_COMMAND} -f9 environment @@ -601,15 +607,7 @@ dyn_install() { trap - SIGINT SIGQUIT } -dyn_preinst() { - if [ -z "${D}" ]; then - eerror "${FUNCNAME}: D is unset" - return 1 - fi - ebuild_phase_with_hooks pkg_preinst -} - -dyn_help() { +__dyn_help() { echo echo "Portage" echo "Copyright 1999-2010 Gentoo Foundation" @@ -625,6 +623,7 @@ dyn_help() { echo " pretend : execute package specific pretend actions" echo " setup : execute package specific setup actions" echo " fetch : download source archive(s) and patches" + echo " nofetch : display special fetch instructions" echo " digest : create a manifest file for the package" echo " manifest : create a manifest file for the package" echo " unpack : unpack sources (auto-dependencies if needed)" @@ -672,19 +671,18 @@ dyn_help() { echo } -# @FUNCTION: _ebuild_arg_to_phase +# @FUNCTION: __ebuild_arg_to_phase # @DESCRIPTION: # Translate a known ebuild(1) argument into the precise # name of it's corresponding ebuild phase. -_ebuild_arg_to_phase() { - [ $# -ne 2 ] && die "expected exactly 2 args, got $#: $*" - local eapi=$1 - local arg=$2 +__ebuild_arg_to_phase() { + [ $# -ne 1 ] && die "expected exactly 1 arg, got $#: $*" + local arg=$1 local phase_func="" case "$arg" in pretend) - ! has $eapi 0 1 2 3 3_pre2 && \ + ___eapi_has_pkg_pretend && \ phase_func=pkg_pretend ;; setup) @@ -697,11 +695,11 @@ _ebuild_arg_to_phase() { phase_func=src_unpack ;; prepare) - ! has $eapi 0 1 && \ + ___eapi_has_src_prepare && \ phase_func=src_prepare ;; configure) - ! has $eapi 0 1 && \ + ___eapi_has_src_configure && \ phase_func=src_configure ;; compile) @@ -732,7 +730,7 @@ _ebuild_arg_to_phase() { return 0 } -_ebuild_phase_funcs() { +__ebuild_phase_funcs() { [ $# -ne 2 ] && die "expected exactly 2 args, got $#: $*" local eapi=$1 local phase_func=$2 @@ -742,20 +740,20 @@ _ebuild_phase_funcs() { for x in pkg_nofetch src_unpack src_test ; do declare -F $x >/dev/null || \ - eval "$x() { _eapi0_$x \"\$@\" ; }" + eval "$x() { __eapi0_$x \"\$@\" ; }" done - case $eapi in + case "$eapi" in 0|1) if ! declare -F src_compile >/dev/null ; then - case $eapi in + case "$eapi" in 0) - src_compile() { _eapi0_src_compile "$@" ; } + src_compile() { __eapi0_src_compile "$@" ; } ;; *) - src_compile() { _eapi1_src_compile "$@" ; } + src_compile() { __eapi1_src_compile "$@" ; } ;; esac fi @@ -775,35 +773,35 @@ _ebuild_phase_funcs() { *) declare -F src_configure >/dev/null || \ - src_configure() { _eapi2_src_configure "$@" ; } + src_configure() { __eapi2_src_configure "$@" ; } declare -F src_compile >/dev/null || \ - src_compile() { _eapi2_src_compile "$@" ; } + src_compile() { __eapi2_src_compile "$@" ; } - has $eapi 2 3 3_pre2 || declare -F src_install >/dev/null || \ - src_install() { _eapi4_src_install "$@" ; } + has $eapi 2 3 || declare -F src_install >/dev/null || \ + src_install() { __eapi4_src_install "$@" ; } if has $phase_func $default_phases ; then - _eapi2_pkg_nofetch () { _eapi0_pkg_nofetch "$@" ; } - _eapi2_src_unpack () { _eapi0_src_unpack "$@" ; } - _eapi2_src_prepare () { true ; } - _eapi2_src_test () { _eapi0_src_test "$@" ; } - _eapi2_src_install () { die "$FUNCNAME is not supported" ; } + __eapi2_pkg_nofetch () { __eapi0_pkg_nofetch "$@" ; } + __eapi2_src_unpack () { __eapi0_src_unpack "$@" ; } + __eapi2_src_prepare () { true ; } + __eapi2_src_test () { __eapi0_src_test "$@" ; } + __eapi2_src_install () { die "$FUNCNAME is not supported" ; } for x in $default_phases ; do - eval "default_$x() { _eapi2_$x \"\$@\" ; }" + eval "default_$x() { __eapi2_$x \"\$@\" ; }" done - eval "default() { _eapi2_$phase_func \"\$@\" ; }" + eval "default() { __eapi2_$phase_func \"\$@\" ; }" - case $eapi in + case "$eapi" in 2|3) ;; *) - eval "default_src_install() { _eapi4_src_install \"\$@\" ; }" + eval "default_src_install() { __eapi4_src_install \"\$@\" ; }" [[ $phase_func = src_install ]] && \ - eval "default() { _eapi4_$phase_func \"\$@\" ; }" + eval "default() { __eapi4_$phase_func \"\$@\" ; }" ;; esac @@ -825,14 +823,14 @@ _ebuild_phase_funcs() { esac } -ebuild_main() { +__ebuild_main() { # Subshell/helper die support (must export for the die helper). # Since this function is typically executed in a subshell, # setup EBUILD_MASTER_PID to refer to the current $BASHPID, # which seems to give the best results when further # nested subshells call die. - export EBUILD_MASTER_PID=$BASHPID + export EBUILD_MASTER_PID=${BASHPID:-$(__bashpid)} trap 'exit 1' SIGTERM #a reasonable default for $S @@ -861,37 +859,39 @@ ebuild_main() { # respect FEATURES="-ccache". has ccache $FEATURES || export CCACHE_DISABLE=1 - local phase_func=$(_ebuild_arg_to_phase "$EAPI" "$EBUILD_PHASE") - [[ -n $phase_func ]] && _ebuild_phase_funcs "$EAPI" "$phase_func" + local phase_func=$(__ebuild_arg_to_phase "$EBUILD_PHASE") + [[ -n $phase_func ]] && __ebuild_phase_funcs "$EAPI" "$phase_func" unset phase_func - source_all_bashrcs + __source_all_bashrcs case ${1} in nofetch) - ebuild_phase_with_hooks pkg_nofetch + __ebuild_phase_with_hooks pkg_nofetch ;; - prerm|postrm|postinst|config|info) + prerm|postrm|preinst|postinst|config|info) if has "${1}" config info && \ ! declare -F "pkg_${1}" >/dev/null ; then ewarn "pkg_${1}() is not defined: '${EBUILD##*/}'" fi export SANDBOX_ON="0" if [ "${PORTAGE_DEBUG}" != "1" ] || [ "${-/x/}" != "$-" ]; then - ebuild_phase_with_hooks pkg_${1} + __ebuild_phase_with_hooks pkg_${1} else set -x - ebuild_phase_with_hooks pkg_${1} + __ebuild_phase_with_hooks pkg_${1} set +x fi - if [[ $EBUILD_PHASE == postinst ]] && [[ -n $PORTAGE_UPDATE_ENV ]]; then + if [[ -n $PORTAGE_UPDATE_ENV ]] ; then # Update environment.bz2 in case installation phases # need to pass some variables to uninstallation phases. - save_ebuild_env --exclude-init-phases | \ - filter_readonly_variables --filter-path \ + # Use safe cwd, avoiding unsafe import for bug #469338. + cd "${PORTAGE_PYM_PATH}" + __save_ebuild_env --exclude-init-phases | \ + __filter_readonly_variables --filter-path \ --filter-sandbox --allow-extra-vars \ | ${PORTAGE_BZIP2_COMMAND} -c -f9 > "$PORTAGE_UPDATE_ENV" - assert "save_ebuild_env failed" + assert "__save_ebuild_env failed" fi ;; unpack|prepare|configure|compile|test|clean|install) @@ -917,7 +917,7 @@ ebuild_main() { x=LIBDIR_$ABI [ -z "$PKG_CONFIG_PATH" -a -n "$ABI" -a -n "${!x}" ] && \ - export PKG_CONFIG_PATH=/usr/${!x}/pkgconfig + export PKG_CONFIG_PATH=${EPREFIX}/usr/${!x}/pkgconfig if has noauto $FEATURES && \ [[ ! -f $PORTAGE_BUILDDIR/.unpacked ]] ; then @@ -952,24 +952,24 @@ ebuild_main() { esac if [ "${PORTAGE_DEBUG}" != "1" ] || [ "${-/x/}" != "$-" ]; then - dyn_${1} + __dyn_${1} else set -x - dyn_${1} + __dyn_${1} set +x fi export SANDBOX_ON="0" ;; - help|pretend|setup|preinst) + help|pretend|setup) #pkg_setup needs to be out of the sandbox for tmp file creation; #for example, awking and piping a file in /tmp requires a temp file to be created #in /etc. If pkg_setup is in the sandbox, both our lilo and apache ebuilds break. export SANDBOX_ON="0" if [ "${PORTAGE_DEBUG}" != "1" ] || [ "${-/x/}" != "$-" ]; then - dyn_${1} + __dyn_${1} else set -x - dyn_${1} + __dyn_${1} set +x fi ;; @@ -979,7 +979,7 @@ ebuild_main() { export SANDBOX_ON="1" echo "Unrecognized arg '${1}'" echo - dyn_help + __dyn_help exit 1 ;; esac @@ -987,11 +987,13 @@ ebuild_main() { # Save the env only for relevant phases. if ! has "${1}" clean help info nofetch ; then umask 002 - save_ebuild_env | filter_readonly_variables \ + # Use safe cwd, avoiding unsafe import for bug #469338. + cd "${PORTAGE_PYM_PATH}" + __save_ebuild_env | __filter_readonly_variables \ --filter-features > "$T/environment" - assert "save_ebuild_env failed" - chown portage:portage "$T/environment" &>/dev/null - chmod g+w "$T/environment" &>/dev/null + assert "__save_ebuild_env failed" + chgrp "${PORTAGE_GRPNAME:-portage}" "$T/environment" + chmod g+w "$T/environment" fi [[ -n $PORTAGE_EBUILD_EXIT_FILE ]] && > "$PORTAGE_EBUILD_EXIT_FILE" if [[ -n $PORTAGE_IPC_DAEMON ]] ; then diff --git a/portage_with_autodep/bin/phase-helpers.sh b/portage_with_autodep/bin/phase-helpers.sh index 946520b..412decb 100755 --- a/portage_with_autodep/bin/phase-helpers.sh +++ b/portage_with_autodep/bin/phase-helpers.sh @@ -1,5 +1,5 @@ #!/bin/bash -# Copyright 1999-2011 Gentoo Foundation +# Copyright 1999-2013 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 export DESTTREE=/usr @@ -11,6 +11,8 @@ export EXEOPTIONS="-m0755" export LIBOPTIONS="-m0644" export DIROPTIONS="-m0755" export MOPREFIX=${PN} +# Do not compress files which are smaller than this (in bytes). #169260 +export PORTAGE_DOCOMPRESS_SIZE_LIMIT="128" declare -a PORTAGE_DOCOMPRESS=( /usr/share/{doc,info,man} ) declare -a PORTAGE_DOCOMPRESS_SKIP=( /usr/share/doc/${PF}/html ) @@ -19,13 +21,14 @@ into() { export DESTTREE="" else export DESTTREE=$1 - [[ " ${FEATURES} " == *" force-prefix "* ]] || \ - case "$EAPI" in 0|1|2) local ED=${D} ;; esac + if ! ___eapi_has_prefix_variables; then + local ED=${D} + fi if [ ! -d "${ED}${DESTTREE}" ]; then install -d "${ED}${DESTTREE}" local ret=$? if [[ $ret -ne 0 ]] ; then - helpers_die "${FUNCNAME[0]} failed" + __helpers_die "${FUNCNAME[0]} failed" return $ret fi fi @@ -37,13 +40,14 @@ insinto() { export INSDESTTREE="" else export INSDESTTREE=$1 - [[ " ${FEATURES} " == *" force-prefix "* ]] || \ - case "$EAPI" in 0|1|2) local ED=${D} ;; esac + if ! ___eapi_has_prefix_variables; then + local ED=${D} + fi if [ ! -d "${ED}${INSDESTTREE}" ]; then install -d "${ED}${INSDESTTREE}" local ret=$? if [[ $ret -ne 0 ]] ; then - helpers_die "${FUNCNAME[0]} failed" + __helpers_die "${FUNCNAME[0]} failed" return $ret fi fi @@ -55,13 +59,14 @@ exeinto() { export _E_EXEDESTTREE_="" else export _E_EXEDESTTREE_="$1" - [[ " ${FEATURES} " == *" force-prefix "* ]] || \ - case "$EAPI" in 0|1|2) local ED=${D} ;; esac + if ! ___eapi_has_prefix_variables; then + local ED=${D} + fi if [ ! -d "${ED}${_E_EXEDESTTREE_}" ]; then install -d "${ED}${_E_EXEDESTTREE_}" local ret=$? if [[ $ret -ne 0 ]] ; then - helpers_die "${FUNCNAME[0]} failed" + __helpers_die "${FUNCNAME[0]} failed" return $ret fi fi @@ -73,13 +78,14 @@ docinto() { export _E_DOCDESTTREE_="" else export _E_DOCDESTTREE_="$1" - [[ " ${FEATURES} " == *" force-prefix "* ]] || \ - case "$EAPI" in 0|1|2) local ED=${D} ;; esac + if ! ___eapi_has_prefix_variables; then + local ED=${D} + fi if [ ! -d "${ED}usr/share/doc/${PF}/${_E_DOCDESTTREE_}" ]; then install -d "${ED}usr/share/doc/${PF}/${_E_DOCDESTTREE_}" local ret=$? if [[ $ret -ne 0 ]] ; then - helpers_die "${FUNCNAME[0]} failed" + __helpers_die "${FUNCNAME[0]} failed" return $ret fi fi @@ -112,13 +118,13 @@ libopts() { } docompress() { - has "${EAPI}" 0 1 2 3 && die "'docompress' not supported in this EAPI" + ___eapi_has_docompress || die "'docompress' not supported in this EAPI" local f g if [[ $1 = "-x" ]]; then shift for f; do - f=$(strip_duplicate_slashes "${f}"); f=${f%/} + f=$(__strip_duplicate_slashes "${f}"); f=${f%/} [[ ${f:0:1} = / ]] || f="/${f}" for g in "${PORTAGE_DOCOMPRESS_SKIP[@]}"; do [[ ${f} = "${g}" ]] && continue 2 @@ -127,7 +133,7 @@ docompress() { done else for f; do - f=$(strip_duplicate_slashes "${f}"); f=${f%/} + f=$(__strip_duplicate_slashes "${f}"); f=${f%/} [[ ${f:0:1} = / ]] || f="/${f}" for g in "${PORTAGE_DOCOMPRESS[@]}"; do [[ ${f} = "${g}" ]] && continue 2 @@ -137,29 +143,6 @@ docompress() { fi } -# adds ".keep" files so that dirs aren't auto-cleaned -keepdir() { - dodir "$@" - local x - [[ " ${FEATURES} " == *" force-prefix "* ]] || \ - case "$EAPI" in 0|1|2) local ED=${D} ;; esac - if [ "$1" == "-R" ] || [ "$1" == "-r" ]; then - shift - find "$@" -type d -printf "${ED}%p/.keep_${CATEGORY}_${PN}-${SLOT}\n" \ - | tr "\n" "\0" | \ - while read -r -d $'\0' ; do - >> "$REPLY" || \ - die "Failed to recursively create .keep files" - done - else - for x in "$@"; do - >> "${ED}${x}/.keep_${CATEGORY}_${PN}-${SLOT}" || \ - die "Failed to create .keep in ${ED}${x}" - done - fi -} - - useq() { has $EBUILD_PHASE prerm postrm || eqawarn \ "QA Notice: The 'useq' function is deprecated (replaced by 'use')" @@ -174,6 +157,17 @@ usev() { return 1 } +if ___eapi_has_usex; then + usex() { + if use "$1"; then + echo "${2-yes}$4" + else + echo "${3-no}$5" + fi + return 0 + } +fi + use() { local u=$1 local found=0 @@ -194,18 +188,31 @@ use() { #fi true - # Make sure we have this USE flag in IUSE - elif [[ -n $PORTAGE_IUSE && -n $EBUILD_PHASE ]] ; then - [[ $u =~ $PORTAGE_IUSE ]] || \ + # Make sure we have this USE flag in IUSE, but exempt binary + # packages for API consumers like Entropy which do not require + # a full profile with IUSE_IMPLICIT and stuff (see bug #456830). + elif [[ -n $PORTAGE_IUSE && -n $EBUILD_PHASE && + -n $PORTAGE_INTERNAL_CALLER ]] ; then + if [[ ! $u =~ $PORTAGE_IUSE ]] ; then + if [[ ! ${EAPI} =~ ^(0|1|2|3|4|4-python|4-slot-abi)$ ]] ; then + # This is only strict starting with EAPI 5, since implicit IUSE + # is not well defined for earlier EAPIs (see bug #449708). + die "USE Flag '${u}' not in IUSE for ${CATEGORY}/${PF}" + fi eqawarn "QA Notice: USE Flag '${u}' not" \ "in IUSE for ${CATEGORY}/${PF}" + fi fi + local IFS=$' \t\n' prev_shopts=$- ret + set -f if has ${u} ${USE} ; then - return ${found} + ret=${found} else - return $((!found)) + ret=$((!found)) fi + [[ ${prev_shopts} == *f* ]] || set +f + return ${ret} } use_with() { @@ -215,7 +222,7 @@ use_with() { return 1 fi - if ! has "${EAPI:-0}" 0 1 2 3 ; then + if ___eapi_use_enable_and_use_with_support_empty_third_argument; then local UW_SUFFIX=${3+=$3} else local UW_SUFFIX=${3:+=$3} @@ -237,7 +244,7 @@ use_enable() { return 1 fi - if ! has "${EAPI:-0}" 0 1 2 3 ; then + if ___eapi_use_enable_and_use_with_support_empty_third_argument; then local UE_SUFFIX=${3+=$3} else local UE_SUFFIX=${3:+=$3} @@ -255,15 +262,19 @@ use_enable() { unpack() { local srcdir local x - local y + local y y_insensitive + local suffix suffix_insensitive local myfail local eapi=${EAPI:-0} [ -z "$*" ] && die "Nothing passed to the 'unpack' command" for x in "$@"; do - vecho ">>> Unpacking ${x} to ${PWD}" + __vecho ">>> Unpacking ${x} to ${PWD}" + suffix=${x##*.} + suffix_insensitive=$(LC_ALL=C tr "[:upper:]" "[:lower:]" <<< "${suffix}") y=${x%.*} y=${y##*.} + y_insensitive=$(LC_ALL=C tr "[:upper:]" "[:lower:]" <<< "${y}") if [[ ${x} == "./"* ]] ; then srcdir="" @@ -276,10 +287,16 @@ unpack() { fi [[ ! -s ${srcdir}${x} ]] && die "${x} does not exist" - _unpack_tar() { - if [ "${y}" == "tar" ]; then + __unpack_tar() { + if [[ ${y_insensitive} == tar ]] ; then + if ___eapi_unpack_is_case_sensitive && \ + [[ tar != ${y} ]] ; then + eqawarn "QA Notice: unpack called with" \ + "secondary suffix '${y}' which is unofficially" \ + "supported with EAPI '${EAPI}'. Instead use 'tar'." + fi $1 -c -- "$srcdir$x" | tar xof - - assert_sigpipe_ok "$myfail" + __assert_sigpipe_ok "$myfail" else local cwd_dest=${x##*/} cwd_dest=${cwd_dest%.*} @@ -288,30 +305,67 @@ unpack() { } myfail="failure unpacking ${x}" - case "${x##*.}" in + case "${suffix_insensitive}" in tar) + if ___eapi_unpack_is_case_sensitive && \ + [[ tar != ${suffix} ]] ; then + eqawarn "QA Notice: unpack called with" \ + "suffix '${suffix}' which is unofficially supported" \ + "with EAPI '${EAPI}'. Instead use 'tar'." + fi tar xof "$srcdir$x" || die "$myfail" ;; tgz) + if ___eapi_unpack_is_case_sensitive && \ + [[ tgz != ${suffix} ]] ; then + eqawarn "QA Notice: unpack called with" \ + "suffix '${suffix}' which is unofficially supported" \ + "with EAPI '${EAPI}'. Instead use 'tgz'." + fi tar xozf "$srcdir$x" || die "$myfail" ;; tbz|tbz2) + if ___eapi_unpack_is_case_sensitive && \ + [[ " tbz tbz2 " != *" ${suffix} "* ]] ; then + eqawarn "QA Notice: unpack called with" \ + "suffix '${suffix}' which is unofficially supported" \ + "with EAPI '${EAPI}'. Instead use 'tbz' or 'tbz2'." + fi ${PORTAGE_BUNZIP2_COMMAND:-${PORTAGE_BZIP2_COMMAND} -d} -c -- "$srcdir$x" | tar xof - - assert_sigpipe_ok "$myfail" + __assert_sigpipe_ok "$myfail" ;; - ZIP|zip|jar) + zip|jar) + if ___eapi_unpack_is_case_sensitive && \ + [[ " ZIP zip jar " != *" ${suffix} "* ]] ; then + eqawarn "QA Notice: unpack called with" \ + "suffix '${suffix}' which is unofficially supported" \ + "with EAPI '${EAPI}'." \ + "Instead use 'ZIP', 'zip', or 'jar'." + fi # unzip will interactively prompt under some error conditions, # as reported in bug #336285 ( set +x ; while true ; do echo n || break ; done ) | \ unzip -qo "${srcdir}${x}" || die "$myfail" ;; - gz|Z|z) - _unpack_tar "gzip -d" + gz|z) + if ___eapi_unpack_is_case_sensitive && \ + [[ " gz z Z " != *" ${suffix} "* ]] ; then + eqawarn "QA Notice: unpack called with" \ + "suffix '${suffix}' which is unofficially supported" \ + "with EAPI '${EAPI}'. Instead use 'gz', 'z', or 'Z'." + fi + __unpack_tar "gzip -d" ;; bz2|bz) - _unpack_tar "${PORTAGE_BUNZIP2_COMMAND:-${PORTAGE_BZIP2_COMMAND} -d}" + if ___eapi_unpack_is_case_sensitive && \ + [[ " bz bz2 " != *" ${suffix} "* ]] ; then + eqawarn "QA Notice: unpack called with" \ + "suffix '${suffix}' which is unofficially supported" \ + "with EAPI '${EAPI}'. Instead use 'bz' or 'bz2'." + fi + __unpack_tar "${PORTAGE_BUNZIP2_COMMAND:-${PORTAGE_BZIP2_COMMAND} -d}" ;; - 7Z|7z) + 7z) local my_output my_output="$(7z x -y "${srcdir}${x}")" if [ $? -ne 0 ]; then @@ -319,16 +373,41 @@ unpack() { die "$myfail" fi ;; - RAR|rar) + rar) + if ___eapi_unpack_is_case_sensitive && \ + [[ " rar RAR " != *" ${suffix} "* ]] ; then + eqawarn "QA Notice: unpack called with" \ + "suffix '${suffix}' which is unofficially supported" \ + "with EAPI '${EAPI}'. Instead use 'rar' or 'RAR'." + fi unrar x -idq -o+ "${srcdir}${x}" || die "$myfail" ;; - LHa|LHA|lha|lzh) + lha|lzh) + if ___eapi_unpack_is_case_sensitive && \ + [[ " LHA LHa lha lzh " != *" ${suffix} "* ]] ; then + eqawarn "QA Notice: unpack called with" \ + "suffix '${suffix}' which is unofficially supported" \ + "with EAPI '${EAPI}'." \ + "Instead use 'LHA', 'LHa', 'lha', or 'lzh'." + fi lha xfq "${srcdir}${x}" || die "$myfail" ;; a) + if ___eapi_unpack_is_case_sensitive && \ + [[ " a " != *" ${suffix} "* ]] ; then + eqawarn "QA Notice: unpack called with" \ + "suffix '${suffix}' which is unofficially supported" \ + "with EAPI '${EAPI}'. Instead use 'a'." + fi ar x "${srcdir}${x}" || die "$myfail" ;; deb) + if ___eapi_unpack_is_case_sensitive && \ + [[ " deb " != *" ${suffix} "* ]] ; then + eqawarn "QA Notice: unpack called with" \ + "suffix '${suffix}' which is unofficially supported" \ + "with EAPI '${EAPI}'. Instead use 'deb'." + fi # Unpacking .deb archives can not always be done with # `ar`. For instance on AIX this doesn't work out. If # we have `deb2targz` installed, prefer it over `ar` for @@ -356,17 +435,29 @@ unpack() { fi ;; lzma) - _unpack_tar "lzma -d" + if ___eapi_unpack_is_case_sensitive && \ + [[ " lzma " != *" ${suffix} "* ]] ; then + eqawarn "QA Notice: unpack called with" \ + "suffix '${suffix}' which is unofficially supported" \ + "with EAPI '${EAPI}'. Instead use 'lzma'." + fi + __unpack_tar "lzma -d" ;; xz) - if has $eapi 0 1 2 ; then - vecho "unpack ${x}: file format not recognized. Ignoring." + if ___eapi_unpack_is_case_sensitive && \ + [[ " xz " != *" ${suffix} "* ]] ; then + eqawarn "QA Notice: unpack called with" \ + "suffix '${suffix}' which is unofficially supported" \ + "with EAPI '${EAPI}'. Instead use 'xz'." + fi + if ___eapi_unpack_supports_xz; then + __unpack_tar "xz -d" else - _unpack_tar "xz -d" + __vecho "unpack ${x}: file format not recognized. Ignoring." fi ;; *) - vecho "unpack ${x}: file format not recognized. Ignoring." + __vecho "unpack ${x}: file format not recognized. Ignoring." ;; esac done @@ -378,22 +469,24 @@ unpack() { econf() { local x + local pid=${BASHPID:-$(__bashpid)} - [[ " ${FEATURES} " == *" force-prefix "* ]] || \ - case "$EAPI" in 0|1|2) local EPREFIX= ;; esac + if ! ___eapi_has_prefix_variables; then + local EPREFIX= + fi - _hasg() { + __hasg() { local x s=$1 shift for x ; do [[ ${x} == ${s} ]] && echo "${x}" && return 0 ; done return 1 } - _hasgq() { _hasg "$@" >/dev/null ; } + __hasgq() { __hasg "$@" >/dev/null ; } - local phase_func=$(_ebuild_arg_to_phase "$EAPI" "$EBUILD_PHASE") + local phase_func=$(__ebuild_arg_to_phase "$EBUILD_PHASE") if [[ -n $phase_func ]] ; then - if has "$EAPI" 0 1 ; then + if ! ___eapi_has_src_configure; then [[ $phase_func != src_compile ]] && \ eqawarn "QA Notice: econf called in" \ "$phase_func instead of src_compile" @@ -408,23 +501,44 @@ econf() { if [ -x "${ECONF_SOURCE}/configure" ]; then if [[ -n $CONFIG_SHELL && \ "$(head -n1 "$ECONF_SOURCE/configure")" =~ ^'#!'[[:space:]]*/bin/sh([[:space:]]|$) ]] ; then - sed -e "1s:^#![[:space:]]*/bin/sh:#!$CONFIG_SHELL:" -i "$ECONF_SOURCE/configure" || \ - die "Substition of shebang in '$ECONF_SOURCE/configure' failed" + # preserve timestamp, see bug #440304 + touch -r "${ECONF_SOURCE}/configure" "${ECONF_SOURCE}/configure._portage_tmp_.${pid}" || die + sed -i \ + -e "1s:^#![[:space:]]*/bin/sh:#!$CONFIG_SHELL:" \ + "${ECONF_SOURCE}/configure" \ + || die "Substition of shebang in '${ECONF_SOURCE}/configure' failed" + touch -r "${ECONF_SOURCE}/configure._portage_tmp_.${pid}" "${ECONF_SOURCE}/configure" || die + rm -f "${ECONF_SOURCE}/configure._portage_tmp_.${pid}" fi if [ -e "${EPREFIX}"/usr/share/gnuconfig/ ]; then find "${WORKDIR}" -type f '(' \ -name config.guess -o -name config.sub ')' -print0 | \ while read -r -d $'\0' x ; do - vecho " * econf: updating ${x/${WORKDIR}\/} with ${EPREFIX}/usr/share/gnuconfig/${x##*/}" - cp -f "${EPREFIX}"/usr/share/gnuconfig/"${x##*/}" "${x}" + __vecho " * econf: updating ${x/${WORKDIR}\/} with ${EPREFIX}/usr/share/gnuconfig/${x##*/}" + # Make sure we do this atomically incase we're run in parallel. #487478 + cp -f "${EPREFIX}"/usr/share/gnuconfig/"${x##*/}" "${x}.${pid}" + mv -f "${x}.${pid}" "${x}" done fi - # EAPI=4 adds --disable-dependency-tracking to econf - if ! has "$EAPI" 0 1 2 3 3_pre2 && \ - "${ECONF_SOURCE}/configure" --help 2>/dev/null | \ - grep -q disable-dependency-tracking ; then - set -- --disable-dependency-tracking "$@" + if ___eapi_econf_passes_--disable-dependency-tracking || ___eapi_econf_passes_--disable-silent-rules; then + local conf_help=$("${ECONF_SOURCE}/configure" --help 2>/dev/null) + + if ___eapi_econf_passes_--disable-dependency-tracking; then + case "${conf_help}" in + *--disable-dependency-tracking*) + set -- --disable-dependency-tracking "$@" + ;; + esac + fi + + if ___eapi_econf_passes_--disable-silent-rules; then + case "${conf_help}" in + *--disable-silent-rules*) + set -- --disable-silent-rules "$@" + ;; + esac + fi fi # if the profile defines a location to install libs to aside from default, pass it on. @@ -433,16 +547,19 @@ econf() { if [[ -n ${ABI} && -n ${!LIBDIR_VAR} ]] ; then CONF_LIBDIR=${!LIBDIR_VAR} fi - if [[ -n ${CONF_LIBDIR} ]] && ! _hasgq --libdir=\* "$@" ; then - export CONF_PREFIX=$(_hasg --exec-prefix=\* "$@") - [[ -z ${CONF_PREFIX} ]] && CONF_PREFIX=$(_hasg --prefix=\* "$@") + if [[ -n ${CONF_LIBDIR} ]] && ! __hasgq --libdir=\* "$@" ; then + export CONF_PREFIX=$(__hasg --exec-prefix=\* "$@") + [[ -z ${CONF_PREFIX} ]] && CONF_PREFIX=$(__hasg --prefix=\* "$@") : ${CONF_PREFIX:=${EPREFIX}/usr} CONF_PREFIX=${CONF_PREFIX#*=} [[ ${CONF_PREFIX} != /* ]] && CONF_PREFIX="/${CONF_PREFIX}" [[ ${CONF_LIBDIR} != /* ]] && CONF_LIBDIR="/${CONF_LIBDIR}" - set -- --libdir="$(strip_duplicate_slashes ${CONF_PREFIX}${CONF_LIBDIR})" "$@" + set -- --libdir="$(__strip_duplicate_slashes "${CONF_PREFIX}${CONF_LIBDIR}")" "$@" fi + # Handle arguments containing quoted whitespace (see bug #457136). + eval "local -a EXTRA_ECONF=(${EXTRA_ECONF})" + set -- \ --prefix="${EPREFIX}"/usr \ ${CBUILD:+--build=${CBUILD}} \ @@ -454,8 +571,8 @@ econf() { --sysconfdir="${EPREFIX}"/etc \ --localstatedir="${EPREFIX}"/var/lib \ "$@" \ - ${EXTRA_ECONF} - vecho "${ECONF_SOURCE}/configure" "$@" + "${EXTRA_ECONF[@]}" + __vecho "${ECONF_SOURCE}/configure" "$@" if ! "${ECONF_SOURCE}/configure" "$@" ; then @@ -476,8 +593,9 @@ econf() { einstall() { # CONF_PREFIX is only set if they didn't pass in libdir above. local LOCAL_EXTRA_EINSTALL="${EXTRA_EINSTALL}" - [[ " ${FEATURES} " == *" force-prefix "* ]] || \ - case "$EAPI" in 0|1|2) local ED=${D} ;; esac + if ! ___eapi_has_prefix_variables; then + local ED=${D} + fi LIBDIR_VAR="LIBDIR_${ABI}" if [ -n "${ABI}" -a -n "${!LIBDIR_VAR}" ]; then CONF_LIBDIR="${!LIBDIR_VAR}" @@ -485,7 +603,7 @@ einstall() { unset LIBDIR_VAR if [ -n "${CONF_LIBDIR}" ] && [ "${CONF_PREFIX:+set}" = set ]; then EI_DESTLIBDIR="${D}/${CONF_PREFIX}/${CONF_LIBDIR}" - EI_DESTLIBDIR="$(strip_duplicate_slashes ${EI_DESTLIBDIR})" + EI_DESTLIBDIR="$(__strip_duplicate_slashes "${EI_DESTLIBDIR}")" LOCAL_EXTRA_EINSTALL="libdir=${EI_DESTLIBDIR} ${LOCAL_EXTRA_EINSTALL}" unset EI_DESTLIBDIR fi @@ -516,7 +634,7 @@ einstall() { fi } -_eapi0_pkg_nofetch() { +__eapi0_pkg_nofetch() { [ -z "${SRC_URI}" ] && return elog "The following are listed in SRC_URI for ${PN}:" @@ -526,55 +644,59 @@ _eapi0_pkg_nofetch() { done } -_eapi0_src_unpack() { +__eapi0_src_unpack() { [[ -n ${A} ]] && unpack ${A} } -_eapi0_src_compile() { +__eapi0_src_compile() { if [ -x ./configure ] ; then econf fi - _eapi2_src_compile + __eapi2_src_compile } -_eapi0_src_test() { +__eapi0_src_test() { # Since we don't want emake's automatic die # support (EAPI 4 and later), and we also don't # want the warning messages that it produces if # we call it in 'nonfatal' mode, we use emake_cmd # to emulate the desired parts of emake behavior. local emake_cmd="${MAKE:-make} ${MAKEOPTS} ${EXTRA_EMAKE}" - if $emake_cmd -j1 check -n &> /dev/null; then - vecho ">>> Test phase [check]: ${CATEGORY}/${PF}" - $emake_cmd -j1 check || \ + local internal_opts= + if ___eapi_default_src_test_disables_parallel_jobs; then + internal_opts+=" -j1" + fi + if $emake_cmd ${internal_opts} check -n &> /dev/null; then + __vecho ">>> Test phase [check]: ${CATEGORY}/${PF}" + $emake_cmd ${internal_opts} check || \ die "Make check failed. See above for details." - elif $emake_cmd -j1 test -n &> /dev/null; then - vecho ">>> Test phase [test]: ${CATEGORY}/${PF}" - $emake_cmd -j1 test || \ + elif $emake_cmd ${internal_opts} test -n &> /dev/null; then + __vecho ">>> Test phase [test]: ${CATEGORY}/${PF}" + $emake_cmd ${internal_opts} test || \ die "Make test failed. See above for details." else - vecho ">>> Test phase [none]: ${CATEGORY}/${PF}" + __vecho ">>> Test phase [none]: ${CATEGORY}/${PF}" fi } -_eapi1_src_compile() { - _eapi2_src_configure - _eapi2_src_compile +__eapi1_src_compile() { + __eapi2_src_configure + __eapi2_src_compile } -_eapi2_src_configure() { +__eapi2_src_configure() { if [[ -x ${ECONF_SOURCE:-.}/configure ]] ; then econf fi } -_eapi2_src_compile() { +__eapi2_src_compile() { if [ -f Makefile ] || [ -f GNUmakefile ] || [ -f makefile ]; then emake || die "emake failed" fi } -_eapi4_src_install() { +__eapi4_src_install() { if [[ -f Makefile || -f GNUmakefile || -f makefile ]] ; then emake DESTDIR="${D}" install fi @@ -593,71 +715,285 @@ _eapi4_src_install() { } # @FUNCTION: has_version -# @USAGE: <DEPEND ATOM> +# @USAGE: [--host-root] <DEPEND ATOM> # @DESCRIPTION: # Return true if given package is installed. Otherwise return false. # Callers may override the ROOT variable in order to match packages from an # alternative ROOT. has_version() { - local eroot - case "$EAPI" in - 0|1|2) - [[ " ${FEATURES} " == *" force-prefix "* ]] && \ - eroot=${ROOT%/}${EPREFIX}/ || eroot=${ROOT} - ;; - *) - eroot=${ROOT%/}${EPREFIX}/ - ;; - esac + local atom eroot host_root=false root=${ROOT} + if [[ $1 == --host-root ]] ; then + host_root=true + shift + fi + atom=$1 + shift + [ $# -gt 0 ] && die "${FUNCNAME[0]}: unused argument(s): $*" + + if ${host_root} ; then + if ! ___eapi_best_version_and_has_version_support_--host-root; then + die "${FUNCNAME[0]}: option --host-root is not supported with EAPI ${EAPI}" + fi + root=/ + fi + + if ___eapi_has_prefix_variables; then + # [[ ${root} == / ]] would be ambiguous here, + # since both prefixes can share root=/ while + # having different EPREFIX offsets. + if ${host_root} ; then + eroot=${root%/}${PORTAGE_OVERRIDE_EPREFIX}/ + else + eroot=${root%/}${EPREFIX}/ + fi + else + eroot=${root} + fi if [[ -n $PORTAGE_IPC_DAEMON ]] ; then - "$PORTAGE_BIN_PATH"/ebuild-ipc has_version "${eroot}" "$1" + "$PORTAGE_BIN_PATH"/ebuild-ipc has_version "${eroot}" "${atom}" else - PYTHONPATH=${PORTAGE_PYM_PATH}${PYTHONPATH:+:}${PYTHONPATH} \ - "${PORTAGE_PYTHON:-/usr/bin/python}" "${PORTAGE_BIN_PATH}/portageq" has_version "${eroot}" "$1" + "${PORTAGE_BIN_PATH}/ebuild-helpers/portageq" has_version "${eroot}" "${atom}" fi local retval=$? case "${retval}" in 0|1) return ${retval} ;; + 2) + die "${FUNCNAME[0]}: invalid atom: ${atom}" + ;; *) - die "unexpected portageq exit code: ${retval}" + if [[ -n ${PORTAGE_IPC_DAEMON} ]]; then + die "${FUNCNAME[0]}: unexpected ebuild-ipc exit code: ${retval}" + else + die "${FUNCNAME[0]}: unexpected portageq exit code: ${retval}" + fi ;; esac } # @FUNCTION: best_version -# @USAGE: <DEPEND ATOM> +# @USAGE: [--host-root] <DEPEND ATOM> # @DESCRIPTION: # Returns the best/most-current match. # Callers may override the ROOT variable in order to match packages from an # alternative ROOT. best_version() { - local eroot - case "$EAPI" in - 0|1|2) - [[ " ${FEATURES} " == *" force-prefix "* ]] && \ - eroot=${ROOT%/}${EPREFIX}/ || eroot=${ROOT} - ;; - *) - eroot=${ROOT%/}${EPREFIX}/ - ;; - esac + local atom eroot host_root=false root=${ROOT} + if [[ $1 == --host-root ]] ; then + host_root=true + shift + fi + atom=$1 + shift + [ $# -gt 0 ] && die "${FUNCNAME[0]}: unused argument(s): $*" + + if ${host_root} ; then + if ! ___eapi_best_version_and_has_version_support_--host-root; then + die "${FUNCNAME[0]}: option --host-root is not supported with EAPI ${EAPI}" + fi + root=/ + fi + + if ___eapi_has_prefix_variables; then + # [[ ${root} == / ]] would be ambiguous here, + # since both prefixes can share root=/ while + # having different EPREFIX offsets. + if ${host_root} ; then + eroot=${root%/}${PORTAGE_OVERRIDE_EPREFIX}/ + else + eroot=${root%/}${EPREFIX}/ + fi + else + eroot=${root} + fi if [[ -n $PORTAGE_IPC_DAEMON ]] ; then - "$PORTAGE_BIN_PATH"/ebuild-ipc best_version "${eroot}" "$1" + "$PORTAGE_BIN_PATH"/ebuild-ipc best_version "${eroot}" "${atom}" else - PYTHONPATH=${PORTAGE_PYM_PATH}${PYTHONPATH:+:}${PYTHONPATH} \ - "${PORTAGE_PYTHON:-/usr/bin/python}" "${PORTAGE_BIN_PATH}/portageq" best_version "${eroot}" "$1" + "${PORTAGE_BIN_PATH}/ebuild-helpers/portageq" best_version "${eroot}" "${atom}" fi local retval=$? case "${retval}" in 0|1) return ${retval} ;; + 2) + die "${FUNCNAME[0]}: invalid atom: ${atom}" + ;; *) - die "unexpected portageq exit code: ${retval}" + if [[ -n ${PORTAGE_IPC_DAEMON} ]]; then + die "${FUNCNAME[0]}: unexpected ebuild-ipc exit code: ${retval}" + else + die "${FUNCNAME[0]}: unexpected portageq exit code: ${retval}" + fi ;; esac } + +if ___eapi_has_master_repositories; then + master_repositories() { + local output repository=$1 retval + shift + [[ $# -gt 0 ]] && die "${FUNCNAME[0]}: unused argument(s): $*" + + if [[ -n ${PORTAGE_IPC_DAEMON} ]]; then + "${PORTAGE_BIN_PATH}/ebuild-ipc" master_repositories "${EROOT}" "${repository}" + else + output=$("${PORTAGE_BIN_PATH}/ebuild-helpers/portageq" master_repositories "${EROOT}" "${repository}") + fi + retval=$? + [[ -n ${output} ]] && echo "${output}" + case "${retval}" in + 0|1) + return ${retval} + ;; + 2) + die "${FUNCNAME[0]}: invalid repository: ${repository}" + ;; + *) + if [[ -n ${PORTAGE_IPC_DAEMON} ]]; then + die "${FUNCNAME[0]}: unexpected ebuild-ipc exit code: ${retval}" + else + die "${FUNCNAME[0]}: unexpected portageq exit code: ${retval}" + fi + ;; + esac + } +fi + +if ___eapi_has_repository_path; then + repository_path() { + local output repository=$1 retval + shift + [[ $# -gt 0 ]] && die "${FUNCNAME[0]}: unused argument(s): $*" + + if [[ -n ${PORTAGE_IPC_DAEMON} ]]; then + "${PORTAGE_BIN_PATH}/ebuild-ipc" repository_path "${EROOT}" "${repository}" + else + output=$("${PORTAGE_BIN_PATH}/ebuild-helpers/portageq" get_repo_path "${EROOT}" "${repository}") + fi + retval=$? + [[ -n ${output} ]] && echo "${output}" + case "${retval}" in + 0|1) + return ${retval} + ;; + 2) + die "${FUNCNAME[0]}: invalid repository: ${repository}" + ;; + *) + if [[ -n ${PORTAGE_IPC_DAEMON} ]]; then + die "${FUNCNAME[0]}: unexpected ebuild-ipc exit code: ${retval}" + else + die "${FUNCNAME[0]}: unexpected portageq exit code: ${retval}" + fi + ;; + esac + } +fi + +if ___eapi_has_available_eclasses; then + available_eclasses() { + local output repository=${PORTAGE_REPO_NAME} retval + [[ $# -gt 0 ]] && die "${FUNCNAME[0]}: unused argument(s): $*" + + if [[ -n ${PORTAGE_IPC_DAEMON} ]]; then + "${PORTAGE_BIN_PATH}/ebuild-ipc" available_eclasses "${EROOT}" "${repository}" + else + output=$("${PORTAGE_BIN_PATH}/ebuild-helpers/portageq" available_eclasses "${EROOT}" "${repository}") + fi + retval=$? + [[ -n ${output} ]] && echo "${output}" + case "${retval}" in + 0|1) + return ${retval} + ;; + 2) + die "${FUNCNAME[0]}: invalid repository: ${repository}" + ;; + *) + if [[ -n ${PORTAGE_IPC_DAEMON} ]]; then + die "${FUNCNAME[0]}: unexpected ebuild-ipc exit code: ${retval}" + else + die "${FUNCNAME[0]}: unexpected portageq exit code: ${retval}" + fi + ;; + esac + } +fi + +if ___eapi_has_eclass_path; then + eclass_path() { + local eclass=$1 output repository=${PORTAGE_REPO_NAME} retval + shift + [[ $# -gt 0 ]] && die "${FUNCNAME[0]}: unused argument(s): $*" + + if [[ -n ${PORTAGE_IPC_DAEMON} ]]; then + "${PORTAGE_BIN_PATH}/ebuild-ipc" eclass_path "${EROOT}" "${repository}" "${eclass}" + else + output=$("${PORTAGE_BIN_PATH}/ebuild-helpers/portageq" eclass_path "${EROOT}" "${repository}" "${eclass}") + fi + retval=$? + [[ -n ${output} ]] && echo "${output}" + case "${retval}" in + 0|1) + return ${retval} + ;; + 2) + die "${FUNCNAME[0]}: invalid repository: ${repository}" + ;; + *) + if [[ -n ${PORTAGE_IPC_DAEMON} ]]; then + die "${FUNCNAME[0]}: unexpected ebuild-ipc exit code: ${retval}" + else + die "${FUNCNAME[0]}: unexpected portageq exit code: ${retval}" + fi + ;; + esac + } +fi + +if ___eapi_has_license_path; then + license_path() { + local license=$1 output repository=${PORTAGE_REPO_NAME} retval + shift + [[ $# -gt 0 ]] && die "${FUNCNAME[0]}: unused argument(s): $*" + + if [[ -n ${PORTAGE_IPC_DAEMON} ]]; then + "${PORTAGE_BIN_PATH}/ebuild-ipc" license_path "${EROOT}" "${repository}" "${license}" + else + output=$("${PORTAGE_BIN_PATH}/ebuild-helpers/portageq" license_path "${EROOT}" "${repository}" "${license}") + fi + retval=$? + [[ -n ${output} ]] && echo "${output}" + case "${retval}" in + 0|1) + return ${retval} + ;; + 2) + die "${FUNCNAME[0]}: invalid repository: ${repository}" + ;; + *) + if [[ -n ${PORTAGE_IPC_DAEMON} ]]; then + die "${FUNCNAME[0]}: unexpected ebuild-ipc exit code: ${retval}" + else + die "${FUNCNAME[0]}: unexpected portageq exit code: ${retval}" + fi + ;; + esac + } +fi + +if ___eapi_has_package_manager_build_user; then + package_manager_build_user() { + echo "${PORTAGE_BUILD_USER}" + } +fi + +if ___eapi_has_package_manager_build_group; then + package_manager_build_group() { + echo "${PORTAGE_BUILD_GROUP}" + } +fi diff --git a/portage_with_autodep/bin/portageq b/portage_with_autodep/bin/portageq index 280fe94..a50b805 100755 --- a/portage_with_autodep/bin/portageq +++ b/portage_with_autodep/bin/portageq @@ -1,15 +1,15 @@ #!/usr/bin/python -O -# Copyright 1999-2012 Gentoo Foundation +# Copyright 1999-2013 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 -from __future__ import print_function +from __future__ import print_function, unicode_literals import signal import sys # This block ensures that ^C interrupts are handled quietly. try: - def exithandler(signum, frame): + def exithandler(signum, _frame): signal.signal(signal.SIGINT, signal.SIG_IGN) signal.signal(signal.SIGTERM, signal.SIG_IGN) sys.exit(128 + signum) @@ -34,23 +34,22 @@ if os.environ.get("SANDBOX_ON") == "1": ":".join(filter(None, sandbox_write)) del sandbox_write -try: - import portage -except ImportError: - sys.path.insert(0, pym_path) - import portage -del pym_path - +sys.path.insert(0, pym_path) +import portage +portage._internal_caller = True from portage import os from portage.eapi import eapi_has_repo_deps from portage.util import writemsg, writemsg_stdout -from portage.output import colormap +from portage.util._argparse import ArgumentParser portage.proxy.lazyimport.lazyimport(globals(), + 're', 'subprocess', '_emerge.Package:Package', '_emerge.RootConfig:RootConfig', + '_emerge.is_valid_package_atom:insert_category_into_atom', 'portage.dbapi._expand_new_virt:expand_new_virt', 'portage._sets.base:InternalPackageSet', + 'portage.xml.metadata:MetaDataXML' ) def eval_atom_use(atom): @@ -59,6 +58,10 @@ def eval_atom_use(atom): atom = atom.evaluate_conditionals(use) return atom +def uses_eroot(function): + function.uses_eroot = True + return function + #----------------------------------------------------------------------------- # # To add functionality to this tool, add a function below. @@ -80,13 +83,14 @@ def eval_atom_use(atom): # and will automaticly add a command by the same name as the function! # +@uses_eroot def has_version(argv): """<eroot> <category/package> Return code 0 if it's available, 1 otherwise. """ if (len(argv) < 2): print("ERROR: insufficient parameters!") - return 2 + return 3 warnings = [] @@ -105,9 +109,7 @@ def has_version(argv): try: atom = portage.dep.Atom(argv[1], allow_repo=allow_repo, eapi=eapi) except portage.exception.InvalidAtom as e: - warnings.append( - portage._unicode_decode("QA Notice: %s: %s") % \ - ('has_version', e)) + warnings.append("QA Notice: %s: %s" % ('has_version', e)) atom = eval_atom_use(atom) if warnings: @@ -125,16 +127,16 @@ def has_version(argv): portage.writemsg("ERROR: Invalid atom: '%s'\n" % argv[1], noiselevel=-1) return 2 -has_version.uses_root = True +@uses_eroot def best_version(argv): """<eroot> <category/package> Returns category/package-version (without .ebuild). """ if (len(argv) < 2): print("ERROR: insufficient parameters!") - return 2 + return 3 warnings = [] @@ -153,9 +155,7 @@ def best_version(argv): try: atom = portage.dep.Atom(argv[1], allow_repo=allow_repo, eapi=eapi) except portage.exception.InvalidAtom as e: - warnings.append( - portage._unicode_decode("QA Notice: %s: %s") % \ - ('best_version', e)) + warnings.append("QA Notice: %s: %s" % ('best_version', e)) atom = eval_atom_use(atom) if warnings: @@ -166,9 +166,9 @@ def best_version(argv): print(portage.best(mylist)) except KeyError: return 1 -best_version.uses_root = True +@uses_eroot def mass_best_version(argv): """<eroot> [<category/package>]+ Returns category/package-version (without .ebuild). @@ -178,23 +178,25 @@ def mass_best_version(argv): return 2 try: for pack in argv[1:]: - mylist=portage.db[argv[0]]["vartree"].dbapi.match(pack) - print(pack+":"+portage.best(mylist)) + mylist = portage.db[argv[0]]['vartree'].dbapi.match(pack) + print('%s:%s' % (pack, portage.best(mylist))) except KeyError: return 1 -mass_best_version.uses_root = True + +@uses_eroot def metadata(argv): if (len(argv) < 4): - print("ERROR: insufficient parameters!", file=sys.stderr) + print('ERROR: insufficient parameters!', file=sys.stderr) return 2 eroot, pkgtype, pkgspec = argv[0:3] metakeys = argv[3:] type_map = { - "ebuild":"porttree", - "binary":"bintree", - "installed":"vartree"} + 'ebuild': 'porttree', + 'binary': 'bintree', + 'installed': 'vartree' + } if pkgtype not in type_map: print("Unrecognized package type: '%s'" % pkgtype, file=sys.stderr) return 1 @@ -202,9 +204,9 @@ def metadata(argv): repo = portage.dep.dep_getrepo(pkgspec) pkgspec = portage.dep.remove_slot(pkgspec) try: - values = trees[eroot][type_map[pkgtype]].dbapi.aux_get( - pkgspec, metakeys, myrepo=repo) - writemsg_stdout(''.join('%s\n' % x for x in values), noiselevel=-1) + values = trees[eroot][type_map[pkgtype]].dbapi.aux_get( + pkgspec, metakeys, myrepo=repo) + writemsg_stdout(''.join('%s\n' % x for x in values), noiselevel=-1) except KeyError: print("Package not found: '%s'" % pkgspec, file=sys.stderr) return 1 @@ -216,8 +218,8 @@ Available keys: %s """ % ','.join(sorted(x for x in portage.auxdbkeys \ if not x.startswith('UNUSED_'))) -metadata.uses_root = True +@uses_eroot def contents(argv): """<eroot> <category/package> List the files that are installed for a given package, with @@ -238,8 +240,9 @@ def contents(argv): treetype="vartree", vartree=vartree) writemsg_stdout(''.join('%s\n' % x for x in sorted(db.getcontents())), noiselevel=-1) -contents.uses_root = True + +@uses_eroot def owners(argv): """<eroot> [<filename>]+ Given a list of files, print the packages that own the files and which @@ -253,7 +256,6 @@ def owners(argv): sys.stderr.flush() return 2 - from portage import catsplit, dblink eroot = argv[0] vardb = portage.db[eroot]["vartree"].dbapi root = portage.settings['ROOT'] @@ -319,8 +321,8 @@ def owners(argv): return 0 return 1 -owners.uses_root = True +@uses_eroot def is_protected(argv): """<eroot> <filename> Given a single filename, return code 0 if it's protected, 1 otherwise. @@ -366,8 +368,8 @@ def is_protected(argv): return 0 return 1 -is_protected.uses_root = True +@uses_eroot def filter_protected(argv): """<eroot> Read filenames from stdin and write them to stdout if they are protected. @@ -395,7 +397,6 @@ def filter_protected(argv): settings.get("CONFIG_PROTECT_MASK", "")) protect_obj = ConfigProtect(root, protect, protect_mask) - protected = 0 errors = 0 for line in sys.stdin: @@ -417,7 +418,6 @@ def filter_protected(argv): continue if protect_obj.isprotected(f): - protected += 1 out.write("%s\n" % filename) out.flush() @@ -426,8 +426,8 @@ def filter_protected(argv): return 0 -filter_protected.uses_root = True +@uses_eroot def best_visible(argv): """<eroot> [pkgtype] <atom> Returns category/package-version (without .ebuild). @@ -465,8 +465,7 @@ def best_visible(argv): noiselevel=-1) return 2 - root_config = RootConfig(portage.settings, - portage.db[eroot], None) + root_config = RootConfig(portage.settings, portage.db[eroot], None) if hasattr(db, "xmatch"): cpv_list = db.xmatch("match-all-cpv-only", atom) @@ -508,11 +507,11 @@ def best_visible(argv): writemsg_stdout("\n", noiselevel=-1) return 1 -best_visible.uses_root = True +@uses_eroot def mass_best_visible(argv): - """<root> [<type>] [<category/package>]+ + """<eroot> [<type>] [<category/package>]+ Returns category/package-version (without .ebuild). The pkgtype argument defaults to "ebuild" if unspecified, otherwise it must be one of ebuild, binary, or installed. @@ -535,9 +534,9 @@ def mass_best_visible(argv): best_visible([root, pkgtype, pack]) except KeyError: return 1 -mass_best_visible.uses_root = True +@uses_eroot def all_best_visible(argv): """<eroot> Returns all best_visible packages (without .ebuild). @@ -552,9 +551,9 @@ def all_best_visible(argv): mybest=portage.best(portage.db[argv[0]]["porttree"].dbapi.match(pkg)) if mybest: print(mybest) -all_best_visible.uses_root = True +@uses_eroot def match(argv): """<eroot> <atom> Returns a \\n separated list of category/package-version. @@ -583,17 +582,15 @@ def match(argv): require_metadata = atom.slot or atom.repo for cpv in vardb.cpv_all(): - if not portage.dep.extended_cp_match( - atom.cp, portage.cpv_getkey(cpv)): + if not portage.match_from_list(atom, [cpv]): continue if require_metadata: - slot, repo = vardb.aux_get(cpv, ["SLOT", "repository"]) - - if atom.slot is not None and atom.slot != slot: + try: + cpv = vardb._pkg_str(cpv, atom.repo) + except (KeyError, portage.exception.InvalidData): continue - - if atom.repo is not None and atom.repo != repo: + if not portage.match_from_list(atom, [cpv]): continue results.append(cpv) @@ -603,8 +600,9 @@ def match(argv): results = vardb.match(atom) for cpv in results: print(cpv) -match.uses_root = True + +@uses_eroot def expand_virtual(argv): """<eroot> <atom> Returns a \\n separated list of atoms expanded from a @@ -639,9 +637,8 @@ def expand_virtual(argv): return os.EX_OK -expand_virtual.uses_root = True -def vdb_path(argv): +def vdb_path(_argv): """ Returns the path used for the var(installed) package database for the set environment/configuration options. @@ -651,56 +648,79 @@ def vdb_path(argv): out.flush() return os.EX_OK -def gentoo_mirrors(argv): +def gentoo_mirrors(_argv): """ Returns the mirrors set to use in the portage configuration. """ print(portage.settings["GENTOO_MIRRORS"]) -def portdir(argv): +@uses_eroot +def repositories_configuration(argv): + """<eroot> + Returns the configuration of repositories. + """ + if len(argv) < 1: + print("ERROR: insufficient parameters!", file=sys.stderr) + return 3 + sys.stdout.write(portage.db[argv[0]]["vartree"].settings.repositories.config_string()) + sys.stdout.flush() + +@uses_eroot +def repos_config(argv): + """ + <eroot> + This is an alias for the repositories_configuration command. + """ + return repositories_configuration(argv) + +def portdir(_argv): """ Returns the PORTDIR path. + Deprecated in favor of repositories_configuration command. """ + print("WARNING: 'portageq portdir' is deprecated. Use 'portageq repositories_configuration' instead.", file=sys.stderr) print(portage.settings["PORTDIR"]) -def config_protect(argv): +def config_protect(_argv): """ Returns the CONFIG_PROTECT paths. """ print(portage.settings["CONFIG_PROTECT"]) -def config_protect_mask(argv): +def config_protect_mask(_argv): """ Returns the CONFIG_PROTECT_MASK paths. """ print(portage.settings["CONFIG_PROTECT_MASK"]) -def portdir_overlay(argv): +def portdir_overlay(_argv): """ Returns the PORTDIR_OVERLAY path. + Deprecated in favor of repositories_configuration command. """ + print("WARNING: 'portageq portdir_overlay' is deprecated. Use 'portageq repositories_configuration' instead.", file=sys.stderr) print(portage.settings["PORTDIR_OVERLAY"]) -def pkgdir(argv): +def pkgdir(_argv): """ Returns the PKGDIR path. """ print(portage.settings["PKGDIR"]) -def distdir(argv): +def distdir(_argv): """ Returns the DISTDIR path. """ print(portage.settings["DISTDIR"]) -def colormap(argv): +def colormap(_argv): """ Display the color.map as environment variables. """ @@ -721,11 +741,15 @@ def envvar(argv): return 2 for arg in argv: + if arg in ("PORTDIR", "PORTDIR_OVERLAY", "SYNC"): + print("WARNING: 'portageq envvar %s' is deprecated. Use 'portageq repositories_configuration' instead." % arg, file=sys.stderr) if verbose: - print(arg +"='"+ portage.settings[arg] +"'") + print(arg + "=" + portage._shell_quote(portage.settings[arg])) else: print(portage.settings[arg]) + +@uses_eroot def get_repos(argv): """<eroot> Returns all repos with names (repo_name file) argv[0] = $EROOT @@ -733,25 +757,137 @@ def get_repos(argv): if len(argv) < 1: print("ERROR: insufficient parameters!") return 2 - print(" ".join(portage.db[argv[0]]["porttree"].dbapi.getRepositories())) + print(" ".join(reversed(portage.db[argv[0]]["vartree"].settings.repositories.prepos_order))) + + +@uses_eroot +def master_repositories(argv): + """<eroot> <repo_id>+ + Returns space-separated list of master repositories for specified repository. + """ + if len(argv) < 2: + print("ERROR: insufficient parameters!", file=sys.stderr) + return 3 + for arg in argv[1:]: + if portage.dep._repo_name_re.match(arg) is None: + print("ERROR: invalid repository: %s" % arg, file=sys.stderr) + return 2 + try: + repo = portage.db[argv[0]]["vartree"].settings.repositories[arg] + except KeyError: + print("") + return 1 + else: + print(" ".join(x.name for x in repo.masters)) -get_repos.uses_root = True +@uses_eroot +def master_repos(argv): + """<eroot> <repo_id>+ + This is an alias for the master_repositories command. + """ + return master_repositories(argv) +@uses_eroot def get_repo_path(argv): """<eroot> <repo_id>+ Returns the path to the repo named argv[1], argv[0] = $EROOT """ if len(argv) < 2: - print("ERROR: insufficient parameters!") - return 2 + print("ERROR: insufficient parameters!", file=sys.stderr) + return 3 for arg in argv[1:]: - path = portage.db[argv[0]]["porttree"].dbapi.getRepositoryPath(arg) + if portage.dep._repo_name_re.match(arg) is None: + print("ERROR: invalid repository: %s" % arg, file=sys.stderr) + return 2 + path = portage.db[argv[0]]["vartree"].settings.repositories.treemap.get(arg) if path is None: - path = "" + print("") + return 1 print(path) -get_repo_path.uses_root = True +@uses_eroot +def available_eclasses(argv): + """<eroot> <repo_id>+ + Returns space-separated list of available eclasses for specified repository. + """ + if len(argv) < 2: + print("ERROR: insufficient parameters!", file=sys.stderr) + return 3 + for arg in argv[1:]: + if portage.dep._repo_name_re.match(arg) is None: + print("ERROR: invalid repository: %s" % arg, file=sys.stderr) + return 2 + try: + repo = portage.db[argv[0]]["vartree"].settings.repositories[arg] + except KeyError: + print("") + return 1 + else: + print(" ".join(sorted(repo.eclass_db.eclasses))) + + +@uses_eroot +def eclass_path(argv): + """<eroot> <repo_id> <eclass>+ + Returns the path to specified eclass for specified repository. + """ + if len(argv) < 3: + print("ERROR: insufficient parameters!", file=sys.stderr) + return 3 + if portage.dep._repo_name_re.match(argv[1]) is None: + print("ERROR: invalid repository: %s" % argv[1], file=sys.stderr) + return 2 + try: + repo = portage.db[argv[0]]["vartree"].settings.repositories[argv[1]] + except KeyError: + print("") + return 1 + else: + retval = 0 + for arg in argv[2:]: + try: + eclass = repo.eclass_db.eclasses[arg] + except KeyError: + print("") + retval = 1 + else: + print(eclass.location) + return retval + + +@uses_eroot +def license_path(argv): + """<eroot> <repo_id> <license>+ + Returns the path to specified license for specified repository. + """ + if len(argv) < 3: + print("ERROR: insufficient parameters!", file=sys.stderr) + return 3 + if portage.dep._repo_name_re.match(argv[1]) is None: + print("ERROR: invalid repository: %s" % argv[1], file=sys.stderr) + return 2 + try: + repo = portage.db[argv[0]]["vartree"].settings.repositories[argv[1]] + except KeyError: + print("") + return 1 + else: + retval = 0 + for arg in argv[2:]: + eclass_path = "" + paths = reversed([os.path.join(x.location, 'licenses', arg) for x in list(repo.masters) + [repo]]) + for path in paths: + if os.path.exists(path): + eclass_path = path + break + if eclass_path == "": + retval = 1 + print(eclass_path) + return retval + + +@uses_eroot def list_preserved_libs(argv): """<eroot> Print a list of libraries preserved during a package update in the form @@ -773,21 +909,296 @@ def list_preserved_libs(argv): msg.append('\n') writemsg_stdout(''.join(msg), noiselevel=-1) return rValue -list_preserved_libs.uses_root = True + + +class MaintainerEmailMatcher(object): + def __init__(self, maintainer_emails): + self._re = re.compile("^(%s)$" % "|".join(maintainer_emails)) + + def __call__(self, metadata_xml): + match = False + matcher = self._re.match + for x in metadata_xml.maintainers(): + if x.email is not None and matcher(x.email) is not None: + match = True + break + return match + +class HerdMatcher(object): + def __init__(self, herds): + self._herds = frozenset(herds) + + def __call__(self, metadata_xml): + herds = self._herds + return any(x in herds for x in metadata_xml.herds()) + + +def pquery(parser, opts, args): + """[options] [atom]+ + Emulates a subset of Pkgcore's pquery tool. + """ + + portdb = portage.db[portage.root]['porttree'].dbapi + root_config = RootConfig(portdb.settings, + portage.db[portage.root], None) + + def _pkg(cpv, repo_name): + try: + metadata = dict(zip( + Package.metadata_keys, + portdb.aux_get(cpv, + Package.metadata_keys, + myrepo=repo_name))) + except KeyError: + raise portage.exception.PackageNotFound(cpv) + return Package(built=False, cpv=cpv, + installed=False, metadata=metadata, + root_config=root_config, + type_name="ebuild") + + need_metadata = False + atoms = [] + for arg in args: + if "/" not in arg.split(":")[0]: + atom = insert_category_into_atom(arg, '*') + if atom is None: + writemsg("ERROR: Invalid atom: '%s'\n" % arg, + noiselevel=-1) + return 2 + else: + atom = arg + + try: + atom = portage.dep.Atom(atom, allow_wildcard=True, allow_repo=True) + except portage.exception.InvalidAtom: + writemsg("ERROR: Invalid atom: '%s'\n" % arg, + noiselevel=-1) + return 2 + + if atom.slot is not None: + need_metadata = True + + atoms.append(atom) + + if "*/*" in atoms: + del atoms[:] + need_metadata = False + + if not opts.no_filters: + need_metadata = True + + xml_matchers = [] + if opts.maintainer_email: + maintainer_emails = [] + for x in opts.maintainer_email: + maintainer_emails.extend(x.split(",")) + xml_matchers.append(MaintainerEmailMatcher(maintainer_emails)) + if opts.herd is not None: + herds = [] + for x in opts.herd: + herds.extend(x.split(",")) + xml_matchers.append(HerdMatcher(herds)) + + repos = [] + if opts.all_repos: + repos.extend(portdb.repositories.get_repo_for_location(location) + for location in portdb.porttrees) + elif opts.repo is not None: + repos.append(portdb.repositories[opts.repo]) + else: + repos.append(portdb.repositories.mainRepo()) + + if not atoms: + names = None + categories = list(portdb.categories) + else: + category_wildcard = False + name_wildcard = False + categories = [] + names = [] + for atom in atoms: + category, name = portage.catsplit(atom.cp) + categories.append(category) + names.append(name) + if "*" in category: + category_wildcard = True + if "*" in name: + name_wildcard = True + + if category_wildcard: + categories = list(portdb.categories) + else: + categories = list(set(categories)) + + if name_wildcard: + names = None + else: + names = sorted(set(names)) + + no_version = opts.no_version + categories.sort() + + for category in categories: + if names is None: + cp_list = portdb.cp_all(categories=(category,)) + else: + cp_list = [category + "/" + name for name in names] + for cp in cp_list: + matches = [] + for repo in repos: + match = True + if xml_matchers: + metadata_xml_path = os.path.join( + repo.location, cp, 'metadata.xml') + try: + metadata_xml = MetaDataXML(metadata_xml_path, None) + except (EnvironmentError, SyntaxError): + match = False + else: + for matcher in xml_matchers: + if not matcher(metadata_xml): + match = False + break + if not match: + continue + cpv_list = portdb.cp_list(cp, mytree=[repo.location]) + if atoms: + for cpv in cpv_list: + pkg = None + for atom in atoms: + if atom.repo is not None and \ + atom.repo != repo.name: + continue + if not portage.match_from_list(atom, [cpv]): + continue + if need_metadata: + if pkg is None: + try: + pkg = _pkg(cpv, repo.name) + except portage.exception.PackageNotFound: + continue + + if not (opts.no_filters or pkg.visible): + continue + if not portage.match_from_list(atom, [pkg]): + continue + matches.append(cpv) + break + if no_version and matches: + break + elif opts.no_filters: + matches.extend(cpv_list) + else: + for cpv in cpv_list: + try: + pkg = _pkg(cpv, repo.name) + except portage.exception.PackageNotFound: + continue + else: + if pkg.visible: + matches.append(cpv) + if no_version: + break + + if no_version and matches: + break + + if not matches: + continue + + if no_version: + writemsg_stdout("%s\n" % (cp,), noiselevel=-1) + else: + matches = list(set(matches)) + portdb._cpv_sort_ascending(matches) + for cpv in matches: + writemsg_stdout("%s\n" % (cpv,), noiselevel=-1) + + return os.EX_OK + #----------------------------------------------------------------------------- # # DO NOT CHANGE CODE BEYOND THIS POINT - IT'S NOT NEEDED! # -if not portage.const._ENABLE_PRESERVE_LIBS: - del list_preserved_libs - -non_commands = frozenset(['elog', 'eval_atom_use', - 'exithandler', 'expand_new_virt', 'main', - 'usage', 'writemsg', 'writemsg_stdout']) +non_commands = frozenset(['elog', 'eval_atom_use', 'exithandler', 'main', 'usage', 'uses_eroot']) commands = sorted(k for k, v in globals().items() \ - if k not in non_commands and isinstance(v, types.FunctionType)) + if k not in non_commands and isinstance(v, types.FunctionType) and v.__module__ == "__main__") + + +def add_pquery_arguments(parser): + pquery_option_groups = ( + ( + 'Repository matching options', + ( + { + "longopt": "--no-filters", + "action": "store_true", + "help": "no visibility filters (ACCEPT_KEYWORDS, package masking, etc)" + }, + { + "longopt": "--repo", + "help": "repo to use (default is PORTDIR if omitted)" + }, + { + "longopt": "--all-repos", + "help": "search all repos" + } + ) + ), + ( + 'Package matching options', + ( + { + "longopt": "--herd", + "action": "append", + "help": "exact match on a herd" + }, + { + "longopt": "--maintainer-email", + "action": "append", + "help": "comma-separated list of maintainer email regexes to search for" + } + ) + ), + ( + 'Output formatting', + ( + { + "shortopt": "-n", + "longopt": "--no-version", + "action": "store_true", + "help": "collapse multiple matching versions together" + }, + ) + ), + ) + + for group_title, opt_data in pquery_option_groups: + arg_group = parser.add_argument_group(group_title) + for opt_info in opt_data: + pargs = [] + try: + pargs.append(opt_info["shortopt"]) + except KeyError: + pass + try: + pargs.append(opt_info["longopt"]) + except KeyError: + pass + + kwargs = {} + try: + kwargs["action"] = opt_info["action"] + except KeyError: + pass + try: + kwargs["help"] = opt_info["help"] + except KeyError: + pass + arg_group.add_argument(*pargs, **portage._native_kwargs(kwargs)) + def usage(argv): print(">>> Portage information query tool") @@ -800,7 +1211,7 @@ def usage(argv): # Show our commands -- we do this by scanning the functions in this # file, and formatting each functions documentation. # - help_mode = '--help' in sys.argv + help_mode = '--help' in argv for name in commands: # Drop non-functions obj = globals()[name] @@ -814,12 +1225,21 @@ def usage(argv): lines = doc.lstrip("\n").split("\n") print(" " + name + " " + lines[0].strip()) - if (len(sys.argv) > 1): + if len(argv) > 1: if (not help_mode): lines = lines[:-1] for line in lines[1:]: print(" " + line.strip()) - if (len(sys.argv) == 1): + + print() + print('Pkgcore pquery compatible options:') + print() + parser = ArgumentParser(add_help=False, + usage='portageq pquery [options] [atom ...]') + add_pquery_arguments(parser) + parser.print_help() + + if len(argv) == 1: print("\nRun portageq with --help for info") atom_validate_strict = "EBUILD_PHASE" in os.environ @@ -838,52 +1258,84 @@ else: def elog(elog_funcname, lines): pass -def main(): +def main(argv): + + argv = portage._decode_argv(argv) nocolor = os.environ.get('NOCOLOR') if nocolor in ('yes', 'true'): portage.output.nocolor() - if len(sys.argv) < 2: - usage(sys.argv) - sys.exit(os.EX_USAGE) + parser = ArgumentParser(add_help=False) - for x in sys.argv: - if x in ("-h", "--help"): - usage(sys.argv) - sys.exit(os.EX_OK) - elif x == "--version": - print("Portage", portage.VERSION) - sys.exit(os.EX_OK) - - cmd = sys.argv[1] - function = globals().get(cmd) - if function is None or cmd not in commands: - usage(sys.argv) + # used by envvar + parser.add_argument("-v", dest="verbose", action="store_true") + + actions = parser.add_argument_group('Actions') + actions.add_argument("-h", "--help", action="store_true") + actions.add_argument("--version", action="store_true") + + add_pquery_arguments(parser) + + opts, args = parser.parse_known_args(argv[1:]) + + if opts.help: + usage(argv) + return os.EX_OK + elif opts.version: + print("Portage", portage.VERSION) + return os.EX_OK + + cmd = None + if args and args[0] in commands: + cmd = args[0] + + if cmd == 'pquery': + cmd = None + args = args[1:] + + if cmd is None: + return pquery(parser, opts, args) + + if opts.verbose: + # used by envvar + args.append("-v") + + argv = argv[:1] + args + + if len(argv) < 2: + usage(argv) sys.exit(os.EX_USAGE) + function = globals()[cmd] - uses_root = getattr(function, "uses_root", False) and len(sys.argv) > 2 - if uses_root: - if not os.path.isdir(sys.argv[2]): - sys.stderr.write("Not a directory: '%s'\n" % sys.argv[2]) + uses_eroot = getattr(function, "uses_eroot", False) and len(argv) > 2 + if uses_eroot: + if not os.path.isdir(argv[2]): + sys.stderr.write("Not a directory: '%s'\n" % argv[2]) sys.stderr.write("Run portageq with --help for info\n") sys.stderr.flush() sys.exit(os.EX_USAGE) - eprefix = portage.const.EPREFIX - eroot = portage.util.normalize_path(sys.argv[2]) + eprefix = portage.settings["EPREFIX"] + eroot = portage.util.normalize_path(argv[2]) + if eprefix: - root = eroot[:1-len(eprefix)] + if not eroot.endswith(eprefix): + sys.stderr.write("ERROR: This version of portageq" + " only supports <eroot>s ending in" + " '%s'. The provided <eroot>, '%s'," + " doesn't.\n" % (eprefix, eroot)) + sys.stderr.flush() + sys.exit(os.EX_USAGE) + root = eroot[:1 - len(eprefix)] else: root = eroot + os.environ["ROOT"] = root - args = sys.argv[2:] - if args and isinstance(args[0], bytes): - for i in range(len(args)): - args[i] = portage._unicode_decode(args[i]) + args = argv[2:] try: - if uses_root: + if uses_eroot: args[0] = portage.settings['EROOT'] retval = function(args) if retval: @@ -904,6 +1356,7 @@ def main(): portage.writemsg("\nPlease use a more specific atom.\n", noiselevel=-1) sys.exit(1) -main() +if __name__ == '__main__': + sys.exit(main(sys.argv)) #----------------------------------------------------------------------------- diff --git a/portage_with_autodep/bin/quickpkg b/portage_with_autodep/bin/quickpkg index d908c03..cf5800c 100755 --- a/portage_with_autodep/bin/quickpkg +++ b/portage_with_autodep/bin/quickpkg @@ -1,33 +1,31 @@ #!/usr/bin/python -# Copyright 1999-2010 Gentoo Foundation +# Copyright 1999-2013 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 from __future__ import print_function import errno import math -import optparse import signal import sys import tarfile -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 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 xpak from portage.dbapi.dep_expand import dep_expand -from portage.dep import Atom, extended_cp_match, use_reduce +from portage.dep import Atom, use_reduce from portage.exception import (AmbiguousPackageName, InvalidAtom, InvalidData, InvalidDependString, PackageSetNotFound, PermissionDenied) from portage.util import ConfigProtect, ensure_dirs, shlex_split from portage.dbapi.vartree import dblink, tar_contents from portage.checksum import perform_md5 from portage._sets import load_default_config, SETPREFIX +from portage.util._argparse import ArgumentParser def quickpkg_atom(options, infos, arg, eout): settings = portage.settings @@ -68,11 +66,14 @@ def quickpkg_atom(options, infos, arg, eout): bintree.prevent_collision(cpv) dblnk = vardb._dblink(cpv) have_lock = False - try: - dblnk.lockdb() - have_lock = True - except PermissionDenied: - pass + + if "__PORTAGE_INHERIT_VARDB_LOCK" not in settings: + try: + dblnk.lockdb() + have_lock = True + except PermissionDenied: + pass + try: if not dblnk.exists(): # unmerged by a concurrent process @@ -201,16 +202,15 @@ def quickpkg_extended_atom(options, infos, atom, eout): atoms.append(cpv_atom) continue - if not extended_cp_match(atom.cp, cpv_atom.cp): + if not portage.match_from_list(atom, [cpv]): continue if require_metadata: - slot, repo = vardb.aux_get(cpv, ["SLOT", "repository"]) - - if atom.slot and atom.slot != slot: + try: + cpv = vardb._pkg_str(cpv, atom.repo) + except (KeyError, InvalidData): continue - - if atom.repo and atom.repo != repo: + if not portage.match_from_list(atom, [cpv]): continue atoms.append(cpv_atom) @@ -289,29 +289,28 @@ def quickpkg_main(options, args, eout): if __name__ == "__main__": usage = "quickpkg [options] <list of package atoms or package sets>" - parser = optparse.OptionParser(usage=usage) - parser.add_option("--umask", + parser = ArgumentParser(usage=usage) + parser.add_argument("--umask", default="0077", help="umask used during package creation (default is 0077)") - parser.add_option("--ignore-default-opts", + parser.add_argument("--ignore-default-opts", action="store_true", help="do not use the QUICKPKG_DEFAULT_OPTS environment variable") - parser.add_option("--include-config", - type="choice", + parser.add_argument("--include-config", choices=["y","n"], default="n", metavar="<y|n>", help="include all files protected by CONFIG_PROTECT (as a security precaution, default is 'n')") - parser.add_option("--include-unmodified-config", - type="choice", + parser.add_argument("--include-unmodified-config", choices=["y","n"], default="n", metavar="<y|n>", help="include files protected by CONFIG_PROTECT that have not been modified since installation (as a security precaution, default is 'n')") - options, args = parser.parse_args(sys.argv[1:]) + options, args = parser.parse_known_args(sys.argv[1:]) if not options.ignore_default_opts: - default_opts = portage.settings.get("QUICKPKG_DEFAULT_OPTS","").split() - options, args = parser.parse_args(default_opts + sys.argv[1:]) + default_opts = shlex_split( + portage.settings.get("QUICKPKG_DEFAULT_OPTS", "")) + options, args = parser.parse_known_args(default_opts + sys.argv[1:]) if not args: parser.error("no packages atoms given") try: diff --git a/portage_with_autodep/bin/regenworld b/portage_with_autodep/bin/regenworld index 3199fdf..f74b3dd 100755 --- a/portage_with_autodep/bin/regenworld +++ b/portage_with_autodep/bin/regenworld @@ -1,17 +1,15 @@ #!/usr/bin/python -# Copyright 1999-2011 Gentoo Foundation +# Copyright 1999-2013 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 from __future__ import print_function import sys -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 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._sets.files import StaticFileSet, WorldSelectedSet diff --git a/portage_with_autodep/bin/repoman b/portage_with_autodep/bin/repoman index fd87847..d1542e9 100755 --- a/portage_with_autodep/bin/repoman +++ b/portage_with_autodep/bin/repoman @@ -1,20 +1,19 @@ #!/usr/bin/python -O -# Copyright 1999-2012 Gentoo Foundation +# Copyright 1999-2013 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 # Next to do: dep syntax checking in mask files # Then, check to make sure deps are satisfiable (to avoid "can't find match for" problems) # that last one is tricky because multiple profiles need to be checked. -from __future__ import print_function +from __future__ import print_function, unicode_literals -import calendar +import codecs import copy import errno import formatter import io import logging -import optparse import re import signal import stat @@ -24,28 +23,29 @@ import tempfile import textwrap import time import platform - -try: - from urllib.request import urlopen as urllib_request_urlopen -except ImportError: - from urllib import urlopen as urllib_request_urlopen - from itertools import chain from stat import S_ISDIR try: - import portage + from urllib.parse import urlparse 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 urlparse import urlparse + +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 portage._disable_legacy_globals() -portage.dep._internal_warnings = True try: import xml.etree.ElementTree from xml.parsers.expat import ExpatError -except (ImportError, SystemError): +except (SystemExit, KeyboardInterrupt): + raise +except (ImportError, SystemError, RuntimeError, Exception): + # broken or missing xml support + # http://bugs.python.org/issue14988 msg = ["Please enable python's \"xml\" USE flag in order to use repoman."] from portage.output import EOutput out = EOutput() @@ -54,9 +54,9 @@ except (ImportError, SystemError): sys.exit(1) from portage import os -from portage import subprocess_getstatusoutput from portage import _encodings from portage import _unicode_encode +import repoman.checks from repoman.checks import run_checks from repoman import utilities from repoman.herdbase import make_herd_base @@ -65,18 +65,18 @@ from _emerge.RootConfig import RootConfig from _emerge.userquery import userquery import portage.checksum import portage.const +import portage.repository.config from portage import cvstree, normalize_path from portage import util -from portage.exception import (FileNotFound, MissingParameter, +from portage.exception import (FileNotFound, InvalidAtom, MissingParameter, ParseError, PermissionDenied) -from portage.manifest import _prohibited_filename_chars_re as \ - disallowed_filename_chars_re +from portage.dep import Atom from portage.process import find_binary, spawn from portage.output import bold, create_color_func, \ green, nocolor, red from portage.output import ConsoleStyleFile, StyleWriter from portage.util import writemsg_level -from portage.util._desktop_entry import validate_desktop_entry +from portage.util._argparse import ArgumentParser from portage.package.ebuild.digestgen import digestgen from portage.eapi import eapi_has_iuse_defaults, eapi_has_required_use @@ -89,6 +89,7 @@ util.initialize_logger() max_desc_len = 100 allowed_filename_chars="a-zA-Z0-9._-+:" pv_toolong_re = re.compile(r'[0-9]{19,}') +GPG_KEY_ID_REGEX = r'(0x)?([0-9a-fA-F]{8}|[0-9a-fA-F]{16}|[0-9a-fA-F]{24}|[0-9a-fA-F]{32}|[0-9a-fA-F]{40})!?' bad = create_color_func("BAD") # A sane umask is needed for files that portage creates. @@ -112,41 +113,14 @@ def err(txt): warn(txt) sys.exit(1) -def exithandler(signum=None, frame=None): +def exithandler(signum=None, _frame=None): logging.fatal("Interrupted; exiting...") if signum is None: sys.exit(1) else: sys.exit(128 + signum) -signal.signal(signal.SIGINT,exithandler) - -class RepomanHelpFormatter(optparse.IndentedHelpFormatter): - """Repoman needs it's own HelpFormatter for now, because the default ones - murder the help text.""" - - def __init__(self, indent_increment=1, max_help_position=24, width=150, short_first=1): - optparse.HelpFormatter.__init__(self, indent_increment, max_help_position, width, short_first) - - def format_description(self, description): - return description - -class RepomanOptionParser(optparse.OptionParser): - """Add the on_tail function, ruby has it, optionParser should too - """ - - def __init__(self, *args, **kwargs): - optparse.OptionParser.__init__(self, *args, **kwargs) - self.tail = "" - - def on_tail(self, description): - self.tail += description - - def format_help(self, formatter=None): - result = optparse.OptionParser.format_help(self, formatter) - result += self.tail - return result - +signal.signal(signal.SIGINT, exithandler) def ParseArgs(argv, qahelp): """This function uses a customized optionParser to parse command line arguments for repoman @@ -157,8 +131,7 @@ def ParseArgs(argv, qahelp): (opts, args), just like a call to parser.parse_args() """ - if argv and isinstance(argv[0], bytes): - argv = [portage._unicode_decode(x) for x in argv] + argv = portage._decode_argv(argv) modes = { 'commit' : 'Run a scan then commit changes', @@ -168,102 +141,103 @@ def ParseArgs(argv, qahelp): 'help' : 'Show this screen', 'manifest' : 'Generate a Manifest (fetches files if necessary)', 'manifest-check' : 'Check Manifests for missing or incorrect digests', - 'scan' : 'Scan directory tree for QA issues' + 'scan' : 'Scan directory tree for QA issues' } mode_keys = list(modes) mode_keys.sort() - parser = RepomanOptionParser(formatter=RepomanHelpFormatter(), usage="%prog [options] [mode]") - parser.description = green(" ".join((os.path.basename(argv[0]), "1.2"))) - parser.description += "\nCopyright 1999-2007 Gentoo Foundation" - parser.description += "\nDistributed under the terms of the GNU General Public License v2" - parser.description += "\nmodes: " + " | ".join(map(green,mode_keys)) + parser = ArgumentParser(usage="repoman [options] [mode]", + description="Modes: %s" % " | ".join(mode_keys), + epilog="For more help consult the man page.") - parser.add_option('-a', '--ask', dest='ask', action='store_true', default=False, + parser.add_argument('-a', '--ask', dest='ask', action='store_true', default=False, help='Request a confirmation before commiting') - parser.add_option('-m', '--commitmsg', dest='commitmsg', + parser.add_argument('-m', '--commitmsg', dest='commitmsg', help='specify a commit message on the command line') - parser.add_option('-M', '--commitmsgfile', dest='commitmsgfile', + parser.add_argument('-M', '--commitmsgfile', dest='commitmsgfile', help='specify a path to a file that contains a commit message') - parser.add_option('--digest', - type='choice', choices=('y', 'n'), metavar='<y|n>', + parser.add_argument('--digest', + choices=('y', 'n'), metavar='<y|n>', help='Automatically update Manifest digests for modified files') - parser.add_option('-p', '--pretend', dest='pretend', default=False, + parser.add_argument('-p', '--pretend', dest='pretend', default=False, action='store_true', help='don\'t commit or fix anything; just show what would be done') - - parser.add_option('-q', '--quiet', dest="quiet", action="count", default=0, + + parser.add_argument('-q', '--quiet', dest="quiet", action="count", default=0, help='do not print unnecessary messages') - parser.add_option( - '--echangelog', type='choice', choices=('y', 'n', 'force'), metavar="<y|n|force>", + parser.add_argument( + '--echangelog', choices=('y', 'n', 'force'), metavar="<y|n|force>", help='for commit mode, call echangelog if ChangeLog is unmodified (or ' 'regardless of modification if \'force\' is specified)') - parser.add_option('-f', '--force', dest='force', default=False, action='store_true', + parser.add_argument('--experimental-inherit', choices=('y', 'n'), + metavar="<y|n>", default='n', + help='Enable experimental inherit.missing checks which may misbehave' + ' when the internal eclass database becomes outdated') + + parser.add_argument('-f', '--force', dest='force', default=False, action='store_true', help='Commit with QA violations') - parser.add_option('--vcs', dest='vcs', + parser.add_argument('--vcs', dest='vcs', help='Force using specific VCS instead of autodetection') - parser.add_option('-v', '--verbose', dest="verbosity", action='count', + parser.add_argument('-v', '--verbose', dest="verbosity", action='count', help='be very verbose in output', default=0) - parser.add_option('-V', '--version', dest='version', action='store_true', + parser.add_argument('-V', '--version', dest='version', action='store_true', help='show version info') - parser.add_option('-x', '--xmlparse', dest='xml_parse', action='store_true', + parser.add_argument('-x', '--xmlparse', dest='xml_parse', action='store_true', default=False, help='forces the metadata.xml parse check to be carried out') - parser.add_option( - '--if-modified', type='choice', choices=('y', 'n'), default='n', + parser.add_argument( + '--if-modified', choices=('y', 'n'), default='n', metavar="<y|n>", help='only check packages that have uncommitted modifications') - parser.add_option('-i', '--ignore-arches', dest='ignore_arches', action='store_true', + parser.add_argument('-i', '--ignore-arches', dest='ignore_arches', action='store_true', default=False, help='ignore arch-specific failures (where arch != host)') - parser.add_option("--ignore-default-opts", + parser.add_argument("--ignore-default-opts", action="store_true", help="do not use the REPOMAN_DEFAULT_OPTS environment variable") - parser.add_option('-I', '--ignore-masked', dest='ignore_masked', action='store_true', + parser.add_argument('-I', '--ignore-masked', dest='ignore_masked', action='store_true', default=False, help='ignore masked packages (not allowed with commit mode)') - parser.add_option('-d', '--include-dev', dest='include_dev', action='store_true', + parser.add_argument('--include-arches', dest='include_arches', + metavar='ARCHES', action='append', + help='A space separated list of arches used to ' + 'filter the selection of profiles for dependency checks') + + parser.add_argument('-d', '--include-dev', dest='include_dev', action='store_true', default=False, help='include dev profiles in dependency checks') - parser.add_option('--unmatched-removal', dest='unmatched_removal', action='store_true', + parser.add_argument('-e', '--include-exp-profiles', choices=('y', 'n'), + default=False, help='include exp profiles in dependency checks', + metavar='<y|n>') + + parser.add_argument('--unmatched-removal', dest='unmatched_removal', action='store_true', default=False, help='enable strict checking of package.mask and package.unmask files for unmatched removal atoms') - parser.add_option('--without-mask', dest='without_mask', action='store_true', + parser.add_argument('--without-mask', dest='without_mask', action='store_true', default=False, help='behave as if no package.mask entries exist (not allowed with commit mode)') - parser.add_option('--mode', type='choice', dest='mode', choices=list(modes), + parser.add_argument('--mode', dest='mode', choices=mode_keys, help='specify which mode repoman will run in (default=full)') - parser.on_tail("\n " + green("Modes".ljust(20) + " Description\n")) - - for k in mode_keys: - parser.on_tail(" %s %s\n" % (k.ljust(20), modes[k])) - - parser.on_tail("\n " + green("QA keyword".ljust(20) + " Description\n")) - - sorted_qa = list(qahelp) - sorted_qa.sort() - for k in sorted_qa: - parser.on_tail(" %s %s\n" % (k.ljust(20), qahelp[k])) - - opts, args = parser.parse_args(argv[1:]) + opts, args = parser.parse_known_args(argv[1:]) if not opts.ignore_default_opts: - default_opts = repoman_settings.get("REPOMAN_DEFAULT_OPTS", "").split() + default_opts = portage.util.shlex_split( + repoman_settings.get("REPOMAN_DEFAULT_OPTS", "")) if default_opts: - opts, args = parser.parse_args(default_opts + sys.argv[1:]) + opts, args = parser.parse_known_args(default_opts + sys.argv[1:]) if opts.mode == 'help': parser.print_help(short=False) @@ -278,16 +252,10 @@ def ParseArgs(argv, qahelp): if not opts.mode: opts.mode = 'full' - + if opts.mode == 'ci': opts.mode = 'commit' # backwards compat shortcut - if opts.mode == 'commit' and not (opts.force or opts.pretend): - if opts.ignore_masked: - parser.error('Commit mode and --ignore-masked are not compatible') - if opts.without_mask: - parser.error('Commit mode and --without-mask are not compatible') - # Use the verbosity and quiet options to fiddle with the loglevel appropriately for val in range(opts.verbosity): logger = logging.getLogger() @@ -297,100 +265,99 @@ def ParseArgs(argv, qahelp): logger = logging.getLogger() logger.setLevel(logger.getEffectiveLevel() + 10) + if opts.mode == 'commit' and not (opts.force or opts.pretend): + if opts.ignore_masked: + opts.ignore_masked = False + logging.warn('Commit mode automatically disables --ignore-masked') + if opts.without_mask: + opts.without_mask = False + logging.warn('Commit mode automatically disables --without-mask') + return (opts, args) -qahelp={ - "CVS/Entries.IO_error":"Attempting to commit, and an IO error was encountered access the Entries file", - "desktop.invalid":"desktop-file-validate reports errors in a *.desktop file", - "ebuild.invalidname":"Ebuild files with a non-parseable or syntactically incorrect name (or using 2.1 versioning extensions)", - "ebuild.namenomatch":"Ebuild files that do not have the same name as their parent directory", - "changelog.ebuildadded":"An ebuild was added but the ChangeLog was not modified", - "changelog.missing":"Missing ChangeLog files", - "ebuild.notadded":"Ebuilds that exist but have not been added to cvs", - "ebuild.patches":"PATCHES variable should be a bash array to ensure white space safety", - "changelog.notadded":"ChangeLogs that exist but have not been added to cvs", - "dependency.unknown" : "Ebuild has a dependency that refers to an unknown package (which may be valid if it is a blocker for a renamed/removed package, or is an alternative choice provided by an overlay)", - "file.executable":"Ebuilds, digests, metadata.xml, Manifest, and ChangeLog do not need the executable bit", - "file.size":"Files in the files directory must be under 20 KiB", - "file.size.fatal":"Files in the files directory must be under 60 KiB", - "file.name":"File/dir name must be composed of only the following chars: %s " % allowed_filename_chars, - "file.UTF8":"File is not UTF8 compliant", - "inherit.autotools":"Ebuild inherits autotools but does not call eautomake, eautoconf or eautoreconf", - "inherit.deprecated":"Ebuild inherits a deprecated eclass", - "java.eclassesnotused":"With virtual/jdk in DEPEND you must inherit a java eclass", - "wxwidgets.eclassnotused":"Ebuild DEPENDs on x11-libs/wxGTK without inheriting wxwidgets.eclass", - "KEYWORDS.dropped":"Ebuilds that appear to have dropped KEYWORDS for some arch", - "KEYWORDS.missing":"Ebuilds that have a missing or empty KEYWORDS variable", - "KEYWORDS.stable":"Ebuilds that have been added directly with stable KEYWORDS", - "KEYWORDS.stupid":"Ebuilds that use KEYWORDS=-* instead of package.mask", - "LICENSE.missing":"Ebuilds that have a missing or empty LICENSE variable", - "LICENSE.virtual":"Virtuals that have a non-empty LICENSE variable", - "DESCRIPTION.missing":"Ebuilds that have a missing or empty DESCRIPTION variable", - "DESCRIPTION.toolong":"DESCRIPTION is over %d characters" % max_desc_len, - "EAPI.definition":"EAPI definition does not conform to PMS section 7.3.1 (first non-comment, non-blank line)", - "EAPI.deprecated":"Ebuilds that use features that are deprecated in the current EAPI", - "EAPI.incompatible":"Ebuilds that use features that are only available with a different EAPI", - "EAPI.unsupported":"Ebuilds that have an unsupported EAPI version (you must upgrade portage)", - "SLOT.invalid":"Ebuilds that have a missing or invalid SLOT variable value", - "HOMEPAGE.missing":"Ebuilds that have a missing or empty HOMEPAGE variable", - "HOMEPAGE.virtual":"Virtuals that have a non-empty HOMEPAGE variable", - "DEPEND.bad":"User-visible ebuilds with bad DEPEND settings (matched against *visible* ebuilds)", - "RDEPEND.bad":"User-visible ebuilds with bad RDEPEND settings (matched against *visible* ebuilds)", - "PDEPEND.bad":"User-visible ebuilds with bad PDEPEND settings (matched against *visible* ebuilds)", - "DEPEND.badmasked":"Masked ebuilds with bad DEPEND settings (matched against *all* ebuilds)", - "RDEPEND.badmasked":"Masked ebuilds with RDEPEND settings (matched against *all* ebuilds)", - "PDEPEND.badmasked":"Masked ebuilds with PDEPEND settings (matched against *all* ebuilds)", - "DEPEND.badindev":"User-visible ebuilds with bad DEPEND settings (matched against *visible* ebuilds) in developing arch", - "RDEPEND.badindev":"User-visible ebuilds with bad RDEPEND settings (matched against *visible* ebuilds) in developing arch", - "PDEPEND.badindev":"User-visible ebuilds with bad PDEPEND settings (matched against *visible* ebuilds) in developing arch", - "DEPEND.badmaskedindev":"Masked ebuilds with bad DEPEND settings (matched against *all* ebuilds) in developing arch", - "RDEPEND.badmaskedindev":"Masked ebuilds with RDEPEND settings (matched against *all* ebuilds) in developing arch", - "PDEPEND.badmaskedindev":"Masked ebuilds with PDEPEND settings (matched against *all* ebuilds) in developing arch", - "PDEPEND.suspect":"PDEPEND contains a package that usually only belongs in DEPEND.", - "DEPEND.syntax":"Syntax error in DEPEND (usually an extra/missing space/parenthesis)", - "RDEPEND.syntax":"Syntax error in RDEPEND (usually an extra/missing space/parenthesis)", - "PDEPEND.syntax":"Syntax error in PDEPEND (usually an extra/missing space/parenthesis)", - "DEPEND.badtilde":"DEPEND uses the ~ dep operator with a non-zero revision part, which is useless (the revision is ignored)", - "RDEPEND.badtilde":"RDEPEND uses the ~ dep operator with a non-zero revision part, which is useless (the revision is ignored)", - "PDEPEND.badtilde":"PDEPEND uses the ~ dep operator with a non-zero revision part, which is useless (the revision is ignored)", - "LICENSE.syntax":"Syntax error in LICENSE (usually an extra/missing space/parenthesis)", - "PROVIDE.syntax":"Syntax error in PROVIDE (usually an extra/missing space/parenthesis)", - "PROPERTIES.syntax":"Syntax error in PROPERTIES (usually an extra/missing space/parenthesis)", - "RESTRICT.syntax":"Syntax error in RESTRICT (usually an extra/missing space/parenthesis)", - "REQUIRED_USE.syntax":"Syntax error in REQUIRED_USE (usually an extra/missing space/parenthesis)", - "SRC_URI.syntax":"Syntax error in SRC_URI (usually an extra/missing space/parenthesis)", - "SRC_URI.mirror":"A uri listed in profiles/thirdpartymirrors is found in SRC_URI", - "ebuild.syntax":"Error generating cache entry for ebuild; typically caused by ebuild syntax error or digest verification failure", - "ebuild.output":"A simple sourcing of the ebuild produces output; this breaks ebuild policy.", - "ebuild.nesteddie":"Placing 'die' inside ( ) prints an error, but doesn't stop the ebuild.", - "variable.invalidchar":"A variable contains an invalid character that is not part of the ASCII character set", - "variable.readonly":"Assigning a readonly variable", - "variable.usedwithhelpers":"Ebuild uses D, ROOT, ED, EROOT or EPREFIX with helpers", - "LIVEVCS.stable":"This ebuild is a live checkout from a VCS but has stable keywords.", - "LIVEVCS.unmasked":"This ebuild is a live checkout from a VCS but has keywords and is not masked in the global package.mask.", - "IUSE.invalid":"This ebuild has a variable in IUSE that is not in the use.desc or its metadata.xml file", - "IUSE.missing":"This ebuild has a USE conditional which references a flag that is not listed in IUSE", - "IUSE.undefined":"This ebuild does not define IUSE (style guideline says to define IUSE even when empty)", - "LICENSE.invalid":"This ebuild is listing a license that doesnt exist in portages license/ dir.", - "KEYWORDS.invalid":"This ebuild contains KEYWORDS that are not listed in profiles/arch.list or for which no valid profile was found", - "RDEPEND.implicit":"RDEPEND is unset in the ebuild which triggers implicit RDEPEND=$DEPEND assignment (prior to EAPI 4)", - "RDEPEND.suspect":"RDEPEND contains a package that usually only belongs in DEPEND.", - "RESTRICT.invalid":"This ebuild contains invalid RESTRICT values.", - "digest.assumed":"Existing digest must be assumed correct (Package level only)", - "digest.missing":"Some files listed in SRC_URI aren't referenced in the Manifest", - "digest.unused":"Some files listed in the Manifest aren't referenced in SRC_URI", - "ebuild.majorsyn":"This ebuild has a major syntax error that may cause the ebuild to fail partially or fully", - "ebuild.minorsyn":"This ebuild has a minor syntax error that contravenes gentoo coding style", - "ebuild.badheader":"This ebuild has a malformed header", - "eprefixify.defined":"The ebuild uses eprefixify, but does not inherit the prefix eclass", - "manifest.bad":"Manifest has missing or incorrect digests", - "metadata.missing":"Missing metadata.xml files", - "metadata.bad":"Bad metadata.xml files", - "metadata.warning":"Warnings in metadata.xml files", - "portage.internal":"The ebuild uses an internal Portage function", - "virtual.oldstyle":"The ebuild PROVIDEs an old-style virtual (see GLEP 37)", - "usage.obsolete":"The ebuild makes use of an obsolete construct", - "upstream.workaround":"The ebuild works around an upstream bug, an upstream bug should be filed and tracked in bugs.gentoo.org" +qahelp = { + "CVS/Entries.IO_error": "Attempting to commit, and an IO error was encountered access the Entries file", + "ebuild.invalidname": "Ebuild files with a non-parseable or syntactically incorrect name (or using 2.1 versioning extensions)", + "ebuild.namenomatch": "Ebuild files that do not have the same name as their parent directory", + "changelog.ebuildadded": "An ebuild was added but the ChangeLog was not modified", + "changelog.missing": "Missing ChangeLog files", + "ebuild.notadded": "Ebuilds that exist but have not been added to cvs", + "ebuild.patches": "PATCHES variable should be a bash array to ensure white space safety", + "changelog.notadded": "ChangeLogs that exist but have not been added to cvs", + "dependency.bad": "User-visible ebuilds with unsatisfied dependencies (matched against *visible* ebuilds)", + "dependency.badmasked": "Masked ebuilds with unsatisfied dependencies (matched against *all* ebuilds)", + "dependency.badindev": "User-visible ebuilds with unsatisfied dependencies (matched against *visible* ebuilds) in developing arch", + "dependency.badmaskedindev": "Masked ebuilds with unsatisfied dependencies (matched against *all* ebuilds) in developing arch", + "dependency.badtilde": "Uses the ~ dep operator with a non-zero revision part, which is useless (the revision is ignored)", + "dependency.syntax": "Syntax error in dependency string (usually an extra/missing space/parenthesis)", + "dependency.unknown": "Ebuild has a dependency that refers to an unknown package (which may be valid if it is a blocker for a renamed/removed package, or is an alternative choice provided by an overlay)", + "file.executable": "Ebuilds, digests, metadata.xml, Manifest, and ChangeLog do not need the executable bit", + "file.size": "Files in the files directory must be under 20 KiB", + "file.size.fatal": "Files in the files directory must be under 60 KiB", + "file.name": "File/dir name must be composed of only the following chars: %s " % allowed_filename_chars, + "file.UTF8": "File is not UTF8 compliant", + "inherit.deprecated": "Ebuild inherits a deprecated eclass", + "inherit.missing": "Ebuild uses functions from an eclass but does not inherit it", + "inherit.unused": "Ebuild inherits an eclass but does not use it", + "java.eclassesnotused": "With virtual/jdk in DEPEND you must inherit a java eclass", + "wxwidgets.eclassnotused": "Ebuild DEPENDs on x11-libs/wxGTK without inheriting wxwidgets.eclass", + "KEYWORDS.dropped": "Ebuilds that appear to have dropped KEYWORDS for some arch", + "KEYWORDS.missing": "Ebuilds that have a missing or empty KEYWORDS variable", + "KEYWORDS.stable": "Ebuilds that have been added directly with stable KEYWORDS", + "KEYWORDS.stupid": "Ebuilds that use KEYWORDS=-* instead of package.mask", + "LICENSE.missing": "Ebuilds that have a missing or empty LICENSE variable", + "LICENSE.virtual": "Virtuals that have a non-empty LICENSE variable", + "DESCRIPTION.missing": "Ebuilds that have a missing or empty DESCRIPTION variable", + "DESCRIPTION.toolong": "DESCRIPTION is over %d characters" % max_desc_len, + "EAPI.definition": "EAPI definition does not conform to PMS section 7.3.1 (first non-comment, non-blank line)", + "EAPI.deprecated": "Ebuilds that use features that are deprecated in the current EAPI", + "EAPI.incompatible": "Ebuilds that use features that are only available with a different EAPI", + "EAPI.unsupported": "Ebuilds that have an unsupported EAPI version (you must upgrade portage)", + "SLOT.invalid": "Ebuilds that have a missing or invalid SLOT variable value", + "HOMEPAGE.missing": "Ebuilds that have a missing or empty HOMEPAGE variable", + "HOMEPAGE.virtual": "Virtuals that have a non-empty HOMEPAGE variable", + "PDEPEND.suspect": "PDEPEND contains a package that usually only belongs in DEPEND.", + "LICENSE.syntax": "Syntax error in LICENSE (usually an extra/missing space/parenthesis)", + "PROVIDE.syntax": "Syntax error in PROVIDE (usually an extra/missing space/parenthesis)", + "PROPERTIES.syntax": "Syntax error in PROPERTIES (usually an extra/missing space/parenthesis)", + "RESTRICT.syntax": "Syntax error in RESTRICT (usually an extra/missing space/parenthesis)", + "REQUIRED_USE.syntax": "Syntax error in REQUIRED_USE (usually an extra/missing space/parenthesis)", + "SRC_URI.syntax": "Syntax error in SRC_URI (usually an extra/missing space/parenthesis)", + "SRC_URI.mirror": "A uri listed in profiles/thirdpartymirrors is found in SRC_URI", + "ebuild.syntax": "Error generating cache entry for ebuild; typically caused by ebuild syntax error or digest verification failure", + "ebuild.output": "A simple sourcing of the ebuild produces output; this breaks ebuild policy.", + "ebuild.nesteddie": "Placing 'die' inside ( ) prints an error, but doesn't stop the ebuild.", + "variable.invalidchar": "A variable contains an invalid character that is not part of the ASCII character set", + "variable.readonly": "Assigning a readonly variable", + "variable.usedwithhelpers": "Ebuild uses D, ROOT, ED, EROOT or EPREFIX with helpers", + "LIVEVCS.stable": "This ebuild is a live checkout from a VCS but has stable keywords.", + "LIVEVCS.unmasked": "This ebuild is a live checkout from a VCS but has keywords and is not masked in the global package.mask.", + "IUSE.invalid": "This ebuild has a variable in IUSE that is not in the use.desc or its metadata.xml file", + "IUSE.missing": "This ebuild has a USE conditional which references a flag that is not listed in IUSE", + "IUSE.rubydeprecated": "The ebuild has set a ruby interpreter in USE_RUBY, that is not available as a ruby target anymore", + "LICENSE.invalid": "This ebuild is listing a license that doesnt exist in portages license/ dir.", + "LICENSE.deprecated": "This ebuild is listing a deprecated license.", + "KEYWORDS.invalid": "This ebuild contains KEYWORDS that are not listed in profiles/arch.list or for which no valid profile was found", + "RDEPEND.implicit": "RDEPEND is unset in the ebuild which triggers implicit RDEPEND=$DEPEND assignment (prior to EAPI 4)", + "RDEPEND.suspect": "RDEPEND contains a package that usually only belongs in DEPEND.", + "RESTRICT.invalid": "This ebuild contains invalid RESTRICT values.", + "digest.assumed": "Existing digest must be assumed correct (Package level only)", + "digest.missing": "Some files listed in SRC_URI aren't referenced in the Manifest", + "digest.unused": "Some files listed in the Manifest aren't referenced in SRC_URI", + "ebuild.majorsyn": "This ebuild has a major syntax error that may cause the ebuild to fail partially or fully", + "ebuild.minorsyn": "This ebuild has a minor syntax error that contravenes gentoo coding style", + "ebuild.badheader": "This ebuild has a malformed header", + "manifest.bad": "Manifest has missing or incorrect digests", + "metadata.missing": "Missing metadata.xml files", + "metadata.bad": "Bad metadata.xml files", + "metadata.warning": "Warnings in metadata.xml files", + "portage.internal": "The ebuild uses an internal Portage function or variable", + "repo.eapi.banned": "The ebuild uses an EAPI which is banned by the repository's metadata/layout.conf settings", + "repo.eapi.deprecated": "The ebuild uses an EAPI which is deprecated by the repository's metadata/layout.conf settings", + "virtual.oldstyle": "The ebuild PROVIDEs an old-style virtual (see GLEP 37)", + "virtual.suspect": "Ebuild contains a package that usually should be pulled via virtual/, not directly.", + "usage.obsolete": "The ebuild makes use of an obsolete construct", + "upstream.workaround": "The ebuild works around an upstream bug, an upstream bug should be filed and tracked in bugs.gentoo.org" } qacats = list(qahelp) @@ -404,37 +371,39 @@ qawarnings = set(( "digest.unused", "ebuild.notadded", "ebuild.nesteddie", -"desktop.invalid", -"DEPEND.badmasked","RDEPEND.badmasked","PDEPEND.badmasked", -"DEPEND.badindev","RDEPEND.badindev","PDEPEND.badindev", -"DEPEND.badmaskedindev","RDEPEND.badmaskedindev","PDEPEND.badmaskedindev", -"DEPEND.badtilde", "RDEPEND.badtilde", "PDEPEND.badtilde", +"dependency.badmasked", +"dependency.badindev", +"dependency.badmaskedindev", +"dependency.badtilde", "DESCRIPTION.toolong", "EAPI.deprecated", "HOMEPAGE.virtual", +"LICENSE.deprecated", "LICENSE.virtual", "KEYWORDS.dropped", "KEYWORDS.stupid", "KEYWORDS.missing", -"IUSE.undefined", "PDEPEND.suspect", "RDEPEND.implicit", "RDEPEND.suspect", +"virtual.suspect", "RESTRICT.invalid", "ebuild.minorsyn", "ebuild.badheader", "ebuild.patches", "file.size", -"inherit.autotools", +"inherit.unused", "inherit.deprecated", "java.eclassesnotused", "wxwidgets.eclassnotused", "metadata.warning", "portage.internal", +"repo.eapi.deprecated", "usage.obsolete", "upstream.workaround", "LIVEVCS.stable", "LIVEVCS.unmasked", +"IUSE.rubydeprecated", )) non_ascii_re = re.compile(r'[^\x00-\x7f]') @@ -443,7 +412,7 @@ missingvars = ["KEYWORDS", "LICENSE", "DESCRIPTION", "HOMEPAGE"] allvars = set(x for x in portage.auxdbkeys if not x.startswith("UNUSED_")) allvars.update(Package.metadata_keys) allvars = sorted(allvars) -commitmessage=None +commitmessage = None for x in missingvars: x += ".missing" if x not in qacats: @@ -452,19 +421,10 @@ for x in missingvars: qawarnings.add(x) valid_restrict = frozenset(["binchecks", "bindist", - "fetch", "installsources", "mirror", - "primaryuri", "strip", "test", "userpriv"]) - -live_eclasses = frozenset([ - "bzr", - "cvs", - "darcs", - "git", - "git-2", - "mercurial", - "subversion", - "tla", -]) + "fetch", "installsources", "mirror", "preserve-libs", + "primaryuri", "splitdebug", "strip", "test", "userpriv"]) + +live_eclasses = portage.const.LIVE_ECLASSES suspect_rdepend = frozenset([ "app-arch/cabextract", @@ -482,7 +442,10 @@ suspect_rdepend = frozenset([ "dev-util/gtk-doc-am", "dev-util/intltool", "dev-util/jam", + "dev-util/pkg-config-lite", + "dev-util/pkgconf", "dev-util/pkgconfig", + "dev-util/pkgconfig-openbsd", "dev-util/scons", "dev-util/unifdef", "dev-util/yacc", @@ -497,16 +460,35 @@ suspect_rdepend = frozenset([ "sys-devel/m4", "sys-devel/pmake", "virtual/linux-sources", + "virtual/pkgconfig", "x11-misc/bdftopcf", "x11-misc/imake", ]) +suspect_virtual = { + "dev-util/pkg-config-lite":"virtual/pkgconfig", + "dev-util/pkgconf":"virtual/pkgconfig", + "dev-util/pkgconfig":"virtual/pkgconfig", + "dev-util/pkgconfig-openbsd":"virtual/pkgconfig", + "dev-libs/libusb":"virtual/libusb", + "dev-libs/libusbx":"virtual/libusb", + "dev-libs/libusb-compat":"virtual/libusb", +} + +ruby_deprecated = frozenset([ + "ruby_targets_ree18", +]) + +metadata_xml_encoding = 'UTF-8' +metadata_xml_declaration = '<?xml version="1.0" encoding="%s"?>' % \ + (metadata_xml_encoding,) +metadata_doctype_name = 'pkgmetadata' metadata_dtd_uri = 'http://www.gentoo.org/dtd/metadata.dtd' # force refetch if the local copy creation time is older than this metadata_dtd_ctime_interval = 60 * 60 * 24 * 7 # 7 days # file.executable -no_exec = frozenset(["Manifest","ChangeLog","metadata.xml"]) +no_exec = frozenset(["Manifest", "ChangeLog", "metadata.xml"]) options, arguments = ParseArgs(sys.argv, qahelp) @@ -514,6 +496,11 @@ if options.version: print("Portage", portage.VERSION) sys.exit(0) +if options.experimental_inherit == 'y': + # This is experimental, so it's non-fatal. + qawarnings.add("inherit.missing") + repoman.checks._init(experimental_inherit=True) + # Set this to False when an extraordinary issue (generally # something other than a QA issue) makes it impossible to # commit (like if Manifest generation fails). @@ -563,14 +550,29 @@ if options.mode == 'commit' and not options.pretend and not vcs: logging.info("Not in a version controlled repository; enabling pretend mode.") options.pretend = True -# Ensure that PORTDIR_OVERLAY contains the repository corresponding to $PWD. -repoman_settings['PORTDIR_OVERLAY'] = "%s %s" % \ - (repoman_settings.get('PORTDIR_OVERLAY', ''), - portage._shell_quote(portdir_overlay)) -# We have to call the config constructor again so -# that config.repositories is initialized correctly. -repoman_settings = portage.config(config_root=config_root, local_config=False, - env=dict(os.environ, PORTDIR_OVERLAY=repoman_settings['PORTDIR_OVERLAY'])) +# Ensure that current repository is in the list of enabled repositories. +repodir = os.path.realpath(portdir_overlay) +try: + repoman_settings.repositories.get_repo_for_location(repodir) +except KeyError: + repo_name = portage.repository.config.RepoConfig._read_valid_repo_name(portdir_overlay)[0] + layout_conf_data = portage.repository.config.parse_layout_conf(portdir_overlay)[0] + if layout_conf_data['repo-name']: + repo_name = layout_conf_data['repo-name'] + tmp_conf_file = io.StringIO(textwrap.dedent(""" + [%s] + location = %s + """) % (repo_name, portdir_overlay)) + # Ensure that the repository corresponding to $PWD overrides a + # repository of the same name referenced by the existing PORTDIR + # or PORTDIR_OVERLAY settings. + repoman_settings['PORTDIR_OVERLAY'] = "%s %s" % \ + (repoman_settings.get('PORTDIR_OVERLAY', ''), + portage._shell_quote(portdir_overlay)) + repositories = portage.repository.config.load_repository_config(repoman_settings, extra_files=[tmp_conf_file]) + # We have to call the config constructor again so that attributes + # dependent on config.repositories are initialized correctly. + repoman_settings = portage.config(config_root=config_root, local_config=False, repositories=repositories) root = repoman_settings['EROOT'] trees = { @@ -580,10 +582,15 @@ portdb = trees[root]['porttree'].dbapi # Constrain dependency resolution to the master(s) # that are specified in layout.conf. -repodir = os.path.realpath(portdir_overlay) repo_config = repoman_settings.repositories.get_repo_for_location(repodir) portdb.porttrees = list(repo_config.eclass_db.porttrees) portdir = portdb.porttrees[0] +commit_env = os.environ.copy() +# list() is for iteration on a copy. +for repo in list(repoman_settings.repositories): + # all paths are canonical + if repo.location not in repo_config.eclass_db.porttrees: + del repoman_settings.repositories[repo.name] if repo_config.allow_provide_virtual: qawarnings.add("virtual.oldstyle") @@ -594,6 +601,15 @@ if repo_config.sign_commit: # the commit arguments. If key_id is unspecified, then it must be # configured by `git config user.signingkey key_id`. vcs_local_opts.append("--gpg-sign") + if repoman_settings.get("PORTAGE_GPG_DIR"): + # Pass GNUPGHOME to git for bug #462362. + commit_env["GNUPGHOME"] = repoman_settings["PORTAGE_GPG_DIR"] + + # Pass GPG_TTY to git for bug #477728. + try: + commit_env["GPG_TTY"] = os.ttyname(sys.stdin.fileno()) + except OSError: + pass # In order to disable manifest signatures, repos may set # "sign-manifests = false" in metadata/layout.conf. This @@ -602,6 +618,25 @@ if repo_config.sign_commit: sign_manifests = "sign" in repoman_settings.features and \ repo_config.sign_manifest +if repo_config.sign_manifest and repo_config.name == "gentoo" and \ + options.mode in ("commit",) and not sign_manifests: + msg = ("The '%s' repository has manifest signatures enabled, " + "but FEATURES=sign is currently disabled. In order to avoid this " + "warning, enable FEATURES=sign in make.conf. Alternatively, " + "repositories can disable manifest signatures by setting " + "'sign-manifests = false' in metadata/layout.conf.") % \ + (repo_config.name,) + for line in textwrap.wrap(msg, 60): + logging.warn(line) + +if sign_manifests and options.mode in ("commit",) and \ + repoman_settings.get("PORTAGE_GPG_KEY") and \ + re.match(r'^%s$' % GPG_KEY_ID_REGEX, + repoman_settings["PORTAGE_GPG_KEY"]) is None: + logging.error("PORTAGE_GPG_KEY value is invalid: %s" % + repoman_settings["PORTAGE_GPG_KEY"]) + sys.exit(1) + manifest_hashes = repo_config.manifest_hashes if manifest_hashes is None: manifest_hashes = portage.const.MANIFEST2_HASH_DEFAULTS @@ -631,19 +666,6 @@ if options.mode in ("commit", "fix", "manifest"): logging.error(line) sys.exit(1) -if "commit" == options.mode and \ - repo_config.name == "gentoo" and \ - "RMD160" in manifest_hashes and \ - "RMD160" not in portage.checksum.hashorigin_map: - msg = "Please install " \ - "pycrypto or enable python's ssl USE flag in order " \ - "to enable RMD160 hash support. See bug #198398 for " \ - "more information." - prefix = bad(" * ") - for line in textwrap.wrap(msg, 70): - print(prefix + line) - sys.exit(1) - if options.echangelog is None and repo_config.update_changelog: options.echangelog = 'y' @@ -668,18 +690,9 @@ logging.debug("vcs: %s" % (vcs,)) logging.debug("repo config: %s" % (repo_config,)) logging.debug("options: %s" % (options,)) -# Generate an appropriate PORTDIR_OVERLAY value for passing into the -# profile-specific config constructor calls. -env = os.environ.copy() -env['PORTDIR'] = portdir -env['PORTDIR_OVERLAY'] = ' '.join(portdb.porttrees[1:]) - -logging.info('Setting paths:') -logging.info('PORTDIR = "' + portdir + '"') -logging.info('PORTDIR_OVERLAY = "%s"' % env['PORTDIR_OVERLAY']) - # It's confusing if these warnings are displayed without the user # being told which profile they come from, so disable them. +env = os.environ.copy() env['FEATURES'] = env.get('FEATURES', '') + ' -unknown-features-warn' categories = [] @@ -703,7 +716,7 @@ repolevel = len(reposplit) # check if it's in $PORTDIR/$CATEGORY/$PN , otherwise bail if commiting. # Reason for this is if they're trying to commit in just $FILESDIR/*, the Manifest needs updating. # this check ensures that repoman knows where it is, and the manifest recommit is at least possible. -if options.mode == 'commit' and repolevel not in [1,2,3]: +if options.mode == 'commit' and repolevel not in [1, 2, 3]: print(red("***")+" Commit attempts *must* be from within a vcs co, category, or package directory.") print(red("***")+" Attempting to commit from a packages files directory will be blocked for instance.") print(red("***")+" This is intended behaviour, to ensure the manifest is recommitted for a package.") @@ -716,10 +729,76 @@ if repolevel == 1: startdir = repodir else: startdir = normalize_path(mydir) - startdir = os.path.join(repodir, *startdir.split(os.sep)[-2-repolevel+3:]) + startdir = os.path.join(repodir, *startdir.split(os.sep)[-2 - repolevel + 3:]) def caterror(mycat): - err(mycat+" is not an official category. Skipping QA checks in this directory.\nPlease ensure that you add "+catdir+" to "+repodir+"/profiles/categories\nif it is a new category.") + err(mycat + " is not an official category. Skipping QA checks in this directory.\nPlease ensure that you add " + catdir + " to " + repodir + "/profiles/categories\nif it is a new category.") + +def repoman_getstatusoutput(cmd): + """ + Implements an interface similar to getstatusoutput(), but with + customized unicode handling (see bug #310789) and without the shell. + """ + args = portage.util.shlex_split(cmd) + + if sys.hexversion < 0x3020000 and sys.hexversion >= 0x3000000 and \ + not os.path.isabs(args[0]): + # Python 3.1 _execvp throws TypeError for non-absolute executable + # path passed as bytes (see http://bugs.python.org/issue8513). + fullname = find_binary(args[0]) + if fullname is None: + raise portage.exception.CommandNotFound(args[0]) + args[0] = fullname + + encoding = _encodings['fs'] + args = [_unicode_encode(x, + encoding=encoding, errors='strict') for x in args] + proc = subprocess.Popen(args, stdout=subprocess.PIPE, + stderr=subprocess.STDOUT) + output = portage._unicode_decode(proc.communicate()[0], + encoding=encoding, errors='strict') + if output and output[-1] == "\n": + # getstatusoutput strips one newline + output = output[:-1] + return (proc.wait(), output) + +class repoman_popen(portage.proxy.objectproxy.ObjectProxy): + """ + Implements an interface similar to os.popen(), but with customized + unicode handling (see bug #310789) and without the shell. + """ + + __slots__ = ('_proc', '_stdout') + + def __init__(self, cmd): + args = portage.util.shlex_split(cmd) + + if sys.hexversion < 0x3020000 and sys.hexversion >= 0x3000000 and \ + not os.path.isabs(args[0]): + # Python 3.1 _execvp throws TypeError for non-absolute executable + # path passed as bytes (see http://bugs.python.org/issue8513). + fullname = find_binary(args[0]) + if fullname is None: + raise portage.exception.CommandNotFound(args[0]) + args[0] = fullname + + encoding = _encodings['fs'] + args = [_unicode_encode(x, + encoding=encoding, errors='strict') for x in args] + proc = subprocess.Popen(args, stdout=subprocess.PIPE) + object.__setattr__(self, '_proc', proc) + object.__setattr__(self, '_stdout', + codecs.getreader(encoding)(proc.stdout, 'strict')) + + def _get_target(self): + return object.__getattribute__(self, '_stdout') + + __enter__ = _get_target + + def __exit__(self, exc_type, exc_value, traceback): + proc = object.__getattribute__(self, '_proc') + proc.wait() + proc.stdout.close() class ProfileDesc(object): __slots__ = ('abs_path', 'arch', 'status', 'sub_path', 'tree_path',) @@ -797,18 +876,18 @@ for path in portdb.porttrees: continue if len(arch) != 3: err("wrong format: \"" + bad(x.strip()) + "\" in " + \ - desc_path + " line %d" % (i+1, )) + desc_path + " line %d" % (i + 1, )) elif arch[0] not in kwlist: err("invalid arch: \"" + bad(arch[0]) + "\" in " + \ - desc_path + " line %d" % (i+1, )) + desc_path + " line %d" % (i + 1, )) elif arch[2] not in valid_profile_types: err("invalid profile type: \"" + bad(arch[2]) + "\" in " + \ - desc_path + " line %d" % (i+1, )) + desc_path + " line %d" % (i + 1, )) profile_desc = ProfileDesc(arch[0], arch[2], arch[1], path) if not os.path.isdir(profile_desc.abs_path): logging.error( "Invalid %s profile (%s) for arch %s in %s line %d", - arch[2], arch[1], arch[0], desc_path, i+1) + arch[2], arch[1], arch[0], desc_path, i + 1) continue if os.path.exists( os.path.join(profile_desc.abs_path, 'deprecated')): @@ -855,11 +934,16 @@ for x in repoman_settings.archlist(): if x[0] == "~": continue if x not in profiles: - print(red("\""+x+"\" doesn't have a valid profile listed in profiles.desc.")) + print(red("\"" + x + "\" doesn't have a valid profile listed in profiles.desc.")) print(red("You need to either \"cvs update\" your profiles dir or follow this")) - print(red("up with the "+x+" team.")) + print(red("up with the " + x + " team.")) print() +liclist_deprecated = set() +if "DEPRECATED" in repoman_settings._license_manager._license_groups: + liclist_deprecated.update( + repoman_settings._license_manager.expandLicenseTokens(["@DEPRECATED"])) + if not liclist: logging.fatal("Couldn't find licenses?") sys.exit(1) @@ -872,34 +956,34 @@ if not uselist: logging.fatal("Couldn't find use.desc?") sys.exit(1) -scanlist=[] -if repolevel==2: - #we are inside a category directory - catdir=reposplit[-1] +scanlist = [] +if repolevel == 2: + # we are inside a category directory + catdir = reposplit[-1] if catdir not in categories: caterror(catdir) - mydirlist=os.listdir(startdir) + mydirlist = os.listdir(startdir) for x in mydirlist: if x == "CVS" or x.startswith("."): continue - if os.path.isdir(startdir+"/"+x): - scanlist.append(catdir+"/"+x) + if os.path.isdir(startdir + "/" + x): + scanlist.append(catdir + "/" + x) repo_subdir = catdir + os.sep -elif repolevel==1: +elif repolevel == 1: for x in categories: - if not os.path.isdir(startdir+"/"+x): + if not os.path.isdir(startdir + "/" + x): continue - for y in os.listdir(startdir+"/"+x): + for y in os.listdir(startdir + "/" + x): if y == "CVS" or y.startswith("."): continue - if os.path.isdir(startdir+"/"+x+"/"+y): - scanlist.append(x+"/"+y) + if os.path.isdir(startdir + "/" + x + "/" + y): + scanlist.append(x + "/" + y) repo_subdir = "" -elif repolevel==3: +elif repolevel == 3: catdir = reposplit[-2] if catdir not in categories: caterror(catdir) - scanlist.append(catdir+"/"+reposplit[-1]) + scanlist.append(catdir + "/" + reposplit[-1]) repo_subdir = scanlist[-1] + os.sep else: msg = 'Repoman is unable to determine PORTDIR or PORTDIR_OVERLAY' + \ @@ -931,7 +1015,7 @@ def vcs_files_to_cps(vcs_file_iter): if category in categories: for filename in vcs_file_iter: f_split = filename.split(os.sep) - # ['.', pn,...] + # ['.', pn, ...] if len(f_split) > 2: modified_cps.append(category + "/" + f_split[1]) @@ -939,7 +1023,7 @@ def vcs_files_to_cps(vcs_file_iter): # repolevel == 1 for filename in vcs_file_iter: f_split = filename.split(os.sep) - # ['.', category, pn,...] + # ['.', category, pn, ...] if len(f_split) > 3 and f_split[1] in categories: modified_cps.append("/".join(f_split[1:3])) @@ -947,12 +1031,12 @@ def vcs_files_to_cps(vcs_file_iter): def git_supports_gpg_sign(): status, cmd_output = \ - subprocess_getstatusoutput("git --version") + repoman_getstatusoutput("git --version") cmd_output = cmd_output.split() if cmd_output: version = re.match(r'^(\d+)\.(\d+)\.(\d+)', cmd_output[-1]) if version is not None: - version = [int(x) for x in version.groups()[1:]] + version = [int(x) for x in version.groups()] if version[0] > 1 or \ (version[0] == 1 and version[1] > 7) or \ (version[0] == 1 and version[1] == 7 and version[2] >= 9): @@ -981,47 +1065,16 @@ def dev_keywords(profiles): dev_keywords = dev_keywords(profiles) -stats={} -fails={} - -# provided by the desktop-file-utils package -desktop_file_validate = find_binary("desktop-file-validate") -desktop_pattern = re.compile(r'.*\.desktop$') +stats = {} +fails = {} for x in qacats: - stats[x]=0 - fails[x]=[] + stats[x] = 0 + fails[x] = [] xmllint_capable = False metadata_dtd = os.path.join(repoman_settings["DISTDIR"], 'metadata.dtd') -def parsedate(s): - """Parse a RFC 822 date and time string. - This is required for python3 compatibility, since the - rfc822.parsedate() function is not available.""" - - s_split = [] - for x in s.upper().split(): - for y in x.split(','): - if y: - s_split.append(y) - - if len(s_split) != 6: - return None - - # %a, %d %b %Y %H:%M:%S %Z - a, d, b, Y, H_M_S, Z = s_split - - # Convert month to integer, since strptime %w is locale-dependent. - month_map = {'JAN':1, 'FEB':2, 'MAR':3, 'APR':4, 'MAY':5, 'JUN':6, - 'JUL':7, 'AUG':8, 'SEP':9, 'OCT':10, 'NOV':11, 'DEC':12} - m = month_map.get(b) - if m is None: - return None - m = str(m).rjust(2, '0') - - return time.strptime(':'.join((Y, m, d, H_M_S)), '%Y:%m:%d:%H:%M:%S') - def fetch_metadata_dtd(): """ Fetch metadata.dtd if it doesn't exist or the ctime is older than @@ -1050,45 +1103,40 @@ def fetch_metadata_dtd(): print(green("***") + " the local copy of metadata.dtd " + \ "needs to be refetched, doing that now") print() + parsed_url = urlparse(metadata_dtd_uri) + setting = 'FETCHCOMMAND_' + parsed_url.scheme.upper() + fcmd = repoman_settings.get(setting) + if not fcmd: + fcmd = repoman_settings.get('FETCHCOMMAND') + if not fcmd: + logging.error("FETCHCOMMAND is unset") + return False + + destdir = repoman_settings["DISTDIR"] + fd, metadata_dtd_tmp = tempfile.mkstemp( + prefix='metadata.dtd.', dir=destdir) + os.close(fd) + try: - url_f = urllib_request_urlopen(metadata_dtd_uri) - msg_info = url_f.info() - last_modified = msg_info.get('last-modified') - if last_modified is not None: - last_modified = parsedate(last_modified) - if last_modified is not None: - last_modified = calendar.timegm(last_modified) - - metadata_dtd_tmp = "%s.%s" % (metadata_dtd, os.getpid()) - try: - local_f = open(metadata_dtd_tmp, mode='wb') - local_f.write(url_f.read()) - local_f.close() - if last_modified is not None: - try: - os.utime(metadata_dtd_tmp, - (int(last_modified), int(last_modified))) - except OSError: - # This fails on some odd non-unix-like filesystems. - # We don't really need the mtime to be preserved - # anyway here (currently we use ctime to trigger - # fetch), so just ignore it. - pass - os.rename(metadata_dtd_tmp, metadata_dtd) - finally: - try: - os.unlink(metadata_dtd_tmp) - except OSError: - pass + if not portage.getbinpkg.file_get(metadata_dtd_uri, + destdir, fcmd=fcmd, + filename=os.path.basename(metadata_dtd_tmp)): + logging.error("failed to fetch metadata.dtd from '%s'" % + metadata_dtd_uri) + return False - url_f.close() + try: + portage.util.apply_secpass_permissions(metadata_dtd_tmp, + gid=portage.data.portage_gid, mode=0o664, mask=0o2) + except portage.exception.PortageException: + pass - except EnvironmentError as e: - print() - print(red("!!!")+" attempting to fetch '%s', caught" % metadata_dtd_uri) - print(red("!!!")+" exception '%s' though." % (e,)) - print(red("!!!")+" fetching new metadata.dtd failed, aborting") - return False + os.rename(metadata_dtd_tmp, metadata_dtd) + finally: + try: + os.unlink(metadata_dtd_tmp) + except OSError: + pass return True @@ -1096,14 +1144,14 @@ if options.mode == "manifest": pass elif not find_binary('xmllint'): print(red("!!! xmllint not found. Can't check metadata.xml.\n")) - if options.xml_parse or repolevel==3: + if options.xml_parse or repolevel == 3: print(red("!!!")+" sorry, xmllint is needed. failing\n") sys.exit(1) else: if not fetch_metadata_dtd(): sys.exit(1) - #this can be problematic if xmllint changes their output - xmllint_capable=True + # this can be problematic if xmllint changes their output + xmllint_capable = True if options.mode == 'commit' and vcs: utilities.detect_vcs_conflicts(options, vcs) @@ -1130,45 +1178,46 @@ if vcs == "cvs": myremoved = cvstree.findremoved(mycvstree, recursive=1, basedir="./") elif vcs == "svn": - with os.popen("svn status") as f: + with repoman_popen("svn status") as f: svnstatus = f.readlines() - mychanged = [ "./" + elem.split()[-1:][0] for elem in svnstatus if elem and elem[:1] in "MR" ] - mynew = [ "./" + elem.split()[-1:][0] for elem in svnstatus if elem.startswith("A") ] + mychanged = ["./" + elem.split()[-1:][0] for elem in svnstatus if elem and elem[:1] in "MR"] + mynew = ["./" + elem.split()[-1:][0] for elem in svnstatus if elem.startswith("A")] if options.if_modified == "y": - myremoved = [ "./" + elem.split()[-1:][0] for elem in svnstatus if elem.startswith("D")] + myremoved = ["./" + elem.split()[-1:][0] for elem in svnstatus if elem.startswith("D")] elif vcs == "git": - with os.popen("git diff-index --name-only " + with repoman_popen("git diff-index --name-only " "--relative --diff-filter=M HEAD") as f: mychanged = f.readlines() mychanged = ["./" + elem[:-1] for elem in mychanged] - with os.popen("git diff-index --name-only " + with repoman_popen("git diff-index --name-only " "--relative --diff-filter=A HEAD") as f: mynew = f.readlines() mynew = ["./" + elem[:-1] for elem in mynew] if options.if_modified == "y": - with os.popen("git diff-index --name-only " + with repoman_popen("git diff-index --name-only " "--relative --diff-filter=D HEAD") as f: myremoved = f.readlines() myremoved = ["./" + elem[:-1] for elem in myremoved] elif vcs == "bzr": - with os.popen("bzr status -S .") as f: + with repoman_popen("bzr status -S .") as f: bzrstatus = f.readlines() - mychanged = [ "./" + elem.split()[-1:][0].split('/')[-1:][0] for elem in bzrstatus if elem and elem[1:2] == "M" ] - mynew = [ "./" + elem.split()[-1:][0].split('/')[-1:][0] for elem in bzrstatus if elem and ( elem[1:2] == "NK" or elem[0:1] == "R" ) ] + mychanged = ["./" + elem.split()[-1:][0].split('/')[-1:][0] for elem in bzrstatus if elem and elem[1:2] == "M"] + mynew = ["./" + elem.split()[-1:][0].split('/')[-1:][0] for elem in bzrstatus if elem and (elem[1:2] == "NK" or elem[0:1] == "R")] if options.if_modified == "y": - myremoved = [ "./" + elem.split()[-3:-2][0].split('/')[-1:][0] for elem in bzrstatus if elem and ( elem[1:2] == "K" or elem[0:1] == "R" ) ] + myremoved = ["./" + elem.split()[-3:-2][0].split('/')[-1:][0] for elem in bzrstatus if elem and (elem[1:2] == "K" or elem[0:1] == "R")] elif vcs == "hg": - with os.popen("hg status --no-status --modified .") as f: + with repoman_popen("hg status --no-status --modified .") as f: mychanged = f.readlines() mychanged = ["./" + elem.rstrip() for elem in mychanged] - mynew = os.popen("hg status --no-status --added .").readlines() + with repoman_popen("hg status --no-status --added .") as f: + mynew = f.readlines() mynew = ["./" + elem.rstrip() for elem in mynew] if options.if_modified == "y": - with os.popen("hg status --no-status --removed .") as f: + with repoman_popen("hg status --no-status --removed .") as f: myremoved = f.readlines() myremoved = ["./" + elem.rstrip() for elem in myremoved] @@ -1190,10 +1239,15 @@ dofail = 0 # NOTE: match-all caches are not shared due to potential # differences between profiles in _get_implicit_iuse. -arch_caches={} +arch_caches = {} arch_xmatch_caches = {} shared_xmatch_caches = {"cp-list":{}} +include_arches = None +if options.include_arches: + include_arches = set() + include_arches.update(*[x.split() for x in options.include_arches]) + # Disable the "ebuild.notadded" check when not in commit mode and # running `svn status` in every package dir will be too expensive. @@ -1201,12 +1255,37 @@ check_ebuild_notadded = not \ (vcs == "svn" and repolevel < 3 and options.mode != "commit") # Build a regex from thirdpartymirrors for the SRC_URI.mirror check. -thirdpartymirrors = [] -for v in repoman_settings.thirdpartymirrors().values(): +thirdpartymirrors = {} +for k, v in repoman_settings.thirdpartymirrors().items(): for v in v: if not v.endswith("/"): v += "/" - thirdpartymirrors.append(v) + thirdpartymirrors[v] = k + +class _XMLParser(xml.etree.ElementTree.XMLParser): + + def __init__(self, data, **kwargs): + xml.etree.ElementTree.XMLParser.__init__(self, **kwargs) + self._portage_data = data + if hasattr(self, 'parser'): + self._base_XmlDeclHandler = self.parser.XmlDeclHandler + self.parser.XmlDeclHandler = self._portage_XmlDeclHandler + self._base_StartDoctypeDeclHandler = \ + self.parser.StartDoctypeDeclHandler + self.parser.StartDoctypeDeclHandler = \ + self._portage_StartDoctypeDeclHandler + + def _portage_XmlDeclHandler(self, version, encoding, standalone): + if self._base_XmlDeclHandler is not None: + self._base_XmlDeclHandler(version, encoding, standalone) + self._portage_data["XML_DECLARATION"] = (version, encoding, standalone) + + def _portage_StartDoctypeDeclHandler(self, doctypeName, systemId, publicId, + has_internal_subset): + if self._base_StartDoctypeDeclHandler is not None: + self._base_StartDoctypeDeclHandler(doctypeName, systemId, publicId, + has_internal_subset) + self._portage_data["DOCTYPE"] = (doctypeName, systemId, publicId) class _MetadataTreeBuilder(xml.etree.ElementTree.TreeBuilder): """ @@ -1231,13 +1310,13 @@ if options.if_modified == "y": chain(mychanged, mynew, myremoved))) for x in effective_scanlist: - #ebuilds and digests added to cvs respectively. + # ebuilds and digests added to cvs respectively. logging.info("checking package %s" % x) # save memory by discarding xmatch caches from previous package(s) arch_xmatch_caches.clear() - eadded=[] - catdir,pkgdir=x.split("/") - checkdir=repodir+"/"+x + eadded = [] + catdir, pkgdir = x.split("/") + checkdir = repodir + "/" + x checkdir_relative = "" if repolevel < 3: checkdir_relative = os.path.join(pkgdir, checkdir_relative) @@ -1319,15 +1398,15 @@ for x in effective_scanlist: if options.mode == 'manifest-check': continue - checkdirlist=os.listdir(checkdir) - ebuildlist=[] + checkdirlist = os.listdir(checkdir) + ebuildlist = [] pkgs = {} allvalid = True for y in checkdirlist: if (y in no_exec or y.endswith(".ebuild")) and \ - stat.S_IMODE(os.stat(os.path.join(checkdir, y)).st_mode) & 0o111: - stats["file.executable"] += 1 - fails["file.executable"].append(os.path.join(checkdir, y)) + stat.S_IMODE(os.stat(os.path.join(checkdir, y)).st_mode) & 0o111: + stats["file.executable"] += 1 + fails["file.executable"].append(os.path.join(checkdir, y)) if y.endswith(".ebuild"): pf = y[:-7] ebuildlist.append(pf) @@ -1368,19 +1447,19 @@ for x in effective_scanlist: ebuildlist = [pkg.pf for pkg in ebuildlist] for y in checkdirlist: - m = disallowed_filename_chars_re.search(y.strip(os.sep)) - if m is not None: + index = repo_config.find_invalid_path_char(y) + if index != -1: y_relative = os.path.join(checkdir_relative, y) if vcs is not None and not vcs_new_changed(y_relative): # If the file isn't in the VCS new or changed set, then # assume that it's an irrelevant temporary file (Manifest # entries are not generated for file names containing # prohibited characters). See bug #406877. - m = None - if m is not None: + index = -1 + if index != -1: stats["file.name"] += 1 fails["file.name"].append("%s/%s: char '%s'" % \ - (checkdir, y, m.group(0))) + (checkdir, y, y[index])) if not (y in ("ChangeLog", "metadata.xml") or y.endswith(".ebuild")): continue @@ -1391,7 +1470,7 @@ for x in effective_scanlist: encoding=_encodings['fs'], errors='strict'), mode='r', encoding=_encodings['repo.content']) for l in f: - line +=1 + line += 1 except UnicodeDecodeError as ue: stats["file.UTF8"] += 1 s = ue.object[:ue.start] @@ -1406,10 +1485,10 @@ for x in effective_scanlist: if vcs in ("git", "hg") and check_ebuild_notadded: if vcs == "git": - myf = os.popen("git ls-files --others %s" % \ + myf = repoman_popen("git ls-files --others %s" % \ (portage._shell_quote(checkdir_relative),)) if vcs == "hg": - myf = os.popen("hg status --no-status --unknown %s" % \ + myf = repoman_popen("hg status --no-status --unknown %s" % \ (portage._shell_quote(checkdir_relative),)) for l in myf: if l[:-1][-7:] == ".ebuild": @@ -1421,21 +1500,23 @@ for x in effective_scanlist: if vcs in ("cvs", "svn", "bzr") and check_ebuild_notadded: try: if vcs == "cvs": - myf=open(checkdir+"/CVS/Entries","r") + myf = open(checkdir + "/CVS/Entries", "r") if vcs == "svn": - myf = os.popen("svn status --depth=files --verbose " + checkdir) + myf = repoman_popen("svn status --depth=files --verbose " + + portage._shell_quote(checkdir)) if vcs == "bzr": - myf = os.popen("bzr ls -v --kind=file " + checkdir) + myf = repoman_popen("bzr ls -v --kind=file " + + portage._shell_quote(checkdir)) myl = myf.readlines() myf.close() for l in myl: if vcs == "cvs": - if l[0]!="/": + if l[0] != "/": continue - splitl=l[1:].split("/") + splitl = l[1:].split("/") if not len(splitl): continue - if splitl[0][-7:]==".ebuild": + if splitl[0][-7:] == ".ebuild": eadded.append(splitl[0][:-7]) if vcs == "svn": if l[:1] == "?": @@ -1453,8 +1534,9 @@ for x in effective_scanlist: if l[-7:] == ".ebuild": eadded.append(os.path.basename(l[:-7])) if vcs == "svn": - myf = os.popen("svn status " + checkdir) - myl=myf.readlines() + myf = repoman_popen("svn status " + + portage._shell_quote(checkdir)) + myl = myf.readlines() myf.close() for l in myl: if l[0] == "A": @@ -1464,7 +1546,7 @@ for x in effective_scanlist: except IOError: if vcs == "cvs": stats["CVS/Entries.IO_error"] += 1 - fails["CVS/Entries.IO_error"].append(checkdir+"/CVS/Entries") + fails["CVS/Entries.IO_error"].append(checkdir + "/CVS/Entries") else: raise continue @@ -1472,7 +1554,7 @@ for x in effective_scanlist: mf = repoman_settings.repositories.get_repo_for_location( os.path.dirname(os.path.dirname(checkdir))) mf = mf.load_manifest(checkdir, repoman_settings["DISTDIR"]) - mydigests=mf.getTypeDigests("DIST") + mydigests = mf.getTypeDigests("DIST") fetchlist_dict = portage.FetchlistDict(checkdir, repoman_settings, portdb) myfiles_all = [] @@ -1488,7 +1570,7 @@ for x in effective_scanlist: # This will be reported as an "ebuild.syntax" error. pass else: - stats["SRC_URI.syntax"] = stats["SRC_URI.syntax"] + 1 + stats["SRC_URI.syntax"] += 1 fails["SRC_URI.syntax"].append( "%s.ebuild SRC_URI: %s" % (mykey, e)) del fetchlist_dict @@ -1502,15 +1584,15 @@ for x in effective_scanlist: for entry in mydigests: if entry not in myfiles_all: stats["digest.unused"] += 1 - fails["digest.unused"].append(checkdir+"::"+entry) + fails["digest.unused"].append(checkdir + "::" + entry) for entry in myfiles_all: if entry not in mydigests: stats["digest.missing"] += 1 - fails["digest.missing"].append(checkdir+"::"+entry) + fails["digest.missing"].append(checkdir + "::" + entry) del myfiles_all - if os.path.exists(checkdir+"/files"): - filesdirlist=os.listdir(checkdir+"/files") + if os.path.exists(checkdir + "/files"): + filesdirlist = os.listdir(checkdir + "/files") # recurse through files directory # use filesdirlist as a stack, appending directories as needed so people can't hide > 20k files in a subdirectory. @@ -1530,77 +1612,110 @@ for x in effective_scanlist: # !!! VCS "portability" alert! Need some function isVcsDir() or alike !!! if y == "CVS" or y == ".svn": continue - for z in os.listdir(checkdir+"/files/"+y): + for z in os.listdir(checkdir + "/files/" + y): if z == "CVS" or z == ".svn": continue - filesdirlist.append(y+"/"+z) + filesdirlist.append(y + "/" + z) # Current policy is no files over 20 KiB, these are the checks. File size between # 20 KiB and 60 KiB causes a warning, while file size over 60 KiB causes an error. elif mystat.st_size > 61440: stats["file.size.fatal"] += 1 - fails["file.size.fatal"].append("("+ str(mystat.st_size//1024) + " KiB) "+x+"/files/"+y) + fails["file.size.fatal"].append("(" + str(mystat.st_size//1024) + " KiB) " + x + "/files/" + y) elif mystat.st_size > 20480: stats["file.size"] += 1 - fails["file.size"].append("("+ str(mystat.st_size//1024) + " KiB) "+x+"/files/"+y) + fails["file.size"].append("(" + str(mystat.st_size//1024) + " KiB) " + x + "/files/" + y) - m = disallowed_filename_chars_re.search( - os.path.basename(y.rstrip(os.sep))) - if m is not None: + index = repo_config.find_invalid_path_char(y) + if index != -1: y_relative = os.path.join(checkdir_relative, "files", y) if vcs is not None and not vcs_new_changed(y_relative): # If the file isn't in the VCS new or changed set, then # assume that it's an irrelevant temporary file (Manifest # entries are not generated for file names containing # prohibited characters). See bug #406877. - m = None - if m is not None: + index = -1 + if index != -1: stats["file.name"] += 1 fails["file.name"].append("%s/files/%s: char '%s'" % \ - (checkdir, y, m.group(0))) - - if desktop_file_validate and desktop_pattern.match(y): - cmd_output = validate_desktop_entry(full_path) - if cmd_output: - # Note: in the future we may want to grab the - # warnings in addition to the errors. We're - # just doing errors now since we don't want - # to generate too much noise at first. - error_re = re.compile(r'.*\s*error:\s*(.*)') - for line in cmd_output: - error_match = error_re.match(line) - if error_match is None: - continue - stats["desktop.invalid"] += 1 - fails["desktop.invalid"].append( - relative_path + ': %s' % error_match.group(1)) - + (checkdir, y, y[index])) del mydigests if check_changelog and "ChangeLog" not in checkdirlist: - stats["changelog.missing"]+=1 - fails["changelog.missing"].append(x+"/ChangeLog") - + stats["changelog.missing"] += 1 + fails["changelog.missing"].append(x + "/ChangeLog") + musedict = {} - #metadata.xml file check + # metadata.xml file check if "metadata.xml" not in checkdirlist: - stats["metadata.missing"]+=1 - fails["metadata.missing"].append(x+"/metadata.xml") - #metadata.xml parse check + stats["metadata.missing"] += 1 + fails["metadata.missing"].append(x + "/metadata.xml") + # metadata.xml parse check else: metadata_bad = False + xml_info = {} + xml_parser = _XMLParser(xml_info, target=_MetadataTreeBuilder()) # read metadata.xml into memory try: _metadata_xml = xml.etree.ElementTree.parse( - os.path.join(checkdir, "metadata.xml"), - parser=xml.etree.ElementTree.XMLParser( - target=_MetadataTreeBuilder())) + _unicode_encode(os.path.join(checkdir, "metadata.xml"), + encoding=_encodings['fs'], errors='strict'), + parser=xml_parser) except (ExpatError, SyntaxError, EnvironmentError) as e: metadata_bad = True stats["metadata.bad"] += 1 fails["metadata.bad"].append("%s/metadata.xml: %s" % (x, e)) del e else: + if not hasattr(xml_parser, 'parser') or \ + sys.hexversion < 0x2070000 or \ + (sys.hexversion > 0x3000000 and sys.hexversion < 0x3020000): + # doctype is not parsed with python 2.6 or 3.1 + pass + else: + if "XML_DECLARATION" not in xml_info: + stats["metadata.bad"] += 1 + fails["metadata.bad"].append("%s/metadata.xml: " + "xml declaration is missing on first line, " + "should be '%s'" % (x, metadata_xml_declaration)) + else: + xml_version, xml_encoding, xml_standalone = \ + xml_info["XML_DECLARATION"] + if xml_encoding is None or \ + xml_encoding.upper() != metadata_xml_encoding: + stats["metadata.bad"] += 1 + if xml_encoding is None: + encoding_problem = "but it is undefined" + else: + encoding_problem = "not '%s'" % xml_encoding + fails["metadata.bad"].append("%s/metadata.xml: " + "xml declaration encoding should be '%s', %s" % + (x, metadata_xml_encoding, encoding_problem)) + + if "DOCTYPE" not in xml_info: + metadata_bad = True + stats["metadata.bad"] += 1 + fails["metadata.bad"].append("%s/metadata.xml: %s" % (x, + "DOCTYPE is missing")) + else: + doctype_name, doctype_system, doctype_pubid = \ + xml_info["DOCTYPE"] + if doctype_system != metadata_dtd_uri: + stats["metadata.bad"] += 1 + if doctype_system is None: + system_problem = "but it is undefined" + else: + system_problem = "not '%s'" % doctype_system + fails["metadata.bad"].append("%s/metadata.xml: " + "DOCTYPE: SYSTEM should refer to '%s', %s" % + (x, metadata_dtd_uri, system_problem)) + + if doctype_name != metadata_doctype_name: + stats["metadata.bad"] += 1 + fails["metadata.bad"].append("%s/metadata.xml: " + "DOCTYPE: name should be '%s', not '%s'" % + (x, metadata_doctype_name, doctype_name)) + # load USE flags from metadata.xml try: musedict = utilities.parse_metadata_use(_metadata_xml) @@ -1608,6 +1723,22 @@ for x in effective_scanlist: metadata_bad = True stats["metadata.bad"] += 1 fails["metadata.bad"].append("%s/metadata.xml: %s" % (x, e)) + else: + for atom in chain(*musedict.values()): + if atom is None: + continue + try: + atom = Atom(atom) + except InvalidAtom as e: + stats["metadata.bad"] += 1 + fails["metadata.bad"].append( + "%s/metadata.xml: Invalid atom: %s" % (x, e)) + else: + if atom.cp != x: + stats["metadata.bad"] += 1 + fails["metadata.bad"].append( + ("%s/metadata.xml: Atom contains " + "unexpected cat/pn: %s") % (x, atom)) # Run other metadata.xml checkers try: @@ -1618,19 +1749,20 @@ for x in effective_scanlist: fails["metadata.bad"].append("%s/metadata.xml: %s" % (x, e)) del e - #Only carry out if in package directory or check forced + # Only carry out if in package directory or check forced if xmllint_capable and not metadata_bad: # xmlint can produce garbage output even on success, so only dump # the ouput when it fails. - st, out = subprocess_getstatusoutput( - "xmllint --nonet --noout --dtdvalid '%s' '%s'" % \ - (metadata_dtd, os.path.join(checkdir, "metadata.xml"))) + st, out = repoman_getstatusoutput( + "xmllint --nonet --noout --dtdvalid %s %s" % \ + (portage._shell_quote(metadata_dtd), + portage._shell_quote(os.path.join(checkdir, "metadata.xml")))) if st != os.EX_OK: print(red("!!!") + " metadata.xml is invalid:") for z in out.splitlines(): - print(red("!!! ")+z) - stats["metadata.bad"]+=1 - fails["metadata.bad"].append(x+"/metadata.xml") + print(red("!!! ") + z) + stats["metadata.bad"] += 1 + fails["metadata.bad"].append(x + "/metadata.xml") del metadata_bad muselist = frozenset(musedict) @@ -1656,20 +1788,20 @@ for x in effective_scanlist: fails['changelog.ebuildadded'].append(relative_path) if vcs in ("cvs", "svn", "bzr") and check_ebuild_notadded and y not in eadded: - #ebuild not added to vcs - stats["ebuild.notadded"]=stats["ebuild.notadded"]+1 - fails["ebuild.notadded"].append(x+"/"+y+".ebuild") - myesplit=portage.pkgsplit(y) + # ebuild not added to vcs + stats["ebuild.notadded"] += 1 + fails["ebuild.notadded"].append(x + "/" + y + ".ebuild") + myesplit = portage.pkgsplit(y) if myesplit is None or myesplit[0] != x.split("/")[-1] \ or pv_toolong_re.search(myesplit[1]) \ or pv_toolong_re.search(myesplit[2]): - stats["ebuild.invalidname"]=stats["ebuild.invalidname"]+1 - fails["ebuild.invalidname"].append(x+"/"+y+".ebuild") + stats["ebuild.invalidname"] += 1 + fails["ebuild.invalidname"].append(x + "/" + y + ".ebuild") continue - elif myesplit[0]!=pkgdir: - print(pkgdir,myesplit[0]) - stats["ebuild.namenomatch"]=stats["ebuild.namenomatch"]+1 - fails["ebuild.namenomatch"].append(x+"/"+y+".ebuild") + elif myesplit[0] != pkgdir: + print(pkgdir, myesplit[0]) + stats["ebuild.namenomatch"] += 1 + fails["ebuild.namenomatch"].append(x + "/" + y + ".ebuild") continue pkg = pkgs[y] @@ -1678,15 +1810,25 @@ for x in effective_scanlist: allvalid = False for k, msgs in pkg.invalid.items(): for msg in msgs: - stats[k] = stats[k] + 1 - fails[k].append("%s %s" % (relative_path, msg)) + stats[k] += 1 + fails[k].append("%s: %s" % (relative_path, msg)) continue - myaux = pkg.metadata + myaux = pkg._metadata eapi = myaux["EAPI"] inherited = pkg.inherited live_ebuild = live_eclasses.intersection(inherited) + if repo_config.eapi_is_banned(eapi): + stats["repo.eapi.banned"] += 1 + fails["repo.eapi.banned"].append( + "%s: %s" % (relative_path, eapi)) + + elif repo_config.eapi_is_deprecated(eapi): + stats["repo.eapi.deprecated"] += 1 + fails["repo.eapi.deprecated"].append( + "%s: %s" % (relative_path, eapi)) + for k, v in myaux.items(): if not isinstance(v, basestring): continue @@ -1703,20 +1845,21 @@ for x in effective_scanlist: for uri in portage.dep.use_reduce( \ myaux["SRC_URI"], matchall=True, is_src_uri=True, eapi=eapi, flat=True): contains_mirror = False - for mirror in thirdpartymirrors: + for mirror, mirror_alias in thirdpartymirrors.items(): if uri.startswith(mirror): contains_mirror = True break if not contains_mirror: continue + new_uri = "mirror://%s/%s" % (mirror_alias, uri[len(mirror):]) stats["SRC_URI.mirror"] += 1 fails["SRC_URI.mirror"].append( - "%s: '%s' found in thirdpartymirrors" % \ - (relative_path, mirror)) + "%s: '%s' found in thirdpartymirrors, use '%s'" % \ + (relative_path, mirror, new_uri)) if myaux.get("PROVIDE"): - stats["virtual.oldstyle"]+=1 + stats["virtual.oldstyle"] += 1 fails["virtual.oldstyle"].append(relative_path) for pos, missing_var in enumerate(missingvars): @@ -1726,15 +1869,15 @@ for x in effective_scanlist: continue if live_ebuild and missing_var == "KEYWORDS": continue - myqakey=missingvars[pos]+".missing" - stats[myqakey]=stats[myqakey]+1 - fails[myqakey].append(x+"/"+y+".ebuild") + myqakey = missingvars[pos] + ".missing" + stats[myqakey] += 1 + fails[myqakey].append(x + "/" + y + ".ebuild") if catdir == "virtual": for var in ("HOMEPAGE", "LICENSE"): if myaux.get(var): myqakey = var + ".virtual" - stats[myqakey] = stats[myqakey] + 1 + stats[myqakey] += 1 fails[myqakey].append(relative_path) # 14 is the length of DESCRIPTION="" @@ -1751,7 +1894,7 @@ for x in effective_scanlist: not keyword.startswith("-"): stable_keywords.append(keyword) if stable_keywords: - if ebuild_path in new_ebuilds: + if ebuild_path in new_ebuilds and catdir != "virtual": stable_keywords.sort() stats["KEYWORDS.stable"] += 1 fails["KEYWORDS.stable"].append( @@ -1761,10 +1904,10 @@ for x in effective_scanlist: ebuild_archs = set(kw.lstrip("~") for kw in keywords \ if not kw.startswith("-")) - previous_keywords = slot_keywords.get(myaux["SLOT"]) + previous_keywords = slot_keywords.get(pkg.slot) if previous_keywords is None: - slot_keywords[myaux["SLOT"]] = set() - elif ebuild_archs and not live_ebuild: + slot_keywords[pkg.slot] = set() + elif ebuild_archs and "*" not in ebuild_archs and not live_ebuild: dropped_keywords = previous_keywords.difference(ebuild_archs) if dropped_keywords: stats["KEYWORDS.dropped"] += 1 @@ -1772,7 +1915,7 @@ for x in effective_scanlist: relative_path + ": %s" % \ " ".join(sorted(dropped_keywords))) - slot_keywords[myaux["SLOT"]].update(ebuild_archs) + slot_keywords[pkg.slot].update(ebuild_archs) # KEYWORDS="-*" is a stupid replacement for package.mask and screws general KEYWORDS semantics if "-*" in keywords: @@ -1784,7 +1927,7 @@ for x in effective_scanlist: haskeyword = True if not haskeyword: stats["KEYWORDS.stupid"] += 1 - fails["KEYWORDS.stupid"].append(x+"/"+y+".ebuild") + fails["KEYWORDS.stupid"].append(x + "/" + y + ".ebuild") """ Ebuilds that inherit a "Live" eclass (darcs,subversion,git,cvs,etc..) should @@ -1812,37 +1955,53 @@ for x in effective_scanlist: arches = [[repoman_settings["ARCH"], repoman_settings["ARCH"], repoman_settings["ACCEPT_KEYWORDS"].split()]] else: - arches=[] - for keyword in myaux["KEYWORDS"].split(): - if (keyword[0]=="-"): + arches = set() + for keyword in keywords: + if keyword[0] == "-": continue - elif (keyword[0]=="~"): - arches.append([keyword, keyword[1:], [keyword[1:], keyword]]) + elif keyword[0] == "~": + arch = keyword[1:] + if arch == "*": + for expanded_arch in profiles: + if expanded_arch == "**": + continue + arches.add((keyword, expanded_arch, + (expanded_arch, "~" + expanded_arch))) + else: + arches.add((keyword, arch, (arch, keyword))) else: - arches.append([keyword, keyword, [keyword]]) + if keyword == "*": + for expanded_arch in profiles: + if expanded_arch == "**": + continue + arches.add((keyword, expanded_arch, + (expanded_arch,))) + else: + arches.add((keyword, keyword, (keyword,))) if not arches: # Use an empty profile for checking dependencies of # packages that have empty KEYWORDS. - arches.append(['**', '**', ['**']]) + arches.add(('**', '**', ('**',))) unknown_pkgs = set() baddepsyntax = False badlicsyntax = False badprovsyntax = False - catpkg = catdir+"/"+y + catpkg = catdir + "/" + y inherited_java_eclass = "java-pkg-2" in inherited or \ "java-pkg-opt-2" in inherited inherited_wxwidgets_eclass = "wxwidgets" in inherited operator_tokens = set(["||", "(", ")"]) type_list, badsyntax = [], [] - for mytype in ("DEPEND", "RDEPEND", "PDEPEND", - "LICENSE", "PROPERTIES", "PROVIDE"): + for mytype in Package._dep_keys + ("LICENSE", "PROPERTIES", "PROVIDE"): mydepstr = myaux[mytype] + buildtime = mytype in Package._buildtime_keys + runtime = mytype in Package._runtime_keys token_class = None - if mytype in ("DEPEND", "RDEPEND", "PDEPEND"): - token_class=portage.dep.Atom + if mytype.endswith("DEPEND"): + token_class = portage.dep.Atom try: atoms = portage.dep.use_reduce(mydepstr, matchall=1, flat=True, \ @@ -1851,8 +2010,8 @@ for x in effective_scanlist: atoms = None badsyntax.append(str(e)) - if atoms and mytype in ("DEPEND", "RDEPEND", "PDEPEND"): - if mytype in ("RDEPEND", "PDEPEND") and \ + if atoms and mytype.endswith("DEPEND"): + if runtime and \ "test?" in mydepstr.split(): stats[mytype + '.suspect'] += 1 fails[mytype + '.suspect'].append(relative_path + \ @@ -1872,21 +2031,30 @@ for x in effective_scanlist: is_blocker = atom.blocker - if mytype == "DEPEND" and \ + if catdir != "virtual": + if not is_blocker and \ + atom.cp in suspect_virtual: + stats['virtual.suspect'] += 1 + fails['virtual.suspect'].append( + relative_path + + ": %s: consider using '%s' instead of '%s'" % + (mytype, suspect_virtual[atom.cp], atom)) + + if buildtime and \ not is_blocker and \ not inherited_java_eclass and \ atom.cp == "virtual/jdk": stats['java.eclassesnotused'] += 1 fails['java.eclassesnotused'].append(relative_path) - elif mytype == "DEPEND" and \ + elif buildtime and \ not is_blocker and \ not inherited_wxwidgets_eclass and \ atom.cp == "x11-libs/wxGTK": stats['wxwidgets.eclassnotused'] += 1 fails['wxwidgets.eclassnotused'].append( - relative_path + ": DEPENDs on x11-libs/wxGTK" - " without inheriting wxwidgets.eclass") - elif mytype in ("PDEPEND", "RDEPEND"): + (relative_path + ": %ss on x11-libs/wxGTK" + " without inheriting wxwidgets.eclass") % mytype) + elif runtime: if not is_blocker and \ atom.cp in suspect_rdepend: stats[mytype + '.suspect'] += 1 @@ -1895,21 +2063,26 @@ for x in effective_scanlist: if atom.operator == "~" and \ portage.versions.catpkgsplit(atom.cpv)[3] != "r0": - stats[mytype + '.badtilde'] += 1 - fails[mytype + '.badtilde'].append( + qacat = 'dependency.badtilde' + stats[qacat] += 1 + fails[qacat].append( (relative_path + ": %s uses the ~ operator" " with a non-zero revision:" + \ " '%s'") % (mytype, atom)) type_list.extend([mytype] * (len(badsyntax) - len(type_list))) - for m,b in zip(type_list, badsyntax): - stats[m+".syntax"] += 1 - fails[m+".syntax"].append(catpkg+".ebuild "+m+": "+b) + for m, b in zip(type_list, badsyntax): + if m.endswith("DEPEND"): + qacat = "dependency.syntax" + else: + qacat = m + ".syntax" + stats[qacat] += 1 + fails[qacat].append("%s: %s: %s" % (relative_path, m, b)) badlicsyntax = len([z for z in type_list if z == "LICENSE"]) badprovsyntax = len([z for z in type_list if z == "PROVIDE"]) - baddepsyntax = len(type_list) != badlicsyntax + badprovsyntax + baddepsyntax = len(type_list) != badlicsyntax + badprovsyntax badlicsyntax = badlicsyntax > 0 badprovsyntax = badprovsyntax > 0 @@ -1925,7 +2098,7 @@ for x in effective_scanlist: myuse.append(flag_name) # uselist checks - metadata - for mypos in range(len(myuse)-1,-1,-1): + for mypos in range(len(myuse)-1, -1, -1): if myuse[mypos] and (myuse[mypos] in muselist): del myuse[mypos] @@ -1938,8 +2111,17 @@ for x in effective_scanlist: " '%s'") % (eapi, myflag)) for mypos in range(len(myuse)): - stats["IUSE.invalid"]=stats["IUSE.invalid"]+1 - fails["IUSE.invalid"].append(x+"/"+y+".ebuild: %s" % myuse[mypos]) + stats["IUSE.invalid"] += 1 + fails["IUSE.invalid"].append(x + "/" + y + ".ebuild: %s" % myuse[mypos]) + + # Check for outdated RUBY targets + if "ruby-ng" in inherited or "ruby-fakegem" in inherited or "ruby" in inherited: + ruby_intersection = pkg.iuse.all.intersection(ruby_deprecated) + if ruby_intersection: + for myruby in ruby_intersection: + stats["IUSE.rubydeprecated"] += 1 + fails["IUSE.rubydeprecated"].append( + (relative_path + ": Deprecated ruby target: %s") % myruby) # license checks if not badlicsyntax: @@ -1952,10 +2134,13 @@ for x in effective_scanlist: # Need to check for "||" manually as no portage # function will remove it without removing values. if lic not in liclist and lic != "||": - stats["LICENSE.invalid"]=stats["LICENSE.invalid"]+1 - fails["LICENSE.invalid"].append(x+"/"+y+".ebuild: %s" % lic) + stats["LICENSE.invalid"] += 1 + fails["LICENSE.invalid"].append(x + "/" + y + ".ebuild: %s" % lic) + elif lic in liclist_deprecated: + stats["LICENSE.deprecated"] += 1 + fails["LICENSE.deprecated"].append("%s: %s" % (relative_path, lic)) - #keyword checks + # keyword checks myuse = myaux["KEYWORDS"].split() for mykey in myuse: if mykey not in ("-*", "*", "~*"): @@ -1966,17 +2151,17 @@ for x in effective_scanlist: myskey = myskey[1:] if myskey not in kwlist: stats["KEYWORDS.invalid"] += 1 - fails["KEYWORDS.invalid"].append(x+"/"+y+".ebuild: %s" % mykey) + fails["KEYWORDS.invalid"].append(x + "/" + y + ".ebuild: %s" % mykey) elif myskey not in profiles: stats["KEYWORDS.invalid"] += 1 - fails["KEYWORDS.invalid"].append(x+"/"+y+".ebuild: %s (profile invalid)" % mykey) + fails["KEYWORDS.invalid"].append(x + "/" + y + ".ebuild: %s (profile invalid)" % mykey) - #restrict checks + # restrict checks myrestrict = None try: myrestrict = portage.dep.use_reduce(myaux["RESTRICT"], matchall=1, flat=True) except portage.exception.InvalidDependString as e: - stats["RESTRICT.syntax"] = stats["RESTRICT.syntax"] + 1 + stats["RESTRICT.syntax"] += 1 fails["RESTRICT.syntax"].append( "%s: RESTRICT: %s" % (relative_path, e)) del e @@ -1986,8 +2171,8 @@ for x in effective_scanlist: if mybadrestrict: stats["RESTRICT.invalid"] += len(mybadrestrict) for mybad in mybadrestrict: - fails["RESTRICT.invalid"].append(x+"/"+y+".ebuild: %s" % mybad) - #REQUIRED_USE check + fails["RESTRICT.invalid"].append(x + "/" + y + ".ebuild: %s" % mybad) + # REQUIRED_USE check required_use = myaux["REQUIRED_USE"] if required_use: if not eapi_has_required_use(eapi): @@ -1997,9 +2182,9 @@ for x in effective_scanlist: " not supported with EAPI='%s'" % (eapi,)) try: portage.dep.check_required_use(required_use, (), - pkg.iuse.is_valid_flag) + pkg.iuse.is_valid_flag, eapi=eapi) except portage.exception.InvalidDependString as e: - stats["REQUIRED_USE.syntax"] = stats["REQUIRED_USE.syntax"] + 1 + stats["REQUIRED_USE.syntax"] += 1 fails["REQUIRED_USE.syntax"].append( "%s: REQUIRED_USE: %s" % (relative_path, e)) del e @@ -2032,127 +2217,154 @@ for x in effective_scanlist: # user is intent on forcing the commit anyway. continue - for keyword,arch,groups in arches: - + relevant_profiles = [] + for keyword, arch, groups in arches: if arch not in profiles: # A missing profile will create an error further down # during the KEYWORDS verification. continue - - for prof in profiles[arch]: - if prof.status not in ("stable", "dev") or \ - prof.status == "dev" and not options.include_dev: + if include_arches is not None: + if arch not in include_arches: continue - dep_settings = arch_caches.get(prof.sub_path) - if dep_settings is None: - dep_settings = portage.config( - config_profile_path=prof.abs_path, - config_incrementals=repoman_incrementals, - config_root=config_root, - local_config=False, - _unmatched_removal=options.unmatched_removal, - env=env) - dep_settings.categories = repoman_settings.categories - if options.without_mask: - dep_settings._mask_manager = \ - copy.deepcopy(dep_settings._mask_manager) - dep_settings._mask_manager._pmaskdict.clear() - arch_caches[prof.sub_path] = dep_settings - - xmatch_cache_key = (prof.sub_path, tuple(groups)) - xcache = arch_xmatch_caches.get(xmatch_cache_key) - if xcache is None: - portdb.melt() - portdb.freeze() - xcache = portdb.xcache - xcache.update(shared_xmatch_caches) - arch_xmatch_caches[xmatch_cache_key] = xcache - - trees[root]["porttree"].settings = dep_settings - portdb.settings = dep_settings - portdb.xcache = xcache - # for package.use.mask support inside dep_check - dep_settings.setcpv(pkg) - dep_settings["ACCEPT_KEYWORDS"] = " ".join(groups) - # just in case, prevent config.reset() from nuking these. - dep_settings.backup_changes("ACCEPT_KEYWORDS") - - if not baddepsyntax: - ismasked = not ebuild_archs or \ - pkg.cpv not in portdb.xmatch("match-visible", pkg.cp) - if ismasked: - if not have_pmasked: - have_pmasked = bool(dep_settings._getMaskAtom( - pkg.cpv, pkg.metadata)) - if options.ignore_masked: - continue - #we are testing deps for a masked package; give it some lee-way - suffix="masked" - matchmode = "minimum-all" - else: - suffix="" - matchmode = "minimum-visible" - - if not have_dev_keywords: - have_dev_keywords = \ - bool(dev_keywords.intersection(keywords)) - - if prof.status == "dev": - suffix=suffix+"indev" - - for mytype,mypos in [["DEPEND",len(missingvars)],["RDEPEND",len(missingvars)+1],["PDEPEND",len(missingvars)+2]]: - - mykey=mytype+".bad"+suffix - myvalue = myaux[mytype] - if not myvalue: - continue - - success, atoms = portage.dep_check(myvalue, portdb, - dep_settings, use="all", mode=matchmode, - trees=trees) - - if success: - if atoms: - - # Don't bother with dependency.unknown for - # cases in which *DEPEND.bad is triggered. - for atom in atoms: - # dep_check returns all blockers and they - # aren't counted for *DEPEND.bad, so we - # ignore them here. - if not atom.blocker: - unknown_pkgs.discard( - (mytype, atom.unevaluated_atom)) - - if not prof.sub_path: - # old-style virtuals currently aren't - # resolvable with empty profile, since - # 'virtuals' mappings are unavailable - # (it would be expensive to search - # for PROVIDE in all ebuilds) - atoms = [atom for atom in atoms if not \ - (atom.cp.startswith('virtual/') and \ - not portdb.cp_list(atom.cp))] - - #we have some unsolvable deps - #remove ! deps, which always show up as unsatisfiable - atoms = [str(atom.unevaluated_atom) \ - for atom in atoms if not atom.blocker] - - #if we emptied out our list, continue: - if not atoms: - continue - stats[mykey]=stats[mykey]+1 - fails[mykey].append("%s: %s(%s) %s" % \ - (relative_path, keyword, - prof, repr(atoms))) - else: - stats[mykey]=stats[mykey]+1 - fails[mykey].append("%s: %s(%s) %s" % \ - (relative_path, keyword, + relevant_profiles.extend((keyword, groups, prof) + for prof in profiles[arch]) + + def sort_key(item): + return item[2].sub_path + + relevant_profiles.sort(key=sort_key) + + for keyword, groups, prof in relevant_profiles: + + if not (prof.status == "stable" or \ + (prof.status == "dev" and options.include_dev) or \ + (prof.status == "exp" and options.include_exp_profiles == 'y')): + continue + + dep_settings = arch_caches.get(prof.sub_path) + if dep_settings is None: + dep_settings = portage.config( + config_profile_path=prof.abs_path, + config_incrementals=repoman_incrementals, + config_root=config_root, + local_config=False, + _unmatched_removal=options.unmatched_removal, + env=env, repositories=repoman_settings.repositories) + dep_settings.categories = repoman_settings.categories + if options.without_mask: + dep_settings._mask_manager_obj = \ + copy.deepcopy(dep_settings._mask_manager) + dep_settings._mask_manager._pmaskdict.clear() + arch_caches[prof.sub_path] = dep_settings + + xmatch_cache_key = (prof.sub_path, tuple(groups)) + xcache = arch_xmatch_caches.get(xmatch_cache_key) + if xcache is None: + portdb.melt() + portdb.freeze() + xcache = portdb.xcache + xcache.update(shared_xmatch_caches) + arch_xmatch_caches[xmatch_cache_key] = xcache + + trees[root]["porttree"].settings = dep_settings + portdb.settings = dep_settings + portdb.xcache = xcache + + dep_settings["ACCEPT_KEYWORDS"] = " ".join(groups) + # just in case, prevent config.reset() from nuking these. + dep_settings.backup_changes("ACCEPT_KEYWORDS") + + # This attribute is used in dbapi._match_use() to apply + # use.stable.{mask,force} settings based on the stable + # status of the parent package. This is required in order + # for USE deps of unstable packages to be resolved correctly, + # since otherwise use.stable.{mask,force} settings of + # dependencies may conflict (see bug #456342). + dep_settings._parent_stable = dep_settings._isStable(pkg) + + # Handle package.use*.{force,mask) calculation, for use + # in dep_check. + dep_settings.useforce = dep_settings._use_manager.getUseForce( + pkg, stable=dep_settings._parent_stable) + dep_settings.usemask = dep_settings._use_manager.getUseMask( + pkg, stable=dep_settings._parent_stable) + + if not baddepsyntax: + ismasked = not ebuild_archs or \ + pkg.cpv not in portdb.xmatch("match-visible", pkg.cp) + if ismasked: + if not have_pmasked: + have_pmasked = bool(dep_settings._getMaskAtom( + pkg.cpv, pkg._metadata)) + if options.ignore_masked: + continue + # we are testing deps for a masked package; give it some lee-way + suffix = "masked" + matchmode = "minimum-all" + else: + suffix = "" + matchmode = "minimum-visible" + + if not have_dev_keywords: + have_dev_keywords = \ + bool(dev_keywords.intersection(keywords)) + + if prof.status == "dev": + suffix = suffix + "indev" + + for mytype in Package._dep_keys: + + mykey = "dependency.bad" + suffix + myvalue = myaux[mytype] + if not myvalue: + continue + + success, atoms = portage.dep_check(myvalue, portdb, + dep_settings, use="all", mode=matchmode, + trees=trees) + + if success: + if atoms: + + # Don't bother with dependency.unknown for + # cases in which *DEPEND.bad is triggered. + for atom in atoms: + # dep_check returns all blockers and they + # aren't counted for *DEPEND.bad, so we + # ignore them here. + if not atom.blocker: + unknown_pkgs.discard( + (mytype, atom.unevaluated_atom)) + + if not prof.sub_path: + # old-style virtuals currently aren't + # resolvable with empty profile, since + # 'virtuals' mappings are unavailable + # (it would be expensive to search + # for PROVIDE in all ebuilds) + atoms = [atom for atom in atoms if not \ + (atom.cp.startswith('virtual/') and \ + not portdb.cp_list(atom.cp))] + + # we have some unsolvable deps + # remove ! deps, which always show up as unsatisfiable + atoms = [str(atom.unevaluated_atom) \ + for atom in atoms if not atom.blocker] + + # if we emptied out our list, continue: + if not atoms: + continue + stats[mykey] += 1 + fails[mykey].append("%s: %s: %s(%s) %s" % \ + (relative_path, mytype, keyword, prof, repr(atoms))) + else: + stats[mykey] += 1 + fails[mykey].append("%s: %s: %s(%s) %s" % \ + (relative_path, mytype, keyword, + prof, repr(atoms))) if not baddepsyntax and unknown_pkgs: type_map = {} @@ -2178,11 +2390,11 @@ if options.if_modified == "y" and len(effective_scanlist) < 1: if options.mode == "manifest": sys.exit(dofail) -#dofail will be set to 1 if we have failed in at least one non-warning category -dofail=0 -#dowarn will be set to 1 if we tripped any warnings -dowarn=0 -#dofull will be set if we should print a "repoman full" informational message +# dofail will be set to 1 if we have failed in at least one non-warning category +dofail = 0 +# dowarn will be set to 1 if we tripped any warnings +dowarn = 0 +# dofull will be set if we should print a "repoman full" informational message dofull = options.mode != 'full' for x in qacats: @@ -2217,22 +2429,6 @@ del console_writer, f, style_file qa_output = qa_output.getvalue() qa_output = qa_output.splitlines(True) -def grouplist(mylist,seperator="/"): - """(list,seperator="/") -- Takes a list of elements; groups them into - same initial element categories. Returns a dict of {base:[sublist]} - From: ["blah/foo","spork/spatula","blah/weee/splat"] - To: {"blah":["foo","weee/splat"], "spork":["spatula"]}""" - mygroups={} - for x in mylist: - xs=x.split(seperator) - if xs[0]==".": - xs=xs[1:] - if xs[0] not in mygroups: - mygroups[xs[0]]=[seperator.join(xs[1:])] - else: - mygroups[xs[0]]+=[seperator.join(xs[1:])] - return mygroups - suggest_ignore_masked = False suggest_include_dev = False @@ -2281,65 +2477,65 @@ else: myunadded = [] if vcs == "cvs": try: - myvcstree=portage.cvstree.getentries("./",recursive=1) - myunadded=portage.cvstree.findunadded(myvcstree,recursive=1,basedir="./") + myvcstree = portage.cvstree.getentries("./", recursive=1) + myunadded = portage.cvstree.findunadded(myvcstree, recursive=1, basedir="./") except SystemExit as e: raise # TODO propagate this except: err("Error retrieving CVS tree; exiting.") if vcs == "svn": try: - with os.popen("svn status --no-ignore") as f: + with repoman_popen("svn status --no-ignore") as f: svnstatus = f.readlines() - myunadded = [ "./"+elem.rstrip().split()[1] for elem in svnstatus if elem.startswith("?") or elem.startswith("I") ] + myunadded = ["./" + elem.rstrip().split()[1] for elem in svnstatus if elem.startswith("?") or elem.startswith("I")] except SystemExit as e: raise # TODO propagate this except: err("Error retrieving SVN info; exiting.") if vcs == "git": # get list of files not under version control or missing - myf = os.popen("git ls-files --others") - myunadded = [ "./" + elem[:-1] for elem in myf ] + myf = repoman_popen("git ls-files --others") + myunadded = ["./" + elem[:-1] for elem in myf] myf.close() if vcs == "bzr": try: - with os.popen("bzr status -S .") as f: + with repoman_popen("bzr status -S .") as f: bzrstatus = f.readlines() - myunadded = [ "./"+elem.rstrip().split()[1].split('/')[-1:][0] for elem in bzrstatus if elem.startswith("?") or elem[0:2] == " D" ] + myunadded = ["./" + elem.rstrip().split()[1].split('/')[-1:][0] for elem in bzrstatus if elem.startswith("?") or elem[0:2] == " D"] except SystemExit as e: raise # TODO propagate this except: err("Error retrieving bzr info; exiting.") if vcs == "hg": - with os.popen("hg status --no-status --unknown .") as f: + with repoman_popen("hg status --no-status --unknown .") as f: myunadded = f.readlines() myunadded = ["./" + elem.rstrip() for elem in myunadded] - + # Mercurial doesn't handle manually deleted files as removed from # the repository, so the user need to remove them before commit, # using "hg remove [FILES]" - with os.popen("hg status --no-status --deleted .") as f: + with repoman_popen("hg status --no-status --deleted .") as f: mydeleted = f.readlines() mydeleted = ["./" + elem.rstrip() for elem in mydeleted] - myautoadd=[] + myautoadd = [] if myunadded: - for x in range(len(myunadded)-1,-1,-1): - xs=myunadded[x].split("/") - if xs[-1]=="files": + for x in range(len(myunadded)-1, -1, -1): + xs = myunadded[x].split("/") + if xs[-1] == "files": print("!!! files dir is not added! Please correct this.") sys.exit(-1) - elif xs[-1]=="Manifest": + elif xs[-1] == "Manifest": # It's a manifest... auto add - myautoadd+=[myunadded[x]] + myautoadd += [myunadded[x]] del myunadded[x] if myunadded: print(red("!!! The following files are in your local tree but are not added to the master")) print(red("!!! tree. Please remove them from the local tree or add them to the master tree.")) for x in myunadded: - print(" ",x) + print(" ", x) print() print() sys.exit(1) @@ -2348,7 +2544,7 @@ else: print(red("!!! The following files are removed manually from your local tree but are not")) print(red("!!! removed from the repository. Please remove them, using \"hg remove [FILES]\".")) for x in mydeleted: - print(" ",x) + print(" ", x) print() print() sys.exit(1) @@ -2357,60 +2553,59 @@ else: mycvstree = cvstree.getentries("./", recursive=1) mychanged = cvstree.findchanged(mycvstree, recursive=1, basedir="./") mynew = cvstree.findnew(mycvstree, recursive=1, basedir="./") - myremoved=portage.cvstree.findremoved(mycvstree,recursive=1,basedir="./") + myremoved = portage.cvstree.findremoved(mycvstree, recursive=1, basedir="./") bin_blob_pattern = re.compile("^-kb$") no_expansion = set(portage.cvstree.findoption(mycvstree, bin_blob_pattern, recursive=1, basedir="./")) - if vcs == "svn": - with os.popen("svn status") as f: + with repoman_popen("svn status") as f: svnstatus = f.readlines() - mychanged = [ "./" + elem.split()[-1:][0] for elem in svnstatus if (elem[:1] in "MR" or elem[1:2] in "M")] - mynew = [ "./" + elem.split()[-1:][0] for elem in svnstatus if elem.startswith("A")] - myremoved = [ "./" + elem.split()[-1:][0] for elem in svnstatus if elem.startswith("D")] + mychanged = ["./" + elem.split()[-1:][0] for elem in svnstatus if (elem[:1] in "MR" or elem[1:2] in "M")] + mynew = ["./" + elem.split()[-1:][0] for elem in svnstatus if elem.startswith("A")] + myremoved = ["./" + elem.split()[-1:][0] for elem in svnstatus if elem.startswith("D")] # Subversion expands keywords specified in svn:keywords properties. - with os.popen("svn propget -R svn:keywords") as f: + with repoman_popen("svn propget -R svn:keywords") as f: props = f.readlines() expansion = dict(("./" + prop.split(" - ")[0], prop.split(" - ")[1].split()) \ for prop in props if " - " in prop) elif vcs == "git": - with os.popen("git diff-index --name-only " + with repoman_popen("git diff-index --name-only " "--relative --diff-filter=M HEAD") as f: mychanged = f.readlines() mychanged = ["./" + elem[:-1] for elem in mychanged] - with os.popen("git diff-index --name-only " + with repoman_popen("git diff-index --name-only " "--relative --diff-filter=A HEAD") as f: mynew = f.readlines() mynew = ["./" + elem[:-1] for elem in mynew] - with os.popen("git diff-index --name-only " + with repoman_popen("git diff-index --name-only " "--relative --diff-filter=D HEAD") as f: myremoved = f.readlines() myremoved = ["./" + elem[:-1] for elem in myremoved] if vcs == "bzr": - with os.popen("bzr status -S .") as f: + with repoman_popen("bzr status -S .") as f: bzrstatus = f.readlines() - mychanged = [ "./" + elem.split()[-1:][0].split('/')[-1:][0] for elem in bzrstatus if elem and elem[1:2] == "M" ] - mynew = [ "./" + elem.split()[-1:][0].split('/')[-1:][0] for elem in bzrstatus if elem and ( elem[1:2] in "NK" or elem[0:1] == "R" ) ] - myremoved = [ "./" + elem.split()[-1:][0].split('/')[-1:][0] for elem in bzrstatus if elem.startswith("-") ] - myremoved = [ "./" + elem.split()[-3:-2][0].split('/')[-1:][0] for elem in bzrstatus if elem and ( elem[1:2] == "K" or elem[0:1] == "R" ) ] + mychanged = ["./" + elem.split()[-1:][0].split('/')[-1:][0] for elem in bzrstatus if elem and elem[1:2] == "M"] + mynew = ["./" + elem.split()[-1:][0].split('/')[-1:][0] for elem in bzrstatus if elem and (elem[1:2] in "NK" or elem[0:1] == "R")] + myremoved = ["./" + elem.split()[-1:][0].split('/')[-1:][0] for elem in bzrstatus if elem.startswith("-")] + myremoved = ["./" + elem.split()[-3:-2][0].split('/')[-1:][0] for elem in bzrstatus if elem and (elem[1:2] == "K" or elem[0:1] == "R")] # Bazaar expands nothing. if vcs == "hg": - with os.popen("hg status --no-status --modified .") as f: + with repoman_popen("hg status --no-status --modified .") as f: mychanged = f.readlines() mychanged = ["./" + elem.rstrip() for elem in mychanged] - with os.popen("hg status --no-status --added .") as f: + with repoman_popen("hg status --no-status --added .") as f: mynew = f.readlines() mynew = ["./" + elem.rstrip() for elem in mynew] - with os.popen("hg status --no-status --removed .") as f: + with repoman_popen("hg status --no-status --removed .") as f: myremoved = f.readlines() myremoved = ["./" + elem.rstrip() for elem in myremoved] @@ -2469,21 +2664,54 @@ else: commitmessage = commitmessage.rstrip() changelog_msg = commitmessage portage_version = getattr(portage, "VERSION", None) + gpg_key = repoman_settings.get("PORTAGE_GPG_KEY", "") + dco_sob = repoman_settings.get("DCO_SIGNED_OFF_BY", "") if portage_version is None: sys.stderr.write("Failed to insert portage version in message!\n") sys.stderr.flush() portage_version = "Unknown" - unameout = platform.system() + " " - if platform.system() in ["Darwin", "SunOS"]: - unameout += platform.processor() - else: - unameout += platform.machine() - commitmessage += "\n\n(Portage version: %s/%s/%s" % \ - (portage_version, vcs, unameout) + + report_options = [] if options.force: - commitmessage += ", RepoMan options: --force" - commitmessage += ")" + report_options.append("--force") + if options.ignore_arches: + report_options.append("--ignore-arches") + if include_arches is not None: + report_options.append("--include-arches=\"%s\"" % + " ".join(sorted(include_arches))) + if vcs == "git": + # Use new footer only for git (see bug #438364). + commit_footer = "\n\nPackage-Manager: portage-%s" % portage_version + if report_options: + commit_footer += "\nRepoMan-Options: " + " ".join(report_options) + if sign_manifests: + commit_footer += "\nManifest-Sign-Key: %s" % (gpg_key, ) + if dco_sob: + commit_footer += "\nSigned-off-by: %s" % (dco_sob, ) + else: + unameout = platform.system() + " " + if platform.system() in ["Darwin", "SunOS"]: + unameout += platform.processor() + else: + unameout += platform.machine() + commit_footer = "\n\n" + if dco_sob: + commit_footer += "Signed-off-by: %s\n" % (dco_sob, ) + commit_footer += "(Portage version: %s/%s/%s" % \ + (portage_version, vcs, unameout) + if report_options: + commit_footer += ", RepoMan options: " + " ".join(report_options) + if sign_manifests: + commit_footer += ", signed Manifest commit with key %s" % \ + (gpg_key, ) + else: + commit_footer += ", unsigned Manifest commit" + commit_footer += ")" + + commitmessage += commit_footer + + broken_changelog_manifests = [] if options.echangelog in ('y', 'force'): logging.info("checking for unmodified ChangeLog files") committer_name = utilities.get_committer_name(env=repoman_settings) @@ -2535,6 +2763,13 @@ else: else: myupdates.append(changelog_path) + if options.ask and not options.pretend: + # regenerate Manifest for modified ChangeLog (bug #420735) + repoman_settings["O"] = checkdir + digestgen(mysettings=repoman_settings, myportdb=portdb) + else: + broken_changelog_manifests.append(x) + if myautoadd: print(">>> Auto-Adding missing Manifest/ChangeLog file(s)...") add_cmd = [vcs, "add"] @@ -2543,15 +2778,17 @@ else: portage.writemsg_stdout("(%s)\n" % " ".join(add_cmd), noiselevel=-1) else: - if not (sys.hexversion >= 0x3000000 and sys.hexversion < 0x3020000): - # Python 3.1 produces the following TypeError if raw bytes are - # passed to subprocess.call(): - # File "/usr/lib/python3.1/subprocess.py", line 646, in __init__ - # errread, errwrite) - # File "/usr/lib/python3.1/subprocess.py", line 1157, in _execute_child - # raise child_exception - # TypeError: expected an object with the buffer interface - add_cmd = [_unicode_encode(arg) for arg in add_cmd] + + if sys.hexversion < 0x3020000 and sys.hexversion >= 0x3000000 and \ + not os.path.isabs(add_cmd[0]): + # Python 3.1 _execvp throws TypeError for non-absolute executable + # path passed as bytes (see http://bugs.python.org/issue8513). + fullname = find_binary(add_cmd[0]) + if fullname is None: + raise portage.exception.CommandNotFound(add_cmd[0]) + add_cmd[0] = fullname + + add_cmd = [_unicode_encode(arg) for arg in add_cmd] retcode = subprocess.call(add_cmd) if retcode != os.EX_OK: logging.error( @@ -2596,7 +2833,7 @@ else: elif vcs == "svn": if myfile not in expansion: continue - + # Subversion keywords are case-insensitive in svn:keywords properties, but case-sensitive in contents of files. enabled_keywords = [] for k in expansion[myfile]: @@ -2606,7 +2843,8 @@ else: headerstring = "'\$(%s).*\$'" % "|".join(enabled_keywords) - myout = subprocess_getstatusoutput("egrep -q "+headerstring+" "+myfile) + myout = repoman_getstatusoutput("egrep -q " + headerstring + " " + + portage._shell_quote(myfile)) if myout[0] == 0: myheaders.append(myfile) @@ -2653,7 +2891,7 @@ else: if options.pretend: print("(%s)" % (" ".join(commit_cmd),)) else: - retval = spawn(commit_cmd, env=os.environ) + retval = spawn(commit_cmd, env=commit_env) if retval != os.EX_OK: writemsg_level(("!!! Exiting on %s (shell) " + \ "error code: %s\n") % (vcs, retval), @@ -2694,14 +2932,38 @@ else: gpgvars[k] = v gpgcmd = portage.util.varexpand(gpgcmd, mydict=gpgvars) if options.pretend: - print("("+gpgcmd+")") + print("(" + gpgcmd + ")") else: - rValue = os.system(gpgcmd) + # Encode unicode manually for bug #310789. + gpgcmd = portage.util.shlex_split(gpgcmd) + + if sys.hexversion < 0x3020000 and sys.hexversion >= 0x3000000 and \ + not os.path.isabs(gpgcmd[0]): + # Python 3.1 _execvp throws TypeError for non-absolute executable + # path passed as bytes (see http://bugs.python.org/issue8513). + fullname = find_binary(gpgcmd[0]) + if fullname is None: + raise portage.exception.CommandNotFound(gpgcmd[0]) + gpgcmd[0] = fullname + + gpgcmd = [_unicode_encode(arg, + encoding=_encodings['fs'], errors='strict') for arg in gpgcmd] + rValue = subprocess.call(gpgcmd) if rValue == os.EX_OK: - os.rename(filename+".asc", filename) + os.rename(filename + ".asc", filename) else: raise portage.exception.PortageException("!!! gpg exited with '" + str(rValue) + "' status") + def need_signature(filename): + try: + with open(_unicode_encode(filename, + encoding=_encodings['fs'], errors='strict'), 'rb') as f: + return b"BEGIN PGP SIGNED MESSAGE" not in f.readline() + except IOError as e: + if e.errno in (errno.ENOENT, errno.ESTALE): + return False + raise + # When files are removed and re-added, the cvs server will put /Attic/ # inside the $Header path. This code detects the problem and corrects it # so that the Manifest will generate correctly. See bug #169500. @@ -2736,6 +2998,11 @@ else: repoman_settings["O"] = os.path.join(repodir, x) digestgen(mysettings=repoman_settings, myportdb=portdb) + elif broken_changelog_manifests: + for x in broken_changelog_manifests: + repoman_settings["O"] = os.path.join(repodir, x) + digestgen(mysettings=repoman_settings, myportdb=portdb) + signed = False if sign_manifests: signed = True @@ -2743,7 +3010,10 @@ else: for x in sorted(vcs_files_to_cps( chain(myupdates, myremoved, mymanifests))): repoman_settings["O"] = os.path.join(repodir, x) - gpgsign(os.path.join(repoman_settings["O"], "Manifest")) + manifest_path = os.path.join(repoman_settings["O"], "Manifest") + if not need_signature(manifest_path): + continue + gpgsign(manifest_path) except portage.exception.PortageException as e: portage.writemsg("!!! %s\n" % str(e)) portage.writemsg("!!! Disabled FEATURES='sign'\n") @@ -2771,7 +3041,6 @@ else: sys.exit(retval) if True: - myfiles = mymanifests[:] # If there are no header (SVN/CVS keywords) changes in # the files, this Manifest commit must include the @@ -2783,14 +3052,7 @@ else: fd, commitmessagefile = tempfile.mkstemp(".repoman.msg") mymsg = os.fdopen(fd, "wb") - # strip the closing parenthesis - mymsg.write(_unicode_encode(commitmessage[:-1])) - if signed: - mymsg.write(_unicode_encode( - ", signed Manifest commit with key %s)" % \ - repoman_settings["PORTAGE_GPG_KEY"])) - else: - mymsg.write(b", unsigned Manifest commit)") + mymsg.write(_unicode_encode(commitmessage)) mymsg.close() commit_cmd = [] @@ -2813,9 +3075,8 @@ else: if options.pretend: print("(%s)" % (" ".join(commit_cmd),)) else: - retval = spawn(commit_cmd, env=os.environ) + retval = spawn(commit_cmd, env=commit_env) if retval != os.EX_OK: - if repo_config.sign_commit and vcs == 'git' and \ not git_supports_gpg_sign(): # Inform user that newer git is needed (bug #403323). @@ -2839,4 +3100,3 @@ else: print("repoman was too scared by not seeing any familiar version control file that he forgot to commit anything") print(green("RepoMan sez:"), "\"If everyone were like you, I'd be out of business!\"\n") sys.exit(0) - diff --git a/portage_with_autodep/bin/save-ebuild-env.sh b/portage_with_autodep/bin/save-ebuild-env.sh index 23e7aaa..7a31b89 100755 --- a/portage_with_autodep/bin/save-ebuild-env.sh +++ b/portage_with_autodep/bin/save-ebuild-env.sh @@ -1,8 +1,8 @@ #!/bin/bash -# Copyright 1999-2011 Gentoo Foundation +# Copyright 1999-2013 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 -# @FUNCTION: save_ebuild_env +# @FUNCTION: __save_ebuild_env # @DESCRIPTION: # echo the current environment to stdout, filtering out redundant info. # @@ -10,11 +10,12 @@ # be excluded from the output. These function are not needed for installation # or removal of the packages, and can therefore be safely excluded. # -save_ebuild_env() { +__save_ebuild_env() { ( if has --exclude-init-phases $* ; then unset S _E_DOCDESTTREE_ _E_EXEDESTTREE_ \ - PORTAGE_DOCOMPRESS PORTAGE_DOCOMPRESS_SKIP + PORTAGE_DOCOMPRESS_SIZE_LIMIT PORTAGE_DOCOMPRESS \ + PORTAGE_DOCOMPRESS_SKIP if [[ -n $PYTHONPATH && ${PYTHONPATH%%:*} -ef $PORTAGE_PYM_PATH ]] ; then if [[ $PYTHONPATH == *:* ]] ; then @@ -42,35 +43,51 @@ save_ebuild_env() { for x in pkg_setup pkg_nofetch src_unpack src_prepare src_configure \ src_compile src_test src_install pkg_preinst pkg_postinst \ pkg_prerm pkg_postrm ; do - unset -f default_$x _eapi{0,1,2,3,4}_$x + unset -f default_$x __eapi{0,1,2,3,4}_$x done unset x - unset -f assert assert_sigpipe_ok dump_trace die diefunc \ - quiet_mode vecho elog_base eqawarn elog \ - esyslog einfo einfon ewarn eerror ebegin _eend eend KV_major \ - KV_minor KV_micro KV_to_int get_KV unset_colors set_colors has \ - has_phase_defined_up_to \ - hasv hasq qa_source qa_call \ - addread addwrite adddeny addpredict _sb_append_var \ + unset -f assert __assert_sigpipe_ok \ + __dump_trace die \ + __quiet_mode __vecho __elog_base eqawarn elog \ + einfo einfon ewarn eerror ebegin __eend eend KV_major \ + KV_minor KV_micro KV_to_int get_KV __1 __1 has \ + __has_phase_defined_up_to \ + hasv hasq __qa_source __qa_call \ + addread addwrite adddeny addpredict __sb_append_var \ use usev useq has_version portageq \ best_version use_with use_enable register_die_hook \ - keepdir unpack strip_duplicate_slashes econf einstall \ - dyn_setup dyn_unpack dyn_clean into insinto exeinto docinto \ + unpack __strip_duplicate_slashes econf einstall \ + __dyn_setup __dyn_unpack __dyn_clean \ + into insinto exeinto docinto \ insopts diropts exeopts libopts docompress \ - abort_handler abort_prepare abort_configure abort_compile \ - abort_test abort_install dyn_prepare dyn_configure \ - dyn_compile dyn_test dyn_install \ - dyn_preinst dyn_pretend dyn_help debug-print debug-print-function \ - debug-print-section helpers_die inherit EXPORT_FUNCTIONS \ - nonfatal register_success_hook remove_path_entry \ - save_ebuild_env filter_readonly_variables preprocess_ebuild_env \ - set_unless_changed unset_unless_changed source_all_bashrcs \ - ebuild_main ebuild_phase ebuild_phase_with_hooks \ - _ebuild_arg_to_phase _ebuild_phase_funcs default \ - _hasg _hasgq _unpack_tar \ + __abort_handler __abort_prepare __abort_configure __abort_compile \ + __abort_test __abort_install __dyn_prepare __dyn_configure \ + __dyn_compile __dyn_test __dyn_install \ + __dyn_pretend __dyn_help \ + debug-print debug-print-function \ + debug-print-section __helpers_die inherit EXPORT_FUNCTIONS \ + nonfatal register_success_hook \ + __hasg __hasgq \ + __save_ebuild_env __set_colors __filter_readonly_variables \ + __preprocess_ebuild_env \ + __repo_key __source_all_bashrcs \ + __ebuild_main __ebuild_phase __ebuild_phase_with_hooks \ + __ebuild_arg_to_phase __ebuild_phase_funcs default \ + __unpack_tar __unset_colors \ ${QA_INTERCEPTORS} + ___eapi_has_usex && unset -f usex + ___eapi_has_master_repositories && unset -f master_repositories + ___eapi_has_repository_path && unset -f repository_path + ___eapi_has_available_eclasses && unset -f available_eclasses + ___eapi_has_eclass_path && unset -f eclass_path + ___eapi_has_license_path && unset -f license_path + ___eapi_has_package_manager_build_user && unset -f package_manager_build_user + ___eapi_has_package_manager_build_group && unset -f package_manager_build_group + + unset -f $(compgen -A function ___eapi_) + # portage config variables and variables set directly by portage unset ACCEPT_LICENSE BAD BRACKET BUILD_PREFIX COLS \ DISTCC_DIR DISTDIR DOC_SYMLINKS_DIR \ @@ -79,7 +96,11 @@ save_ebuild_env() { GOOD HILITE HOME \ LAST_E_CMD LAST_E_LEN LD_PRELOAD MISC_FUNCTIONS_ARGS MOPREFIX \ NOCOLOR NORMAL PKGDIR PKGUSE PKG_LOGDIR PKG_TMPDIR \ - PORTAGE_BASHRCS_SOURCED PORTAGE_COMPRESS_EXCLUDE_SUFFIXES \ + PORTAGE_BASHRCS_SOURCED PORTAGE_COMPRESS \ + PORTAGE_COMPRESS_EXCLUDE_SUFFIXES \ + PORTAGE_DOHTML_UNWARNED_SKIPPED_EXTENSIONS \ + PORTAGE_DOHTML_UNWARNED_SKIPPED_FILES \ + PORTAGE_DOHTML_WARN_ON_SKIPPED_FILES \ PORTAGE_NONFATAL PORTAGE_QUIET \ PORTAGE_SANDBOX_DENY PORTAGE_SANDBOX_PREDICT \ PORTAGE_SANDBOX_READ PORTAGE_SANDBOX_WRITE PREROOTPATH \ diff --git a/portage_with_autodep/bin/xpak-helper.py b/portage_with_autodep/bin/xpak-helper.py index ef74920..d9d325d 100755 --- a/portage_with_autodep/bin/xpak-helper.py +++ b/portage_with_autodep/bin/xpak-helper.py @@ -1,11 +1,12 @@ #!/usr/bin/python -# Copyright 2009-2011 Gentoo Foundation +# Copyright 2009-2013 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 -import optparse import sys import portage +portage._internal_caller = True from portage import os +from portage.util._argparse import ArgumentParser def command_recompose(args): @@ -45,8 +46,8 @@ def main(argv): usage = "usage: %s COMMAND [args]" % \ os.path.basename(argv[0]) - parser = optparse.OptionParser(description=description, usage=usage) - options, args = parser.parse_args(argv[1:]) + parser = ArgumentParser(description=description, usage=usage) + options, args = parser.parse_known_args(argv[1:]) if not args: parser.error("missing command argument") diff --git a/portage_with_autodep/integration_with_portage.patch b/portage_with_autodep/integration_with_portage.patch deleted file mode 100644 index 794c156..0000000 --- a/portage_with_autodep/integration_with_portage.patch +++ /dev/null @@ -1,920 +0,0 @@ -diff -urN /usr/lib/portage/pym/_emerge/EbuildBuild.py ./pym/_emerge/EbuildBuild.py ---- /usr/lib/portage/pym/_emerge/EbuildBuild.py 2012-05-28 16:20:40.737712559 +0600 -+++ ./pym/_emerge/EbuildBuild.py 2012-06-01 21:37:22.799844102 +0600 -@@ -9,6 +9,8 @@ - from _emerge.EbuildMerge import EbuildMerge - from _emerge.EbuildFetchonly import EbuildFetchonly - from _emerge.EbuildBuildDir import EbuildBuildDir -+from _emerge.EventsAnalyser import EventsAnalyser, FilterProcGenerator -+from _emerge.EventsLogger import EventsLogger - from _emerge.MiscFunctionsProcess import MiscFunctionsProcess - from portage.util import writemsg - import portage -@@ -21,7 +23,7 @@ - class EbuildBuild(CompositeTask): - - __slots__ = ("args_set", "config_pool", "find_blockers", -- "ldpath_mtimes", "logger", "opts", "pkg", "pkg_count", -+ "ldpath_mtimes", "logger", "logserver", "opts", "pkg", "pkg_count", - "prefetcher", "settings", "world_atom") + \ - ("_build_dir", "_buildpkg", "_ebuild_path", "_issyspkg", "_tree") - -@@ -251,8 +253,54 @@ - - build = EbuildExecuter(background=self.background, pkg=pkg, - scheduler=scheduler, settings=settings) -+ -+ build.addStartListener(self._build_start) -+ build.addExitListener(self._build_stop) -+ - self._start_task(build, self._build_exit) - -+ def _build_start(self,phase): -+ if "depcheck" in self.settings["FEATURES"] or \ -+ "depcheckstrict" in self.settings["FEATURES"]: -+ # Lets start a log listening server -+ temp_path=self.settings.get("T",self.settings["PORTAGE_TMPDIR"]) -+ -+ if "depcheckstrict" not in self.settings["FEATURES"]: -+ # use default filter_proc -+ self.logserver=EventsLogger(socket_dir=temp_path) -+ else: -+ portage.util.writemsg("Getting list of allowed files..." + \ -+ "This may take some time\n") -+ filter_gen=FilterProcGenerator(self.pkg.cpv, self.settings) -+ filter_proc=filter_gen.get_filter_proc() -+ self.logserver=EventsLogger(socket_dir=temp_path, -+ filter_proc=filter_proc) -+ -+ self.logserver.start() -+ -+ # Copy socket path to LOG_SOCKET environment variable -+ env=self.settings.configdict["pkg"] -+ env['LOG_SOCKET'] = self.logserver.socket_name -+ -+ #import pdb; pdb.set_trace() -+ -+ def _build_stop(self,phase): -+ if "depcheck" in self.settings["FEATURES"] or \ -+ "depcheckstrict" in self.settings["FEATURES"]: -+ # Delete LOG_SOCKET from environment -+ env=self.settings.configdict["pkg"] -+ if 'LOG_SOCKET' in env: -+ del env['LOG_SOCKET'] -+ -+ events=self.logserver.stop() -+ self.logserver=None -+ analyser=EventsAnalyser(self.pkg.cpv, events, self.settings) -+ analyser.display() # show the analyse -+ -+ #import pdb; pdb.set_trace() -+ -+ -+ - def _fetch_failed(self): - # We only call the pkg_nofetch phase if either RESTRICT=fetch - # is set or the package has explicitly overridden the default -diff -urN /usr/lib/portage/pym/_emerge/EbuildPhase.py ./pym/_emerge/EbuildPhase.py ---- /usr/lib/portage/pym/_emerge/EbuildPhase.py 2012-05-28 16:20:40.738712559 +0600 -+++ ./pym/_emerge/EbuildPhase.py 2012-06-01 21:38:11.935842036 +0600 -@@ -34,7 +34,8 @@ - - # FEATURES displayed prior to setup phase - _features_display = ( -- "ccache", "compressdebug", "distcc", "distcc-pump", "fakeroot", -+ "ccache", "compressdebug", "depcheck", "depcheckstrict", -+ "distcc", "distcc-pump", "fakeroot", - "installsources", "keeptemp", "keepwork", "nostrip", - "preserve-libs", "sandbox", "selinux", "sesandbox", - "splitdebug", "suidctl", "test", "userpriv", -diff -urN /usr/lib/portage/pym/_emerge/EbuildPhase.py.rej ./pym/_emerge/EbuildPhase.py.rej ---- /usr/lib/portage/pym/_emerge/EbuildPhase.py.rej 1970-01-01 05:00:00.000000000 +0500 -+++ ./pym/_emerge/EbuildPhase.py.rej 2012-06-01 21:37:22.800844102 +0600 -@@ -0,0 +1,12 @@ -+--- pym/_emerge/EbuildPhase.py -++++ pym/_emerge/EbuildPhase.py -+@@ -33,7 +33,8 @@ -+ ("_ebuild_lock",) -+ -+ # FEATURES displayed prior to setup phase -+- _features_display = ("ccache", "distcc", "distcc-pump", "fakeroot", -++ _features_display = ("ccache", "depcheck", "depcheckstrict" "distcc", -++ "distcc-pump", "fakeroot", -+ "installsources", "keeptemp", "keepwork", "nostrip", -+ "preserve-libs", "sandbox", "selinux", "sesandbox", -+ "splitdebug", "suidctl", "test", "userpriv", -diff -urN /usr/lib/portage/pym/_emerge/EventsAnalyser.py ./pym/_emerge/EventsAnalyser.py ---- /usr/lib/portage/pym/_emerge/EventsAnalyser.py 1970-01-01 05:00:00.000000000 +0500 -+++ ./pym/_emerge/EventsAnalyser.py 2012-06-01 21:37:22.802844102 +0600 -@@ -0,0 +1,511 @@ -+# Distributed under the terms of the GNU General Public License v2 -+ -+import portage -+from portage.dbapi._expand_new_virt import expand_new_virt -+from portage import os -+ -+import subprocess -+import re -+ -+class PortageUtils: -+ """ class for accessing the portage api """ -+ def __init__(self, settings): -+ """ test """ -+ self.settings=settings -+ self.vartree=portage.vartree(settings=settings) -+ self.vardbapi=portage.vardbapi(settings=settings, vartree=self.vartree) -+ self.portdbapi=portage.portdbapi(mysettings=settings) -+ self.metadata_keys = [k for k in portage.auxdbkeys if not k.startswith("UNUSED_")] -+ self.use=self.settings["USE"] -+ -+ def get_best_visible_pkg(self,pkg): -+ """ -+ Gets best candidate on installing. Returns empty string if no found -+ -+ :param pkg: package name -+ -+ """ -+ try: -+ return self.portdbapi.xmatch("bestmatch-visible", pkg) -+ except: -+ return '' -+ -+ # non-recursive dependency getter -+ def get_dep(self,pkg,dep_type=["RDEPEND","DEPEND"]): -+ """ -+ Gets current dependencies of a package. Looks in portage db -+ -+ :param pkg: name of package -+ :param dep_type: type of dependencies to recurse. Can be ["DEPEND"] or -+ ["RDEPEND", "DEPEND"] -+ :returns: **set** of packages names -+ """ -+ ret=set() -+ -+ pkg = self.get_best_visible_pkg(pkg) -+ if not pkg: -+ return ret -+ -+ # we found the best visible match in common tree -+ -+ -+ metadata = dict(zip(self.metadata_keys, -+ self.portdbapi.aux_get(pkg, self.metadata_keys))) -+ dep_str = " ".join(metadata[k] for k in dep_type) -+ -+ # the IUSE default are very important for us -+ iuse_defaults=[ -+ u[1:] for u in metadata.get("IUSE",'').split() if u.startswith("+")] -+ -+ use=self.use.split() -+ -+ for u in iuse_defaults: -+ if u not in use: -+ use.append(u) -+ -+ success, atoms = portage.dep_check(dep_str, None, self.settings, -+ myuse=use, myroot=self.settings["ROOT"], -+ trees={self.settings["ROOT"]:{"vartree":self.vartree, "porttree": self.vartree}}) -+ if not success: -+ return ret -+ -+ for atom in atoms: -+ atomname = self.vartree.dep_bestmatch(atom) -+ -+ if not atomname: -+ continue -+ -+ for unvirt_pkg in expand_new_virt(self.vardbapi,'='+atomname): -+ for pkg in self.vartree.dep_match(unvirt_pkg): -+ ret.add(pkg) -+ -+ return ret -+ -+ # recursive dependency getter -+ def get_deps(self,pkg,dep_type=["RDEPEND","DEPEND"]): -+ """ -+ Gets current dependencies of a package on any depth -+ All dependencies **must** be installed -+ -+ :param pkg: name of package -+ :param dep_type: type of dependencies to recurse. Can be ["DEPEND"] or -+ ["RDEPEND", "DEPEND"] -+ :returns: **set** of packages names -+ """ -+ ret=set() -+ -+ -+ # get porttree dependencies on the first package -+ -+ pkg = self.portdbapi.xmatch("bestmatch-visible", pkg) -+ if not pkg: -+ return ret -+ -+ known_packages=set() -+ unknown_packages=self.get_dep(pkg,dep_type) -+ ret=ret.union(unknown_packages) -+ -+ while unknown_packages: -+ p=unknown_packages.pop() -+ if p in known_packages: -+ continue -+ known_packages.add(p) -+ -+ metadata = dict(zip(self.metadata_keys, self.vardbapi.aux_get(p, self.metadata_keys))) -+ -+ dep_str = " ".join(metadata[k] for k in dep_type) -+ -+ # the IUSE default are very important for us -+ iuse_defaults=[ -+ u[1:] for u in metadata.get("IUSE",'').split() if u.startswith("+")] -+ -+ use=self.use.split() -+ -+ for u in iuse_defaults: -+ if u not in use: -+ use.append(u) -+ -+ success, atoms = portage.dep_check(dep_str, None, self.settings, -+ myuse=use, myroot=self.settings["ROOT"], -+ trees={self.settings["ROOT"]:{"vartree":self.vartree,"porttree": self.vartree}}) -+ -+ if not success: -+ continue -+ -+ for atom in atoms: -+ atomname = self.vartree.dep_bestmatch(atom) -+ if not atomname: -+ continue -+ -+ for unvirt_pkg in expand_new_virt(self.vardbapi,'='+atomname): -+ for pkg in self.vartree.dep_match(unvirt_pkg): -+ ret.add(pkg) -+ unknown_packages.add(pkg) -+ return ret -+ -+ def get_deps_for_package_building(self, pkg): -+ """ -+ returns buildtime dependencies of current package and -+ all runtime dependencies of that buildtime dependencies -+ """ -+ buildtime_deps=self.get_dep(pkg, ["DEPEND"]) -+ runtime_deps=set() -+ for dep in buildtime_deps: -+ runtime_deps=runtime_deps.union(self.get_deps(dep,["RDEPEND"])) -+ -+ ret=buildtime_deps.union(runtime_deps) -+ return ret -+ -+ def get_system_packages_list(self): -+ """ -+ returns all packages from system set. They are always implicit dependencies -+ -+ :returns: **list** of package names -+ """ -+ ret=[] -+ for atom in self.settings.packages: -+ for pre_pkg in self.vartree.dep_match(atom): -+ for unvirt_pkg in expand_new_virt(self.vardbapi,'='+pre_pkg): -+ for pkg in self.vartree.dep_match(unvirt_pkg): -+ ret.append(pkg) -+ return ret -+ -+ -+class GentoolkitUtils: -+ """ -+ Interface with qfile and qlist utils. They are much faster than -+ internals. -+ """ -+ -+ def getpackagesbyfiles(files): -+ """ -+ :param files: list of filenames -+ :returns: **dictionary** file->package, if file doesn't belong to any -+ package it not returned as key of this dictionary -+ """ -+ ret={} -+ listtocheck=[] -+ for f in files: -+ if os.path.isdir(f): -+ ret[f]="directory" -+ else: -+ listtocheck.append(f) -+ -+ try: -+ proc=subprocess.Popen(['qfile']+['--nocolor','--exact','','--from','-'], -+ stdin=subprocess.PIPE, stdout=subprocess.PIPE,stderr=subprocess.PIPE, -+ bufsize=4096) -+ -+ out,err=proc.communicate("\n".join(listtocheck).encode("utf8")) -+ -+ lines=out.decode("utf8").split("\n") -+ #print lines -+ line_re=re.compile(r"^([^ ]+)\s+\(([^)]+)\)$") -+ for line in lines: -+ if len(line)==0: -+ continue -+ match=line_re.match(line) -+ if match: -+ ret[match.group(2)]=match.group(1) -+ else: -+ portage.util.writemsg("Util qfile returned unparsable string: %s\n" % line) -+ -+ except OSError as e: -+ portage.util.writemsg("Error while launching qfile: %s\n" % e) -+ -+ -+ return ret -+ -+ def getfilesbypackages(packagenames): -+ """ -+ -+ :param packagename: name of package -+ :returns: **list** of files in package with name *packagename* -+ """ -+ ret=[] -+ try: -+ proc=subprocess.Popen(['qlist']+['--nocolor',"--obj"]+packagenames, -+ stdout=subprocess.PIPE,stderr=subprocess.PIPE, -+ bufsize=4096) -+ -+ out,err=proc.communicate() -+ -+ ret=out.decode("utf8").split("\n") -+ if ret==['']: -+ ret=[] -+ except OSError as e: -+ portage.util.writemsg("Error while launching qfile: %s\n" % e) -+ -+ return ret -+ -+ def get_all_packages_files(): -+ """ -+ Memory-hungry operation -+ -+ :returns: **set** of all files that belongs to package -+ """ -+ ret=[] -+ try: -+ proc=subprocess.Popen(['qlist']+['--all',"--obj"], -+ stdout=subprocess.PIPE,stderr=subprocess.PIPE, -+ bufsize=4096) -+ -+ out,err=proc.communicate() -+ -+ ret=out.decode("utf8").split("\n") -+ except OSError as e: -+ portage.util.writemsg("Error while launching qfile: %s\n" % e) -+ -+ return set(ret) -+ -+class FilterProcGenerator: -+ def __init__(self, pkgname, settings): -+ portageutils=PortageUtils(settings=settings) -+ -+ deps_all=portageutils.get_deps_for_package_building(pkgname) -+ deps_portage=portageutils.get_dep('portage',["RDEPEND"]) -+ -+ system_packages=portageutils.get_system_packages_list() -+ -+ allfiles=GentoolkitUtils.get_all_packages_files() -+ portage.util.writemsg("All files list recieved, waiting for " \ -+ "a list of allowed files\n") -+ -+ -+ allowedpkgs=system_packages+list(deps_portage)+list(deps_all) -+ -+ allowedfiles=GentoolkitUtils.getfilesbypackages(allowedpkgs) -+ #for pkg in allowedpkgs: -+ # allowedfiles+=GentoolkitUtils.getfilesbypackage(pkg) -+ -+ #import pdb; pdb.set_trace() -+ -+ # manually add all python interpreters to this list -+ allowedfiles+=GentoolkitUtils.getfilesbypackages(['python']) -+ allowedfiles=set(allowedfiles) -+ -+ deniedfiles=allfiles-allowedfiles -+ -+ def filter_proc(eventname,filename,stage): -+ if filename in deniedfiles: -+ return False -+ return True -+ -+ self.filter_proc=filter_proc -+ def get_filter_proc(self): -+ return self.filter_proc -+ -+class EventsAnalyser: -+ def __init__(self, pkgname, events, settings): -+ self.pkgname=pkgname -+ self.events=events -+ self.settings=settings -+ self.portageutils=PortageUtils(settings=settings) -+ -+ self.deps_all=self.portageutils.get_deps_for_package_building(pkgname) -+ self.deps_direct=self.portageutils.get_dep(pkgname,["DEPEND"]) -+ self.deps_portage=self.portageutils.get_dep('portage',["RDEPEND"]) -+ -+ self.system_packages=self.portageutils.get_system_packages_list() -+ # All analyse work is here -+ -+ # get unique filenames -+ filenames=set() -+ for stage in events: -+ succ_events=set(events[stage][0]) -+ fail_events=set(events[stage][1]) -+ filenames=filenames.union(succ_events) -+ filenames=filenames.union(fail_events) -+ filenames=list(filenames) -+ -+ file_to_package=GentoolkitUtils.getpackagesbyfiles(filenames) -+ # This part is completly unreadable. -+ # It converting one complex struct(returned by getfsevents) to another complex -+ # struct which good for generating output. -+ # -+ # Old struct is also used during output -+ -+ packagesinfo={} -+ -+ for stage in sorted(events): -+ succ_events=events[stage][0] -+ fail_events=events[stage][1] -+ -+ for filename in succ_events: -+ if filename in file_to_package: -+ package=file_to_package[filename] -+ else: -+ package="unknown" -+ -+ if not package in packagesinfo: -+ packagesinfo[package]={} -+ stageinfo=packagesinfo[package] -+ if not stage in stageinfo: -+ stageinfo[stage]={} -+ -+ filesinfo=stageinfo[stage] -+ if not filename in filesinfo: -+ filesinfo[filename]={"found":[],"notfound":[]} -+ filesinfo[filename]["found"]=succ_events[filename] -+ -+ for filename in fail_events: -+ if filename in file_to_package: -+ package=file_to_package[filename] -+ else: -+ package="unknown" -+ if not package in packagesinfo: -+ packagesinfo[package]={} -+ stageinfo=packagesinfo[package] -+ if not stage in stageinfo: -+ stageinfo[stage]={} -+ -+ filesinfo=stageinfo[stage] -+ if not filename in filesinfo: -+ filesinfo[filename]={"found":[],"notfound":[]} -+ filesinfo[filename]["notfound"]=fail_events[filename] -+ self.packagesinfo=packagesinfo -+ -+ def display(self): -+ portage.util.writemsg( -+ portage.output.colorize( -+ "WARN", "\nFile access report for %s:\n" % self.pkgname)) -+ -+ stagesorder={"clean":1,"setup":2,"unpack":3,"prepare":4,"configure":5,"compile":6,"test":7, -+ "install":8,"preinst":9,"postinst":10,"prerm":11,"postrm":12,"unknown":13} -+ packagesinfo=self.packagesinfo -+ # print information grouped by package -+ for package in sorted(packagesinfo): -+ # not showing special directory package -+ if package=="directory": -+ continue -+ -+ if package=="unknown": -+ continue -+ -+ -+ is_pkg_in_ |