summaryrefslogtreecommitdiffstats
path: root/pym
diff options
context:
space:
mode:
authorZac Medico <zmedico@gentoo.org>2008-07-05 07:18:31 +0000
committerZac Medico <zmedico@gentoo.org>2008-07-05 07:18:31 +0000
commitddddc6e7ff41d6c30bde682dac4e2e42e017a13f (patch)
tree1a2b10f3ec699d7bb5415d231634de0758783451 /pym
parentefead8fa199be63234d8b93e64e68797d3909aa9 (diff)
downloadportage-ddddc6e7ff41d6c30bde682dac4e2e42e017a13f.tar.gz
portage-ddddc6e7ff41d6c30bde682dac4e2e42e017a13f.tar.bz2
portage-ddddc6e7ff41d6c30bde682dac4e2e42e017a13f.zip
* Implement a new binarytree.digestCheck() method and use it to check
digests for binary packages. * Split out a AsynchronousTask base class from SubProcess. * Derive a new BinpkgVerifier class from AsynchronousTask. Even though this is not really asynchronous yet, it can fake the interface by doing everything in the start() method. svn path=/main/trunk/; revision=10935
Diffstat (limited to 'pym')
-rw-r--r--pym/_emerge/__init__.py78
-rw-r--r--pym/portage/__init__.py21
-rw-r--r--pym/portage/dbapi/bintree.py90
3 files changed, 153 insertions, 36 deletions
diff --git a/pym/_emerge/__init__.py b/pym/_emerge/__init__.py
index bfae9e20a..20629c1f9 100644
--- a/pym/_emerge/__init__.py
+++ b/pym/_emerge/__init__.py
@@ -1454,8 +1454,29 @@ class EbuildFetchPretend(SlotObject):
mydbapi=portdb, tree="porttree")
return retval
-class SubProcess(SlotObject):
- __slots__ = ("cancelled", "pid", "returncode")
+class AsynchronousTask(SlotObject):
+ __slots__ = ("cancelled", "returncode")
+
+ def start(self):
+ """
+ Start an asynchronous task and then return as soon as possible.
+ """
+ pass
+
+ def isAlive(self):
+ return self.returncode is None
+
+ def poll(self):
+ return self.returncode
+
+ def wait(self):
+ return self.returncode
+
+ def cancel(self):
+ pass
+
+class SubProcess(AsynchronousTask):
+ __slots__ = ("pid",)
def poll(self):
if self.returncode is not None:
@@ -2175,6 +2196,8 @@ class Binpkg(EbuildBuildDir):
tree = "bintree"
settings.setcpv(pkg)
debug = settings.get("PORTAGE_DEBUG") == "1"
+ verify = "strict" in settings.features and \
+ not opts.pretend
# The prefetcher has already completed or it
# could be running now. If it's running now,
@@ -2227,6 +2250,13 @@ class Binpkg(EbuildBuildDir):
if opts.fetchonly:
return os.EX_OK
+ if verify:
+ verifier = BinpkgVerifier(pkg=pkg)
+ verifier.start()
+ retval = verifier.wait()
+ if retval != os.EX_OK:
+ return retval
+
msg = " === (%s of %s) Merging Binary (%s::%s)" % \
(pkg_count.curval, pkg_count.maxval, pkg.cpv, pkg_path)
short_msg = "emerge: (%s of %s) %s Merge Binary" % \
@@ -2352,8 +2382,7 @@ class Binpkg(EbuildBuildDir):
class BinpkgFetcher(Task):
- __slots__ = ("use_locks", "pkg", "pretend",
- "pkg_path", "remote")
+ __slots__ = ("use_locks", "pkg", "pretend", "pkg_path", "remote")
def __init__(self, **kwargs):
Task.__init__(self, **kwargs)
@@ -2498,6 +2527,47 @@ class BinpkgFetcherAsync(SpawnProcess):
self._lock_obj = None
self.locked = False
+class BinpkgVerifier(AsynchronousTask):
+ __slots__ = ("pkg",)
+
+ def start(self):
+ """
+ Note: Unlike a normal AsynchronousTask.start() method,
+ this one does all work is synchronously. The returncode
+ attribute will be set before it returns.
+ """
+
+ pkg = self.pkg
+ root_config = pkg.root_config
+ bintree = root_config.trees["bintree"]
+ rval = os.EX_OK
+ try:
+ bintree.digestCheck(pkg)
+ except portage.exception.FileNotFound:
+ writemsg("!!! Fetching Binary failed " + \
+ "for '%s'\n" % pkg.cpv, noiselevel=-1)
+ rval = 1
+ except portage.exception.DigestException, e:
+ writemsg("\n!!! Digest verification failed:\n",
+ noiselevel=-1)
+ writemsg("!!! %s\n" % e.value[0],
+ noiselevel=-1)
+ writemsg("!!! Reason: %s\n" % e.value[1],
+ noiselevel=-1)
+ writemsg("!!! Got: %s\n" % e.value[2],
+ noiselevel=-1)
+ writemsg("!!! Expected: %s\n" % e.value[3],
+ noiselevel=-1)
+ rval = 1
+
+ self.returncode = rval
+
+ def cancel(self):
+ self.cancelled = True
+
+ def poll(self):
+ return self.returncode
+
class BinpkgExtractorAsync(SpawnProcess):
__slots__ = ("image_dir", "pkg", "pkg_path")
diff --git a/pym/portage/__init__.py b/pym/portage/__init__.py
index 6aa4d2664..abba1f39e 100644
--- a/pym/portage/__init__.py
+++ b/pym/portage/__init__.py
@@ -3143,24 +3143,25 @@ def _checksum_failure_temp_file(distdir, basename):
os.rename(filename, temp_filename)
return temp_filename
-def _check_digests(filename, digests):
+def _check_digests(filename, digests, show_errors=1):
"""
Check digests and display a message if an error occurs.
@return True if all digests match, False otherwise.
"""
verified_ok, reason = portage.checksum.verify_all(filename, digests)
if not verified_ok:
- writemsg("!!! Previously fetched" + \
- " file: '%s'\n" % filename, noiselevel=-1)
- writemsg("!!! Reason: %s\n" % reason[0],
- noiselevel=-1)
- writemsg(("!!! Got: %s\n" + \
- "!!! Expected: %s\n") % \
- (reason[1], reason[2]), noiselevel=-1)
+ if show_errors:
+ writemsg("!!! Previously fetched" + \
+ " file: '%s'\n" % filename, noiselevel=-1)
+ writemsg("!!! Reason: %s\n" % reason[0],
+ noiselevel=-1)
+ writemsg(("!!! Got: %s\n" + \
+ "!!! Expected: %s\n") % \
+ (reason[1], reason[2]), noiselevel=-1)
return False
return True
-def _check_distfile(filename, digests, eout):
+def _check_distfile(filename, digests, eout, show_errors=1):
"""
@return a tuple of (match, stat_obj) where match is True if filename
matches all given digests (if any) and stat_obj is a stat result, or
@@ -3183,7 +3184,7 @@ def _check_distfile(filename, digests, eout):
eout.ebegin("%s %s ;-)" % (os.path.basename(filename), "size"))
eout.eend(0)
else:
- if _check_digests(filename, digests):
+ if _check_digests(filename, digests, show_errors=show_errors):
eout.ebegin("%s %s ;-)" % (os.path.basename(filename),
" ".join(sorted(digests))))
eout.eend(0)
diff --git a/pym/portage/dbapi/bintree.py b/pym/portage/dbapi/bintree.py
index 22f91ceef..6de9b5d87 100644
--- a/pym/portage/dbapi/bintree.py
+++ b/pym/portage/dbapi/bintree.py
@@ -7,12 +7,12 @@ from portage.dep import isvalidatom, isjustname, dep_getkey, match_from_list
from portage.dbapi.virtual import fakedbapi
from portage.exception import InvalidPackageName, InvalidAtom, \
PermissionDenied, PortageException
-from portage.output import green
+from portage.output import green, EOutput
from portage.util import ensure_dirs, normalize_path, writemsg, writemsg_stdout
from portage.versions import best, catpkgsplit, catsplit
from portage.update import update_dbentries
-from portage import dep_expand, listdir, _movefile
+from portage import dep_expand, listdir, _check_distfile, _movefile
import portage.xpak, portage.getbinpkg
@@ -991,26 +991,6 @@ class binarytree(object):
if not fcmd:
fcmd = self.settings.get(fcmd_prefix)
success = portage.getbinpkg.file_get(url, mydest, fcmd=fcmd)
- if success and "strict" in self.settings.features:
- metadata = self._remotepkgs[pkgname]
- digests = {}
- from portage.checksum import hashfunc_map, verify_all
- for k in hashfunc_map:
- v = metadata.get(k)
- if not v:
- continue
- digests[k] = v
- if "SIZE" in metadata:
- try:
- digests["size"] = long(self._remotepkgs[pkgname]["SIZE"])
- except ValueError:
- writemsg("!!! Malformed SIZE attribute in remote " + \
- "metadata for '%s'\n" % pkgname)
- if digests:
- ok, reason = verify_all(tbz2_path, digests)
- if not ok:
- raise portage.exception.DigestException(
- tuple([tbz2_path]+list(reason)))
if not success:
try:
os.unlink(self.getname(pkgname))
@@ -1019,6 +999,72 @@ class binarytree(object):
raise portage.exception.FileNotFound(mydest)
self.inject(pkgname)
+ def _load_pkgindex(self):
+ pkgindex = self._new_pkgindex()
+ try:
+ f = open(self._pkgindex_file)
+ except EnvironmentError:
+ pass
+ else:
+ try:
+ pkgindex.read(f)
+ finally:
+ f.close()
+ return pkgindex
+
+ def digestCheck(self, pkg):
+ """
+ Verify digests for the given package and raise DigestException
+ if verification fails.
+ @rtype: bool
+ @returns: True if digests could be located, False otherwise.
+ """
+ cpv = pkg
+ if not isinstance(cpv, basestring):
+ cpv = pkg.cpv
+ pkg = None
+
+ pkg_path = self.getname(cpv)
+ metadata = None
+ if self._remotepkgs is None or cpv not in self._remotepkgs:
+ for d in self._load_pkgindex().packages:
+ if d["CPV"] == cpv:
+ metadata = d
+ break
+ else:
+ metadata = self._remotepkgs[cpv]
+ if metadata is None:
+ return False
+
+ digests = {}
+ from portage.checksum import hashfunc_map, verify_all
+ for k in hashfunc_map:
+ v = metadata.get(k)
+ if not v:
+ continue
+ digests[k] = v
+
+ if "SIZE" in metadata:
+ try:
+ digests["size"] = int(metadata["SIZE"])
+ except ValueError:
+ writemsg("!!! Malformed SIZE attribute in remote " + \
+ "metadata for '%s'\n" % cpv)
+
+ if not digests:
+ return False
+
+ eout = EOutput()
+ eout.quiet = self.settings.get("PORTAGE_QUIET") == "1"
+ ok, st = _check_distfile(pkg_path, digests, eout, show_errors=0)
+ if not ok:
+ ok, reason = verify_all(pkg_path, digests)
+ if not ok:
+ raise portage.exception.DigestException(
+ (pkg_path,) + tuple(reason))
+
+ return True
+
def getslot(self, mycatpkg):
"Get a slot for a catpkg; assume it exists."
myslot = ""