Package _emerge :: Module EbuildBuild
[hide private]

Source Code for Module _emerge.EbuildBuild

  1  # Copyright 1999-2013 Gentoo Foundation 
  2  # Distributed under the terms of the GNU General Public License v2 
  3   
  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 _emerge.TaskSequence import TaskSequence 
 14   
 15  from portage.util import writemsg 
 16  import portage 
 17  from portage import os 
 18  from portage.output import colorize 
 19  from portage.package.ebuild.digestcheck import digestcheck 
 20  from portage.package.ebuild.digestgen import digestgen 
 21  from portage.package.ebuild.doebuild import _check_temp_dir 
 22  from portage.package.ebuild._spawn_nofetch import spawn_nofetch 
 23   
24 -class EbuildBuild(CompositeTask):
25 26 __slots__ = ("args_set", "config_pool", "find_blockers", 27 "ldpath_mtimes", "logger", "opts", "pkg", "pkg_count", 28 "prefetcher", "settings", "world_atom") + \ 29 ("_build_dir", "_buildpkg", "_ebuild_path", "_issyspkg", "_tree") 30
31 - def _start(self):
32 33 pkg = self.pkg 34 settings = self.settings 35 36 if not self.opts.fetchonly: 37 rval = _check_temp_dir(settings) 38 if rval != os.EX_OK: 39 self.returncode = rval 40 self._current_task = None 41 self._async_wait() 42 return 43 44 root_config = pkg.root_config 45 tree = "porttree" 46 self._tree = tree 47 portdb = root_config.trees[tree].dbapi 48 settings.setcpv(pkg) 49 settings.configdict["pkg"]["EMERGE_FROM"] = "ebuild" 50 if self.opts.buildpkgonly: 51 settings.configdict["pkg"]["MERGE_TYPE"] = "buildonly" 52 else: 53 settings.configdict["pkg"]["MERGE_TYPE"] = "source" 54 ebuild_path = portdb.findname(pkg.cpv, myrepo=pkg.repo) 55 if ebuild_path is None: 56 raise AssertionError("ebuild not found for '%s'" % pkg.cpv) 57 self._ebuild_path = ebuild_path 58 portage.doebuild_environment(ebuild_path, 'setup', 59 settings=self.settings, db=portdb) 60 61 # Check the manifest here since with --keep-going mode it's 62 # currently possible to get this far with a broken manifest. 63 if not self._check_manifest(): 64 self.returncode = 1 65 self._current_task = None 66 self._async_wait() 67 return 68 69 prefetcher = self.prefetcher 70 if prefetcher is None: 71 pass 72 elif prefetcher.isAlive() and \ 73 prefetcher.poll() is None: 74 75 waiting_msg = "Fetching files " + \ 76 "in the background. " + \ 77 "To view fetch progress, run `tail -f " + \ 78 "/var/log/emerge-fetch.log` in another " + \ 79 "terminal." 80 msg_prefix = colorize("GOOD", " * ") 81 from textwrap import wrap 82 waiting_msg = "".join("%s%s\n" % (msg_prefix, line) \ 83 for line in wrap(waiting_msg, 65)) 84 if not self.background: 85 writemsg(waiting_msg, noiselevel=-1) 86 87 self._current_task = prefetcher 88 prefetcher.addExitListener(self._prefetch_exit) 89 return 90 91 self._prefetch_exit(prefetcher)
92
93 - def _check_manifest(self):
94 success = True 95 96 settings = self.settings 97 if 'strict' in settings.features and \ 98 'digest' not in settings.features: 99 settings['O'] = os.path.dirname(self._ebuild_path) 100 quiet_setting = settings.get('PORTAGE_QUIET') 101 settings['PORTAGE_QUIET'] = '1' 102 try: 103 success = digestcheck([], settings, strict=True) 104 finally: 105 if quiet_setting: 106 settings['PORTAGE_QUIET'] = quiet_setting 107 else: 108 del settings['PORTAGE_QUIET'] 109 110 return success
111
112 - def _prefetch_exit(self, prefetcher):
113 114 if self._was_cancelled(): 115 self.wait() 116 return 117 118 opts = self.opts 119 pkg = self.pkg 120 settings = self.settings 121 122 if opts.fetchonly: 123 if opts.pretend: 124 fetcher = EbuildFetchonly( 125 fetch_all=opts.fetch_all_uri, 126 pkg=pkg, pretend=opts.pretend, 127 settings=settings) 128 retval = fetcher.execute() 129 self.returncode = retval 130 self.wait() 131 return 132 else: 133 fetcher = EbuildFetcher( 134 config_pool=self.config_pool, 135 ebuild_path=self._ebuild_path, 136 fetchall=self.opts.fetch_all_uri, 137 fetchonly=self.opts.fetchonly, 138 background=False, 139 logfile=None, 140 pkg=self.pkg, 141 scheduler=self.scheduler) 142 self._start_task(fetcher, self._fetchonly_exit) 143 return 144 145 self._build_dir = EbuildBuildDir( 146 scheduler=self.scheduler, settings=settings) 147 self._build_dir.lock() 148 149 # Cleaning needs to happen before fetch, since the build dir 150 # is used for log handling. 151 msg = " === (%s of %s) Cleaning (%s::%s)" % \ 152 (self.pkg_count.curval, self.pkg_count.maxval, 153 self.pkg.cpv, self._ebuild_path) 154 short_msg = "emerge: (%s of %s) %s Clean" % \ 155 (self.pkg_count.curval, self.pkg_count.maxval, self.pkg.cpv) 156 self.logger.log(msg, short_msg=short_msg) 157 158 pre_clean_phase = EbuildPhase(background=self.background, 159 phase='clean', scheduler=self.scheduler, settings=self.settings) 160 self._start_task(pre_clean_phase, self._pre_clean_exit)
161
162 - def _fetchonly_exit(self, fetcher):
163 self._final_exit(fetcher) 164 if self.returncode != os.EX_OK: 165 portdb = self.pkg.root_config.trees[self._tree].dbapi 166 spawn_nofetch(portdb, self._ebuild_path, settings=self.settings) 167 elif 'digest' in self.settings.features: 168 if not digestgen(mysettings=self.settings, 169 myportdb=self.pkg.root_config.trees[self._tree].dbapi): 170 self.returncode = 1 171 self.wait()
172
173 - def _pre_clean_exit(self, pre_clean_phase):
174 if self._default_exit(pre_clean_phase) != os.EX_OK: 175 self._unlock_builddir() 176 self.wait() 177 return 178 179 # for log handling 180 portage.prepare_build_dirs(self.pkg.root, self.settings, 1) 181 182 fetcher = EbuildFetcher(config_pool=self.config_pool, 183 ebuild_path=self._ebuild_path, 184 fetchall=self.opts.fetch_all_uri, 185 fetchonly=self.opts.fetchonly, 186 background=self.background, 187 logfile=self.settings.get('PORTAGE_LOG_FILE'), 188 pkg=self.pkg, scheduler=self.scheduler) 189 190 try: 191 already_fetched = fetcher.already_fetched(self.settings) 192 except portage.exception.InvalidDependString as e: 193 msg_lines = [] 194 msg = "Fetch failed for '%s' due to invalid SRC_URI: %s" % \ 195 (self.pkg.cpv, e) 196 msg_lines.append(msg) 197 fetcher._eerror(msg_lines) 198 portage.elog.elog_process(self.pkg.cpv, self.settings) 199 self.returncode = 1 200 self._current_task = None 201 self._unlock_builddir() 202 self.wait() 203 return 204 205 if already_fetched: 206 # This case is optimized to skip the fetch queue. 207 fetcher = None 208 self._fetch_exit(fetcher) 209 return 210 211 # Allow the Scheduler's fetch queue to control the 212 # number of concurrent fetchers. 213 fetcher.addExitListener(self._fetch_exit) 214 self._task_queued(fetcher) 215 self.scheduler.fetch.schedule(fetcher)
216
217 - def _fetch_exit(self, fetcher):
218 219 if fetcher is not None and \ 220 self._default_exit(fetcher) != os.EX_OK: 221 self._fetch_failed() 222 return 223 224 # discard successful fetch log 225 self._build_dir.clean_log() 226 pkg = self.pkg 227 logger = self.logger 228 opts = self.opts 229 pkg_count = self.pkg_count 230 scheduler = self.scheduler 231 settings = self.settings 232 features = settings.features 233 ebuild_path = self._ebuild_path 234 system_set = pkg.root_config.sets["system"] 235 236 #buildsyspkg: Check if we need to _force_ binary package creation 237 self._issyspkg = "buildsyspkg" in features and \ 238 system_set.findAtomForPackage(pkg) and \ 239 "buildpkg" not in features and \ 240 opts.buildpkg != 'n' 241 242 if ("buildpkg" in features or self._issyspkg) \ 243 and not self.opts.buildpkg_exclude.findAtomForPackage(pkg): 244 245 self._buildpkg = True 246 247 msg = " === (%s of %s) Compiling/Packaging (%s::%s)" % \ 248 (pkg_count.curval, pkg_count.maxval, pkg.cpv, ebuild_path) 249 short_msg = "emerge: (%s of %s) %s Compile" % \ 250 (pkg_count.curval, pkg_count.maxval, pkg.cpv) 251 logger.log(msg, short_msg=short_msg) 252 253 else: 254 msg = " === (%s of %s) Compiling/Merging (%s::%s)" % \ 255 (pkg_count.curval, pkg_count.maxval, pkg.cpv, ebuild_path) 256 short_msg = "emerge: (%s of %s) %s Compile" % \ 257 (pkg_count.curval, pkg_count.maxval, pkg.cpv) 258 logger.log(msg, short_msg=short_msg) 259 260 build = EbuildExecuter(background=self.background, pkg=pkg, 261 scheduler=scheduler, settings=settings) 262 self._start_task(build, self._build_exit)
263
264 - def _fetch_failed(self):
265 # We only call the pkg_nofetch phase if either RESTRICT=fetch 266 # is set or the package has explicitly overridden the default 267 # pkg_nofetch implementation. This allows specialized messages 268 # to be displayed for problematic packages even though they do 269 # not set RESTRICT=fetch (bug #336499). 270 271 if 'fetch' not in self.pkg.restrict and \ 272 'nofetch' not in self.pkg.defined_phases: 273 self._unlock_builddir() 274 self.wait() 275 return 276 277 self.returncode = None 278 nofetch_phase = EbuildPhase(background=self.background, 279 phase='nofetch', scheduler=self.scheduler, settings=self.settings) 280 self._start_task(nofetch_phase, self._nofetch_exit)
281
282 - def _nofetch_exit(self, nofetch_phase):
283 self._final_exit(nofetch_phase) 284 self._unlock_builddir() 285 self.returncode = 1 286 self.wait()
287
288 - def _unlock_builddir(self):
291
292 - def _build_exit(self, build):
293 if self._default_exit(build) != os.EX_OK: 294 self._unlock_builddir() 295 self.wait() 296 return 297 298 buildpkg = self._buildpkg 299 300 if not buildpkg: 301 self._final_exit(build) 302 self.wait() 303 return 304 305 if self._issyspkg: 306 msg = ">>> This is a system package, " + \ 307 "let's pack a rescue tarball.\n" 308 self.scheduler.output(msg, 309 log_path=self.settings.get("PORTAGE_LOG_FILE")) 310 311 binpkg_tasks = TaskSequence() 312 requested_binpkg_formats = self.settings.get("PORTAGE_BINPKG_FORMAT", "tar").split() 313 for pkg_fmt in portage.const.SUPPORTED_BINPKG_FORMATS: 314 if pkg_fmt in requested_binpkg_formats: 315 if pkg_fmt == "rpm": 316 binpkg_tasks.add(EbuildPhase(background=self.background, 317 phase="rpm", scheduler=self.scheduler, 318 settings=self.settings)) 319 else: 320 binpkg_tasks.add(EbuildBinpkg(background=self.background, 321 pkg=self.pkg, scheduler=self.scheduler, 322 settings=self.settings)) 323 324 self._start_task(binpkg_tasks, self._buildpkg_exit)
325
326 - def _buildpkg_exit(self, packager):
327 """ 328 Released build dir lock when there is a failure or 329 when in buildpkgonly mode. Otherwise, the lock will 330 be released when merge() is called. 331 """ 332 333 if self._default_exit(packager) != os.EX_OK: 334 self._unlock_builddir() 335 self.wait() 336 return 337 338 if self.opts.buildpkgonly: 339 phase = 'success_hooks' 340 success_hooks = MiscFunctionsProcess( 341 background=self.background, 342 commands=[phase], phase=phase, 343 scheduler=self.scheduler, settings=self.settings) 344 self._start_task(success_hooks, 345 self._buildpkgonly_success_hook_exit) 346 return 347 348 # Continue holding the builddir lock until 349 # after the package has been installed. 350 self._current_task = None 351 self.returncode = packager.returncode 352 self.wait()
353
354 - def _buildpkgonly_success_hook_exit(self, success_hooks):
355 self._default_exit(success_hooks) 356 self.returncode = None 357 # Need to call "clean" phase for buildpkgonly mode 358 portage.elog.elog_process(self.pkg.cpv, self.settings) 359 phase = 'clean' 360 clean_phase = EbuildPhase(background=self.background, 361 phase=phase, scheduler=self.scheduler, settings=self.settings) 362 self._start_task(clean_phase, self._clean_exit)
363
364 - def _clean_exit(self, clean_phase):
365 if self._final_exit(clean_phase) != os.EX_OK or \ 366 self.opts.buildpkgonly: 367 self._unlock_builddir() 368 self.wait()
369
370 - def create_install_task(self):
371 """ 372 Install the package and then clean up and release locks. 373 Only call this after the build has completed successfully 374 and neither fetchonly nor buildpkgonly mode are enabled. 375 """ 376 377 ldpath_mtimes = self.ldpath_mtimes 378 logger = self.logger 379 pkg = self.pkg 380 pkg_count = self.pkg_count 381 settings = self.settings 382 world_atom = self.world_atom 383 ebuild_path = self._ebuild_path 384 tree = self._tree 385 386 task = EbuildMerge(exit_hook=self._install_exit, 387 find_blockers=self.find_blockers, 388 ldpath_mtimes=ldpath_mtimes, logger=logger, pkg=pkg, 389 pkg_count=pkg_count, pkg_path=ebuild_path, 390 scheduler=self.scheduler, 391 settings=settings, tree=tree, world_atom=world_atom) 392 393 msg = " === (%s of %s) Merging (%s::%s)" % \ 394 (pkg_count.curval, pkg_count.maxval, 395 pkg.cpv, ebuild_path) 396 short_msg = "emerge: (%s of %s) %s Merge" % \ 397 (pkg_count.curval, pkg_count.maxval, pkg.cpv) 398 logger.log(msg, short_msg=short_msg) 399 400 return task
401
402 - def _install_exit(self, task):
403 self._unlock_builddir()
404