Skip to content
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

Add an "-Z offline" flag to Cargo, altering it's dependency resolution behavior #4770

Merged
merged 2 commits into from
Jan 9, 2018
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
2 changes: 2 additions & 0 deletions src/cargo/core/features.rs
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,7 @@ impl Features {
pub struct CliUnstable {
pub print_im_a_teapot: bool,
pub unstable_options: bool,
pub offline: bool,
}

impl CliUnstable {
Expand Down Expand Up @@ -262,6 +263,7 @@ impl CliUnstable {
match k {
"print-im-a-teapot" => self.print_im_a_teapot = parse_bool(v)?,
"unstable-options" => self.unstable_options = true,
"offline" => self.offline = true,
_ => bail!("unknown `-Z` flag specified: {}", k),
}

Expand Down
16 changes: 13 additions & 3 deletions src/cargo/core/resolver/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -722,7 +722,7 @@ fn activate_deps_loop<'a>(mut cx: Context<'a>,
None => return Err(activation_error(&cx, registry, &parent,
&dep,
cx.prev_active(&dep),
&candidates)),
&candidates, config)),
Some(candidate) => candidate,
}
}
Expand Down Expand Up @@ -788,7 +788,8 @@ fn activation_error(cx: &Context,
parent: &Summary,
dep: &Dependency,
prev_active: &[Summary],
candidates: &[Candidate]) -> CargoError {
candidates: &[Candidate],
config: Option<&Config>) -> CargoError {
if !candidates.is_empty() {
let mut msg = format!("failed to select a version for `{}` \
(required by `{}`):\n\
Expand Down Expand Up @@ -843,7 +844,7 @@ fn activation_error(cx: &Context,
b.version().cmp(a.version())
});

let msg = if !candidates.is_empty() {
let mut msg = if !candidates.is_empty() {
let versions = {
let mut versions = candidates.iter().take(3).map(|cand| {
cand.version().to_string()
Expand Down Expand Up @@ -886,6 +887,15 @@ fn activation_error(cx: &Context,
dep.version_req())
};

if let Some(config) = config {
if config.cli_unstable().offline {
msg.push_str("\nAs a reminder, you're using offline mode (-Z offline) \
which can sometimes cause surprising resolution failures, \
if this error is too confusing you may with to retry \
without the offline flag.");
}
}

format_err!("{}", msg)
}

Expand Down
4 changes: 4 additions & 0 deletions src/cargo/ops/cargo_generate_lockfile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ pub fn update_lockfile(ws: &Workspace, opts: &UpdateOptions)
bail!("you can't generate a lockfile for an empty workspace.")
}

if opts.config.cli_unstable().offline {
bail!("you can't update in the offline mode");
}

let previous_resolve = match ops::load_pkg_lockfile(ws)? {
Some(resolve) => resolve,
None => return generate_lockfile(ws),
Expand Down
4 changes: 4 additions & 0 deletions src/cargo/ops/lockfile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,10 @@ pub fn write_pkg_lockfile(ws: &Workspace, resolve: &Resolve) -> CargoResult<()>
}

if !ws.config().lock_update_allowed() {
if ws.config().cli_unstable().offline {
bail!("can't update in the offline mode");
}

let flag = if ws.config().network_allowed() {"--locked"} else {"--frozen"};
bail!("the lock file needs to be updated but {} was passed to \
prevent this", flag);
Expand Down
5 changes: 4 additions & 1 deletion src/cargo/ops/registry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -263,10 +263,13 @@ pub fn registry(config: &Config,

/// Create a new HTTP handle with appropriate global configuration for cargo.
pub fn http_handle(config: &Config) -> CargoResult<Easy> {
if !config.network_allowed() {
if config.frozen() {
bail!("attempting to make an HTTP request, but --frozen was \
specified")
}
if !config.network_allowed() {
bail!("can't make HTTP request in the offline mode")
}

// The timeout option for libcurl by default times out the entire transfer,
// but we probably don't want this. Instead we only set timeouts for the
Expand Down
7 changes: 6 additions & 1 deletion src/cargo/sources/git/source.rs
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,11 @@ impl<'cfg> Source for GitSource<'cfg> {

let db_path = lock.parent().join("db").join(&self.ident);

if self.config.cli_unstable().offline && !db_path.exists() {
bail!("can't checkout from '{}': you are in the offline mode (-Z offline)",
self.remote.url());
}

// Resolve our reference to an actual revision, and check if the
// database already has that revision. If it does, we just load a
// database pinned at that revision, and if we don't we issue an update
Expand All @@ -159,7 +164,7 @@ impl<'cfg> Source for GitSource<'cfg> {
let should_update = actual_rev.is_err() ||
self.source_id.precise().is_none();

let (db, actual_rev) = if should_update {
let (db, actual_rev) = if should_update && !self.config.cli_unstable().offline {
self.config.shell().status("Updating",
format!("git repository `{}`", self.remote.url()))?;

Expand Down
5 changes: 4 additions & 1 deletion src/cargo/sources/git/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -615,10 +615,13 @@ pub fn fetch(repo: &mut git2::Repository,
url: &Url,
refspec: &str,
config: &Config) -> CargoResult<()> {
if !config.network_allowed() {
if config.frozen() {
bail!("attempting to update a git repository, but --frozen \
was specified")
}
if !config.network_allowed() {
bail!("can't update a git repository in the offline mode")
}

// If we're fetching from github, attempt github's special fast path for
// testing if we've already got an up-to-date copy of the repository
Expand Down
9 changes: 8 additions & 1 deletion src/cargo/sources/registry/index.rs
Original file line number Diff line number Diff line change
Expand Up @@ -110,13 +110,20 @@ impl<'cfg> RegistryIndex<'cfg> {
.map(|s| s.trim())
.filter(|l| !l.is_empty());

let online = !self.config.cli_unstable().offline;
// Attempt forwards-compatibility on the index by ignoring
// everything that we ourselves don't understand, that should
// allow future cargo implementations to break the
// interpretation of each line here and older cargo will simply
// ignore the new lines.
ret.extend(lines.filter_map(|line| {
self.parse_registry_package(line).ok()
self.parse_registry_package(line).ok().and_then(|v|{
if online || load.is_crate_downloaded(v.0.package_id()) {
Some(v)
} else {
None
}
})
}));

Ok(())
Expand Down
2 changes: 2 additions & 0 deletions src/cargo/sources/registry/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,8 @@ pub trait RegistryData {
fn download(&mut self,
pkg: &PackageId,
checksum: &str) -> CargoResult<FileLock>;

fn is_crate_downloaded(&self, _pkg: &PackageId) -> bool { true }
}

mod index;
Expand Down
18 changes: 18 additions & 0 deletions src/cargo/sources/registry/remote.rs
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,10 @@ impl<'cfg> RegistryData for RemoteRegistry<'cfg> {
}

fn update_index(&mut self) -> CargoResult<()> {
if self.config.cli_unstable().offline {
return Ok(());
}

// Ensure that we'll actually be able to acquire an HTTP handle later on
// once we start trying to download crates. This will weed out any
// problems with `.cargo/config` configuration related to HTTP.
Expand Down Expand Up @@ -258,6 +262,20 @@ impl<'cfg> RegistryData for RemoteRegistry<'cfg> {
dst.seek(SeekFrom::Start(0))?;
Ok(dst)
}


fn is_crate_downloaded(&self, pkg: &PackageId) -> bool {
let filename = format!("{}-{}.crate", pkg.name(), pkg.version());
let path = Path::new(&filename);

if let Ok(dst) = self.cache_path.open_ro(path, self.config, &filename) {
if let Ok(meta) = dst.file().metadata(){
return meta.len() > 0;
}
}
false
}

}

impl<'cfg> Drop for RemoteRegistry<'cfg> {
Expand Down
6 changes: 5 additions & 1 deletion src/cargo/util/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -504,7 +504,11 @@ impl Config {
}

pub fn network_allowed(&self) -> bool {
!self.frozen
!self.frozen() && !self.cli_unstable().offline
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm a little worried about modifying this function which is already uses in a few other locations. For example I think this error message may no longer be right (or this one or this one). Perhaps these locations could use a central method to determine why the network isn't allowed?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also I think that these error messages should never happen during offline mode, right? In that offline mode should divert Cargo from executing code paths like that.

}

pub fn frozen(&self) -> bool {
self.frozen
}

pub fn lock_update_allowed(&self) -> bool {
Expand Down
Loading