Build the given list of targets, if necessary. Builds in parallel using whatever jobserver tokens can be obtained. Args: targets: a list of target filenames to consider building. shouldbuildfunc: a function(target) which determines whether the given target needs to be b
(targets, shouldbuildfunc)
| 469 | |
| 470 | |
| 471 | def run(targets, shouldbuildfunc): |
| 472 | """Build the given list of targets, if necessary. |
| 473 | |
| 474 | Builds in parallel using whatever jobserver tokens can be obtained. |
| 475 | |
| 476 | Args: |
| 477 | targets: a list of target filenames to consider building. |
| 478 | shouldbuildfunc: a function(target) which determines whether the given |
| 479 | target needs to be built, as of the time it is called. |
| 480 | |
| 481 | Returns: |
| 482 | 0 if all necessary targets returned exit code zero; nonzero otherwise. |
| 483 | """ |
| 484 | retcode = [0] # a list so that it can be reassigned from done() |
| 485 | if env.v.SHUFFLE: |
| 486 | import random |
| 487 | random.shuffle(targets) |
| 488 | |
| 489 | locked = [] |
| 490 | |
| 491 | def job_exited(t, rv): |
| 492 | if rv: |
| 493 | retcode[0] = 1 |
| 494 | |
| 495 | if env.v.TARGET and not env.v.UNLOCKED: |
| 496 | me = os.path.join(env.v.STARTDIR, |
| 497 | os.path.join(env.v.PWD, env.v.TARGET)) |
| 498 | myfile = state.File(name=me) |
| 499 | selflock = state.Lock(state.LOG_LOCK_MAGIC + myfile.id) |
| 500 | else: |
| 501 | selflock = myfile = me = None |
| 502 | |
| 503 | for t in targets: |
| 504 | if '\n' in t: |
| 505 | err('%r: filenames containing newlines are not allowed.\n' % t) |
| 506 | return 204 |
| 507 | |
| 508 | def cheat(): |
| 509 | if not selflock: |
| 510 | return 0 |
| 511 | selflock.trylock() |
| 512 | if not selflock.owned: |
| 513 | # redo-log already owns it: let's cheat. |
| 514 | # Give ourselves one extra token so that the "foreground" log |
| 515 | # can always make progress. |
| 516 | return 1 |
| 517 | else: |
| 518 | # redo-log isn't watching us (yet) |
| 519 | selflock.unlock() |
| 520 | return 0 |
| 521 | |
| 522 | # In the first cycle, we just build as much as we can without worrying |
| 523 | # about any lock contention. If someone else has it locked, we move on. |
| 524 | seen = {} |
| 525 | lock = None |
| 526 | for t in targets: |
| 527 | if not t: |
| 528 | err('cannot build the empty target ("").\n') |