Ensure all publishable images in this dependency set exist on Docker Hub. Images are pushed using their spec as their tag. Args: pre_build: A callback to invoke with all dependency that are going to be built locally, invoked after their ca
(self, pre_build: Callable[[list[ResolvedImage]], None] | None = None)
| 1424 | dep.build(prep) |
| 1425 | |
| 1426 | def ensure(self, pre_build: Callable[[list[ResolvedImage]], None] | None = None): |
| 1427 | """Ensure all publishable images in this dependency set exist on Docker |
| 1428 | Hub. |
| 1429 | |
| 1430 | Images are pushed using their spec as their tag. |
| 1431 | |
| 1432 | Args: |
| 1433 | pre_build: A callback to invoke with all dependency that are going |
| 1434 | to be built locally, invoked after their cargo build is |
| 1435 | done, but before the Docker images are build and |
| 1436 | uploaded to DockerHub. |
| 1437 | """ |
| 1438 | num_deps = len(list(self)) |
| 1439 | if not num_deps: |
| 1440 | deps_to_build = [] |
| 1441 | else: |
| 1442 | with ThreadPoolExecutor(max_workers=num_deps) as executor: |
| 1443 | futures = list( |
| 1444 | executor.map( |
| 1445 | lambda dep: (dep, not dep.is_published_if_necessary()), self |
| 1446 | ) |
| 1447 | ) |
| 1448 | |
| 1449 | deps_to_build = [dep for dep, should_build in futures if should_build] |
| 1450 | |
| 1451 | prep = self._prepare_batch(deps_to_build) |
| 1452 | if pre_build: |
| 1453 | pre_build(deps_to_build) |
| 1454 | lock = Lock() |
| 1455 | built_deps: set[str] = set([dep.name for dep in self]) - set( |
| 1456 | [dep.name for dep in deps_to_build] |
| 1457 | ) |
| 1458 | |
| 1459 | def build_dep(dep): |
| 1460 | end_time = time.time() + 600 |
| 1461 | while True: |
| 1462 | if time.time() > end_time: |
| 1463 | raise TimeoutError( |
| 1464 | f"Timed out in {dep.name} waiting for {[dep2 for dep2 in dep.dependencies if dep2 not in built_deps]}" |
| 1465 | ) |
| 1466 | with lock: |
| 1467 | if all(dep2 in built_deps for dep2 in dep.dependencies): |
| 1468 | break |
| 1469 | time.sleep(0.01) |
| 1470 | for attempts_remaining in reversed(range(3)): |
| 1471 | try: |
| 1472 | dep.build(prep, push=dep.publish) |
| 1473 | with lock: |
| 1474 | built_deps.add(dep.name) |
| 1475 | break |
| 1476 | except Exception: |
| 1477 | if not dep.publish or attempts_remaining == 0: |
| 1478 | raise |
| 1479 | |
| 1480 | if deps_to_build: |
| 1481 | with ThreadPoolExecutor(max_workers=len(deps_to_build)) as executor: |
| 1482 | futures = [executor.submit(build_dep, dep) for dep in deps_to_build] |
| 1483 | for future in as_completed(futures): |
no test coverage detected