1 # Copyright 1999-2011 Gentoo Foundation
2 # Distributed under the terms of the GNU General Public License v2
4 from _emerge.EbuildExecuter import EbuildExecuter
5 from _emerge.EbuildPhase import EbuildPhase
6 from _emerge.EbuildBinpkg import EbuildBinpkg
7 from _emerge.EbuildFetcher import EbuildFetcher
8 from _emerge.CompositeTask import CompositeTask
9 from _emerge.EbuildMerge import EbuildMerge
10 from _emerge.EbuildFetchonly import EbuildFetchonly
11 from _emerge.EbuildBuildDir import EbuildBuildDir
12 from _emerge.MiscFunctionsProcess import MiscFunctionsProcess
13 from portage.util import writemsg
15 from portage import os
16 from portage.output import colorize
17 from portage.package.ebuild.digestcheck import digestcheck
18 from portage.package.ebuild.doebuild import _check_temp_dir
19 from portage.package.ebuild._spawn_nofetch import spawn_nofetch
21 class EbuildBuild(CompositeTask):
23 __slots__ = ("args_set", "config_pool", "find_blockers",
24 "ldpath_mtimes", "logger", "opts", "pkg", "pkg_count",
25 "prefetcher", "settings", "world_atom") + \
26 ("_build_dir", "_buildpkg", "_ebuild_path", "_issyspkg", "_tree")
31 settings = self.settings
33 rval = _check_temp_dir(settings)
35 self.returncode = rval
36 self._current_task = None
40 root_config = pkg.root_config
43 portdb = root_config.trees[tree].dbapi
45 settings.configdict["pkg"]["EMERGE_FROM"] = "ebuild"
46 if self.opts.buildpkgonly:
47 settings.configdict["pkg"]["MERGE_TYPE"] = "buildonly"
49 settings.configdict["pkg"]["MERGE_TYPE"] = "source"
50 ebuild_path = portdb.findname(pkg.cpv, myrepo=pkg.repo)
51 if ebuild_path is None:
52 raise AssertionError("ebuild not found for '%s'" % pkg.cpv)
53 self._ebuild_path = ebuild_path
54 portage.doebuild_environment(ebuild_path, 'setup',
55 settings=self.settings, db=portdb)
57 # Check the manifest here since with --keep-going mode it's
58 # currently possible to get this far with a broken manifest.
59 if not self._check_manifest():
61 self._current_task = None
65 prefetcher = self.prefetcher
66 if prefetcher is None:
68 elif prefetcher.isAlive() and \
69 prefetcher.poll() is None:
71 waiting_msg = "Fetching files " + \
72 "in the background. " + \
73 "To view fetch progress, run `tail -f " + \
74 "/var/log/emerge-fetch.log` in another " + \
76 msg_prefix = colorize("GOOD", " * ")
77 from textwrap import wrap
78 waiting_msg = "".join("%s%s\n" % (msg_prefix, line) \
79 for line in wrap(waiting_msg, 65))
80 if not self.background:
81 writemsg(waiting_msg, noiselevel=-1)
83 self._current_task = prefetcher
84 prefetcher.addExitListener(self._prefetch_exit)
87 self._prefetch_exit(prefetcher)
89 def _check_manifest(self):
92 settings = self.settings
93 if 'strict' in settings.features:
94 settings['O'] = os.path.dirname(self._ebuild_path)
95 quiet_setting = settings.get('PORTAGE_QUIET')
96 settings['PORTAGE_QUIET'] = '1'
98 success = digestcheck([], settings, strict=True)
101 settings['PORTAGE_QUIET'] = quiet_setting
103 del settings['PORTAGE_QUIET']
107 def _prefetch_exit(self, prefetcher):
111 settings = self.settings
115 fetcher = EbuildFetchonly(
116 fetch_all=opts.fetch_all_uri,
117 pkg=pkg, pretend=opts.pretend,
119 retval = fetcher.execute()
120 self.returncode = retval
124 fetcher = EbuildFetcher(
125 config_pool=self.config_pool,
126 fetchall=self.opts.fetch_all_uri,
127 fetchonly=self.opts.fetchonly,
131 scheduler=self.scheduler)
132 self._start_task(fetcher, self._fetchonly_exit)
135 self._build_dir = EbuildBuildDir(
136 scheduler=self.scheduler, settings=settings)
137 self._build_dir.lock()
139 # Cleaning needs to happen before fetch, since the build dir
140 # is used for log handling.
141 msg = " === (%s of %s) Cleaning (%s::%s)" % \
142 (self.pkg_count.curval, self.pkg_count.maxval,
143 self.pkg.cpv, self._ebuild_path)
144 short_msg = "emerge: (%s of %s) %s Clean" % \
145 (self.pkg_count.curval, self.pkg_count.maxval, self.pkg.cpv)
146 self.logger.log(msg, short_msg=short_msg)
148 pre_clean_phase = EbuildPhase(background=self.background,
149 phase='clean', scheduler=self.scheduler, settings=self.settings)
150 self._start_task(pre_clean_phase, self._pre_clean_exit)
152 def _fetchonly_exit(self, fetcher):
153 self._final_exit(fetcher)
154 if self.returncode != os.EX_OK:
155 portdb = self.pkg.root_config.trees[self._tree].dbapi
156 spawn_nofetch(portdb, self._ebuild_path, settings=self.settings)
159 def _pre_clean_exit(self, pre_clean_phase):
160 if self._default_exit(pre_clean_phase) != os.EX_OK:
161 self._unlock_builddir()
166 portage.prepare_build_dirs(self.pkg.root, self.settings, 1)
168 fetcher = EbuildFetcher(config_pool=self.config_pool,
169 fetchall=self.opts.fetch_all_uri,
170 fetchonly=self.opts.fetchonly,
171 background=self.background,
172 logfile=self.settings.get('PORTAGE_LOG_FILE'),
173 pkg=self.pkg, scheduler=self.scheduler)
175 # Allow the Scheduler's fetch queue to control the
176 # number of concurrent fetchers.
177 fetcher.addExitListener(self._fetch_exit)
178 self._task_queued(fetcher)
179 self.scheduler.fetch.schedule(fetcher)
181 def _fetch_exit(self, fetcher):
183 if self._default_exit(fetcher) != os.EX_OK:
187 # discard successful fetch log
188 self._build_dir.clean_log()
192 pkg_count = self.pkg_count
193 scheduler = self.scheduler
194 settings = self.settings
195 features = settings.features
196 ebuild_path = self._ebuild_path
197 system_set = pkg.root_config.sets["system"]
199 #buildsyspkg: Check if we need to _force_ binary package creation
200 self._issyspkg = "buildsyspkg" in features and \
201 system_set.findAtomForPackage(pkg) and \
204 if opts.buildpkg or self._issyspkg:
206 self._buildpkg = True
208 msg = " === (%s of %s) Compiling/Packaging (%s::%s)" % \
209 (pkg_count.curval, pkg_count.maxval, pkg.cpv, ebuild_path)
210 short_msg = "emerge: (%s of %s) %s Compile" % \
211 (pkg_count.curval, pkg_count.maxval, pkg.cpv)
212 logger.log(msg, short_msg=short_msg)
215 msg = " === (%s of %s) Compiling/Merging (%s::%s)" % \
216 (pkg_count.curval, pkg_count.maxval, pkg.cpv, ebuild_path)
217 short_msg = "emerge: (%s of %s) %s Compile" % \
218 (pkg_count.curval, pkg_count.maxval, pkg.cpv)
219 logger.log(msg, short_msg=short_msg)
221 build = EbuildExecuter(background=self.background, pkg=pkg,
222 scheduler=scheduler, settings=settings)
223 self._start_task(build, self._build_exit)
225 def _fetch_failed(self):
226 # We only call the pkg_nofetch phase if either RESTRICT=fetch
227 # is set or the package has explicitly overridden the default
228 # pkg_nofetch implementation. This allows specialized messages
229 # to be displayed for problematic packages even though they do
230 # not set RESTRICT=fetch (bug #336499).
232 if 'fetch' not in self.pkg.metadata.restrict and \
233 'nofetch' not in self.pkg.metadata.defined_phases:
234 self._unlock_builddir()
238 self.returncode = None
239 nofetch_phase = EbuildPhase(background=self.background,
240 phase='nofetch', scheduler=self.scheduler, settings=self.settings)
241 self._start_task(nofetch_phase, self._nofetch_exit)
243 def _nofetch_exit(self, nofetch_phase):
244 self._final_exit(nofetch_phase)
245 self._unlock_builddir()
249 def _unlock_builddir(self):
250 portage.elog.elog_process(self.pkg.cpv, self.settings)
251 self._build_dir.unlock()
253 def _build_exit(self, build):
254 if self._default_exit(build) != os.EX_OK:
255 self._unlock_builddir()
259 buildpkg = self._buildpkg
262 self._final_exit(build)
267 msg = ">>> This is a system package, " + \
268 "let's pack a rescue tarball.\n"
269 self.scheduler.output(msg,
270 log_path=self.settings.get("PORTAGE_LOG_FILE"))
272 packager = EbuildBinpkg(background=self.background, pkg=self.pkg,
273 scheduler=self.scheduler, settings=self.settings)
275 self._start_task(packager, self._buildpkg_exit)
277 def _buildpkg_exit(self, packager):
279 Released build dir lock when there is a failure or
280 when in buildpkgonly mode. Otherwise, the lock will
281 be released when merge() is called.
284 if self._default_exit(packager) != os.EX_OK:
285 self._unlock_builddir()
289 if self.opts.buildpkgonly:
290 phase = 'success_hooks'
291 success_hooks = MiscFunctionsProcess(
292 background=self.background,
293 commands=[phase], phase=phase,
294 scheduler=self.scheduler, settings=self.settings)
295 self._start_task(success_hooks,
296 self._buildpkgonly_success_hook_exit)
299 # Continue holding the builddir lock until
300 # after the package has been installed.
301 self._current_task = None
302 self.returncode = packager.returncode
305 def _buildpkgonly_success_hook_exit(self, success_hooks):
306 self._default_exit(success_hooks)
307 self.returncode = None
308 # Need to call "clean" phase for buildpkgonly mode
309 portage.elog.elog_process(self.pkg.cpv, self.settings)
311 clean_phase = EbuildPhase(background=self.background,
312 phase=phase, scheduler=self.scheduler, settings=self.settings)
313 self._start_task(clean_phase, self._clean_exit)
315 def _clean_exit(self, clean_phase):
316 if self._final_exit(clean_phase) != os.EX_OK or \
317 self.opts.buildpkgonly:
318 self._unlock_builddir()
321 def create_install_task(self):
323 Install the package and then clean up and release locks.
324 Only call this after the build has completed successfully
325 and neither fetchonly nor buildpkgonly mode are enabled.
328 ldpath_mtimes = self.ldpath_mtimes
331 pkg_count = self.pkg_count
332 settings = self.settings
333 world_atom = self.world_atom
334 ebuild_path = self._ebuild_path
337 task = EbuildMerge(find_blockers=self.find_blockers,
338 ldpath_mtimes=ldpath_mtimes, logger=logger, pkg=pkg,
339 pkg_count=pkg_count, pkg_path=ebuild_path,
340 scheduler=self.scheduler,
341 settings=settings, tree=tree, world_atom=world_atom)
343 msg = " === (%s of %s) Merging (%s::%s)" % \
344 (pkg_count.curval, pkg_count.maxval,
345 pkg.cpv, ebuild_path)
346 short_msg = "emerge: (%s of %s) %s Merge" % \
347 (pkg_count.curval, pkg_count.maxval, pkg.cpv)
348 logger.log(msg, short_msg=short_msg)
350 task.addExitListener(self._install_exit)
353 def _install_exit(self, task):
354 self._unlock_builddir()