From 8f02a7e9cf5438d7e7259ae945dbb3af132da296 Mon Sep 17 00:00:00 2001 From: Fabian Groffen Date: Sun, 10 Dec 2006 11:20:04 +0000 Subject: [PATCH] Merged from trunk 5238:5247 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 | 15 ++++-- bin/emerge | 121 +++++++++++++++++++++++---------------------- bin/repoman | 10 ++-- pym/portage.py | 6 ++- pym/portage_dep.py | 7 ++- 5 files changed, 90 insertions(+), 69 deletions(-) diff --git a/bin/ebuild.sh b/bin/ebuild.sh index dfedfff26..f681c7784 100755 --- a/bin/ebuild.sh +++ b/bin/ebuild.sh @@ -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 diff --git a/bin/emerge b/bin/emerge index fb555d271..c296e8c2b 100755 --- a/bin/emerge +++ b/bin/emerge @@ -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() diff --git a/bin/repoman b/bin/repoman index bbb5a4ff6..7a258e0a0 100755 --- a/bin/repoman +++ b/bin/repoman @@ -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) diff --git a/pym/portage.py b/pym/portage.py index 46a8d031f..d66dfee66 100644 --- a/pym/portage.py +++ b/pym/portage.py @@ -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")) diff --git a/pym/portage_dep.py b/pym/portage_dep.py index 82b434a7b..6459137e0 100644 --- a/pym/portage_dep.py +++ b/pym/portage_dep.py @@ -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: -- 2.26.2