Squashed 'third_party/rules_rust/' changes from bf59038cac..078c6908fc

078c6908fc add cc_common.link support for rust_library and rust_test (#1490)
c07aef0287 Skip supplying rpaths on Fuchsia (#1511)
6ee7c80bdb Propagate rustc_env{,_files} from rust_test.crate (#1443)
1cd0788d2a Apply get_lib_name correctly to the C++ runtime libraries (#1508)
90808f0dc4 Minor cleanup to documentation (#1505)
735640f2df Enable rust-analyzer tests on windows. (#1506)
0f34573166 Updated rules_rust to version 0.9.0 (#1503)
9b61b49934 Promoted crate_universe to non-experimental (#1504)
76360dd354 Implement rules archive release artifact in github action. (#1501)
4e5fac5980 Do not pass `--Clink-arg=-l` for libstd and libtest (#1500)
6c38934636 pipelining: add the ability to disable pipelining for a single rule. (#1499)
867fc37c17 rules_rust: enable pipelined compilation. (#1275)
c97f255dfe Delete deprecated targets (#1496)
43b42884a7 Updated examples to use crate_universe (#1494)
0ffde973e8 Updated `//util/import` to use crate_universe (#1492)
83a03ab03e Updated proto rules to fetch dependencies using crate_universe (#1491)
67e204ff22 fix: `rust_doc_test` failure to find params file (#1418)
0fc834bdfa Updated all toolchain_type definitions to be named `toolchain_type`. (#1479)
3be056a7a3 toolchain files: ensure test depends on std (#1486)
228ebfa6eb Updated rules_rust to version `0.8.1`. (#1484)
685dfda497 Fixed use of rust-analyzer with rust_static_library and rust_shared_library (#1482)
2d7f94543f Fix rust-analyzer being unable to find rust sysroot sources. (#1483)
81a77acde2 Updated rules_rust to version `0.8.0`. (#1472)
caad908848 Give useful error on missing workspace manifest (#1475)
0e86b9dd30 Added `rust_analyzer_toolchain` and repository rules for creating one (#1455)
838e4ea828 Update docs on lockfiles (#1477)
fce1222628 Fix typo in function name (#1478)
1929bfbc3e Added Rust version 1.62.1 (#1476)
9a8e878d3d Fix `rust_binary_without_process_wrapper` build with `--stamp` (#1473)
25baabc205 Updated bindgen version (#1470)
8c9d5c7051 Updated rust-analyzer generator to use clap (#1471)
6d8009dbc8 Update `//bindgen` to use `crate_universe` (#1440)
67c97d44ff Updated `tools/rust_analyzer` to use `crate_universe`. (#1448)
6c285eb28e Updated `wasm_bindgen` rules dependencies. (#1464)
82a437cc17 Fixed crate_universe lockfile checks for crates_repository rule (#1468)
e83d5f3c77 Limit coverage to requested files (#1467)
daff327ea7 Stamp only binaries by default (#1452)
adc80a301d Cleanup crate_universe dependency macros (#1460)
824b121acc Updated header of crate_universe generated files to include a regen command (#1461)
d44e1d8363 feat: add `rustc_flags` attr to `rust_doc` rule (#1458)
6b54feb0ff add a way to distinguish proc-macro deps (#1420)
6070b3c9f4 Fixed missing items in distro artifact (#1450)
1e83e74159 do not add proc-macro deps to transitive_link_search_paths (#1424)
ced94dec1b Fix @libgit2 (#1457)
03d1d5e4ac Add extra_rustc_flag and extra_exec_rustc_flag (#1413)
711adc7985 crate_universe: shorten `crate_universe_crate_index` to `cui` (#1454)
8cb9247f18 Replaced small genrules with uses of bazel_skylib (#1451)
38e841aece Upgrade stardoc (#1444)
674762f66a Updated toolchain repository rules to represent one toolchain per repo (#1442)
b22a6e1416 Re-enable disabled windows jobs in CI (#1353)
2fb94c48fd docs: Update homepage to use latest version (#1441)
389c58fcb1 Updated rules_rust to version `0.7.0`. (#1436)
60f26d49d8 exclude `BUILD` and `WORKSPACE` files from generated crate_universe targets (#1437)
26344d4cd7 Have rust_test put its compilation outputs in a subdirectory (#1434)
8b0f644122 Updated crate_universe version to `0.4.0`. (#1435)
adf92b1534 update crate_universe `--repin` args to not require values. (#1433)
da75146d0a Do not attempt to instrument rust code for coverage if rust_toolchain.llvm-cov is None (#1432)
bde2c36821 Added Rust 1.62.0 (#1427)
7056f22bd0 Fixed crate_universe not finding target library names for "rlib"s (#1429)
3d65214d23 crate_universe support for individually updating packages. (#1426)
5a9d999db9 Updated `attr.label` attribute defaults to use `Label` constructor (#1422)
52fc70145a Added `TemplateVariableInfo` to `rust_toolchain`. (#1416)
7465c1aa29 Add test coverage support (#1324)
c5c3603da6 Bump the min supported bazel version (#1414)
937bdc9d05 Add a `cargo_dep_env` rule for setting build.rs environment variables (#1415)
91466fc0d1 Updated `rules_rust` version to `0.6.0`. (#1397)
97264b79d5 Update wasm_bindgen to use crate universe. (#1398)
d3197a65c5 Updated crate_universe version (to `0.3.0`) and dependencies (#1409)
a15e67d666 Deleted "extra workspace member" functionality from crate_universe (#1406)
5910a7585a Use a vec, not set for rustc_flags for crate_universe annotations (#1404)
3aa88ab067 Deleted deprecated `rust_analyzer` rule. (#1405)
7adf7210d0 cargo: Fix handling of relative sysroots (#1371)
57607239ec Enable rustfmt CI for Windows. (#1403)
30e68b49be Added more "ignore" tags to rustfmt and clippy rules. (#1400)
53ad14eead Added support for vendoring external manifests (#1381)
ff243c6ef0 Reorganized rustfmt source tree (#1399)
94e0044afe Refactored the Rustfmt tool to work cross-platform (#1375)
8fca438124 Ran clang-format on all C++ sources (#1396)
e765719e29 Added TemplateVariableInfo to rust_toolchain (#1377)
81590f4b6a Fixed Clippy bug with `--@rules_rust//:clippy_flags`. (#1392)
d77b9f7c6a Use  `target_compatible_with` to make `macos` with `Xcode` happy (#1391)
ec27dbe310 Added comments to internal function (#1378)
a9dd2f9200 Removed deprecated file (#1380)
16175c881c Renamed toolchain files targets (#1376)
c7cb5bd7a8 Support crates that have mix of generated and nongenerated inputs (#1340)
521e649ff4 Avoid using common substrings as encodings. (#1370)
28ac6b133d Use a more compact encoding in the `import` macro. (#1365)
3a099bfa97 Fix incorrect assertion in test_env_launcher test (#1368)
4661093fb1 Use target instead of rule in rust_register_toolchains edition docs (#1366)
652f2802e3 Add `env` attribute to `rust_toolchain`. (#1363)
9520f37f1e Update rules_perl in examples (#1364)
1b451c301e Add armv7-linux-androideabi tier 2 triple (#1362)
0265c293f1 Ensure crate_features to be included correctly in rust_project.json (#1356)
121d65fe6a Updated `rules_rust` version to `0.5.0` (#1360)
aca4ec1a0f crate_universe: fix typo (#1314)
69ca2611c5 Don't leak native dependencies of proc_macro (#1359)
4c7f08b8b9 Fixed missing docs (#1358)
e48bec94de feat: build script toolchains annotations (#1344)
ffb946f4b7 Ensure memchr is linked after libobject (#1349)
edca1d8042 Add developing notes for crate_universe (#1351)
120f911d2f Updated rust_bindgen dependencies API (#1354)
42c4528a5f Added Rust 1.61.0 (#1347)
c05e0c6ab1 Fixed fetch_shas script to correctly include .gz and .xz extensions (#1355)
9770b0dd75 Update apple_support (#1346)
87eb807e67 Added support for Rust 1.61.0 to crate_universe (#1348)
84c1d42128 Temporarily disable windows job in CI. (#1352)
421d30e4ff Remove unnecessary `crate_name` usage in `rust_test_suite`. (#1345)
10185339dd Build `rust_test` targets with `crate` using the same crate name as the underlying library target. (#1332)
0049ce3884 Add support for riscv32 targets (#1323)
3aa6de3c63 remove experimental_use_whole_archive_for_native_deps (#1338)
a066bfed46 Replace slashes with underscores in default crate names. (#1336)
1b91e592d5 Revert "Replace slashes with underscores in default crate names. (#1334)" (#1335)
51f8e302e9 "sandwich" rlibs between native deps in linker order (#1333)
df354904a1 Replace slashes with underscores in default crate names. (#1334)
21eed19188 Bump version to 0.4.0 (#1329)
d3d9abac4d Support . workspace member (#1326)
fccaae3055 Error calling `all_crate_deps` without `Cargo.toml` (#1327)
d7c532cb78 Updated wasm_bindgen dependencies API (#1313)
fb4d5546ea Updated wasm_bindgen rules to only require core `rules_nodejs` rules (#1311)
1590670ae1 Prevents running of clippy on bindgen targets (#1320)
73d0164a34 Add support for aarch64-apple-ios-sim (#1304)
61eee54c73 Add bazel-* directories in cargo_manifest_dir/external_crate to gitignore (#1279)
42f78f25e1 crate_universe: Improved documentation (#1305)
bddc4bd94a Silence warnings for example/test dependencies (#1312)
b04fe3b21f Use tinyjson from crates.io instead of github.com. (#1309)
1cab691d14 Remove doc about STATIC_RUST_URL env var. (#1306)
d86e06a884 Don't propagate non-shared transitive linker inputs from `rust_static|shared_library` (#1299)
5abeb93333 Don't emit `CrateInfo` from `rust_static_library` and `rust_shared_library` (#1298)
0175a1b7aa fix for using a nightly channel after https://github.com/bazelbuild/rules_rust/commit/841fc6fb82141576d91aecb1d3f2656d58b0ab71 (#1302)
e07881fa22 Updated crate_universe docs (#1301)
c63ad973f1 rustc: fix a conditional (#1300)
a6f332fcbe Use __EXEC_ROOT__ paths for genfiles in rust_analyzer aspect (#1293)
97de47df51 Remove 'triple' field from triple struct in favor of 'str' (#1297)
58627f59eb Make get_host_triple public to get a triple from Bazel's repository_ctx (#1289)
612f4362bc Updated `rules_rust` version to `0.3.1` (#1296)
26fa5a15de Fixed build issues in release artifact (#1295)
48bb32f817 crate_universe: Added tests for serialized config files. (#1291)
841fc6fb82 Enable xz archives (#1284)
f7cb22efa6 feat(#514): pass extra flags to clippy (#1264)
e9f8b48711 Updated `rules_rust` version to `0.3.0` (#1288)
c900e1c66c Revert "Add workaround for arm vs armv7 android issue (#1259)" (#1290)
01ebef2fb9 Remove DEFAULT_RUST_EDITION (#1256)
03a70796ab Outside of examples, fill in all `edition` attrs (#1257)
207ee4fbcf feat: support extra deps in rust_doc_test (#1286)
4e7d114a8e Fix typo in render config doc (#1281)
db17f291d3 Fix crate annotation anchor (#1282)
fdb6851a92 Fix target name in `rust_test` example. (#1280)
4fb6e40147 Don't leak additive build file content across crates (#1278)
965044ae2b Remove `rust_test` example which doesn't build. (#1267)
f6e7e0a93f add a stopgap experimental_use_whole_archive_for_native_deps attribute (#1269)
34fd46756a process_wrapper: add support for terminating rustc after it emits rmeta. (#1207)
b778fca0ac crate_universe: propagate build_script_tools (#1266)
f6f27a8734 Add workaround for arm vs armv7 android issue (#1259)
c3f56c2d50 Add the BUILD.bazel file to the wasm_bindgen distro filegroup target (#1246) (#1261)
1f2e6231de Set edition for process_wrapper and cargo_build_script_runner (#1254)
55790492ac Updated Rust to 1.60.0 (#1247)
b594f90f17 Workaround for issue in linux Cargo binaries (#1252)
8f0dd9042e rust_test_suite: ensure crate names are valid (#1248)
4144ddeb9c Updating `rules_rust` version to `0.2.1` (#1243)
65cad76a52 Fixed proto package in release artifact (#1241)
4d8de6e361 Updated repository pin in the docs (#1240)
e5a3970754 Updating `rules_rust` version to `0.2.0` (#1235)
d061bf640e Updated `crate_universe` version to `0.2.0` (#1239)
c0505da0d2 Replace `rust_repositories` with `rust_register_toolchains` in docs (#1237)
145ad7609f Fixed `crates_repository` deleting `.cargo/config.toml` files. (#1227)
20066b05e2 fix: distribute `//tools/rust_analyzer` (#1234)
b58ce89603 Enabled `rust_doc_test` for `crate_universe` (#1232)
d2e2470cbf Fix some unit tests to run from another workspace (#1226)
b03aee039a Fixed `crate_universe` clippy defects (#1228)
41b39f0c99 add bots using lld (and examples with clang as a drive by) (#1221)
84e98e4d2f don't emit --codegen={metadata,extra-filename} for rust_static_library and rust_shared_library (#1222)
e48c834a40 Renamed `crate_index` repository to `crate_universe_crate_index` (#1217)
99b4b2574f fix use of stamping in rust_binary_without_process_wrapper (#1218)
8df4517d37 Add NUM_JOBS env var to cargo build scripts (#1216)
628e85e70f Restrucutred `crate_universe` dependency macros (#1208)
e3d67a0a10 Updated docs to guide users to using releases (#1213)
fd912e644c Updated crate_universe docs. (#1212)
cde4c0826c Delete deprecated `rules` targets (#1210)
26e01c8386 cache the release archive in release actions (#1201)
3205c9d846 Updated crate_universe setup guide (#1202)
c078494678 Don't leak deps from rust_proc_macro (#1206)
7c865ffeb1 Build `_import_macro_dep` in `exec` mode (#1203)
635da93206 Updating `rules_rust` version to `0.1.0`. (#1198)
6c797c9070 disable advanced features of C++ rules (#1200)
86d47a1bba Tweak import macro bootstrap to trick rust analyzer aspect (#1179)
80d197205a Added release workflow (#1195)
cd44b3670a Added support for producing distribution archives (#1194)
a665447989 Traverse custom alias-like rules in the rust analyzer aspect (#1190)
4504983fa9 Add a test showing that rust_analayzer aspect traverses aliases (#1188)
297dd18215 Updated `crate_universe` to version `0.1.0`. (#1197)
0d9c7d5e1b Specify root target for rust_analyzer test (#1189)
4a0352fecd Updated `crate_universe` dependencies (#1196)
5126479254 Fixed crate_universe release tools (#1193)
e840400eb6 Remove last remains of use_process_wrapper flag. (#1192)
eb7db68d96 Fix iOS linker arguments (#1186)
de726a10c9 Create internal rust_binary rule instead of using transitions (#1187)
5e6ad9f638 Regenerated `cargo-raze` outputs with v0.15.0 (#1184)
980b662843 add static_library to get_preferred_artifact with pic (#1183)
97fd329540 Populate CFLAGS and CXXFLAGS when invoking build script. (#1081)

git-subtree-dir: third_party/rules_rust
git-subtree-split: 078c6908fc32c168b58e72cc3884dd8e30419e3a
Signed-off-by: Brian Silverman <bsilver16384@gmail.com>
Change-Id: Ifc218edaa852263bd76835ee7de44de07c08aec2
diff --git a/crate_universe/src/cli/generate.rs b/crate_universe/src/cli/generate.rs
index 67ae868..3fdc97e 100644
--- a/crate_universe/src/cli/generate.rs
+++ b/crate_universe/src/cli/generate.rs
@@ -1,13 +1,14 @@
 //! The cli entrypoint for the `generate` subcommand
 
+use std::fs;
 use std::path::PathBuf;
 
-use anyhow::{bail, Result};
+use anyhow::{bail, Context as AnyhowContext, Result};
 use clap::Parser;
 
 use crate::config::Config;
 use crate::context::Context;
-use crate::lockfile::{is_cargo_lockfile, lock_context, write_lockfile, LockfileKind};
+use crate::lockfile::{lock_context, write_lockfile};
 use crate::metadata::load_metadata;
 use crate::metadata::Annotations;
 use crate::rendering::{write_outputs, Renderer};
@@ -15,7 +16,7 @@
 
 /// Command line options for the `generate` subcommand
 #[derive(Parser, Debug)]
-#[clap(about, version)]
+#[clap(about = "Command line options for the `generate` subcommand", version)]
 pub struct GenerateOptions {
     /// The path to a Cargo binary to use for gathering metadata
     #[clap(long, env = "CARGO")]
@@ -35,11 +36,11 @@
 
     /// The path to either a Cargo or Bazel lockfile
     #[clap(long)]
-    pub lockfile: PathBuf,
+    pub lockfile: Option<PathBuf>,
 
-    /// The type of lockfile
+    /// The path to a [Cargo.lock](https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html) file.
     #[clap(long)]
-    pub lockfile_kind: LockfileKind,
+    pub cargo_lockfile: PathBuf,
 
     /// The directory of the current repository rule
     #[clap(long)]
@@ -54,7 +55,7 @@
     #[clap(long)]
     pub repin: bool,
 
-    /// The path to a Cargo metadata `json` file.
+    /// The path to a Cargo metadata `json` file. This file must be next to a `Cargo.toml` and `Cargo.lock` file.
     #[clap(long)]
     pub metadata: Option<PathBuf>,
 
@@ -67,25 +68,19 @@
     // Load the config
     let config = Config::try_from_path(&opt.config)?;
 
-    // Determine if the dependencies need to be repinned.
-    let mut should_repin = opt.repin;
-
-    // Cargo lockfiles must always be repinned.
-    if is_cargo_lockfile(&opt.lockfile, &opt.lockfile_kind) {
-        should_repin = true;
-    }
-
     // Go straight to rendering if there is no need to repin
-    if !should_repin {
-        let context = Context::try_from_path(opt.lockfile)?;
+    if !opt.repin {
+        if let Some(lockfile) = &opt.lockfile {
+            let context = Context::try_from_path(lockfile)?;
 
-        // Render build files
-        let outputs = Renderer::new(config.rendering).render(&context)?;
+            // Render build files
+            let outputs = Renderer::new(config.rendering).render(&context)?;
 
-        // Write the outputs to disk
-        write_outputs(outputs, &opt.repository_dir, opt.dry_run)?;
+            // Write the outputs to disk
+            write_outputs(outputs, &opt.repository_dir, opt.dry_run)?;
 
-        return Ok(());
+            return Ok(());
+        }
     }
 
     // Ensure Cargo and Rustc are available for use during generation.
@@ -105,20 +100,13 @@
     };
 
     // Load Metadata and Lockfile
-    let (cargo_metadata, cargo_lockfile) = load_metadata(
-        metadata_path,
-        if is_cargo_lockfile(&opt.lockfile, &opt.lockfile_kind) {
-            Some(&opt.lockfile)
-        } else {
-            None
-        },
-    )?;
+    let (cargo_metadata, cargo_lockfile) = load_metadata(metadata_path)?;
 
     // Copy the rendering config for later use
     let render_config = config.rendering.clone();
 
     // Annotate metadata
-    let annotations = Annotations::new(cargo_metadata, cargo_lockfile, config.clone())?;
+    let annotations = Annotations::new(cargo_metadata, cargo_lockfile.clone(), config.clone())?;
 
     // Generate renderable contexts for earch package
     let context = Context::new(annotations)?;
@@ -130,13 +118,18 @@
     write_outputs(outputs, &opt.repository_dir, opt.dry_run)?;
 
     // Ensure Bazel lockfiles are written to disk so future generations can be short-circuted.
-    if matches!(opt.lockfile_kind, LockfileKind::Bazel) {
+    if let Some(lockfile) = opt.lockfile {
         let splicing_manifest = SplicingManifest::try_from_path(&opt.splicing_manifest)?;
 
-        let lockfile = lock_context(context, &config, &splicing_manifest, cargo_bin, rustc_bin)?;
+        let lock_content =
+            lock_context(context, &config, &splicing_manifest, cargo_bin, rustc_bin)?;
 
-        write_lockfile(lockfile, &opt.lockfile, opt.dry_run)?;
+        write_lockfile(lock_content, &lockfile, opt.dry_run)?;
     }
 
+    // Write the updated Cargo.lock file
+    fs::write(&opt.cargo_lockfile, cargo_lockfile.to_string())
+        .context("Failed to write Cargo.lock file back to the workspace.")?;
+
     Ok(())
 }
diff --git a/crate_universe/src/cli/query.rs b/crate_universe/src/cli/query.rs
index 668f64f..19087ab 100644
--- a/crate_universe/src/cli/query.rs
+++ b/crate_universe/src/cli/query.rs
@@ -13,7 +13,7 @@
 
 /// Command line options for the `query` subcommand
 #[derive(Parser, Debug)]
-#[clap(about, version)]
+#[clap(about = "Command line options for the `query` subcommand", version)]
 pub struct QueryOptions {
     /// The lockfile path for reproducible Cargo->Bazel renderings
     #[clap(long)]
diff --git a/crate_universe/src/cli/splice.rs b/crate_universe/src/cli/splice.rs
index cb8ba20..213ee34 100644
--- a/crate_universe/src/cli/splice.rs
+++ b/crate_universe/src/cli/splice.rs
@@ -2,34 +2,37 @@
 
 use std::path::PathBuf;
 
+use anyhow::Context;
 use clap::Parser;
 
 use crate::cli::Result;
-use crate::metadata::{write_metadata, Generator, MetadataGenerator};
-use crate::splicing::{
-    generate_lockfile, ExtraManifestsManifest, Splicer, SplicingManifest, WorkspaceMetadata,
-};
+use crate::metadata::{write_metadata, CargoUpdateRequest, Generator, MetadataGenerator};
+use crate::splicing::{generate_lockfile, Splicer, SplicingManifest, WorkspaceMetadata};
 
 /// Command line options for the `splice` subcommand
 #[derive(Parser, Debug)]
-#[clap(about, version)]
+#[clap(about = "Command line options for the `splice` subcommand", version)]
 pub struct SpliceOptions {
     /// A generated manifest of splicing inputs
     #[clap(long)]
     pub splicing_manifest: PathBuf,
 
-    /// A generated manifest of "extra workspace members"
-    #[clap(long)]
-    pub extra_manifests_manifest: PathBuf,
-
-    /// A Cargo lockfile (Cargo.lock).
+    /// The path to a [Cargo.lock](https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html) file.
     #[clap(long)]
     pub cargo_lockfile: Option<PathBuf>,
 
-    /// The directory in which to build the workspace. A `Cargo.toml` file
-    /// should always be produced within this directory.
+    /// The desired update/repin behavior
+    #[clap(long, env = "CARGO_BAZEL_REPIN", default_missing_value = "true")]
+    pub repin: Option<CargoUpdateRequest>,
+
+    /// The directory in which to build the workspace. If this argument is not
+    /// passed, a temporary directory will be generated.
     #[clap(long)]
-    pub workspace_dir: PathBuf,
+    pub workspace_dir: Option<PathBuf>,
+
+    /// The location where the results of splicing are written.
+    #[clap(long)]
+    pub output_dir: PathBuf,
 
     /// If true, outputs will be printed instead of written to disk.
     #[clap(long)]
@@ -52,39 +55,62 @@
 pub fn splice(opt: SpliceOptions) -> Result<()> {
     // Load the all config files required for splicing a workspace
     let splicing_manifest = SplicingManifest::try_from_path(&opt.splicing_manifest)?;
-    let extra_manifests_manifest =
-        ExtraManifestsManifest::try_from_path(opt.extra_manifests_manifest)?;
+
+    // Determine the splicing workspace
+    let temp_dir;
+    let splicing_dir = match &opt.workspace_dir {
+        Some(dir) => dir.clone(),
+        None => {
+            temp_dir = tempfile::tempdir().context("Failed to generate temporary directory")?;
+            temp_dir.as_ref().to_path_buf()
+        }
+    };
 
     // Generate a splicer for creating a Cargo workspace manifest
-    let splicer = Splicer::new(
-        opt.workspace_dir,
-        splicing_manifest,
-        extra_manifests_manifest,
-    )?;
+    let splicer = Splicer::new(splicing_dir, splicing_manifest)?;
 
     // Splice together the manifest
-    let manifest_path = splicer.splice_workspace()?;
+    let manifest_path = splicer.splice_workspace(&opt.cargo)?;
 
     // Generate a lockfile
-    let cargo_lockfile =
-        generate_lockfile(&manifest_path, &opt.cargo_lockfile, &opt.cargo, &opt.rustc)?;
+    let cargo_lockfile = generate_lockfile(
+        &manifest_path,
+        &opt.cargo_lockfile,
+        &opt.cargo,
+        &opt.rustc,
+        &opt.repin,
+    )?;
 
     // Write the registry url info to the manifest now that a lockfile has been generated
     WorkspaceMetadata::write_registry_urls(&cargo_lockfile, &manifest_path)?;
 
+    let output_dir = opt.output_dir.clone();
+
     // Write metadata to the workspace for future reuse
     let (cargo_metadata, _) = Generator::new()
         .with_cargo(opt.cargo)
         .with_rustc(opt.rustc)
         .generate(&manifest_path.as_path_buf())?;
 
-    // Write metadata next to the manifest
-    let metadata_path = manifest_path
+    let cargo_lockfile_path = manifest_path
         .as_path_buf()
         .parent()
-        .expect("Newly spliced cargo manifest has no parent directory")
-        .join("cargo-bazel-spliced-metadata.json");
-    write_metadata(&metadata_path, &cargo_metadata)?;
+        .with_context(|| {
+            format!(
+                "The path {} is expected to have a parent directory",
+                manifest_path.as_path_buf().display()
+            )
+        })?
+        .join("Cargo.lock");
+
+    // Generate the consumable outputs of the splicing process
+    std::fs::create_dir_all(&output_dir)
+        .with_context(|| format!("Failed to create directories for {}", &output_dir.display()))?;
+
+    write_metadata(&opt.output_dir.join("metadata.json"), &cargo_metadata)?;
+
+    std::fs::copy(cargo_lockfile_path, output_dir.join("Cargo.lock"))
+        .context("Failed to copy lockfile")?;
 
     Ok(())
 }
diff --git a/crate_universe/src/cli/vendor.rs b/crate_universe/src/cli/vendor.rs
index 68e107f..0b90541 100644
--- a/crate_universe/src/cli/vendor.rs
+++ b/crate_universe/src/cli/vendor.rs
@@ -1,6 +1,7 @@
 //! The cli entrypoint for the `vendor` subcommand
 
 use std::collections::BTreeSet;
+use std::env;
 use std::fs;
 use std::path::{Path, PathBuf};
 use std::process::{self, ExitStatus};
@@ -10,16 +11,15 @@
 
 use crate::config::{Config, VendorMode};
 use crate::context::Context;
+use crate::metadata::CargoUpdateRequest;
 use crate::metadata::{Annotations, VendorGenerator};
 use crate::metadata::{Generator, MetadataGenerator};
 use crate::rendering::{render_module_label, write_outputs, Renderer};
-use crate::splicing::{
-    generate_lockfile, ExtraManifestsManifest, Splicer, SplicingManifest, WorkspaceMetadata,
-};
+use crate::splicing::{generate_lockfile, Splicer, SplicingManifest, WorkspaceMetadata};
 
 /// Command line options for the `vendor` subcommand
 #[derive(Parser, Debug)]
-#[clap(about, version)]
+#[clap(about = "Command line options for the `vendor` subcommand", version)]
 pub struct VendorOptions {
     /// The path to a Cargo binary to use for gathering metadata
     #[clap(long, env = "CARGO")]
@@ -41,7 +41,7 @@
     #[clap(long)]
     pub splicing_manifest: PathBuf,
 
-    /// The path to a Cargo lockfile
+    /// The path to a [Cargo.lock](https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html) file.
     #[clap(long)]
     pub cargo_lockfile: Option<PathBuf>,
 
@@ -50,13 +50,19 @@
     #[clap(long)]
     pub cargo_config: Option<PathBuf>,
 
+    /// The desired update/repin behavior. The arguments passed here are forward to
+    /// [cargo update](https://doc.rust-lang.org/cargo/commands/cargo-update.html). See
+    /// [metadata::CargoUpdateRequest] for details on the values to pass here.
+    #[clap(long, env = "CARGO_BAZEL_REPIN", default_missing_value = "true")]
+    pub repin: Option<CargoUpdateRequest>,
+
     /// The path to a Cargo metadata `json` file.
     #[clap(long)]
     pub metadata: Option<PathBuf>,
 
-    /// A generated manifest of "extra workspace members"
-    #[clap(long)]
-    pub extra_manifests_manifest: PathBuf,
+    /// The path to a bazel binary
+    #[clap(long, env = "BAZEL_REAL", default_value = "bazel")]
+    pub bazel: PathBuf,
 
     /// The directory in which to build the workspace. A `Cargo.toml` file
     /// should always be produced within this directory.
@@ -83,31 +89,55 @@
     Ok(status)
 }
 
+/// Query the Bazel output_base to determine the location of external repositories.
+fn locate_bazel_output_base(bazel: &Path, workspace_dir: &Path) -> Result<PathBuf> {
+    // Allow a predefined environment variable to take precedent. This
+    // solves for the specific needs of Bazel CI on Github.
+    if let Ok(output_base) = env::var("OUTPUT_BASE") {
+        return Ok(PathBuf::from(output_base));
+    }
+
+    let output = process::Command::new(bazel)
+        .current_dir(workspace_dir)
+        .args(["info", "output_base"])
+        .output()
+        .context("Failed to query the Bazel workspace's `output_base`")?;
+
+    if !output.status.success() {
+        bail!(output.status)
+    }
+
+    Ok(PathBuf::from(
+        String::from_utf8_lossy(&output.stdout).trim(),
+    ))
+}
+
 pub fn vendor(opt: VendorOptions) -> Result<()> {
+    let output_base = locate_bazel_output_base(&opt.bazel, &opt.workspace_dir)?;
+
     // Load the all config files required for splicing a workspace
-    let splicing_manifest =
-        SplicingManifest::try_from_path(&opt.splicing_manifest)?.absoulutize(&opt.workspace_dir);
-    let extra_manifests_manifest =
-        ExtraManifestsManifest::try_from_path(opt.extra_manifests_manifest)?.absoulutize();
+    let splicing_manifest = SplicingManifest::try_from_path(&opt.splicing_manifest)?
+        .resolve(&opt.workspace_dir, &output_base);
 
     let temp_dir = tempfile::tempdir().context("Failed to create temporary directory")?;
 
     // Generate a splicer for creating a Cargo workspace manifest
-    let splicer = Splicer::new(
-        PathBuf::from(temp_dir.as_ref()),
-        splicing_manifest,
-        extra_manifests_manifest,
-    )
-    .context("Failed to crate splicer")?;
+    let splicer = Splicer::new(PathBuf::from(temp_dir.as_ref()), splicing_manifest)
+        .context("Failed to create splicer")?;
 
     // Splice together the manifest
     let manifest_path = splicer
-        .splice_workspace()
+        .splice_workspace(&opt.cargo)
         .context("Failed to splice workspace")?;
 
-    // Generate a lockfile
-    let cargo_lockfile =
-        generate_lockfile(&manifest_path, &opt.cargo_lockfile, &opt.cargo, &opt.rustc)?;
+    // Gather a cargo lockfile
+    let cargo_lockfile = generate_lockfile(
+        &manifest_path,
+        &opt.cargo_lockfile,
+        &opt.cargo,
+        &opt.rustc,
+        &opt.repin,
+    )?;
 
     // Write the registry url info to the manifest now that a lockfile has been generated
     WorkspaceMetadata::write_registry_urls(&cargo_lockfile, &manifest_path)?;
@@ -122,7 +152,7 @@
     let config = Config::try_from_path(&opt.config)?;
 
     // Annotate metadata
-    let annotations = Annotations::new(cargo_metadata, cargo_lockfile, config.clone())?;
+    let annotations = Annotations::new(cargo_metadata, cargo_lockfile.clone(), config.clone())?;
 
     // Generate renderable contexts for earch package
     let context = Context::new(annotations)?;
@@ -143,6 +173,12 @@
             .with_context(|| format!("Failed to delete {}", vendor_dir.display()))?;
     }
 
+    // Store the updated Cargo.lock
+    if let Some(path) = &opt.cargo_lockfile {
+        fs::write(path, cargo_lockfile.to_string())
+            .context("Failed to write Cargo.lock file back to the workspace.")?;
+    }
+
     // Vendor the crates from the spliced workspace
     if matches!(config.rendering.vendor_mode, Some(VendorMode::Local)) {
         VendorGenerator::new(opt.cargo.clone(), opt.rustc.clone())