76ae5bf750df8a585a153e3840eaacd9fd7e5233
[portage.git] / pym / _emerge / EbuildFetcher.py
1 # Copyright 1999-2009 Gentoo Foundation
2 # Distributed under the terms of the GNU General Public License v2
3 # $Id$
4
5 from _emerge.SpawnProcess import SpawnProcess
6 from _emerge.EbuildBuildDir import EbuildBuildDir
7 import sys
8 import portage
9 from portage import os
10 from portage import _encodings
11 from portage import _unicode_encode
12 import codecs
13 from portage.elog.messages import eerror
14
15 class EbuildFetcher(SpawnProcess):
16
17         __slots__ = ("config_pool", "fetchonly", "fetchall", "pkg", "prefetch") + \
18                 ("_build_dir",)
19
20         def _start(self):
21
22                 root_config = self.pkg.root_config
23                 portdb = root_config.trees["porttree"].dbapi
24                 ebuild_path = portdb.findname(self.pkg.cpv)
25                 settings = self.config_pool.allocate()
26                 settings.setcpv(self.pkg)
27
28                 # In prefetch mode, logging goes to emerge-fetch.log and the builddir
29                 # should not be touched since otherwise it could interfere with
30                 # another instance of the same cpv concurrently being built for a
31                 # different $ROOT (currently, builds only cooperate with prefetchers
32                 # that are spawned for the same $ROOT).
33                 if not self.prefetch:
34                         self._build_dir = EbuildBuildDir(pkg=self.pkg, settings=settings)
35                         self._build_dir.lock()
36                         self._build_dir.clean_log()
37                         portage.prepare_build_dirs(self.pkg.root, self._build_dir.settings, 0)
38                         if self.logfile is None:
39                                 self.logfile = settings.get("PORTAGE_LOG_FILE")
40
41                 phase = "fetch"
42                 if self.fetchall:
43                         phase = "fetchall"
44
45                 # If any incremental variables have been overridden
46                 # via the environment, those values need to be passed
47                 # along here so that they are correctly considered by
48                 # the config instance in the subproccess.
49                 fetch_env = os.environ.copy()
50
51                 nocolor = settings.get("NOCOLOR")
52                 if nocolor is not None:
53                         fetch_env["NOCOLOR"] = nocolor
54
55                 fetch_env["PORTAGE_NICENESS"] = "0"
56                 if self.prefetch:
57                         fetch_env["PORTAGE_PARALLEL_FETCHONLY"] = "1"
58
59                 ebuild_binary = os.path.join(
60                         settings["PORTAGE_BIN_PATH"], "ebuild")
61
62                 fetch_args = [ebuild_binary, ebuild_path, phase]
63                 debug = settings.get("PORTAGE_DEBUG") == "1"
64                 if debug:
65                         fetch_args.append("--debug")
66
67                 self.args = fetch_args
68                 self.env = fetch_env
69                 SpawnProcess._start(self)
70
71         def _pipe(self, fd_pipes):
72                 """When appropriate, use a pty so that fetcher progress bars,
73                 like wget has, will work properly."""
74                 if self.background or not sys.stdout.isatty():
75                         # When the output only goes to a log file,
76                         # there's no point in creating a pty.
77                         return os.pipe()
78                 stdout_pipe = fd_pipes.get(1)
79                 got_pty, master_fd, slave_fd = \
80                         portage._create_pty_or_pipe(copy_term_size=stdout_pipe)
81                 return (master_fd, slave_fd)
82
83         def _set_returncode(self, wait_retval):
84                 SpawnProcess._set_returncode(self, wait_retval)
85                 # Collect elog messages that might have been
86                 # created by the pkg_nofetch phase.
87                 if self._build_dir is not None:
88                         # Skip elog messages for prefetch, in order to avoid duplicates.
89                         if not self.prefetch and self.returncode != os.EX_OK:
90                                 elog_out = None
91                                 if self.logfile is not None:
92                                         if self.background:
93                                                 elog_out = codecs.open(_unicode_encode(self.logfile,
94                                                         encoding=_encodings['fs'], errors='strict'),
95                                                         mode='a', encoding=_encodings['content'], errors='replace')
96                                 msg = "Fetch failed for '%s'" % (self.pkg.cpv,)
97                                 if self.logfile is not None:
98                                         msg += ", Log file:"
99                                 eerror(msg, phase="unpack", key=self.pkg.cpv, out=elog_out)
100                                 if self.logfile is not None:
101                                         eerror(" '%s'" % (self.logfile,),
102                                                 phase="unpack", key=self.pkg.cpv, out=elog_out)
103                                 if elog_out is not None:
104                                         elog_out.close()
105                         if not self.prefetch:
106                                 portage.elog.elog_process(self.pkg.cpv, self._build_dir.settings)
107                         features = self._build_dir.settings.features
108                         if self.returncode == os.EX_OK:
109                                 self._build_dir.clean_log()
110                         self._build_dir.unlock()
111                         self.config_pool.deallocate(self._build_dir.settings)
112                         self._build_dir = None
113