Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(323)

Side by Side Diff: parallel_emerge

Issue 3010056: Add --show-output option to parallel_emerge which prints output from jobs. (Closed) Base URL: ssh://git@chromiumos-git/crosutils.git
Patch Set: Update comment Created 10 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 #!/usr/bin/python2.6 1 #!/usr/bin/python2.6
2 # Copyright (c) 2010 The Chromium OS Authors. All rights reserved. 2 # Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be 3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file. 4 # found in the LICENSE file.
5 5
6 """Program to run emerge in parallel, for significant speedup. 6 """Program to run emerge in parallel, for significant speedup.
7 7
8 Usage: 8 Usage:
9 ./parallel_emerge [--board=BOARD] [--workon=PKGS] [--no-workon-deps] 9 ./parallel_emerge [--board=BOARD] [--workon=PKGS] [--no-workon-deps]
10 [emerge args] package" 10 [emerge args] package"
(...skipping 20 matching lines...) Expand all
31 or "--nodeps" write only access. 31 or "--nodeps" write only access.
32 Caveats: 32 Caveats:
33 * Some ebuild packages have incorrectly specified deps, and running 33 * Some ebuild packages have incorrectly specified deps, and running
34 them in parallel is more likely to bring out these failures. 34 them in parallel is more likely to bring out these failures.
35 * Some ebuilds (especially the build part) have complex dependencies 35 * Some ebuilds (especially the build part) have complex dependencies
36 that are not captured well by this script (it may be necessary to 36 that are not captured well by this script (it may be necessary to
37 install an old package to build, but then install a newer version 37 install an old package to build, but then install a newer version
38 of the same package for a runtime dep). 38 of the same package for a runtime dep).
39 """ 39 """
40 40
41 import codecs
41 import copy 42 import copy
42 import multiprocessing 43 import multiprocessing
43 import os 44 import os
44 import Queue 45 import Queue
45 import shlex 46 import shlex
47 import signal
46 import sys 48 import sys
47 import tempfile 49 import tempfile
48 import time 50 import time
51 import traceback
49 import urllib2 52 import urllib2
50 53
51 # If PORTAGE_USERNAME isn't specified, scrape it from the $HOME variable. On 54 # If PORTAGE_USERNAME isn't specified, scrape it from the $HOME variable. On
52 # Chromium OS, the default "portage" user doesn't have the necessary 55 # Chromium OS, the default "portage" user doesn't have the necessary
53 # permissions. It'd be easier if we could default to $USERNAME, but $USERNAME 56 # permissions. It'd be easier if we could default to $USERNAME, but $USERNAME
54 # is "root" here because we get called through sudo. 57 # is "root" here because we get called through sudo.
55 # 58 #
56 # We need to set this before importing any portage modules, because portage 59 # We need to set this before importing any portage modules, because portage
57 # looks up "PORTAGE_USERNAME" at import time. 60 # looks up "PORTAGE_USERNAME" at import time.
58 # 61 #
(...skipping 148 matching lines...) Expand 10 before | Expand all | Expand 10 after
207 Typical usage: 210 Typical usage:
208 deps = DepGraphGenerator() 211 deps = DepGraphGenerator()
209 deps.Initialize(sys.argv[1:]) 212 deps.Initialize(sys.argv[1:])
210 deps_tree, deps_info = deps.GenDependencyTree() 213 deps_tree, deps_info = deps.GenDependencyTree()
211 deps_graph = deps.GenDependencyGraph(deps_tree, deps_info) 214 deps_graph = deps.GenDependencyGraph(deps_tree, deps_info)
212 deps.PrintTree(deps_tree) 215 deps.PrintTree(deps_tree)
213 PrintDepsMap(deps_graph) 216 PrintDepsMap(deps_graph)
214 """ 217 """
215 218
216 __slots__ = ["board", "emerge", "mandatory_source", "no_workon_deps", 219 __slots__ = ["board", "emerge", "mandatory_source", "no_workon_deps",
217 "package_db", "rebuild"] 220 "package_db", "rebuild", "show_output"]
218 221
219 def __init__(self): 222 def __init__(self):
220 self.board = None 223 self.board = None
221 self.emerge = EmergeData() 224 self.emerge = EmergeData()
222 self.mandatory_source = set() 225 self.mandatory_source = set()
223 self.no_workon_deps = False 226 self.no_workon_deps = False
224 self.package_db = {} 227 self.package_db = {}
225 self.rebuild = False 228 self.rebuild = False
229 self.show_output = False
226 230
227 def ParseParallelEmergeArgs(self, argv): 231 def ParseParallelEmergeArgs(self, argv):
228 """Read the parallel emerge arguments from the command-line. 232 """Read the parallel emerge arguments from the command-line.
229 233
230 We need to be compatible with emerge arg format. We scrape arguments that 234 We need to be compatible with emerge arg format. We scrape arguments that
231 are specific to parallel_emerge, and pass through the rest directly to 235 are specific to parallel_emerge, and pass through the rest directly to
232 emerge. 236 emerge.
233 Args: 237 Args:
234 argv: arguments list 238 argv: arguments list
235 Returns: 239 Returns:
236 Arguments that don't belong to parallel_emerge 240 Arguments that don't belong to parallel_emerge
237 """ 241 """
238 emerge_args = [] 242 emerge_args = []
239 for arg in argv: 243 for arg in argv:
240 # Specifically match arguments that are specific to parallel_emerge, and 244 # Specifically match arguments that are specific to parallel_emerge, and
241 # pass through the rest. 245 # pass through the rest.
242 if arg.startswith("--board="): 246 if arg.startswith("--board="):
243 self.board = arg.replace("--board=", "") 247 self.board = arg.replace("--board=", "")
244 elif arg.startswith("--workon="): 248 elif arg.startswith("--workon="):
245 workon_str = arg.replace("--workon=", "") 249 workon_str = arg.replace("--workon=", "")
246 package_list = shlex.split(" ".join(shlex.split(workon_str))) 250 package_list = shlex.split(" ".join(shlex.split(workon_str)))
247 self.mandatory_source.update(package_list) 251 self.mandatory_source.update(package_list)
248 elif arg == "--no-workon-deps": 252 elif arg == "--no-workon-deps":
249 self.no_workon_deps = True 253 self.no_workon_deps = True
250 elif arg == "--rebuild": 254 elif arg == "--rebuild":
251 self.rebuild = True 255 self.rebuild = True
256 elif arg == "--show-output":
257 self.show_output = True
252 else: 258 else:
253 # Not one of our options, so pass through to emerge. 259 # Not one of our options, so pass through to emerge.
254 emerge_args.append(arg) 260 emerge_args.append(arg)
255 261
256 if self.rebuild: 262 if self.rebuild:
257 if self.no_workon_deps: 263 if self.no_workon_deps:
258 print "--rebuild is not compatible with --no-workon-deps" 264 print "--rebuild is not compatible with --no-workon-deps"
259 sys.exit(1) 265 sys.exit(1)
260 266
261 return emerge_args 267 return emerge_args
(...skipping 798 matching lines...) Expand 10 before | Expand all | Expand 10 after
1060 """Print dependency graph, for each package list it's prerequisites.""" 1066 """Print dependency graph, for each package list it's prerequisites."""
1061 for i in deps_map: 1067 for i in deps_map:
1062 print "%s: (%s) needs" % (i, deps_map[i]["action"]) 1068 print "%s: (%s) needs" % (i, deps_map[i]["action"])
1063 needs = deps_map[i]["needs"] 1069 needs = deps_map[i]["needs"]
1064 for j in needs: 1070 for j in needs:
1065 print " %s" % (j) 1071 print " %s" % (j)
1066 if not needs: 1072 if not needs:
1067 print " no dependencies" 1073 print " no dependencies"
1068 1074
1069 1075
1070 def EmergeWorker(task_queue, done_queue, emerge, package_db): 1076 class EmergeJobState(object):
1077 __slots__ = ["done", "filename", "last_output_seek", "last_output_timestamp",
1078 "pkgname", "retcode", "start_timestamp", "target"]
1079
1080 def __init__(self, target, pkgname, done, filename, start_timestamp,
1081 retcode=None):
1082
1083 # The full name of the target we're building (e.g.
1084 # chromeos-base/chromeos-0.0.1-r60)
1085 self.target = target
1086
1087 # The short name of the target we're building (e.g. chromeos-0.0.1-r60)
1088 self.pkgname = pkgname
1089
1090 # Whether the job is done. (True if the job is done; false otherwise.)
1091 self.done = done
1092
1093 # The filename where output is currently stored.
1094 self.filename = filename
1095
1096 # The location (in bytes) of the end of the last complete line we printed.
1097 # This starts off at zero. We use this to jump to the right place when we
1098 # print output from the same ebuild multiple times.
1099 self.last_output_seek = 0
1100
1101 # The timestamp of the last time we printed output. Since we haven't
1102 # printed output yet, this starts at zero.
1103 self.last_output_timestamp = 0
1104
1105 # The return code of our job, if the job is actually finished.
1106 self.retcode = retcode
1107
1108 # The timestamp when our job started.
1109 self.start_timestamp = start_timestamp
1110
1111
1112 def EmergeWorker(task_queue, job_queue, emerge, package_db):
1071 """This worker emerges any packages given to it on the task_queue. 1113 """This worker emerges any packages given to it on the task_queue.
1072 1114
1073 Args: 1115 Args:
1074 task_queue: The queue of tasks for this worker to do. 1116 task_queue: The queue of tasks for this worker to do.
1075 done_queue: The queue of results from the worker. 1117 job_queue: The queue of results from the worker.
1076 emerge: An EmergeData() object. 1118 emerge: An EmergeData() object.
1077 package_db: A dict, mapping package ids to portage Package objects. 1119 package_db: A dict, mapping package ids to portage Package objects.
1078 1120
1079 It expects package identifiers to be passed to it via task_queue. When 1121 It expects package identifiers to be passed to it via task_queue. When
1080 the package is merged, it pushes (target, retval, outputstr) into the 1122 a task is started, it pushes the (target, filename) to the started_queue.
1081 done_queue. 1123 The output is stored in filename. When a merge starts or finishes, we push
1124 EmergeJobState objects to the job_queue.
1082 """ 1125 """
1083 1126
1127 def ExitHandler(signum, frame):
1128 # Remove our signal handlers so we don't get called recursively.
1129 signal.signal(signal.SIGINT, signal.SIG_DFL)
1130 signal.signal(signal.SIGTERM, signal.SIG_DFL)
1131
1132 # Try to exit cleanly
1133 sys.exit(1)
1134
1135 # Ensure that we exit quietly and cleanly, if possible, when we receive
1136 # SIGTERM or SIGINT signals. By default, when the user hits CTRL-C, all
1137 # of the child processes will print details about KeyboardInterrupt
1138 # exceptions, which isn't very helpful.
1139 signal.signal(signal.SIGINT, ExitHandler)
1140 signal.signal(signal.SIGTERM, ExitHandler)
1141
1084 settings, trees, mtimedb = emerge.settings, emerge.trees, emerge.mtimedb 1142 settings, trees, mtimedb = emerge.settings, emerge.trees, emerge.mtimedb
1085 opts, spinner = emerge.opts, emerge.spinner 1143 opts, spinner = emerge.opts, emerge.spinner
1086 opts["--nodeps"] = True 1144 opts["--nodeps"] = True
1087 while True: 1145 while True:
1088 # Wait for a new item to show up on the queue. This is a blocking wait, 1146 # Wait for a new item to show up on the queue. This is a blocking wait,
1089 # so if there's nothing to do, we just sit here. 1147 # so if there's nothing to do, we just sit here.
1090 target = task_queue.get() 1148 target = task_queue.get()
1091 print "Emerging", target
1092 db_pkg = package_db[target] 1149 db_pkg = package_db[target]
1093 db_pkg.root_config = emerge.root_config 1150 db_pkg.root_config = emerge.root_config
1094 install_list = [db_pkg] 1151 install_list = [db_pkg]
1095 output = tempfile.TemporaryFile() 1152 pkgname = db_pkg.pf
1096 outputstr = "" 1153 output = tempfile.NamedTemporaryFile(prefix=pkgname + "-", delete=False)
1154 start_timestamp = time.time()
1155 job = EmergeJobState(target, pkgname, False, output.name, start_timestamp)
1156 job_queue.put(job)
1097 if "--pretend" in opts: 1157 if "--pretend" in opts:
1098 retval = 0 1158 retcode = 0
1099 else: 1159 else:
1100 save_stdout = sys.stdout 1160 save_stdout = sys.stdout
1101 save_stderr = sys.stderr 1161 save_stderr = sys.stderr
1102 try: 1162 try:
1103 sys.stdout = output 1163 sys.stdout = output
1104 sys.stderr = output 1164 sys.stderr = output
1105 scheduler = Scheduler(settings, trees, mtimedb, opts, spinner, 1165 scheduler = Scheduler(settings, trees, mtimedb, opts, spinner,
1106 install_list, [], emerge.scheduler_graph) 1166 install_list, [], emerge.scheduler_graph)
1107 retval = scheduler.merge() 1167 retcode = scheduler.merge()
1168 except Exception:
1169 traceback.print_exc(file=output)
1170 retcode = 1
1108 finally: 1171 finally:
1109 sys.stdout = save_stdout 1172 sys.stdout = save_stdout
1110 sys.stderr = save_stderr 1173 sys.stderr = save_stderr
1111 if retval is None: 1174 output.close()
1112 retval = 0 1175 if retcode is None:
1113 if retval != 0: 1176 retcode = 0
1114 output.seek(0)
1115 outputstr = output.read()
1116 1177
1117 done_queue.put((target, retval, outputstr)) 1178 job = EmergeJobState(target, pkgname, True, output.name, start_timestamp,
1179 retcode)
1180 job_queue.put(job)
1118 1181
1119 1182
1120 class EmergeQueue(object): 1183 class EmergeQueue(object):
1121 """Class to schedule emerge jobs according to a dependency graph.""" 1184 """Class to schedule emerge jobs according to a dependency graph."""
1122 1185
1123 def __init__(self, deps_map, emerge, package_db): 1186 def __init__(self, deps_map, emerge, package_db, show_output):
1124 # Store the dependency graph. 1187 # Store the dependency graph.
1125 self._deps_map = deps_map 1188 self._deps_map = deps_map
1126 # Initialize the running queue to empty 1189 # Initialize the running queue to empty
1127 self._jobs = set() 1190 self._jobs = {}
1128 # List of total package installs represented in deps_map. 1191 # List of total package installs represented in deps_map.
1129 install_jobs = [x for x in deps_map if deps_map[x]["action"] == "merge"] 1192 install_jobs = [x for x in deps_map if deps_map[x]["action"] == "merge"]
1130 self._total_jobs = len(install_jobs) 1193 self._total_jobs = len(install_jobs)
1194 self._show_output = show_output
1131 1195
1132 if "--pretend" in emerge.opts: 1196 if "--pretend" in emerge.opts:
1133 print "Skipping merge because of --pretend mode." 1197 print "Skipping merge because of --pretend mode."
1134 sys.exit(0) 1198 sys.exit(0)
1135 1199
1136 # Setup scheduler graph object. This is used by the child processes 1200 # Setup scheduler graph object. This is used by the child processes
1137 # to help schedule jobs. 1201 # to help schedule jobs.
1138 emerge.scheduler_graph = emerge.depgraph.schedulerGraph() 1202 emerge.scheduler_graph = emerge.depgraph.schedulerGraph()
1139 1203
1140 procs = min(self._total_jobs, 1204 procs = min(self._total_jobs,
1141 emerge.opts.get("--jobs", multiprocessing.cpu_count())) 1205 emerge.opts.get("--jobs", multiprocessing.cpu_count()))
1142 self._emerge_queue = multiprocessing.Queue() 1206 self._emerge_queue = multiprocessing.Queue()
1143 self._done_queue = multiprocessing.Queue() 1207 self._job_queue = multiprocessing.Queue()
1144 args = (self._emerge_queue, self._done_queue, emerge, package_db) 1208 args = (self._emerge_queue, self._job_queue, emerge, package_db)
1145 self._pool = multiprocessing.Pool(procs, EmergeWorker, args) 1209 self._pool = multiprocessing.Pool(procs, EmergeWorker, args)
1146 1210
1147 # Initialize the failed queue to empty. 1211 # Initialize the failed queue to empty.
1148 self._retry_queue = [] 1212 self._retry_queue = []
1149 self._failed = {} 1213 self._failed = set()
1150 1214
1151 # Print an update before we launch the merges. 1215 # Print an update before we launch the merges.
1152 self._Status() 1216 self._Status()
1153 1217
1218 # Setup an exit handler so that we print nice messages if we are
1219 # terminated.
1220 self._SetupExitHandler()
1221
1222 # Schedule our jobs.
1154 for target, info in deps_map.items(): 1223 for target, info in deps_map.items():
1155 if not info["needs"]: 1224 if not info["needs"]:
1156 self._Schedule(target) 1225 self._Schedule(target)
1157 1226
1227 def _SetupExitHandler(self):
1228
1229 def ExitHandler(signum, frame):
1230
1231 # Kill our signal handlers so we don't get called recursively
1232 signal.signal(signal.SIGINT, signal.SIG_DFL)
1233 signal.signal(signal.SIGTERM, signal.SIG_DFL)
1234
1235 # Print our current job status
1236 for target, job in self._jobs.iteritems():
1237 if job:
1238 self._PrintJob(job)
1239 os.unlink(job.filename)
1240
1241 # Notify the user that we are exiting
1242 print "Exiting on signal %s" % signum
1243 sys.exit(1)
1244
1245 # Print out job status when we are killed
1246 signal.signal(signal.SIGINT, ExitHandler)
1247 signal.signal(signal.SIGTERM, ExitHandler)
1248
1158 def _Schedule(self, target): 1249 def _Schedule(self, target):
1159 # We maintain a tree of all deps, if this doesn't need 1250 # We maintain a tree of all deps, if this doesn't need
1160 # to be installed just free up it's children and continue. 1251 # to be installed just free up it's children and continue.
1161 # It is possible to reinstall deps of deps, without reinstalling 1252 # It is possible to reinstall deps of deps, without reinstalling
1162 # first level deps, like so: 1253 # first level deps, like so:
1163 # chromeos (merge) -> eselect (nomerge) -> python (merge) 1254 # chromeos (merge) -> eselect (nomerge) -> python (merge)
1164 if self._deps_map[target]["action"] == "nomerge": 1255 if self._deps_map[target]["action"] == "nomerge":
1165 self._Finish(target) 1256 self._Finish(target)
1166 else: 1257 else:
1167 # Kick off the build if it's marked to be built. 1258 # Kick off the build if it's marked to be built.
1168 self._jobs.add(target) 1259 self._jobs[target] = None
1169 self._emerge_queue.put(target) 1260 self._emerge_queue.put(target)
1170 1261
1171 def _LoadAvg(self): 1262 def _LoadAvg(self):
1172 loads = open("/proc/loadavg", "r").readline().split()[:3] 1263 loads = open("/proc/loadavg", "r").readline().split()[:3]
1173 return " ".join(loads) 1264 return " ".join(loads)
1174 1265
1266 def _PrintJob(self, job):
1267 """Print output so far of specified job"""
1268
1269 # Calculate how long the job has been running.
1270 current_time = time.time()
1271 seconds = current_time - job.start_timestamp
1272
1273 # Note that we've printed out the job so far.
1274 job.last_output_timestamp = current_time
1275
1276 # Note that we're starting the job
1277 info = "job %s (%dm%.1fs) ===" % (job.pkgname, seconds / 60, seconds % 60)
1278 if job.last_output_seek:
1279 print "=== Continue output for %s " % info
1280 else:
1281 print "=== Start output for %s ===" % info
1282
1283 # Print actual output from job
1284 f = codecs.open(job.filename, encoding='utf-8', errors='replace')
1285 f.seek(job.last_output_seek)
1286 prefix = job.pkgname + ":"
1287 for line in f:
1288
1289 # Save off our position in the file
1290 if line and line[-1] == "\n":
1291 job.last_output_seek = f.tell()
1292 line = line[:-1]
1293
1294 # Print our line
1295 print prefix, line.encode('utf-8', 'replace')
1296 f.close()
1297
1298 # Note end of output section
1299 if job.done:
1300 print "=== Complete: %s ===" % info
1301 else:
1302 print "=== Still running: %s ===" % info
1303
1304
1175 def _Status(self): 1305 def _Status(self):
1176 """Print status.""" 1306 """Print status."""
1177 seconds = time.time() - GLOBAL_START 1307 current_time = time.time()
1308 seconds = current_time - GLOBAL_START
1178 line = ("Pending %s, Ready %s, Running %s, Retrying %s, Total %s " 1309 line = ("Pending %s, Ready %s, Running %s, Retrying %s, Total %s "
1179 "[Time %dm%.1fs Load %s]") 1310 "[Time %dm%.1fs Load %s]")
1180 qsize = self._emerge_queue.qsize() 1311 qsize = self._emerge_queue.qsize()
1181 print line % (len(self._deps_map), qsize, len(self._jobs) - qsize, 1312 print line % (len(self._deps_map), qsize, len(self._jobs) - qsize,
1182 len(self._retry_queue), self._total_jobs, 1313 len(self._retry_queue), self._total_jobs,
1183 seconds / 60, seconds % 60, self._LoadAvg()) 1314 seconds / 60, seconds % 60, self._LoadAvg())
1184 1315
1316 # Print interim output every minute if --show-output is used. Otherwise,
1317 # only print output if a job has been running for 60 minutes or more.
1318 if self._show_output:
1319 interval = 60
1320 else:
1321 interval = 60 * 60
1322 for target, job in self._jobs.iteritems():
1323 if job:
1324 last_timestamp = max(job.start_timestamp, job.last_output_timestamp)
1325 if last_timestamp + interval < current_time:
1326 self._PrintJob(job)
1327
1185 def _Finish(self, target): 1328 def _Finish(self, target):
1186 """Mark a target as completed and unblock dependecies.""" 1329 """Mark a target as completed and unblock dependecies."""
1187 for dep in self._deps_map[target]["provides"]: 1330 for dep in self._deps_map[target]["provides"]:
1188 del self._deps_map[dep]["needs"][target] 1331 del self._deps_map[dep]["needs"][target]
1189 if not self._deps_map[dep]["needs"]: 1332 if not self._deps_map[dep]["needs"]:
1190 self._Schedule(dep) 1333 self._Schedule(dep)
1191 self._deps_map.pop(target) 1334 self._deps_map.pop(target)
1192 1335
1193 def _Retry(self): 1336 def _Retry(self):
1194 if self._retry_queue: 1337 if self._retry_queue:
1195 target = self._retry_queue.pop(0) 1338 target = self._retry_queue.pop(0)
1196 self._Schedule(target) 1339 self._Schedule(target)
1197 print "Retrying emerge of %s." % target 1340 print "Retrying emerge of %s." % target
1198 1341
1199 def Run(self): 1342 def Run(self):
1200 """Run through the scheduled ebuilds. 1343 """Run through the scheduled ebuilds.
1201 1344
1202 Keep running so long as we have uninstalled packages in the 1345 Keep running so long as we have uninstalled packages in the
1203 dependency graph to merge. 1346 dependency graph to merge.
1204 """ 1347 """
1205 while self._deps_map: 1348 while self._deps_map:
1206 # Check here that we are actually waiting for something. 1349 # Check here that we are actually waiting for something.
1207 if (self._emerge_queue.empty() and 1350 if (self._emerge_queue.empty() and
1208 self._done_queue.empty() and 1351 self._job_queue.empty() and
1209 not self._jobs and 1352 not self._jobs and
1210 self._deps_map): 1353 self._deps_map):
1211 # If we have failed on a package, retry it now. 1354 # If we have failed on a package, retry it now.
1212 if self._retry_queue: 1355 if self._retry_queue:
1213 self._Retry() 1356 self._Retry()
1214 # If we have failed a package twice, just give up. 1357 # If we have failed a package twice, just give up.
1215 elif self._failed: 1358 elif self._failed:
1216 for failure, output in self._failed.items(): 1359 for failure in self._failed:
1217 print "Package failed: %s" % failure 1360 print "Package failed: %s" % failure
1218 print output
1219 PrintDepsMap(self._deps_map) 1361 PrintDepsMap(self._deps_map)
1220 print "Packages failed: %s" % " ,".join(self._failed.keys()) 1362 print "Packages failed: %s" % " ,".join(self._failed)
1221 sys.exit(1) 1363 sys.exit(1)
1222 # If we have dependency cycles. 1364 # If we have dependency cycles.
1223 else: 1365 else:
1224 print "Deadlock! Circular dependencies!" 1366 print "Deadlock! Circular dependencies!"
1225 PrintDepsMap(self._deps_map) 1367 PrintDepsMap(self._deps_map)
1226 sys.exit(1) 1368 sys.exit(1)
1227 1369
1228 try: 1370 try:
1229 target, retcode, output = self._done_queue.get(timeout=5) 1371 job = self._job_queue.get(timeout=5)
1230 except Queue.Empty: 1372 except Queue.Empty:
1231 # Print an update. 1373 # Print an update.
1232 self._Status() 1374 self._Status()
1233 continue 1375 continue
1234 1376
1235 self._jobs.discard(target) 1377 target = job.target
1236 1378
1237 # Print if necessary. 1379 if not job.done:
1238 if retcode != 0: 1380 self._jobs[target] = job
1239 print output 1381 print "Started %s (logged in %s)" % (target, job.filename)
1240 if retcode != 0: 1382 continue
1383
1384 # Print output of job
1385 if self._show_output or job.retcode != 0:
1386 self._PrintJob(job)
1387 os.unlink(job.filename)
1388 del self._jobs[target]
1389
1390 seconds = time.time() - job.start_timestamp
1391 details = "%s (in %dm%.1fs)" % (target, seconds / 60, seconds % 60)
1392
1393 # Complain if necessary.
1394 if job.retcode != 0:
1241 # Handle job failure. 1395 # Handle job failure.
1242 if target in self._failed: 1396 if target in self._failed:
1243 # If this job has failed previously, give up. 1397 # If this job has failed previously, give up.
1244 print "Failed %s. Your build has failed." % target 1398 print "Failed %s. Your build has failed." % details
1245 else: 1399 else:
1246 # Queue up this build to try again after a long while. 1400 # Queue up this build to try again after a long while.
1247 self._retry_queue.append(target) 1401 self._retry_queue.append(target)
1248 self._failed[target] = 1 1402 self._failed.add(target)
1249 print "Failed %s, retrying later." % target 1403 print "Failed %s, retrying later." % details
1250 else: 1404 else:
1251 if target in self._failed and self._retry_queue: 1405 if target in self._failed and self._retry_queue:
1252 # If we have successfully retried a failed package, and there 1406 # If we have successfully retried a failed package, and there
1253 # are more failed packages, try the next one. We will only have 1407 # are more failed packages, try the next one. We will only have
1254 # one retrying package actively running at a time. 1408 # one retrying package actively running at a time.
1255 self._Retry() 1409 self._Retry()
1256 1410
1257 print "Completed %s" % target 1411 print "Completed %s" % details
1258 # Mark as completed and unblock waiting ebuilds. 1412 # Mark as completed and unblock waiting ebuilds.
1259 self._Finish(target) 1413 self._Finish(target)
1260 1414
1261 # Print an update. 1415 # Print an update.
1262 self._Status() 1416 self._Status()
1263 1417
1264 1418
1265 def main(): 1419 def main():
1266 1420
1267 deps = DepGraphGenerator() 1421 deps = DepGraphGenerator()
(...skipping 30 matching lines...) Expand all
1298 deps.PrintTree(deps_tree) 1452 deps.PrintTree(deps_tree)
1299 1453
1300 deps_graph = deps.GenDependencyGraph(deps_tree, deps_info) 1454 deps_graph = deps.GenDependencyGraph(deps_tree, deps_info)
1301 1455
1302 # OK, time to print out our progress so far. 1456 # OK, time to print out our progress so far.
1303 deps.PrintInstallPlan(deps_graph) 1457 deps.PrintInstallPlan(deps_graph)
1304 if "--tree" in emerge.opts: 1458 if "--tree" in emerge.opts:
1305 PrintDepsMap(deps_graph) 1459 PrintDepsMap(deps_graph)
1306 1460
1307 # Run the queued emerges. 1461 # Run the queued emerges.
1308 scheduler = EmergeQueue(deps_graph, emerge, deps.package_db) 1462 scheduler = EmergeQueue(deps_graph, emerge, deps.package_db, deps.show_output)
1309 scheduler.Run() 1463 scheduler.Run()
1310 1464
1311 # Update world. 1465 # Update world.
1312 if ("--oneshot" not in emerge.opts and 1466 if ("--oneshot" not in emerge.opts and
1313 "--pretend" not in emerge.opts): 1467 "--pretend" not in emerge.opts):
1314 world_set = emerge.root_config.sets["selected"] 1468 world_set = emerge.root_config.sets["selected"]
1315 new_world_pkgs = [] 1469 new_world_pkgs = []
1316 root = emerge.settings["ROOT"] 1470 root = emerge.settings["ROOT"]
1317 final_db = emerge.depgraph._dynamic_config.mydbapi[root] 1471 final_db = emerge.depgraph._dynamic_config.mydbapi[root]
1318 for pkg in emerge.cmdline_packages: 1472 for pkg in emerge.cmdline_packages:
1319 for db_pkg in final_db.match_pkgs(pkg): 1473 for db_pkg in final_db.match_pkgs(pkg):
1320 print "Adding %s to world" % db_pkg.cp 1474 print "Adding %s to world" % db_pkg.cp
1321 new_world_pkgs.append(db_pkg.cp) 1475 new_world_pkgs.append(db_pkg.cp)
1322 if new_world_pkgs: 1476 if new_world_pkgs:
1323 world_set.update(new_world_pkgs) 1477 world_set.update(new_world_pkgs)
1324 1478
1325 # Update environment (library cache, symlinks, etc.) 1479 # Update environment (library cache, symlinks, etc.)
1326 if deps.board and "--pretend" not in emerge.opts: 1480 if deps.board and "--pretend" not in emerge.opts:
1327 portage.env_update() 1481 portage.env_update()
1328 1482
1329 print "Done" 1483 print "Done"
1330 1484
1331 if __name__ == "__main__": 1485 if __name__ == "__main__":
1332 main() 1486 main()
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698