Skip to content

feat: support for ctx.actions.copy aliasing content - #30386

Open
thesayyn wants to merge 2 commits into
bazelbuild:masterfrom
thesayyn:copy-support
Open

feat: support for ctx.actions.copy aliasing content#30386
thesayyn wants to merge 2 commits into
bazelbuild:masterfrom
thesayyn:copy-support

Conversation

@thesayyn

Copy link
Copy Markdown
Contributor

Description

Adds ctx.actions.copy(output, target_file): a Starlark action that makes
target_file's content available at output (a second exec path), sharing its
digest, with no byte copy and no spawn. Unlike ctx.actions.symlink (which is
always a followable symlink), a copy requests content materialization: strategies
that can honor it — the hardlinking/copying sandbox, or remote execution via the
shared digest — place a real file at the output's path, so its realpath is
stable within the consuming tree (which tools such as Node.js require). Whether
and how that happens is up to the execution strategy; a purely symlinking sandbox
or non-sandboxed local execution does not provide it. The original is never a
declared input of the consumer — it sees only the copy.

Motivation

Rulesets that must present inputs at a canonical layout — most visibly rules_js
copying every source into bazel-bin (copy_to_bin), and similarly rules_python
and rules_oci — do so today with a byte copy per file. The dominant cost is the
per-action work (spawns, uploads), not the bytes. ctx.actions.copy gives the
same observable result (a content-identical file at a new path) while avoiding the
duplication wherever the execution strategy can.

Design: bazelbuild/proposals#419

Build API Changes

Yes — adds the ctx.actions.copy Starlark method.

  1. Discussed in a design doc/issue: yes, Proposal: add support for artifact aliasing proposals#419.
  2. Backward compatible: yes. Purely additive; no existing behavior changes
    (ordinary symlink and copy actions are untouched).
  3. Breaking change: no.

Checklist

  • I have added tests for the new use cases (if any).
  • I have updated the documentation (if applicable).

Release Notes

RELNOTES[NEW]: ctx.actions.copy(output, target_file) makes a file's content
available at a second path without duplicating bytes (realized as a hard
link/copy, or via the shared digest on remote execution) — an alternative to
copying for tools that require real files rather than symlinks.

@thesayyn
thesayyn requested review from a team as code owners July 21, 2026 04:37
@thesayyn
thesayyn requested review from gregestren and removed request for a team July 21, 2026 04:37
@github-actions github-actions Bot added team-Performance Issues for Performance teams team-Configurability platforms, toolchains, cquery, select(), config transitions team-Local-Exec Issues and PRs for the Execution (Local) team team-Remote-Exec Issues and PRs for the Execution (Remote) team awaiting-review PR is awaiting review from an assigned reviewer team-Rules-API API for writing rules/aspects: providers, runfiles, actions, artifacts labels Jul 21, 2026
@thesayyn
thesayyn force-pushed the copy-support branch 4 times, most recently from d32dfa2 to 4c41310 Compare July 21, 2026 05:40
Adds ctx.actions.copy(output, target_file): makes target_file's content
available at output (a second exec path), sharing its digest, with no byte
copy and no spawn.

Unlike ctx.actions.symlink, which plants a followable symbolic link that
resolves back to the target's location, ctx.actions.copy only declares the
relationship and defers materialization to sandbox/spawn creation -- the
execution strategy places the target's content at the output's own path (hard
link, copy, or the shared digest on remote execution), so its realpath stays
inside the consuming tree (which tools such as Node.js require). Strategies
that cannot materialize content (a purely symlinking sandbox or non-sandboxed
local execution) fall back to a symlink. The original is never a declared
input of the consumer -- it sees only the copy.

Reuses the existing resolved-path metadata rather than adding new machinery:
FileArtifactValue.isContentCopy() marks the value (ordinary symlinks are
unchanged), a declaration-only CopyAction injects it, and the remote
prefetcher and the local sandbox stage the content from the recorded source.

Design: bazelbuild/proposals#419
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

awaiting-review PR is awaiting review from an assigned reviewer team-Configurability platforms, toolchains, cquery, select(), config transitions team-Local-Exec Issues and PRs for the Execution (Local) team team-Performance Issues for Performance teams team-Remote-Exec Issues and PRs for the Execution (Remote) team team-Rules-API API for writing rules/aspects: providers, runfiles, actions, artifacts

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant