portage.prepare_build_dirs(self.pkg.root, self.settings, 1)
fetcher = EbuildFetcher(config_pool=self.config_pool,
+ ebuild_path=self._ebuild_path,
fetchall=self.opts.fetch_all_uri,
fetchonly=self.opts.fetchonly,
background=self.background,
logfile=self.settings.get('PORTAGE_LOG_FILE'),
pkg=self.pkg, scheduler=self.scheduler)
+ try:
+ already_fetched = fetcher.already_fetched(self.settings)
+ except portage.exception.InvalidDependString as e:
+ msg_lines = []
+ msg = "Fetch failed for '%s' due to invalid SRC_URI: %s" % \
+ (self.pkg.cpv, e)
+ msg_lines.append(msg)
+ fetcher._eerror(msg_lines)
+ portage.elog.elog_process(self.pkg.cpv, self.settings)
+ self.returncode = 1
+ self._current_task = None
+ self._unlock_builddir()
+ self.wait()
+ return
+
+ if already_fetched:
+ # This case is optimized to skip the fetch queue.
+ fetcher = None
+ self._fetch_exit(fetcher)
+ return
+
# Allow the Scheduler's fetch queue to control the
# number of concurrent fetchers.
fetcher.addExitListener(self._fetch_exit)
def _fetch_exit(self, fetcher):
- if self._default_exit(fetcher) != os.EX_OK:
+ if fetcher is not None and \
+ self._default_exit(fetcher) != os.EX_OK:
self._fetch_failed()
return
from portage import _unicode_encode
from portage import _unicode_decode
from portage.elog.messages import eerror
-from portage.package.ebuild.fetch import fetch
+from portage.package.ebuild.fetch import _check_distfile, fetch
from portage.util._pty import _create_pty_or_pipe
class EbuildFetcher(SpawnProcess):
- __slots__ = ("config_pool", "fetchonly", "fetchall", "pkg", "prefetch") + \
+ __slots__ = ("config_pool", "ebuild_path", "fetchonly", "fetchall",
+ "pkg", "prefetch") + \
("_digests", "_settings", "_uri_map")
+ def already_fetched(self, settings):
+ """
+ Returns True if all files are already exist locally and have correct
+ digests, otherwise return False. When returning True, appropriate
+ digest checking messages are produced for display and/or logging.
+ When returning False, no messages are produced, since we assume
+ that a fetcher process will later be executed in order to produce
+ such messages. This will raise InvalidDependString if SRC_URI is
+ invalid.
+ """
+
+ uri_map = self._get_uri_map()
+ if not uri_map:
+ return True
+
+ digests = self._get_digests()
+ distdir = settings["DISTDIR"]
+ allow_missing = "allow-missing-manifests" in settings.features
+
+ for filename in uri_map:
+ # Use stat rather than lstat since fetch() creates
+ # symlinks when PORTAGE_RO_DISTDIRS is used.
+ try:
+ st = os.stat(os.path.join(distdir, filename))
+ except OSError:
+ return False
+ if st.st_size == 0:
+ return False
+ expected_size = digests.get(filename, {}).get('size')
+ if expected_size is None:
+ continue
+ if st.st_size != expected_size:
+ return False
+
+ stdout_orig = sys.stdout
+ stderr_orig = sys.stderr
+ global_havecolor = portage.output.havecolor
+ out = io.StringIO()
+ eout = portage.output.EOutput()
+ eout.quiet = settings.get("PORTAGE_QUIET") == "1"
+ success = True
+ try:
+ sys.stdout = out
+ sys.stderr = out
+ if portage.output.havecolor:
+ portage.output.havecolor = not self.background
+
+ for filename in uri_map:
+ mydigests = digests.get(filename)
+ if mydigests is None:
+ if not allow_missing:
+ success = False
+ break
+ continue
+ ok, st = _check_distfile(os.path.join(distdir, filename),
+ mydigests, eout, show_errors=False)
+ if not ok:
+ success = False
+ break
+ finally:
+ sys.stdout = stdout_orig
+ sys.stderr = stderr_orig
+ portage.output.havecolor = global_havecolor
+
+ if success:
+ # When returning uncessessfully, no messages are produced, since
+ # we assume that a fetcher process will later be executed in order
+ # to produce such messages.
+ msg = out.getvalue()
+ if msg:
+ self.scheduler.output(msg, log_path=self.logfile)
+
+ return success
+
def _start(self):
root_config = self.pkg.root_config
portdb = root_config.trees["porttree"].dbapi
- ebuild_path = portdb.findname(self.pkg.cpv, myrepo=self.pkg.repo)
- if ebuild_path is None:
- raise AssertionError("ebuild not found for '%s'" % self.pkg.cpv)
+ ebuild_path = self._get_ebuild_path()
try:
- uri_map = self._get_uri_map(portdb, ebuild_path)
+ uri_map = self._get_uri_map()
except portage.exception.InvalidDependString as e:
msg_lines = []
msg = "Fetch failed for '%s' due to invalid SRC_URI: %s" % \
self.wait()
return
- self._digests = portage.Manifest(
- os.path.dirname(ebuild_path), None).getTypeDigests("DIST")
-
settings = self.config_pool.allocate()
settings.setcpv(self.pkg)
portage.doebuild_environment(ebuild_path, 'fetch',
settings["NOCOLOR"] = nocolor
self._settings = settings
- self._uri_map = uri_map
SpawnProcess._start(self)
# Free settings now since it's no longer needed in
allow_missing = 'allow-missing-manifests' in self._settings.features
try:
if fetch(self._uri_map, self._settings, fetchonly=self.fetchonly,
- digests=copy.deepcopy(self._digests),
+ digests=copy.deepcopy(self._get_digests()),
allow_missing_digests=allow_missing):
rval = os.EX_OK
except SystemExit:
# finally blocks from earlier in the call stack. See bug #345289.
os._exit(rval)
- def _get_uri_map(self, portdb, ebuild_path):
+ def _get_ebuild_path(self):
+ if self.ebuild_path is not None:
+ return self.ebuild_path
+ portdb = self.pkg.root_config.trees["porttree"].dbapi
+ self.ebuild_path = portdb.findname(self.pkg.cpv, myrepo=self.pkg.repo)
+ if self.ebuild_path is None:
+ raise AssertionError("ebuild not found for '%s'" % self.pkg.cpv)
+ return self.ebuild_path
+
+ def _get_digests(self):
+ if self._digests is not None:
+ return self._digests
+ self._digests = portage.Manifest(os.path.dirname(
+ self._get_ebuild_path()), None).getTypeDigests("DIST")
+ return self._digests
+
+ def _get_uri_map(self):
"""
This can raise InvalidDependString from portdbapi.getFetchMap().
"""
- pkgdir = os.path.dirname(ebuild_path)
+ if self._uri_map is not None:
+ return self._uri_map
+ pkgdir = os.path.dirname(self._get_ebuild_path())
mytree = os.path.dirname(os.path.dirname(pkgdir))
use = None
if not self.fetchall:
use = self.pkg.use.enabled
- return portdb.getFetchMap(self.pkg.cpv, useflags=use, mytree=mytree)
+ portdb = self.pkg.root_config.trees["porttree"].dbapi
+ self._uri_map = portdb.getFetchMap(self.pkg.cpv,
+ useflags=use, mytree=mytree)
+ return self._uri_map
def _prefetch_size_ok(self, uri_map, settings, ebuild_path):
distdir = settings["DISTDIR"]
return False
sizes[filename] = st.st_size
- digests = self._digests
+ digests = self._get_digests()
for filename, actual_size in sizes.items():
size = digests.get(filename, {}).get('size')
if size is None: