Optimize parallel-fetch for the case where all files are already fetched and
authorZac Medico <zmedico@gentoo.org>
Tue, 2 Mar 2010 20:05:30 +0000 (20:05 -0000)
committerZac Medico <zmedico@gentoo.org>
Tue, 2 Mar 2010 20:05:30 +0000 (20:05 -0000)
have the correct size. In this case we can avoid the expense of spawning
ebuild(1). (trunk r15312)

svn path=/main/branches/2.1.7/; revision=15547

pym/_emerge/EbuildFetcher.py

index b8931df1586fb3a30c6ba2c61c4d67dec7fe2552..bc443dda200aa33822f1e83b27f67328d6f94ec4 100644 (file)
@@ -26,6 +26,12 @@ class EbuildFetcher(SpawnProcess):
                        raise AssertionError("ebuild not found for '%s'" % self.pkg.cpv)
                settings = self.config_pool.allocate()
                settings.setcpv(self.pkg)
+               if self.prefetch and \
+                       self._prefetch_size_ok(portdb, settings, ebuild_path):
+                       self.config_pool.deallocate(settings)
+                       self.returncode = os.EX_OK
+                       self.wait()
+                       return
 
                # In prefetch mode, logging goes to emerge-fetch.log and the builddir
                # should not be touched since otherwise it could interfere with
@@ -78,6 +84,52 @@ class EbuildFetcher(SpawnProcess):
                        self.config_pool.deallocate(settings)
                SpawnProcess._start(self)
 
+       def _prefetch_size_ok(self, portdb, settings, ebuild_path):
+               pkgdir = os.path.dirname(ebuild_path)
+               mytree = os.path.dirname(os.path.dirname(pkgdir))
+               distdir = settings["DISTDIR"]
+               use = None
+               if not self.fetchall:
+                       use = frozenset(settings["PORTAGE_USE"].split())
+
+               try:
+                       uri_map = portdb.getFetchMap(self.pkg.cpv,
+                               useflags=use, mytree=mytree)
+               except portage.exception.InvalidDependString as e:
+                       return False
+
+               sizes = {}
+               for filename in uri_map:
+                       try:
+                               st = os.lstat(os.path.join(distdir, filename))
+                       except OSError:
+                               return False
+                       if st.st_size == 0:
+                               return False
+                       sizes[filename] = st.st_size
+
+               digests = portage.Manifest(pkgdir, distdir).getTypeDigests("DIST")
+               for filename, actual_size in sizes.items():
+                       size = digests.get(filename, {}).get('size')
+                       if size is None:
+                               continue
+                       if size != actual_size:
+                               return False
+
+               # All files are present and sizes are ok. In this case the normal
+               # fetch code will be skipped, so we need to generate equivalent
+               # output here.
+               if self.logfile is not None:
+                       f = codecs.open(_unicode_encode(self.logfile,
+                               encoding=_encodings['fs'], errors='strict'),
+                               mode='a', encoding=_encodings['content'], errors='replace')
+                       for filename in uri_map:
+                               f.write((' * %s size ;-) ...' % \
+                                       filename).ljust(73) + '[ ok ]\n')
+                       f.close()
+
+               return True
+
        def _pipe(self, fd_pipes):
                """When appropriate, use a pty so that fetcher progress bars,
                like wget has, will work properly."""