cargo/tests/overrides.rs

928 lines
24 KiB
Rust
Raw Normal View History

extern crate cargotest;
extern crate hamcrest;
Implement top-level overrides This commit is an implementation of top-level overrides to be encoded into the manifest itself directly. This style of override is distinct from the existing `paths` support in `.cargo/config` in two important ways: * Top level overrides are intended to be checked in and shared amongst all developers of a project. * Top level overrides are reflected in `Cargo.lock`. The second point is crucially important here as it will ensure that an override on one machine behaves the same as an override on another machine. This solves many long-standing problems with `paths`-based overrides which suffer from some level of nondeterminism as they're not encoded. From a syntactical point of view, an override looks like: ```toml [replace] "libc:0.2.0" = { git = 'https://github.com/my-username/libc', branch = '0.2-fork' } ``` This declaration indicates that whenever resolution would otherwise encounter the `libc` package version 0.2.0 from crates.io, it should instead replace it with the custom git dependency on a specific branch. The key "libc:0.2.0" here is actually a package id specification which will allow selecting various components of a graph. For example the same named package coming from two distinct locations can be selected against, as well as multiple versions of one crate in a dependency graph. The replacement dependency has the same syntax as the `[dependencies]` section of Cargo.toml. One of the major uses of this syntax will be, for example, using a temporary fork of a crate while the changes are pushed upstream to the original repo. This will avoid the need to change the intermediate projects immediately, and over time once fixes have landed upstream the `[replace]` section in a `Cargo.toml` can be removed. There are also two crucial restrictions on overrides. * A crate with the name `foo` can only get overridden with packages also of the name `foo`. * A crate can only get overridden with a crate of the exact same version. A consequence of these restrictions is that crates.io cannot be used to replace anything from crates.io. There's only one version of something on crates.io, so there's nothing else to replace it with (name/version are a unique key). Closes #942
2016-02-09 23:42:17 +00:00
use cargotest::support::git;
use cargotest::support::paths;
Implement source redirection This commit implements a scheme for .cargo/config files where sources can be redirected to other sources. The purpose of this will be to override crates.io for a few use cases: * Replace it with a mirror site that is sync'd to crates.io * Replace it with a "directory source" or some other local source This major feature of this redirection, however, is that none of it is encoded into the lock file. If one source is redirected to another then it is assumed that packages from both are exactly the same (e.g. `foo v0.0.1` is the same in both location). The lock file simply encodes the canonical soure (e.g. crates.io) rather than the replacement source. In the end this means that Cargo.lock files can be generated from any replacement source and shipped to other locations without the lockfile oscillating about where packages came from. Eventually this support will be extended to `Cargo.toml` itself (which will be encoded into the lock file), but that support is not implemented today. The syntax for what was implemented today looks like: # .cargo/config [source.my-awesome-registry] registry = 'https://example.com/path/to/index' [source.crates-io] replace-with = 'my-awesome-registry' Each source will have a canonical name and will be configured with the various keys underneath it (today just 'registry' and 'directory' will be accepted). The global `crates-io` source represents crates from the standard registry, and this can be replaced with other mirror sources. All tests have been modified to use this new infrastructure instead of the old `registry.index` configuration. This configuration is now also deprecated and will emit an unconditional warning about how it will no longer be used in the future. Finally, all subcommands now use this "source map" except for `cargo publish`, which will always publish to the default registry (in this case crates.io).
2016-02-03 18:54:07 +00:00
use cargotest::support::registry::Package;
use cargotest::support::{execs, project};
use hamcrest::assert_that;
Implement top-level overrides This commit is an implementation of top-level overrides to be encoded into the manifest itself directly. This style of override is distinct from the existing `paths` support in `.cargo/config` in two important ways: * Top level overrides are intended to be checked in and shared amongst all developers of a project. * Top level overrides are reflected in `Cargo.lock`. The second point is crucially important here as it will ensure that an override on one machine behaves the same as an override on another machine. This solves many long-standing problems with `paths`-based overrides which suffer from some level of nondeterminism as they're not encoded. From a syntactical point of view, an override looks like: ```toml [replace] "libc:0.2.0" = { git = 'https://github.com/my-username/libc', branch = '0.2-fork' } ``` This declaration indicates that whenever resolution would otherwise encounter the `libc` package version 0.2.0 from crates.io, it should instead replace it with the custom git dependency on a specific branch. The key "libc:0.2.0" here is actually a package id specification which will allow selecting various components of a graph. For example the same named package coming from two distinct locations can be selected against, as well as multiple versions of one crate in a dependency graph. The replacement dependency has the same syntax as the `[dependencies]` section of Cargo.toml. One of the major uses of this syntax will be, for example, using a temporary fork of a crate while the changes are pushed upstream to the original repo. This will avoid the need to change the intermediate projects immediately, and over time once fixes have landed upstream the `[replace]` section in a `Cargo.toml` can be removed. There are also two crucial restrictions on overrides. * A crate with the name `foo` can only get overridden with packages also of the name `foo`. * A crate can only get overridden with a crate of the exact same version. A consequence of these restrictions is that crates.io cannot be used to replace anything from crates.io. There's only one version of something on crates.io, so there's nothing else to replace it with (name/version are a unique key). Closes #942
2016-02-09 23:42:17 +00:00
#[test]
fn override_simple() {
Implement top-level overrides This commit is an implementation of top-level overrides to be encoded into the manifest itself directly. This style of override is distinct from the existing `paths` support in `.cargo/config` in two important ways: * Top level overrides are intended to be checked in and shared amongst all developers of a project. * Top level overrides are reflected in `Cargo.lock`. The second point is crucially important here as it will ensure that an override on one machine behaves the same as an override on another machine. This solves many long-standing problems with `paths`-based overrides which suffer from some level of nondeterminism as they're not encoded. From a syntactical point of view, an override looks like: ```toml [replace] "libc:0.2.0" = { git = 'https://github.com/my-username/libc', branch = '0.2-fork' } ``` This declaration indicates that whenever resolution would otherwise encounter the `libc` package version 0.2.0 from crates.io, it should instead replace it with the custom git dependency on a specific branch. The key "libc:0.2.0" here is actually a package id specification which will allow selecting various components of a graph. For example the same named package coming from two distinct locations can be selected against, as well as multiple versions of one crate in a dependency graph. The replacement dependency has the same syntax as the `[dependencies]` section of Cargo.toml. One of the major uses of this syntax will be, for example, using a temporary fork of a crate while the changes are pushed upstream to the original repo. This will avoid the need to change the intermediate projects immediately, and over time once fixes have landed upstream the `[replace]` section in a `Cargo.toml` can be removed. There are also two crucial restrictions on overrides. * A crate with the name `foo` can only get overridden with packages also of the name `foo`. * A crate can only get overridden with a crate of the exact same version. A consequence of these restrictions is that crates.io cannot be used to replace anything from crates.io. There's only one version of something on crates.io, so there's nothing else to replace it with (name/version are a unique key). Closes #942
2016-02-09 23:42:17 +00:00
Package::new("foo", "0.1.0").publish();
let foo = git::repo(&paths::root().join("override"))
.file("Cargo.toml", r#"
[package]
name = "foo"
version = "0.1.0"
authors = []
"#)
.file("src/lib.rs", "pub fn foo() {}");
foo.build();
let p = project("local")
.file("Cargo.toml", &format!(r#"
[package]
name = "local"
version = "0.0.1"
authors = []
[dependencies]
foo = "0.1.0"
[replace]
"foo:0.1.0" = {{ git = '{}' }}
"#, foo.url()))
.file("src/lib.rs", "
extern crate foo;
pub fn bar() {
foo::foo();
}
");
assert_that(p.cargo_process("build"),
2016-05-14 21:15:22 +00:00
execs().with_status(0).with_stderr("\
[UPDATING] registry `file://[..]`
[UPDATING] git repository `[..]`
[COMPILING] foo v0.1.0 (file://[..])
[COMPILING] local v0.0.1 (file://[..])
[FINISHED] debug [unoptimized + debuginfo] target(s) in [..]
2016-05-12 17:06:36 +00:00
"));
}
Implement top-level overrides This commit is an implementation of top-level overrides to be encoded into the manifest itself directly. This style of override is distinct from the existing `paths` support in `.cargo/config` in two important ways: * Top level overrides are intended to be checked in and shared amongst all developers of a project. * Top level overrides are reflected in `Cargo.lock`. The second point is crucially important here as it will ensure that an override on one machine behaves the same as an override on another machine. This solves many long-standing problems with `paths`-based overrides which suffer from some level of nondeterminism as they're not encoded. From a syntactical point of view, an override looks like: ```toml [replace] "libc:0.2.0" = { git = 'https://github.com/my-username/libc', branch = '0.2-fork' } ``` This declaration indicates that whenever resolution would otherwise encounter the `libc` package version 0.2.0 from crates.io, it should instead replace it with the custom git dependency on a specific branch. The key "libc:0.2.0" here is actually a package id specification which will allow selecting various components of a graph. For example the same named package coming from two distinct locations can be selected against, as well as multiple versions of one crate in a dependency graph. The replacement dependency has the same syntax as the `[dependencies]` section of Cargo.toml. One of the major uses of this syntax will be, for example, using a temporary fork of a crate while the changes are pushed upstream to the original repo. This will avoid the need to change the intermediate projects immediately, and over time once fixes have landed upstream the `[replace]` section in a `Cargo.toml` can be removed. There are also two crucial restrictions on overrides. * A crate with the name `foo` can only get overridden with packages also of the name `foo`. * A crate can only get overridden with a crate of the exact same version. A consequence of these restrictions is that crates.io cannot be used to replace anything from crates.io. There's only one version of something on crates.io, so there's nothing else to replace it with (name/version are a unique key). Closes #942
2016-02-09 23:42:17 +00:00
#[test]
fn missing_version() {
Implement top-level overrides This commit is an implementation of top-level overrides to be encoded into the manifest itself directly. This style of override is distinct from the existing `paths` support in `.cargo/config` in two important ways: * Top level overrides are intended to be checked in and shared amongst all developers of a project. * Top level overrides are reflected in `Cargo.lock`. The second point is crucially important here as it will ensure that an override on one machine behaves the same as an override on another machine. This solves many long-standing problems with `paths`-based overrides which suffer from some level of nondeterminism as they're not encoded. From a syntactical point of view, an override looks like: ```toml [replace] "libc:0.2.0" = { git = 'https://github.com/my-username/libc', branch = '0.2-fork' } ``` This declaration indicates that whenever resolution would otherwise encounter the `libc` package version 0.2.0 from crates.io, it should instead replace it with the custom git dependency on a specific branch. The key "libc:0.2.0" here is actually a package id specification which will allow selecting various components of a graph. For example the same named package coming from two distinct locations can be selected against, as well as multiple versions of one crate in a dependency graph. The replacement dependency has the same syntax as the `[dependencies]` section of Cargo.toml. One of the major uses of this syntax will be, for example, using a temporary fork of a crate while the changes are pushed upstream to the original repo. This will avoid the need to change the intermediate projects immediately, and over time once fixes have landed upstream the `[replace]` section in a `Cargo.toml` can be removed. There are also two crucial restrictions on overrides. * A crate with the name `foo` can only get overridden with packages also of the name `foo`. * A crate can only get overridden with a crate of the exact same version. A consequence of these restrictions is that crates.io cannot be used to replace anything from crates.io. There's only one version of something on crates.io, so there's nothing else to replace it with (name/version are a unique key). Closes #942
2016-02-09 23:42:17 +00:00
let p = project("local")
.file("Cargo.toml", r#"
[package]
name = "local"
version = "0.0.1"
authors = []
[dependencies]
foo = "0.1.0"
[replace]
foo = { git = 'https://example.com' }
"#)
.file("src/lib.rs", "");
assert_that(p.cargo_process("build"),
execs().with_status(101).with_stderr("\
error: failed to parse manifest at `[..]`
Caused by:
replacements must specify a version to replace, but `[..]foo` does not
Implement top-level overrides This commit is an implementation of top-level overrides to be encoded into the manifest itself directly. This style of override is distinct from the existing `paths` support in `.cargo/config` in two important ways: * Top level overrides are intended to be checked in and shared amongst all developers of a project. * Top level overrides are reflected in `Cargo.lock`. The second point is crucially important here as it will ensure that an override on one machine behaves the same as an override on another machine. This solves many long-standing problems with `paths`-based overrides which suffer from some level of nondeterminism as they're not encoded. From a syntactical point of view, an override looks like: ```toml [replace] "libc:0.2.0" = { git = 'https://github.com/my-username/libc', branch = '0.2-fork' } ``` This declaration indicates that whenever resolution would otherwise encounter the `libc` package version 0.2.0 from crates.io, it should instead replace it with the custom git dependency on a specific branch. The key "libc:0.2.0" here is actually a package id specification which will allow selecting various components of a graph. For example the same named package coming from two distinct locations can be selected against, as well as multiple versions of one crate in a dependency graph. The replacement dependency has the same syntax as the `[dependencies]` section of Cargo.toml. One of the major uses of this syntax will be, for example, using a temporary fork of a crate while the changes are pushed upstream to the original repo. This will avoid the need to change the intermediate projects immediately, and over time once fixes have landed upstream the `[replace]` section in a `Cargo.toml` can be removed. There are also two crucial restrictions on overrides. * A crate with the name `foo` can only get overridden with packages also of the name `foo`. * A crate can only get overridden with a crate of the exact same version. A consequence of these restrictions is that crates.io cannot be used to replace anything from crates.io. There's only one version of something on crates.io, so there's nothing else to replace it with (name/version are a unique key). Closes #942
2016-02-09 23:42:17 +00:00
"));
}
Implement top-level overrides This commit is an implementation of top-level overrides to be encoded into the manifest itself directly. This style of override is distinct from the existing `paths` support in `.cargo/config` in two important ways: * Top level overrides are intended to be checked in and shared amongst all developers of a project. * Top level overrides are reflected in `Cargo.lock`. The second point is crucially important here as it will ensure that an override on one machine behaves the same as an override on another machine. This solves many long-standing problems with `paths`-based overrides which suffer from some level of nondeterminism as they're not encoded. From a syntactical point of view, an override looks like: ```toml [replace] "libc:0.2.0" = { git = 'https://github.com/my-username/libc', branch = '0.2-fork' } ``` This declaration indicates that whenever resolution would otherwise encounter the `libc` package version 0.2.0 from crates.io, it should instead replace it with the custom git dependency on a specific branch. The key "libc:0.2.0" here is actually a package id specification which will allow selecting various components of a graph. For example the same named package coming from two distinct locations can be selected against, as well as multiple versions of one crate in a dependency graph. The replacement dependency has the same syntax as the `[dependencies]` section of Cargo.toml. One of the major uses of this syntax will be, for example, using a temporary fork of a crate while the changes are pushed upstream to the original repo. This will avoid the need to change the intermediate projects immediately, and over time once fixes have landed upstream the `[replace]` section in a `Cargo.toml` can be removed. There are also two crucial restrictions on overrides. * A crate with the name `foo` can only get overridden with packages also of the name `foo`. * A crate can only get overridden with a crate of the exact same version. A consequence of these restrictions is that crates.io cannot be used to replace anything from crates.io. There's only one version of something on crates.io, so there's nothing else to replace it with (name/version are a unique key). Closes #942
2016-02-09 23:42:17 +00:00
#[test]
fn invalid_semver_version() {
let p = project("local")
.file("Cargo.toml", r#"
[package]
name = "local"
version = "0.0.1"
authors = []
[dependencies]
foo = "*"
[replace]
"foo:*" = { git = 'https://example.com' }
"#)
.file("src/lib.rs", "");
assert_that(p.cargo_process("build"),
execs().with_status(101).with_stderr_contains("\
error: failed to parse manifest at `[..]`
Caused by:
replacements must specify a valid semver version to replace, but `foo:*` does not
"));
}
#[test]
fn different_version() {
Implement top-level overrides This commit is an implementation of top-level overrides to be encoded into the manifest itself directly. This style of override is distinct from the existing `paths` support in `.cargo/config` in two important ways: * Top level overrides are intended to be checked in and shared amongst all developers of a project. * Top level overrides are reflected in `Cargo.lock`. The second point is crucially important here as it will ensure that an override on one machine behaves the same as an override on another machine. This solves many long-standing problems with `paths`-based overrides which suffer from some level of nondeterminism as they're not encoded. From a syntactical point of view, an override looks like: ```toml [replace] "libc:0.2.0" = { git = 'https://github.com/my-username/libc', branch = '0.2-fork' } ``` This declaration indicates that whenever resolution would otherwise encounter the `libc` package version 0.2.0 from crates.io, it should instead replace it with the custom git dependency on a specific branch. The key "libc:0.2.0" here is actually a package id specification which will allow selecting various components of a graph. For example the same named package coming from two distinct locations can be selected against, as well as multiple versions of one crate in a dependency graph. The replacement dependency has the same syntax as the `[dependencies]` section of Cargo.toml. One of the major uses of this syntax will be, for example, using a temporary fork of a crate while the changes are pushed upstream to the original repo. This will avoid the need to change the intermediate projects immediately, and over time once fixes have landed upstream the `[replace]` section in a `Cargo.toml` can be removed. There are also two crucial restrictions on overrides. * A crate with the name `foo` can only get overridden with packages also of the name `foo`. * A crate can only get overridden with a crate of the exact same version. A consequence of these restrictions is that crates.io cannot be used to replace anything from crates.io. There's only one version of something on crates.io, so there's nothing else to replace it with (name/version are a unique key). Closes #942
2016-02-09 23:42:17 +00:00
Package::new("foo", "0.2.0").publish();
Package::new("foo", "0.1.0").publish();
let p = project("local")
.file("Cargo.toml", r#"
[package]
name = "local"
version = "0.0.1"
authors = []
[dependencies]
foo = "0.1.0"
[replace]
"foo:0.1.0" = "0.2.0"
"#)
.file("src/lib.rs", "");
assert_that(p.cargo_process("build"),
execs().with_status(101).with_stderr("\
error: failed to parse manifest at `[..]`
Caused by:
replacements cannot specify a version requirement, but found one for [..]
"));
}
Implement top-level overrides This commit is an implementation of top-level overrides to be encoded into the manifest itself directly. This style of override is distinct from the existing `paths` support in `.cargo/config` in two important ways: * Top level overrides are intended to be checked in and shared amongst all developers of a project. * Top level overrides are reflected in `Cargo.lock`. The second point is crucially important here as it will ensure that an override on one machine behaves the same as an override on another machine. This solves many long-standing problems with `paths`-based overrides which suffer from some level of nondeterminism as they're not encoded. From a syntactical point of view, an override looks like: ```toml [replace] "libc:0.2.0" = { git = 'https://github.com/my-username/libc', branch = '0.2-fork' } ``` This declaration indicates that whenever resolution would otherwise encounter the `libc` package version 0.2.0 from crates.io, it should instead replace it with the custom git dependency on a specific branch. The key "libc:0.2.0" here is actually a package id specification which will allow selecting various components of a graph. For example the same named package coming from two distinct locations can be selected against, as well as multiple versions of one crate in a dependency graph. The replacement dependency has the same syntax as the `[dependencies]` section of Cargo.toml. One of the major uses of this syntax will be, for example, using a temporary fork of a crate while the changes are pushed upstream to the original repo. This will avoid the need to change the intermediate projects immediately, and over time once fixes have landed upstream the `[replace]` section in a `Cargo.toml` can be removed. There are also two crucial restrictions on overrides. * A crate with the name `foo` can only get overridden with packages also of the name `foo`. * A crate can only get overridden with a crate of the exact same version. A consequence of these restrictions is that crates.io cannot be used to replace anything from crates.io. There's only one version of something on crates.io, so there's nothing else to replace it with (name/version are a unique key). Closes #942
2016-02-09 23:42:17 +00:00
#[test]
fn transitive() {
Implement top-level overrides This commit is an implementation of top-level overrides to be encoded into the manifest itself directly. This style of override is distinct from the existing `paths` support in `.cargo/config` in two important ways: * Top level overrides are intended to be checked in and shared amongst all developers of a project. * Top level overrides are reflected in `Cargo.lock`. The second point is crucially important here as it will ensure that an override on one machine behaves the same as an override on another machine. This solves many long-standing problems with `paths`-based overrides which suffer from some level of nondeterminism as they're not encoded. From a syntactical point of view, an override looks like: ```toml [replace] "libc:0.2.0" = { git = 'https://github.com/my-username/libc', branch = '0.2-fork' } ``` This declaration indicates that whenever resolution would otherwise encounter the `libc` package version 0.2.0 from crates.io, it should instead replace it with the custom git dependency on a specific branch. The key "libc:0.2.0" here is actually a package id specification which will allow selecting various components of a graph. For example the same named package coming from two distinct locations can be selected against, as well as multiple versions of one crate in a dependency graph. The replacement dependency has the same syntax as the `[dependencies]` section of Cargo.toml. One of the major uses of this syntax will be, for example, using a temporary fork of a crate while the changes are pushed upstream to the original repo. This will avoid the need to change the intermediate projects immediately, and over time once fixes have landed upstream the `[replace]` section in a `Cargo.toml` can be removed. There are also two crucial restrictions on overrides. * A crate with the name `foo` can only get overridden with packages also of the name `foo`. * A crate can only get overridden with a crate of the exact same version. A consequence of these restrictions is that crates.io cannot be used to replace anything from crates.io. There's only one version of something on crates.io, so there's nothing else to replace it with (name/version are a unique key). Closes #942
2016-02-09 23:42:17 +00:00
Package::new("foo", "0.1.0").publish();
Package::new("bar", "0.2.0")
.dep("foo", "0.1.0")
.file("src/lib.rs", "extern crate foo; fn bar() { foo::foo(); }")
.publish();
let foo = git::repo(&paths::root().join("override"))
.file("Cargo.toml", r#"
[package]
name = "foo"
version = "0.1.0"
authors = []
"#)
.file("src/lib.rs", "pub fn foo() {}");
foo.build();
let p = project("local")
.file("Cargo.toml", &format!(r#"
[package]
name = "local"
version = "0.0.1"
authors = []
[dependencies]
bar = "0.2.0"
[replace]
"foo:0.1.0" = {{ git = '{}' }}
"#, foo.url()))
.file("src/lib.rs", "");
assert_that(p.cargo_process("build"),
2016-05-14 21:15:22 +00:00
execs().with_status(0).with_stderr("\
[UPDATING] registry `file://[..]`
[UPDATING] git repository `[..]`
[DOWNLOADING] bar v0.2.0 (registry [..])
[COMPILING] foo v0.1.0 (file://[..])
Implement source redirection This commit implements a scheme for .cargo/config files where sources can be redirected to other sources. The purpose of this will be to override crates.io for a few use cases: * Replace it with a mirror site that is sync'd to crates.io * Replace it with a "directory source" or some other local source This major feature of this redirection, however, is that none of it is encoded into the lock file. If one source is redirected to another then it is assumed that packages from both are exactly the same (e.g. `foo v0.0.1` is the same in both location). The lock file simply encodes the canonical soure (e.g. crates.io) rather than the replacement source. In the end this means that Cargo.lock files can be generated from any replacement source and shipped to other locations without the lockfile oscillating about where packages came from. Eventually this support will be extended to `Cargo.toml` itself (which will be encoded into the lock file), but that support is not implemented today. The syntax for what was implemented today looks like: # .cargo/config [source.my-awesome-registry] registry = 'https://example.com/path/to/index' [source.crates-io] replace-with = 'my-awesome-registry' Each source will have a canonical name and will be configured with the various keys underneath it (today just 'registry' and 'directory' will be accepted). The global `crates-io` source represents crates from the standard registry, and this can be replaced with other mirror sources. All tests have been modified to use this new infrastructure instead of the old `registry.index` configuration. This configuration is now also deprecated and will emit an unconditional warning about how it will no longer be used in the future. Finally, all subcommands now use this "source map" except for `cargo publish`, which will always publish to the default registry (in this case crates.io).
2016-02-03 18:54:07 +00:00
[COMPILING] bar v0.2.0
[COMPILING] local v0.0.1 (file://[..])
[FINISHED] debug [unoptimized + debuginfo] target(s) in [..]
2016-05-12 17:06:36 +00:00
"));
Implement top-level overrides This commit is an implementation of top-level overrides to be encoded into the manifest itself directly. This style of override is distinct from the existing `paths` support in `.cargo/config` in two important ways: * Top level overrides are intended to be checked in and shared amongst all developers of a project. * Top level overrides are reflected in `Cargo.lock`. The second point is crucially important here as it will ensure that an override on one machine behaves the same as an override on another machine. This solves many long-standing problems with `paths`-based overrides which suffer from some level of nondeterminism as they're not encoded. From a syntactical point of view, an override looks like: ```toml [replace] "libc:0.2.0" = { git = 'https://github.com/my-username/libc', branch = '0.2-fork' } ``` This declaration indicates that whenever resolution would otherwise encounter the `libc` package version 0.2.0 from crates.io, it should instead replace it with the custom git dependency on a specific branch. The key "libc:0.2.0" here is actually a package id specification which will allow selecting various components of a graph. For example the same named package coming from two distinct locations can be selected against, as well as multiple versions of one crate in a dependency graph. The replacement dependency has the same syntax as the `[dependencies]` section of Cargo.toml. One of the major uses of this syntax will be, for example, using a temporary fork of a crate while the changes are pushed upstream to the original repo. This will avoid the need to change the intermediate projects immediately, and over time once fixes have landed upstream the `[replace]` section in a `Cargo.toml` can be removed. There are also two crucial restrictions on overrides. * A crate with the name `foo` can only get overridden with packages also of the name `foo`. * A crate can only get overridden with a crate of the exact same version. A consequence of these restrictions is that crates.io cannot be used to replace anything from crates.io. There's only one version of something on crates.io, so there's nothing else to replace it with (name/version are a unique key). Closes #942
2016-02-09 23:42:17 +00:00
assert_that(p.cargo("build"), execs().with_status(0).with_stdout(""));
}
Implement top-level overrides This commit is an implementation of top-level overrides to be encoded into the manifest itself directly. This style of override is distinct from the existing `paths` support in `.cargo/config` in two important ways: * Top level overrides are intended to be checked in and shared amongst all developers of a project. * Top level overrides are reflected in `Cargo.lock`. The second point is crucially important here as it will ensure that an override on one machine behaves the same as an override on another machine. This solves many long-standing problems with `paths`-based overrides which suffer from some level of nondeterminism as they're not encoded. From a syntactical point of view, an override looks like: ```toml [replace] "libc:0.2.0" = { git = 'https://github.com/my-username/libc', branch = '0.2-fork' } ``` This declaration indicates that whenever resolution would otherwise encounter the `libc` package version 0.2.0 from crates.io, it should instead replace it with the custom git dependency on a specific branch. The key "libc:0.2.0" here is actually a package id specification which will allow selecting various components of a graph. For example the same named package coming from two distinct locations can be selected against, as well as multiple versions of one crate in a dependency graph. The replacement dependency has the same syntax as the `[dependencies]` section of Cargo.toml. One of the major uses of this syntax will be, for example, using a temporary fork of a crate while the changes are pushed upstream to the original repo. This will avoid the need to change the intermediate projects immediately, and over time once fixes have landed upstream the `[replace]` section in a `Cargo.toml` can be removed. There are also two crucial restrictions on overrides. * A crate with the name `foo` can only get overridden with packages also of the name `foo`. * A crate can only get overridden with a crate of the exact same version. A consequence of these restrictions is that crates.io cannot be used to replace anything from crates.io. There's only one version of something on crates.io, so there's nothing else to replace it with (name/version are a unique key). Closes #942
2016-02-09 23:42:17 +00:00
#[test]
fn persists_across_rebuilds() {
Implement top-level overrides This commit is an implementation of top-level overrides to be encoded into the manifest itself directly. This style of override is distinct from the existing `paths` support in `.cargo/config` in two important ways: * Top level overrides are intended to be checked in and shared amongst all developers of a project. * Top level overrides are reflected in `Cargo.lock`. The second point is crucially important here as it will ensure that an override on one machine behaves the same as an override on another machine. This solves many long-standing problems with `paths`-based overrides which suffer from some level of nondeterminism as they're not encoded. From a syntactical point of view, an override looks like: ```toml [replace] "libc:0.2.0" = { git = 'https://github.com/my-username/libc', branch = '0.2-fork' } ``` This declaration indicates that whenever resolution would otherwise encounter the `libc` package version 0.2.0 from crates.io, it should instead replace it with the custom git dependency on a specific branch. The key "libc:0.2.0" here is actually a package id specification which will allow selecting various components of a graph. For example the same named package coming from two distinct locations can be selected against, as well as multiple versions of one crate in a dependency graph. The replacement dependency has the same syntax as the `[dependencies]` section of Cargo.toml. One of the major uses of this syntax will be, for example, using a temporary fork of a crate while the changes are pushed upstream to the original repo. This will avoid the need to change the intermediate projects immediately, and over time once fixes have landed upstream the `[replace]` section in a `Cargo.toml` can be removed. There are also two crucial restrictions on overrides. * A crate with the name `foo` can only get overridden with packages also of the name `foo`. * A crate can only get overridden with a crate of the exact same version. A consequence of these restrictions is that crates.io cannot be used to replace anything from crates.io. There's only one version of something on crates.io, so there's nothing else to replace it with (name/version are a unique key). Closes #942
2016-02-09 23:42:17 +00:00
Package::new("foo", "0.1.0").publish();
let foo = git::repo(&paths::root().join("override"))
.file("Cargo.toml", r#"
[package]
name = "foo"
version = "0.1.0"
authors = []
"#)
.file("src/lib.rs", "pub fn foo() {}");
foo.build();
let p = project("local")
.file("Cargo.toml", &format!(r#"
[package]
name = "local"
version = "0.0.1"
authors = []
[dependencies]
foo = "0.1.0"
[replace]
"foo:0.1.0" = {{ git = '{}' }}
"#, foo.url()))
.file("src/lib.rs", "
extern crate foo;
pub fn bar() {
foo::foo();
}
");
assert_that(p.cargo_process("build"),
2016-05-14 21:15:22 +00:00
execs().with_status(0).with_stderr("\
[UPDATING] registry `file://[..]`
[UPDATING] git repository `file://[..]`
[COMPILING] foo v0.1.0 (file://[..])
[COMPILING] local v0.0.1 (file://[..])
[FINISHED] debug [unoptimized + debuginfo] target(s) in [..]
2016-05-12 17:06:36 +00:00
"));
Implement top-level overrides This commit is an implementation of top-level overrides to be encoded into the manifest itself directly. This style of override is distinct from the existing `paths` support in `.cargo/config` in two important ways: * Top level overrides are intended to be checked in and shared amongst all developers of a project. * Top level overrides are reflected in `Cargo.lock`. The second point is crucially important here as it will ensure that an override on one machine behaves the same as an override on another machine. This solves many long-standing problems with `paths`-based overrides which suffer from some level of nondeterminism as they're not encoded. From a syntactical point of view, an override looks like: ```toml [replace] "libc:0.2.0" = { git = 'https://github.com/my-username/libc', branch = '0.2-fork' } ``` This declaration indicates that whenever resolution would otherwise encounter the `libc` package version 0.2.0 from crates.io, it should instead replace it with the custom git dependency on a specific branch. The key "libc:0.2.0" here is actually a package id specification which will allow selecting various components of a graph. For example the same named package coming from two distinct locations can be selected against, as well as multiple versions of one crate in a dependency graph. The replacement dependency has the same syntax as the `[dependencies]` section of Cargo.toml. One of the major uses of this syntax will be, for example, using a temporary fork of a crate while the changes are pushed upstream to the original repo. This will avoid the need to change the intermediate projects immediately, and over time once fixes have landed upstream the `[replace]` section in a `Cargo.toml` can be removed. There are also two crucial restrictions on overrides. * A crate with the name `foo` can only get overridden with packages also of the name `foo`. * A crate can only get overridden with a crate of the exact same version. A consequence of these restrictions is that crates.io cannot be used to replace anything from crates.io. There's only one version of something on crates.io, so there's nothing else to replace it with (name/version are a unique key). Closes #942
2016-02-09 23:42:17 +00:00
assert_that(p.cargo("build"),
execs().with_status(0).with_stdout(""));
}
Implement top-level overrides This commit is an implementation of top-level overrides to be encoded into the manifest itself directly. This style of override is distinct from the existing `paths` support in `.cargo/config` in two important ways: * Top level overrides are intended to be checked in and shared amongst all developers of a project. * Top level overrides are reflected in `Cargo.lock`. The second point is crucially important here as it will ensure that an override on one machine behaves the same as an override on another machine. This solves many long-standing problems with `paths`-based overrides which suffer from some level of nondeterminism as they're not encoded. From a syntactical point of view, an override looks like: ```toml [replace] "libc:0.2.0" = { git = 'https://github.com/my-username/libc', branch = '0.2-fork' } ``` This declaration indicates that whenever resolution would otherwise encounter the `libc` package version 0.2.0 from crates.io, it should instead replace it with the custom git dependency on a specific branch. The key "libc:0.2.0" here is actually a package id specification which will allow selecting various components of a graph. For example the same named package coming from two distinct locations can be selected against, as well as multiple versions of one crate in a dependency graph. The replacement dependency has the same syntax as the `[dependencies]` section of Cargo.toml. One of the major uses of this syntax will be, for example, using a temporary fork of a crate while the changes are pushed upstream to the original repo. This will avoid the need to change the intermediate projects immediately, and over time once fixes have landed upstream the `[replace]` section in a `Cargo.toml` can be removed. There are also two crucial restrictions on overrides. * A crate with the name `foo` can only get overridden with packages also of the name `foo`. * A crate can only get overridden with a crate of the exact same version. A consequence of these restrictions is that crates.io cannot be used to replace anything from crates.io. There's only one version of something on crates.io, so there's nothing else to replace it with (name/version are a unique key). Closes #942
2016-02-09 23:42:17 +00:00
#[test]
fn replace_registry_with_path() {
Implement top-level overrides This commit is an implementation of top-level overrides to be encoded into the manifest itself directly. This style of override is distinct from the existing `paths` support in `.cargo/config` in two important ways: * Top level overrides are intended to be checked in and shared amongst all developers of a project. * Top level overrides are reflected in `Cargo.lock`. The second point is crucially important here as it will ensure that an override on one machine behaves the same as an override on another machine. This solves many long-standing problems with `paths`-based overrides which suffer from some level of nondeterminism as they're not encoded. From a syntactical point of view, an override looks like: ```toml [replace] "libc:0.2.0" = { git = 'https://github.com/my-username/libc', branch = '0.2-fork' } ``` This declaration indicates that whenever resolution would otherwise encounter the `libc` package version 0.2.0 from crates.io, it should instead replace it with the custom git dependency on a specific branch. The key "libc:0.2.0" here is actually a package id specification which will allow selecting various components of a graph. For example the same named package coming from two distinct locations can be selected against, as well as multiple versions of one crate in a dependency graph. The replacement dependency has the same syntax as the `[dependencies]` section of Cargo.toml. One of the major uses of this syntax will be, for example, using a temporary fork of a crate while the changes are pushed upstream to the original repo. This will avoid the need to change the intermediate projects immediately, and over time once fixes have landed upstream the `[replace]` section in a `Cargo.toml` can be removed. There are also two crucial restrictions on overrides. * A crate with the name `foo` can only get overridden with packages also of the name `foo`. * A crate can only get overridden with a crate of the exact same version. A consequence of these restrictions is that crates.io cannot be used to replace anything from crates.io. There's only one version of something on crates.io, so there's nothing else to replace it with (name/version are a unique key). Closes #942
2016-02-09 23:42:17 +00:00
Package::new("foo", "0.1.0").publish();
project("foo")
.file("Cargo.toml", r#"
[package]
name = "foo"
version = "0.1.0"
authors = []
"#)
.file("src/lib.rs", "pub fn foo() {}")
.build();
let p = project("local")
.file("Cargo.toml", r#"
[package]
name = "local"
version = "0.0.1"
authors = []
[dependencies]
foo = "0.1.0"
[replace]
"foo:0.1.0" = { path = "../foo" }
"#)
.file("src/lib.rs", "
extern crate foo;
pub fn bar() {
foo::foo();
}
");
assert_that(p.cargo_process("build"),
2016-05-14 21:15:22 +00:00
execs().with_status(0).with_stderr("\
[UPDATING] registry `file://[..]`
[COMPILING] foo v0.1.0 (file://[..])
[COMPILING] local v0.0.1 (file://[..])
[FINISHED] debug [unoptimized + debuginfo] target(s) in [..]
2016-05-12 17:06:36 +00:00
"));
}
Implement top-level overrides This commit is an implementation of top-level overrides to be encoded into the manifest itself directly. This style of override is distinct from the existing `paths` support in `.cargo/config` in two important ways: * Top level overrides are intended to be checked in and shared amongst all developers of a project. * Top level overrides are reflected in `Cargo.lock`. The second point is crucially important here as it will ensure that an override on one machine behaves the same as an override on another machine. This solves many long-standing problems with `paths`-based overrides which suffer from some level of nondeterminism as they're not encoded. From a syntactical point of view, an override looks like: ```toml [replace] "libc:0.2.0" = { git = 'https://github.com/my-username/libc', branch = '0.2-fork' } ``` This declaration indicates that whenever resolution would otherwise encounter the `libc` package version 0.2.0 from crates.io, it should instead replace it with the custom git dependency on a specific branch. The key "libc:0.2.0" here is actually a package id specification which will allow selecting various components of a graph. For example the same named package coming from two distinct locations can be selected against, as well as multiple versions of one crate in a dependency graph. The replacement dependency has the same syntax as the `[dependencies]` section of Cargo.toml. One of the major uses of this syntax will be, for example, using a temporary fork of a crate while the changes are pushed upstream to the original repo. This will avoid the need to change the intermediate projects immediately, and over time once fixes have landed upstream the `[replace]` section in a `Cargo.toml` can be removed. There are also two crucial restrictions on overrides. * A crate with the name `foo` can only get overridden with packages also of the name `foo`. * A crate can only get overridden with a crate of the exact same version. A consequence of these restrictions is that crates.io cannot be used to replace anything from crates.io. There's only one version of something on crates.io, so there's nothing else to replace it with (name/version are a unique key). Closes #942
2016-02-09 23:42:17 +00:00
#[test]
fn use_a_spec_to_select() {
Implement top-level overrides This commit is an implementation of top-level overrides to be encoded into the manifest itself directly. This style of override is distinct from the existing `paths` support in `.cargo/config` in two important ways: * Top level overrides are intended to be checked in and shared amongst all developers of a project. * Top level overrides are reflected in `Cargo.lock`. The second point is crucially important here as it will ensure that an override on one machine behaves the same as an override on another machine. This solves many long-standing problems with `paths`-based overrides which suffer from some level of nondeterminism as they're not encoded. From a syntactical point of view, an override looks like: ```toml [replace] "libc:0.2.0" = { git = 'https://github.com/my-username/libc', branch = '0.2-fork' } ``` This declaration indicates that whenever resolution would otherwise encounter the `libc` package version 0.2.0 from crates.io, it should instead replace it with the custom git dependency on a specific branch. The key "libc:0.2.0" here is actually a package id specification which will allow selecting various components of a graph. For example the same named package coming from two distinct locations can be selected against, as well as multiple versions of one crate in a dependency graph. The replacement dependency has the same syntax as the `[dependencies]` section of Cargo.toml. One of the major uses of this syntax will be, for example, using a temporary fork of a crate while the changes are pushed upstream to the original repo. This will avoid the need to change the intermediate projects immediately, and over time once fixes have landed upstream the `[replace]` section in a `Cargo.toml` can be removed. There are also two crucial restrictions on overrides. * A crate with the name `foo` can only get overridden with packages also of the name `foo`. * A crate can only get overridden with a crate of the exact same version. A consequence of these restrictions is that crates.io cannot be used to replace anything from crates.io. There's only one version of something on crates.io, so there's nothing else to replace it with (name/version are a unique key). Closes #942
2016-02-09 23:42:17 +00:00
Package::new("foo", "0.1.1")
.file("src/lib.rs", "pub fn foo1() {}")
.publish();
Package::new("foo", "0.2.0").publish();
Package::new("bar", "0.1.1")
.dep("foo", "0.2")
.file("src/lib.rs", "
extern crate foo;
pub fn bar() { foo::foo3(); }
")
.publish();
let foo = git::repo(&paths::root().join("override"))
.file("Cargo.toml", r#"
[package]
name = "foo"
version = "0.2.0"
authors = []
"#)
.file("src/lib.rs", "pub fn foo3() {}");
foo.build();
let p = project("local")
.file("Cargo.toml", &format!(r#"
[package]
name = "local"
version = "0.0.1"
authors = []
[dependencies]
bar = "0.1"
foo = "0.1"
[replace]
"foo:0.2.0" = {{ git = '{}' }}
"#, foo.url()))
.file("src/lib.rs", "
extern crate foo;
extern crate bar;
2016-05-20 11:47:39 +00:00
pub fn local() {
Implement top-level overrides This commit is an implementation of top-level overrides to be encoded into the manifest itself directly. This style of override is distinct from the existing `paths` support in `.cargo/config` in two important ways: * Top level overrides are intended to be checked in and shared amongst all developers of a project. * Top level overrides are reflected in `Cargo.lock`. The second point is crucially important here as it will ensure that an override on one machine behaves the same as an override on another machine. This solves many long-standing problems with `paths`-based overrides which suffer from some level of nondeterminism as they're not encoded. From a syntactical point of view, an override looks like: ```toml [replace] "libc:0.2.0" = { git = 'https://github.com/my-username/libc', branch = '0.2-fork' } ``` This declaration indicates that whenever resolution would otherwise encounter the `libc` package version 0.2.0 from crates.io, it should instead replace it with the custom git dependency on a specific branch. The key "libc:0.2.0" here is actually a package id specification which will allow selecting various components of a graph. For example the same named package coming from two distinct locations can be selected against, as well as multiple versions of one crate in a dependency graph. The replacement dependency has the same syntax as the `[dependencies]` section of Cargo.toml. One of the major uses of this syntax will be, for example, using a temporary fork of a crate while the changes are pushed upstream to the original repo. This will avoid the need to change the intermediate projects immediately, and over time once fixes have landed upstream the `[replace]` section in a `Cargo.toml` can be removed. There are also two crucial restrictions on overrides. * A crate with the name `foo` can only get overridden with packages also of the name `foo`. * A crate can only get overridden with a crate of the exact same version. A consequence of these restrictions is that crates.io cannot be used to replace anything from crates.io. There's only one version of something on crates.io, so there's nothing else to replace it with (name/version are a unique key). Closes #942
2016-02-09 23:42:17 +00:00
foo::foo1();
bar::bar();
}
");
assert_that(p.cargo_process("build"),
2016-05-14 21:15:22 +00:00
execs().with_status(0).with_stderr("\
[UPDATING] registry `file://[..]`
[UPDATING] git repository `[..]`
[DOWNLOADING] [..]
[DOWNLOADING] [..]
[COMPILING] [..]
[COMPILING] [..]
[COMPILING] [..]
[COMPILING] local v0.0.1 (file://[..])
[FINISHED] debug [unoptimized + debuginfo] target(s) in [..]
2016-05-12 17:06:36 +00:00
"));
}
Implement top-level overrides This commit is an implementation of top-level overrides to be encoded into the manifest itself directly. This style of override is distinct from the existing `paths` support in `.cargo/config` in two important ways: * Top level overrides are intended to be checked in and shared amongst all developers of a project. * Top level overrides are reflected in `Cargo.lock`. The second point is crucially important here as it will ensure that an override on one machine behaves the same as an override on another machine. This solves many long-standing problems with `paths`-based overrides which suffer from some level of nondeterminism as they're not encoded. From a syntactical point of view, an override looks like: ```toml [replace] "libc:0.2.0" = { git = 'https://github.com/my-username/libc', branch = '0.2-fork' } ``` This declaration indicates that whenever resolution would otherwise encounter the `libc` package version 0.2.0 from crates.io, it should instead replace it with the custom git dependency on a specific branch. The key "libc:0.2.0" here is actually a package id specification which will allow selecting various components of a graph. For example the same named package coming from two distinct locations can be selected against, as well as multiple versions of one crate in a dependency graph. The replacement dependency has the same syntax as the `[dependencies]` section of Cargo.toml. One of the major uses of this syntax will be, for example, using a temporary fork of a crate while the changes are pushed upstream to the original repo. This will avoid the need to change the intermediate projects immediately, and over time once fixes have landed upstream the `[replace]` section in a `Cargo.toml` can be removed. There are also two crucial restrictions on overrides. * A crate with the name `foo` can only get overridden with packages also of the name `foo`. * A crate can only get overridden with a crate of the exact same version. A consequence of these restrictions is that crates.io cannot be used to replace anything from crates.io. There's only one version of something on crates.io, so there's nothing else to replace it with (name/version are a unique key). Closes #942
2016-02-09 23:42:17 +00:00
#[test]
fn override_adds_some_deps() {
Implement top-level overrides This commit is an implementation of top-level overrides to be encoded into the manifest itself directly. This style of override is distinct from the existing `paths` support in `.cargo/config` in two important ways: * Top level overrides are intended to be checked in and shared amongst all developers of a project. * Top level overrides are reflected in `Cargo.lock`. The second point is crucially important here as it will ensure that an override on one machine behaves the same as an override on another machine. This solves many long-standing problems with `paths`-based overrides which suffer from some level of nondeterminism as they're not encoded. From a syntactical point of view, an override looks like: ```toml [replace] "libc:0.2.0" = { git = 'https://github.com/my-username/libc', branch = '0.2-fork' } ``` This declaration indicates that whenever resolution would otherwise encounter the `libc` package version 0.2.0 from crates.io, it should instead replace it with the custom git dependency on a specific branch. The key "libc:0.2.0" here is actually a package id specification which will allow selecting various components of a graph. For example the same named package coming from two distinct locations can be selected against, as well as multiple versions of one crate in a dependency graph. The replacement dependency has the same syntax as the `[dependencies]` section of Cargo.toml. One of the major uses of this syntax will be, for example, using a temporary fork of a crate while the changes are pushed upstream to the original repo. This will avoid the need to change the intermediate projects immediately, and over time once fixes have landed upstream the `[replace]` section in a `Cargo.toml` can be removed. There are also two crucial restrictions on overrides. * A crate with the name `foo` can only get overridden with packages also of the name `foo`. * A crate can only get overridden with a crate of the exact same version. A consequence of these restrictions is that crates.io cannot be used to replace anything from crates.io. There's only one version of something on crates.io, so there's nothing else to replace it with (name/version are a unique key). Closes #942
2016-02-09 23:42:17 +00:00
Package::new("foo", "0.1.1").publish();
Package::new("bar", "0.1.0").publish();
let foo = git::repo(&paths::root().join("override"))
.file("Cargo.toml", r#"
[package]
name = "bar"
version = "0.1.0"
authors = []
[dependencies]
foo = "0.1"
"#)
.file("src/lib.rs", "");
foo.build();
let p = project("local")
.file("Cargo.toml", &format!(r#"
[package]
name = "local"
version = "0.0.1"
authors = []
[dependencies]
bar = "0.1"
[replace]
"bar:0.1.0" = {{ git = '{}' }}
"#, foo.url()))
.file("src/lib.rs", "");
assert_that(p.cargo_process("build"),
2016-05-14 21:15:22 +00:00
execs().with_status(0).with_stderr("\
[UPDATING] registry `file://[..]`
[UPDATING] git repository `[..]`
[DOWNLOADING] foo v0.1.1 (registry [..])
Implement source redirection This commit implements a scheme for .cargo/config files where sources can be redirected to other sources. The purpose of this will be to override crates.io for a few use cases: * Replace it with a mirror site that is sync'd to crates.io * Replace it with a "directory source" or some other local source This major feature of this redirection, however, is that none of it is encoded into the lock file. If one source is redirected to another then it is assumed that packages from both are exactly the same (e.g. `foo v0.0.1` is the same in both location). The lock file simply encodes the canonical soure (e.g. crates.io) rather than the replacement source. In the end this means that Cargo.lock files can be generated from any replacement source and shipped to other locations without the lockfile oscillating about where packages came from. Eventually this support will be extended to `Cargo.toml` itself (which will be encoded into the lock file), but that support is not implemented today. The syntax for what was implemented today looks like: # .cargo/config [source.my-awesome-registry] registry = 'https://example.com/path/to/index' [source.crates-io] replace-with = 'my-awesome-registry' Each source will have a canonical name and will be configured with the various keys underneath it (today just 'registry' and 'directory' will be accepted). The global `crates-io` source represents crates from the standard registry, and this can be replaced with other mirror sources. All tests have been modified to use this new infrastructure instead of the old `registry.index` configuration. This configuration is now also deprecated and will emit an unconditional warning about how it will no longer be used in the future. Finally, all subcommands now use this "source map" except for `cargo publish`, which will always publish to the default registry (in this case crates.io).
2016-02-03 18:54:07 +00:00
[COMPILING] foo v0.1.1
[COMPILING] bar v0.1.0 ([..])
[COMPILING] local v0.0.1 (file://[..])
[FINISHED] debug [unoptimized + debuginfo] target(s) in [..]
2016-05-12 17:06:36 +00:00
"));
Implement top-level overrides This commit is an implementation of top-level overrides to be encoded into the manifest itself directly. This style of override is distinct from the existing `paths` support in `.cargo/config` in two important ways: * Top level overrides are intended to be checked in and shared amongst all developers of a project. * Top level overrides are reflected in `Cargo.lock`. The second point is crucially important here as it will ensure that an override on one machine behaves the same as an override on another machine. This solves many long-standing problems with `paths`-based overrides which suffer from some level of nondeterminism as they're not encoded. From a syntactical point of view, an override looks like: ```toml [replace] "libc:0.2.0" = { git = 'https://github.com/my-username/libc', branch = '0.2-fork' } ``` This declaration indicates that whenever resolution would otherwise encounter the `libc` package version 0.2.0 from crates.io, it should instead replace it with the custom git dependency on a specific branch. The key "libc:0.2.0" here is actually a package id specification which will allow selecting various components of a graph. For example the same named package coming from two distinct locations can be selected against, as well as multiple versions of one crate in a dependency graph. The replacement dependency has the same syntax as the `[dependencies]` section of Cargo.toml. One of the major uses of this syntax will be, for example, using a temporary fork of a crate while the changes are pushed upstream to the original repo. This will avoid the need to change the intermediate projects immediately, and over time once fixes have landed upstream the `[replace]` section in a `Cargo.toml` can be removed. There are also two crucial restrictions on overrides. * A crate with the name `foo` can only get overridden with packages also of the name `foo`. * A crate can only get overridden with a crate of the exact same version. A consequence of these restrictions is that crates.io cannot be used to replace anything from crates.io. There's only one version of something on crates.io, so there's nothing else to replace it with (name/version are a unique key). Closes #942
2016-02-09 23:42:17 +00:00
assert_that(p.cargo("build"), execs().with_status(0).with_stdout(""));
Package::new("foo", "0.1.2").publish();
assert_that(p.cargo("update").arg("-p").arg(&format!("{}#bar", foo.url())),
2016-05-14 21:15:22 +00:00
execs().with_status(0).with_stderr("\
[UPDATING] git repository `file://[..]`
2016-05-12 17:06:36 +00:00
"));
Implement source redirection This commit implements a scheme for .cargo/config files where sources can be redirected to other sources. The purpose of this will be to override crates.io for a few use cases: * Replace it with a mirror site that is sync'd to crates.io * Replace it with a "directory source" or some other local source This major feature of this redirection, however, is that none of it is encoded into the lock file. If one source is redirected to another then it is assumed that packages from both are exactly the same (e.g. `foo v0.0.1` is the same in both location). The lock file simply encodes the canonical soure (e.g. crates.io) rather than the replacement source. In the end this means that Cargo.lock files can be generated from any replacement source and shipped to other locations without the lockfile oscillating about where packages came from. Eventually this support will be extended to `Cargo.toml` itself (which will be encoded into the lock file), but that support is not implemented today. The syntax for what was implemented today looks like: # .cargo/config [source.my-awesome-registry] registry = 'https://example.com/path/to/index' [source.crates-io] replace-with = 'my-awesome-registry' Each source will have a canonical name and will be configured with the various keys underneath it (today just 'registry' and 'directory' will be accepted). The global `crates-io` source represents crates from the standard registry, and this can be replaced with other mirror sources. All tests have been modified to use this new infrastructure instead of the old `registry.index` configuration. This configuration is now also deprecated and will emit an unconditional warning about how it will no longer be used in the future. Finally, all subcommands now use this "source map" except for `cargo publish`, which will always publish to the default registry (in this case crates.io).
2016-02-03 18:54:07 +00:00
assert_that(p.cargo("update")
.arg("-p")
.arg("https://github.com/rust-lang/crates.io-index#bar"),
2016-05-14 21:15:22 +00:00
execs().with_status(0).with_stderr("\
[UPDATING] registry `file://[..]`
2016-05-12 17:06:36 +00:00
"));
Implement top-level overrides This commit is an implementation of top-level overrides to be encoded into the manifest itself directly. This style of override is distinct from the existing `paths` support in `.cargo/config` in two important ways: * Top level overrides are intended to be checked in and shared amongst all developers of a project. * Top level overrides are reflected in `Cargo.lock`. The second point is crucially important here as it will ensure that an override on one machine behaves the same as an override on another machine. This solves many long-standing problems with `paths`-based overrides which suffer from some level of nondeterminism as they're not encoded. From a syntactical point of view, an override looks like: ```toml [replace] "libc:0.2.0" = { git = 'https://github.com/my-username/libc', branch = '0.2-fork' } ``` This declaration indicates that whenever resolution would otherwise encounter the `libc` package version 0.2.0 from crates.io, it should instead replace it with the custom git dependency on a specific branch. The key "libc:0.2.0" here is actually a package id specification which will allow selecting various components of a graph. For example the same named package coming from two distinct locations can be selected against, as well as multiple versions of one crate in a dependency graph. The replacement dependency has the same syntax as the `[dependencies]` section of Cargo.toml. One of the major uses of this syntax will be, for example, using a temporary fork of a crate while the changes are pushed upstream to the original repo. This will avoid the need to change the intermediate projects immediately, and over time once fixes have landed upstream the `[replace]` section in a `Cargo.toml` can be removed. There are also two crucial restrictions on overrides. * A crate with the name `foo` can only get overridden with packages also of the name `foo`. * A crate can only get overridden with a crate of the exact same version. A consequence of these restrictions is that crates.io cannot be used to replace anything from crates.io. There's only one version of something on crates.io, so there's nothing else to replace it with (name/version are a unique key). Closes #942
2016-02-09 23:42:17 +00:00
assert_that(p.cargo("build"), execs().with_status(0).with_stdout(""));
}
Implement top-level overrides This commit is an implementation of top-level overrides to be encoded into the manifest itself directly. This style of override is distinct from the existing `paths` support in `.cargo/config` in two important ways: * Top level overrides are intended to be checked in and shared amongst all developers of a project. * Top level overrides are reflected in `Cargo.lock`. The second point is crucially important here as it will ensure that an override on one machine behaves the same as an override on another machine. This solves many long-standing problems with `paths`-based overrides which suffer from some level of nondeterminism as they're not encoded. From a syntactical point of view, an override looks like: ```toml [replace] "libc:0.2.0" = { git = 'https://github.com/my-username/libc', branch = '0.2-fork' } ``` This declaration indicates that whenever resolution would otherwise encounter the `libc` package version 0.2.0 from crates.io, it should instead replace it with the custom git dependency on a specific branch. The key "libc:0.2.0" here is actually a package id specification which will allow selecting various components of a graph. For example the same named package coming from two distinct locations can be selected against, as well as multiple versions of one crate in a dependency graph. The replacement dependency has the same syntax as the `[dependencies]` section of Cargo.toml. One of the major uses of this syntax will be, for example, using a temporary fork of a crate while the changes are pushed upstream to the original repo. This will avoid the need to change the intermediate projects immediately, and over time once fixes have landed upstream the `[replace]` section in a `Cargo.toml` can be removed. There are also two crucial restrictions on overrides. * A crate with the name `foo` can only get overridden with packages also of the name `foo`. * A crate can only get overridden with a crate of the exact same version. A consequence of these restrictions is that crates.io cannot be used to replace anything from crates.io. There's only one version of something on crates.io, so there's nothing else to replace it with (name/version are a unique key). Closes #942
2016-02-09 23:42:17 +00:00
#[test]
fn locked_means_locked_yes_no_seriously_i_mean_locked() {
Implement top-level overrides This commit is an implementation of top-level overrides to be encoded into the manifest itself directly. This style of override is distinct from the existing `paths` support in `.cargo/config` in two important ways: * Top level overrides are intended to be checked in and shared amongst all developers of a project. * Top level overrides are reflected in `Cargo.lock`. The second point is crucially important here as it will ensure that an override on one machine behaves the same as an override on another machine. This solves many long-standing problems with `paths`-based overrides which suffer from some level of nondeterminism as they're not encoded. From a syntactical point of view, an override looks like: ```toml [replace] "libc:0.2.0" = { git = 'https://github.com/my-username/libc', branch = '0.2-fork' } ``` This declaration indicates that whenever resolution would otherwise encounter the `libc` package version 0.2.0 from crates.io, it should instead replace it with the custom git dependency on a specific branch. The key "libc:0.2.0" here is actually a package id specification which will allow selecting various components of a graph. For example the same named package coming from two distinct locations can be selected against, as well as multiple versions of one crate in a dependency graph. The replacement dependency has the same syntax as the `[dependencies]` section of Cargo.toml. One of the major uses of this syntax will be, for example, using a temporary fork of a crate while the changes are pushed upstream to the original repo. This will avoid the need to change the intermediate projects immediately, and over time once fixes have landed upstream the `[replace]` section in a `Cargo.toml` can be removed. There are also two crucial restrictions on overrides. * A crate with the name `foo` can only get overridden with packages also of the name `foo`. * A crate can only get overridden with a crate of the exact same version. A consequence of these restrictions is that crates.io cannot be used to replace anything from crates.io. There's only one version of something on crates.io, so there's nothing else to replace it with (name/version are a unique key). Closes #942
2016-02-09 23:42:17 +00:00
// this in theory exercises #2041
Package::new("foo", "0.1.0").publish();
Package::new("foo", "0.2.0").publish();
Package::new("bar", "0.1.0").publish();
let foo = git::repo(&paths::root().join("override"))
.file("Cargo.toml", r#"
[package]
name = "bar"
version = "0.1.0"
authors = []
[dependencies]
foo = "*"
"#)
.file("src/lib.rs", "");
foo.build();
let p = project("local")
.file("Cargo.toml", &format!(r#"
[package]
name = "local"
version = "0.0.1"
authors = []
[dependencies]
foo = "0.1"
bar = "0.1"
[replace]
"bar:0.1.0" = {{ git = '{}' }}
"#, foo.url()))
.file("src/lib.rs", "");
assert_that(p.cargo_process("build"),
execs().with_status(0));
assert_that(p.cargo("build"), execs().with_status(0).with_stdout(""));
assert_that(p.cargo("build"), execs().with_status(0).with_stdout(""));
}
Implement top-level overrides This commit is an implementation of top-level overrides to be encoded into the manifest itself directly. This style of override is distinct from the existing `paths` support in `.cargo/config` in two important ways: * Top level overrides are intended to be checked in and shared amongst all developers of a project. * Top level overrides are reflected in `Cargo.lock`. The second point is crucially important here as it will ensure that an override on one machine behaves the same as an override on another machine. This solves many long-standing problems with `paths`-based overrides which suffer from some level of nondeterminism as they're not encoded. From a syntactical point of view, an override looks like: ```toml [replace] "libc:0.2.0" = { git = 'https://github.com/my-username/libc', branch = '0.2-fork' } ``` This declaration indicates that whenever resolution would otherwise encounter the `libc` package version 0.2.0 from crates.io, it should instead replace it with the custom git dependency on a specific branch. The key "libc:0.2.0" here is actually a package id specification which will allow selecting various components of a graph. For example the same named package coming from two distinct locations can be selected against, as well as multiple versions of one crate in a dependency graph. The replacement dependency has the same syntax as the `[dependencies]` section of Cargo.toml. One of the major uses of this syntax will be, for example, using a temporary fork of a crate while the changes are pushed upstream to the original repo. This will avoid the need to change the intermediate projects immediately, and over time once fixes have landed upstream the `[replace]` section in a `Cargo.toml` can be removed. There are also two crucial restrictions on overrides. * A crate with the name `foo` can only get overridden with packages also of the name `foo`. * A crate can only get overridden with a crate of the exact same version. A consequence of these restrictions is that crates.io cannot be used to replace anything from crates.io. There's only one version of something on crates.io, so there's nothing else to replace it with (name/version are a unique key). Closes #942
2016-02-09 23:42:17 +00:00
#[test]
fn override_wrong_name() {
Implement top-level overrides This commit is an implementation of top-level overrides to be encoded into the manifest itself directly. This style of override is distinct from the existing `paths` support in `.cargo/config` in two important ways: * Top level overrides are intended to be checked in and shared amongst all developers of a project. * Top level overrides are reflected in `Cargo.lock`. The second point is crucially important here as it will ensure that an override on one machine behaves the same as an override on another machine. This solves many long-standing problems with `paths`-based overrides which suffer from some level of nondeterminism as they're not encoded. From a syntactical point of view, an override looks like: ```toml [replace] "libc:0.2.0" = { git = 'https://github.com/my-username/libc', branch = '0.2-fork' } ``` This declaration indicates that whenever resolution would otherwise encounter the `libc` package version 0.2.0 from crates.io, it should instead replace it with the custom git dependency on a specific branch. The key "libc:0.2.0" here is actually a package id specification which will allow selecting various components of a graph. For example the same named package coming from two distinct locations can be selected against, as well as multiple versions of one crate in a dependency graph. The replacement dependency has the same syntax as the `[dependencies]` section of Cargo.toml. One of the major uses of this syntax will be, for example, using a temporary fork of a crate while the changes are pushed upstream to the original repo. This will avoid the need to change the intermediate projects immediately, and over time once fixes have landed upstream the `[replace]` section in a `Cargo.toml` can be removed. There are also two crucial restrictions on overrides. * A crate with the name `foo` can only get overridden with packages also of the name `foo`. * A crate can only get overridden with a crate of the exact same version. A consequence of these restrictions is that crates.io cannot be used to replace anything from crates.io. There's only one version of something on crates.io, so there's nothing else to replace it with (name/version are a unique key). Closes #942
2016-02-09 23:42:17 +00:00
Package::new("foo", "0.1.0").publish();
let foo = git::repo(&paths::root().join("override"))
.file("Cargo.toml", r#"
[package]
name = "bar"
version = "0.1.0"
authors = []
"#)
.file("src/lib.rs", "");
foo.build();
let p = project("local")
.file("Cargo.toml", &format!(r#"
[package]
name = "local"
version = "0.0.1"
authors = []
[dependencies]
foo = "0.1"
[replace]
"foo:0.1.0" = {{ git = '{}' }}
"#, foo.url()))
.file("src/lib.rs", "");
assert_that(p.cargo_process("build"),
execs().with_status(101).with_stderr("\
2016-05-20 11:47:39 +00:00
[UPDATING] registry [..]
[UPDATING] git repository [..]
error: no matching package for override `[..]foo:0.1.0` found
Implement top-level overrides This commit is an implementation of top-level overrides to be encoded into the manifest itself directly. This style of override is distinct from the existing `paths` support in `.cargo/config` in two important ways: * Top level overrides are intended to be checked in and shared amongst all developers of a project. * Top level overrides are reflected in `Cargo.lock`. The second point is crucially important here as it will ensure that an override on one machine behaves the same as an override on another machine. This solves many long-standing problems with `paths`-based overrides which suffer from some level of nondeterminism as they're not encoded. From a syntactical point of view, an override looks like: ```toml [replace] "libc:0.2.0" = { git = 'https://github.com/my-username/libc', branch = '0.2-fork' } ``` This declaration indicates that whenever resolution would otherwise encounter the `libc` package version 0.2.0 from crates.io, it should instead replace it with the custom git dependency on a specific branch. The key "libc:0.2.0" here is actually a package id specification which will allow selecting various components of a graph. For example the same named package coming from two distinct locations can be selected against, as well as multiple versions of one crate in a dependency graph. The replacement dependency has the same syntax as the `[dependencies]` section of Cargo.toml. One of the major uses of this syntax will be, for example, using a temporary fork of a crate while the changes are pushed upstream to the original repo. This will avoid the need to change the intermediate projects immediately, and over time once fixes have landed upstream the `[replace]` section in a `Cargo.toml` can be removed. There are also two crucial restrictions on overrides. * A crate with the name `foo` can only get overridden with packages also of the name `foo`. * A crate can only get overridden with a crate of the exact same version. A consequence of these restrictions is that crates.io cannot be used to replace anything from crates.io. There's only one version of something on crates.io, so there's nothing else to replace it with (name/version are a unique key). Closes #942
2016-02-09 23:42:17 +00:00
location searched: file://[..]
version required: = 0.1.0
"));
}
Implement top-level overrides This commit is an implementation of top-level overrides to be encoded into the manifest itself directly. This style of override is distinct from the existing `paths` support in `.cargo/config` in two important ways: * Top level overrides are intended to be checked in and shared amongst all developers of a project. * Top level overrides are reflected in `Cargo.lock`. The second point is crucially important here as it will ensure that an override on one machine behaves the same as an override on another machine. This solves many long-standing problems with `paths`-based overrides which suffer from some level of nondeterminism as they're not encoded. From a syntactical point of view, an override looks like: ```toml [replace] "libc:0.2.0" = { git = 'https://github.com/my-username/libc', branch = '0.2-fork' } ``` This declaration indicates that whenever resolution would otherwise encounter the `libc` package version 0.2.0 from crates.io, it should instead replace it with the custom git dependency on a specific branch. The key "libc:0.2.0" here is actually a package id specification which will allow selecting various components of a graph. For example the same named package coming from two distinct locations can be selected against, as well as multiple versions of one crate in a dependency graph. The replacement dependency has the same syntax as the `[dependencies]` section of Cargo.toml. One of the major uses of this syntax will be, for example, using a temporary fork of a crate while the changes are pushed upstream to the original repo. This will avoid the need to change the intermediate projects immediately, and over time once fixes have landed upstream the `[replace]` section in a `Cargo.toml` can be removed. There are also two crucial restrictions on overrides. * A crate with the name `foo` can only get overridden with packages also of the name `foo`. * A crate can only get overridden with a crate of the exact same version. A consequence of these restrictions is that crates.io cannot be used to replace anything from crates.io. There's only one version of something on crates.io, so there's nothing else to replace it with (name/version are a unique key). Closes #942
2016-02-09 23:42:17 +00:00
#[test]
fn override_with_nothing() {
Implement top-level overrides This commit is an implementation of top-level overrides to be encoded into the manifest itself directly. This style of override is distinct from the existing `paths` support in `.cargo/config` in two important ways: * Top level overrides are intended to be checked in and shared amongst all developers of a project. * Top level overrides are reflected in `Cargo.lock`. The second point is crucially important here as it will ensure that an override on one machine behaves the same as an override on another machine. This solves many long-standing problems with `paths`-based overrides which suffer from some level of nondeterminism as they're not encoded. From a syntactical point of view, an override looks like: ```toml [replace] "libc:0.2.0" = { git = 'https://github.com/my-username/libc', branch = '0.2-fork' } ``` This declaration indicates that whenever resolution would otherwise encounter the `libc` package version 0.2.0 from crates.io, it should instead replace it with the custom git dependency on a specific branch. The key "libc:0.2.0" here is actually a package id specification which will allow selecting various components of a graph. For example the same named package coming from two distinct locations can be selected against, as well as multiple versions of one crate in a dependency graph. The replacement dependency has the same syntax as the `[dependencies]` section of Cargo.toml. One of the major uses of this syntax will be, for example, using a temporary fork of a crate while the changes are pushed upstream to the original repo. This will avoid the need to change the intermediate projects immediately, and over time once fixes have landed upstream the `[replace]` section in a `Cargo.toml` can be removed. There are also two crucial restrictions on overrides. * A crate with the name `foo` can only get overridden with packages also of the name `foo`. * A crate can only get overridden with a crate of the exact same version. A consequence of these restrictions is that crates.io cannot be used to replace anything from crates.io. There's only one version of something on crates.io, so there's nothing else to replace it with (name/version are a unique key). Closes #942
2016-02-09 23:42:17 +00:00
Package::new("foo", "0.1.0").publish();
let foo = git::repo(&paths::root().join("override"))
.file("src/lib.rs", "");
foo.build();
let p = project("local")
.file("Cargo.toml", &format!(r#"
[package]
name = "local"
version = "0.0.1"
authors = []
[dependencies]
foo = "0.1"
[replace]
"foo:0.1.0" = {{ git = '{}' }}
"#, foo.url()))
.file("src/lib.rs", "");
assert_that(p.cargo_process("build"),
execs().with_status(101).with_stderr("\
2016-05-20 11:47:39 +00:00
[UPDATING] registry [..]
[UPDATING] git repository [..]
Add flags to assert lock/cache behavior to Cargo If a lock file is generated and some equivalent of `cargo fetch` is run then Cargo shouldn't ever touch the network or modify `Cargo.lock` until any `Cargo.toml` later changes, but this often wants to be asserted in some build environments where it's a programmer error if Cargo attempts to access the network. The `--locked` flag added here will assert that `Cargo.lock` does not need to change to proceed. That is, if `Cargo.lock` would be modified (as it automatically is by default) this is turned into a hard error instead. This `--frozen` will not only assert that `Cargo.lock` doesn't change (the same behavior as `--locked`), but it will also will manually prevent Cargo from touching the network by ensuring that all network requests return an error. These flags can be used in environments where it is *expected* that no network access happens (or no lockfile changes happen) because it has been pre-arranged for Cargo to not happen. Examples of this include: * CI for projects want to pass `--locked` to ensure that `Cargo.lock` is up to date before changes are checked in. * Environments with vendored dependencies want to pass `--frozen` as touching the network indicates a programmer error that something wasn't vendored correctly. A crucial property of these two flags is that **they do not change the behavior of Cargo**. They are simply assertions at a few locations in Cargo to ensure that actions expected to not happen indeed don't happen. Some documentation has also been added to this effect. Closes #2111
2016-06-28 17:39:46 +00:00
[ERROR] failed to load source for a dependency on `foo`
Caused by:
Unable to update file://[..]
Implement top-level overrides This commit is an implementation of top-level overrides to be encoded into the manifest itself directly. This style of override is distinct from the existing `paths` support in `.cargo/config` in two important ways: * Top level overrides are intended to be checked in and shared amongst all developers of a project. * Top level overrides are reflected in `Cargo.lock`. The second point is crucially important here as it will ensure that an override on one machine behaves the same as an override on another machine. This solves many long-standing problems with `paths`-based overrides which suffer from some level of nondeterminism as they're not encoded. From a syntactical point of view, an override looks like: ```toml [replace] "libc:0.2.0" = { git = 'https://github.com/my-username/libc', branch = '0.2-fork' } ``` This declaration indicates that whenever resolution would otherwise encounter the `libc` package version 0.2.0 from crates.io, it should instead replace it with the custom git dependency on a specific branch. The key "libc:0.2.0" here is actually a package id specification which will allow selecting various components of a graph. For example the same named package coming from two distinct locations can be selected against, as well as multiple versions of one crate in a dependency graph. The replacement dependency has the same syntax as the `[dependencies]` section of Cargo.toml. One of the major uses of this syntax will be, for example, using a temporary fork of a crate while the changes are pushed upstream to the original repo. This will avoid the need to change the intermediate projects immediately, and over time once fixes have landed upstream the `[replace]` section in a `Cargo.toml` can be removed. There are also two crucial restrictions on overrides. * A crate with the name `foo` can only get overridden with packages also of the name `foo`. * A crate can only get overridden with a crate of the exact same version. A consequence of these restrictions is that crates.io cannot be used to replace anything from crates.io. There's only one version of something on crates.io, so there's nothing else to replace it with (name/version are a unique key). Closes #942
2016-02-09 23:42:17 +00:00
Caused by:
Could not find Cargo.toml in `[..]`
"));
}
Implement top-level overrides This commit is an implementation of top-level overrides to be encoded into the manifest itself directly. This style of override is distinct from the existing `paths` support in `.cargo/config` in two important ways: * Top level overrides are intended to be checked in and shared amongst all developers of a project. * Top level overrides are reflected in `Cargo.lock`. The second point is crucially important here as it will ensure that an override on one machine behaves the same as an override on another machine. This solves many long-standing problems with `paths`-based overrides which suffer from some level of nondeterminism as they're not encoded. From a syntactical point of view, an override looks like: ```toml [replace] "libc:0.2.0" = { git = 'https://github.com/my-username/libc', branch = '0.2-fork' } ``` This declaration indicates that whenever resolution would otherwise encounter the `libc` package version 0.2.0 from crates.io, it should instead replace it with the custom git dependency on a specific branch. The key "libc:0.2.0" here is actually a package id specification which will allow selecting various components of a graph. For example the same named package coming from two distinct locations can be selected against, as well as multiple versions of one crate in a dependency graph. The replacement dependency has the same syntax as the `[dependencies]` section of Cargo.toml. One of the major uses of this syntax will be, for example, using a temporary fork of a crate while the changes are pushed upstream to the original repo. This will avoid the need to change the intermediate projects immediately, and over time once fixes have landed upstream the `[replace]` section in a `Cargo.toml` can be removed. There are also two crucial restrictions on overrides. * A crate with the name `foo` can only get overridden with packages also of the name `foo`. * A crate can only get overridden with a crate of the exact same version. A consequence of these restrictions is that crates.io cannot be used to replace anything from crates.io. There's only one version of something on crates.io, so there's nothing else to replace it with (name/version are a unique key). Closes #942
2016-02-09 23:42:17 +00:00
#[test]
fn override_wrong_version() {
Implement top-level overrides This commit is an implementation of top-level overrides to be encoded into the manifest itself directly. This style of override is distinct from the existing `paths` support in `.cargo/config` in two important ways: * Top level overrides are intended to be checked in and shared amongst all developers of a project. * Top level overrides are reflected in `Cargo.lock`. The second point is crucially important here as it will ensure that an override on one machine behaves the same as an override on another machine. This solves many long-standing problems with `paths`-based overrides which suffer from some level of nondeterminism as they're not encoded. From a syntactical point of view, an override looks like: ```toml [replace] "libc:0.2.0" = { git = 'https://github.com/my-username/libc', branch = '0.2-fork' } ``` This declaration indicates that whenever resolution would otherwise encounter the `libc` package version 0.2.0 from crates.io, it should instead replace it with the custom git dependency on a specific branch. The key "libc:0.2.0" here is actually a package id specification which will allow selecting various components of a graph. For example the same named package coming from two distinct locations can be selected against, as well as multiple versions of one crate in a dependency graph. The replacement dependency has the same syntax as the `[dependencies]` section of Cargo.toml. One of the major uses of this syntax will be, for example, using a temporary fork of a crate while the changes are pushed upstream to the original repo. This will avoid the need to change the intermediate projects immediately, and over time once fixes have landed upstream the `[replace]` section in a `Cargo.toml` can be removed. There are also two crucial restrictions on overrides. * A crate with the name `foo` can only get overridden with packages also of the name `foo`. * A crate can only get overridden with a crate of the exact same version. A consequence of these restrictions is that crates.io cannot be used to replace anything from crates.io. There's only one version of something on crates.io, so there's nothing else to replace it with (name/version are a unique key). Closes #942
2016-02-09 23:42:17 +00:00
let p = project("local")
.file("Cargo.toml", r#"
[package]
name = "local"
version = "0.0.1"
authors = []
[replace]
"foo:0.1.0" = { git = 'https://example.com', version = '0.2.0' }
"#)
.file("src/lib.rs", "");
assert_that(p.cargo_process("build"),
execs().with_status(101).with_stderr("\
error: failed to parse manifest at `[..]`
Caused by:
replacements cannot specify a version requirement, but found one for `[..]foo:0.1.0`
Implement top-level overrides This commit is an implementation of top-level overrides to be encoded into the manifest itself directly. This style of override is distinct from the existing `paths` support in `.cargo/config` in two important ways: * Top level overrides are intended to be checked in and shared amongst all developers of a project. * Top level overrides are reflected in `Cargo.lock`. The second point is crucially important here as it will ensure that an override on one machine behaves the same as an override on another machine. This solves many long-standing problems with `paths`-based overrides which suffer from some level of nondeterminism as they're not encoded. From a syntactical point of view, an override looks like: ```toml [replace] "libc:0.2.0" = { git = 'https://github.com/my-username/libc', branch = '0.2-fork' } ``` This declaration indicates that whenever resolution would otherwise encounter the `libc` package version 0.2.0 from crates.io, it should instead replace it with the custom git dependency on a specific branch. The key "libc:0.2.0" here is actually a package id specification which will allow selecting various components of a graph. For example the same named package coming from two distinct locations can be selected against, as well as multiple versions of one crate in a dependency graph. The replacement dependency has the same syntax as the `[dependencies]` section of Cargo.toml. One of the major uses of this syntax will be, for example, using a temporary fork of a crate while the changes are pushed upstream to the original repo. This will avoid the need to change the intermediate projects immediately, and over time once fixes have landed upstream the `[replace]` section in a `Cargo.toml` can be removed. There are also two crucial restrictions on overrides. * A crate with the name `foo` can only get overridden with packages also of the name `foo`. * A crate can only get overridden with a crate of the exact same version. A consequence of these restrictions is that crates.io cannot be used to replace anything from crates.io. There's only one version of something on crates.io, so there's nothing else to replace it with (name/version are a unique key). Closes #942
2016-02-09 23:42:17 +00:00
"));
}
Implement top-level overrides This commit is an implementation of top-level overrides to be encoded into the manifest itself directly. This style of override is distinct from the existing `paths` support in `.cargo/config` in two important ways: * Top level overrides are intended to be checked in and shared amongst all developers of a project. * Top level overrides are reflected in `Cargo.lock`. The second point is crucially important here as it will ensure that an override on one machine behaves the same as an override on another machine. This solves many long-standing problems with `paths`-based overrides which suffer from some level of nondeterminism as they're not encoded. From a syntactical point of view, an override looks like: ```toml [replace] "libc:0.2.0" = { git = 'https://github.com/my-username/libc', branch = '0.2-fork' } ``` This declaration indicates that whenever resolution would otherwise encounter the `libc` package version 0.2.0 from crates.io, it should instead replace it with the custom git dependency on a specific branch. The key "libc:0.2.0" here is actually a package id specification which will allow selecting various components of a graph. For example the same named package coming from two distinct locations can be selected against, as well as multiple versions of one crate in a dependency graph. The replacement dependency has the same syntax as the `[dependencies]` section of Cargo.toml. One of the major uses of this syntax will be, for example, using a temporary fork of a crate while the changes are pushed upstream to the original repo. This will avoid the need to change the intermediate projects immediately, and over time once fixes have landed upstream the `[replace]` section in a `Cargo.toml` can be removed. There are also two crucial restrictions on overrides. * A crate with the name `foo` can only get overridden with packages also of the name `foo`. * A crate can only get overridden with a crate of the exact same version. A consequence of these restrictions is that crates.io cannot be used to replace anything from crates.io. There's only one version of something on crates.io, so there's nothing else to replace it with (name/version are a unique key). Closes #942
2016-02-09 23:42:17 +00:00
#[test]
fn multiple_specs() {
Implement top-level overrides This commit is an implementation of top-level overrides to be encoded into the manifest itself directly. This style of override is distinct from the existing `paths` support in `.cargo/config` in two important ways: * Top level overrides are intended to be checked in and shared amongst all developers of a project. * Top level overrides are reflected in `Cargo.lock`. The second point is crucially important here as it will ensure that an override on one machine behaves the same as an override on another machine. This solves many long-standing problems with `paths`-based overrides which suffer from some level of nondeterminism as they're not encoded. From a syntactical point of view, an override looks like: ```toml [replace] "libc:0.2.0" = { git = 'https://github.com/my-username/libc', branch = '0.2-fork' } ``` This declaration indicates that whenever resolution would otherwise encounter the `libc` package version 0.2.0 from crates.io, it should instead replace it with the custom git dependency on a specific branch. The key "libc:0.2.0" here is actually a package id specification which will allow selecting various components of a graph. For example the same named package coming from two distinct locations can be selected against, as well as multiple versions of one crate in a dependency graph. The replacement dependency has the same syntax as the `[dependencies]` section of Cargo.toml. One of the major uses of this syntax will be, for example, using a temporary fork of a crate while the changes are pushed upstream to the original repo. This will avoid the need to change the intermediate projects immediately, and over time once fixes have landed upstream the `[replace]` section in a `Cargo.toml` can be removed. There are also two crucial restrictions on overrides. * A crate with the name `foo` can only get overridden with packages also of the name `foo`. * A crate can only get overridden with a crate of the exact same version. A consequence of these restrictions is that crates.io cannot be used to replace anything from crates.io. There's only one version of something on crates.io, so there's nothing else to replace it with (name/version are a unique key). Closes #942
2016-02-09 23:42:17 +00:00
Package::new("foo", "0.1.0").publish();
let foo = git::repo(&paths::root().join("override"))
.file("Cargo.toml", r#"
[package]
name = "foo"
version = "0.1.0"
authors = []
"#)
.file("src/lib.rs", "pub fn foo() {}");
foo.build();
let p = project("local")
.file("Cargo.toml", &format!(r#"
[package]
name = "local"
version = "0.0.1"
authors = []
[dependencies]
foo = "0.1.0"
[replace]
"foo:0.1.0" = {{ git = '{0}' }}
Implement source redirection This commit implements a scheme for .cargo/config files where sources can be redirected to other sources. The purpose of this will be to override crates.io for a few use cases: * Replace it with a mirror site that is sync'd to crates.io * Replace it with a "directory source" or some other local source This major feature of this redirection, however, is that none of it is encoded into the lock file. If one source is redirected to another then it is assumed that packages from both are exactly the same (e.g. `foo v0.0.1` is the same in both location). The lock file simply encodes the canonical soure (e.g. crates.io) rather than the replacement source. In the end this means that Cargo.lock files can be generated from any replacement source and shipped to other locations without the lockfile oscillating about where packages came from. Eventually this support will be extended to `Cargo.toml` itself (which will be encoded into the lock file), but that support is not implemented today. The syntax for what was implemented today looks like: # .cargo/config [source.my-awesome-registry] registry = 'https://example.com/path/to/index' [source.crates-io] replace-with = 'my-awesome-registry' Each source will have a canonical name and will be configured with the various keys underneath it (today just 'registry' and 'directory' will be accepted). The global `crates-io` source represents crates from the standard registry, and this can be replaced with other mirror sources. All tests have been modified to use this new infrastructure instead of the old `registry.index` configuration. This configuration is now also deprecated and will emit an unconditional warning about how it will no longer be used in the future. Finally, all subcommands now use this "source map" except for `cargo publish`, which will always publish to the default registry (in this case crates.io).
2016-02-03 18:54:07 +00:00
[replace."https://github.com/rust-lang/crates.io-index#foo:0.1.0"]
git = '{0}'
"#, foo.url()))
Implement top-level overrides This commit is an implementation of top-level overrides to be encoded into the manifest itself directly. This style of override is distinct from the existing `paths` support in `.cargo/config` in two important ways: * Top level overrides are intended to be checked in and shared amongst all developers of a project. * Top level overrides are reflected in `Cargo.lock`. The second point is crucially important here as it will ensure that an override on one machine behaves the same as an override on another machine. This solves many long-standing problems with `paths`-based overrides which suffer from some level of nondeterminism as they're not encoded. From a syntactical point of view, an override looks like: ```toml [replace] "libc:0.2.0" = { git = 'https://github.com/my-username/libc', branch = '0.2-fork' } ``` This declaration indicates that whenever resolution would otherwise encounter the `libc` package version 0.2.0 from crates.io, it should instead replace it with the custom git dependency on a specific branch. The key "libc:0.2.0" here is actually a package id specification which will allow selecting various components of a graph. For example the same named package coming from two distinct locations can be selected against, as well as multiple versions of one crate in a dependency graph. The replacement dependency has the same syntax as the `[dependencies]` section of Cargo.toml. One of the major uses of this syntax will be, for example, using a temporary fork of a crate while the changes are pushed upstream to the original repo. This will avoid the need to change the intermediate projects immediately, and over time once fixes have landed upstream the `[replace]` section in a `Cargo.toml` can be removed. There are also two crucial restrictions on overrides. * A crate with the name `foo` can only get overridden with packages also of the name `foo`. * A crate can only get overridden with a crate of the exact same version. A consequence of these restrictions is that crates.io cannot be used to replace anything from crates.io. There's only one version of something on crates.io, so there's nothing else to replace it with (name/version are a unique key). Closes #942
2016-02-09 23:42:17 +00:00
.file("src/lib.rs", "");
assert_that(p.cargo_process("build"),
execs().with_status(101).with_stderr("\
2016-05-20 11:47:39 +00:00
[UPDATING] registry [..]
[UPDATING] git repository [..]
Implement top-level overrides This commit is an implementation of top-level overrides to be encoded into the manifest itself directly. This style of override is distinct from the existing `paths` support in `.cargo/config` in two important ways: * Top level overrides are intended to be checked in and shared amongst all developers of a project. * Top level overrides are reflected in `Cargo.lock`. The second point is crucially important here as it will ensure that an override on one machine behaves the same as an override on another machine. This solves many long-standing problems with `paths`-based overrides which suffer from some level of nondeterminism as they're not encoded. From a syntactical point of view, an override looks like: ```toml [replace] "libc:0.2.0" = { git = 'https://github.com/my-username/libc', branch = '0.2-fork' } ``` This declaration indicates that whenever resolution would otherwise encounter the `libc` package version 0.2.0 from crates.io, it should instead replace it with the custom git dependency on a specific branch. The key "libc:0.2.0" here is actually a package id specification which will allow selecting various components of a graph. For example the same named package coming from two distinct locations can be selected against, as well as multiple versions of one crate in a dependency graph. The replacement dependency has the same syntax as the `[dependencies]` section of Cargo.toml. One of the major uses of this syntax will be, for example, using a temporary fork of a crate while the changes are pushed upstream to the original repo. This will avoid the need to change the intermediate projects immediately, and over time once fixes have landed upstream the `[replace]` section in a `Cargo.toml` can be removed. There are also two crucial restrictions on overrides. * A crate with the name `foo` can only get overridden with packages also of the name `foo`. * A crate can only get overridden with a crate of the exact same version. A consequence of these restrictions is that crates.io cannot be used to replace anything from crates.io. There's only one version of something on crates.io, so there's nothing else to replace it with (name/version are a unique key). Closes #942
2016-02-09 23:42:17 +00:00
error: overlapping replacement specifications found:
* [..]
* [..]
Implement source redirection This commit implements a scheme for .cargo/config files where sources can be redirected to other sources. The purpose of this will be to override crates.io for a few use cases: * Replace it with a mirror site that is sync'd to crates.io * Replace it with a "directory source" or some other local source This major feature of this redirection, however, is that none of it is encoded into the lock file. If one source is redirected to another then it is assumed that packages from both are exactly the same (e.g. `foo v0.0.1` is the same in both location). The lock file simply encodes the canonical soure (e.g. crates.io) rather than the replacement source. In the end this means that Cargo.lock files can be generated from any replacement source and shipped to other locations without the lockfile oscillating about where packages came from. Eventually this support will be extended to `Cargo.toml` itself (which will be encoded into the lock file), but that support is not implemented today. The syntax for what was implemented today looks like: # .cargo/config [source.my-awesome-registry] registry = 'https://example.com/path/to/index' [source.crates-io] replace-with = 'my-awesome-registry' Each source will have a canonical name and will be configured with the various keys underneath it (today just 'registry' and 'directory' will be accepted). The global `crates-io` source represents crates from the standard registry, and this can be replaced with other mirror sources. All tests have been modified to use this new infrastructure instead of the old `registry.index` configuration. This configuration is now also deprecated and will emit an unconditional warning about how it will no longer be used in the future. Finally, all subcommands now use this "source map" except for `cargo publish`, which will always publish to the default registry (in this case crates.io).
2016-02-03 18:54:07 +00:00
both specifications match: foo v0.1.0
Implement top-level overrides This commit is an implementation of top-level overrides to be encoded into the manifest itself directly. This style of override is distinct from the existing `paths` support in `.cargo/config` in two important ways: * Top level overrides are intended to be checked in and shared amongst all developers of a project. * Top level overrides are reflected in `Cargo.lock`. The second point is crucially important here as it will ensure that an override on one machine behaves the same as an override on another machine. This solves many long-standing problems with `paths`-based overrides which suffer from some level of nondeterminism as they're not encoded. From a syntactical point of view, an override looks like: ```toml [replace] "libc:0.2.0" = { git = 'https://github.com/my-username/libc', branch = '0.2-fork' } ``` This declaration indicates that whenever resolution would otherwise encounter the `libc` package version 0.2.0 from crates.io, it should instead replace it with the custom git dependency on a specific branch. The key "libc:0.2.0" here is actually a package id specification which will allow selecting various components of a graph. For example the same named package coming from two distinct locations can be selected against, as well as multiple versions of one crate in a dependency graph. The replacement dependency has the same syntax as the `[dependencies]` section of Cargo.toml. One of the major uses of this syntax will be, for example, using a temporary fork of a crate while the changes are pushed upstream to the original repo. This will avoid the need to change the intermediate projects immediately, and over time once fixes have landed upstream the `[replace]` section in a `Cargo.toml` can be removed. There are also two crucial restrictions on overrides. * A crate with the name `foo` can only get overridden with packages also of the name `foo`. * A crate can only get overridden with a crate of the exact same version. A consequence of these restrictions is that crates.io cannot be used to replace anything from crates.io. There's only one version of something on crates.io, so there's nothing else to replace it with (name/version are a unique key). Closes #942
2016-02-09 23:42:17 +00:00
"));
}
#[test]
fn test_override_dep() {
Package::new("foo", "0.1.0").publish();
let foo = git::repo(&paths::root().join("override"))
.file("Cargo.toml", r#"
[package]
name = "foo"
version = "0.1.0"
authors = []
"#)
.file("src/lib.rs", "pub fn foo() {}");
foo.build();
let p = project("local")
.file("Cargo.toml", &format!(r#"
[package]
name = "local"
version = "0.0.1"
authors = []
[dependencies]
foo = "0.1.0"
[replace]
"foo:0.1.0" = {{ git = '{0}' }}
"#, foo.url()))
.file("src/lib.rs", "");
assert_that(p.cargo_process("test").arg("-p").arg("foo"),
execs().with_status(101)
.with_stderr_contains("\
error: There are multiple `foo` packages in your project, and the [..]
Please re-run this command with [..]
[..]#foo:0.1.0
[..]#foo:0.1.0
"));
}
#[test]
fn update() {
Package::new("foo", "0.1.0").publish();
let foo = git::repo(&paths::root().join("override"))
.file("Cargo.toml", r#"
[package]
name = "foo"
version = "0.1.0"
authors = []
"#)
.file("src/lib.rs", "pub fn foo() {}");
foo.build();
let p = project("local")
.file("Cargo.toml", &format!(r#"
[package]
name = "local"
version = "0.0.1"
authors = []
[dependencies]
foo = "0.1.0"
[replace]
"foo:0.1.0" = {{ git = '{0}' }}
"#, foo.url()))
.file("src/lib.rs", "");
assert_that(p.cargo_process("generate-lockfile"),
execs().with_status(0));
assert_that(p.cargo("update"),
execs().with_status(0)
.with_stderr("\
[UPDATING] registry `[..]`
[UPDATING] git repository `[..]`
"));
}
// local -> near -> far
// near is overridden with itself
#[test]
fn no_override_self() {
let deps = git::repo(&paths::root().join("override"))
.file("far/Cargo.toml", r#"
[package]
name = "far"
version = "0.1.0"
authors = []
"#)
.file("far/src/lib.rs", "")
.file("near/Cargo.toml", r#"
[package]
name = "near"
version = "0.1.0"
authors = []
[dependencies]
far = { path = "../far" }
"#)
.file("near/src/lib.rs", r#"
#![no_std]
pub extern crate far;
"#);
deps.build();
let p = project("local")
.file("Cargo.toml", &format!(r#"
[package]
name = "local"
version = "0.0.1"
authors = []
[dependencies]
near = {{ git = '{0}' }}
[replace]
"near:0.1.0" = {{ git = '{0}' }}
"#, deps.url()))
.file("src/lib.rs", r#"
#![no_std]
pub extern crate near;
"#);
assert_that(p.cargo_process("build").arg("--verbose"),
execs().with_status(0));
}
#[test]
fn broken_path_override_warns() {
Package::new("foo", "0.1.0").publish();
Package::new("foo", "0.2.0").publish();
let p = project("local")
.file("Cargo.toml", r#"
[package]
name = "local"
version = "0.0.1"
authors = []
[dependencies]
a = { path = "a1" }
"#)
.file("src/lib.rs", "")
.file("a1/Cargo.toml", r#"
[package]
name = "a"
version = "0.0.1"
authors = []
[dependencies]
foo = "0.1"
"#)
.file("a1/src/lib.rs", "")
.file("a2/Cargo.toml", r#"
[package]
name = "a"
version = "0.0.1"
authors = []
[dependencies]
foo = "0.2"
"#)
.file("a2/src/lib.rs", "")
.file(".cargo/config", r#"
paths = ["a2"]
"#);
assert_that(p.cargo_process("build"),
execs().with_status(0)
.with_stderr("\
[UPDATING] [..]
warning: path override for crate `a` has altered the original list of
dependencies; the dependency on `foo` was either added or
modified to not match the previously resolved version
This is currently allowed but is known to produce buggy behavior with spurious
recompiles and changes to the crate graph. Path overrides unfortunately were
never intended to support this feature, so for now this message is just a
warning. In the future, however, this message will become a hard error.
To change the dependency graph via an override it's recommended to use the
`[replace]` feature of Cargo instead of the path override feature. This is
documented online at the url below for more information.
http://doc.crates.io/specifying-dependencies.html#overriding-dependencies
[DOWNLOADING] [..]
[COMPILING] [..]
[COMPILING] [..]
[COMPILING] [..]
[FINISHED] [..]
"));
}
#[test]
fn override_an_override() {
Package::new("chrono", "0.2.0").dep("serde", "< 0.9").publish();
Package::new("serde", "0.7.0")
.file("src/lib.rs", "pub fn serde07() {}")
.publish();
Package::new("serde", "0.8.0")
.file("src/lib.rs", "pub fn serde08() {}")
.publish();
let p = project("local")
.file("Cargo.toml", r#"
[package]
name = "local"
version = "0.0.1"
authors = []
[dependencies]
chrono = "0.2"
serde = "0.8"
[replace]
"chrono:0.2.0" = { path = "chrono" }
"serde:0.8.0" = { path = "serde" }
"#)
.file("Cargo.lock", r#"
[root]
name = "local"
version = "0.0.1"
dependencies = [
"chrono 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "chrono"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
replace = "chrono 0.2.0"
[[package]]
name = "chrono"
version = "0.2.0"
dependencies = [
"serde 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "serde"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "serde"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
replace = "serde 0.8.0"
[[package]]
name = "serde"
version = "0.8.0"
"#)
.file("src/lib.rs", "
extern crate chrono;
extern crate serde;
pub fn local() {
chrono::chrono();
serde::serde08_override();
}
")
.file("chrono/Cargo.toml", r#"
[package]
name = "chrono"
version = "0.2.0"
authors = []
[dependencies]
serde = "< 0.9"
"#)
.file("chrono/src/lib.rs", "
extern crate serde;
pub fn chrono() {
serde::serde07();
}
")
.file("serde/Cargo.toml", r#"
[package]
name = "serde"
version = "0.8.0"
authors = []
"#)
.file("serde/src/lib.rs", "
pub fn serde08_override() {}
");
assert_that(p.cargo_process("build").arg("-v"),
execs().with_status(0));
}
#[test]
fn overriding_nonexistent_no_spurious() {
Package::new("foo", "0.1.0").dep("bar", "0.1").publish();
Package::new("bar", "0.1.0").publish();
let foo = git::repo(&paths::root().join("override"))
.file("Cargo.toml", r#"
[package]
name = "foo"
version = "0.1.0"
authors = []
[dependencies]
bar = { path = "bar" }
"#)
.file("src/lib.rs", "pub fn foo() {}")
.file("bar/Cargo.toml", r#"
[package]
name = "bar"
version = "0.1.0"
authors = []
"#)
.file("bar/src/lib.rs", "pub fn foo() {}");
foo.build();
let p = project("local")
.file("Cargo.toml", &format!(r#"
[package]
name = "local"
version = "0.0.1"
authors = []
[dependencies]
foo = "0.1.0"
[replace]
"foo:0.1.0" = {{ git = '{url}' }}
"bar:0.1.0" = {{ git = '{url}' }}
"#, url = foo.url()))
.file("src/lib.rs", "");
assert_that(p.cargo_process("build"),
execs().with_status(0));
assert_that(p.cargo("build"),
execs().with_status(0).with_stderr("\
[FINISHED] [..]
").with_stdout(""));
}