Skip to content

Commit 3842d8e

Browse files
committed
Import the cargo-vendor subcommand into Cargo
This commit imports the external [alexcrichton/cargo-vendor repository][repo] into Cargo itself. This means it will no longer be necessary to install the `cargo-vendor` subcommand in order to vendor dependencies. Additionally it'll always support the latest feature set of Cargo as it'll be built into Cargo! All tests were imported as part of this commit, but not all features were imported. Some flags have been left out that were added later in the lifetime of `cargo vendor` which seem like they're more questionable to stabilize. I'm hoping that they can have separate PRs adding their implementation here, and we can make a decision of their stabilization at a later date. The current man page for `cargo vendor -h` will look like: cargo-vendor Vendor all dependencies for a project locally USAGE: cargo vendor [OPTIONS] [--] [path] OPTIONS: -q, --quiet No output printed to stdout --manifest-path <PATH> Path to Cargo.toml --no-delete Don't delete older crates in the vendor directory -s, --sync <TOML>... Additional `Cargo.toml` to sync and vendor --respect-source-config Respect `[source]` config in `.cargo/config` -v, --verbose Use verbose output (-vv very verbose/build.rs output) --color <WHEN> Coloring: auto, always, never --frozen Require Cargo.lock and cache are up to date --locked Require Cargo.lock is up to date -Z <FLAG>... Unstable (nightly-only) flags to Cargo, see 'cargo -Z help' for details -h, --help Prints help information ARGS: <path> Where to vendor crates (`vendor` by default) This cargo subcommand will vendor all crates.io and git dependencies for a project into the specified directory at `<path>`. After this command completes the vendor directory specified by `<path>` will contain all remote sources from dependencies specified. Additionally manifest beyond the default one can be specified with the `-s` option. The `cargo vendor` command will also print out the configuration necessary to use the vendored sources, which when needed is then encoded into `.cargo/config`. Since this change is not importing 100% of the functionality of the existing `cargo vendor` this change does run a risk of being a breaking change for any folks using such functionality. Executing `cargo vendor` will favor the built-in command rather than an external subcommand, causing unimplemented features to become errors about flag usage. [repo]: https://github.com/alexcrichton/cargo-vendor
1 parent 0ef35b9 commit 3842d8e

File tree

21 files changed

+1553
-60
lines changed

21 files changed

+1553
-60
lines changed

src/bin/cargo/commands/mod.rs

+3
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ pub fn builtin() -> Vec<App> {
3030
test::cli(),
3131
uninstall::cli(),
3232
update::cli(),
33+
vendor::cli(),
3334
verify_project::cli(),
3435
version::cli(),
3536
yank::cli(),
@@ -66,6 +67,7 @@ pub fn builtin_exec(cmd: &str) -> Option<fn(&mut Config, &ArgMatches<'_>) -> Cli
6667
"test" => test::exec,
6768
"uninstall" => uninstall::exec,
6869
"update" => update::exec,
70+
"vendor" => vendor::exec,
6971
"verify-project" => verify_project::exec,
7072
"version" => version::exec,
7173
"yank" => yank::exec,
@@ -102,6 +104,7 @@ pub mod search;
102104
pub mod test;
103105
pub mod uninstall;
104106
pub mod update;
107+
pub mod vendor;
105108
pub mod verify_project;
106109
pub mod version;
107110
pub mod yank;

src/bin/cargo/commands/vendor.rs

+123
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
use crate::command_prelude::*;
2+
use cargo::ops;
3+
use std::path::PathBuf;
4+
5+
pub fn cli() -> App {
6+
subcommand("vendor")
7+
.about("Vendor all dependencies for a project locally")
8+
.arg(opt("quiet", "No output printed to stdout").short("q"))
9+
.arg_manifest_path()
10+
.arg(Arg::with_name("path").help("Where to vendor crates (`vendor` by default)"))
11+
.arg(
12+
Arg::with_name("no-delete")
13+
.long("no-delete")
14+
.help("Don't delete older crates in the vendor directory"),
15+
)
16+
.arg(
17+
Arg::with_name("tomls")
18+
.short("s")
19+
.long("sync")
20+
.help("Additional `Cargo.toml` to sync and vendor")
21+
.value_name("TOML")
22+
.multiple(true),
23+
)
24+
.arg(
25+
Arg::with_name("respect-source-config")
26+
.long("respect-source-config")
27+
.help("Respect `[source]` config in `.cargo/config`")
28+
.multiple(true),
29+
)
30+
.arg(
31+
Arg::with_name("no-merge-sources")
32+
.long("no-merge-sources")
33+
.hidden(true),
34+
)
35+
.arg(
36+
Arg::with_name("relative-path")
37+
.long("relative-path")
38+
.hidden(true),
39+
)
40+
.arg(
41+
Arg::with_name("only-git-deps")
42+
.long("only-git-deps")
43+
.hidden(true),
44+
)
45+
.arg(
46+
Arg::with_name("explicit-version")
47+
.short("-x")
48+
.long("explicit-version")
49+
.hidden(true),
50+
)
51+
.arg(
52+
Arg::with_name("disallow-duplicates")
53+
.long("disallow-duplicates")
54+
.hidden(true),
55+
)
56+
.after_help(
57+
"\
58+
This cargo subcommand will vendor all crates.io and git dependencies for a
59+
project into the specified directory at `<path>`. After this command completes
60+
the vendor directory specified by `<path>` will contain all remote sources from
61+
dependencies specified. Additional manifests beyond the default one can be
62+
specified with the `-s` option.
63+
64+
The `cargo vendor` command will also print out the configuration necessary
65+
to use the vendored sources, which you will need to add to `.cargo/config`.
66+
",
67+
)
68+
}
69+
70+
pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult {
71+
// We're doing the vendoring operation outselves, so we don't actually want
72+
// to respect any of the `source` configuration in Cargo itself. That's
73+
// intended for other consumers of Cargo, but we want to go straight to the
74+
// source, e.g. crates.io, to fetch crates.
75+
if !args.is_present("respect-source-config") {
76+
config.values_mut()?.remove("source");
77+
}
78+
79+
// When we moved `cargo vendor` into Cargo itself we didn't stabilize a few
80+
// flags, so try to provide a helpful error message in that case to enusre
81+
// that users currently using the flag aren't tripped up.
82+
let crates_io_cargo_vendor_flag = if args.is_present("no-merge-sources") {
83+
Some("--no-merge-sources")
84+
} else if args.is_present("relative-path") {
85+
Some("--relative-path")
86+
} else if args.is_present("only-git-deps") {
87+
Some("--only-git-deps")
88+
} else if args.is_present("explicit-version") {
89+
Some("--explicit-version")
90+
} else if args.is_present("disallow-duplicates") {
91+
Some("--disallow-duplicates")
92+
} else {
93+
None
94+
};
95+
if let Some(flag) = crates_io_cargo_vendor_flag {
96+
return Err(failure::format_err!("\
97+
the crates.io `cargo vendor` command has now been merged into Cargo itself
98+
and does not support the flag `{}` currently; to continue using the flag you
99+
can execute `cargo-vendor vendor ...`, and if you would like to see this flag
100+
supported in Cargo itself please feel free to file an issue at
101+
https://github.com/rust-lang/cargo/issues/new
102+
", flag).into());
103+
}
104+
105+
let ws = args.workspace(config)?;
106+
let path = args
107+
.value_of_os("path")
108+
.map(|val| PathBuf::from(val.to_os_string()))
109+
.unwrap_or(PathBuf::from("vendor"));
110+
ops::vendor(
111+
&ws,
112+
&ops::VendorOptions {
113+
no_delete: args.is_present("no-delete"),
114+
destination: &path,
115+
extra: args
116+
.values_of_os("tomls")
117+
.unwrap_or_default()
118+
.map(|s| PathBuf::from(s.to_os_string()))
119+
.collect(),
120+
},
121+
)?;
122+
Ok(())
123+
}

src/cargo/lib.rs

+29-13
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#![allow(clippy::unneeded_field_pattern)]
2727

2828
use std::fmt;
29+
use std::io;
2930

3031
use failure::Error;
3132
use log::debug;
@@ -147,23 +148,38 @@ fn handle_cause(cargo_err: &Error, shell: &mut Shell) -> bool {
147148
drop(writeln!(shell.err(), " {}", error));
148149
}
149150

151+
fn print_stderror_causes(error: &dyn std::error::Error, shell: &mut Shell) {
152+
let mut cur = std::error::Error::source(error);
153+
while let Some(err) = cur {
154+
print(&err.to_string(), shell);
155+
cur = std::error::Error::source(err);
156+
}
157+
}
158+
150159
let verbose = shell.verbosity();
151160

152-
if verbose == Verbose {
153-
// The first error has already been printed to the shell.
154-
// Print all remaining errors.
155-
for err in cargo_err.iter_causes() {
156-
print(&err.to_string(), shell);
161+
// The first error has already been printed to the shell.
162+
for err in cargo_err.iter_causes() {
163+
164+
// If we're not in verbose mode then print remaining errors until one
165+
// marked as `Internal` appears.
166+
if verbose != Verbose && err.downcast_ref::<Internal>().is_some() {
167+
return false;
157168
}
158-
} else {
159-
// The first error has already been printed to the shell.
160-
// Print remaining errors until one marked as `Internal` appears.
161-
for err in cargo_err.iter_causes() {
162-
if err.downcast_ref::<Internal>().is_some() {
163-
return false;
164-
}
165169

166-
print(&err.to_string(), shell);
170+
print(&err.to_string(), shell);
171+
172+
// Using the `failure` crate currently means that when using
173+
// `iter_causes` we're only iterating over the `failure` causes, but
174+
// this doesn't include the causes from the standard library `Error`
175+
// trait. We don't have a great way of getting an `&dyn Error` from a
176+
// `&dyn Fail`, so we currently just special case a few errors that are
177+
// known to maybe have causes and we try to print them here.
178+
//
179+
// Note that this isn't an exhaustive match since causes for
180+
// `std::error::Error` aren't the most common thing in the world.
181+
if let Some(io) = err.downcast_ref::<io::Error>() {
182+
print_stderror_causes(io, shell);
167183
}
168184
}
169185

src/cargo/ops/mod.rs

+2
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ pub use self::resolve::{
2626
add_overrides, get_resolved_packages, resolve_with_previous, resolve_ws, resolve_ws_precisely,
2727
resolve_ws_with_method,
2828
};
29+
pub use self::vendor::{vendor, VendorOptions};
2930

3031
mod cargo_clean;
3132
mod cargo_compile;
@@ -46,3 +47,4 @@ mod fix;
4647
mod lockfile;
4748
mod registry;
4849
mod resolve;
50+
mod vendor;

0 commit comments

Comments
 (0)