Skip to content

Commit 0a7eefa

Browse files
committed
Run output
1 parent bb1c6bf commit 0a7eefa

3 files changed

Lines changed: 42 additions & 2 deletions

File tree

out.dvc

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
outs:
2-
- path: out
2+
- md5: 4f98f59e877ecb84ff75ef0fab45bac5
3+
size: 3
4+
hash: md5
5+
path: out
36
meta:
47
computation:
58
cmd: echo "v1" > out

src/dvx/cli/run_cmd.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,10 @@
1717
@click.option("--no-provenance", is_flag=True, help="Don't include provenance in .dvc files.")
1818
@click.option("-p", "--push", type=click.Choice(["each", "end"]), default=None, help="Push strategy: 'each' (after each commit) or 'end' (once at finish). Also via $DVX_PUSH.")
1919
@click.option("-P", "--no-cache-push", is_flag=True, help="With --push, only git-push; don't push cache blobs to the remote.")
20+
@click.option("-D", "--no-pull-deps", is_flag=True, help="Don't auto-fetch materializable trans-deps from remote (default: try fetch before rerunning).")
2021
@click.option("-U", "--no-prune-fresh", is_flag=True, help="Walk full upstream chain even past fresh artifacts (default: stop at fresh).")
2122
@click.option("-v", "--verbose", is_flag=True, help="Show detailed output.")
22-
def run_cmd(targets, force, force_upstream, cached, jobs, commit, dry_run, no_provenance, push, no_cache_push, no_prune_fresh, verbose):
23+
def run_cmd(targets, force, force_upstream, cached, jobs, commit, dry_run, no_provenance, push, no_cache_push, no_pull_deps, no_prune_fresh, verbose):
2324
"""Execute artifact computations from .dvc files.
2425
2526
Run computations defined in .dvc files, respecting dependencies and
@@ -63,6 +64,7 @@ def run_cmd(targets, force, force_upstream, cached, jobs, commit, dry_run, no_pr
6364
push=push or "never",
6465
cache_push=not no_cache_push,
6566
prune_fresh=not no_prune_fresh,
67+
pull_deps=not no_pull_deps,
6668
)
6769

6870
try:

src/dvx/run/executor.py

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,12 @@ class ExecutionConfig:
4747
# auto-disabled when --force-upstream patterns are set (we have to walk to
4848
# find pattern matches).
4949
prune_fresh: bool = True
50+
# Try to materialize "materializable" stages (deps fresh, output missing
51+
# locally) from the configured remote before running the cmd. CI runners
52+
# on fresh checkouts otherwise rebuild every stage from upstream roots
53+
# even when the cache already holds byte-identical outputs.
54+
# See specs/done/run-auto-pull.md.
55+
pull_deps: bool = True
5056

5157

5258
def _matches_patterns(path: str, patterns: list[str]) -> bool:
@@ -258,8 +264,37 @@ def _should_run(self, artifact: Artifact) -> tuple[bool, str]:
258264
if fresh:
259265
return False, reason
260266

267+
# Materializable trans-deps: if the output is just missing locally
268+
# but the deps would otherwise let this skip, try fetching the .dvc's
269+
# recorded hash from the remote cache. On success, re-evaluate and
270+
# short-circuit the rerun. See specs/done/run-auto-pull.md.
271+
if self.config.pull_deps and reason == "output missing":
272+
if self._try_materialize_from_remote(path):
273+
fresh2, reason2 = is_output_fresh(Path(path))
274+
if fresh2:
275+
return False, f"fetched ({reason2})"
276+
261277
return True, reason
262278

279+
def _try_materialize_from_remote(self, path: str) -> bool:
280+
"""Pull ``path``'s recorded hash from the remote into local cache and
281+
materialize the workspace file. Returns True on success.
282+
283+
Non-fatal: any failure (no remote configured, blob missing remotely,
284+
network error) just logs at verbose and returns False so the stage
285+
falls through to its normal rerun.
286+
"""
287+
try:
288+
from dvx import Repo
289+
dvc_path = f"{path}.dvc"
290+
with Repo() as repo:
291+
repo.pull(targets=[dvc_path])
292+
except Exception as e:
293+
if self.config.verbose:
294+
self._log(f" ↓ {path}: pull failed ({e})")
295+
return False
296+
return True
297+
263298
def _execute_level(self, artifacts: list[Artifact]) -> list[ExecutionResult]:
264299
"""Execute all artifacts in a level in parallel.
265300

0 commit comments

Comments
 (0)