cargo/tests/build.rs

2267 lines
60 KiB
Rust
Raw Normal View History

extern crate cargo;
extern crate cargotest;
extern crate hamcrest;
extern crate tempdir;
2015-02-06 07:27:53 +00:00
use std::env;
use std::fs::{self, File};
use std::io::prelude::*;
Implement a registry source # cargo upload The cargo-upload command will take the local package and upload it to the specified registry. The local package is uploaded as a tarball compressed with gzip under maximum compression. Most of this is done by just delegating to `cargo package` The host to upload to is specified, in order of priority, by a command line `--host` flag, the `registry.host` config key, and then the default registry. The default registry is still `example.com` The registry itself is still a work in progress, but the general plumbing for a command such as this would look like: 1. Ensure the local package has been compressed into an archive. 2. Fetch the relevant registry and login token from config files. 3. Ensure all dependencies for a package are listed as coming from the same registry. 4. Upload the archive to the registry with the login token. 5. The registry will verify the package is under 2MB (configurable). 6. The registry will upload the archive to S3, calculating a checksum in the process. 7. The registry will add an entry to the registry's index (a git repository). The entry will include the name of the package, the version uploaded, the checksum of the upload, and then the list of dependencies (name/version req) 8. The local `cargo upload` command will succeed. # cargo login Uploading requires a token from the api server, and this token follows the same config chain for the host except that there is no fallback. To implement login, the `cargo login` command is used. With 0 arguments, the command will request that a site be visited for a login token, and with an argument it will set the argument as the new login token. The `util::config` module was modified to allow writing configuration as well as reading it. The support is a little lacking in that comments are blown away, but the support is there at least. # RegistrySource An implementation of `RegistrySource` has been created (deleting the old `DummyRegistrySource`). This implementation only needs a URL to be constructed, and it is assumed that the URL is running an instance of the cargo registry. ## RegistrySource::update Currently this will unconditionally update the registry's index (a git repository). Tuning is necessary to prevent updating the index each time (more coming soon). ## RegistrySource::query This is called in the resolve phase of cargo. This function is given a dependency to query for, and the source will simply look into the index to see if any package with the name is present. If found, the package's index file will be loaded and parsed into a list of summaries. The main optimization of this function is to not require the entire registry to ever be resident in memory. Instead, only necessary packages are loaded into memory and parsed. ## RegistrySource::download This is also called during the resolve phase of cargo, but only when a package has been selected to be built (actually resolved). This phase of the source will actually download and unpack the tarball for the package. Currently a configuration file is located in the root of a registry's index describing the root url to download packages from. This function is optimized for two different metrics: 1. If a tarball is downloaded, it is not downloaded again. It is assumed that once a tarball is successfully downloaded it will never change. 2. If the unpacking destination has a `.cargo-ok` file, it is assumed that the unpacking has already occurred and does not need to happen again. With these in place, a rebuild should take almost no time at all. ## RegistrySource::get This function is simply implemented in terms of a PathSource's `get` function by creating a `PathSource` for all unpacked tarballs as part of the `download` stage. ## Filesystem layout There are a few new directories as part of the `.cargo` home folder: * `.cargo/registry/index/$hostname-$hash` - This is the directory containing the actual index of the registry. `$hostname` comes from its url, and `$hash` is the hash of the entire url. * `.cargo/registry/cache/$hostname-$hash/$pkg-$vers.tar.gz` - This is a directory used to cache the downloads of packages from the registry. * `.cargo/registry/src/$hostname-$hash/$pkg-$vers` - This is the location of the unpacked packages. They will be compiled from this location. # New Dependencies Cargo has picked up a new dependency on the `curl-rust` package in order to send HTTP requests to the registry as well as send HTTP requests to download tarballs.
2014-07-18 15:40:45 +00:00
use cargo::util::process;
use cargotest::{is_nightly, rustc_host, sleep_ms};
use cargotest::support::paths::{CargoPathExt,root};
use cargotest::support::{ProjectBuilder};
use cargotest::support::{project, execs, main_file, basic_bin_manifest};
use hamcrest::{assert_that, existing_file, is_not};
use tempdir::TempDir;
#[test]
fn cargo_compile_simple() {
let p = project("foo")
2015-03-26 18:17:44 +00:00
.file("Cargo.toml", &basic_bin_manifest("foo"))
.file("src/foo.rs", &main_file(r#""i am foo""#, &[]));
assert_that(p.cargo_process("build"), execs());
assert_that(&p.bin("foo"), existing_file());
2014-05-09 00:50:28 +00:00
2015-10-28 09:20:00 +00:00
assert_that(process(&p.bin("foo")),
execs().with_stdout("i am foo\n"));
}
#[test]
fn cargo_compile_manifest_path() {
let p = project("foo")
2015-03-26 18:17:44 +00:00
.file("Cargo.toml", &basic_bin_manifest("foo"))
.file("src/foo.rs", &main_file(r#""i am foo""#, &[]));
assert_that(p.cargo_process("build")
.arg("--manifest-path").arg("foo/Cargo.toml")
.cwd(p.root().parent().unwrap()),
execs().with_status(0));
assert_that(&p.bin("foo"), existing_file());
}
#[test]
fn cargo_compile_with_invalid_manifest() {
let p = project("foo")
.file("Cargo.toml", "");
2014-05-09 00:50:28 +00:00
assert_that(p.cargo_process("build"),
execs()
.with_status(101)
2016-05-12 17:06:36 +00:00
.with_stderr("\
[ERROR] failed to parse manifest at `[..]`
Caused by:
no `package` or `project` section found.
2016-05-12 17:06:36 +00:00
"))
}
#[test]
fn cargo_compile_with_invalid_manifest2() {
let p = project("foo")
.file("Cargo.toml", r"
[project]
foo = bar
");
assert_that(p.cargo_process("build"),
execs()
.with_status(101)
2016-05-12 17:06:36 +00:00
.with_stderr("\
[ERROR] failed to parse manifest at `[..]`
Caused by:
could not parse input as TOML
Cargo.toml:3:19-3:20 expected a value
2016-05-12 17:06:36 +00:00
"))
}
2014-05-09 00:50:28 +00:00
#[test]
fn cargo_compile_with_invalid_manifest3() {
let p = project("foo")
.file("Cargo.toml", r#"
[package]
name = "foo"
version = "0.0.1"
authors = []
"#)
.file("src/Cargo.toml", "a = bar");
assert_that(p.cargo_process("build").arg("--manifest-path")
.arg("src/Cargo.toml"),
execs()
.with_status(101)
2016-05-12 17:06:36 +00:00
.with_stderr("\
[ERROR] failed to parse manifest at `[..]`
Caused by:
could not parse input as TOML\n\
2016-05-12 17:06:36 +00:00
src[..]Cargo.toml:1:5-1:6 expected a value\n\n"))
}
#[test]
fn cargo_compile_with_invalid_version() {
let p = project("foo")
.file("Cargo.toml", r#"
[project]
name = "foo"
authors = []
version = "1.0"
"#);
assert_that(p.cargo_process("build"),
execs()
.with_status(101)
2016-05-12 17:06:36 +00:00
.with_stderr("\
[ERROR] failed to parse manifest at `[..]`
Caused by:
cannot parse '1.0' as a semver for the key `project.version`
2016-05-12 17:06:36 +00:00
"))
}
#[test]
fn cargo_compile_with_invalid_package_name() {
let p = project("foo")
.file("Cargo.toml", r#"
[package]
name = ""
authors = []
version = "0.0.0"
"#);
assert_that(p.cargo_process("build"),
execs()
.with_status(101)
2016-05-12 17:06:36 +00:00
.with_stderr("\
[ERROR] failed to parse manifest at `[..]`
Caused by:
package name cannot be an empty string.
2016-05-12 17:06:36 +00:00
"))
}
#[test]
fn cargo_compile_with_invalid_bin_target_name() {
let p = project("foo")
.file("Cargo.toml", r#"
[package]
name = "foo"
authors = []
version = "0.0.0"
[[bin]]
name = ""
"#);
assert_that(p.cargo_process("build"),
execs()
.with_status(101)
2016-05-12 17:06:36 +00:00
.with_stderr("\
[ERROR] failed to parse manifest at `[..]`
Caused by:
binary target names cannot be empty.
2016-05-12 17:06:36 +00:00
"))
}
#[test]
fn cargo_compile_with_forbidden_bin_target_name() {
let p = project("foo")
.file("Cargo.toml", r#"
[package]
name = "foo"
authors = []
version = "0.0.0"
[[bin]]
name = "build"
"#);
assert_that(p.cargo_process("build"),
execs()
.with_status(101)
2016-05-12 17:06:36 +00:00
.with_stderr("\
[ERROR] failed to parse manifest at `[..]`
Caused by:
the binary target name `build` is forbidden
2016-05-12 17:06:36 +00:00
"))
}
#[test]
fn cargo_compile_with_invalid_lib_target_name() {
let p = project("foo")
.file("Cargo.toml", r#"
[package]
name = "foo"
authors = []
version = "0.0.0"
[lib]
name = ""
"#);
assert_that(p.cargo_process("build"),
execs()
.with_status(101)
2016-05-12 17:06:36 +00:00
.with_stderr("\
[ERROR] failed to parse manifest at `[..]`
Caused by:
library target names cannot be empty.
2016-05-12 17:06:36 +00:00
"))
}
#[test]
fn cargo_compile_without_manifest() {
2014-07-16 00:51:49 +00:00
let tmpdir = TempDir::new("cargo").unwrap();
let p = ProjectBuilder::new("foo", tmpdir.path().to_path_buf());
2014-05-09 00:50:28 +00:00
assert_that(p.cargo_process("build"),
2015-02-06 07:27:53 +00:00
execs().with_status(101)
2016-05-12 17:06:36 +00:00
.with_stderr("\
[ERROR] could not find `Cargo.toml` in `[..]` or any parent directory
2016-05-12 17:06:36 +00:00
"));
}
#[test]
fn cargo_compile_with_invalid_code() {
let p = project("foo")
2015-03-26 18:17:44 +00:00
.file("Cargo.toml", &basic_bin_manifest("foo"))
.file("src/foo.rs", "invalid rust code!");
assert_that(p.cargo_process("build"),
execs()
.with_status(101)
2016-01-12 17:47:31 +00:00
.with_stderr_contains("\
[ERROR] Could not compile `foo`.
2016-05-12 17:06:36 +00:00
To learn more, run the command again with --verbose.\n"));
assert_that(&p.root().join("Cargo.lock"), existing_file());
}
#[test]
fn cargo_compile_with_invalid_code_in_deps() {
let p = project("foo")
.file("Cargo.toml", r#"
[package]
name = "foo"
version = "0.0.1"
authors = []
[dependencies.bar]
path = "../bar"
[dependencies.baz]
path = "../baz"
"#)
.file("src/main.rs", "invalid rust code!");
let bar = project("bar")
2015-03-26 18:17:44 +00:00
.file("Cargo.toml", &basic_bin_manifest("bar"))
.file("src/lib.rs", "invalid rust code!");
let baz = project("baz")
2015-03-26 18:17:44 +00:00
.file("Cargo.toml", &basic_bin_manifest("baz"))
.file("src/lib.rs", "invalid rust code!");
bar.build();
baz.build();
assert_that(p.cargo_process("build"), execs().with_status(101));
}
#[test]
fn cargo_compile_with_warnings_in_the_root_package() {
let p = project("foo")
2015-03-26 18:17:44 +00:00
.file("Cargo.toml", &basic_bin_manifest("foo"))
.file("src/foo.rs", "fn main() {} fn dead() {}");
assert_that(p.cargo_process("build"),
execs().with_stderr_contains("\
[..]function is never used: `dead`[..]
"));
}
#[test]
fn cargo_compile_with_warnings_in_a_dep_package() {
let mut p = project("foo");
p = p
.file("Cargo.toml", r#"
[project]
name = "foo"
version = "0.5.0"
authors = ["wycats@example.com"]
Implement a registry source # cargo upload The cargo-upload command will take the local package and upload it to the specified registry. The local package is uploaded as a tarball compressed with gzip under maximum compression. Most of this is done by just delegating to `cargo package` The host to upload to is specified, in order of priority, by a command line `--host` flag, the `registry.host` config key, and then the default registry. The default registry is still `example.com` The registry itself is still a work in progress, but the general plumbing for a command such as this would look like: 1. Ensure the local package has been compressed into an archive. 2. Fetch the relevant registry and login token from config files. 3. Ensure all dependencies for a package are listed as coming from the same registry. 4. Upload the archive to the registry with the login token. 5. The registry will verify the package is under 2MB (configurable). 6. The registry will upload the archive to S3, calculating a checksum in the process. 7. The registry will add an entry to the registry's index (a git repository). The entry will include the name of the package, the version uploaded, the checksum of the upload, and then the list of dependencies (name/version req) 8. The local `cargo upload` command will succeed. # cargo login Uploading requires a token from the api server, and this token follows the same config chain for the host except that there is no fallback. To implement login, the `cargo login` command is used. With 0 arguments, the command will request that a site be visited for a login token, and with an argument it will set the argument as the new login token. The `util::config` module was modified to allow writing configuration as well as reading it. The support is a little lacking in that comments are blown away, but the support is there at least. # RegistrySource An implementation of `RegistrySource` has been created (deleting the old `DummyRegistrySource`). This implementation only needs a URL to be constructed, and it is assumed that the URL is running an instance of the cargo registry. ## RegistrySource::update Currently this will unconditionally update the registry's index (a git repository). Tuning is necessary to prevent updating the index each time (more coming soon). ## RegistrySource::query This is called in the resolve phase of cargo. This function is given a dependency to query for, and the source will simply look into the index to see if any package with the name is present. If found, the package's index file will be loaded and parsed into a list of summaries. The main optimization of this function is to not require the entire registry to ever be resident in memory. Instead, only necessary packages are loaded into memory and parsed. ## RegistrySource::download This is also called during the resolve phase of cargo, but only when a package has been selected to be built (actually resolved). This phase of the source will actually download and unpack the tarball for the package. Currently a configuration file is located in the root of a registry's index describing the root url to download packages from. This function is optimized for two different metrics: 1. If a tarball is downloaded, it is not downloaded again. It is assumed that once a tarball is successfully downloaded it will never change. 2. If the unpacking destination has a `.cargo-ok` file, it is assumed that the unpacking has already occurred and does not need to happen again. With these in place, a rebuild should take almost no time at all. ## RegistrySource::get This function is simply implemented in terms of a PathSource's `get` function by creating a `PathSource` for all unpacked tarballs as part of the `download` stage. ## Filesystem layout There are a few new directories as part of the `.cargo` home folder: * `.cargo/registry/index/$hostname-$hash` - This is the directory containing the actual index of the registry. `$hostname` comes from its url, and `$hash` is the hash of the entire url. * `.cargo/registry/cache/$hostname-$hash/$pkg-$vers.tar.gz` - This is a directory used to cache the downloads of packages from the registry. * `.cargo/registry/src/$hostname-$hash/$pkg-$vers` - This is the location of the unpacked packages. They will be compiled from this location. # New Dependencies Cargo has picked up a new dependency on the `curl-rust` package in order to send HTTP requests to the registry as well as send HTTP requests to download tarballs.
2014-07-18 15:40:45 +00:00
[dependencies.bar]
path = "bar"
[[bin]]
name = "foo"
"#)
.file("src/foo.rs",
2015-03-26 18:17:44 +00:00
&main_file(r#""{}", bar::gimme()"#, &["bar"]))
.file("bar/Cargo.toml", r#"
[project]
name = "bar"
version = "0.5.0"
authors = ["wycats@example.com"]
2014-08-14 06:08:02 +00:00
[lib]
name = "bar"
"#)
.file("bar/src/bar.rs", r#"
2015-01-13 16:41:04 +00:00
pub fn gimme() -> &'static str {
"test passed"
}
fn dead() {}
"#);
assert_that(p.cargo_process("build"),
execs().with_stderr_contains("\
[..]function is never used: `dead`[..]
"));
assert_that(&p.bin("foo"), existing_file());
assert_that(
2015-10-28 09:20:00 +00:00
process(&p.bin("foo")),
execs().with_stdout("test passed\n"));
}
2014-05-09 00:50:28 +00:00
#[test]
fn cargo_compile_with_nested_deps_inferred() {
Implement a registry source # cargo upload The cargo-upload command will take the local package and upload it to the specified registry. The local package is uploaded as a tarball compressed with gzip under maximum compression. Most of this is done by just delegating to `cargo package` The host to upload to is specified, in order of priority, by a command line `--host` flag, the `registry.host` config key, and then the default registry. The default registry is still `example.com` The registry itself is still a work in progress, but the general plumbing for a command such as this would look like: 1. Ensure the local package has been compressed into an archive. 2. Fetch the relevant registry and login token from config files. 3. Ensure all dependencies for a package are listed as coming from the same registry. 4. Upload the archive to the registry with the login token. 5. The registry will verify the package is under 2MB (configurable). 6. The registry will upload the archive to S3, calculating a checksum in the process. 7. The registry will add an entry to the registry's index (a git repository). The entry will include the name of the package, the version uploaded, the checksum of the upload, and then the list of dependencies (name/version req) 8. The local `cargo upload` command will succeed. # cargo login Uploading requires a token from the api server, and this token follows the same config chain for the host except that there is no fallback. To implement login, the `cargo login` command is used. With 0 arguments, the command will request that a site be visited for a login token, and with an argument it will set the argument as the new login token. The `util::config` module was modified to allow writing configuration as well as reading it. The support is a little lacking in that comments are blown away, but the support is there at least. # RegistrySource An implementation of `RegistrySource` has been created (deleting the old `DummyRegistrySource`). This implementation only needs a URL to be constructed, and it is assumed that the URL is running an instance of the cargo registry. ## RegistrySource::update Currently this will unconditionally update the registry's index (a git repository). Tuning is necessary to prevent updating the index each time (more coming soon). ## RegistrySource::query This is called in the resolve phase of cargo. This function is given a dependency to query for, and the source will simply look into the index to see if any package with the name is present. If found, the package's index file will be loaded and parsed into a list of summaries. The main optimization of this function is to not require the entire registry to ever be resident in memory. Instead, only necessary packages are loaded into memory and parsed. ## RegistrySource::download This is also called during the resolve phase of cargo, but only when a package has been selected to be built (actually resolved). This phase of the source will actually download and unpack the tarball for the package. Currently a configuration file is located in the root of a registry's index describing the root url to download packages from. This function is optimized for two different metrics: 1. If a tarball is downloaded, it is not downloaded again. It is assumed that once a tarball is successfully downloaded it will never change. 2. If the unpacking destination has a `.cargo-ok` file, it is assumed that the unpacking has already occurred and does not need to happen again. With these in place, a rebuild should take almost no time at all. ## RegistrySource::get This function is simply implemented in terms of a PathSource's `get` function by creating a `PathSource` for all unpacked tarballs as part of the `download` stage. ## Filesystem layout There are a few new directories as part of the `.cargo` home folder: * `.cargo/registry/index/$hostname-$hash` - This is the directory containing the actual index of the registry. `$hostname` comes from its url, and `$hash` is the hash of the entire url. * `.cargo/registry/cache/$hostname-$hash/$pkg-$vers.tar.gz` - This is a directory used to cache the downloads of packages from the registry. * `.cargo/registry/src/$hostname-$hash/$pkg-$vers` - This is the location of the unpacked packages. They will be compiled from this location. # New Dependencies Cargo has picked up a new dependency on the `curl-rust` package in order to send HTTP requests to the registry as well as send HTTP requests to download tarballs.
2014-07-18 15:40:45 +00:00
let p = project("foo")
2014-07-08 00:59:18 +00:00
.file("Cargo.toml", r#"
[project]
name = "foo"
version = "0.5.0"
authors = ["wycats@example.com"]
Implement a registry source # cargo upload The cargo-upload command will take the local package and upload it to the specified registry. The local package is uploaded as a tarball compressed with gzip under maximum compression. Most of this is done by just delegating to `cargo package` The host to upload to is specified, in order of priority, by a command line `--host` flag, the `registry.host` config key, and then the default registry. The default registry is still `example.com` The registry itself is still a work in progress, but the general plumbing for a command such as this would look like: 1. Ensure the local package has been compressed into an archive. 2. Fetch the relevant registry and login token from config files. 3. Ensure all dependencies for a package are listed as coming from the same registry. 4. Upload the archive to the registry with the login token. 5. The registry will verify the package is under 2MB (configurable). 6. The registry will upload the archive to S3, calculating a checksum in the process. 7. The registry will add an entry to the registry's index (a git repository). The entry will include the name of the package, the version uploaded, the checksum of the upload, and then the list of dependencies (name/version req) 8. The local `cargo upload` command will succeed. # cargo login Uploading requires a token from the api server, and this token follows the same config chain for the host except that there is no fallback. To implement login, the `cargo login` command is used. With 0 arguments, the command will request that a site be visited for a login token, and with an argument it will set the argument as the new login token. The `util::config` module was modified to allow writing configuration as well as reading it. The support is a little lacking in that comments are blown away, but the support is there at least. # RegistrySource An implementation of `RegistrySource` has been created (deleting the old `DummyRegistrySource`). This implementation only needs a URL to be constructed, and it is assumed that the URL is running an instance of the cargo registry. ## RegistrySource::update Currently this will unconditionally update the registry's index (a git repository). Tuning is necessary to prevent updating the index each time (more coming soon). ## RegistrySource::query This is called in the resolve phase of cargo. This function is given a dependency to query for, and the source will simply look into the index to see if any package with the name is present. If found, the package's index file will be loaded and parsed into a list of summaries. The main optimization of this function is to not require the entire registry to ever be resident in memory. Instead, only necessary packages are loaded into memory and parsed. ## RegistrySource::download This is also called during the resolve phase of cargo, but only when a package has been selected to be built (actually resolved). This phase of the source will actually download and unpack the tarball for the package. Currently a configuration file is located in the root of a registry's index describing the root url to download packages from. This function is optimized for two different metrics: 1. If a tarball is downloaded, it is not downloaded again. It is assumed that once a tarball is successfully downloaded it will never change. 2. If the unpacking destination has a `.cargo-ok` file, it is assumed that the unpacking has already occurred and does not need to happen again. With these in place, a rebuild should take almost no time at all. ## RegistrySource::get This function is simply implemented in terms of a PathSource's `get` function by creating a `PathSource` for all unpacked tarballs as part of the `download` stage. ## Filesystem layout There are a few new directories as part of the `.cargo` home folder: * `.cargo/registry/index/$hostname-$hash` - This is the directory containing the actual index of the registry. `$hostname` comes from its url, and `$hash` is the hash of the entire url. * `.cargo/registry/cache/$hostname-$hash/$pkg-$vers.tar.gz` - This is a directory used to cache the downloads of packages from the registry. * `.cargo/registry/src/$hostname-$hash/$pkg-$vers` - This is the location of the unpacked packages. They will be compiled from this location. # New Dependencies Cargo has picked up a new dependency on the `curl-rust` package in order to send HTTP requests to the registry as well as send HTTP requests to download tarballs.
2014-07-18 15:40:45 +00:00
[dependencies.bar]
path = 'bar'
2014-07-08 00:59:18 +00:00
[[bin]]
name = "foo"
"#)
.file("src/foo.rs",
2015-03-26 18:17:44 +00:00
&main_file(r#""{}", bar::gimme()"#, &["bar"]))
2014-07-08 00:59:18 +00:00
.file("bar/Cargo.toml", r#"
[project]
name = "bar"
version = "0.5.0"
authors = ["wycats@example.com"]
Implement a registry source # cargo upload The cargo-upload command will take the local package and upload it to the specified registry. The local package is uploaded as a tarball compressed with gzip under maximum compression. Most of this is done by just delegating to `cargo package` The host to upload to is specified, in order of priority, by a command line `--host` flag, the `registry.host` config key, and then the default registry. The default registry is still `example.com` The registry itself is still a work in progress, but the general plumbing for a command such as this would look like: 1. Ensure the local package has been compressed into an archive. 2. Fetch the relevant registry and login token from config files. 3. Ensure all dependencies for a package are listed as coming from the same registry. 4. Upload the archive to the registry with the login token. 5. The registry will verify the package is under 2MB (configurable). 6. The registry will upload the archive to S3, calculating a checksum in the process. 7. The registry will add an entry to the registry's index (a git repository). The entry will include the name of the package, the version uploaded, the checksum of the upload, and then the list of dependencies (name/version req) 8. The local `cargo upload` command will succeed. # cargo login Uploading requires a token from the api server, and this token follows the same config chain for the host except that there is no fallback. To implement login, the `cargo login` command is used. With 0 arguments, the command will request that a site be visited for a login token, and with an argument it will set the argument as the new login token. The `util::config` module was modified to allow writing configuration as well as reading it. The support is a little lacking in that comments are blown away, but the support is there at least. # RegistrySource An implementation of `RegistrySource` has been created (deleting the old `DummyRegistrySource`). This implementation only needs a URL to be constructed, and it is assumed that the URL is running an instance of the cargo registry. ## RegistrySource::update Currently this will unconditionally update the registry's index (a git repository). Tuning is necessary to prevent updating the index each time (more coming soon). ## RegistrySource::query This is called in the resolve phase of cargo. This function is given a dependency to query for, and the source will simply look into the index to see if any package with the name is present. If found, the package's index file will be loaded and parsed into a list of summaries. The main optimization of this function is to not require the entire registry to ever be resident in memory. Instead, only necessary packages are loaded into memory and parsed. ## RegistrySource::download This is also called during the resolve phase of cargo, but only when a package has been selected to be built (actually resolved). This phase of the source will actually download and unpack the tarball for the package. Currently a configuration file is located in the root of a registry's index describing the root url to download packages from. This function is optimized for two different metrics: 1. If a tarball is downloaded, it is not downloaded again. It is assumed that once a tarball is successfully downloaded it will never change. 2. If the unpacking destination has a `.cargo-ok` file, it is assumed that the unpacking has already occurred and does not need to happen again. With these in place, a rebuild should take almost no time at all. ## RegistrySource::get This function is simply implemented in terms of a PathSource's `get` function by creating a `PathSource` for all unpacked tarballs as part of the `download` stage. ## Filesystem layout There are a few new directories as part of the `.cargo` home folder: * `.cargo/registry/index/$hostname-$hash` - This is the directory containing the actual index of the registry. `$hostname` comes from its url, and `$hash` is the hash of the entire url. * `.cargo/registry/cache/$hostname-$hash/$pkg-$vers.tar.gz` - This is a directory used to cache the downloads of packages from the registry. * `.cargo/registry/src/$hostname-$hash/$pkg-$vers` - This is the location of the unpacked packages. They will be compiled from this location. # New Dependencies Cargo has picked up a new dependency on the `curl-rust` package in order to send HTTP requests to the registry as well as send HTTP requests to download tarballs.
2014-07-18 15:40:45 +00:00
[dependencies.baz]
path = "../baz"
2014-07-08 00:59:18 +00:00
"#)
.file("bar/src/lib.rs", r#"
extern crate baz;
pub fn gimme() -> String {
baz::gimme()
}
"#)
.file("baz/Cargo.toml", r#"
[project]
name = "baz"
version = "0.5.0"
authors = ["wycats@example.com"]
"#)
.file("baz/src/lib.rs", r#"
pub fn gimme() -> String {
"test passed".to_string()
2014-07-08 00:59:18 +00:00
}
"#);
p.cargo_process("build")
2014-07-08 00:59:18 +00:00
.exec_with_output()
.unwrap();
2014-07-08 00:59:18 +00:00
assert_that(&p.bin("foo"), existing_file());
assert_that(
2015-10-28 09:20:00 +00:00
process(&p.bin("foo")),
2014-07-08 00:59:18 +00:00
execs().with_stdout("test passed\n"));
}
2014-07-08 00:59:18 +00:00
#[test]
fn cargo_compile_with_nested_deps_correct_bin() {
Implement a registry source # cargo upload The cargo-upload command will take the local package and upload it to the specified registry. The local package is uploaded as a tarball compressed with gzip under maximum compression. Most of this is done by just delegating to `cargo package` The host to upload to is specified, in order of priority, by a command line `--host` flag, the `registry.host` config key, and then the default registry. The default registry is still `example.com` The registry itself is still a work in progress, but the general plumbing for a command such as this would look like: 1. Ensure the local package has been compressed into an archive. 2. Fetch the relevant registry and login token from config files. 3. Ensure all dependencies for a package are listed as coming from the same registry. 4. Upload the archive to the registry with the login token. 5. The registry will verify the package is under 2MB (configurable). 6. The registry will upload the archive to S3, calculating a checksum in the process. 7. The registry will add an entry to the registry's index (a git repository). The entry will include the name of the package, the version uploaded, the checksum of the upload, and then the list of dependencies (name/version req) 8. The local `cargo upload` command will succeed. # cargo login Uploading requires a token from the api server, and this token follows the same config chain for the host except that there is no fallback. To implement login, the `cargo login` command is used. With 0 arguments, the command will request that a site be visited for a login token, and with an argument it will set the argument as the new login token. The `util::config` module was modified to allow writing configuration as well as reading it. The support is a little lacking in that comments are blown away, but the support is there at least. # RegistrySource An implementation of `RegistrySource` has been created (deleting the old `DummyRegistrySource`). This implementation only needs a URL to be constructed, and it is assumed that the URL is running an instance of the cargo registry. ## RegistrySource::update Currently this will unconditionally update the registry's index (a git repository). Tuning is necessary to prevent updating the index each time (more coming soon). ## RegistrySource::query This is called in the resolve phase of cargo. This function is given a dependency to query for, and the source will simply look into the index to see if any package with the name is present. If found, the package's index file will be loaded and parsed into a list of summaries. The main optimization of this function is to not require the entire registry to ever be resident in memory. Instead, only necessary packages are loaded into memory and parsed. ## RegistrySource::download This is also called during the resolve phase of cargo, but only when a package has been selected to be built (actually resolved). This phase of the source will actually download and unpack the tarball for the package. Currently a configuration file is located in the root of a registry's index describing the root url to download packages from. This function is optimized for two different metrics: 1. If a tarball is downloaded, it is not downloaded again. It is assumed that once a tarball is successfully downloaded it will never change. 2. If the unpacking destination has a `.cargo-ok` file, it is assumed that the unpacking has already occurred and does not need to happen again. With these in place, a rebuild should take almost no time at all. ## RegistrySource::get This function is simply implemented in terms of a PathSource's `get` function by creating a `PathSource` for all unpacked tarballs as part of the `download` stage. ## Filesystem layout There are a few new directories as part of the `.cargo` home folder: * `.cargo/registry/index/$hostname-$hash` - This is the directory containing the actual index of the registry. `$hostname` comes from its url, and `$hash` is the hash of the entire url. * `.cargo/registry/cache/$hostname-$hash/$pkg-$vers.tar.gz` - This is a directory used to cache the downloads of packages from the registry. * `.cargo/registry/src/$hostname-$hash/$pkg-$vers` - This is the location of the unpacked packages. They will be compiled from this location. # New Dependencies Cargo has picked up a new dependency on the `curl-rust` package in order to send HTTP requests to the registry as well as send HTTP requests to download tarballs.
2014-07-18 15:40:45 +00:00
let p = project("foo")
2014-07-08 00:59:18 +00:00
.file("Cargo.toml", r#"
[project]
name = "foo"
version = "0.5.0"
authors = ["wycats@example.com"]
Implement a registry source # cargo upload The cargo-upload command will take the local package and upload it to the specified registry. The local package is uploaded as a tarball compressed with gzip under maximum compression. Most of this is done by just delegating to `cargo package` The host to upload to is specified, in order of priority, by a command line `--host` flag, the `registry.host` config key, and then the default registry. The default registry is still `example.com` The registry itself is still a work in progress, but the general plumbing for a command such as this would look like: 1. Ensure the local package has been compressed into an archive. 2. Fetch the relevant registry and login token from config files. 3. Ensure all dependencies for a package are listed as coming from the same registry. 4. Upload the archive to the registry with the login token. 5. The registry will verify the package is under 2MB (configurable). 6. The registry will upload the archive to S3, calculating a checksum in the process. 7. The registry will add an entry to the registry's index (a git repository). The entry will include the name of the package, the version uploaded, the checksum of the upload, and then the list of dependencies (name/version req) 8. The local `cargo upload` command will succeed. # cargo login Uploading requires a token from the api server, and this token follows the same config chain for the host except that there is no fallback. To implement login, the `cargo login` command is used. With 0 arguments, the command will request that a site be visited for a login token, and with an argument it will set the argument as the new login token. The `util::config` module was modified to allow writing configuration as well as reading it. The support is a little lacking in that comments are blown away, but the support is there at least. # RegistrySource An implementation of `RegistrySource` has been created (deleting the old `DummyRegistrySource`). This implementation only needs a URL to be constructed, and it is assumed that the URL is running an instance of the cargo registry. ## RegistrySource::update Currently this will unconditionally update the registry's index (a git repository). Tuning is necessary to prevent updating the index each time (more coming soon). ## RegistrySource::query This is called in the resolve phase of cargo. This function is given a dependency to query for, and the source will simply look into the index to see if any package with the name is present. If found, the package's index file will be loaded and parsed into a list of summaries. The main optimization of this function is to not require the entire registry to ever be resident in memory. Instead, only necessary packages are loaded into memory and parsed. ## RegistrySource::download This is also called during the resolve phase of cargo, but only when a package has been selected to be built (actually resolved). This phase of the source will actually download and unpack the tarball for the package. Currently a configuration file is located in the root of a registry's index describing the root url to download packages from. This function is optimized for two different metrics: 1. If a tarball is downloaded, it is not downloaded again. It is assumed that once a tarball is successfully downloaded it will never change. 2. If the unpacking destination has a `.cargo-ok` file, it is assumed that the unpacking has already occurred and does not need to happen again. With these in place, a rebuild should take almost no time at all. ## RegistrySource::get This function is simply implemented in terms of a PathSource's `get` function by creating a `PathSource` for all unpacked tarballs as part of the `download` stage. ## Filesystem layout There are a few new directories as part of the `.cargo` home folder: * `.cargo/registry/index/$hostname-$hash` - This is the directory containing the actual index of the registry. `$hostname` comes from its url, and `$hash` is the hash of the entire url. * `.cargo/registry/cache/$hostname-$hash/$pkg-$vers.tar.gz` - This is a directory used to cache the downloads of packages from the registry. * `.cargo/registry/src/$hostname-$hash/$pkg-$vers` - This is the location of the unpacked packages. They will be compiled from this location. # New Dependencies Cargo has picked up a new dependency on the `curl-rust` package in order to send HTTP requests to the registry as well as send HTTP requests to download tarballs.
2014-07-18 15:40:45 +00:00
[dependencies.bar]
path = "bar"
2014-07-08 00:59:18 +00:00
[[bin]]
name = "foo"
"#)
.file("src/main.rs",
2015-03-26 18:17:44 +00:00
&main_file(r#""{}", bar::gimme()"#, &["bar"]))
2014-07-08 00:59:18 +00:00
.file("bar/Cargo.toml", r#"
[project]
name = "bar"
version = "0.5.0"
authors = ["wycats@example.com"]
Implement a registry source # cargo upload The cargo-upload command will take the local package and upload it to the specified registry. The local package is uploaded as a tarball compressed with gzip under maximum compression. Most of this is done by just delegating to `cargo package` The host to upload to is specified, in order of priority, by a command line `--host` flag, the `registry.host` config key, and then the default registry. The default registry is still `example.com` The registry itself is still a work in progress, but the general plumbing for a command such as this would look like: 1. Ensure the local package has been compressed into an archive. 2. Fetch the relevant registry and login token from config files. 3. Ensure all dependencies for a package are listed as coming from the same registry. 4. Upload the archive to the registry with the login token. 5. The registry will verify the package is under 2MB (configurable). 6. The registry will upload the archive to S3, calculating a checksum in the process. 7. The registry will add an entry to the registry's index (a git repository). The entry will include the name of the package, the version uploaded, the checksum of the upload, and then the list of dependencies (name/version req) 8. The local `cargo upload` command will succeed. # cargo login Uploading requires a token from the api server, and this token follows the same config chain for the host except that there is no fallback. To implement login, the `cargo login` command is used. With 0 arguments, the command will request that a site be visited for a login token, and with an argument it will set the argument as the new login token. The `util::config` module was modified to allow writing configuration as well as reading it. The support is a little lacking in that comments are blown away, but the support is there at least. # RegistrySource An implementation of `RegistrySource` has been created (deleting the old `DummyRegistrySource`). This implementation only needs a URL to be constructed, and it is assumed that the URL is running an instance of the cargo registry. ## RegistrySource::update Currently this will unconditionally update the registry's index (a git repository). Tuning is necessary to prevent updating the index each time (more coming soon). ## RegistrySource::query This is called in the resolve phase of cargo. This function is given a dependency to query for, and the source will simply look into the index to see if any package with the name is present. If found, the package's index file will be loaded and parsed into a list of summaries. The main optimization of this function is to not require the entire registry to ever be resident in memory. Instead, only necessary packages are loaded into memory and parsed. ## RegistrySource::download This is also called during the resolve phase of cargo, but only when a package has been selected to be built (actually resolved). This phase of the source will actually download and unpack the tarball for the package. Currently a configuration file is located in the root of a registry's index describing the root url to download packages from. This function is optimized for two different metrics: 1. If a tarball is downloaded, it is not downloaded again. It is assumed that once a tarball is successfully downloaded it will never change. 2. If the unpacking destination has a `.cargo-ok` file, it is assumed that the unpacking has already occurred and does not need to happen again. With these in place, a rebuild should take almost no time at all. ## RegistrySource::get This function is simply implemented in terms of a PathSource's `get` function by creating a `PathSource` for all unpacked tarballs as part of the `download` stage. ## Filesystem layout There are a few new directories as part of the `.cargo` home folder: * `.cargo/registry/index/$hostname-$hash` - This is the directory containing the actual index of the registry. `$hostname` comes from its url, and `$hash` is the hash of the entire url. * `.cargo/registry/cache/$hostname-$hash/$pkg-$vers.tar.gz` - This is a directory used to cache the downloads of packages from the registry. * `.cargo/registry/src/$hostname-$hash/$pkg-$vers` - This is the location of the unpacked packages. They will be compiled from this location. # New Dependencies Cargo has picked up a new dependency on the `curl-rust` package in order to send HTTP requests to the registry as well as send HTTP requests to download tarballs.
2014-07-18 15:40:45 +00:00
[dependencies.baz]
path = "../baz"
2014-07-08 00:59:18 +00:00
"#)
.file("bar/src/lib.rs", r#"
extern crate baz;
pub fn gimme() -> String {
baz::gimme()
}
"#)
.file("baz/Cargo.toml", r#"
[project]
name = "baz"
version = "0.5.0"
authors = ["wycats@example.com"]
"#)
.file("baz/src/lib.rs", r#"
pub fn gimme() -> String {
"test passed".to_string()
2014-07-08 00:59:18 +00:00
}
"#);
p.cargo_process("build")
2014-07-08 00:59:18 +00:00
.exec_with_output()
.unwrap();
2014-07-08 00:59:18 +00:00
assert_that(&p.bin("foo"), existing_file());
assert_that(
2015-10-28 09:20:00 +00:00
process(&p.bin("foo")),
2014-07-08 00:59:18 +00:00
execs().with_stdout("test passed\n"));
}
2014-07-08 00:59:18 +00:00
#[test]
fn cargo_compile_with_nested_deps_shorthand() {
Implement a registry source # cargo upload The cargo-upload command will take the local package and upload it to the specified registry. The local package is uploaded as a tarball compressed with gzip under maximum compression. Most of this is done by just delegating to `cargo package` The host to upload to is specified, in order of priority, by a command line `--host` flag, the `registry.host` config key, and then the default registry. The default registry is still `example.com` The registry itself is still a work in progress, but the general plumbing for a command such as this would look like: 1. Ensure the local package has been compressed into an archive. 2. Fetch the relevant registry and login token from config files. 3. Ensure all dependencies for a package are listed as coming from the same registry. 4. Upload the archive to the registry with the login token. 5. The registry will verify the package is under 2MB (configurable). 6. The registry will upload the archive to S3, calculating a checksum in the process. 7. The registry will add an entry to the registry's index (a git repository). The entry will include the name of the package, the version uploaded, the checksum of the upload, and then the list of dependencies (name/version req) 8. The local `cargo upload` command will succeed. # cargo login Uploading requires a token from the api server, and this token follows the same config chain for the host except that there is no fallback. To implement login, the `cargo login` command is used. With 0 arguments, the command will request that a site be visited for a login token, and with an argument it will set the argument as the new login token. The `util::config` module was modified to allow writing configuration as well as reading it. The support is a little lacking in that comments are blown away, but the support is there at least. # RegistrySource An implementation of `RegistrySource` has been created (deleting the old `DummyRegistrySource`). This implementation only needs a URL to be constructed, and it is assumed that the URL is running an instance of the cargo registry. ## RegistrySource::update Currently this will unconditionally update the registry's index (a git repository). Tuning is necessary to prevent updating the index each time (more coming soon). ## RegistrySource::query This is called in the resolve phase of cargo. This function is given a dependency to query for, and the source will simply look into the index to see if any package with the name is present. If found, the package's index file will be loaded and parsed into a list of summaries. The main optimization of this function is to not require the entire registry to ever be resident in memory. Instead, only necessary packages are loaded into memory and parsed. ## RegistrySource::download This is also called during the resolve phase of cargo, but only when a package has been selected to be built (actually resolved). This phase of the source will actually download and unpack the tarball for the package. Currently a configuration file is located in the root of a registry's index describing the root url to download packages from. This function is optimized for two different metrics: 1. If a tarball is downloaded, it is not downloaded again. It is assumed that once a tarball is successfully downloaded it will never change. 2. If the unpacking destination has a `.cargo-ok` file, it is assumed that the unpacking has already occurred and does not need to happen again. With these in place, a rebuild should take almost no time at all. ## RegistrySource::get This function is simply implemented in terms of a PathSource's `get` function by creating a `PathSource` for all unpacked tarballs as part of the `download` stage. ## Filesystem layout There are a few new directories as part of the `.cargo` home folder: * `.cargo/registry/index/$hostname-$hash` - This is the directory containing the actual index of the registry. `$hostname` comes from its url, and `$hash` is the hash of the entire url. * `.cargo/registry/cache/$hostname-$hash/$pkg-$vers.tar.gz` - This is a directory used to cache the downloads of packages from the registry. * `.cargo/registry/src/$hostname-$hash/$pkg-$vers` - This is the location of the unpacked packages. They will be compiled from this location. # New Dependencies Cargo has picked up a new dependency on the `curl-rust` package in order to send HTTP requests to the registry as well as send HTTP requests to download tarballs.
2014-07-18 15:40:45 +00:00
let p = project("foo")
2014-05-08 23:49:58 +00:00
.file("Cargo.toml", r#"
[project]
name = "foo"
version = "0.5.0"
authors = ["wycats@example.com"]
Implement a registry source # cargo upload The cargo-upload command will take the local package and upload it to the specified registry. The local package is uploaded as a tarball compressed with gzip under maximum compression. Most of this is done by just delegating to `cargo package` The host to upload to is specified, in order of priority, by a command line `--host` flag, the `registry.host` config key, and then the default registry. The default registry is still `example.com` The registry itself is still a work in progress, but the general plumbing for a command such as this would look like: 1. Ensure the local package has been compressed into an archive. 2. Fetch the relevant registry and login token from config files. 3. Ensure all dependencies for a package are listed as coming from the same registry. 4. Upload the archive to the registry with the login token. 5. The registry will verify the package is under 2MB (configurable). 6. The registry will upload the archive to S3, calculating a checksum in the process. 7. The registry will add an entry to the registry's index (a git repository). The entry will include the name of the package, the version uploaded, the checksum of the upload, and then the list of dependencies (name/version req) 8. The local `cargo upload` command will succeed. # cargo login Uploading requires a token from the api server, and this token follows the same config chain for the host except that there is no fallback. To implement login, the `cargo login` command is used. With 0 arguments, the command will request that a site be visited for a login token, and with an argument it will set the argument as the new login token. The `util::config` module was modified to allow writing configuration as well as reading it. The support is a little lacking in that comments are blown away, but the support is there at least. # RegistrySource An implementation of `RegistrySource` has been created (deleting the old `DummyRegistrySource`). This implementation only needs a URL to be constructed, and it is assumed that the URL is running an instance of the cargo registry. ## RegistrySource::update Currently this will unconditionally update the registry's index (a git repository). Tuning is necessary to prevent updating the index each time (more coming soon). ## RegistrySource::query This is called in the resolve phase of cargo. This function is given a dependency to query for, and the source will simply look into the index to see if any package with the name is present. If found, the package's index file will be loaded and parsed into a list of summaries. The main optimization of this function is to not require the entire registry to ever be resident in memory. Instead, only necessary packages are loaded into memory and parsed. ## RegistrySource::download This is also called during the resolve phase of cargo, but only when a package has been selected to be built (actually resolved). This phase of the source will actually download and unpack the tarball for the package. Currently a configuration file is located in the root of a registry's index describing the root url to download packages from. This function is optimized for two different metrics: 1. If a tarball is downloaded, it is not downloaded again. It is assumed that once a tarball is successfully downloaded it will never change. 2. If the unpacking destination has a `.cargo-ok` file, it is assumed that the unpacking has already occurred and does not need to happen again. With these in place, a rebuild should take almost no time at all. ## RegistrySource::get This function is simply implemented in terms of a PathSource's `get` function by creating a `PathSource` for all unpacked tarballs as part of the `download` stage. ## Filesystem layout There are a few new directories as part of the `.cargo` home folder: * `.cargo/registry/index/$hostname-$hash` - This is the directory containing the actual index of the registry. `$hostname` comes from its url, and `$hash` is the hash of the entire url. * `.cargo/registry/cache/$hostname-$hash/$pkg-$vers.tar.gz` - This is a directory used to cache the downloads of packages from the registry. * `.cargo/registry/src/$hostname-$hash/$pkg-$vers` - This is the location of the unpacked packages. They will be compiled from this location. # New Dependencies Cargo has picked up a new dependency on the `curl-rust` package in order to send HTTP requests to the registry as well as send HTTP requests to download tarballs.
2014-07-18 15:40:45 +00:00
[dependencies.bar]
path = "bar"
2014-05-08 23:49:58 +00:00
[[bin]]
name = "foo"
"#)
.file("src/foo.rs",
2015-03-26 18:17:44 +00:00
&main_file(r#""{}", bar::gimme()"#, &["bar"]))
2014-05-08 23:49:58 +00:00
.file("bar/Cargo.toml", r#"
[project]
name = "bar"
version = "0.5.0"
authors = ["wycats@example.com"]
Implement a registry source # cargo upload The cargo-upload command will take the local package and upload it to the specified registry. The local package is uploaded as a tarball compressed with gzip under maximum compression. Most of this is done by just delegating to `cargo package` The host to upload to is specified, in order of priority, by a command line `--host` flag, the `registry.host` config key, and then the default registry. The default registry is still `example.com` The registry itself is still a work in progress, but the general plumbing for a command such as this would look like: 1. Ensure the local package has been compressed into an archive. 2. Fetch the relevant registry and login token from config files. 3. Ensure all dependencies for a package are listed as coming from the same registry. 4. Upload the archive to the registry with the login token. 5. The registry will verify the package is under 2MB (configurable). 6. The registry will upload the archive to S3, calculating a checksum in the process. 7. The registry will add an entry to the registry's index (a git repository). The entry will include the name of the package, the version uploaded, the checksum of the upload, and then the list of dependencies (name/version req) 8. The local `cargo upload` command will succeed. # cargo login Uploading requires a token from the api server, and this token follows the same config chain for the host except that there is no fallback. To implement login, the `cargo login` command is used. With 0 arguments, the command will request that a site be visited for a login token, and with an argument it will set the argument as the new login token. The `util::config` module was modified to allow writing configuration as well as reading it. The support is a little lacking in that comments are blown away, but the support is there at least. # RegistrySource An implementation of `RegistrySource` has been created (deleting the old `DummyRegistrySource`). This implementation only needs a URL to be constructed, and it is assumed that the URL is running an instance of the cargo registry. ## RegistrySource::update Currently this will unconditionally update the registry's index (a git repository). Tuning is necessary to prevent updating the index each time (more coming soon). ## RegistrySource::query This is called in the resolve phase of cargo. This function is given a dependency to query for, and the source will simply look into the index to see if any package with the name is present. If found, the package's index file will be loaded and parsed into a list of summaries. The main optimization of this function is to not require the entire registry to ever be resident in memory. Instead, only necessary packages are loaded into memory and parsed. ## RegistrySource::download This is also called during the resolve phase of cargo, but only when a package has been selected to be built (actually resolved). This phase of the source will actually download and unpack the tarball for the package. Currently a configuration file is located in the root of a registry's index describing the root url to download packages from. This function is optimized for two different metrics: 1. If a tarball is downloaded, it is not downloaded again. It is assumed that once a tarball is successfully downloaded it will never change. 2. If the unpacking destination has a `.cargo-ok` file, it is assumed that the unpacking has already occurred and does not need to happen again. With these in place, a rebuild should take almost no time at all. ## RegistrySource::get This function is simply implemented in terms of a PathSource's `get` function by creating a `PathSource` for all unpacked tarballs as part of the `download` stage. ## Filesystem layout There are a few new directories as part of the `.cargo` home folder: * `.cargo/registry/index/$hostname-$hash` - This is the directory containing the actual index of the registry. `$hostname` comes from its url, and `$hash` is the hash of the entire url. * `.cargo/registry/cache/$hostname-$hash/$pkg-$vers.tar.gz` - This is a directory used to cache the downloads of packages from the registry. * `.cargo/registry/src/$hostname-$hash/$pkg-$vers` - This is the location of the unpacked packages. They will be compiled from this location. # New Dependencies Cargo has picked up a new dependency on the `curl-rust` package in order to send HTTP requests to the registry as well as send HTTP requests to download tarballs.
2014-07-18 15:40:45 +00:00
[dependencies.baz]
path = "../baz"
2014-05-08 23:49:58 +00:00
2014-08-14 06:08:02 +00:00
[lib]
2014-05-08 23:49:58 +00:00
name = "bar"
"#)
.file("bar/src/bar.rs", r#"
extern crate baz;
2014-05-27 23:14:34 +00:00
pub fn gimme() -> String {
2014-05-08 23:49:58 +00:00
baz::gimme()
}
"#)
.file("baz/Cargo.toml", r#"
[project]
name = "baz"
version = "0.5.0"
authors = ["wycats@example.com"]
2014-08-14 06:08:02 +00:00
[lib]
2014-05-08 23:49:58 +00:00
name = "baz"
"#)
.file("baz/src/baz.rs", r#"
2014-05-27 23:14:34 +00:00
pub fn gimme() -> String {
"test passed".to_string()
2014-05-08 23:49:58 +00:00
}
2014-05-09 00:50:28 +00:00
"#);
2014-05-08 23:49:58 +00:00
p.cargo_process("build")
2014-05-08 23:49:58 +00:00
.exec_with_output()
.unwrap();
2014-05-08 23:49:58 +00:00
assert_that(&p.bin("foo"), existing_file());
2014-05-08 23:49:58 +00:00
assert_that(
2015-10-28 09:20:00 +00:00
process(&p.bin("foo")),
2014-05-08 23:49:58 +00:00
execs().with_stdout("test passed\n"));
}
2014-05-08 23:49:58 +00:00
#[test]
fn cargo_compile_with_nested_deps_longhand() {
Implement a registry source # cargo upload The cargo-upload command will take the local package and upload it to the specified registry. The local package is uploaded as a tarball compressed with gzip under maximum compression. Most of this is done by just delegating to `cargo package` The host to upload to is specified, in order of priority, by a command line `--host` flag, the `registry.host` config key, and then the default registry. The default registry is still `example.com` The registry itself is still a work in progress, but the general plumbing for a command such as this would look like: 1. Ensure the local package has been compressed into an archive. 2. Fetch the relevant registry and login token from config files. 3. Ensure all dependencies for a package are listed as coming from the same registry. 4. Upload the archive to the registry with the login token. 5. The registry will verify the package is under 2MB (configurable). 6. The registry will upload the archive to S3, calculating a checksum in the process. 7. The registry will add an entry to the registry's index (a git repository). The entry will include the name of the package, the version uploaded, the checksum of the upload, and then the list of dependencies (name/version req) 8. The local `cargo upload` command will succeed. # cargo login Uploading requires a token from the api server, and this token follows the same config chain for the host except that there is no fallback. To implement login, the `cargo login` command is used. With 0 arguments, the command will request that a site be visited for a login token, and with an argument it will set the argument as the new login token. The `util::config` module was modified to allow writing configuration as well as reading it. The support is a little lacking in that comments are blown away, but the support is there at least. # RegistrySource An implementation of `RegistrySource` has been created (deleting the old `DummyRegistrySource`). This implementation only needs a URL to be constructed, and it is assumed that the URL is running an instance of the cargo registry. ## RegistrySource::update Currently this will unconditionally update the registry's index (a git repository). Tuning is necessary to prevent updating the index each time (more coming soon). ## RegistrySource::query This is called in the resolve phase of cargo. This function is given a dependency to query for, and the source will simply look into the index to see if any package with the name is present. If found, the package's index file will be loaded and parsed into a list of summaries. The main optimization of this function is to not require the entire registry to ever be resident in memory. Instead, only necessary packages are loaded into memory and parsed. ## RegistrySource::download This is also called during the resolve phase of cargo, but only when a package has been selected to be built (actually resolved). This phase of the source will actually download and unpack the tarball for the package. Currently a configuration file is located in the root of a registry's index describing the root url to download packages from. This function is optimized for two different metrics: 1. If a tarball is downloaded, it is not downloaded again. It is assumed that once a tarball is successfully downloaded it will never change. 2. If the unpacking destination has a `.cargo-ok` file, it is assumed that the unpacking has already occurred and does not need to happen again. With these in place, a rebuild should take almost no time at all. ## RegistrySource::get This function is simply implemented in terms of a PathSource's `get` function by creating a `PathSource` for all unpacked tarballs as part of the `download` stage. ## Filesystem layout There are a few new directories as part of the `.cargo` home folder: * `.cargo/registry/index/$hostname-$hash` - This is the directory containing the actual index of the registry. `$hostname` comes from its url, and `$hash` is the hash of the entire url. * `.cargo/registry/cache/$hostname-$hash/$pkg-$vers.tar.gz` - This is a directory used to cache the downloads of packages from the registry. * `.cargo/registry/src/$hostname-$hash/$pkg-$vers` - This is the location of the unpacked packages. They will be compiled from this location. # New Dependencies Cargo has picked up a new dependency on the `curl-rust` package in order to send HTTP requests to the registry as well as send HTTP requests to download tarballs.
2014-07-18 15:40:45 +00:00
let p = project("foo")
.file("Cargo.toml", r#"
[project]
name = "foo"
version = "0.5.0"
authors = ["wycats@example.com"]
Implement a registry source # cargo upload The cargo-upload command will take the local package and upload it to the specified registry. The local package is uploaded as a tarball compressed with gzip under maximum compression. Most of this is done by just delegating to `cargo package` The host to upload to is specified, in order of priority, by a command line `--host` flag, the `registry.host` config key, and then the default registry. The default registry is still `example.com` The registry itself is still a work in progress, but the general plumbing for a command such as this would look like: 1. Ensure the local package has been compressed into an archive. 2. Fetch the relevant registry and login token from config files. 3. Ensure all dependencies for a package are listed as coming from the same registry. 4. Upload the archive to the registry with the login token. 5. The registry will verify the package is under 2MB (configurable). 6. The registry will upload the archive to S3, calculating a checksum in the process. 7. The registry will add an entry to the registry's index (a git repository). The entry will include the name of the package, the version uploaded, the checksum of the upload, and then the list of dependencies (name/version req) 8. The local `cargo upload` command will succeed. # cargo login Uploading requires a token from the api server, and this token follows the same config chain for the host except that there is no fallback. To implement login, the `cargo login` command is used. With 0 arguments, the command will request that a site be visited for a login token, and with an argument it will set the argument as the new login token. The `util::config` module was modified to allow writing configuration as well as reading it. The support is a little lacking in that comments are blown away, but the support is there at least. # RegistrySource An implementation of `RegistrySource` has been created (deleting the old `DummyRegistrySource`). This implementation only needs a URL to be constructed, and it is assumed that the URL is running an instance of the cargo registry. ## RegistrySource::update Currently this will unconditionally update the registry's index (a git repository). Tuning is necessary to prevent updating the index each time (more coming soon). ## RegistrySource::query This is called in the resolve phase of cargo. This function is given a dependency to query for, and the source will simply look into the index to see if any package with the name is present. If found, the package's index file will be loaded and parsed into a list of summaries. The main optimization of this function is to not require the entire registry to ever be resident in memory. Instead, only necessary packages are loaded into memory and parsed. ## RegistrySource::download This is also called during the resolve phase of cargo, but only when a package has been selected to be built (actually resolved). This phase of the source will actually download and unpack the tarball for the package. Currently a configuration file is located in the root of a registry's index describing the root url to download packages from. This function is optimized for two different metrics: 1. If a tarball is downloaded, it is not downloaded again. It is assumed that once a tarball is successfully downloaded it will never change. 2. If the unpacking destination has a `.cargo-ok` file, it is assumed that the unpacking has already occurred and does not need to happen again. With these in place, a rebuild should take almost no time at all. ## RegistrySource::get This function is simply implemented in terms of a PathSource's `get` function by creating a `PathSource` for all unpacked tarballs as part of the `download` stage. ## Filesystem layout There are a few new directories as part of the `.cargo` home folder: * `.cargo/registry/index/$hostname-$hash` - This is the directory containing the actual index of the registry. `$hostname` comes from its url, and `$hash` is the hash of the entire url. * `.cargo/registry/cache/$hostname-$hash/$pkg-$vers.tar.gz` - This is a directory used to cache the downloads of packages from the registry. * `.cargo/registry/src/$hostname-$hash/$pkg-$vers` - This is the location of the unpacked packages. They will be compiled from this location. # New Dependencies Cargo has picked up a new dependency on the `curl-rust` package in order to send HTTP requests to the registry as well as send HTTP requests to download tarballs.
2014-07-18 15:40:45 +00:00
[dependencies.bar]
path = "bar"
version = "0.5.0"
[[bin]]
name = "foo"
"#)
.file("src/foo.rs",
2015-03-26 18:17:44 +00:00
&main_file(r#""{}", bar::gimme()"#, &["bar"]))
.file("bar/Cargo.toml", r#"
[project]
name = "bar"
version = "0.5.0"
authors = ["wycats@example.com"]
[dependencies.baz]
Implement a registry source # cargo upload The cargo-upload command will take the local package and upload it to the specified registry. The local package is uploaded as a tarball compressed with gzip under maximum compression. Most of this is done by just delegating to `cargo package` The host to upload to is specified, in order of priority, by a command line `--host` flag, the `registry.host` config key, and then the default registry. The default registry is still `example.com` The registry itself is still a work in progress, but the general plumbing for a command such as this would look like: 1. Ensure the local package has been compressed into an archive. 2. Fetch the relevant registry and login token from config files. 3. Ensure all dependencies for a package are listed as coming from the same registry. 4. Upload the archive to the registry with the login token. 5. The registry will verify the package is under 2MB (configurable). 6. The registry will upload the archive to S3, calculating a checksum in the process. 7. The registry will add an entry to the registry's index (a git repository). The entry will include the name of the package, the version uploaded, the checksum of the upload, and then the list of dependencies (name/version req) 8. The local `cargo upload` command will succeed. # cargo login Uploading requires a token from the api server, and this token follows the same config chain for the host except that there is no fallback. To implement login, the `cargo login` command is used. With 0 arguments, the command will request that a site be visited for a login token, and with an argument it will set the argument as the new login token. The `util::config` module was modified to allow writing configuration as well as reading it. The support is a little lacking in that comments are blown away, but the support is there at least. # RegistrySource An implementation of `RegistrySource` has been created (deleting the old `DummyRegistrySource`). This implementation only needs a URL to be constructed, and it is assumed that the URL is running an instance of the cargo registry. ## RegistrySource::update Currently this will unconditionally update the registry's index (a git repository). Tuning is necessary to prevent updating the index each time (more coming soon). ## RegistrySource::query This is called in the resolve phase of cargo. This function is given a dependency to query for, and the source will simply look into the index to see if any package with the name is present. If found, the package's index file will be loaded and parsed into a list of summaries. The main optimization of this function is to not require the entire registry to ever be resident in memory. Instead, only necessary packages are loaded into memory and parsed. ## RegistrySource::download This is also called during the resolve phase of cargo, but only when a package has been selected to be built (actually resolved). This phase of the source will actually download and unpack the tarball for the package. Currently a configuration file is located in the root of a registry's index describing the root url to download packages from. This function is optimized for two different metrics: 1. If a tarball is downloaded, it is not downloaded again. It is assumed that once a tarball is successfully downloaded it will never change. 2. If the unpacking destination has a `.cargo-ok` file, it is assumed that the unpacking has already occurred and does not need to happen again. With these in place, a rebuild should take almost no time at all. ## RegistrySource::get This function is simply implemented in terms of a PathSource's `get` function by creating a `PathSource` for all unpacked tarballs as part of the `download` stage. ## Filesystem layout There are a few new directories as part of the `.cargo` home folder: * `.cargo/registry/index/$hostname-$hash` - This is the directory containing the actual index of the registry. `$hostname` comes from its url, and `$hash` is the hash of the entire url. * `.cargo/registry/cache/$hostname-$hash/$pkg-$vers.tar.gz` - This is a directory used to cache the downloads of packages from the registry. * `.cargo/registry/src/$hostname-$hash/$pkg-$vers` - This is the location of the unpacked packages. They will be compiled from this location. # New Dependencies Cargo has picked up a new dependency on the `curl-rust` package in order to send HTTP requests to the registry as well as send HTTP requests to download tarballs.
2014-07-18 15:40:45 +00:00
path = "../baz"
version = "0.5.0"
2014-08-14 06:08:02 +00:00
[lib]
name = "bar"
"#)
.file("bar/src/bar.rs", r#"
extern crate baz;
pub fn gimme() -> String {
baz::gimme()
}
"#)
.file("baz/Cargo.toml", r#"
[project]
name = "baz"
version = "0.5.0"
authors = ["wycats@example.com"]
2014-08-14 06:08:02 +00:00
[lib]
name = "baz"
"#)
.file("baz/src/baz.rs", r#"
pub fn gimme() -> String {
"test passed".to_string()
}
"#);
assert_that(p.cargo_process("build"), execs());
assert_that(&p.bin("foo"), existing_file());
2015-10-28 09:20:00 +00:00
assert_that(process(&p.bin("foo")),
execs().with_stdout("test passed\n"));
}
// Check that Cargo gives a sensible error if a dependency can't be found
// because of a name mismatch.
#[test]
fn cargo_compile_with_dep_name_mismatch() {
let p = project("foo")
.file("Cargo.toml", r#"
[package]
name = "foo"
version = "0.0.1"
authors = ["wycats@example.com"]
[[bin]]
name = "foo"
[dependencies.notquitebar]
path = "bar"
"#)
2015-03-26 18:17:44 +00:00
.file("src/foo.rs", &main_file(r#""i am foo""#, &["bar"]))
.file("bar/Cargo.toml", &basic_bin_manifest("bar"))
.file("bar/src/bar.rs", &main_file(r#""i am bar""#, &[]));
assert_that(p.cargo_process("build"),
2015-03-26 18:17:44 +00:00
execs().with_status(101).with_stderr(&format!(
r#"[ERROR] no matching package named `notquitebar` found (required by `foo`)
location searched: {proj_dir}/bar
version required: *
"#, proj_dir = p.url())));
}
#[test]
fn cargo_compile_with_filename() {
let p = project("foo")
.file("Cargo.toml", r#"
[project]
name = "foo"
version = "0.0.1"
authors = []
"#)
.file("src/lib.rs", "")
.file("src/bin/a.rs", r#"
extern crate foo;
fn main() { println!("hello a.rs"); }
"#)
.file("examples/a.rs", r#"
fn main() { println!("example"); }
"#);
assert_that(p.cargo_process("build").arg("--bin").arg("bin.rs"),
2016-05-12 17:06:36 +00:00
execs().with_status(101).with_stderr("\
[ERROR] no bin target named `bin.rs`"));
assert_that(p.cargo_process("build").arg("--bin").arg("a.rs"),
2016-05-12 17:06:36 +00:00
execs().with_status(101).with_stderr("\
[ERROR] no bin target named `a.rs`
2016-05-12 17:06:36 +00:00
Did you mean `a`?"));
assert_that(p.cargo_process("build").arg("--example").arg("example.rs"),
2016-05-12 17:06:36 +00:00
execs().with_status(101).with_stderr("\
[ERROR] no example target named `example.rs`"));
assert_that(p.cargo_process("build").arg("--example").arg("a.rs"),
2016-05-12 17:06:36 +00:00
execs().with_status(101).with_stderr("\
[ERROR] no example target named `a.rs`
2016-05-12 17:06:36 +00:00
Did you mean `a`?"));
}
#[test]
fn compile_path_dep_then_change_version() {
let p = project("foo")
.file("Cargo.toml", r#"
[package]
name = "foo"
version = "0.0.1"
authors = []
[dependencies.bar]
path = "bar"
"#)
.file("src/lib.rs", "")
.file("bar/Cargo.toml", r#"
[package]
name = "bar"
version = "0.0.1"
authors = []
"#)
.file("bar/src/lib.rs", "");
assert_that(p.cargo_process("build"), execs().with_status(0));
File::create(&p.root().join("bar/Cargo.toml")).unwrap().write_all(br#"
[package]
name = "bar"
version = "0.0.2"
authors = []
"#).unwrap();
assert_that(p.cargo("build"),
2016-05-12 17:06:36 +00:00
execs().with_status(101).with_stderr("\
[ERROR] no matching package named `bar` found (required by `foo`)
location searched: [..]
version required: = 0.0.1
versions found: 0.0.2
consider running `cargo update` to update a path dependency's locked version
2016-05-12 17:06:36 +00:00
"));
}
#[test]
fn ignores_carriage_return_in_lockfile() {
let p = project("foo")
.file("Cargo.toml", r#"
[package]
name = "foo"
authors = []
version = "0.0.1"
"#)
.file("src/main.rs", r#"
mod a; fn main() {}
"#)
.file("src/a.rs", "");
assert_that(p.cargo_process("build"),
execs().with_status(0));
let lockfile = p.root().join("Cargo.lock");
let mut lock = String::new();
File::open(&lockfile).unwrap().read_to_string(&mut lock).unwrap();
let lock = lock.replace("\n", "\r\n");
File::create(&lockfile).unwrap().write_all(lock.as_bytes()).unwrap();
assert_that(p.cargo("build"),
execs().with_status(0));
}
#[test]
fn crate_env_vars() {
2014-07-24 00:57:49 +00:00
let p = project("foo")
.file("Cargo.toml", r#"
[project]
name = "foo"
version = "0.5.1-alpha.1"
description = "This is foo"
homepage = "http://example.com"
authors = ["wycats@example.com"]
2014-07-24 00:57:49 +00:00
"#)
.file("src/main.rs", r#"
extern crate foo;
2014-07-24 00:57:49 +00:00
static VERSION_MAJOR: &'static str = env!("CARGO_PKG_VERSION_MAJOR");
static VERSION_MINOR: &'static str = env!("CARGO_PKG_VERSION_MINOR");
static VERSION_PATCH: &'static str = env!("CARGO_PKG_VERSION_PATCH");
static VERSION_PRE: &'static str = env!("CARGO_PKG_VERSION_PRE");
static VERSION: &'static str = env!("CARGO_PKG_VERSION");
static CARGO_MANIFEST_DIR: &'static str = env!("CARGO_MANIFEST_DIR");
static PKG_NAME: &'static str = env!("CARGO_PKG_NAME");
static HOMEPAGE: &'static str = env!("CARGO_PKG_HOMEPAGE");
static DESCRIPTION: &'static str = env!("CARGO_PKG_DESCRIPTION");
2014-07-24 00:57:49 +00:00
fn main() {
let s = format!("{}-{}-{} @ {} in {}", VERSION_MAJOR,
VERSION_MINOR, VERSION_PATCH, VERSION_PRE,
CARGO_MANIFEST_DIR);
assert_eq!(s, foo::version());
println!("{}", s);
assert_eq!("foo", PKG_NAME);
assert_eq!("http://example.com", HOMEPAGE);
assert_eq!("This is foo", DESCRIPTION);
assert_eq!(s, VERSION);
}
"#)
.file("src/lib.rs", r#"
pub fn version() -> String {
format!("{}-{}-{} @ {} in {}",
env!("CARGO_PKG_VERSION_MAJOR"),
env!("CARGO_PKG_VERSION_MINOR"),
env!("CARGO_PKG_VERSION_PATCH"),
env!("CARGO_PKG_VERSION_PRE"),
env!("CARGO_MANIFEST_DIR"))
2014-07-24 00:57:49 +00:00
}
"#);
Overhaul how cargo treats profiles This commit is a complete overhaul of how Cargo handles compilation profiles internally. The external interface of Cargo is not affected by this change. Previously each Target had a Profile embedded within it. Conceptually a Target is an entry in the manifest (a binary, benchmark, etc) and a Profile controlled various flags (e.g. --test, -C opt-level, etc). Each Package then contained many profiles for each possible compilation mode. For example a Package would have one target for testing a library, benchmarking a library, documenting a library, etc. When it came to building these targets, Cargo would filter out the targets listed to determine what needed to be built. This filtering was largely done based off an "environment" represented as a string. Each mode of compilation got a separate environment string like `"test"` or `"bench"`. Altogether, however, this approach had a number of drawbacks: * Examples in release mode do not currently work. This is due to how examples are classified and how release mode is handled (e.g. the "release" environment where examples are meant to be built in the "test" environment). * It is not trivial to implement `cargo test --release` today. * It is not trivial to implement `cargo build --bin foo` where *only* the binary `foo` is built. The same is true for examples. * It is not trivial to add selective building of a number of binaries/examples/etc. * Filtering the list of targets to build has some pretty hokey logic that involves pseudo-environments like "doc-all" vs "doc". This logic is duplicated in a few places and in general is quite brittle. * The TOML parser greatly affects compilation due to the time at which profiles are generated, which seems somewhat backwards. * Profiles must be overridden, but only partially, at compile time becuase only the top-level package's profile is applied. In general, this system just needed an overhaul. This commit made a single change of separating `Profile` from `Target` and then basically hit `make` until all the tests passed again. The other large architectural changes are: * Environment strings are now entirely gone. * Filters are implemented in a much more robust fashion. * Release mode is now handled much more gracefully. * The unit of compilation in the backend is no longer (package, target) but rather (package, target, profile). This change had to be propagated many location in the `cargo_rustc` module. * The backend does not filter targets to build *at all*. All filtering now happens entirely in the frontend. I'll test issues after this change lands, but the motivation behind this is to open the door to quickly fixing a number of outstanding issues against Cargo. This change itself is not intended to close many bugs.
2015-02-19 19:30:35 +00:00
println!("build");
assert_that(p.cargo_process("build").arg("-v"), execs().with_status(0));
2014-07-24 00:57:49 +00:00
Overhaul how cargo treats profiles This commit is a complete overhaul of how Cargo handles compilation profiles internally. The external interface of Cargo is not affected by this change. Previously each Target had a Profile embedded within it. Conceptually a Target is an entry in the manifest (a binary, benchmark, etc) and a Profile controlled various flags (e.g. --test, -C opt-level, etc). Each Package then contained many profiles for each possible compilation mode. For example a Package would have one target for testing a library, benchmarking a library, documenting a library, etc. When it came to building these targets, Cargo would filter out the targets listed to determine what needed to be built. This filtering was largely done based off an "environment" represented as a string. Each mode of compilation got a separate environment string like `"test"` or `"bench"`. Altogether, however, this approach had a number of drawbacks: * Examples in release mode do not currently work. This is due to how examples are classified and how release mode is handled (e.g. the "release" environment where examples are meant to be built in the "test" environment). * It is not trivial to implement `cargo test --release` today. * It is not trivial to implement `cargo build --bin foo` where *only* the binary `foo` is built. The same is true for examples. * It is not trivial to add selective building of a number of binaries/examples/etc. * Filtering the list of targets to build has some pretty hokey logic that involves pseudo-environments like "doc-all" vs "doc". This logic is duplicated in a few places and in general is quite brittle. * The TOML parser greatly affects compilation due to the time at which profiles are generated, which seems somewhat backwards. * Profiles must be overridden, but only partially, at compile time becuase only the top-level package's profile is applied. In general, this system just needed an overhaul. This commit made a single change of separating `Profile` from `Target` and then basically hit `make` until all the tests passed again. The other large architectural changes are: * Environment strings are now entirely gone. * Filters are implemented in a much more robust fashion. * Release mode is now handled much more gracefully. * The unit of compilation in the backend is no longer (package, target) but rather (package, target, profile). This change had to be propagated many location in the `cargo_rustc` module. * The backend does not filter targets to build *at all*. All filtering now happens entirely in the frontend. I'll test issues after this change lands, but the motivation behind this is to open the door to quickly fixing a number of outstanding issues against Cargo. This change itself is not intended to close many bugs.
2015-02-19 19:30:35 +00:00
println!("bin");
2015-10-28 09:20:00 +00:00
assert_that(process(&p.bin("foo")),
2015-03-26 18:17:44 +00:00
execs().with_stdout(&format!("0-5-1 @ alpha.1 in {}\n",
p.root().display())));
Overhaul how cargo treats profiles This commit is a complete overhaul of how Cargo handles compilation profiles internally. The external interface of Cargo is not affected by this change. Previously each Target had a Profile embedded within it. Conceptually a Target is an entry in the manifest (a binary, benchmark, etc) and a Profile controlled various flags (e.g. --test, -C opt-level, etc). Each Package then contained many profiles for each possible compilation mode. For example a Package would have one target for testing a library, benchmarking a library, documenting a library, etc. When it came to building these targets, Cargo would filter out the targets listed to determine what needed to be built. This filtering was largely done based off an "environment" represented as a string. Each mode of compilation got a separate environment string like `"test"` or `"bench"`. Altogether, however, this approach had a number of drawbacks: * Examples in release mode do not currently work. This is due to how examples are classified and how release mode is handled (e.g. the "release" environment where examples are meant to be built in the "test" environment). * It is not trivial to implement `cargo test --release` today. * It is not trivial to implement `cargo build --bin foo` where *only* the binary `foo` is built. The same is true for examples. * It is not trivial to add selective building of a number of binaries/examples/etc. * Filtering the list of targets to build has some pretty hokey logic that involves pseudo-environments like "doc-all" vs "doc". This logic is duplicated in a few places and in general is quite brittle. * The TOML parser greatly affects compilation due to the time at which profiles are generated, which seems somewhat backwards. * Profiles must be overridden, but only partially, at compile time becuase only the top-level package's profile is applied. In general, this system just needed an overhaul. This commit made a single change of separating `Profile` from `Target` and then basically hit `make` until all the tests passed again. The other large architectural changes are: * Environment strings are now entirely gone. * Filters are implemented in a much more robust fashion. * Release mode is now handled much more gracefully. * The unit of compilation in the backend is no longer (package, target) but rather (package, target, profile). This change had to be propagated many location in the `cargo_rustc` module. * The backend does not filter targets to build *at all*. All filtering now happens entirely in the frontend. I'll test issues after this change lands, but the motivation behind this is to open the door to quickly fixing a number of outstanding issues against Cargo. This change itself is not intended to close many bugs.
2015-02-19 19:30:35 +00:00
println!("test");
assert_that(p.cargo("test").arg("-v"),
execs().with_status(0));
}
2014-07-24 00:57:49 +00:00
#[test]
fn crate_authors_env_vars() {
let p = project("foo")
.file("Cargo.toml", r#"
[project]
name = "foo"
version = "0.5.1-alpha.1"
authors = ["wycats@example.com", "neikos@example.com"]
"#)
.file("src/main.rs", r#"
extern crate foo;
static AUTHORS: &'static str = env!("CARGO_PKG_AUTHORS");
fn main() {
let s = "wycats@example.com:neikos@example.com";
assert_eq!(AUTHORS, foo::authors());
println!("{}", AUTHORS);
assert_eq!(s, AUTHORS);
}
"#)
.file("src/lib.rs", r#"
pub fn authors() -> String {
format!("{}", env!("CARGO_PKG_AUTHORS"))
}
"#);
println!("build");
assert_that(p.cargo_process("build").arg("-v"), execs().with_status(0));
println!("bin");
assert_that(process(&p.bin("foo")),
2016-05-12 17:06:36 +00:00
execs().with_stdout("wycats@example.com:neikos@example.com"));
println!("test");
assert_that(p.cargo("test").arg("-v"),
execs().with_status(0));
}
2014-07-08 00:59:18 +00:00
// this is testing that src/<pkg-name>.rs still works (for now)
#[test]
fn many_crate_types_old_style_lib_location() {
let mut p = project("foo");
p = p
.file("Cargo.toml", r#"
[project]
name = "foo"
version = "0.5.0"
authors = ["wycats@example.com"]
2014-08-14 06:08:02 +00:00
[lib]
name = "foo"
crate_type = ["rlib", "dylib"]
"#)
.file("src/foo.rs", r#"
pub fn foo() {}
"#);
assert_that(p.cargo_process("build"), execs().with_status(0));
assert_that(&p.root().join("target/debug/libfoo.rlib"), existing_file());
let fname = format!("{}foo{}", env::consts::DLL_PREFIX,
env::consts::DLL_SUFFIX);
assert_that(&p.root().join("target/debug").join(&fname), existing_file());
}
2014-07-08 00:59:18 +00:00
#[test]
fn many_crate_types_correct() {
2014-07-08 00:59:18 +00:00
let mut p = project("foo");
p = p
.file("Cargo.toml", r#"
[project]
name = "foo"
version = "0.5.0"
authors = ["wycats@example.com"]
2014-08-14 06:08:02 +00:00
[lib]
2014-07-08 00:59:18 +00:00
name = "foo"
crate_type = ["rlib", "dylib"]
"#)
.file("src/lib.rs", r#"
pub fn foo() {}
"#);
assert_that(p.cargo_process("build"),
2014-07-08 00:59:18 +00:00
execs().with_status(0));
assert_that(&p.root().join("target/debug/libfoo.rlib"), existing_file());
let fname = format!("{}foo{}", env::consts::DLL_PREFIX,
env::consts::DLL_SUFFIX);
assert_that(&p.root().join("target/debug").join(&fname), existing_file());
}
2014-06-27 05:53:05 +00:00
#[test]
fn unused_keys() {
2014-06-27 05:53:05 +00:00
let mut p = project("foo");
p = p
.file("Cargo.toml", r#"
[project]
name = "foo"
version = "0.5.0"
authors = ["wycats@example.com"]
bulid = "foo"
2014-08-14 06:08:02 +00:00
[lib]
2014-06-27 05:53:05 +00:00
name = "foo"
"#)
.file("src/foo.rs", r#"
pub fn foo() {}
"#);
assert_that(p.cargo_process("build"),
2014-06-27 05:53:05 +00:00
execs().with_status(0)
.with_stderr("\
warning: unused manifest key: project.bulid
2016-05-20 13:22:58 +00:00
[COMPILING] foo [..]
[FINISHED] debug [unoptimized + debuginfo] target(s) in [..]
"));
2014-06-27 05:53:05 +00:00
let mut p = project("bar");
p = p
.file("Cargo.toml", r#"
[project]
name = "foo"
version = "0.5.0"
authors = ["wycats@example.com"]
2014-08-14 06:08:02 +00:00
[lib]
2014-06-27 05:53:05 +00:00
name = "foo"
build = "foo"
"#)
.file("src/foo.rs", r#"
pub fn foo() {}
"#);
assert_that(p.cargo_process("build"),
2014-06-27 05:53:05 +00:00
execs().with_status(0)
.with_stderr("\
warning: unused manifest key: lib.build
2016-05-20 13:22:58 +00:00
[COMPILING] foo [..]
[FINISHED] debug [unoptimized + debuginfo] target(s) in [..]
"));
}
#[test]
fn self_dependency() {
let mut p = project("foo");
p = p
.file("Cargo.toml", r#"
[package]
name = "test"
version = "0.0.0"
authors = []
[dependencies.test]
path = "."
2014-08-14 06:08:02 +00:00
[lib]
name = "test"
"#)
.file("src/test.rs", "fn main() {}");
assert_that(p.cargo_process("build"),
execs().with_status(101)
2016-05-12 17:06:36 +00:00
.with_stderr("\
[ERROR] cyclic package dependency: package `test v0.0.0 ([..])` depends on itself
2016-05-12 17:06:36 +00:00
"));
}
#[test]
fn ignore_broken_symlinks() {
2014-12-21 18:45:39 +00:00
// windows and symlinks don't currently agree that well
if cfg!(windows) { return }
let p = project("foo")
2015-03-26 18:17:44 +00:00
.file("Cargo.toml", &basic_bin_manifest("foo"))
.file("src/foo.rs", &main_file(r#""i am foo""#, &[]))
.symlink("Notafile", "bar");
assert_that(p.cargo_process("build"), execs());
assert_that(&p.bin("foo"), existing_file());
2015-10-28 09:20:00 +00:00
assert_that(process(&p.bin("foo")),
execs().with_stdout("i am foo\n"));
}
#[test]
fn missing_lib_and_bin() {
let mut p = project("foo");
p = p
.file("Cargo.toml", r#"
[package]
name = "test"
version = "0.0.0"
authors = []
"#);
assert_that(p.cargo_process("build"),
execs().with_status(101)
2016-05-12 17:06:36 +00:00
.with_stderr("\
[ERROR] failed to parse manifest at `[..]Cargo.toml`
Caused by:
no targets specified in the manifest
2016-05-12 17:06:36 +00:00
either src/lib.rs, src/main.rs, a [lib] section, or [[bin]] section must be present\n"));
}
#[test]
fn lto_build() {
// FIXME: currently this hits a linker bug on 32-bit MSVC
if cfg!(all(target_env = "msvc", target_pointer_width = "32")) {
return
}
let mut p = project("foo");
p = p
.file("Cargo.toml", r#"
[package]
name = "test"
version = "0.0.0"
authors = []
2014-11-14 16:49:01 +00:00
[profile.release]
lto = true
"#)
.file("src/main.rs", "fn main() {}");
2014-11-14 16:49:01 +00:00
assert_that(p.cargo_process("build").arg("-v").arg("--release"),
2016-05-15 21:26:24 +00:00
execs().with_status(0).with_stderr(&format!("\
[COMPILING] test v0.0.0 ({url})
[RUNNING] `rustc src[..]main.rs --crate-name test --crate-type bin \
2014-12-21 18:45:39 +00:00
-C opt-level=3 \
-C lto \
--out-dir {dir}[..]target[..]release \
2014-12-21 18:45:39 +00:00
--emit=dep-info,link \
-L dependency={dir}[..]target[..]release[..]deps`
[FINISHED] release [optimized] target(s) in [..]
",
dir = p.root().display(),
url = p.url(),
)));
}
#[test]
fn verbose_build() {
let mut p = project("foo");
p = p
.file("Cargo.toml", r#"
[package]
name = "test"
version = "0.0.0"
authors = []
"#)
.file("src/lib.rs", "");
assert_that(p.cargo_process("build").arg("-v"),
2016-05-15 21:26:24 +00:00
execs().with_status(0).with_stderr(&format!("\
[COMPILING] test v0.0.0 ({url})
[RUNNING] `rustc src[..]lib.rs --crate-name test --crate-type lib -g \
--out-dir [..] \
2014-12-21 18:45:39 +00:00
--emit=dep-info,link \
-L dependency={dir}[..]target[..]debug[..]deps`
[FINISHED] debug [unoptimized + debuginfo] target(s) in [..]
",
dir = p.root().display(),
url = p.url(),
)));
}
#[test]
fn verbose_release_build() {
let mut p = project("foo");
p = p
.file("Cargo.toml", r#"
[package]
name = "test"
version = "0.0.0"
authors = []
"#)
.file("src/lib.rs", "");
assert_that(p.cargo_process("build").arg("-v").arg("--release"),
2016-05-15 21:26:24 +00:00
execs().with_status(0).with_stderr(&format!("\
[COMPILING] test v0.0.0 ({url})
[RUNNING] `rustc src[..]lib.rs --crate-name test --crate-type lib \
2014-12-21 18:45:39 +00:00
-C opt-level=3 \
--out-dir [..] \
2014-12-21 18:45:39 +00:00
--emit=dep-info,link \
-L dependency={dir}[..]target[..]release[..]deps`
[FINISHED] release [optimized] target(s) in [..]
",
dir = p.root().display(),
url = p.url(),
)));
}
#[test]
fn verbose_release_build_deps() {
let mut p = project("foo");
p = p
.file("Cargo.toml", r#"
[package]
name = "test"
version = "0.0.0"
authors = []
[dependencies.foo]
path = "foo"
"#)
.file("src/lib.rs", "")
.file("foo/Cargo.toml", r#"
[package]
name = "foo"
version = "0.0.0"
authors = []
2014-08-14 06:08:02 +00:00
[lib]
name = "foo"
crate_type = ["dylib", "rlib"]
"#)
.file("foo/src/lib.rs", "");
assert_that(p.cargo_process("build").arg("-v").arg("--release"),
2016-05-15 21:26:24 +00:00
execs().with_status(0).with_stderr(&format!("\
[COMPILING] foo v0.0.0 ({url}/foo)
[RUNNING] `rustc foo[..]src[..]lib.rs --crate-name foo \
--crate-type dylib --crate-type rlib -C prefer-dynamic \
2014-12-21 18:45:39 +00:00
-C opt-level=3 \
--out-dir [..] \
2014-12-21 18:45:39 +00:00
--emit=dep-info,link \
-L dependency={dir}[..]target[..]release[..]deps`
[COMPILING] test v0.0.0 ({url})
[RUNNING] `rustc src[..]lib.rs --crate-name test --crate-type lib \
2014-12-21 18:45:39 +00:00
-C opt-level=3 \
--out-dir [..] \
2014-12-21 18:45:39 +00:00
--emit=dep-info,link \
-L dependency={dir}[..]target[..]release[..]deps \
--extern foo={dir}[..]target[..]release[..]deps[..]\
{prefix}foo{suffix} \
--extern foo={dir}[..]target[..]release[..]deps[..]libfoo.rlib`
[FINISHED] release [optimized] target(s) in [..]
",
dir = p.root().display(),
url = p.url(),
2015-02-06 07:27:53 +00:00
prefix = env::consts::DLL_PREFIX,
2015-03-26 18:17:44 +00:00
suffix = env::consts::DLL_SUFFIX)));
}
2014-07-10 22:13:53 +00:00
#[test]
fn explicit_examples() {
2014-07-10 22:13:53 +00:00
let mut p = project("world");
p = p.file("Cargo.toml", r#"
[package]
name = "world"
version = "1.0.0"
authors = []
2014-08-14 06:08:02 +00:00
[lib]
2014-07-10 22:13:53 +00:00
name = "world"
path = "src/lib.rs"
[[example]]
name = "hello"
path = "examples/ex-hello.rs"
[[example]]
name = "goodbye"
path = "examples/ex-goodbye.rs"
"#)
.file("src/lib.rs", r#"
pub fn get_hello() -> &'static str { "Hello" }
pub fn get_goodbye() -> &'static str { "Goodbye" }
pub fn get_world() -> &'static str { "World" }
"#)
.file("examples/ex-hello.rs", r#"
extern crate world;
fn main() { println!("{}, {}!", world::get_hello(), world::get_world()); }
"#)
.file("examples/ex-goodbye.rs", r#"
extern crate world;
fn main() { println!("{}, {}!", world::get_goodbye(), world::get_world()); }
"#);
Overhaul how cargo treats profiles This commit is a complete overhaul of how Cargo handles compilation profiles internally. The external interface of Cargo is not affected by this change. Previously each Target had a Profile embedded within it. Conceptually a Target is an entry in the manifest (a binary, benchmark, etc) and a Profile controlled various flags (e.g. --test, -C opt-level, etc). Each Package then contained many profiles for each possible compilation mode. For example a Package would have one target for testing a library, benchmarking a library, documenting a library, etc. When it came to building these targets, Cargo would filter out the targets listed to determine what needed to be built. This filtering was largely done based off an "environment" represented as a string. Each mode of compilation got a separate environment string like `"test"` or `"bench"`. Altogether, however, this approach had a number of drawbacks: * Examples in release mode do not currently work. This is due to how examples are classified and how release mode is handled (e.g. the "release" environment where examples are meant to be built in the "test" environment). * It is not trivial to implement `cargo test --release` today. * It is not trivial to implement `cargo build --bin foo` where *only* the binary `foo` is built. The same is true for examples. * It is not trivial to add selective building of a number of binaries/examples/etc. * Filtering the list of targets to build has some pretty hokey logic that involves pseudo-environments like "doc-all" vs "doc". This logic is duplicated in a few places and in general is quite brittle. * The TOML parser greatly affects compilation due to the time at which profiles are generated, which seems somewhat backwards. * Profiles must be overridden, but only partially, at compile time becuase only the top-level package's profile is applied. In general, this system just needed an overhaul. This commit made a single change of separating `Profile` from `Target` and then basically hit `make` until all the tests passed again. The other large architectural changes are: * Environment strings are now entirely gone. * Filters are implemented in a much more robust fashion. * Release mode is now handled much more gracefully. * The unit of compilation in the backend is no longer (package, target) but rather (package, target, profile). This change had to be propagated many location in the `cargo_rustc` module. * The backend does not filter targets to build *at all*. All filtering now happens entirely in the frontend. I'll test issues after this change lands, but the motivation behind this is to open the door to quickly fixing a number of outstanding issues against Cargo. This change itself is not intended to close many bugs.
2015-02-19 19:30:35 +00:00
assert_that(p.cargo_process("test").arg("-v"), execs().with_status(0));
2015-10-28 09:20:00 +00:00
assert_that(process(&p.bin("examples/hello")),
execs().with_stdout("Hello, World!\n"));
2015-10-28 09:20:00 +00:00
assert_that(process(&p.bin("examples/goodbye")),
execs().with_stdout("Goodbye, World!\n"));
}
2014-07-10 22:13:53 +00:00
#[test]
fn implicit_examples() {
2014-07-10 22:13:53 +00:00
let mut p = project("world");
p = p.file("Cargo.toml", r#"
[package]
name = "world"
version = "1.0.0"
authors = []
"#)
.file("src/lib.rs", r#"
pub fn get_hello() -> &'static str { "Hello" }
pub fn get_goodbye() -> &'static str { "Goodbye" }
pub fn get_world() -> &'static str { "World" }
"#)
.file("examples/hello.rs", r#"
extern crate world;
fn main() {
println!("{}, {}!", world::get_hello(), world::get_world());
}
2014-07-10 22:13:53 +00:00
"#)
.file("examples/goodbye.rs", r#"
extern crate world;
fn main() {
println!("{}, {}!", world::get_goodbye(), world::get_world());
}
2014-07-10 22:13:53 +00:00
"#);
assert_that(p.cargo_process("test"), execs().with_status(0));
2015-10-28 09:20:00 +00:00
assert_that(process(&p.bin("examples/hello")),
execs().with_stdout("Hello, World!\n"));
2015-10-28 09:20:00 +00:00
assert_that(process(&p.bin("examples/goodbye")),
execs().with_stdout("Goodbye, World!\n"));
}
#[test]
fn standard_build_no_ndebug() {
let p = project("world")
.file("Cargo.toml", &basic_bin_manifest("foo"))
.file("src/foo.rs", r#"
fn main() {
if cfg!(debug_assertions) {
println!("slow")
} else {
println!("fast")
}
}
"#);
assert_that(p.cargo_process("build"), execs().with_status(0));
2015-10-28 09:20:00 +00:00
assert_that(process(&p.bin("foo")),
execs().with_stdout("slow\n"));
}
#[test]
fn release_build_ndebug() {
let p = project("world")
.file("Cargo.toml", &basic_bin_manifest("foo"))
.file("src/foo.rs", r#"
fn main() {
if cfg!(debug_assertions) {
println!("slow")
} else {
println!("fast")
}
}
"#);
assert_that(p.cargo_process("build").arg("--release"),
execs().with_status(0));
2015-10-28 09:20:00 +00:00
assert_that(process(&p.release_bin("foo")),
execs().with_stdout("fast\n"));
}
#[test]
fn inferred_main_bin() {
let p = project("world")
.file("Cargo.toml", r#"
[project]
name = "foo"
version = "0.0.1"
authors = []
"#)
.file("src/main.rs", r#"
fn main() {}
"#);
assert_that(p.cargo_process("build"), execs().with_status(0));
2015-10-28 09:20:00 +00:00
assert_that(process(&p.bin("foo")), execs().with_status(0));
}
#[test]
fn deletion_causes_failure() {
let p = project("foo")
.file("Cargo.toml", r#"
[package]
name = "foo"
version = "0.0.1"
authors = []
[dependencies.bar]
path = "bar"
"#)
.file("src/main.rs", r#"
extern crate bar;
fn main() {}
"#)
.file("bar/Cargo.toml", r#"
[package]
name = "bar"
version = "0.0.1"
authors = []
"#)
.file("bar/src/lib.rs", "");
assert_that(p.cargo_process("build"), execs().with_status(0));
let p = p.file("Cargo.toml", r#"
[package]
name = "foo"
version = "0.0.1"
authors = []
"#);
assert_that(p.cargo_process("build"), execs().with_status(101));
}
#[test]
fn bad_cargo_toml_in_target_dir() {
let p = project("world")
.file("Cargo.toml", r#"
[project]
name = "foo"
version = "0.0.1"
authors = []
"#)
.file("src/main.rs", r#"
fn main() {}
"#)
.file("target/Cargo.toml", "bad-toml");
assert_that(p.cargo_process("build"), execs().with_status(0));
2015-10-28 09:20:00 +00:00
assert_that(process(&p.bin("foo")), execs().with_status(0));
}
#[test]
fn lib_with_standard_name() {
let p = project("foo")
.file("Cargo.toml", r#"
[package]
name = "syntax"
version = "0.0.1"
authors = []
"#)
.file("src/lib.rs", "
pub fn foo() {}
")
.file("src/main.rs", "
extern crate syntax;
fn main() { syntax::foo() }
");
assert_that(p.cargo_process("build"),
execs().with_status(0)
2016-05-14 21:44:18 +00:00
.with_stderr(&format!("\
[COMPILING] syntax v0.0.1 ({dir})
[FINISHED] debug [unoptimized + debuginfo] target(s) in [..]
",
2015-03-26 18:17:44 +00:00
dir = p.url())));
}
#[test]
fn simple_staticlib() {
let p = project("foo")
.file("Cargo.toml", r#"
[package]
name = "foo"
authors = []
version = "0.0.1"
2014-08-14 06:08:02 +00:00
[lib]
name = "foo"
crate-type = ["staticlib"]
"#)
.file("src/lib.rs", "pub fn foo() {}");
// env var is a test for #1381
assert_that(p.cargo_process("build").env("RUST_LOG", "nekoneko=trace"),
execs().with_status(0));
}
#[test]
fn staticlib_rlib_and_bin() {
let p = project("foo")
.file("Cargo.toml", r#"
[package]
name = "foo"
authors = []
version = "0.0.1"
[lib]
name = "foo"
crate-type = ["staticlib", "rlib"]
"#)
.file("src/lib.rs", "pub fn foo() {}")
.file("src/main.rs", r#"
extern crate foo;
fn main() {
foo::foo();
}"#);
assert_that(p.cargo_process("build").arg("-v"), execs().with_status(0));
}
#[test]
fn opt_out_of_bin() {
let p = project("foo")
.file("Cargo.toml", r#"
bin = []
[package]
name = "foo"
authors = []
version = "0.0.1"
"#)
.file("src/lib.rs", "")
.file("src/main.rs", "bad syntax");
assert_that(p.cargo_process("build"), execs().with_status(0));
}
#[test]
fn single_lib() {
let p = project("foo")
.file("Cargo.toml", r#"
[package]
name = "foo"
authors = []
version = "0.0.1"
[lib]
name = "foo"
path = "src/bar.rs"
"#)
.file("src/bar.rs", "");
assert_that(p.cargo_process("build"), execs().with_status(0));
}
2014-08-14 06:08:02 +00:00
#[test]
fn freshness_ignores_excluded() {
let foo = project("foo")
.file("Cargo.toml", r#"
[package]
name = "foo"
version = "0.0.0"
authors = []
build = "build.rs"
exclude = ["src/b*.rs"]
"#)
.file("build.rs", "fn main() {}")
2015-02-13 04:10:07 +00:00
.file("src/lib.rs", "pub fn bar() -> i32 { 1 }");
foo.build();
foo.root().move_into_the_past();
assert_that(foo.cargo("build"),
execs().with_status(0)
2016-05-14 21:44:18 +00:00
.with_stderr(&format!("\
[COMPILING] foo v0.0.0 ({url})
[FINISHED] debug [unoptimized + debuginfo] target(s) in [..]
", url = foo.url())));
// Smoke test to make sure it doesn't compile again
println!("first pass");
assert_that(foo.cargo("build"),
execs().with_status(0)
.with_stdout(""));
// Modify an ignored file and make sure we don't rebuild
println!("second pass");
File::create(&foo.root().join("src/bar.rs")).unwrap();
assert_that(foo.cargo("build"),
execs().with_status(0)
.with_stdout(""));
}
#[test]
fn rebuild_preserves_out_dir() {
let foo = project("foo")
.file("Cargo.toml", r#"
[package]
name = "foo"
version = "0.0.0"
authors = []
build = 'build.rs'
"#)
.file("build.rs", r#"
2015-02-06 07:27:53 +00:00
use std::env;
2015-03-26 18:17:44 +00:00
use std::fs::File;
use std::path::Path;
fn main() {
2015-03-26 18:17:44 +00:00
let path = Path::new(&env::var("OUT_DIR").unwrap()).join("foo");
2015-02-13 04:10:07 +00:00
if env::var_os("FIRST").is_some() {
File::create(&path).unwrap();
} else {
File::create(&path).unwrap();
}
}
"#)
2015-02-13 04:10:07 +00:00
.file("src/lib.rs", "pub fn bar() -> i32 { 1 }");
foo.build();
foo.root().move_into_the_past();
assert_that(foo.cargo("build").env("FIRST", "1"),
execs().with_status(0)
2016-05-14 21:44:18 +00:00
.with_stderr(&format!("\
[COMPILING] foo v0.0.0 ({url})
[FINISHED] debug [unoptimized + debuginfo] target(s) in [..]
", url = foo.url())));
File::create(&foo.root().join("src/bar.rs")).unwrap();
assert_that(foo.cargo("build"),
execs().with_status(0)
2016-05-14 21:44:18 +00:00
.with_stderr(&format!("\
[COMPILING] foo v0.0.0 ({url})
[FINISHED] debug [unoptimized + debuginfo] target(s) in [..]
", url = foo.url())));
}
2014-09-07 18:48:35 +00:00
#[test]
fn dep_no_libs() {
2014-09-07 18:48:35 +00:00
let foo = project("foo")
.file("Cargo.toml", r#"
[package]
name = "foo"
version = "0.0.0"
authors = []
[dependencies.bar]
path = "bar"
"#)
2015-02-13 04:10:07 +00:00
.file("src/lib.rs", "pub fn bar() -> i32 { 1 }")
2014-09-07 18:48:35 +00:00
.file("bar/Cargo.toml", r#"
[package]
name = "bar"
version = "0.0.0"
authors = []
"#)
.file("bar/src/main.rs", "");
assert_that(foo.cargo_process("build"),
execs().with_status(0));
}
#[test]
fn recompile_space_in_name() {
let foo = project("foo")
.file("Cargo.toml", r#"
[package]
name = "foo"
version = "0.0.0"
authors = []
[lib]
name = "foo"
path = "src/my lib.rs"
"#)
.file("src/my lib.rs", "");
assert_that(foo.cargo_process("build"), execs().with_status(0));
foo.root().move_into_the_past();
assert_that(foo.cargo("build"),
execs().with_status(0).with_stdout(""));
}
#[cfg(unix)]
#[test]
fn ignore_bad_directories() {
use std::os::unix::prelude::*;
let foo = project("foo")
.file("Cargo.toml", r#"
[package]
name = "foo"
version = "0.0.0"
authors = []
"#)
.file("src/lib.rs", "");
foo.build();
let dir = foo.root().join("tmp");
fs::create_dir(&dir).unwrap();
let stat = fs::metadata(&dir).unwrap();
let mut perms = stat.permissions();
perms.set_mode(0o644);
fs::set_permissions(&dir, perms.clone()).unwrap();
assert_that(foo.cargo("build"),
execs().with_status(0));
perms.set_mode(0o755);
fs::set_permissions(&dir, perms).unwrap();
}
#[test]
fn bad_cargo_config() {
let foo = project("foo")
.file("Cargo.toml", r#"
[package]
name = "foo"
version = "0.0.0"
authors = []
"#)
.file("src/lib.rs", "")
.file(".cargo/config", r#"
this is not valid toml
"#);
assert_that(foo.cargo_process("build").arg("-v"),
2016-05-12 17:06:36 +00:00
execs().with_status(101).with_stderr("\
[ERROR] Couldn't load Cargo configuration
Caused by:
could not parse TOML configuration in `[..]`
Caused by:
could not parse input as TOML
[..].cargo[..]config:2:20-2:21 expected `=`, but found `i`
2016-05-12 17:06:36 +00:00
"));
}
#[test]
fn cargo_platform_specific_dependency() {
let host = rustc_host();
let p = project("foo")
.file("Cargo.toml", &format!(r#"
[project]
name = "foo"
version = "0.5.0"
authors = ["wycats@example.com"]
build = "build.rs"
[target.{host}.dependencies]
dep = {{ path = "dep" }}
[target.{host}.build-dependencies]
build = {{ path = "build" }}
[target.{host}.dev-dependencies]
dev = {{ path = "dev" }}
"#, host = host))
.file("src/main.rs", r#"
extern crate dep;
fn main() { dep::dep() }
"#)
.file("tests/foo.rs", r#"
extern crate dev;
#[test]
fn foo() { dev::dev() }
"#)
.file("build.rs", r#"
extern crate build;
fn main() { build::build(); }
"#)
.file("dep/Cargo.toml", r#"
[project]
name = "dep"
version = "0.5.0"
authors = ["wycats@example.com"]
"#)
.file("dep/src/lib.rs", "pub fn dep() {}")
.file("build/Cargo.toml", r#"
[project]
name = "build"
version = "0.5.0"
authors = ["wycats@example.com"]
"#)
.file("build/src/lib.rs", "pub fn build() {}")
.file("dev/Cargo.toml", r#"
[project]
name = "dev"
version = "0.5.0"
authors = ["wycats@example.com"]
"#)
.file("dev/src/lib.rs", "pub fn dev() {}");
assert_that(p.cargo_process("build"),
execs().with_status(0));
assert_that(&p.bin("foo"), existing_file());
assert_that(p.cargo("test"),
execs().with_status(0));
}
#[test]
fn bad_platform_specific_dependency() {
let p = project("foo")
.file("Cargo.toml", r#"
[project]
name = "foo"
version = "0.5.0"
authors = ["wycats@example.com"]
[target.wrong-target.dependencies.bar]
path = "bar"
"#)
.file("src/main.rs",
2015-03-26 18:17:44 +00:00
&main_file(r#""{}", bar::gimme()"#, &["bar"]))
.file("bar/Cargo.toml", r#"
[project]
name = "bar"
version = "0.5.0"
authors = ["wycats@example.com"]
"#)
.file("bar/src/lib.rs", r#"
extern crate baz;
pub fn gimme() -> String {
format!("")
}
"#);
assert_that(p.cargo_process("build"),
execs().with_status(101));
}
#[test]
fn cargo_platform_specific_dependency_wrong_platform() {
let p = project("foo")
.file("Cargo.toml", r#"
[project]
name = "foo"
version = "0.5.0"
authors = ["wycats@example.com"]
[target.non-existing-triplet.dependencies.bar]
path = "bar"
"#)
.file("src/main.rs", r#"
fn main() {}
"#)
.file("bar/Cargo.toml", r#"
[project]
name = "bar"
version = "0.5.0"
authors = ["wycats@example.com"]
"#)
.file("bar/src/lib.rs", r#"
invalid rust file, should not be compiled
"#);
p.cargo_process("build").exec_with_output().unwrap();
assert_that(&p.bin("foo"), existing_file());
2015-10-28 09:20:00 +00:00
assert_that(process(&p.bin("foo")),
execs());
let loc = p.root().join("Cargo.lock");
let mut lockfile = String::new();
File::open(&loc).unwrap().read_to_string(&mut lockfile).unwrap();
assert!(lockfile.contains("bar"))
}
#[test]
fn example_bin_same_name() {
let p = project("foo")
.file("Cargo.toml", r#"
[package]
name = "foo"
version = "0.0.1"
authors = []
"#)
.file("src/main.rs", "fn main() {}")
.file("examples/foo.rs", "fn main() {}");
Overhaul how cargo treats profiles This commit is a complete overhaul of how Cargo handles compilation profiles internally. The external interface of Cargo is not affected by this change. Previously each Target had a Profile embedded within it. Conceptually a Target is an entry in the manifest (a binary, benchmark, etc) and a Profile controlled various flags (e.g. --test, -C opt-level, etc). Each Package then contained many profiles for each possible compilation mode. For example a Package would have one target for testing a library, benchmarking a library, documenting a library, etc. When it came to building these targets, Cargo would filter out the targets listed to determine what needed to be built. This filtering was largely done based off an "environment" represented as a string. Each mode of compilation got a separate environment string like `"test"` or `"bench"`. Altogether, however, this approach had a number of drawbacks: * Examples in release mode do not currently work. This is due to how examples are classified and how release mode is handled (e.g. the "release" environment where examples are meant to be built in the "test" environment). * It is not trivial to implement `cargo test --release` today. * It is not trivial to implement `cargo build --bin foo` where *only* the binary `foo` is built. The same is true for examples. * It is not trivial to add selective building of a number of binaries/examples/etc. * Filtering the list of targets to build has some pretty hokey logic that involves pseudo-environments like "doc-all" vs "doc". This logic is duplicated in a few places and in general is quite brittle. * The TOML parser greatly affects compilation due to the time at which profiles are generated, which seems somewhat backwards. * Profiles must be overridden, but only partially, at compile time becuase only the top-level package's profile is applied. In general, this system just needed an overhaul. This commit made a single change of separating `Profile` from `Target` and then basically hit `make` until all the tests passed again. The other large architectural changes are: * Environment strings are now entirely gone. * Filters are implemented in a much more robust fashion. * Release mode is now handled much more gracefully. * The unit of compilation in the backend is no longer (package, target) but rather (package, target, profile). This change had to be propagated many location in the `cargo_rustc` module. * The backend does not filter targets to build *at all*. All filtering now happens entirely in the frontend. I'll test issues after this change lands, but the motivation behind this is to open the door to quickly fixing a number of outstanding issues against Cargo. This change itself is not intended to close many bugs.
2015-02-19 19:30:35 +00:00
p.cargo_process("test").arg("--no-run").arg("-v")
.exec_with_output()
.unwrap();
assert_that(&p.bin("foo"), is_not(existing_file()));
assert_that(&p.bin("examples/foo"), existing_file());
Overhaul how cargo treats profiles This commit is a complete overhaul of how Cargo handles compilation profiles internally. The external interface of Cargo is not affected by this change. Previously each Target had a Profile embedded within it. Conceptually a Target is an entry in the manifest (a binary, benchmark, etc) and a Profile controlled various flags (e.g. --test, -C opt-level, etc). Each Package then contained many profiles for each possible compilation mode. For example a Package would have one target for testing a library, benchmarking a library, documenting a library, etc. When it came to building these targets, Cargo would filter out the targets listed to determine what needed to be built. This filtering was largely done based off an "environment" represented as a string. Each mode of compilation got a separate environment string like `"test"` or `"bench"`. Altogether, however, this approach had a number of drawbacks: * Examples in release mode do not currently work. This is due to how examples are classified and how release mode is handled (e.g. the "release" environment where examples are meant to be built in the "test" environment). * It is not trivial to implement `cargo test --release` today. * It is not trivial to implement `cargo build --bin foo` where *only* the binary `foo` is built. The same is true for examples. * It is not trivial to add selective building of a number of binaries/examples/etc. * Filtering the list of targets to build has some pretty hokey logic that involves pseudo-environments like "doc-all" vs "doc". This logic is duplicated in a few places and in general is quite brittle. * The TOML parser greatly affects compilation due to the time at which profiles are generated, which seems somewhat backwards. * Profiles must be overridden, but only partially, at compile time becuase only the top-level package's profile is applied. In general, this system just needed an overhaul. This commit made a single change of separating `Profile` from `Target` and then basically hit `make` until all the tests passed again. The other large architectural changes are: * Environment strings are now entirely gone. * Filters are implemented in a much more robust fashion. * Release mode is now handled much more gracefully. * The unit of compilation in the backend is no longer (package, target) but rather (package, target, profile). This change had to be propagated many location in the `cargo_rustc` module. * The backend does not filter targets to build *at all*. All filtering now happens entirely in the frontend. I'll test issues after this change lands, but the motivation behind this is to open the door to quickly fixing a number of outstanding issues against Cargo. This change itself is not intended to close many bugs.
2015-02-19 19:30:35 +00:00
p.cargo("test").arg("--no-run").arg("-v")
.exec_with_output()
.unwrap();
assert_that(&p.bin("foo"), is_not(existing_file()));
assert_that(&p.bin("examples/foo"), existing_file());
}
#[test]
fn compile_then_delete() {
let p = project("foo")
.file("Cargo.toml", r#"
[package]
name = "foo"
version = "0.0.1"
authors = []
"#)
.file("src/main.rs", "fn main() {}");
assert_that(p.cargo_process("run").arg("-v"), execs().with_status(0));
assert_that(&p.bin("foo"), existing_file());
if cfg!(windows) {
2015-03-16 13:27:58 +00:00
// On windows unlinking immediately after running often fails, so sleep
sleep_ms(100);
}
fs::remove_file(&p.bin("foo")).unwrap();
assert_that(p.cargo("run").arg("-v"),
execs().with_status(0));
}
#[test]
fn transitive_dependencies_not_available() {
let p = project("foo")
.file("Cargo.toml", r#"
[package]
name = "foo"
version = "0.0.1"
authors = []
2015-02-09 16:16:08 +00:00
[dependencies.aaaaa]
path = "a"
"#)
2015-02-09 16:16:08 +00:00
.file("src/main.rs", "extern crate bbbbb; extern crate aaaaa; fn main() {}")
.file("a/Cargo.toml", r#"
[package]
2015-02-09 16:16:08 +00:00
name = "aaaaa"
version = "0.0.1"
authors = []
2015-02-09 16:16:08 +00:00
[dependencies.bbbbb]
path = "../b"
"#)
2015-02-09 16:16:08 +00:00
.file("a/src/lib.rs", "extern crate bbbbb;")
.file("b/Cargo.toml", r#"
[package]
2015-02-09 16:16:08 +00:00
name = "bbbbb"
version = "0.0.1"
authors = []
"#)
.file("b/src/lib.rs", "");
assert_that(p.cargo_process("build").arg("-v"),
execs().with_status(101)
.with_stderr_contains("\
[..] can't find crate for `bbbbb`[..]
2016-05-12 17:06:36 +00:00
"));
}
#[test]
fn cyclic_deps_rejected() {
let p = project("foo")
.file("Cargo.toml", r#"
[package]
name = "foo"
version = "0.0.1"
authors = []
[dependencies.a]
path = "a"
"#)
.file("src/lib.rs", "")
.file("a/Cargo.toml", r#"
[package]
name = "a"
version = "0.0.1"
authors = []
[dependencies.foo]
path = ".."
"#)
.file("a/src/lib.rs", "");
assert_that(p.cargo_process("build").arg("-v"),
execs().with_status(101)
2016-05-12 17:06:36 +00:00
.with_stderr("\
[ERROR] cyclic package dependency: package `foo v0.0.1 ([..])` depends on itself
2016-05-12 17:06:36 +00:00
"));
}
#[test]
fn predictable_filenames() {
let p = project("foo")
.file("Cargo.toml", r#"
[package]
name = "foo"
version = "0.0.1"
authors = []
[lib]
name = "foo"
crate-type = ["dylib", "rlib"]
"#)
.file("src/lib.rs", "");
assert_that(p.cargo_process("build").arg("-v"),
execs().with_status(0));
assert_that(&p.root().join("target/debug/libfoo.rlib"), existing_file());
let dylib_name = format!("{}foo{}", env::consts::DLL_PREFIX,
env::consts::DLL_SUFFIX);
assert_that(&p.root().join("target/debug").join(dylib_name),
existing_file());
}
#[test]
fn dashes_to_underscores() {
let p = project("foo")
.file("Cargo.toml", r#"
[package]
name = "foo-bar"
version = "0.0.1"
authors = []
"#)
.file("src/lib.rs", "")
.file("src/main.rs", "extern crate foo_bar; fn main() {}");
assert_that(p.cargo_process("build").arg("-v"),
execs().with_status(0));
assert_that(&p.bin("foo-bar"), existing_file());
}
#[test]
fn dashes_in_crate_name_bad() {
let p = project("foo")
.file("Cargo.toml", r#"
[package]
name = "foo"
version = "0.0.1"
authors = []
[lib]
name = "foo-bar"
"#)
.file("src/lib.rs", "")
.file("src/main.rs", "extern crate foo_bar; fn main() {}");
assert_that(p.cargo_process("build").arg("-v"),
execs().with_status(101));
}
#[test]
fn rustc_env_var() {
let p = project("foo")
.file("Cargo.toml", r#"
[package]
name = "foo"
version = "0.0.1"
authors = []
"#)
.file("src/lib.rs", "");
p.build();
assert_that(p.cargo("build")
.env("RUSTC", "rustc-that-does-not-exist").arg("-v"),
execs().with_status(101)
2016-05-12 17:06:36 +00:00
.with_stderr("\
[ERROR] Could not execute process `rustc-that-does-not-exist -vV` ([..])
Caused by:
[..]
2016-05-12 17:06:36 +00:00
"));
assert_that(&p.bin("a"), is_not(existing_file()));
}
#[test]
fn filtering() {
let p = project("foo")
.file("Cargo.toml", r#"
[package]
name = "foo"
version = "0.0.1"
authors = []
"#)
.file("src/lib.rs", "")
.file("src/bin/a.rs", "fn main() {}")
.file("src/bin/b.rs", "fn main() {}")
.file("examples/a.rs", "fn main() {}")
.file("examples/b.rs", "fn main() {}");
p.build();
assert_that(p.cargo("build").arg("--lib"),
execs().with_status(0));
assert_that(&p.bin("a"), is_not(existing_file()));
assert_that(p.cargo("build").arg("--bin=a").arg("--example=a"),
execs().with_status(0));
assert_that(&p.bin("a"), existing_file());
assert_that(&p.bin("b"), is_not(existing_file()));
assert_that(&p.bin("examples/a"), existing_file());
assert_that(&p.bin("examples/b"), is_not(existing_file()));
}
#[test]
fn ignore_dotfile() {
let p = project("foo")
.file("Cargo.toml", r#"
[package]
name = "foo"
version = "0.0.1"
authors = []
"#)
.file("src/bin/.a.rs", "")
.file("src/bin/a.rs", "fn main() {}");
p.build();
assert_that(p.cargo("build"),
execs().with_status(0));
}
#[test]
fn ignore_dotdirs() {
let p = project("foo")
.file("Cargo.toml", r#"
[package]
name = "foo"
version = "0.0.1"
authors = []
"#)
.file("src/bin/a.rs", "fn main() {}")
.file(".git/Cargo.toml", "")
.file(".pc/dummy-fix.patch/Cargo.toml", "");
p.build();
assert_that(p.cargo("build"),
execs().with_status(0));
}
#[test]
fn dotdir_root() {
let p = ProjectBuilder::new("foo", root().join(".foo"))
.file("Cargo.toml", r#"
[package]
name = "foo"
version = "0.0.1"
authors = []
"#)
.file("src/bin/a.rs", "fn main() {}");
p.build();
assert_that(p.cargo("build"),
execs().with_status(0));
}
#[test]
fn custom_target_dir() {
let p = project("foo")
.file("Cargo.toml", r#"
[package]
name = "foo"
version = "0.0.1"
authors = []
"#)
.file("src/main.rs", "fn main() {}");
p.build();
let exe_name = format!("foo{}", env::consts::EXE_SUFFIX);
assert_that(p.cargo("build").env("CARGO_TARGET_DIR", "foo/target"),
execs().with_status(0));
assert_that(&p.root().join("foo/target/debug").join(&exe_name),
existing_file());
assert_that(&p.root().join("target/debug").join(&exe_name),
is_not(existing_file()));
assert_that(p.cargo("build"),
execs().with_status(0));
assert_that(&p.root().join("foo/target/debug").join(&exe_name),
existing_file());
assert_that(&p.root().join("target/debug").join(&exe_name),
existing_file());
fs::create_dir(p.root().join(".cargo")).unwrap();
File::create(p.root().join(".cargo/config")).unwrap().write_all(br#"
[build]
target-dir = "foo/target"
"#).unwrap();
assert_that(p.cargo("build").env("CARGO_TARGET_DIR", "bar/target"),
execs().with_status(0));
assert_that(&p.root().join("bar/target/debug").join(&exe_name),
existing_file());
assert_that(&p.root().join("foo/target/debug").join(&exe_name),
existing_file());
assert_that(&p.root().join("target/debug").join(&exe_name),
existing_file());
}
#[test]
fn rustc_no_trans() {
let p = project("foo")
.file("Cargo.toml", r#"
[package]
name = "foo"
version = "0.0.1"
authors = []
"#)
.file("src/main.rs", "fn main() {}");
p.build();
assert_that(p.cargo("rustc").arg("-v").arg("--").arg("-Zno-trans"),
execs().with_status(0));
}
#[test]
fn build_multiple_packages() {
let p = project("foo")
.file("Cargo.toml", r#"
[package]
name = "foo"
version = "0.0.1"
authors = []
[dependencies.d1]
path = "d1"
[dependencies.d2]
path = "d2"
[[bin]]
name = "foo"
"#)
.file("src/foo.rs", &main_file(r#""i am foo""#, &[]))
.file("d1/Cargo.toml", r#"
[package]
name = "d1"
version = "0.0.1"
authors = []
[[bin]]
name = "d1"
"#)
.file("d1/src/lib.rs", "")
.file("d1/src/main.rs", "fn main() { println!(\"d1\"); }")
.file("d2/Cargo.toml", r#"
[package]
name = "d2"
version = "0.0.1"
authors = []
[[bin]]
name = "d2"
doctest = false
"#)
.file("d2/src/main.rs", "fn main() { println!(\"d2\"); }");
p.build();
assert_that(p.cargo_process("build").arg("-p").arg("d1").arg("-p").arg("d2")
.arg("-p").arg("foo"),
execs());
assert_that(&p.bin("foo"), existing_file());
2015-10-28 09:20:00 +00:00
assert_that(process(&p.bin("foo")),
execs().with_stdout("i am foo\n"));
2015-09-24 21:47:50 +00:00
let d1_path = &p.build_dir().join("debug").join("deps")
.join(format!("d1{}", env::consts::EXE_SUFFIX));
let d2_path = &p.build_dir().join("debug").join("deps")
.join(format!("d2{}", env::consts::EXE_SUFFIX));
2015-09-24 21:47:50 +00:00
assert_that(d1_path, existing_file());
2015-10-28 09:20:00 +00:00
assert_that(process(d1_path), execs().with_stdout("d1"));
2015-09-24 21:47:50 +00:00
assert_that(d2_path, existing_file());
2015-10-28 09:20:00 +00:00
assert_that(process(d2_path),
execs().with_stdout("d2"));
}
#[test]
fn invalid_spec() {
let p = project("foo")
.file("Cargo.toml", r#"
[package]
name = "foo"
version = "0.0.1"
authors = []
[dependencies.d1]
path = "d1"
[[bin]]
name = "foo"
"#)
.file("src/foo.rs", &main_file(r#""i am foo""#, &[]))
.file("d1/Cargo.toml", r#"
[package]
name = "d1"
version = "0.0.1"
authors = []
[[bin]]
name = "d1"
"#)
.file("d1/src/lib.rs", "")
.file("d1/src/main.rs", "fn main() { println!(\"d1\"); }");
p.build();
assert_that(p.cargo_process("build").arg("-p").arg("notAValidDep"),
execs().with_status(101).with_stderr("\
[ERROR] package id specification `notAValidDep` matched no packages
"));
assert_that(p.cargo_process("build").arg("-p").arg("d1").arg("-p").arg("notAValidDep"),
execs().with_status(101).with_stderr("\
[ERROR] package id specification `notAValidDep` matched no packages
"));
}
#[test]
fn manifest_with_bom_is_ok() {
let p = project("foo")
.file("Cargo.toml", "\u{FEFF}
[package]
name = \"foo\"
version = \"0.0.1\"
authors = []
")
.file("src/lib.rs", "");
assert_that(p.cargo_process("build").arg("-v"),
execs().with_status(0));
}
#[test]
fn panic_abort_compiles_with_panic_abort() {
if !is_nightly() {
return
}
let p = project("foo")
.file("Cargo.toml", r#"
[package]
name = "foo"
version = "0.0.1"
authors = []
[profile.dev]
panic = 'abort'
"#)
.file("src/lib.rs", "");
assert_that(p.cargo_process("build").arg("-v"),
execs().with_status(0)
.with_stderr_contains("[..] -C panic=abort [..]"));
}
2016-06-09 20:55:17 +00:00
#[test]
fn explicit_color_config_is_propagated_to_rustc() {
let mut p = project("foo");
p = p
.file("Cargo.toml", r#"
[package]
name = "test"
version = "0.0.0"
authors = []
"#)
.file("src/lib.rs", "");
assert_that(p.cargo_process("build").arg("-v").arg("--color").arg("always"),
execs().with_status(0).with_stderr_contains(
"[..]rustc src[..]lib.rs --color always[..]"));
assert_that(p.cargo_process("build").arg("-v").arg("--color").arg("never"),
execs().with_status(0).with_stderr("\
[COMPILING] test v0.0.0 ([..])
[RUNNING] `rustc [..] --color never [..]`
[FINISHED] debug [unoptimized + debuginfo] target(s) in [..]
2016-06-09 20:55:17 +00:00
"));
}
#[test]
fn no_warn_about_package_metadata() {
let p = project("foo")
.file("Cargo.toml", r#"
[package]
name = "foo"
version = "0.0.1"
authors = []
[package.metadata]
foo = "bar"
a = true
b = 3
[package.metadata.another]
bar = 3
"#)
.file("src/lib.rs", "");
assert_that(p.cargo_process("build"),
execs().with_status(0)
.with_stderr("[..] foo v0.0.1 ([..])\n\
[FINISHED] debug [unoptimized + debuginfo] target(s) in [..]\n"));
}