Merged from trunk -r12004:12020
authorFabian Groffen <grobian@gentoo.org>
Sat, 22 Nov 2008 11:34:13 +0000 (11:34 -0000)
committerFabian Groffen <grobian@gentoo.org>
Sat, 22 Nov 2008 11:34:13 +0000 (11:34 -0000)
   | 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 <maekke@g.o> 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 <darkside@g.o> 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

pym/_emerge/__init__.py
pym/portage/__init__.py
pym/portage/cache/metadata.py
pym/portage/cache/sqlite.py

index d7f82ab6a484c5fa12453e12b083c9bbf56940bd..52b25d7104a0481e772cb65649336ebc742f0413 100644 (file)
@@ -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()
index c491ef6e8e6b22c2085876e783c6c48db53375a1..6162ffe27e5d3108a3ebfa4a7e6e4f73b0f19174 100644 (file)
@@ -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)
index 635eeec69b72fc241d65449cf43ff5747d0b4ed5..c3c83a019eebe9dec9aa802edd6bf44f25acea18 100644 (file)
@@ -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:
index a53e8172ad415b6f6c59f62e74136bf2b697bfc4..a3d313c47e2d19e50f350588a876e46c014f8b6d 100644 (file)
@@ -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"