onProgress(maxval, 0)
pkgindex = self._pkgindex
missing = []
+ metadata = {}
+ for d in pkgindex.packages:
+ metadata[d["CPV"]] = d
for i, cpv in enumerate(cpv_all):
- d = pkgindex.packages.get(cpv)
+ d = metadata.get(cpv)
if not d or "MD5" not in d:
missing.append(cpv)
if onProgress:
onProgress(maxval, i+1)
errors = ["'%s' is not in Packages" % cpv for cpv in missing]
- stale = set(pkgindex.packages).difference(cpv_all)
+ stale = set(metadata).difference(cpv_all)
for cpv in stale:
errors.append("'%s' is not in the repository" % cpv)
return errors
onProgress(maxval, 0)
pkgindex = self._pkgindex
missing = []
+ metadata = {}
+ for d in pkgindex.packages:
+ metadata[d["CPV"]] = d
for i, cpv in enumerate(cpv_all):
- d = pkgindex.packages.get(cpv)
+ d = metadata.get(cpv)
if not d or "MD5" not in d:
bintree.inject(cpv)
if onProgress:
onProgress(maxval, i+1)
- stale = set(pkgindex.packages).difference(cpv_all)
+ stale = set(metadata).difference(cpv_all)
if stale:
from portage import locks
pkgindex_lock = locks.lockfile(
del bintree
portage.db[self._bintree.root]["bintree"] = self._bintree
self._bintree._populate()
- for cpv in set(self._pkgindex.packages).difference(
+ for cpv in set(metadata).difference(
self._bintree.dbapi.cpv_all()):
- del self._pkgindex.packages[cpv]
+ del metadata[cpv]
+ del pkgindex.packages[:]
+ pkgindex.packages.extend(metadata.itervalues())
from portage.util import atomic_ofstream
f = atomic_ofstream(self._pkgindex_file)
try:
func_start_re = re.compile(r'^[-\w]+\s*\(\)\s*$')
func_end_re = re.compile(r'^\}$')
-var_assign_re = re.compile(r'(^|^declare\s+-\S+\s+|^export\s+)([^=\s]+)=("|\')?.*$')
+var_assign_re = re.compile(r'(^|^declare\s+-\S+\s+|^declare\s+|^export\s+)([^=\s]+)=("|\')?.*$')
close_quote_re = re.compile(r'(\\"|"|\')\s*$')
readonly_re = re.compile(r'^declare\s+-(\S*)r(\S*)\s+')
# to prevent depclean from removing them
if arg_atoms:
+ selective = "selective" in self.myparams
portdb = self.trees[pkg.root]["porttree"].dbapi
for arg, atom in arg_atoms:
all_ebuilds_masked = bool(
portdb.xmatch("match-all", atom) and
not portdb.xmatch("bestmatch-visible", atom))
- if all_ebuilds_masked:
+ if all_ebuilds_masked and not selective:
self._missing_args.append((arg, atom))
if not visible(pkgsettings, pkg.cpv, pkg.metadata,
# Kill packages that aren't explicitly merged or are required as a
# dependency of another package. World file is explicit.
+ # Global depclean or prune operations are not very safe when there are
+ # missing dependencies since it's unknown how badly incomplete
+ # the dependency graph is, and we might accidentally remove packages
+ # that should have been pulled into the graph. On the other hand, it's
+ # relatively safe to ignore missing deps when only asked to remove
+ # specific packages.
+ allow_missing_deps = len(myfiles) > 0
+
msg = []
msg.append("Depclean may break link level dependencies. Thus, it is\n")
msg.append("recommended to use a tool such as " + good("`revdep-rebuild`") + " (from\n")
if "--quiet" not in myopts:
print "\b\b... done!\n"
- if unresolveable:
+ if unresolveable and not allow_missing_deps:
print "Dependencies could not be completely resolved due to"
print "the following required packages not being installed:"
print
for atom in unresolveable:
print atom, "required by", " ".join(unresolveable[atom])
- if unresolveable:
+ if unresolveable and not allow_missing_deps:
print
print "Have you forgotten to run " + good("`emerge --update --newuse --deep world`") + " prior to"
print "%s? It may be necessary to manually uninstall packages that no longer" % action
if not self._pkgindex_version_supported(pkgindex):
pkgindex = self._new_pkgindex()
header = pkgindex.header
- metadata = pkgindex.packages
+ metadata = {}
+ for d in pkgindex.packages:
+ metadata[d["CPV"]] = d
update_pkgindex = False
for mydir in dirs:
for myfile in listdir(os.path.join(self.pkgdir, mydir)):
stale = [cpv for cpv in metadata if cpv not in self._pkg_paths]
for cpv in stale:
del metadata[cpv]
- #
+ del pkgindex.packages[:]
+ pkgindex.packages.extend(metadata.itervalues())
self._update_pkgindex_header(pkgindex.header)
from portage.util import atomic_ofstream
f = atomic_ofstream(self._pkgindex_file)
finally:
f.close()
if pkgindex:
- self._remotepkgs = pkgindex.packages
+ self._remotepkgs = {}
+ for d in pkgindex.packages:
+ self._remotepkgs[d["CPV"]] = d
self._remote_has_index = True
self._remote_base_uri = pkgindex.header.get("URI", base_url)
self.remotepkgs = {}
self.dbapi.cpv_remove(cpv)
del self._pkg_paths[cpv]
return
- pkgindex.packages[cpv] = d
+ # If found, remove package(s) with duplicate path.
+ for i in xrange(len(pkgindex.packages) - 1, -1, -1):
+ d2 = pkgindex.packages[i]
+ if d2["CPV"] != cpv:
+ continue
+ if d2.get("PATH") == d.get("PATH"):
+ del pkgindex.packages[i]
+ pkgindex.packages.append(d)
self._update_pkgindex_header(pkgindex.header)
from portage.util import atomic_ofstream
f = atomic_ofstream(os.path.join(self.pkgdir, "Packages"))
@rtype: Array
@return: The array with empty elements removed
"""
-
- for x in range(len(myarr)-1, -1, -1):
- if not myarr[x]:
- del myarr[x]
- return myarr
+ return [x for x in myarr if x]
def paren_reduce(mystr,tokenize=1):
"""
return metadata[baseurl]["data"]
-def readpkgindex(pkgfile):
- d = {}
- for line in pkgfile:
- line = line.rstrip("\n")
- if not line:
- break
- line = line.split(":", 1)
- if not len(line) == 2:
- continue
- k, v = line
- if v:
- v = v[1:]
- d[k] = v
- return d
-
-def writepkgindex(pkgfile, items):
- for k, v in items:
- pkgfile.write("%s: %s\n" % (k, v))
- pkgfile.write("\n")
+def _cmp_cpv(d1, d2):
+ cpv1 = d1["CPV"]
+ cpv2 = d2["CPV"]
+ if cpv1 > cpv2:
+ return 1
+ elif cpv1 == cpv2:
+ return 0
+ else:
+ return -1
class PackageIndex(object):
self._default_pkg_data = default_pkg_data
self._inherited_keys = inherited_keys
self.header = {}
- self.packages = {}
+ self.packages = []
self.modified = True
+ def _readpkgindex(self, pkgfile):
+ d = {}
+ for line in pkgfile:
+ line = line.rstrip("\n")
+ if not line:
+ break
+ line = line.split(":", 1)
+ if not len(line) == 2:
+ continue
+ k, v = line
+ if v:
+ v = v[1:]
+ d[k] = v
+ return d
+
+ def _writepkgindex(self, pkgfile, items):
+ for k, v in items:
+ pkgfile.write("%s: %s\n" % (k, v))
+ pkgfile.write("\n")
+
def read(self, pkgfile):
self.readHeader(pkgfile)
self.readBody(pkgfile)
def readHeader(self, pkgfile):
- self.header.update(readpkgindex(pkgfile))
+ self.header.update(self._readpkgindex(pkgfile))
def readBody(self, pkgfile):
while True:
- d = readpkgindex(pkgfile)
+ d = self._readpkgindex(pkgfile)
if not d:
break
mycpv = d.get("CPV")
v = self.header.get(k)
if v is not None:
d.setdefault(k, v)
- self.packages[mycpv] = d
+ self.packages.append(d)
def write(self, pkgfile):
- cpv_all = self.packages.keys()
- cpv_all.sort()
if self.modified:
self.header["TIMESTAMP"] = str(long(time.time()))
- self.header["PACKAGES"] = str(len(cpv_all))
+ self.header["PACKAGES"] = str(len(self.packages))
keys = self.header.keys()
keys.sort()
- writepkgindex(pkgfile, [(k, self.header[k]) for k in keys])
- for cpv in cpv_all:
- metadata = self.packages[cpv].copy()
+ self._writepkgindex(pkgfile, [(k, self.header[k]) for k in keys])
+ for metadata in sorted(self.packages, _cmp_cpv):
+ metadata = metadata.copy()
+ cpv = metadata["CPV"]
if self._inherited_keys:
for k in self._inherited_keys:
v = self.header.get(k)
metadata.pop(k, None)
keys = metadata.keys()
keys.sort()
- writepkgindex(pkgfile,
+ self._writepkgindex(pkgfile,
[(k, metadata[k]) for k in keys if metadata[k]])
except IOError, e:
if "errno" not in dir(e):
raise
- if e.errno == errno.EAGAIN:
+ if e.errno in (errno.EACCES, errno.EAGAIN):
# resource temp unavailable; eg, someone beat us to the lock.
if waiting_msg is None:
if isinstance(mypath, int):
del path
path = os.path.join(self.unread_path, 'news-%s.unread' % repoid)
+ unread_lock = None
try:
unread_lock = lockfile(path)
if not os.path.exists(path):