Skip to content

Commit 7dff955

Browse files
authored
Crate Universe: crate.spec() supports path (#3596)
This is inspired by #3464
1 parent 362c9c8 commit 7dff955

File tree

17 files changed

+242
-48
lines changed

17 files changed

+242
-48
lines changed

.bazelci/presubmit.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -494,15 +494,15 @@ tasks:
494494
shell_commands: *no_bzlmod_shell_commands
495495
working_directory: examples/crate_universe_local_path
496496
run_targets:
497-
- "//:vendor_edit_test_out_of_tree"
497+
- "//:vendor_edit_test_out_of_tree_nobzlmod"
498498
crate_universe_local_path_in_tree_no_bzlmod:
499499
name: Crate Universe Local Path In Tree (No Bzlmod)
500500
platform: ubuntu2204
501501
bazel: *no_bzlmod_bazel_version
502502
shell_commands: *no_bzlmod_shell_commands
503503
working_directory: examples/crate_universe_local_path
504504
run_targets:
505-
- "//:vendor_edit_test_in_tree"
505+
- "//:vendor_edit_test_in_tree_nobzlmod"
506506
example_bindgen_toolchain:
507507
name: Example custom bindgen toolchain registration
508508
platform: ubuntu2204

crate_universe/extensions.bzl

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -646,6 +646,7 @@ def _generate_hub_and_spokes(
646646
output_dir = tag_path.get_child("splicing-output"),
647647
debug_workspace_dir = tag_path.get_child("splicing-workspace"),
648648
skip_cargo_lockfile_overwrite = cfg.skip_cargo_lockfile_overwrite,
649+
nonhermetic_root_bazel_workspace_dir = nonhermetic_root_bazel_workspace_dir,
649650
repository_name = cfg.name,
650651
)
651652

@@ -1399,7 +1400,7 @@ _spec = tag_class(
13991400
doc = "A list of features to use for the crate.",
14001401
),
14011402
"git": attr.string(
1402-
doc = "The Git url to use for the crate. Cannot be used with `version`.",
1403+
doc = "The Git url to use for the crate. Cannot be used with `version` or `path`.",
14031404
),
14041405
"lib": attr.bool(
14051406
doc = "If using `artifact = 'bin'`, additionally setting `lib = True` declares a dependency on both the package's library and binary, as opposed to just the binary.",
@@ -1408,6 +1409,9 @@ _spec = tag_class(
14081409
doc = "The explicit name of the package.",
14091410
mandatory = True,
14101411
),
1412+
"path": attr.string(
1413+
doc = "The local path of the remote crate. Cannot be used with `version` or `git`.",
1414+
),
14111415
"repositories": attr.string_list(
14121416
doc = "A list of repository names specified from `crate.from_cargo(name=...)` that this spec is applied to. Defaults to all repositories.",
14131417
default = [],
@@ -1419,7 +1423,7 @@ _spec = tag_class(
14191423
doc = "The git tag of the remote crate. Tied with the `git` param. Only one of branch, tag or rev may be specified. Specifying `rev` is recommended for fully-reproducible builds.",
14201424
),
14211425
"version": attr.string(
1422-
doc = "The exact version of the crate. Cannot be used with `git`.",
1426+
doc = "The exact version of the crate. Cannot be used with `git` or `path`.",
14231427
),
14241428
},
14251429
)

crate_universe/private/crate.bzl

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,8 @@ def _spec(
2727
git = None,
2828
branch = None,
2929
tag = None,
30-
rev = None):
30+
rev = None,
31+
path = None):
3132
"""A constructor for a crate dependency.
3233
3334
See [specifying dependencies][sd] in the Cargo book for more details.
@@ -36,15 +37,16 @@ def _spec(
3637
3738
Args:
3839
package (str, optional): The explicit name of the package (used when attempting to alias a crate).
39-
version (str, optional): The exact version of the crate. Cannot be used with `git`.
40+
version (str, optional): The exact version of the crate. Cannot be used with `git` or `path`.
4041
artifact (str, optional): Set to "bin" to pull in a binary crate as an artifact dependency. Requires a nightly Cargo.
4142
lib (bool, optional): If using `artifact = "bin"`, additionally setting `lib = True` declares a dependency on both the package's library and binary, as opposed to just the binary.
4243
default_features (bool, optional): Maps to the `default-features` flag.
4344
features (list, optional): A list of features to use for the crate
44-
git (str, optional): The Git url to use for the crate. Cannot be used with `version`.
45+
git (str, optional): The Git url to use for the crate. Cannot be used with `version` or `path`.
4546
branch (str, optional): The git branch of the remote crate. Tied with the `git` param. Only one of branch, tag or rev may be specified. Specifying `rev` is recommended for fully-reproducible builds.
4647
tag (str, optional): The git tag of the remote crate. Tied with the `git` param. Only one of branch, tag or rev may be specified. Specifying `rev` is recommended for fully-reproducible builds.
4748
rev (str, optional): The git revision of the remote crate. Tied with the `git` param. Only one of branch, tag or rev may be specified.
49+
path (str, optional): The local path of the remote crate. Cannot be used with `version` or `git`.
4850
4951
Returns:
5052
string: A json encoded string of all inputs
@@ -59,6 +61,7 @@ def _spec(
5961
"git": git,
6062
"lib": lib,
6163
"package": package,
64+
"path": path,
6265
"rev": rev,
6366
"tag": tag,
6467
"version": version,

crate_universe/private/crates_repository.bzl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ def _crates_repository_impl(repository_ctx):
9292
config_path = config_path,
9393
output_dir = repository_ctx.path("splicing-output"),
9494
skip_cargo_lockfile_overwrite = repository_ctx.attr.skip_cargo_lockfile_overwrite,
95+
nonhermetic_root_bazel_workspace_dir = nonhermetic_root_bazel_workspace_dir,
9596
repository_name = repository_ctx.name,
9697
)
9798

crate_universe/private/splicing_utils.bzl

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,7 @@ def splice_workspace_manifest(
124124
output_dir,
125125
repository_name,
126126
skip_cargo_lockfile_overwrite,
127+
nonhermetic_root_bazel_workspace_dir,
127128
debug_workspace_dir = None):
128129
"""Splice together a Cargo workspace from various other manifests and package definitions
129130
@@ -138,6 +139,7 @@ def splice_workspace_manifest(
138139
skip_cargo_lockfile_overwrite (bool): Whether to skip writing the cargo lockfile back after resolving.
139140
You may want to set this if your dependency versions are maintained externally through a non-trivial set-up.
140141
But you probably don't want to set this.
142+
nonhermetic_root_bazel_workspace_dir (path): The path to the current workspace root
141143
debug_workspace_dir (path): The location in which to save splicing outputs for future review.
142144
143145
Returns:
@@ -155,6 +157,8 @@ def splice_workspace_manifest(
155157
config_path,
156158
"--repository-name",
157159
repository_name,
160+
"--nonhermetic-root-bazel-workspace-dir",
161+
nonhermetic_root_bazel_workspace_dir,
158162
]
159163

160164
if cargo_lockfile:

crate_universe/src/cli/splice.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,13 @@ pub struct SpliceOptions {
7070
/// But you probably don't want to set this.
7171
#[clap(long)]
7272
pub skip_cargo_lockfile_overwrite: bool,
73+
74+
/// The path to the Bazel root workspace (i.e. the directory containing the WORKSPACE.bazel file or similar).
75+
/// BE CAREFUL with this value. We never want to include it in a lockfile hash (to keep lockfiles portable),
76+
/// which means you also should not use it anywhere that _should_ be guarded by a lockfile hash.
77+
/// You basically never want to use this value.
78+
#[clap(long)]
79+
pub nonhermetic_root_bazel_workspace_dir: Utf8PathBuf,
7380
}
7481

7582
/// Combine a set of disjoint manifests into a single workspace.
@@ -97,7 +104,7 @@ pub fn splice(opt: SpliceOptions) -> Result<()> {
97104

98105
// Splice together the manifest
99106
let manifest_path = prepared_splicer
100-
.splice(&splicing_dir)
107+
.splice(&splicing_dir, &opt.nonhermetic_root_bazel_workspace_dir)
101108
.with_context(|| format!("Failed to splice workspace {}", opt.repository_name))?;
102109

103110
// Use the existing lockfile if possible, otherwise generate a new one.

crate_universe/src/cli/vendor.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -217,7 +217,7 @@ pub fn vendor(opt: VendorOptions) -> anyhow::Result<()> {
217217

218218
// Splice together the manifest
219219
let manifest_path = splicer
220-
.splice_workspace()
220+
.splice_workspace(&opt.nonhermetic_root_bazel_workspace_dir)
221221
.context("Failed to splice workspace")?;
222222

223223
// Gather a cargo lockfile

crate_universe/src/config.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ use crate::utils::starlark::Label;
2222
use crate::utils::target_triple::TargetTriple;
2323

2424
/// Representations of different kinds of crate vendoring into workspaces.
25-
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
25+
#[derive(Debug, Serialize, Deserialize, Clone, Copy, PartialEq, Eq)]
2626
#[serde(rename_all = "lowercase")]
2727
pub(crate) enum VendorMode {
2828
/// Crates having full source being vendored into a workspace

crate_universe/src/rendering.rs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -863,9 +863,15 @@ impl Renderer {
863863
extra_deps: Select<BTreeSet<Label>>,
864864
) -> Select<BTreeSet<Label>> {
865865
Select::merge(
866-
deps.map(|dep| match dep.local_path {
867-
Some(path) => Label::from_str(&format!("//{}:{}", path, &dep.target)).unwrap(),
868-
_ => self.crate_label(&dep.id.name, &dep.id.version.to_string(), &dep.target),
866+
deps.map(|dep| {
867+
match (dep.local_path, self.config.vendor_mode) {
868+
// In local vendor mode, we use paths within the the repo.
869+
(Some(path), Some(VendorMode::Local)) => {
870+
Label::from_str(&format!("//{}:{}", path, &dep.target)).unwrap()
871+
}
872+
// If we're not vendoring source, or don't have a path for the dep, construct the label we expect.
873+
_ => self.crate_label(&dep.id.name, &dep.id.version.to_string(), &dep.target),
874+
}
869875
}),
870876
extra_deps,
871877
)

0 commit comments

Comments
 (0)