* [gentoo-commits] portage r15483 - in main/branches/prefix/pym/portage: . dbapi package/ebuild util
@ 2010-02-27 19:32 99% Fabian Groffen (grobian)
0 siblings, 0 replies; 1+ results
From: Fabian Groffen (grobian) @ 2010-02-27 19:32 UTC (permalink / raw
To: gentoo-commits
Author: grobian
Date: 2010-02-27 19:32:48 +0000 (Sat, 27 Feb 2010)
New Revision: 15483
Added:
main/branches/prefix/pym/portage/dep/
main/branches/prefix/pym/portage/package/ebuild/getmaskingreason.py
main/branches/prefix/pym/portage/package/ebuild/getmaskingstatus.py
main/branches/prefix/pym/portage/util/movefile.py
Removed:
main/branches/prefix/pym/portage/dep.py
Modified:
main/branches/prefix/pym/portage/__init__.py
main/branches/prefix/pym/portage/dbapi/__init__.py
main/branches/prefix/pym/portage/dbapi/vartree.py
Log:
Merged from trunk -r15460:15465
| 15461 | Move dep.py to dep/__init__.py, for splitting into smaller |
| zmedico | files. |
| 15462 | Move portage.dep_check and related functions to |
| zmedico | portage.dep.dep_check. |
| 15463 | Split getmaskingstatus and getmaskingreason info |
| zmedico | portage.package.ebuild submodules. |
| 15464 | Move portage.movefile to portage.util.movefile. |
| zmedico | |
| 15465 | Avoid name collision with dep_expand submodule so epydoc |
| zmedico | won't crash. |
Modified: main/branches/prefix/pym/portage/__init__.py
===================================================================
--- main/branches/prefix/pym/portage/__init__.py 2010-02-27 19:26:00 UTC (rev 15482)
+++ main/branches/prefix/pym/portage/__init__.py 2010-02-27 19:32:48 UTC (rev 15483)
@@ -92,6 +92,7 @@
'portage.dep:best_match_to_list,dep_getcpv,dep_getkey,' + \
'flatten,get_operator,isjustname,isspecific,isvalidatom,' + \
'match_from_list,match_to_list',
+ 'portage.dep.dep_check:dep_check,dep_eval,dep_wordreduce,dep_zapdeps',
'portage.eclass_cache',
'portage.env.loaders',
'portage.exception',
@@ -109,6 +110,8 @@
'portage.package.ebuild.digestcheck:digestcheck',
'portage.package.ebuild.digestgen:digestgen',
'portage.package.ebuild.fetch:fetch',
+ 'portage.package.ebuild.getmaskingreason:getmaskingreason',
+ 'portage.package.ebuild.getmaskingstatus:getmaskingstatus',
'portage.package.ebuild.prepare_build_dirs:prepare_build_dirs',
'portage.process',
'portage.process:atexit_register,run_exitfuncs',
@@ -127,6 +130,7 @@
'portage.util.env_update:env_update',
'portage.util.ExtractKernelVersion:ExtractKernelVersion',
'portage.util.listdir:cacheddir,listdir',
+ 'portage.util.movefile:movefile',
'portage.versions',
'portage.versions:best,catpkgsplit,catsplit,cpv_getkey,' + \
'cpv_getkey@getCPFromCPV,endversion_keys,' + \
@@ -634,223 +638,6 @@
raise portage.exception.PortageException(
"mv '%s' '%s'" % (src, dest))
-def movefile(src, dest, newmtime=None, sstat=None, mysettings=None,
- hardlink_candidates=None, encoding=_encodings['fs']):
- """moves a file from src to dest, preserving all permissions and attributes; mtime will
- be preserved even when moving across filesystems. Returns true on success and false on
- failure. Move is atomic."""
- #print "movefile("+str(src)+","+str(dest)+","+str(newmtime)+","+str(sstat)+")"
-
- if mysettings is None:
- global settings
- mysettings = settings
-
- selinux_enabled = mysettings.selinux_enabled()
- if selinux_enabled:
- selinux = _unicode_module_wrapper(_selinux, encoding=encoding)
-
- lchown = _unicode_func_wrapper(data.lchown, encoding=encoding)
- os = _unicode_module_wrapper(_os,
- encoding=encoding, overrides=_os_overrides)
- shutil = _unicode_module_wrapper(_shutil, encoding=encoding)
-
- try:
- if not sstat:
- sstat=os.lstat(src)
-
- except SystemExit as e:
- raise
- except Exception as e:
- print(_("!!! Stating source file failed... movefile()"))
- print("!!!",e)
- return None
-
- destexists=1
- try:
- dstat=os.lstat(dest)
- except (OSError, IOError):
- dstat=os.lstat(os.path.dirname(dest))
- destexists=0
-
- if bsd_chflags:
- if destexists and dstat.st_flags != 0:
- bsd_chflags.lchflags(dest, 0)
- # Use normal stat/chflags for the parent since we want to
- # follow any symlinks to the real parent directory.
- pflags = os.stat(os.path.dirname(dest)).st_flags
- if pflags != 0:
- bsd_chflags.chflags(os.path.dirname(dest), 0)
-
- if destexists:
- if stat.S_ISLNK(dstat[stat.ST_MODE]):
- try:
- os.unlink(dest)
- destexists=0
- except SystemExit as e:
- raise
- except Exception as e:
- pass
-
- if stat.S_ISLNK(sstat[stat.ST_MODE]):
- try:
- target=os.readlink(src)
- if mysettings and mysettings["D"]:
- if target.find(mysettings["D"])==0:
- target=target[len(mysettings["D"]):]
- if destexists and not stat.S_ISDIR(dstat[stat.ST_MODE]):
- os.unlink(dest)
- if selinux_enabled:
- selinux.symlink(target, dest, src)
- else:
- os.symlink(target,dest)
- lchown(dest,sstat[stat.ST_UID],sstat[stat.ST_GID])
- # utime() only works on the target of a symlink, so it's not
- # possible to perserve mtime on symlinks.
- return os.lstat(dest)[stat.ST_MTIME]
- except SystemExit as e:
- raise
- except Exception as e:
- print(_("!!! failed to properly create symlink:"))
- print("!!!",dest,"->",target)
- print("!!!",e)
- return None
-
- hardlinked = False
- # Since identical files might be merged to multiple filesystems,
- # so os.link() calls might fail for some paths, so try them all.
- # For atomic replacement, first create the link as a temp file
- # and them use os.rename() to replace the destination.
- if hardlink_candidates:
- head, tail = os.path.split(dest)
- hardlink_tmp = os.path.join(head, ".%s._portage_merge_.%s" % \
- (tail, os.getpid()))
- try:
- os.unlink(hardlink_tmp)
- except OSError as e:
- if e.errno != errno.ENOENT:
- writemsg(_("!!! Failed to remove hardlink temp file: %s\n") % \
- (hardlink_tmp,), noiselevel=-1)
- writemsg("!!! %s\n" % (e,), noiselevel=-1)
- return None
- del e
- for hardlink_src in hardlink_candidates:
- try:
- os.link(hardlink_src, hardlink_tmp)
- except OSError:
- continue
- else:
- try:
- os.rename(hardlink_tmp, dest)
- except OSError as e:
- writemsg(_("!!! Failed to rename %s to %s\n") % \
- (hardlink_tmp, dest), noiselevel=-1)
- writemsg("!!! %s\n" % (e,), noiselevel=-1)
- return None
- hardlinked = True
- break
-
- renamefailed=1
- if hardlinked:
- renamefailed = False
- if not hardlinked and (selinux_enabled or sstat.st_dev == dstat.st_dev):
- try:
- if selinux_enabled:
- ret = selinux.rename(src, dest)
- else:
- ret=os.rename(src,dest)
- renamefailed=0
- except OSError as e:
- if e.errno != errno.EXDEV:
- # Some random error.
- print(_("!!! Failed to move %(src)s to %(dest)s") % {"src": src, "dest": dest})
- print("!!!",e)
- return None
- # Invalid cross-device-link 'bind' mounted or actually Cross-Device
- if renamefailed:
- didcopy=0
- if stat.S_ISREG(sstat[stat.ST_MODE]):
- try: # For safety copy then move it over.
- if selinux_enabled:
- selinux.copyfile(src, dest + "#new")
- selinux.rename(dest + "#new", dest)
- else:
- shutil.copyfile(src,dest+"#new")
- os.rename(dest+"#new",dest)
- didcopy=1
- except SystemExit as e:
- raise
- except Exception as e:
- print(_('!!! copy %(src)s -> %(dest)s failed.') % {"src": src, "dest": dest})
- print("!!!",e)
- return None
- else:
- #we don't yet handle special, so we need to fall back to /bin/mv
- a = process.spawn([MOVE_BINARY, '-f', src, dest], env=os.environ)
- if a != os.EX_OK:
- writemsg(_("!!! Failed to move special file:\n"), noiselevel=-1)
- writemsg(_("!!! '%(src)s' to '%(dest)s'\n") % \
- {"src": _unicode_decode(src, encoding=encoding),
- "dest": _unicode_decode(dest, encoding=encoding)}, noiselevel=-1)
- writemsg("!!! %s\n" % a, noiselevel=-1)
- return None # failure
- try:
- if didcopy:
- if stat.S_ISLNK(sstat[stat.ST_MODE]):
- lchown(dest,sstat[stat.ST_UID],sstat[stat.ST_GID])
- else:
- os.chown(dest,sstat[stat.ST_UID],sstat[stat.ST_GID])
- os.chmod(dest, stat.S_IMODE(sstat[stat.ST_MODE])) # Sticky is reset on chown
- os.unlink(src)
- except SystemExit as e:
- raise
- except Exception as e:
- print(_("!!! Failed to chown/chmod/unlink in movefile()"))
- print("!!!",dest)
- print("!!!",e)
- return None
-
- # Always use stat_obj[stat.ST_MTIME] for the integral timestamp which
- # is returned, since the stat_obj.st_mtime float attribute rounds *up*
- # if the nanosecond part of the timestamp is 999999881 ns or greater.
- try:
- if hardlinked:
- newmtime = os.stat(dest)[stat.ST_MTIME]
- else:
- # Note: It is not possible to preserve nanosecond precision
- # (supported in POSIX.1-2008 via utimensat) with the IEEE 754
- # double precision float which only has a 53 bit significand.
- if newmtime is not None:
- os.utime(dest, (newmtime, newmtime))
- else:
- newmtime = sstat[stat.ST_MTIME]
- if renamefailed:
- # If rename succeeded then timestamps are automatically
- # preserved with complete precision because the source
- # and destination inode are the same. Otherwise, round
- # down to the nearest whole second since python's float
- # st_mtime cannot be used to preserve the st_mtim.tv_nsec
- # field with complete precision. Note that we have to use
- # stat_obj[stat.ST_MTIME] here because the float
- # stat_obj.st_mtime rounds *up* sometimes.
- os.utime(dest, (newmtime, newmtime))
- except OSError:
- # The utime can fail here with EPERM even though the move succeeded.
- # Instead of failing, use stat to return the mtime if possible.
- try:
- newmtime = os.stat(dest)[stat.ST_MTIME]
- except OSError as e:
- writemsg(_("!!! Failed to stat in movefile()\n"), noiselevel=-1)
- writemsg("!!! %s\n" % dest, noiselevel=-1)
- writemsg("!!! %s\n" % str(e), noiselevel=-1)
- return None
-
- if bsd_chflags:
- # Restore the flags we saved before moving
- if pflags:
- bsd_chflags.chflags(os.path.dirname(dest), pflags)
-
- return newmtime
-
def merge(mycat, mypkg, pkgloc, infloc, myroot, mysettings, myebuild=None,
mytree=None, mydbapi=None, vartree=None, prev_mtimes=None, blockers=None,
scheduler=None):
@@ -911,835 +698,6 @@
newsplit.append(x)
return newsplit
-def _expand_new_virtuals(mysplit, edebug, mydbapi, mysettings, myroot="/",
- trees=None, use_mask=None, use_force=None, **kwargs):
- """
- In order to solve bug #141118, recursively expand new-style virtuals so
- as to collapse one or more levels of indirection, generating an expanded
- search space. In dep_zapdeps, new-style virtuals will be assigned
- zero cost regardless of whether or not they are currently installed. Virtual
- blockers are supported but only when the virtual expands to a single
- atom because it wouldn't necessarily make sense to block all the components
- of a compound virtual. When more than one new-style virtual is matched,
- the matches are sorted from highest to lowest versions and the atom is
- expanded to || ( highest match ... lowest match )."""
- newsplit = []
- mytrees = trees[myroot]
- portdb = mytrees["porttree"].dbapi
- atom_graph = mytrees.get("atom_graph")
- parent = mytrees.get("parent")
- virt_parent = mytrees.get("virt_parent")
- graph_parent = None
- eapi = None
- if parent is not None:
- if virt_parent is not None:
- graph_parent = virt_parent
- eapi = virt_parent[0].metadata['EAPI']
- else:
- graph_parent = parent
- eapi = parent.metadata["EAPI"]
- repoman = not mysettings.local_config
- if kwargs["use_binaries"]:
- portdb = trees[myroot]["bintree"].dbapi
- myvirtuals = mysettings.getvirtuals()
- pprovideddict = mysettings.pprovideddict
- myuse = kwargs["myuse"]
- for x in mysplit:
- if x == "||":
- newsplit.append(x)
- continue
- elif isinstance(x, list):
- newsplit.append(_expand_new_virtuals(x, edebug, mydbapi,
- mysettings, myroot=myroot, trees=trees, use_mask=use_mask,
- use_force=use_force, **kwargs))
- continue
-
- if not isinstance(x, portage.dep.Atom):
- try:
- x = portage.dep.Atom(x)
- except portage.exception.InvalidAtom:
- if portage.dep._dep_check_strict:
- raise portage.exception.ParseError(
- _("invalid atom: '%s'") % x)
- else:
- # Only real Atom instances are allowed past this point.
- continue
- else:
- if x.blocker and x.blocker.overlap.forbid and \
- eapi in ("0", "1") and portage.dep._dep_check_strict:
- raise portage.exception.ParseError(
- _("invalid atom: '%s'") % (x,))
- if x.use and eapi in ("0", "1") and \
- portage.dep._dep_check_strict:
- raise portage.exception.ParseError(
- _("invalid atom: '%s'") % (x,))
-
- if repoman and x.use and x.use.conditional:
- evaluated_atom = portage.dep.remove_slot(x)
- if x.slot:
- evaluated_atom += ":%s" % x.slot
- evaluated_atom += str(x.use._eval_qa_conditionals(
- use_mask, use_force))
- x = portage.dep.Atom(evaluated_atom)
-
- if not repoman and \
- myuse is not None and isinstance(x, portage.dep.Atom) and x.use:
- if x.use.conditional:
- x = x.evaluate_conditionals(myuse)
-
- mykey = x.cp
- if not mykey.startswith("virtual/"):
- newsplit.append(x)
- if atom_graph is not None:
- atom_graph.add(x, graph_parent)
- continue
- mychoices = myvirtuals.get(mykey, [])
- if x.blocker:
- # Virtual blockers are no longer expanded here since
- # the un-expanded virtual atom is more useful for
- # maintaining a cache of blocker atoms.
- newsplit.append(x)
- if atom_graph is not None:
- atom_graph.add(x, graph_parent)
- continue
-
- if repoman or not hasattr(portdb, 'match_pkgs'):
- if portdb.cp_list(x.cp):
- newsplit.append(x)
- else:
- # TODO: Add PROVIDE check for repoman.
- a = []
- for y in mychoices:
- a.append(dep.Atom(x.replace(x.cp, y.cp, 1)))
- if not a:
- newsplit.append(x)
- elif len(a) == 1:
- newsplit.append(a[0])
- else:
- newsplit.append(['||'] + a)
- continue
-
- pkgs = []
- # Ignore USE deps here, since otherwise we might not
- # get any matches. Choices with correct USE settings
- # will be preferred in dep_zapdeps().
- matches = portdb.match_pkgs(x.without_use)
- # Use descending order to prefer higher versions.
- matches.reverse()
- for pkg in matches:
- # only use new-style matches
- if pkg.cp.startswith("virtual/"):
- pkgs.append(pkg)
- if not (pkgs or mychoices):
- # This one couldn't be expanded as a new-style virtual. Old-style
- # virtuals have already been expanded by dep_virtual, so this one
- # is unavailable and dep_zapdeps will identify it as such. The
- # atom is not eliminated here since it may still represent a
- # dependency that needs to be satisfied.
- newsplit.append(x)
- if atom_graph is not None:
- atom_graph.add(x, graph_parent)
- continue
-
- a = []
- for pkg in pkgs:
- virt_atom = '=' + pkg.cpv
- if x.use:
- virt_atom += str(x.use)
- virt_atom = dep.Atom(virt_atom)
- # According to GLEP 37, RDEPEND is the only dependency
- # type that is valid for new-style virtuals. Repoman
- # should enforce this.
- depstring = pkg.metadata['RDEPEND']
- pkg_kwargs = kwargs.copy()
- pkg_kwargs["myuse"] = pkg.use.enabled
- if edebug:
- util.writemsg_level(_("Virtual Parent: %s\n") \
- % (pkg,), noiselevel=-1, level=logging.DEBUG)
- util.writemsg_level(_("Virtual Depstring: %s\n") \
- % (depstring,), noiselevel=-1, level=logging.DEBUG)
-
- # Set EAPI used for validation in dep_check() recursion.
- mytrees["virt_parent"] = (pkg, virt_atom)
-
- try:
- mycheck = dep_check(depstring, mydbapi, mysettings,
- myroot=myroot, trees=trees, **pkg_kwargs)
- finally:
- # Restore previous EAPI after recursion.
- if virt_parent is not None:
- mytrees["virt_parent"] = virt_parent
- else:
- del mytrees["virt_parent"]
-
- if not mycheck[0]:
- raise portage.exception.ParseError(
- "%s: %s '%s'" % (y[0], mycheck[1], depstring))
-
- # pull in the new-style virtual
- mycheck[1].append(virt_atom)
- a.append(mycheck[1])
- if atom_graph is not None:
- atom_graph.add(virt_atom, graph_parent)
- # Plain old-style virtuals. New-style virtuals are preferred.
- if not pkgs:
- for y in mychoices:
- new_atom = dep.Atom(x.replace(x.cp, y.cp, 1))
- matches = portdb.match(new_atom)
- # portdb is an instance of depgraph._dep_check_composite_db, so
- # USE conditionals are already evaluated.
- if matches and mykey in \
- portdb.aux_get(matches[-1], ['PROVIDE'])[0].split():
- a.append(new_atom)
- if atom_graph is not None:
- atom_graph.add(new_atom, graph_parent)
-
- if not a and mychoices:
- # Check for a virtual package.provided match.
- for y in mychoices:
- new_atom = dep.Atom(x.replace(x.cp, y.cp, 1))
- if match_from_list(new_atom,
- pprovideddict.get(new_atom.cp, [])):
- a.append(new_atom)
- if atom_graph is not None:
- atom_graph.add(new_atom, graph_parent)
-
- if not a:
- newsplit.append(x)
- if atom_graph is not None:
- atom_graph.add(x, graph_parent)
- elif len(a) == 1:
- newsplit.append(a[0])
- else:
- newsplit.append(['||'] + a)
-
- return newsplit
-
-def dep_eval(deplist):
- if not deplist:
- return 1
- if deplist[0]=="||":
- #or list; we just need one "1"
- for x in deplist[1:]:
- if isinstance(x, list):
- if dep_eval(x)==1:
- return 1
- elif x==1:
- return 1
- #XXX: unless there's no available atoms in the list
- #in which case we need to assume that everything is
- #okay as some ebuilds are relying on an old bug.
- if len(deplist) == 1:
- return 1
- return 0
- else:
- for x in deplist:
- if isinstance(x, list):
- if dep_eval(x)==0:
- return 0
- elif x==0 or x==2:
- return 0
- return 1
-
-def dep_zapdeps(unreduced, reduced, myroot, use_binaries=0, trees=None):
- """Takes an unreduced and reduced deplist and removes satisfied dependencies.
- Returned deplist contains steps that must be taken to satisfy dependencies."""
- if trees is None:
- global db
- trees = db
- writemsg("ZapDeps -- %s\n" % (use_binaries), 2)
- if not reduced or unreduced == ["||"] or dep_eval(reduced):
- return []
-
- if unreduced[0] != "||":
- unresolved = []
- for x, satisfied in zip(unreduced, reduced):
- if isinstance(x, list):
- unresolved += dep_zapdeps(x, satisfied, myroot,
- use_binaries=use_binaries, trees=trees)
- elif not satisfied:
- unresolved.append(x)
- return unresolved
-
- # We're at a ( || atom ... ) type level and need to make a choice
- deps = unreduced[1:]
- satisfieds = reduced[1:]
-
- # Our preference order is for an the first item that:
- # a) contains all unmasked packages with the same key as installed packages
- # b) contains all unmasked packages
- # c) contains masked installed packages
- # d) is the first item
-
- preferred_installed = []
- preferred_in_graph = []
- preferred_any_slot = []
- preferred_non_installed = []
- unsat_use_in_graph = []
- unsat_use_installed = []
- unsat_use_non_installed = []
- other = []
-
- # unsat_use_* must come after preferred_non_installed
- # for correct ordering in cases like || ( foo[a] foo[b] ).
- choice_bins = (
- preferred_in_graph,
- preferred_installed,
- preferred_any_slot,
- preferred_non_installed,
- unsat_use_in_graph,
- unsat_use_installed,
- unsat_use_non_installed,
- other,
- )
-
- # Alias the trees we'll be checking availability against
- parent = trees[myroot].get("parent")
- priority = trees[myroot].get("priority")
- graph_db = trees[myroot].get("graph_db")
- vardb = None
- if "vartree" in trees[myroot]:
- vardb = trees[myroot]["vartree"].dbapi
- if use_binaries:
- mydbapi = trees[myroot]["bintree"].dbapi
- else:
- mydbapi = trees[myroot]["porttree"].dbapi
-
- # Sort the deps into installed, not installed but already
- # in the graph and other, not installed and not in the graph
- # and other, with values of [[required_atom], availablility]
- for x, satisfied in zip(deps, satisfieds):
- if isinstance(x, list):
- atoms = dep_zapdeps(x, satisfied, myroot,
- use_binaries=use_binaries, trees=trees)
- else:
- atoms = [x]
- if vardb is None:
- # When called by repoman, we can simply return the first choice
- # because dep_eval() handles preference selection.
- return atoms
-
- all_available = True
- all_use_satisfied = True
- slot_map = {}
- cp_map = {}
- for atom in atoms:
- if atom.blocker:
- continue
- # Ignore USE dependencies here since we don't want USE
- # settings to adversely affect || preference evaluation.
- avail_pkg = mydbapi.match(atom.without_use)
- if avail_pkg:
- avail_pkg = avail_pkg[-1] # highest (ascending order)
- avail_slot = dep.Atom("%s:%s" % (atom.cp,
- mydbapi.aux_get(avail_pkg, ["SLOT"])[0]))
- if not avail_pkg:
- all_available = False
- all_use_satisfied = False
- break
-
- if atom.use:
- avail_pkg_use = mydbapi.match(atom)
- if not avail_pkg_use:
- all_use_satisfied = False
- else:
- # highest (ascending order)
- avail_pkg_use = avail_pkg_use[-1]
- if avail_pkg_use != avail_pkg:
- avail_pkg = avail_pkg_use
- avail_slot = dep.Atom("%s:%s" % (atom.cp,
- mydbapi.aux_get(avail_pkg, ["SLOT"])[0]))
-
- slot_map[avail_slot] = avail_pkg
- pkg_cp = cpv_getkey(avail_pkg)
- highest_cpv = cp_map.get(pkg_cp)
- if highest_cpv is None or \
- pkgcmp(catpkgsplit(avail_pkg)[1:],
- catpkgsplit(highest_cpv)[1:]) > 0:
- cp_map[pkg_cp] = avail_pkg
-
- this_choice = (atoms, slot_map, cp_map, all_available)
- if all_available:
- # The "all installed" criterion is not version or slot specific.
- # If any version of a package is already in the graph then we
- # assume that it is preferred over other possible packages choices.
- all_installed = True
- for atom in set(dep.Atom(atom.cp) for atom in atoms \
- if not atom.blocker):
- # New-style virtuals have zero cost to install.
- if not vardb.match(atom) and not atom.startswith("virtual/"):
- all_installed = False
- break
- all_installed_slots = False
- if all_installed:
- all_installed_slots = True
- for slot_atom in slot_map:
- # New-style virtuals have zero cost to install.
- if not vardb.match(slot_atom) and \
- not slot_atom.startswith("virtual/"):
- all_installed_slots = False
- break
- if graph_db is None:
- if all_use_satisfied:
- if all_installed:
- if all_installed_slots:
- preferred_installed.append(this_choice)
- else:
- preferred_any_slot.append(this_choice)
- else:
- preferred_non_installed.append(this_choice)
- else:
- if all_installed_slots:
- unsat_use_installed.append(this_choice)
- else:
- unsat_use_non_installed.append(this_choice)
- else:
- all_in_graph = True
- for slot_atom in slot_map:
- # New-style virtuals have zero cost to install.
- if not graph_db.match(slot_atom) and \
- not slot_atom.startswith("virtual/"):
- all_in_graph = False
- break
- circular_atom = None
- if all_in_graph:
- if parent is None or priority is None:
- pass
- elif priority.buildtime:
- # Check if the atom would result in a direct circular
- # dependency and try to avoid that if it seems likely
- # to be unresolvable. This is only relevant for
- # buildtime deps that aren't already satisfied by an
- # installed package.
- cpv_slot_list = [parent]
- for atom in atoms:
- if atom.blocker:
- continue
- if vardb.match(atom):
- # If the atom is satisfied by an installed
- # version then it's not a circular dep.
- continue
- if atom.cp != parent.cp:
- continue
- if match_from_list(atom, cpv_slot_list):
- circular_atom = atom
- break
- if circular_atom is not None:
- other.append(this_choice)
- else:
- if all_use_satisfied:
- if all_in_graph:
- preferred_in_graph.append(this_choice)
- elif all_installed:
- if all_installed_slots:
- preferred_installed.append(this_choice)
- else:
- preferred_any_slot.append(this_choice)
- else:
- preferred_non_installed.append(this_choice)
- else:
- if all_in_graph:
- unsat_use_in_graph.append(this_choice)
- elif all_installed_slots:
- unsat_use_installed.append(this_choice)
- else:
- unsat_use_non_installed.append(this_choice)
- else:
- other.append(this_choice)
-
- # Prefer choices which contain upgrades to higher slots. This helps
- # for deps such as || ( foo:1 foo:2 ), where we want to prefer the
- # atom which matches the higher version rather than the atom furthest
- # to the left. Sorting is done separately for each of choice_bins, so
- # as not to interfere with the ordering of the bins. Because of the
- # bin separation, the main function of this code is to allow
- # --depclean to remove old slots (rather than to pull in new slots).
- for choices in choice_bins:
- if len(choices) < 2:
- continue
- for choice_1 in choices[1:]:
- atoms_1, slot_map_1, cp_map_1, all_available_1 = choice_1
- cps = set(cp_map_1)
- for choice_2 in choices:
- if choice_1 is choice_2:
- # choice_1 will not be promoted, so move on
- break
- atoms_2, slot_map_2, cp_map_2, all_available_2 = choice_2
- intersecting_cps = cps.intersection(cp_map_2)
- if not intersecting_cps:
- continue
- has_upgrade = False
- has_downgrade = False
- for cp in intersecting_cps:
- version_1 = cp_map_1[cp]
- version_2 = cp_map_2[cp]
- difference = pkgcmp(catpkgsplit(version_1)[1:],
- catpkgsplit(version_2)[1:])
- if difference != 0:
- if difference > 0:
- has_upgrade = True
- else:
- has_downgrade = True
- break
- if has_upgrade and not has_downgrade:
- # promote choice_1 in front of choice_2
- choices.remove(choice_1)
- index_2 = choices.index(choice_2)
- choices.insert(index_2, choice_1)
- break
-
- for allow_masked in (False, True):
- for choices in choice_bins:
- for atoms, slot_map, cp_map, all_available in choices:
- if all_available or allow_masked:
- return atoms
-
- assert(False) # This point should not be reachable
-
-def dep_check(depstring, mydbapi, mysettings, use="yes", mode=None, myuse=None,
- use_cache=1, use_binaries=0, myroot="/", trees=None):
- """Takes a depend string and parses the condition."""
- edebug = mysettings.get("PORTAGE_DEBUG", None) == "1"
- #check_config_instance(mysettings)
- if trees is None:
- trees = globals()["db"]
- if use=="yes":
- if myuse is None:
- #default behavior
- myusesplit = mysettings["PORTAGE_USE"].split()
- else:
- myusesplit = myuse
- # We've been given useflags to use.
- #print "USE FLAGS PASSED IN."
- #print myuse
- #if "bindist" in myusesplit:
- # print "BINDIST is set!"
- #else:
- # print "BINDIST NOT set."
- else:
- #we are being run by autouse(), don't consult USE vars yet.
- # WE ALSO CANNOT USE SETTINGS
- myusesplit=[]
-
- #convert parenthesis to sublists
- try:
- mysplit = portage.dep.paren_reduce(depstring)
- except portage.exception.InvalidDependString as e:
- return [0, str(e)]
-
- mymasks = set()
- useforce = set()
- useforce.add(mysettings["ARCH"])
- if use == "all":
- # This masking/forcing is only for repoman. In other cases, relevant
- # masking/forcing should have already been applied via
- # config.regenerate(). Also, binary or installed packages may have
- # been built with flags that are now masked, and it would be
- # inconsistent to mask them now. Additionally, myuse may consist of
- # flags from a parent package that is being merged to a $ROOT that is
- # different from the one that mysettings represents.
- mymasks.update(mysettings.usemask)
- mymasks.update(mysettings.archlist())
- mymasks.discard(mysettings["ARCH"])
- useforce.update(mysettings.useforce)
- useforce.difference_update(mymasks)
- try:
- mysplit = portage.dep.use_reduce(mysplit, uselist=myusesplit,
- masklist=mymasks, matchall=(use=="all"), excludeall=useforce)
- except portage.exception.InvalidDependString as e:
- return [0, str(e)]
-
- # Do the || conversions
- mysplit=portage.dep.dep_opconvert(mysplit)
-
- if mysplit == []:
- #dependencies were reduced to nothing
- return [1,[]]
-
- # Recursively expand new-style virtuals so as to
- # collapse one or more levels of indirection.
- try:
- mysplit = _expand_new_virtuals(mysplit, edebug, mydbapi, mysettings,
- use=use, mode=mode, myuse=myuse,
- use_force=useforce, use_mask=mymasks, use_cache=use_cache,
- use_binaries=use_binaries, myroot=myroot, trees=trees)
- except portage.exception.ParseError as e:
- return [0, str(e)]
-
- mysplit2=mysplit[:]
- mysplit2=dep_wordreduce(mysplit2,mysettings,mydbapi,mode,use_cache=use_cache)
- if mysplit2 is None:
- return [0, _("Invalid token")]
-
- writemsg("\n\n\n", 1)
- writemsg("mysplit: %s\n" % (mysplit), 1)
- writemsg("mysplit2: %s\n" % (mysplit2), 1)
-
- try:
- selected_atoms = dep_zapdeps(mysplit, mysplit2, myroot,
- use_binaries=use_binaries, trees=trees)
- except portage.exception.InvalidAtom as 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,)]
-
- return [1, selected_atoms]
-
-def dep_wordreduce(mydeplist,mysettings,mydbapi,mode,use_cache=1):
- "Reduces the deplist to ones and zeros"
- deplist=mydeplist[:]
- for mypos, token in enumerate(deplist):
- if isinstance(deplist[mypos], list):
- #recurse
- deplist[mypos]=dep_wordreduce(deplist[mypos],mysettings,mydbapi,mode,use_cache=use_cache)
- elif deplist[mypos]=="||":
- pass
- elif token[:1] == "!":
- deplist[mypos] = False
- else:
- mykey = deplist[mypos].cp
- if mysettings and mykey in mysettings.pprovideddict and \
- match_from_list(deplist[mypos], mysettings.pprovideddict[mykey]):
- deplist[mypos]=True
- elif mydbapi is None:
- # Assume nothing is satisfied. This forces dep_zapdeps to
- # return all of deps the deps that have been selected
- # (excluding those satisfied by package.provided).
- deplist[mypos] = False
- else:
- if mode:
- x = mydbapi.xmatch(mode, deplist[mypos])
- if mode.startswith("minimum-"):
- mydep = []
- if x:
- mydep.append(x)
- else:
- mydep = x
- else:
- mydep=mydbapi.match(deplist[mypos],use_cache=use_cache)
- if mydep!=None:
- tmp=(len(mydep)>=1)
- if deplist[mypos][0]=="!":
- tmp=False
- deplist[mypos]=tmp
- else:
- #encountered invalid string
- return None
- return deplist
-
-def getmaskingreason(mycpv, metadata=None, settings=None, portdb=None, return_location=False):
- from portage.util import grablines
- if settings is None:
- settings = globals()["settings"]
- if portdb is None:
- portdb = globals()["portdb"]
- mysplit = catpkgsplit(mycpv)
- if not mysplit:
- raise ValueError(_("invalid CPV: %s") % mycpv)
- if metadata is None:
- db_keys = list(portdb._aux_cache_keys)
- try:
- metadata = dict(zip(db_keys, portdb.aux_get(mycpv, db_keys)))
- except KeyError:
- if not portdb.cpv_exists(mycpv):
- raise
- if metadata is None:
- # Can't access SLOT due to corruption.
- cpv_slot_list = [mycpv]
- else:
- cpv_slot_list = ["%s:%s" % (mycpv, metadata["SLOT"])]
- mycp=mysplit[0]+"/"+mysplit[1]
-
- # XXX- This is a temporary duplicate of code from the config constructor.
- locations = [os.path.join(settings["PORTDIR"], "profiles")]
- locations.extend(settings.profiles)
- for ov in settings["PORTDIR_OVERLAY"].split():
- profdir = os.path.join(normalize_path(ov), "profiles")
- if os.path.isdir(profdir):
- locations.append(profdir)
- locations.append(os.path.join(settings["PORTAGE_CONFIGROOT"],
- USER_CONFIG_PATH))
- locations.reverse()
- pmasklists = [(x, grablines(os.path.join(x, "package.mask"), recursive=1)) for x in locations]
-
- if mycp in settings.pmaskdict:
- for x in settings.pmaskdict[mycp]:
- if match_from_list(x, cpv_slot_list):
- for pmask in pmasklists:
- comment = ""
- comment_valid = -1
- pmask_filename = os.path.join(pmask[0], "package.mask")
- for i in range(len(pmask[1])):
- l = pmask[1][i].strip()
- if l == "":
- comment = ""
- comment_valid = -1
- elif l[0] == "#":
- comment += (l+"\n")
- comment_valid = i + 1
- elif l == x:
- if comment_valid != i:
- comment = ""
- if return_location:
- return (comment, pmask_filename)
- else:
- return comment
- elif comment_valid != -1:
- # Apparently this comment applies to muliple masks, so
- # it remains valid until a blank line is encountered.
- comment_valid += 1
- if return_location:
- return (None, None)
- else:
- return None
-
-def getmaskingstatus(mycpv, settings=None, portdb=None):
- if settings is None:
- settings = config(clone=globals()["settings"])
- if portdb is None:
- portdb = globals()["portdb"]
-
- metadata = None
- installed = False
- if not isinstance(mycpv, basestring):
- # emerge passed in a Package instance
- pkg = mycpv
- mycpv = pkg.cpv
- metadata = pkg.metadata
- installed = pkg.installed
-
- mysplit = catpkgsplit(mycpv)
- if not mysplit:
- raise ValueError(_("invalid CPV: %s") % mycpv)
- if metadata is None:
- db_keys = list(portdb._aux_cache_keys)
- try:
- metadata = dict(zip(db_keys, portdb.aux_get(mycpv, db_keys)))
- except KeyError:
- if not portdb.cpv_exists(mycpv):
- raise
- return ["corruption"]
- if "?" in metadata["LICENSE"]:
- settings.setcpv(mycpv, mydb=metadata)
- metadata["USE"] = settings["PORTAGE_USE"]
- else:
- metadata["USE"] = ""
- mycp=mysplit[0]+"/"+mysplit[1]
-
- rValue = []
-
- # profile checking
- if settings._getProfileMaskAtom(mycpv, metadata):
- rValue.append("profile")
-
- # package.mask checking
- if settings._getMaskAtom(mycpv, metadata):
- rValue.append("package.mask")
-
- # keywords checking
- eapi = metadata["EAPI"]
- mygroups = settings._getKeywords(mycpv, metadata)
- licenses = metadata["LICENSE"]
- properties = metadata["PROPERTIES"]
- slot = metadata["SLOT"]
- if eapi.startswith("-"):
- eapi = eapi[1:]
- if not eapi_is_supported(eapi):
- return ["EAPI %s" % eapi]
- elif _eapi_is_deprecated(eapi) and not installed:
- return ["EAPI %s" % eapi]
- egroups = settings.configdict["backupenv"].get(
- "ACCEPT_KEYWORDS", "").split()
- pgroups = settings["ACCEPT_KEYWORDS"].split()
- myarch = settings["ARCH"]
- if pgroups and myarch not in pgroups:
- """For operating systems other than Linux, ARCH is not necessarily a
- valid keyword."""
- myarch = pgroups[0].lstrip("~")
-
- cp = cpv_getkey(mycpv)
- pkgdict = settings.pkeywordsdict.get(cp)
- matches = False
- if pkgdict:
- cpv_slot_list = ["%s:%s" % (mycpv, metadata["SLOT"])]
- for atom, pkgkeywords in pkgdict.items():
- if match_from_list(atom, cpv_slot_list):
- matches = True
- pgroups.extend(pkgkeywords)
- if matches or egroups:
- pgroups.extend(egroups)
- inc_pgroups = set()
- for x in pgroups:
- if x.startswith("-"):
- if x == "-*":
- inc_pgroups.clear()
- else:
- inc_pgroups.discard(x[1:])
- else:
- inc_pgroups.add(x)
- pgroups = inc_pgroups
- del inc_pgroups
-
- kmask = "missing"
-
- if '**' in pgroups:
- kmask = None
- else:
- for keyword in pgroups:
- if keyword in mygroups:
- kmask = None
- break
-
- if kmask:
- fallback = None
- for gp in mygroups:
- if gp=="*":
- kmask=None
- break
- elif gp=="-"+myarch and myarch in pgroups:
- kmask="-"+myarch
- break
- elif gp=="~"+myarch and myarch in pgroups:
- kmask="~"+myarch
- break
-
- try:
- missing_licenses = settings._getMissingLicenses(mycpv, metadata)
- if missing_licenses:
- allowed_tokens = set(["||", "(", ")"])
- allowed_tokens.update(missing_licenses)
- license_split = licenses.split()
- license_split = [x for x in license_split \
- if x in allowed_tokens]
- msg = license_split[:]
- msg.append("license(s)")
- rValue.append(" ".join(msg))
- except portage.exception.InvalidDependString as e:
- rValue.append("LICENSE: "+str(e))
-
- try:
- missing_properties = settings._getMissingProperties(mycpv, metadata)
- if missing_properties:
- allowed_tokens = set(["||", "(", ")"])
- allowed_tokens.update(missing_properties)
- properties_split = properties.split()
- properties_split = [x for x in properties_split \
- if x in allowed_tokens]
- msg = properties_split[:]
- msg.append("properties")
- rValue.append(" ".join(msg))
- except portage.exception.InvalidDependString as e:
- rValue.append("PROPERTIES: "+str(e))
-
- # Only show KEYWORDS masks for installed packages
- # if they're not masked for any other reason.
- if kmask and (not installed or not rValue):
- rValue.append(kmask+" keyword")
-
- return rValue
-
auxdbkeys = (
'DEPEND', 'RDEPEND', 'SLOT', 'SRC_URI',
'RESTRICT', 'HOMEPAGE', 'LICENSE', 'DESCRIPTION',
Modified: main/branches/prefix/pym/portage/dbapi/__init__.py
===================================================================
--- main/branches/prefix/pym/portage/dbapi/__init__.py 2010-02-27 19:26:00 UTC (rev 15482)
+++ main/branches/prefix/pym/portage/dbapi/__init__.py 2010-02-27 19:32:48 UTC (rev 15483)
@@ -8,7 +8,7 @@
import portage
portage.proxy.lazyimport.lazyimport(globals(),
- 'portage.dbapi.dep_expand:dep_expand',
+ 'portage.dbapi.dep_expand:_dep_expand',
'portage.dep:match_from_list',
'portage.locks:unlockfile',
'portage.output:colorize',
@@ -122,7 +122,7 @@
Returns:
a list of packages that match origdep
"""
- mydep = dep_expand(origdep, mydb=self, settings=self.settings)
+ mydep = _dep_expand(origdep, mydb=self, settings=self.settings)
return list(self._iter_match(mydep,
self.cp_list(mydep.cp, use_cache=use_cache)))
Modified: main/branches/prefix/pym/portage/dbapi/vartree.py
===================================================================
--- main/branches/prefix/pym/portage/dbapi/vartree.py 2010-02-27 19:26:00 UTC (rev 15482)
+++ main/branches/prefix/pym/portage/dbapi/vartree.py 2010-02-27 19:32:48 UTC (rev 15483)
@@ -40,8 +40,9 @@
InvalidData, InvalidPackageName, \
FileNotFound, PermissionDenied, UnsupportedAPIException
from portage.localization import _
+from portage.util.movefile import movefile
-from portage import abssymlink, movefile, _movefile, bsd_chflags
+from portage import abssymlink, _movefile, bsd_chflags
# This is a special version of the os module, wrapped for unicode support.
from portage import os
Deleted: main/branches/prefix/pym/portage/dep.py
===================================================================
--- main/branches/prefix/pym/portage/dep.py 2010-02-27 19:26:00 UTC (rev 15482)
+++ main/branches/prefix/pym/portage/dep.py 2010-02-27 19:32:48 UTC (rev 15483)
@@ -1,1203 +0,0 @@
-# deps.py -- Portage dependency resolution functions
-# Copyright 2003-2004 Gentoo Foundation
-# Distributed under the terms of the GNU General Public License v2
-# $Id$
-
-__all__ = [
- 'Atom', 'best_match_to_list', 'cpvequal',
- 'dep_getcpv', 'dep_getkey', 'dep_getslot',
- 'dep_getusedeps', 'dep_opconvert', 'flatten',
- 'get_operator', 'isjustname', 'isspecific',
- 'isvalidatom', 'match_from_list', 'match_to_list',
- 'paren_enclose', 'paren_normalize', 'paren_reduce',
- 'remove_slot', 'strip_empty', 'use_reduce'
-]
-
-# DEPEND SYNTAX:
-#
-# 'use?' only affects the immediately following word!
-# Nesting is the only legal way to form multiple '[!]use?' requirements.
-#
-# Where: 'a' and 'b' are use flags, and 'z' is a depend atom.
-#
-# "a? z" -- If 'a' in [use], then b is valid.
-# "a? ( z )" -- Syntax with parenthesis.
-# "a? b? z" -- Deprecated.
-# "a? ( b? z )" -- Valid
-# "a? ( b? ( z ) ) -- Valid
-#
-
-import re, sys
-import warnings
-from itertools import chain
-import portage.exception
-from portage.exception import InvalidData, InvalidAtom
-from portage.localization import _
-from portage.versions import catpkgsplit, catsplit, \
- pkgcmp, pkgsplit, ververify, _cp, _cpv
-import portage.cache.mappings
-
-if sys.hexversion >= 0x3000000:
- basestring = str
-
-def cpvequal(cpv1, cpv2):
- """
-
- @param cpv1: CategoryPackageVersion (no operators) Example: "sys-apps/portage-2.1"
- @type cpv1: String
- @param cpv2: CategoryPackageVersion (no operators) Example: "sys-apps/portage-2.1"
- @type cpv2: String
- @rtype: Boolean
- @returns:
- 1. True if cpv1 = cpv2
- 2. False Otherwise
- 3. Throws PortageException if cpv1 or cpv2 is not a CPV
-
- Example Usage:
- >>> from portage.dep import cpvequal
- >>> cpvequal("sys-apps/portage-2.1","sys-apps/portage-2.1")
- >>> True
-
- """
-
- split1 = catpkgsplit(cpv1)
- split2 = catpkgsplit(cpv2)
-
- if not split1 or not split2:
- raise portage.exception.PortageException(_("Invalid data '%s, %s', parameter was not a CPV") % (cpv1, cpv2))
-
- if split1[0] != split2[0]:
- return False
-
- return (pkgcmp(split1[1:], split2[1:]) == 0)
-
-def strip_empty(myarr):
- """
- Strip all empty elements from an array
-
- @param myarr: The list of elements
- @type myarr: List
- @rtype: Array
- @return: The array with empty elements removed
- """
- return [x for x in myarr if x]
-
-_paren_whitespace_re = re.compile(r'\S(\(|\))|(\(|\))\S')
-
-def paren_reduce(mystr,tokenize=1):
- """
- Take a string and convert all paren enclosed entities into sublists, optionally
- futher splitting the list elements by spaces.
-
- Example usage:
- >>> paren_reduce('foobar foo ( bar baz )',1)
- ['foobar', 'foo', ['bar', 'baz']]
- >>> paren_reduce('foobar foo ( bar baz )',0)
- ['foobar foo ', [' bar baz ']]
-
- @param mystr: The string to reduce
- @type mystr: String
- @param tokenize: Split on spaces to produces further list breakdown
- @type tokenize: Integer
- @rtype: Array
- @return: The reduced string in an array
- """
- global _dep_check_strict, _paren_whitespace_re
- if _dep_check_strict:
- m = _paren_whitespace_re.search(mystr)
- if m is not None:
- raise portage.exception.InvalidDependString(
- _("missing space by parenthesis: '%s'") % m.group(0))
- mylist = []
- while mystr:
- left_paren = mystr.find("(")
- has_left_paren = left_paren != -1
- right_paren = mystr.find(")")
- has_right_paren = right_paren != -1
- if not has_left_paren and not has_right_paren:
- freesec = mystr
- subsec = None
- tail = ""
- elif mystr[0] == ")":
- return [mylist,mystr[1:]]
- elif has_left_paren and not has_right_paren:
- raise portage.exception.InvalidDependString(
- _("missing right parenthesis: '%s'") % mystr)
- elif has_left_paren and left_paren < right_paren:
- freesec,subsec = mystr.split("(",1)
- sublist = paren_reduce(subsec, tokenize=tokenize)
- if len(sublist) != 2:
- raise portage.exception.InvalidDependString(
- _("malformed syntax: '%s'") % mystr)
- subsec, tail = sublist
- else:
- subsec,tail = mystr.split(")",1)
- if tokenize:
- subsec = strip_empty(subsec.split(" "))
- return [mylist+subsec,tail]
- return mylist+[subsec],tail
- if not isinstance(tail, basestring):
- raise portage.exception.InvalidDependString(
- _("malformed syntax: '%s'") % mystr)
- mystr = tail
- if freesec:
- if tokenize:
- mylist = mylist + strip_empty(freesec.split(" "))
- else:
- mylist = mylist + [freesec]
- if subsec is not None:
- mylist = mylist + [subsec]
- return mylist
-
-class paren_normalize(list):
- """Take a dependency structure as returned by paren_reduce or use_reduce
- and generate an equivalent structure that has no redundant lists."""
- def __init__(self, src):
- list.__init__(self)
- self._zap_parens(src, self)
-
- def _zap_parens(self, src, dest, disjunction=False):
- if not src:
- return dest
- i = iter(src)
- for x in i:
- if isinstance(x, basestring):
- if x == '||':
- x = self._zap_parens(next(i), [], disjunction=True)
- if len(x) == 1:
- dest.append(x[0])
- else:
- dest.append("||")
- dest.append(x)
- elif x.endswith("?"):
- dest.append(x)
- dest.append(self._zap_parens(next(i), []))
- else:
- dest.append(x)
- else:
- if disjunction:
- x = self._zap_parens(x, [])
- if len(x) == 1:
- dest.append(x[0])
- else:
- dest.append(x)
- else:
- self._zap_parens(x, dest)
- return dest
-
-def paren_enclose(mylist):
- """
- Convert a list to a string with sublists enclosed with parens.
-
- Example usage:
- >>> test = ['foobar','foo',['bar','baz']]
- >>> paren_enclose(test)
- 'foobar foo ( bar baz )'
-
- @param mylist: The list
- @type mylist: List
- @rtype: String
- @return: The paren enclosed string
- """
- mystrparts = []
- for x in mylist:
- if isinstance(x, list):
- mystrparts.append("( "+paren_enclose(x)+" )")
- else:
- mystrparts.append(x)
- return " ".join(mystrparts)
-
-# This is just for use by emerge so that it can enable a backward compatibility
-# mode in order to gracefully deal with installed packages that have invalid
-# atoms or dep syntax. For backward compatibility with api consumers, strict
-# behavior will be explicitly enabled as necessary.
-_dep_check_strict = False
-
-def use_reduce(deparray, uselist=[], masklist=[], matchall=0, excludeall=[]):
- """
- Takes a paren_reduce'd array and reduces the use? conditionals out
- leaving an array with subarrays
-
- @param deparray: paren_reduce'd list of deps
- @type deparray: List
- @param uselist: List of use flags
- @type uselist: List
- @param masklist: List of masked flags
- @type masklist: List
- @param matchall: Resolve all conditional deps unconditionally. Used by repoman
- @type matchall: Integer
- @rtype: List
- @return: The use reduced depend array
- """
- # Quick validity checks
- for x, y in enumerate(deparray):
- if y == '||':
- if len(deparray) - 1 == x or not isinstance(deparray[x+1], list):
- raise portage.exception.InvalidDependString(_('%(dep)s missing atom list in "%(deparray)s"') % {"dep": deparray[x], "deparray": paren_enclose(deparray)})
- if deparray and deparray[-1] and deparray[-1][-1] == "?":
- raise portage.exception.InvalidDependString(_('Conditional without target in "%s"') % paren_enclose(deparray))
-
- global _dep_check_strict
-
- mydeparray = deparray[:]
- rlist = []
- while mydeparray:
- head = mydeparray.pop(0)
-
- if not isinstance(head, basestring):
- additions = use_reduce(head, uselist, masklist, matchall, excludeall)
- if additions:
- rlist.append(additions)
- elif rlist and rlist[-1] == "||":
- #XXX: Currently some DEPEND strings have || lists without default atoms.
- # raise portage.exception.InvalidDependString("No default atom(s) in \""+paren_enclose(deparray)+"\"")
- rlist.append([])
-
- else:
- if head[-1:] == "?": # Use reduce next group on fail.
- # Pull any other use conditions and the following atom or list into a separate array
- newdeparray = [head]
- while isinstance(newdeparray[-1], basestring) and \
- newdeparray[-1][-1:] == "?":
- if mydeparray:
- newdeparray.append(mydeparray.pop(0))
- else:
- raise ValueError(_("Conditional with no target."))
-
- # Deprecation checks
- warned = 0
- if len(newdeparray[-1]) == 0:
- sys.stderr.write(_("Note: Empty target in string. (Deprecated)\n"))
- warned = 1
- if len(newdeparray) != 2:
- sys.stderr.write(_("Note: Nested use flags without parenthesis (Deprecated)\n"))
- warned = 1
- if warned:
- sys.stderr.write(" --> "+" ".join(map(str,[head]+newdeparray))+"\n")
-
- # Check that each flag matches
- ismatch = True
- missing_flag = False
- for head in newdeparray[:-1]:
- head = head[:-1]
- if not head:
- missing_flag = True
- break
- if head.startswith("!"):
- head_key = head[1:]
- if not head_key:
- missing_flag = True
- break
- if not matchall and head_key in uselist or \
- head_key in excludeall:
- ismatch = False
- break
- elif head not in masklist:
- if not matchall and head not in uselist:
- ismatch = False
- break
- else:
- ismatch = False
- if missing_flag:
- raise portage.exception.InvalidDependString(
- _('Conditional without flag: "') + \
- paren_enclose([head+"?", newdeparray[-1]])+"\"")
-
- # If they all match, process the target
- if ismatch:
- target = newdeparray[-1]
- if isinstance(target, list):
- additions = use_reduce(target, uselist, masklist, matchall, excludeall)
- if additions:
- rlist.append(additions)
- elif not _dep_check_strict:
- # The old deprecated behavior.
- rlist.append(target)
- else:
- raise portage.exception.InvalidDependString(
- _("Conditional without parenthesis: '%s?'") % head)
-
- else:
- rlist += [head]
-
- return rlist
-
-def dep_opconvert(deplist):
- """
- Iterate recursively through a list of deps, if the
- dep is a '||' or '&&' operator, combine it with the
- list of deps that follows..
-
- Example usage:
- >>> test = ["blah", "||", ["foo", "bar", "baz"]]
- >>> dep_opconvert(test)
- ['blah', ['||', 'foo', 'bar', 'baz']]
-
- @param deplist: A list of deps to format
- @type mydep: List
- @rtype: List
- @return:
- The new list with the new ordering
- """
-
- retlist = []
- x = 0
- while x != len(deplist):
- if isinstance(deplist[x], list):
- retlist.append(dep_opconvert(deplist[x]))
- elif deplist[x] == "||" or deplist[x] == "&&":
- retlist.append([deplist[x]] + dep_opconvert(deplist[x+1]))
- x += 1
- else:
- retlist.append(deplist[x])
- x += 1
- return retlist
-
-def flatten(mylist):
- """
- Recursively traverse nested lists and return a single list containing
- all non-list elements that are found.
-
- Example usage:
- >>> flatten([1, [2, 3, [4]]])
- [1, 2, 3, 4]
-
- @param mylist: A list containing nested lists and non-list elements.
- @type mylist: List
- @rtype: List
- @return: A single list containing only non-list elements.
- """
- newlist = []
- for x in mylist:
- if isinstance(x, list):
- newlist.extend(flatten(x))
- else:
- newlist.append(x)
- return newlist
-
-class _use_dep(object):
-
- __slots__ = ("__weakref__", "conditional",
- "disabled", "enabled", "tokens", "required")
-
- _conditionals_class = portage.cache.mappings.slot_dict_class(
- ("disabled", "enabled", "equal", "not_equal"), prefix="")
-
- _valid_use_re = re.compile(r'^[^-?!=][^?!=]*$')
-
- def __init__(self, use):
- enabled_flags = []
- disabled_flags = []
- conditional = self._conditionals_class()
- for k in conditional.allowed_keys:
- conditional[k] = []
-
- for x in use:
- last_char = x[-1:]
- first_char = x[:1]
-
- if "?" == last_char:
- if "!" == first_char:
- conditional.disabled.append(
- self._validate_flag(x, x[1:-1]))
- else:
- conditional.enabled.append(
- self._validate_flag(x, x[:-1]))
-
- elif "=" == last_char:
- if "!" == first_char:
- conditional.not_equal.append(
- self._validate_flag(x, x[1:-1]))
- else:
- conditional.equal.append(
- self._validate_flag(x, x[:-1]))
-
- else:
- if "-" == first_char:
- disabled_flags.append(self._validate_flag(x, x[1:]))
- else:
- enabled_flags.append(self._validate_flag(x, x))
-
- self.tokens = use
- if not isinstance(self.tokens, tuple):
- self.tokens = tuple(self.tokens)
-
- self.required = frozenset(chain(
- enabled_flags,
- disabled_flags,
- *conditional.values()
- ))
-
- self.enabled = frozenset(enabled_flags)
- self.disabled = frozenset(disabled_flags)
- self.conditional = None
-
- for v in conditional.values():
- if v:
- for k, v in conditional.items():
- conditional[k] = frozenset(v)
- self.conditional = conditional
- break
-
- def _validate_flag(self, token, flag):
- if self._valid_use_re.match(flag) is None:
- raise InvalidAtom(_("Invalid use dep: '%s'") % (token,))
- return flag
-
- def __bool__(self):
- return bool(self.tokens)
-
- if sys.hexversion < 0x3000000:
- __nonzero__ = __bool__
-
- def __str__(self):
- if not self.tokens:
- return ""
- return "[%s]" % (",".join(self.tokens),)
-
- def __repr__(self):
- return "portage.dep._use_dep(%s)" % repr(self.tokens)
-
- def evaluate_conditionals(self, use):
- """
- Create a new instance with conditionals evaluated.
-
- Conditional evaluation behavior:
-
- parent state conditional result
-
- x x? x
- -x x?
- x !x?
- -x !x? -x
-
- x x= x
- -x x= -x
- x !x= -x
- -x !x= x
-
- Conditional syntax examples:
-
- Compact Form Equivalent Expanded Form
-
- foo[bar?] bar? ( foo[bar] ) !bar? ( foo )
- foo[!bar?] bar? ( foo ) !bar? ( foo[-bar] )
- foo[bar=] bar? ( foo[bar] ) !bar? ( foo[-bar] )
- foo[!bar=] bar? ( foo[-bar] ) !bar? ( foo[bar] )
-
- """
- tokens = []
-
- conditional = self.conditional
- tokens.extend(self.enabled)
- tokens.extend("-" + x for x in self.disabled)
- tokens.extend(x for x in conditional.enabled if x in use)
- tokens.extend("-" + x for x in conditional.disabled if x not in use)
-
- tokens.extend(x for x in conditional.equal if x in use)
- tokens.extend("-" + x for x in conditional.equal if x not in use)
- tokens.extend("-" + x for x in conditional.not_equal if x in use)
- tokens.extend(x for x in conditional.not_equal if x not in use)
-
- return _use_dep(tokens)
-
- def _eval_qa_conditionals(self, use_mask, use_force):
- """
- For repoman, evaluate all possible combinations within the constraints
- of the given use.force and use.mask settings. The result may seem
- ambiguous in the sense that the same flag can be in both the enabled
- and disabled sets, but this is useful within the context of how its
- intended to be used by repoman. It is assumed that the caller has
- already ensured that there is no intersection between the given
- use_mask and use_force sets when necessary.
- """
- tokens = []
-
- conditional = self.conditional
- tokens.extend(self.enabled)
- tokens.extend("-" + x for x in self.disabled)
- tokens.extend(x for x in conditional.enabled if x not in use_mask)
- tokens.extend("-" + x for x in conditional.disabled if x not in use_force)
-
- tokens.extend(x for x in conditional.equal if x not in use_mask)
- tokens.extend("-" + x for x in conditional.equal if x not in use_force)
- tokens.extend("-" + x for x in conditional.not_equal if x not in use_mask)
- tokens.extend(x for x in conditional.not_equal if x not in use_force)
-
- return _use_dep(tokens)
-
-if sys.hexversion < 0x3000000:
- _atom_base = unicode
-else:
- _atom_base = str
-
-class Atom(_atom_base):
-
- """
- For compatibility with existing atom string manipulation code, this
- class emulates most of the str methods that are useful with atoms.
- """
-
- class _blocker(object):
- __slots__ = ("overlap",)
-
- class _overlap(object):
- __slots__ = ("forbid",)
-
- def __init__(self, forbid=False):
- self.forbid = forbid
-
- def __init__(self, forbid_overlap=False):
- self.overlap = self._overlap(forbid=forbid_overlap)
-
- def __init__(self, s):
- if isinstance(s, Atom):
- # This is an efficiency assertion, to ensure that the Atom
- # constructor is not called redundantly.
- raise TypeError(_("Expected %s, got %s") % \
- (_atom_base, type(s)))
-
- _atom_base.__init__(s)
-
- if "!" == s[:1]:
- blocker = self._blocker(forbid_overlap=("!" == s[1:2]))
- if blocker.overlap.forbid:
- s = s[2:]
- else:
- s = s[1:]
- else:
- blocker = False
- self.__dict__['blocker'] = blocker
- m = _atom_re.match(s)
- if m is None:
- raise InvalidAtom(self)
-
- if m.group('op') is not None:
- base = _atom_re.groupindex['op']
- op = m.group(base + 1)
- cpv = m.group(base + 2)
- cp = m.group(base + 3)
- if m.group(base + 4) is not None:
- raise InvalidAtom(self)
- elif m.group('star') is not None:
- base = _atom_re.groupindex['star']
- op = '=*'
- cpv = m.group(base + 1)
- cp = m.group(base + 2)
- if m.group(base + 3) is not None:
- raise InvalidAtom(self)
- elif m.group('simple') is not None:
- op = None
- cpv = cp = m.group(_atom_re.groupindex['simple'] + 1)
- if m.group(_atom_re.groupindex['simple'] + 2) is not None:
- raise InvalidAtom(self)
- else:
- raise AssertionError(_("required group not found in atom: '%s'") % self)
- self.__dict__['cp'] = cp
- self.__dict__['cpv'] = cpv
- self.__dict__['slot'] = m.group(_atom_re.groups - 1)
- self.__dict__['operator'] = op
-
- use_str = m.group(_atom_re.groups)
- if use_str is not None:
- use = _use_dep(dep_getusedeps(s))
- without_use = Atom(m.group('without_use'))
- else:
- use = None
- without_use = self
-
- self.__dict__['use'] = use
- self.__dict__['without_use'] = without_use
-
- def __setattr__(self, name, value):
- raise AttributeError("Atom instances are immutable",
- self.__class__, name, value)
-
- def intersects(self, other):
- """
- Atoms with different cpv, operator or use attributes cause this method
- to return False even though there may actually be some intersection.
- TODO: Detect more forms of intersection.
- @param other: The package atom to match
- @type other: Atom
- @rtype: Boolean
- @return: True if this atom and the other atom intersect,
- False otherwise.
- """
- if not isinstance(other, Atom):
- raise TypeError("expected %s, got %s" % \
- (Atom, type(other)))
-
- if self == other:
- return True
-
- if self.cp != other.cp or \
- self.use != other.use or \
- self.operator != other.operator or \
- self.cpv != other.cpv:
- return False
-
- if self.slot is None or \
- other.slot is None or \
- self.slot == other.slot:
- return True
-
- return False
-
- def evaluate_conditionals(self, use):
- """
- Create an atom instance with any USE conditionals evaluated.
- @param use: The set of enabled USE flags
- @type use: set
- @rtype: Atom
- @return: an atom instance with any USE conditionals evaluated
- """
- if not (self.use and self.use.conditional):
- return self
- atom = remove_slot(self)
- if self.slot:
- atom += ":%s" % self.slot
- atom += str(self.use.evaluate_conditionals(use))
- return Atom(atom)
-
- def __copy__(self):
- """Immutable, so returns self."""
- return self
-
- def __deepcopy__(self, memo=None):
- """Immutable, so returns self."""
- memo[id(self)] = self
- return self
-
-def get_operator(mydep):
- """
- Return the operator used in a depstring.
-
- Example usage:
- >>> from portage.dep import *
- >>> get_operator(">=test-1.0")
- '>='
-
- @param mydep: The dep string to check
- @type mydep: String
- @rtype: String
- @return: The operator. One of:
- '~', '=', '>', '<', '=*', '>=', or '<='
- """
- if isinstance(mydep, Atom):
- return mydep.operator
- try:
- return Atom(mydep).operator
- except InvalidAtom:
- pass
-
- # Fall back to legacy code for backward compatibility.
- warnings.warn(_("%s is deprecated, use %s instead") % \
- ('portage.dep.get_operator()', 'portage.dep.Atom.operator'),
- DeprecationWarning)
- operator = None
- if mydep:
- mydep = remove_slot(mydep)
- if not mydep:
- return None
- if mydep[0] == "~":
- operator = "~"
- elif mydep[0] == "=":
- if mydep[-1] == "*":
- operator = "=*"
- else:
- operator = "="
- elif mydep[0] in "><":
- if len(mydep) > 1 and mydep[1] == "=":
- operator = mydep[0:2]
- else:
- operator = mydep[0]
- else:
- operator = None
-
- return operator
-
-def dep_getcpv(mydep):
- """
- Return the category-package-version with any operators/slot specifications stripped off
-
- Example usage:
- >>> dep_getcpv('>=media-libs/test-3.0')
- 'media-libs/test-3.0'
-
- @param mydep: The depstring
- @type mydep: String
- @rtype: String
- @return: The depstring with the operator removed
- """
- if isinstance(mydep, Atom):
- return mydep.cpv
- try:
- return Atom(mydep).cpv
- except InvalidAtom:
- pass
-
- # Fall back to legacy code for backward compatibility.
- warnings.warn(_("%s is deprecated, use %s instead") % \
- ('portage.dep.dep_getcpv()', 'portage.dep.Atom.cpv'),
- DeprecationWarning, stacklevel=2)
- mydep_orig = mydep
- if mydep:
- mydep = remove_slot(mydep)
- if mydep and mydep[0] == "*":
- mydep = mydep[1:]
- if mydep and mydep[-1] == "*":
- mydep = mydep[:-1]
- if mydep and mydep[0] == "!":
- if mydep[1:2] == "!":
- mydep = mydep[2:]
- else:
- mydep = mydep[1:]
- if mydep[:2] in [">=", "<="]:
- mydep = mydep[2:]
- elif mydep[:1] in "=<>~":
- mydep = mydep[1:]
- return mydep
-
-def dep_getslot(mydep):
- """
- Retrieve the slot on a depend.
-
- Example usage:
- >>> dep_getslot('app-misc/test:3')
- '3'
-
- @param mydep: The depstring to retrieve the slot of
- @type mydep: String
- @rtype: String
- @return: The slot
- """
- slot = getattr(mydep, "slot", False)
- if slot is not False:
- return slot
- colon = mydep.find(":")
- if colon != -1:
- bracket = mydep.find("[", colon)
- if bracket == -1:
- return mydep[colon+1:]
- else:
- return mydep[colon+1:bracket]
- return None
-
-def remove_slot(mydep):
- """
- Removes dep components from the right side of an atom:
- * slot
- * use
- * repo
- """
- colon = mydep.find(":")
- if colon != -1:
- mydep = mydep[:colon]
- else:
- bracket = mydep.find("[")
- if bracket != -1:
- mydep = mydep[:bracket]
- return mydep
-
-def dep_getusedeps( depend ):
- """
- Pull a listing of USE Dependencies out of a dep atom.
-
- Example usage:
- >>> dep_getusedeps('app-misc/test:3[foo,-bar]')
- ('foo', '-bar')
-
- @param depend: The depstring to process
- @type depend: String
- @rtype: List
- @return: List of use flags ( or [] if no flags exist )
- """
- use_list = []
- open_bracket = depend.find('[')
- # -1 = failure (think c++ string::npos)
- comma_separated = False
- bracket_count = 0
- while( open_bracket != -1 ):
- bracket_count += 1
- if bracket_count > 1:
- raise InvalidAtom(_("USE Dependency with more "
- "than one set of brackets: %s") % (depend,))
- close_bracket = depend.find(']', open_bracket )
- if close_bracket == -1:
- raise InvalidAtom(_("USE Dependency with no closing bracket: %s") % depend )
- use = depend[open_bracket + 1: close_bracket]
- # foo[1:1] may return '' instead of None, we don't want '' in the result
- if not use:
- raise InvalidAtom(_("USE Dependency with "
- "no use flag ([]): %s") % depend )
- if not comma_separated:
- comma_separated = "," in use
-
- if comma_separated and bracket_count > 1:
- raise InvalidAtom(_("USE Dependency contains a mixture of "
- "comma and bracket separators: %s") % depend )
-
- if comma_separated:
- for x in use.split(","):
- if x:
- use_list.append(x)
- else:
- raise InvalidAtom(_("USE Dependency with no use "
- "flag next to comma: %s") % depend )
- else:
- use_list.append(use)
-
- # Find next use flag
- open_bracket = depend.find( '[', open_bracket+1 )
- return tuple(use_list)
-
-# \w is [a-zA-Z0-9_]
-
-# 2.1.3 A slot name may contain any of the characters [A-Za-z0-9+_.-].
-# It must not begin with a hyphen or a dot.
-_slot = r'([\w+][\w+.-]*)'
-_slot_re = re.compile('^' + _slot + '$', re.VERBOSE)
-
-_use = r'\[.*\]'
-_op = r'([=~]|[><]=?)'
-
-_atom_re = re.compile('^(?P<without_use>(?:' +
- '(?P<op>' + _op + _cpv + ')|' +
- '(?P<star>=' + _cpv + r'\*)|' +
- '(?P<simple>' + _cp + '))(:' + _slot + ')?)(' + _use + ')?$', re.VERBOSE)
-
-def isvalidatom(atom, allow_blockers=False):
- """
- Check to see if a depend atom is valid
-
- Example usage:
- >>> isvalidatom('media-libs/test-3.0')
- False
- >>> isvalidatom('>=media-libs/test-3.0')
- True
-
- @param atom: The depend atom to check against
- @type atom: String or Atom
- @rtype: Boolean
- @return: One of the following:
- 1) False if the atom is invalid
- 2) True if the atom is valid
- """
- try:
- if not isinstance(atom, Atom):
- atom = Atom(atom)
- if not allow_blockers and atom.blocker:
- return False
- return True
- except InvalidAtom:
- return False
-
-def isjustname(mypkg):
- """
- Checks to see if the atom is only the package name (no version parts).
-
- Example usage:
- >>> isjustname('=media-libs/test-3.0')
- False
- >>> isjustname('media-libs/test')
- True
-
- @param mypkg: The package atom to check
- @param mypkg: String or Atom
- @rtype: Integer
- @return: One of the following:
- 1) False if the package string is not just the package name
- 2) True if it is
- """
- try:
- if not isinstance(mypkg, Atom):
- mypkg = Atom(mypkg)
- return mypkg == mypkg.cp
- except InvalidAtom:
- pass
-
- for x in mypkg.split('-')[-2:]:
- if ververify(x):
- return False
- return True
-
-def isspecific(mypkg):
- """
- Checks to see if a package is in =category/package-version or
- package-version format.
-
- Example usage:
- >>> isspecific('media-libs/test')
- False
- >>> isspecific('=media-libs/test-3.0')
- True
-
- @param mypkg: The package depstring to check against
- @type mypkg: String
- @rtype: Boolean
- @return: One of the following:
- 1) False if the package string is not specific
- 2) True if it is
- """
- try:
- if not isinstance(mypkg, Atom):
- mypkg = Atom(mypkg)
- return mypkg != mypkg.cp
- except InvalidAtom:
- pass
-
- # Fall back to legacy code for backward compatibility.
- return not isjustname(mypkg)
-
-def dep_getkey(mydep):
- """
- Return the category/package-name of a depstring.
-
- Example usage:
- >>> dep_getkey('=media-libs/test-3.0')
- 'media-libs/test'
-
- @param mydep: The depstring to retrieve the category/package-name of
- @type mydep: String
- @rtype: String
- @return: The package category/package-name
- """
- if isinstance(mydep, Atom):
- return mydep.cp
- try:
- return Atom(mydep).cp
- except InvalidAtom:
- try:
- atom = Atom('=' + mydep)
- except InvalidAtom:
- pass
- else:
- warnings.warn(_("invalid input to %s: '%s', use %s instead") % \
- ('portage.dep.dep_getkey()', mydep, 'portage.cpv_getkey()'),
- DeprecationWarning, stacklevel=2)
- return atom.cp
-
- # Fall back to legacy code for backward compatibility.
- warnings.warn(_("%s is deprecated, use %s instead") % \
- ('portage.dep.dep_getkey()', 'portage.dep.Atom.cp'),
- DeprecationWarning, stacklevel=2)
- mydep = dep_getcpv(mydep)
- if mydep and isspecific(mydep):
- mysplit = catpkgsplit(mydep)
- if not mysplit:
- return mydep
- return mysplit[0] + "/" + mysplit[1]
- else:
- return mydep
-
-def match_to_list(mypkg, mylist):
- """
- Searches list for entries that matches the package.
-
- @param mypkg: The package atom to match
- @type mypkg: String
- @param mylist: The list of package atoms to compare against
- @param mylist: List
- @rtype: List
- @return: A unique list of package atoms that match the given package atom
- """
- return [ x for x in set(mylist) if match_from_list(x, [mypkg]) ]
-
-def best_match_to_list(mypkg, mylist):
- """
- Returns the most specific entry that matches the package given.
-
- @param mypkg: The package atom to check
- @type mypkg: String
- @param mylist: The list of package atoms to check against
- @type mylist: List
- @rtype: String
- @return: The package atom which best matches given the following ordering:
- - =cpv 6
- - ~cpv 5
- - =cpv* 4
- - cp:slot 3
- - >cpv 2
- - <cpv 2
- - >=cpv 2
- - <=cpv 2
- - cp 1
- """
- operator_values = {'=':6, '~':5, '=*':4,
- '>':2, '<':2, '>=':2, '<=':2, None:1}
- maxvalue = 0
- bestm = None
- for x in match_to_list(mypkg, mylist):
- if dep_getslot(x) is not None:
- if maxvalue < 3:
- maxvalue = 3
- bestm = x
- op_val = operator_values[x.operator]
- if op_val > maxvalue:
- maxvalue = op_val
- bestm = x
- return bestm
-
-def match_from_list(mydep, candidate_list):
- """
- Searches list for entries that matches the package.
-
- @param mydep: The package atom to match
- @type mydep: String
- @param candidate_list: The list of package atoms to compare against
- @param candidate_list: List
- @rtype: List
- @return: A list of package atoms that match the given package atom
- """
-
- if not candidate_list:
- return []
-
- from portage.util import writemsg
- if "!" == mydep[:1]:
- mydep = mydep[1:]
- if not isinstance(mydep, Atom):
- mydep = Atom(mydep)
-
- mycpv = mydep.cpv
- mycpv_cps = catpkgsplit(mycpv) # Can be None if not specific
- slot = mydep.slot
-
- if not mycpv_cps:
- cat, pkg = catsplit(mycpv)
- ver = None
- rev = None
- else:
- cat, pkg, ver, rev = mycpv_cps
- if mydep == mycpv:
- raise KeyError(_("Specific key requires an operator"
- " (%s) (try adding an '=')") % (mydep))
-
- if ver and rev:
- operator = mydep.operator
- if not operator:
- writemsg(_("!!! Invalid atom: %s\n") % mydep, noiselevel=-1)
- return []
- else:
- operator = None
-
- mylist = []
-
- if operator is None:
- for x in candidate_list:
- cp = getattr(x, "cp", None)
- if cp is None:
- mysplit = catpkgsplit(remove_slot(x))
- if mysplit is not None:
- cp = mysplit[0] + '/' + mysplit[1]
- if cp != mycpv:
- continue
- mylist.append(x)
-
- elif operator == "=": # Exact match
- for x in candidate_list:
- xcpv = getattr(x, "cpv", None)
- if xcpv is None:
- xcpv = remove_slot(x)
- if not cpvequal(xcpv, mycpv):
- continue
- mylist.append(x)
-
- elif operator == "=*": # glob match
- # XXX: Nasty special casing for leading zeros
- # Required as =* is a literal prefix match, so can't
- # use vercmp
- mysplit = catpkgsplit(mycpv)
- myver = mysplit[2].lstrip("0")
- if not myver or not myver[0].isdigit():
- myver = "0"+myver
- mycpv = mysplit[0]+"/"+mysplit[1]+"-"+myver
- for x in candidate_list:
- xs = getattr(x, "cpv_split", None)
- if xs is None:
- xs = catpkgsplit(remove_slot(x))
- myver = xs[2].lstrip("0")
- if not myver or not myver[0].isdigit():
- myver = "0"+myver
- xcpv = xs[0]+"/"+xs[1]+"-"+myver
- if xcpv.startswith(mycpv):
- mylist.append(x)
-
- elif operator == "~": # version, any revision, match
- for x in candidate_list:
- xs = getattr(x, "cpv_split", None)
- if xs is None:
- xs = catpkgsplit(remove_slot(x))
- if xs is None:
- raise InvalidData(x)
- if not cpvequal(xs[0]+"/"+xs[1]+"-"+xs[2], mycpv_cps[0]+"/"+mycpv_cps[1]+"-"+mycpv_cps[2]):
- continue
- if xs[2] != ver:
- continue
- mylist.append(x)
-
- elif operator in [">", ">=", "<", "<="]:
- mysplit = ["%s/%s" % (cat, pkg), ver, rev]
- for x in candidate_list:
- xs = getattr(x, "cpv_split", None)
- if xs is None:
- xs = catpkgsplit(remove_slot(x))
- xcat, xpkg, xver, xrev = xs
- xs = ["%s/%s" % (xcat, xpkg), xver, xrev]
- try:
- result = pkgcmp(xs, mysplit)
- except ValueError: # pkgcmp may return ValueError during int() conversion
- writemsg(_("\nInvalid package name: %s\n") % x, noiselevel=-1)
- raise
- if result is None:
- continue
- elif operator == ">":
- if result > 0:
- mylist.append(x)
- elif operator == ">=":
- if result >= 0:
- mylist.append(x)
- elif operator == "<":
- if result < 0:
- mylist.append(x)
- elif operator == "<=":
- if result <= 0:
- mylist.append(x)
- else:
- raise KeyError(_("Unknown operator: %s") % mydep)
- else:
- raise KeyError(_("Unknown operator: %s") % mydep)
-
- if slot is not None:
- candidate_list = mylist
- mylist = []
- for x in candidate_list:
- xslot = getattr(x, "slot", False)
- if xslot is False:
- xslot = dep_getslot(x)
- if xslot is not None and xslot != slot:
- continue
- mylist.append(x)
-
- if mydep.use:
- candidate_list = mylist
- mylist = []
- for x in candidate_list:
- use = getattr(x, "use", None)
- if use is not None:
- regex = x.iuse.regex
- missing_iuse = False
- for y in mydep.use.required:
- if regex.match(y) is None:
- missing_iuse = True
- break
- if missing_iuse:
- continue
- if mydep.use.enabled.difference(use.enabled):
- continue
- if mydep.use.disabled.intersection(use.enabled):
- continue
- mylist.append(x)
-
- return mylist
Copied: main/branches/prefix/pym/portage/package/ebuild/getmaskingreason.py (from rev 15465, main/trunk/pym/portage/package/ebuild/getmaskingreason.py)
===================================================================
--- main/branches/prefix/pym/portage/package/ebuild/getmaskingreason.py (rev 0)
+++ main/branches/prefix/pym/portage/package/ebuild/getmaskingreason.py 2010-02-27 19:32:48 UTC (rev 15483)
@@ -0,0 +1,78 @@
+# Copyright 2010 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+# $Id$
+
+__all__ = ['getmaskingreason']
+
+import portage
+from portage import os
+from portage.const import USER_CONFIG_PATH
+from portage.dep import match_from_list
+from portage.localization import _
+from portage.util import grablines, normalize_path
+from portage.versions import catpkgsplit
+
+def getmaskingreason(mycpv, metadata=None, settings=None, portdb=None, return_location=False):
+ if settings is None:
+ settings = portage.settings
+ if portdb is None:
+ portdb = portage.portdb
+ mysplit = catpkgsplit(mycpv)
+ if not mysplit:
+ raise ValueError(_("invalid CPV: %s") % mycpv)
+ if metadata is None:
+ db_keys = list(portdb._aux_cache_keys)
+ try:
+ metadata = dict(zip(db_keys, portdb.aux_get(mycpv, db_keys)))
+ except KeyError:
+ if not portdb.cpv_exists(mycpv):
+ raise
+ if metadata is None:
+ # Can't access SLOT due to corruption.
+ cpv_slot_list = [mycpv]
+ else:
+ cpv_slot_list = ["%s:%s" % (mycpv, metadata["SLOT"])]
+ mycp=mysplit[0]+"/"+mysplit[1]
+
+ # XXX- This is a temporary duplicate of code from the config constructor.
+ locations = [os.path.join(settings["PORTDIR"], "profiles")]
+ locations.extend(settings.profiles)
+ for ov in settings["PORTDIR_OVERLAY"].split():
+ profdir = os.path.join(normalize_path(ov), "profiles")
+ if os.path.isdir(profdir):
+ locations.append(profdir)
+ locations.append(os.path.join(settings["PORTAGE_CONFIGROOT"],
+ USER_CONFIG_PATH))
+ locations.reverse()
+ pmasklists = [(x, grablines(os.path.join(x, "package.mask"), recursive=1)) for x in locations]
+
+ if mycp in settings.pmaskdict:
+ for x in settings.pmaskdict[mycp]:
+ if match_from_list(x, cpv_slot_list):
+ for pmask in pmasklists:
+ comment = ""
+ comment_valid = -1
+ pmask_filename = os.path.join(pmask[0], "package.mask")
+ for i in range(len(pmask[1])):
+ l = pmask[1][i].strip()
+ if l == "":
+ comment = ""
+ comment_valid = -1
+ elif l[0] == "#":
+ comment += (l+"\n")
+ comment_valid = i + 1
+ elif l == x:
+ if comment_valid != i:
+ comment = ""
+ if return_location:
+ return (comment, pmask_filename)
+ else:
+ return comment
+ elif comment_valid != -1:
+ # Apparently this comment applies to muliple masks, so
+ # it remains valid until a blank line is encountered.
+ comment_valid += 1
+ if return_location:
+ return (None, None)
+ else:
+ return None
Copied: main/branches/prefix/pym/portage/package/ebuild/getmaskingstatus.py (from rev 15465, main/trunk/pym/portage/package/ebuild/getmaskingstatus.py)
===================================================================
--- main/branches/prefix/pym/portage/package/ebuild/getmaskingstatus.py (rev 0)
+++ main/branches/prefix/pym/portage/package/ebuild/getmaskingstatus.py 2010-02-27 19:32:48 UTC (rev 15483)
@@ -0,0 +1,154 @@
+# Copyright 2010 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+# $Id$
+
+__all__ = ['getmaskingstatus']
+
+import portage
+from portage import eapi_is_supported, _eapi_is_deprecated
+from portage.dep import match_from_list
+from portage.localization import _
+from portage.package.ebuild.config import config
+from portage.versions import catpkgsplit, cpv_getkey
+
+def getmaskingstatus(mycpv, settings=None, portdb=None):
+ if settings is None:
+ settings = config(clone=portage.settings)
+ if portdb is None:
+ portdb = portage.portdb
+
+ metadata = None
+ installed = False
+ if not isinstance(mycpv, basestring):
+ # emerge passed in a Package instance
+ pkg = mycpv
+ mycpv = pkg.cpv
+ metadata = pkg.metadata
+ installed = pkg.installed
+
+ mysplit = catpkgsplit(mycpv)
+ if not mysplit:
+ raise ValueError(_("invalid CPV: %s") % mycpv)
+ if metadata is None:
+ db_keys = list(portdb._aux_cache_keys)
+ try:
+ metadata = dict(zip(db_keys, portdb.aux_get(mycpv, db_keys)))
+ except KeyError:
+ if not portdb.cpv_exists(mycpv):
+ raise
+ return ["corruption"]
+ if "?" in metadata["LICENSE"]:
+ settings.setcpv(mycpv, mydb=metadata)
+ metadata["USE"] = settings["PORTAGE_USE"]
+ else:
+ metadata["USE"] = ""
+
+ rValue = []
+
+ # profile checking
+ if settings._getProfileMaskAtom(mycpv, metadata):
+ rValue.append("profile")
+
+ # package.mask checking
+ if settings._getMaskAtom(mycpv, metadata):
+ rValue.append("package.mask")
+
+ # keywords checking
+ eapi = metadata["EAPI"]
+ mygroups = settings._getKeywords(mycpv, metadata)
+ licenses = metadata["LICENSE"]
+ properties = metadata["PROPERTIES"]
+ if eapi.startswith("-"):
+ eapi = eapi[1:]
+ if not eapi_is_supported(eapi):
+ return ["EAPI %s" % eapi]
+ elif _eapi_is_deprecated(eapi) and not installed:
+ return ["EAPI %s" % eapi]
+ egroups = settings.configdict["backupenv"].get(
+ "ACCEPT_KEYWORDS", "").split()
+ pgroups = settings["ACCEPT_KEYWORDS"].split()
+ myarch = settings["ARCH"]
+ if pgroups and myarch not in pgroups:
+ """For operating systems other than Linux, ARCH is not necessarily a
+ valid keyword."""
+ myarch = pgroups[0].lstrip("~")
+
+ cp = cpv_getkey(mycpv)
+ pkgdict = settings.pkeywordsdict.get(cp)
+ matches = False
+ if pkgdict:
+ cpv_slot_list = ["%s:%s" % (mycpv, metadata["SLOT"])]
+ for atom, pkgkeywords in pkgdict.items():
+ if match_from_list(atom, cpv_slot_list):
+ matches = True
+ pgroups.extend(pkgkeywords)
+ if matches or egroups:
+ pgroups.extend(egroups)
+ inc_pgroups = set()
+ for x in pgroups:
+ if x.startswith("-"):
+ if x == "-*":
+ inc_pgroups.clear()
+ else:
+ inc_pgroups.discard(x[1:])
+ else:
+ inc_pgroups.add(x)
+ pgroups = inc_pgroups
+ del inc_pgroups
+
+ kmask = "missing"
+
+ if '**' in pgroups:
+ kmask = None
+ else:
+ for keyword in pgroups:
+ if keyword in mygroups:
+ kmask = None
+ break
+
+ if kmask:
+ for gp in mygroups:
+ if gp=="*":
+ kmask=None
+ break
+ elif gp=="-"+myarch and myarch in pgroups:
+ kmask="-"+myarch
+ break
+ elif gp=="~"+myarch and myarch in pgroups:
+ kmask="~"+myarch
+ break
+
+ try:
+ missing_licenses = settings._getMissingLicenses(mycpv, metadata)
+ if missing_licenses:
+ allowed_tokens = set(["||", "(", ")"])
+ allowed_tokens.update(missing_licenses)
+ license_split = licenses.split()
+ license_split = [x for x in license_split \
+ if x in allowed_tokens]
+ msg = license_split[:]
+ msg.append("license(s)")
+ rValue.append(" ".join(msg))
+ except portage.exception.InvalidDependString as e:
+ rValue.append("LICENSE: "+str(e))
+
+ try:
+ missing_properties = settings._getMissingProperties(mycpv, metadata)
+ if missing_properties:
+ allowed_tokens = set(["||", "(", ")"])
+ allowed_tokens.update(missing_properties)
+ properties_split = properties.split()
+ properties_split = [x for x in properties_split \
+ if x in allowed_tokens]
+ msg = properties_split[:]
+ msg.append("properties")
+ rValue.append(" ".join(msg))
+ except portage.exception.InvalidDependString as e:
+ rValue.append("PROPERTIES: "+str(e))
+
+ # Only show KEYWORDS masks for installed packages
+ # if they're not masked for any other reason.
+ if kmask and (not installed or not rValue):
+ rValue.append(kmask+" keyword")
+
+ return rValue
Copied: main/branches/prefix/pym/portage/util/movefile.py (from rev 15465, main/trunk/pym/portage/util/movefile.py)
===================================================================
--- main/branches/prefix/pym/portage/util/movefile.py (rev 0)
+++ main/branches/prefix/pym/portage/util/movefile.py 2010-02-27 19:32:48 UTC (rev 15483)
@@ -0,0 +1,234 @@
+# Copyright 2010 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+# $Id$
+
+__all__ = ['movefile']
+
+import errno
+import os as _os
+import shutil as _shutil
+import stat
+
+import portage
+from portage import bsd_chflags, _encodings, _os_overrides, _selinux, \
+ _unicode_decode, _unicode_func_wrapper, _unicode_module_wrapper
+from portage.const import MOVE_BINARY
+from portage.localization import _
+from portage.process import spawn
+from portage.util import writemsg
+
+def movefile(src, dest, newmtime=None, sstat=None, mysettings=None,
+ hardlink_candidates=None, encoding=_encodings['fs']):
+ """moves a file from src to dest, preserving all permissions and attributes; mtime will
+ be preserved even when moving across filesystems. Returns true on success and false on
+ failure. Move is atomic."""
+ #print "movefile("+str(src)+","+str(dest)+","+str(newmtime)+","+str(sstat)+")"
+
+ if mysettings is None:
+ mysettings = portage.settings
+
+ selinux_enabled = mysettings.selinux_enabled()
+ if selinux_enabled:
+ selinux = _unicode_module_wrapper(_selinux, encoding=encoding)
+
+ lchown = _unicode_func_wrapper(portage.data.lchown, encoding=encoding)
+ os = _unicode_module_wrapper(_os,
+ encoding=encoding, overrides=_os_overrides)
+ shutil = _unicode_module_wrapper(_shutil, encoding=encoding)
+
+ try:
+ if not sstat:
+ sstat=os.lstat(src)
+
+ except SystemExit as e:
+ raise
+ except Exception as e:
+ print(_("!!! Stating source file failed... movefile()"))
+ print("!!!",e)
+ return None
+
+ destexists=1
+ try:
+ dstat=os.lstat(dest)
+ except (OSError, IOError):
+ dstat=os.lstat(os.path.dirname(dest))
+ destexists=0
+
+ if bsd_chflags:
+ if destexists and dstat.st_flags != 0:
+ bsd_chflags.lchflags(dest, 0)
+ # Use normal stat/chflags for the parent since we want to
+ # follow any symlinks to the real parent directory.
+ pflags = os.stat(os.path.dirname(dest)).st_flags
+ if pflags != 0:
+ bsd_chflags.chflags(os.path.dirname(dest), 0)
+
+ if destexists:
+ if stat.S_ISLNK(dstat[stat.ST_MODE]):
+ try:
+ os.unlink(dest)
+ destexists=0
+ except SystemExit as e:
+ raise
+ except Exception as e:
+ pass
+
+ if stat.S_ISLNK(sstat[stat.ST_MODE]):
+ try:
+ target=os.readlink(src)
+ if mysettings and mysettings["D"]:
+ if target.find(mysettings["D"])==0:
+ target=target[len(mysettings["D"]):]
+ if destexists and not stat.S_ISDIR(dstat[stat.ST_MODE]):
+ os.unlink(dest)
+ if selinux_enabled:
+ selinux.symlink(target, dest, src)
+ else:
+ os.symlink(target,dest)
+ lchown(dest,sstat[stat.ST_UID],sstat[stat.ST_GID])
+ # utime() only works on the target of a symlink, so it's not
+ # possible to perserve mtime on symlinks.
+ return os.lstat(dest)[stat.ST_MTIME]
+ except SystemExit as e:
+ raise
+ except Exception as e:
+ print(_("!!! failed to properly create symlink:"))
+ print("!!!",dest,"->",target)
+ print("!!!",e)
+ return None
+
+ hardlinked = False
+ # Since identical files might be merged to multiple filesystems,
+ # so os.link() calls might fail for some paths, so try them all.
+ # For atomic replacement, first create the link as a temp file
+ # and them use os.rename() to replace the destination.
+ if hardlink_candidates:
+ head, tail = os.path.split(dest)
+ hardlink_tmp = os.path.join(head, ".%s._portage_merge_.%s" % \
+ (tail, os.getpid()))
+ try:
+ os.unlink(hardlink_tmp)
+ except OSError as e:
+ if e.errno != errno.ENOENT:
+ writemsg(_("!!! Failed to remove hardlink temp file: %s\n") % \
+ (hardlink_tmp,), noiselevel=-1)
+ writemsg("!!! %s\n" % (e,), noiselevel=-1)
+ return None
+ del e
+ for hardlink_src in hardlink_candidates:
+ try:
+ os.link(hardlink_src, hardlink_tmp)
+ except OSError:
+ continue
+ else:
+ try:
+ os.rename(hardlink_tmp, dest)
+ except OSError as e:
+ writemsg(_("!!! Failed to rename %s to %s\n") % \
+ (hardlink_tmp, dest), noiselevel=-1)
+ writemsg("!!! %s\n" % (e,), noiselevel=-1)
+ return None
+ hardlinked = True
+ break
+
+ renamefailed=1
+ if hardlinked:
+ renamefailed = False
+ if not hardlinked and (selinux_enabled or sstat.st_dev == dstat.st_dev):
+ try:
+ if selinux_enabled:
+ selinux.rename(src, dest)
+ else:
+ os.rename(src,dest)
+ renamefailed=0
+ except OSError as e:
+ if e.errno != errno.EXDEV:
+ # Some random error.
+ print(_("!!! Failed to move %(src)s to %(dest)s") % {"src": src, "dest": dest})
+ print("!!!",e)
+ return None
+ # Invalid cross-device-link 'bind' mounted or actually Cross-Device
+ if renamefailed:
+ didcopy=0
+ if stat.S_ISREG(sstat[stat.ST_MODE]):
+ try: # For safety copy then move it over.
+ if selinux_enabled:
+ selinux.copyfile(src, dest + "#new")
+ selinux.rename(dest + "#new", dest)
+ else:
+ shutil.copyfile(src,dest+"#new")
+ os.rename(dest+"#new",dest)
+ didcopy=1
+ except SystemExit as e:
+ raise
+ except Exception as e:
+ print(_('!!! copy %(src)s -> %(dest)s failed.') % {"src": src, "dest": dest})
+ print("!!!",e)
+ return None
+ else:
+ #we don't yet handle special, so we need to fall back to /bin/mv
+ a = spawn([MOVE_BINARY, '-f', src, dest], env=os.environ)
+ if a != os.EX_OK:
+ writemsg(_("!!! Failed to move special file:\n"), noiselevel=-1)
+ writemsg(_("!!! '%(src)s' to '%(dest)s'\n") % \
+ {"src": _unicode_decode(src, encoding=encoding),
+ "dest": _unicode_decode(dest, encoding=encoding)}, noiselevel=-1)
+ writemsg("!!! %s\n" % a, noiselevel=-1)
+ return None # failure
+ try:
+ if didcopy:
+ if stat.S_ISLNK(sstat[stat.ST_MODE]):
+ lchown(dest,sstat[stat.ST_UID],sstat[stat.ST_GID])
+ else:
+ os.chown(dest,sstat[stat.ST_UID],sstat[stat.ST_GID])
+ os.chmod(dest, stat.S_IMODE(sstat[stat.ST_MODE])) # Sticky is reset on chown
+ os.unlink(src)
+ except SystemExit as e:
+ raise
+ except Exception as e:
+ print(_("!!! Failed to chown/chmod/unlink in movefile()"))
+ print("!!!",dest)
+ print("!!!",e)
+ return None
+
+ # Always use stat_obj[stat.ST_MTIME] for the integral timestamp which
+ # is returned, since the stat_obj.st_mtime float attribute rounds *up*
+ # if the nanosecond part of the timestamp is 999999881 ns or greater.
+ try:
+ if hardlinked:
+ newmtime = os.stat(dest)[stat.ST_MTIME]
+ else:
+ # Note: It is not possible to preserve nanosecond precision
+ # (supported in POSIX.1-2008 via utimensat) with the IEEE 754
+ # double precision float which only has a 53 bit significand.
+ if newmtime is not None:
+ os.utime(dest, (newmtime, newmtime))
+ else:
+ newmtime = sstat[stat.ST_MTIME]
+ if renamefailed:
+ # If rename succeeded then timestamps are automatically
+ # preserved with complete precision because the source
+ # and destination inode are the same. Otherwise, round
+ # down to the nearest whole second since python's float
+ # st_mtime cannot be used to preserve the st_mtim.tv_nsec
+ # field with complete precision. Note that we have to use
+ # stat_obj[stat.ST_MTIME] here because the float
+ # stat_obj.st_mtime rounds *up* sometimes.
+ os.utime(dest, (newmtime, newmtime))
+ except OSError:
+ # The utime can fail here with EPERM even though the move succeeded.
+ # Instead of failing, use stat to return the mtime if possible.
+ try:
+ newmtime = os.stat(dest)[stat.ST_MTIME]
+ except OSError as e:
+ writemsg(_("!!! Failed to stat in movefile()\n"), noiselevel=-1)
+ writemsg("!!! %s\n" % dest, noiselevel=-1)
+ writemsg("!!! %s\n" % str(e), noiselevel=-1)
+ return None
+
+ if bsd_chflags:
+ # Restore the flags we saved before moving
+ if pflags:
+ bsd_chflags.chflags(os.path.dirname(dest), pflags)
+
+ return newmtime
^ permalink raw reply [relevance 99%]
Results 1-1 of 1 | reverse | options above
-- pct% links below jump to the message on this page, permalinks otherwise --
2010-02-27 19:32 99% [gentoo-commits] portage r15483 - in main/branches/prefix/pym/portage: . dbapi package/ebuild util Fabian Groffen (grobian)
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox