From: Fabian Groffen Date: Sat, 22 Nov 2008 11:34:13 +0000 (-0000) Subject: Merged from trunk -r12004:12020 X-Git-Url: http://git.tremily.us/gitweb.cgi?a=commitdiff_plain;h=e410a9e06a60a97a878db3e6e1270b13f3cc876f;p=portage.git Merged from trunk -r12004:12020 | 12006 | Bug #247370 - Use a private PORTAGE_TMPDIR for --fetchonly | | zmedico | mode in order do avoid locking the normal build dir location | | | (similar to bug #245231). The EbuildFetchPretend class is | | | renamed to EbuildFetchonly and it's used for --fetchonly | | | mode regardless of whether --pretend is enabled. Also, fix | | | stdout/stderr flushing in JobStatusDisplay.displayMessage() | | | and portage.spawn() to ensure output always occurs in the | | | correct order when displaying pkg_nofetch() output in | | | --fetchonly mode. | | 12008 | Inside _parse_data(), don't rely on the magic 22 line count | | zmedico | for the flat_list format, since it doesn't make a | | | significant performance difference and it places an | | | artificial limit on the number of keys that can be stored. | | 12010 | Remove inappropriate backslash escaping inside | | zmedico | _db_escape_string(). | | 12012 | When given an ambiguous ebuild name to install, format the | | zmedico | list of choices in emerge --search format if --quiet mode is | | | not enabled, otherwise just show a brief list. Thanks to | | | Markus Meier for the suggestion. | | 12014 | In JobStatusDisplay, always flush the output stream after | | zmedico | writing to it. | | 12016 | In EbuildProcess._start(), don't open the log file during | | zmedico | the clean phase since the open file can result in an nfs | | | lock on $T/build.log which prevents the clean phase from | | | removing $T. Thanks to Jeremy Olexa for | | | reporting. | | 12018 | Bug #248059 - In action_depclean(), ignore invalid atoms in | | zmedico | deps of packages to be uninstalled. | | 12020 | Bug #248059 - Make --depclean more tolerant of invalid atoms | | zmedico | in dependencies of packages that will be uninstalled anyway. | svn path=/main/branches/prefix/; revision=12038 --- diff --git a/pym/_emerge/__init__.py b/pym/_emerge/__init__.py index d7f82ab6a..52b25d710 100644 --- a/pym/_emerge/__init__.py +++ b/pym/_emerge/__init__.py @@ -441,6 +441,8 @@ class search(object): self.searchdesc = searchdesc self.root_config = root_config self.setconfig = root_config.setconfig + self.matches = {"pkg" : []} + self.mlen = 0 def fake_portdb(): pass @@ -557,7 +559,7 @@ class search(object): if not result or cpv == portage.best([cpv, result]): result = cpv else: - db_keys = list(db._aux_cache_keys) + db_keys = Package.metadata_keys # break out of this loop with highest visible # match, checked in descending order for cpv in reversed(db.match(atom)): @@ -650,6 +652,15 @@ class search(object): self.matches[mtype].sort() self.mlen += len(self.matches[mtype]) + def addCP(self, cp): + if not self.portdb.xmatch("match-all", cp): + return + masked = 0 + if not self.portdb.xmatch("bestmatch-visible", cp): + masked = 1 + self.matches["pkg"].append([cp, masked]) + self.mlen += 1 + def output(self): """Outputs the results of the search.""" print "\b\b \n[ Results for search key : "+white(self.searchkey)+" ]" @@ -744,7 +755,6 @@ class search(object): print " ", darkgreen("Description:")+" ",desc print " ", darkgreen("License:")+" ",license print - print # # private interface # @@ -1610,9 +1620,9 @@ class _PackageMetadataWrapper(_PackageMetadataWrapperBase): v = 0 self._pkg.mtime = v -class EbuildFetchPretend(SlotObject): +class EbuildFetchonly(SlotObject): - __slots__ = ("fetch_all", "pkg", "settings") + __slots__ = ("fetch_all", "pkg", "pretend", "settings") def execute(self): # To spawn pkg_nofetch requires PORTAGE_BUILDDIR for @@ -1648,9 +1658,13 @@ class EbuildFetchPretend(SlotObject): retval = portage.doebuild(ebuild_path, "fetch", self.settings["ROOT"], self.settings, debug=debug, - listonly=1, fetchonly=1, fetchall=self.fetch_all, + listonly=self.pretend, fetchonly=1, fetchall=self.fetch_all, mydbapi=portdb, tree="porttree") + if retval != os.EX_OK: + msg = "Fetch failed for '%s'" % (pkg.cpv,) + eerror(msg, phase="unpack", key=pkg.cpv) + portage.elog.elog_process(self.pkg.cpv, self.settings) return retval @@ -2520,10 +2534,11 @@ class EbuildBuild(CompositeTask): pkg = self.pkg settings = self.settings - if opts.fetchonly and opts.pretend: - fetcher = EbuildFetchPretend( + if opts.fetchonly: + fetcher = EbuildFetchonly( fetch_all=opts.fetch_all_uri, - pkg=pkg, settings=settings) + pkg=pkg, pretend=opts.pretend, + settings=settings) retval = fetcher.execute() self.returncode = retval self.wait() @@ -2897,7 +2912,11 @@ class EbuildProcess(SpawnProcess): __slots__ = ("phase", "pkg", "settings", "tree") def _start(self): - self.logfile = self.settings.get("PORTAGE_LOG_FILE") + # Don't open the log file during the clean phase since the + # open file can result in an nfs lock on $T/build.log which + # prevents the clean phase from removing $T. + if self.phase not in ("clean", "cleanrm"): + self.logfile = self.settings.get("PORTAGE_LOG_FILE") SpawnProcess._start(self) def _pipe(self, fd_pipes): @@ -5045,13 +5064,10 @@ class depgraph(object): if portage.dep_getkey(atom) == installed_cp] if len(expanded_atoms) > 1: - print "\n\n!!! The short ebuild name \"" + x + "\" is ambiguous. Please specify" - print "!!! one of the following fully-qualified ebuild names instead:\n" - expanded_atoms = set(portage.dep_getkey(atom) \ - for atom in expanded_atoms) - for i in sorted(expanded_atoms): - print " " + green(i) print + print + ambiguous_package_name(x, expanded_atoms, root_config, + self.spinner, self.myopts) return False, myfavorites if expanded_atoms: atom = expanded_atoms[0] @@ -8930,10 +8946,12 @@ class JobStatusDisplay(object): self.out.write( self._term_codes['carriage_return'] + \ self._term_codes['clr_eol']) + self.out.flush() self._displayed = False def _display(self, line): self.out.write(line) + self.out.flush() self._displayed = True def _update(self, msg): @@ -8941,6 +8959,7 @@ class JobStatusDisplay(object): out = self.out if not self._isatty: out.write(self._format_msg(msg) + self._term_codes['newline']) + self.out.flush() self._displayed = True return @@ -8957,6 +8976,7 @@ class JobStatusDisplay(object): self._erase() self.out.write(self._format_msg(msg) + self._term_codes['newline']) + self.out.flush() self._displayed = False if was_displayed: @@ -8971,6 +8991,7 @@ class JobStatusDisplay(object): if self._displayed: self.out.write(self._term_codes['newline']) + self.out.flush() self._displayed = False def __setattr__(self, name, value): @@ -12845,14 +12866,16 @@ def action_depclean(settings, trees, ldpath_mtimes, finally: portage.dep._dep_check_strict = True if not success: - show_invalid_depstring_notice( - ("installed", myroot, node, "nomerge"), - depstr, atoms) - return - + # Ignore invalid deps of packages that will + # be uninstalled anyway. + continue + priority = priority_map[dep_type] for atom in atoms: - if atom.startswith("!"): + if not isinstance(atom, portage.dep.Atom): + # Ignore invalid atoms returned from dep_check(). + continue + if atom.blocker: continue matches = vardb.match_pkgs(atom) if not matches: @@ -13955,6 +13978,28 @@ def repo_name_check(trees): return bool(missing_repo_names) +def ambiguous_package_name(arg, atoms, root_config, spinner, myopts): + + if "--quiet" in myopts: + print "!!! The short ebuild name \"%s\" is ambiguous. Please specify" % arg + print "!!! one of the following fully-qualified ebuild names instead:\n" + for cp in sorted(set(portage.dep_getkey(atom) for atom in atoms)): + print " " + colorize("INFORM", cp) + return + + s = search(root_config, spinner, "--searchdesc" in myopts, + "--quiet" not in myopts, "--usepkg" in myopts, + "--usepkgonly" in myopts) + null_cp = portage.dep_getkey(insert_category_into_atom( + arg, "null")) + cat, atom_pn = portage.catsplit(null_cp) + s.searchkey = atom_pn + for cp in sorted(set(portage.dep_getkey(atom) for atom in atoms)): + s.addCP(cp) + s.output() + print "!!! The short ebuild name \"%s\" is ambiguous. Please specify" % arg + print "!!! one of the above fully-qualified ebuild names instead.\n" + def emerge_main(): global portage # NFC why this is necessary now - genone portage._disable_legacy_globals() diff --git a/pym/portage/__init__.py b/pym/portage/__init__.py index c491ef6e8..6162ffe27 100644 --- a/pym/portage/__init__.py +++ b/pym/portage/__init__.py @@ -3076,11 +3076,12 @@ def spawn(mystring, mysettings, debug=0, free=0, droppriv=0, sesandbox=0, fakero # In some cases the above print statements don't flush stdout, so # it needs to be flushed before allowing a child process to use it # so that output always shows in the correct order. + stdout_filenos = (sys.stdout.fileno(), sys.stderr.fileno()) for fd in fd_pipes.itervalues(): - if fd == sys.stdout.fileno(): + if fd in stdout_filenos: sys.stdout.flush() - if fd == sys.stderr.fileno(): sys.stderr.flush() + break # The default policy for the sesandbox domain only allows entry (via exec) # from shells and from binaries that belong to portage (the number of entry @@ -6661,8 +6662,16 @@ def dep_check(depstring, mydbapi, mysettings, use="yes", mode=None, myuse=None, writemsg("mysplit: %s\n" % (mysplit), 1) writemsg("mysplit2: %s\n" % (mysplit2), 1) - myzaps = dep_zapdeps(mysplit, mysplit2, myroot, - use_binaries=use_binaries, trees=trees) + try: + myzaps = dep_zapdeps(mysplit, mysplit2, myroot, + use_binaries=use_binaries, trees=trees) + except portage.exception.InvalidAtom, e: + if portage.dep._dep_check_strict: + raise # This shouldn't happen. + # dbapi.match() failed due to an invalid atom in + # the dependencies of an installed package. + return [0, "Invalid atom: '%s'" % (e,)] + mylist = flatten(myzaps) writemsg("myzaps: %s\n" % (myzaps), 1) writemsg("mylist: %s\n" % (mylist), 1) diff --git a/pym/portage/cache/metadata.py b/pym/portage/cache/metadata.py index 635eeec69..c3c83a019 100644 --- a/pym/portage/cache/metadata.py +++ b/pym/portage/cache/metadata.py @@ -3,7 +3,7 @@ # License: GPL2 # $Id$ -import os, stat +import os, re, stat, types from portage.cache import flat_hash import portage.eclass_cache from portage.cache.template import reconstruct_eclasses @@ -22,6 +22,8 @@ class database(flat_hash.database): autocommits = True + _hashed_re = re.compile('^(\\w+)=([^\n]*)') + def __init__(self, location, *args, **config): loc = location super(database, self).__init__(location, *args, **config) @@ -33,34 +35,23 @@ class database(flat_hash.database): def _parse_data(self, data, cpv): - # easy attempt first. + _hashed_re_match = self._hashed_re.match data = list(data) - if len(data) != magic_line_count: - d = flat_hash.database._parse_data(self, data, cpv) - else: - # this one's interesting. - d = {} - - for line in data: - # yes, meant to iterate over a string. - hashed = False - # poor mans enumerate. replace when python 2.3 is required - for idx, c in zip(range(len(line)), line): - if not c.isalpha(): - if c == "=" and idx > 0: - hashed = True - d[line[:idx]] = line[idx + 1:].rstrip("\n") - elif c == "_" or c.isdigit(): - continue - break + d = {} - if not hashed: - # non hashed. - d.clear() - # poor mans enumerate. replace when python 2.3 is required - for idx, key in zip(range(len(self.auxdbkey_order)), self.auxdbkey_order): - d[key] = data[idx].strip() - break + for line in data: + hashed = False + hashed_match = _hashed_re_match(line) + if hashed_match is None: + d.clear() + try: + for i, key in enumerate(self.auxdbkey_order): + d[key] = data[i].rstrip("\n") + except IndexError: + pass + break + else: + d[hashed_match.group(1)] = hashed_match.group(2) if "_eclasses_" not in d: if "INHERITED" in d: diff --git a/pym/portage/cache/sqlite.py b/pym/portage/cache/sqlite.py index a53e8172a..a3d313c47 100644 --- a/pym/portage/cache/sqlite.py +++ b/pym/portage/cache/sqlite.py @@ -46,7 +46,8 @@ class database(fs_template.FsBased): def _db_escape_string(self, s): """meta escaping, returns quoted string for use in sql statements""" - return "'%s'" % str(s).replace("\\","\\\\").replace("'","''") + # This is equivalent to the _quote function from pysqlite 1.1. + return "'%s'" % str(s).replace("'","''") def _db_init_connection(self, config): self._dbpath = self.location + ".sqlite"