Bug #286522 - Check all portdbapi.findname return values in case it
[portage.git] / pym / _emerge / EbuildBuild.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.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 portage.util import writemsg
14 import portage
15 from portage import os
16 from portage import _encodings
17 from portage import _unicode_encode
18 import codecs
19 from portage.output import colorize
20 class EbuildBuild(CompositeTask):
21
22         __slots__ = ("args_set", "config_pool", "find_blockers",
23                 "ldpath_mtimes", "logger", "opts", "pkg", "pkg_count",
24                 "prefetcher", "settings", "world_atom") + \
25                 ("_build_dir", "_buildpkg", "_ebuild_path", "_issyspkg", "_tree")
26
27         def _start(self):
28
29                 logger = self.logger
30                 opts = self.opts
31                 pkg = self.pkg
32                 settings = self.settings
33                 world_atom = self.world_atom
34                 root_config = pkg.root_config
35                 tree = "porttree"
36                 self._tree = tree
37                 portdb = root_config.trees[tree].dbapi
38                 settings.setcpv(pkg)
39                 settings.configdict["pkg"]["EMERGE_FROM"] = pkg.type_name
40                 ebuild_path = portdb.findname(pkg.cpv)
41                 if ebuild_path is None:
42                         raise AssertionError("ebuild not found for '%s'" % pkg.cpv)
43                 self._ebuild_path = ebuild_path
44
45                 prefetcher = self.prefetcher
46                 if prefetcher is None:
47                         pass
48                 elif not prefetcher.isAlive():
49                         prefetcher.cancel()
50                 elif prefetcher.poll() is None:
51
52                         waiting_msg = "Fetching files " + \
53                                 "in the background. " + \
54                                 "To view fetch progress, run `tail -f " + \
55                                 "/var/log/emerge-fetch.log` in another " + \
56                                 "terminal."
57                         msg_prefix = colorize("GOOD", " * ")
58                         from textwrap import wrap
59                         waiting_msg = "".join("%s%s\n" % (msg_prefix, line) \
60                                 for line in wrap(waiting_msg, 65))
61                         if not self.background:
62                                 writemsg(waiting_msg, noiselevel=-1)
63
64                         self._current_task = prefetcher
65                         prefetcher.addExitListener(self._prefetch_exit)
66                         return
67
68                 self._prefetch_exit(prefetcher)
69
70         def _prefetch_exit(self, prefetcher):
71
72                 opts = self.opts
73                 pkg = self.pkg
74                 settings = self.settings
75
76                 if opts.fetchonly:
77                                 fetcher = EbuildFetchonly(
78                                         fetch_all=opts.fetch_all_uri,
79                                         pkg=pkg, pretend=opts.pretend,
80                                         settings=settings)
81                                 retval = fetcher.execute()
82                                 self.returncode = retval
83                                 self.wait()
84                                 return
85
86                 fetcher = EbuildFetcher(config_pool=self.config_pool,
87                         fetchall=opts.fetch_all_uri,
88                         fetchonly=opts.fetchonly,
89                         background=self.background,
90                         pkg=pkg, scheduler=self.scheduler)
91
92                 self._start_task(fetcher, self._fetch_exit)
93
94         def _fetch_exit(self, fetcher):
95                 opts = self.opts
96                 pkg = self.pkg
97
98                 fetch_failed = False
99                 if opts.fetchonly:
100                         fetch_failed = self._final_exit(fetcher) != os.EX_OK
101                 else:
102                         fetch_failed = self._default_exit(fetcher) != os.EX_OK
103
104                 if fetch_failed and fetcher.logfile is not None and \
105                         os.path.exists(fetcher.logfile):
106                         self.settings["PORTAGE_LOG_FILE"] = fetcher.logfile
107
108                 if not fetch_failed and fetcher.logfile is not None:
109                         # Fetch was successful, so remove the fetch log.
110                         try:
111                                 os.unlink(fetcher.logfile)
112                         except OSError:
113                                 pass
114
115                 if fetch_failed or opts.fetchonly:
116                         self.wait()
117                         return
118
119                 logger = self.logger
120                 opts = self.opts
121                 pkg_count = self.pkg_count
122                 scheduler = self.scheduler
123                 settings = self.settings
124                 features = settings.features
125                 ebuild_path = self._ebuild_path
126                 system_set = pkg.root_config.sets["system"]
127
128                 self._build_dir = EbuildBuildDir(pkg=pkg, settings=settings)
129                 self._build_dir.lock()
130
131                 # Cleaning is triggered before the setup
132                 # phase, in portage.doebuild().
133                 msg = " === (%s of %s) Cleaning (%s::%s)" % \
134                         (pkg_count.curval, pkg_count.maxval, pkg.cpv, ebuild_path)
135                 short_msg = "emerge: (%s of %s) %s Clean" % \
136                         (pkg_count.curval, pkg_count.maxval, pkg.cpv)
137                 logger.log(msg, short_msg=short_msg)
138
139                 #buildsyspkg: Check if we need to _force_ binary package creation
140                 self._issyspkg = "buildsyspkg" in features and \
141                                 system_set.findAtomForPackage(pkg) and \
142                                 not opts.buildpkg
143
144                 if opts.buildpkg or self._issyspkg:
145
146                         self._buildpkg = True
147
148                         msg = " === (%s of %s) Compiling/Packaging (%s::%s)" % \
149                                 (pkg_count.curval, pkg_count.maxval, pkg.cpv, ebuild_path)
150                         short_msg = "emerge: (%s of %s) %s Compile" % \
151                                 (pkg_count.curval, pkg_count.maxval, pkg.cpv)
152                         logger.log(msg, short_msg=short_msg)
153
154                 else:
155                         msg = " === (%s of %s) Compiling/Merging (%s::%s)" % \
156                                 (pkg_count.curval, pkg_count.maxval, pkg.cpv, ebuild_path)
157                         short_msg = "emerge: (%s of %s) %s Compile" % \
158                                 (pkg_count.curval, pkg_count.maxval, pkg.cpv)
159                         logger.log(msg, short_msg=short_msg)
160
161                 build = EbuildExecuter(background=self.background, pkg=pkg,
162                         scheduler=scheduler, settings=settings)
163                 self._start_task(build, self._build_exit)
164
165         def _unlock_builddir(self):
166                 portage.elog.elog_process(self.pkg.cpv, self.settings)
167                 self._build_dir.unlock()
168
169         def _build_exit(self, build):
170                 if self._default_exit(build) != os.EX_OK:
171                         self._unlock_builddir()
172                         self.wait()
173                         return
174
175                 opts = self.opts
176                 buildpkg = self._buildpkg
177
178                 if not buildpkg:
179                         self._final_exit(build)
180                         self.wait()
181                         return
182
183                 if self._issyspkg:
184                         msg = ">>> This is a system package, " + \
185                                 "let's pack a rescue tarball.\n"
186
187                         log_path = self.settings.get("PORTAGE_LOG_FILE")
188                         if log_path is not None:
189                                 log_file = codecs.open(_unicode_encode(log_path,
190                                         encoding=_encodings['fs'], errors='strict'),
191                                         mode='a', encoding=_encodings['content'], errors='replace')
192                                 try:
193                                         log_file.write(msg)
194                                 finally:
195                                         log_file.close()
196
197                         if not self.background:
198                                 portage.writemsg_stdout(msg, noiselevel=-1)
199
200                 packager = EbuildBinpkg(background=self.background, pkg=self.pkg,
201                         scheduler=self.scheduler, settings=self.settings)
202
203                 self._start_task(packager, self._buildpkg_exit)
204
205         def _buildpkg_exit(self, packager):
206                 """
207                 Released build dir lock when there is a failure or
208                 when in buildpkgonly mode. Otherwise, the lock will
209                 be released when merge() is called.
210                 """
211
212                 if self._default_exit(packager) != os.EX_OK:
213                         self._unlock_builddir()
214                         self.wait()
215                         return
216
217                 if self.opts.buildpkgonly:
218                         # Need to call "clean" phase for buildpkgonly mode
219                         portage.elog.elog_process(self.pkg.cpv, self.settings)
220                         phase = "clean"
221                         clean_phase = EbuildPhase(background=self.background,
222                                 pkg=self.pkg, phase=phase,
223                                 scheduler=self.scheduler, settings=self.settings,
224                                 tree=self._tree)
225                         self._start_task(clean_phase, self._clean_exit)
226                         return
227
228                 # Continue holding the builddir lock until
229                 # after the package has been installed.
230                 self._current_task = None
231                 self.returncode = packager.returncode
232                 self.wait()
233
234         def _clean_exit(self, clean_phase):
235                 if self._final_exit(clean_phase) != os.EX_OK or \
236                         self.opts.buildpkgonly:
237                         self._unlock_builddir()
238                 self.wait()
239
240         def install(self):
241                 """
242                 Install the package and then clean up and release locks.
243                 Only call this after the build has completed successfully
244                 and neither fetchonly nor buildpkgonly mode are enabled.
245                 """
246
247                 find_blockers = self.find_blockers
248                 ldpath_mtimes = self.ldpath_mtimes
249                 logger = self.logger
250                 pkg = self.pkg
251                 pkg_count = self.pkg_count
252                 settings = self.settings
253                 world_atom = self.world_atom
254                 ebuild_path = self._ebuild_path
255                 tree = self._tree
256
257                 merge = EbuildMerge(find_blockers=self.find_blockers,
258                         ldpath_mtimes=ldpath_mtimes, logger=logger, pkg=pkg,
259                         pkg_count=pkg_count, pkg_path=ebuild_path,
260                         scheduler=self.scheduler,
261                         settings=settings, tree=tree, world_atom=world_atom)
262
263                 msg = " === (%s of %s) Merging (%s::%s)" % \
264                         (pkg_count.curval, pkg_count.maxval,
265                         pkg.cpv, ebuild_path)
266                 short_msg = "emerge: (%s of %s) %s Merge" % \
267                         (pkg_count.curval, pkg_count.maxval, pkg.cpv)
268                 logger.log(msg, short_msg=short_msg)
269
270                 try:
271                         rval = merge.execute()
272                 finally:
273                         self._unlock_builddir()
274
275                 return rval
276