Merged from trunk 5238:5247
authorFabian Groffen <grobian@gentoo.org>
Sun, 10 Dec 2006 11:20:04 +0000 (11:20 -0000)
committerFabian Groffen <grobian@gentoo.org>
Sun, 10 Dec 2006 11:20:04 +0000 (11:20 -0000)
Add use.force support to dep_check for repoman especially. Thanks to
Flameeyes for reporting and tesing.

Use portage.isvalidatom() for atom validation in repoman.

Make isvalidatom() (and thus repoman) reject atoms containing |()
characters.  Thanks to Brian Harring for the suggestion.

Add ? to the invalid atom characters.

Clean up depstring/atom splitting and filtering.

For bug #157369, clean  when  cleanup has been triggered by changed
timestamps.  Also, allow FEATURES=keepwork to override the ebuild mtime
check.

This patch cleans up the blocker validation logic.  Unlike the previous
implementation, this one carefully considers each parent/block package
relationship in order to ensure that no unresolved blocks slip through.

Don't attempt to enforce merge order unless the blocker parent is
actually a "merge" node.

Escape a newline from the previous commit.

svn path=/main/branches/prefix/; revision=5258

bin/ebuild.sh
bin/emerge
bin/repoman
pym/portage.py
pym/portage_dep.py

index dfedfff26da8f649005cf3169c73716188e03727..f681c7784f3a1bfb9deebd616f61d5ddabb041b4 100755 (executable)
@@ -834,18 +834,25 @@ dyn_unpack() {
                        if [ "${PORTAGE_ACTUAL_DISTDIR:-${DISTDIR}}/${x}" -nt "${WORKDIR}" ]; then
                                vecho ">>> ${x} has been updated; recreating WORKDIR..."
                                newstuff="yes"
-                               rm -rf "${WORKDIR}"
                                break
                        fi
                done
-               if [ "${EBUILD}" -nt "${WORKDIR}" ]; then
+               if [ "${EBUILD}" -nt "${WORKDIR}" ] && ! hasq keepwork ${FEATURES} ; then
                        vecho ">>> ${EBUILD} has been updated; recreating WORKDIR..."
                        newstuff="yes"
-                       rm -rf "${WORKDIR}"
                elif [ ! -f "${PORTAGE_BUILDDIR}/.unpacked" ]; then
                        vecho ">>> Not marked as unpacked; recreating WORKDIR..."
                        newstuff="yes"
-                       rm -rf "${WORKDIR}"
+               fi
+       fi
+       if [ "${newstuff}" == "yes" ]; then
+               # We don't necessarily have privileges to do a full dyn_clean here.
+               rm -rf "${WORKDIR}"
+               if [ -d "${T}" ] && ! hasq keeptemp ${FEATURES} ; then
+                       rm -rf "${T}" && mkdir "${T}"
+               else
+                       [ -e "${T}/environment" ] && \
+                               mv "${T}/environment" "${T}/environment.keeptemp"
                fi
        fi
        if [ -e "${WORKDIR}" ]; then
index fb555d27194d3f13b88822ebf7141ce2a0667e52..c296e8c2b858b6472cf5ac1d087d172b02af66c7 100755 (executable)
@@ -1440,72 +1440,73 @@ class depgraph:
 
                for blocker in self.blocker_parents.keys():
                        mytype, myroot, mydep = blocker
-                       vardb = self.trees[myroot]["vartree"].dbapi
-                       blocked_pkgs = vardb.match(mydep)
-                       blocked_after_update = self.mydbapi[myroot].match(mydep)
-                       if not blocked_pkgs and not blocked_after_update:
+                       initial_db = self.trees[myroot]["vartree"].dbapi
+                       final_db = self.mydbapi[myroot]
+                       blocked_initial = initial_db.match(mydep)
+                       blocked_final = final_db.match(mydep)
+                       if not blocked_initial and not blocked_final:
                                del self.blocker_parents[blocker]
-                       else:
-                               """It may be possible to circumvent this block via correct
-                               ordering of upgrades.  If necessary, create hard deps to
-                               enforce correct merge order."""
-                               fakedb = self.mydbapi[myroot]
-                               new_pkgs = []
-                               unresolvable = False
-                               for cpv in blocked_pkgs:
-                                       myslot = vardb.aux_get(cpv, ["SLOT"])[0]
-                                       myslot_atom = "%s:%s" % (portage.dep_getkey(cpv), myslot)
-                                       mymatches = fakedb.match(myslot_atom)
-                                       if mymatches:
-                                               new_pkgs.append((myslot_atom, mymatches[0]))
-                                       else:
-                                               """There's an installed package that's blocked and
-                                               there's no upgrade found to invalidate it, so leave
-                                               this blocker in the digraph."""
-                                               unresolvable = True
-                                               break
-                               if unresolvable:
-                                       # Keep trying to invalidate as many blockers as possible.
-                                       continue
-
-                               for parent in list(self.blocker_parents[blocker]):
-                                       ptype, proot, pcpv, pstatus = parent
-                                       pdbapi = self.trees[proot][self.pkg_tree_map[ptype]].dbapi
-                                       pslot = pdbapi.aux_get(pcpv, ["SLOT"])[0]
-                                       pslot_atom = "%s:%s" % (portage.dep_getkey(pcpv), pslot)
-                                       depends_on_merge_order = False
-                                       for myslot_atom, pkg in new_pkgs:
-                                               if pslot_atom == myslot_atom:
-                                                       """A merge within a slot invalidates the block,
-                                                       so the order does not need to be enforced."""
+                               continue
+                       blocked_slots_initial = {}
+                       blocked_slots_final = {}
+                       for cpv in blocked_initial:
+                               blocked_slots_initial[cpv] = \
+                                       "%s:%s" % (portage.dep_getkey(cpv),
+                                               initial_db.aux_get(cpv, ["SLOT"])[0])
+                       for cpv in blocked_final:
+                               blocked_slots_final[cpv] = \
+                                       "%s:%s" % (portage.dep_getkey(cpv),
+                                               final_db.aux_get(cpv, ["SLOT"])[0])
+                       for parent in list(self.blocker_parents[blocker]):
+                               ptype, proot, pcpv, pstatus = parent
+                               pdbapi = self.trees[proot][self.pkg_tree_map[ptype]].dbapi
+                               pslot = pdbapi.aux_get(pcpv, ["SLOT"])[0]
+                               pslot_atom = "%s:%s" % (portage.dep_getkey(pcpv), pslot)
+                               unresolved_blocks = False
+                               depends_on_order = set()
+                               for cpv in blocked_initial:
+                                       slot_atom = blocked_slots_initial[cpv]
+                                       if slot_atom == pslot_atom:
+                                               # The parent blocks an initial package in the same
+                                               # slot as itself.  The merge/nomerge status of neither
+                                               # node matters.  In any case, this particular block is
+                                               # automatically resolved.
+                                               continue
+                                       if pstatus == "merge" and \
+                                               slot_atom not in blocked_slots_final.values():
+                                               upgrade_matches = final_db.match(slot_atom)
+                                               if upgrade_matches:
+                                                       # Apparently an upgrade may be able to invalidate
+                                                       # this block.
+                                                       upgrade_node = \
+                                                               self.pkg_node_map[proot][upgrade_matches[0]]
+                                                       depends_on_order.add(upgrade_node)
                                                        continue
-                                               if pkg in blocked_after_update:
-                                                       """This isn't a case of a package blocking itself,
-                                                       and the block is still valid in the final state, so
-                                                       this one is unresolvable."""
-                                                       unresolvable = True
-                                                       break
+                                       # None of the above blocker resolutions techniques apply,
+                                       # so apparently this one is unresolvable.
+                                       unresolved_blocks = True
+                               for cpv in blocked_final:
+                                       slot_atom = blocked_slots_final[cpv]
+                                       if slot_atom == pslot_atom:
+                                               # The parent blocks itself, so the merge order does not
+                                               # need to be enforced.
+                                               continue
+                                       # None of the above blocker resolutions techniques apply,
+                                       # so apparently this one is unresolvable.
+                                       unresolved_blocks = True
+                               if not unresolved_blocks and depends_on_order:
+                                       for node in depends_on_order:
                                                # Enforce correct merge order with a hard dep.
-                                               node = self.pkg_node_map[proot][pkg]
                                                self.digraph.addnode(node, parent,
                                                        priority=DepPriority(buildtime=True))
-                                               """Count references to this blocker so that it can be
-                                               invalidated after nodes referencing it have been merged."""
+                                               # Count references to this blocker so that it can be
+                                               # invalidated after nodes referencing it have been
+                                               # merged.
                                                self.blocker_digraph.addnode(node, blocker)
-                                               depends_on_merge_order = True
-                                       if unresolvable:
-                                               break
-                                       elif not depends_on_merge_order:
-                                               self.blocker_parents[blocker].remove(parent)
-                               if unresolvable:
-                                       """This blocker can not be solved, so make sure that it is
-                                       removed from the digraph if it has already been added."""
-                                       if self.blocker_digraph.contains(blocker):
-                                               self.blocker_digraph.remove(blocker)
-                                       # Keep trying to invalidate as many blockers as possible.
-                                       continue
-                               if not self.blocker_parents[blocker]:
-                                       del self.blocker_parents[blocker]
+                               if not unresolved_blocks and not depends_on_order:
+                                       self.blocker_parents[blocker].remove(parent)
+                       if not self.blocker_parents[blocker]:
+                               del self.blocker_parents[blocker]
                # Validate blockers that depend on merge order.
                if not self.blocker_digraph.empty():
                        self.altlist()
index bbb5a4ff68ae99264d09844612dc23d70e374054..7a258e0a01aa0c639f0e5f8956c55d555331f321 100755 (executable)
@@ -1180,6 +1180,7 @@ for x in scanlist:
                                myflag = myflag[1:]
                        myiuse.add(myflag)
 
+               operator_tokens = set(["||", "(", ")"])
                type_list, badsyntax = [], []
                for mytype in ("DEPEND", "RDEPEND", "PDEPEND", "LICENSE", "PROVIDE"):
                        mydepstr = myaux[mytype]
@@ -1202,7 +1203,7 @@ for x in scanlist:
                        except portage_exception.InvalidDependString, e:
                                badsyntax.append(str(e))
 
-                       for token in ("||", "(", ")"):
+                       for token in operator_tokens:
                                if mydepstr.startswith(token+" "):
                                        myteststr = mydepstr[len(token):]
                                else:
@@ -1216,8 +1217,11 @@ for x in scanlist:
 
 
                        if mytype in ("DEPEND", "RDEPEND", "PDEPEND"):
-                               for token in filter(lambda x: not (x.endswith("?") or x.strip() in ("||", "&&", "(", ")")), mydepstr.split()):
-                                       if not "/" in token or \
+                               for token in mydepstr.split():
+                                       if token in operator_tokens or \
+                                               token.endswith("?"):
+                                               continue
+                                       if not portage.isvalidatom(token) or \
                                                ":" in token and myaux["EAPI"] == "0":
                                                badsyntax.append("'%s' not a valid atom" % token)
 
index 46a8d031f8ed3443753a4f7e0b4caf0e0c08ef03..d66dfee66334dfedb40e818ec8bc9e38e1853699 100644 (file)
@@ -3891,6 +3891,7 @@ def dep_check(depstring, mydbapi, mysettings, use="yes", mode=None, myuse=None,
 
        if mysettings:
                mymasks = set()
+               useforce = set([mysettings["ARCH"]])
                if use == "all":
                        # These masks are only for repoman.  In other cases, relevant masks
                        # should have already been applied via config.regenerate().  Also,
@@ -3902,7 +3903,10 @@ def dep_check(depstring, mydbapi, mysettings, use="yes", mode=None, myuse=None,
                        mymasks.update(mysettings.usemask)
                        mymasks.update(mysettings.archlist())
                        mymasks.discard(mysettings["ARCH"])
-               mysplit = portage_dep.use_reduce(mysplit,uselist=myusesplit,masklist=mymasks,matchall=(use=="all"),excludeall=[mysettings["ARCH"]])
+                       useforce.update(mysettings.useforce)
+                       useforce.difference_update(mymasks)
+               mysplit = portage_dep.use_reduce(mysplit, uselist=myusesplit,
+                       masklist=mymasks, matchall=(use=="all"), excludeall=useforce)
        else:
                mysplit = portage_dep.use_reduce(mysplit,uselist=myusesplit,matchall=(use=="all"))
 
index 82b434a7b12c2629c7a12c40d87269ae72a8cb0d..6459137e028ead0c83e186c9cf6f6e882cf1f843 100644 (file)
@@ -18,7 +18,7 @@
 # "a? ( b? ( z ) ) -- Valid
 #
 
-import os,string,types,sys,copy
+import re, string, sys, types
 import portage_exception
 from portage_versions import catpkgsplit, catsplit, pkgcmp, pkgsplit, ververify
 
@@ -303,6 +303,8 @@ def dep_getslot(mydep):
                return mydep[colon+1:]
        return None
 
+_invalid_atom_chars_regexp = re.compile("[()|?]")
+
 def isvalidatom(atom):
        """
        Check to see if a depend atom is valid
@@ -320,6 +322,9 @@ def isvalidatom(atom):
                1) 0 if the atom is invalid
                2) 1 if the atom is valid
        """
+       global _invalid_atom_chars_regexp
+       if _invalid_atom_chars_regexp.search(atom):
+               return 0
        mycpv_cps = catpkgsplit(dep_getcpv(atom))
        operator = get_operator(atom)
        if operator: