Skip to content

Import the cargo-vendor subcommand into Cargo #6869

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jun 3, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/bin/cargo/commands/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ pub fn builtin() -> Vec<App> {
test::cli(),
uninstall::cli(),
update::cli(),
vendor::cli(),
verify_project::cli(),
version::cli(),
yank::cli(),
Expand Down Expand Up @@ -66,6 +67,7 @@ pub fn builtin_exec(cmd: &str) -> Option<fn(&mut Config, &ArgMatches<'_>) -> Cli
"test" => test::exec,
"uninstall" => uninstall::exec,
"update" => update::exec,
"vendor" => vendor::exec,
"verify-project" => verify_project::exec,
"version" => version::exec,
"yank" => yank::exec,
Expand Down Expand Up @@ -102,6 +104,7 @@ pub mod search;
pub mod test;
pub mod uninstall;
pub mod update;
pub mod vendor;
pub mod verify_project;
pub mod version;
pub mod yank;
123 changes: 123 additions & 0 deletions src/bin/cargo/commands/vendor.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
use crate::command_prelude::*;
use cargo::ops;
use std::path::PathBuf;

pub fn cli() -> App {
subcommand("vendor")
.about("Vendor all dependencies for a project locally")
.arg(opt("quiet", "No output printed to stdout").short("q"))
.arg_manifest_path()
.arg(Arg::with_name("path").help("Where to vendor crates (`vendor` by default)"))
.arg(
Arg::with_name("no-delete")
.long("no-delete")
.help("Don't delete older crates in the vendor directory"),
)
.arg(
Arg::with_name("tomls")
.short("s")
.long("sync")
.help("Additional `Cargo.toml` to sync and vendor")
.value_name("TOML")
.multiple(true),
)
.arg(
Arg::with_name("respect-source-config")
.long("respect-source-config")
.help("Respect `[source]` config in `.cargo/config`")
.multiple(true),
)
.arg(
Arg::with_name("no-merge-sources")
.long("no-merge-sources")
.hidden(true),
)
.arg(
Arg::with_name("relative-path")
.long("relative-path")
.hidden(true),
)
.arg(
Arg::with_name("only-git-deps")
.long("only-git-deps")
.hidden(true),
)
.arg(
Arg::with_name("explicit-version")
.short("-x")
.long("explicit-version")
.hidden(true),
)
.arg(
Arg::with_name("disallow-duplicates")
.long("disallow-duplicates")
.hidden(true),
)
.after_help(
"\
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. Additional manifests 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 you will need to add to `.cargo/config`.
",
)
}

pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult {
// We're doing the vendoring operation outselves, so we don't actually want
// to respect any of the `source` configuration in Cargo itself. That's
// intended for other consumers of Cargo, but we want to go straight to the
// source, e.g. crates.io, to fetch crates.
if !args.is_present("respect-source-config") {
config.values_mut()?.remove("source");
}

// When we moved `cargo vendor` into Cargo itself we didn't stabilize a few
// flags, so try to provide a helpful error message in that case to enusre
// that users currently using the flag aren't tripped up.
let crates_io_cargo_vendor_flag = if args.is_present("no-merge-sources") {
Some("--no-merge-sources")
} else if args.is_present("relative-path") {
Some("--relative-path")
} else if args.is_present("only-git-deps") {
Some("--only-git-deps")
} else if args.is_present("explicit-version") {
Some("--explicit-version")
} else if args.is_present("disallow-duplicates") {
Some("--disallow-duplicates")
} else {
None
};
if let Some(flag) = crates_io_cargo_vendor_flag {
return Err(failure::format_err!("\
the crates.io `cargo vendor` command has now been merged into Cargo itself
and does not support the flag `{}` currently; to continue using the flag you
can execute `cargo-vendor vendor ...`, and if you would like to see this flag
supported in Cargo itself please feel free to file an issue at
https://github.com/rust-lang/cargo/issues/new
", flag).into());
}

let ws = args.workspace(config)?;
let path = args
.value_of_os("path")
.map(|val| PathBuf::from(val.to_os_string()))
.unwrap_or(PathBuf::from("vendor"));
ops::vendor(
&ws,
&ops::VendorOptions {
no_delete: args.is_present("no-delete"),
destination: &path,
extra: args
.values_of_os("tomls")
.unwrap_or_default()
.map(|s| PathBuf::from(s.to_os_string()))
.collect(),
},
)?;
Ok(())
}
42 changes: 29 additions & 13 deletions src/cargo/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#![allow(clippy::unneeded_field_pattern)]

use std::fmt;
use std::io;

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

fn print_stderror_causes(error: &dyn std::error::Error, shell: &mut Shell) {
let mut cur = std::error::Error::source(error);
while let Some(err) = cur {
print(&err.to_string(), shell);
cur = std::error::Error::source(err);
}
}

let verbose = shell.verbosity();

if verbose == Verbose {
// The first error has already been printed to the shell.
// Print all remaining errors.
for err in cargo_err.iter_causes() {
print(&err.to_string(), shell);
// The first error has already been printed to the shell.
for err in cargo_err.iter_causes() {

// If we're not in verbose mode then print remaining errors until one
// marked as `Internal` appears.
if verbose != Verbose && err.downcast_ref::<Internal>().is_some() {
return false;
}
} else {
// The first error has already been printed to the shell.
// Print remaining errors until one marked as `Internal` appears.
for err in cargo_err.iter_causes() {
if err.downcast_ref::<Internal>().is_some() {
return false;
}

print(&err.to_string(), shell);
print(&err.to_string(), shell);

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

Expand Down
2 changes: 2 additions & 0 deletions src/cargo/ops/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ pub use self::resolve::{
add_overrides, get_resolved_packages, resolve_with_previous, resolve_ws, resolve_ws_precisely,
resolve_ws_with_method,
};
pub use self::vendor::{vendor, VendorOptions};

mod cargo_clean;
mod cargo_compile;
Expand All @@ -46,3 +47,4 @@ mod fix;
mod lockfile;
mod registry;
mod resolve;
mod vendor;
Loading