Package _emerge :: Module EbuildBuild
[hide private]

Source Code for Module _emerge.EbuildBuild

  1  # Copyright 1999-2014 Gentoo Foundation 
  2  # Distributed under the terms of the GNU General Public License v2 
  3   
  4  import _emerge.emergelog 
  5  from _emerge.EbuildExecuter import EbuildExecuter 
  6  from _emerge.EbuildPhase import EbuildPhase 
  7  from _emerge.EbuildBinpkg import EbuildBinpkg 
  8  from _emerge.EbuildFetcher import EbuildFetcher 
  9  from _emerge.CompositeTask import CompositeTask 
 10  from _emerge.EbuildMerge import EbuildMerge 
 11  from _emerge.EbuildFetchonly import EbuildFetchonly 
 12  from _emerge.EbuildBuildDir import EbuildBuildDir 
 13  from _emerge.MiscFunctionsProcess import MiscFunctionsProcess 
 14  from _emerge.TaskSequence import TaskSequence 
 15   
 16  from portage.util import writemsg 
 17  import portage 
 18  from portage import os 
 19  from portage.output import colorize 
 20  from portage.package.ebuild.digestcheck import digestcheck 
 21  from portage.package.ebuild.digestgen import digestgen 
 22  from portage.package.ebuild.doebuild import _check_temp_dir 
 23  from portage.package.ebuild._spawn_nofetch import spawn_nofetch 
 24   
25 -class EbuildBuild(CompositeTask):
26 27 __slots__ = ("args_set", "config_pool", "find_blockers", 28 "ldpath_mtimes", "logger", "opts", "pkg", "pkg_count", 29 "prefetcher", "settings", "world_atom") + \ 30 ("_build_dir", "_buildpkg", "_ebuild_path", "_issyspkg", "_tree") 31
32 - def _start(self):
33 34 pkg = self.pkg 35 settings = self.settings 36 37 if not self.opts.fetchonly: 38 rval = _check_temp_dir(settings) 39 if rval != os.EX_OK: 40 self.returncode = rval 41 self._current_task = None 42 self._async_wait() 43 return 44 45 root_config = pkg.root_config 46 tree = "porttree" 47 self._tree = tree 48 portdb = root_config.trees[tree].dbapi 49 settings.setcpv(pkg) 50 settings.configdict["pkg"]["EMERGE_FROM"] = "ebuild" 51 if self.opts.buildpkgonly: 52 settings.configdict["pkg"]["MERGE_TYPE"] = "buildonly" 53 else: 54 settings.configdict["pkg"]["MERGE_TYPE"] = "source" 55 ebuild_path = portdb.findname(pkg.cpv, myrepo=pkg.repo) 56 if ebuild_path is None: 57 raise AssertionError("ebuild not found for '%s'" % pkg.cpv) 58 self._ebuild_path = ebuild_path 59 portage.doebuild_environment(ebuild_path, 'setup', 60 settings=self.settings, db=portdb) 61 62 # Check the manifest here since with --keep-going mode it's 63 # currently possible to get this far with a broken manifest. 64 if not self._check_manifest(): 65 self.returncode = 1 66 self._current_task = None 67 self._async_wait() 68 return 69 70 prefetcher = self.prefetcher 71 if prefetcher is None: 72 pass 73 elif prefetcher.isAlive() and \ 74 prefetcher.poll() is None: 75 76 waiting_msg = "Fetching files " + \ 77 "in the background. " + \ 78 "To view fetch progress, run `tail -f %s` in another terminal." \ 79 % (os.path.join(_emerge.emergelog._emerge_log_dir, "emerge-fetch.log")) 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 if binpkg_tasks: 325 self._start_task(binpkg_tasks, self._buildpkg_exit) 326 return 327 328 self._final_exit(build) 329 self.wait()
330
331 - def _buildpkg_exit(self, packager):
332 """ 333 Released build dir lock when there is a failure or 334 when in buildpkgonly mode. Otherwise, the lock will 335 be released when merge() is called. 336 """ 337 338 if self._default_exit(packager) != os.EX_OK: 339 self._unlock_builddir() 340 self.wait() 341 return 342 343 if self.opts.buildpkgonly: 344 phase = 'success_hooks' 345 success_hooks = MiscFunctionsProcess( 346 background=self.background, 347 commands=[phase], phase=phase, 348 scheduler=self.scheduler, settings=self.settings) 349 self._start_task(success_hooks, 350 self._buildpkgonly_success_hook_exit) 351 return 352 353 # Continue holding the builddir lock until 354 # after the package has been installed. 355 self._current_task = None 356 self.returncode = packager.returncode 357 self.wait()
358
359 - def _buildpkgonly_success_hook_exit(self, success_hooks):
360 self._default_exit(success_hooks) 361 self.returncode = None 362 # Need to call "clean" phase for buildpkgonly mode 363 portage.elog.elog_process(self.pkg.cpv, self.settings) 364 phase = 'clean' 365 clean_phase = EbuildPhase(background=self.background, 366 phase=phase, scheduler=self.scheduler, settings=self.settings) 367 self._start_task(clean_phase, self._clean_exit)
368
369 - def _clean_exit(self, clean_phase):
370 if self._final_exit(clean_phase) != os.EX_OK or \ 371 self.opts.buildpkgonly: 372 self._unlock_builddir() 373 self.wait()
374
375 - def create_install_task(self):
376 """ 377 Install the package and then clean up and release locks. 378 Only call this after the build has completed successfully 379 and neither fetchonly nor buildpkgonly mode are enabled. 380 """ 381 382 ldpath_mtimes = self.ldpath_mtimes 383 logger = self.logger 384 pkg = self.pkg 385 pkg_count = self.pkg_count 386 settings = self.settings 387 world_atom = self.world_atom 388 ebuild_path = self._ebuild_path 389 tree = self._tree 390 391 task = EbuildMerge(exit_hook=self._install_exit, 392 find_blockers=self.find_blockers, 393 ldpath_mtimes=ldpath_mtimes, logger=logger, pkg=pkg, 394 pkg_count=pkg_count, pkg_path=ebuild_path, 395 scheduler=self.scheduler, 396 settings=settings, tree=tree, world_atom=world_atom) 397 398 msg = " === (%s of %s) Merging (%s::%s)" % \ 399 (pkg_count.curval, pkg_count.maxval, 400 pkg.cpv, ebuild_path) 401 short_msg = "emerge: (%s of %s) %s Merge" % \ 402 (pkg_count.curval, pkg_count.maxval, pkg.cpv) 403 logger.log(msg, short_msg=short_msg) 404 405 return task
406
407 - def _install_exit(self, task):
408 self._unlock_builddir()
409