mirror of
https://github.com/rust-lang/cargo.git
synced 2025-09-28 11:20:36 +00:00
Package lock files in published crates
Previously we had logic to explicitly skip lock files but there's actually a good case to read these from crates.io (#2263) so let's do so! Closes #2263
This commit is contained in:
parent
8b475c1085
commit
a4a3302d46
@ -162,6 +162,9 @@ features! {
|
||||
|
||||
// Renaming a package in the manifest via the `package` key
|
||||
[unstable] rename_dependency: bool,
|
||||
|
||||
// Whether a lock file is published with this crate
|
||||
[unstable] publish_lockfile: bool,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -31,6 +31,7 @@ pub struct Manifest {
|
||||
metadata: ManifestMetadata,
|
||||
profiles: Profiles,
|
||||
publish: Option<Vec<String>>,
|
||||
publish_lockfile: bool,
|
||||
replace: Vec<(PackageIdSpec, Dependency)>,
|
||||
patch: HashMap<Url, Vec<Dependency>>,
|
||||
workspace: WorkspaceConfig,
|
||||
@ -267,6 +268,7 @@ impl Manifest {
|
||||
metadata: ManifestMetadata,
|
||||
profiles: Profiles,
|
||||
publish: Option<Vec<String>>,
|
||||
publish_lockfile: bool,
|
||||
replace: Vec<(PackageIdSpec, Dependency)>,
|
||||
patch: HashMap<Url, Vec<Dependency>>,
|
||||
workspace: WorkspaceConfig,
|
||||
@ -291,6 +293,7 @@ impl Manifest {
|
||||
epoch,
|
||||
original,
|
||||
im_a_teapot,
|
||||
publish_lockfile,
|
||||
}
|
||||
}
|
||||
|
||||
@ -306,6 +309,7 @@ impl Manifest {
|
||||
pub fn warnings(&self) -> &[DelayedWarning] { &self.warnings }
|
||||
pub fn profiles(&self) -> &Profiles { &self.profiles }
|
||||
pub fn publish(&self) -> &Option<Vec<String>> { &self.publish }
|
||||
pub fn publish_lockfile(&self) -> bool { self.publish_lockfile }
|
||||
pub fn replace(&self) -> &[(PackageIdSpec, Dependency)] { &self.replace }
|
||||
pub fn original(&self) -> &TomlManifest { &self.original }
|
||||
pub fn patch(&self) -> &HashMap<Url, Vec<Dependency>> { &self.patch }
|
||||
|
@ -12,6 +12,7 @@ use tar::{Archive, Builder, Header, EntryType};
|
||||
use core::{Package, Workspace, Source, SourceId};
|
||||
use sources::PathSource;
|
||||
use util::{self, internal, Config, FileLock};
|
||||
use util::paths;
|
||||
use util::errors::{CargoResult, CargoResultExt};
|
||||
use ops::{self, DefaultExecutor};
|
||||
|
||||
@ -28,6 +29,7 @@ pub struct PackageOpts<'cfg> {
|
||||
|
||||
pub fn package(ws: &Workspace,
|
||||
opts: &PackageOpts) -> CargoResult<Option<FileLock>> {
|
||||
ops::resolve_ws(ws)?;
|
||||
let pkg = ws.current()?;
|
||||
let config = ws.config();
|
||||
|
||||
@ -47,6 +49,9 @@ pub fn package(ws: &Workspace,
|
||||
let mut list: Vec<_> = src.list_files(pkg)?.iter().map(|file| {
|
||||
util::without_prefix(file, root).unwrap().to_path_buf()
|
||||
}).collect();
|
||||
if include_lockfile(&pkg) {
|
||||
list.push("Cargo.lock".into());
|
||||
}
|
||||
list.sort();
|
||||
for file in list.iter() {
|
||||
println!("{}", file.display());
|
||||
@ -91,6 +96,11 @@ pub fn package(ws: &Workspace,
|
||||
Ok(Some(dst))
|
||||
}
|
||||
|
||||
fn include_lockfile(pkg: &Package) -> bool {
|
||||
pkg.manifest().publish_lockfile() &&
|
||||
pkg.targets().iter().any(|t| t.is_example() || t.is_bin())
|
||||
}
|
||||
|
||||
// check that the package has some piece of metadata that a human can
|
||||
// use to tell what the package is about.
|
||||
fn check_metadata(pkg: &Package, config: &Config) -> CargoResult<()> {
|
||||
@ -265,6 +275,22 @@ fn tar(ws: &Workspace,
|
||||
})?;
|
||||
}
|
||||
}
|
||||
|
||||
if include_lockfile(pkg) {
|
||||
let toml = paths::read(&ws.root().join("Cargo.lock"))?;
|
||||
let path = format!("{}-{}{}Cargo.lock", pkg.name(), pkg.version(),
|
||||
path::MAIN_SEPARATOR);
|
||||
let mut header = Header::new_ustar();
|
||||
header.set_path(&path)?;
|
||||
header.set_entry_type(EntryType::file());
|
||||
header.set_mode(0o644);
|
||||
header.set_size(toml.len() as u64);
|
||||
header.set_cksum();
|
||||
ar.append(&header, toml.as_bytes()).chain_err(|| {
|
||||
internal("could not archive source file `Cargo.lock`")
|
||||
})?;
|
||||
}
|
||||
|
||||
let encoder = ar.into_inner()?;
|
||||
encoder.finish()?;
|
||||
Ok(())
|
||||
|
@ -426,6 +426,8 @@ pub struct TomlProject {
|
||||
exclude: Option<Vec<String>>,
|
||||
include: Option<Vec<String>>,
|
||||
publish: Option<VecStringOrBool>,
|
||||
#[serde(rename = "publish-lockfile")]
|
||||
publish_lockfile: Option<bool>,
|
||||
workspace: Option<String>,
|
||||
#[serde(rename = "im-a-teapot")]
|
||||
im_a_teapot: Option<bool>,
|
||||
@ -719,6 +721,14 @@ impl TomlManifest {
|
||||
None | Some(VecStringOrBool::Bool(true)) => None,
|
||||
};
|
||||
|
||||
let publish_lockfile = match project.publish_lockfile {
|
||||
Some(b) => {
|
||||
features.require(Feature::publish_lockfile())?;
|
||||
b
|
||||
}
|
||||
None => false,
|
||||
};
|
||||
|
||||
let epoch = if let Some(ref epoch) = project.rust {
|
||||
features.require(Feature::epoch()).chain_err(|| {
|
||||
"epoches are unstable"
|
||||
@ -739,6 +749,7 @@ impl TomlManifest {
|
||||
metadata,
|
||||
profiles,
|
||||
publish,
|
||||
publish_lockfile,
|
||||
replace,
|
||||
patch,
|
||||
workspace_config,
|
||||
|
@ -1044,3 +1044,33 @@ dependencies = [
|
||||
assert_that(cargo_process("install").arg("foo"),
|
||||
execs().with_status(0));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn lock_file_path_deps_ok() {
|
||||
Package::new("bar", "0.1.0").publish();
|
||||
|
||||
Package::new("foo", "0.1.0")
|
||||
.dep("bar", "0.1")
|
||||
.file("src/lib.rs", "")
|
||||
.file("src/main.rs", "
|
||||
extern crate foo;
|
||||
extern crate bar;
|
||||
fn main() {}
|
||||
")
|
||||
.file("Cargo.lock", r#"
|
||||
[[package]]
|
||||
name = "bar"
|
||||
version = "0.1.0"
|
||||
|
||||
[[package]]
|
||||
name = "foo"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"bar 0.1.0",
|
||||
]
|
||||
"#)
|
||||
.publish();
|
||||
|
||||
assert_that(cargo_process("install").arg("foo"),
|
||||
execs().with_status(0));
|
||||
}
|
||||
|
@ -702,8 +702,9 @@ to proceed despite this, pass the `--allow-dirty` flag
|
||||
#[test]
|
||||
fn generated_manifest() {
|
||||
Package::new("abc", "1.0.0").publish();
|
||||
Package::new("def", "1.0.0").publish();
|
||||
Package::new("def", "1.0.0").alternative(true).publish();
|
||||
Package::new("ghi", "1.0.0").publish();
|
||||
|
||||
let p = project("foo")
|
||||
.file("Cargo.toml", r#"
|
||||
cargo-features = ["alternative-registries"]
|
||||
@ -995,3 +996,160 @@ Caused by:
|
||||
consider adding `cargo-features = [\"epoch\"]` to the manifest
|
||||
")));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn package_lockfile() {
|
||||
let p = project("foo")
|
||||
.file("Cargo.toml", r#"
|
||||
cargo-features = ["publish-lockfile"]
|
||||
|
||||
[project]
|
||||
name = "foo"
|
||||
version = "0.0.1"
|
||||
authors = []
|
||||
license = "MIT"
|
||||
description = "foo"
|
||||
publish-lockfile = true
|
||||
"#)
|
||||
.file("src/main.rs", "fn main() {}")
|
||||
.build();
|
||||
|
||||
assert_that(p.cargo("package").masquerade_as_nightly_cargo(),
|
||||
execs().with_status(0).with_stderr(&format!("\
|
||||
[WARNING] manifest has no documentation[..]
|
||||
See [..]
|
||||
[PACKAGING] foo v0.0.1 ({dir})
|
||||
[VERIFYING] foo v0.0.1 ({dir})
|
||||
[COMPILING] foo v0.0.1 ({dir}[..])
|
||||
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
|
||||
",
|
||||
dir = p.url())));
|
||||
assert_that(&p.root().join("target/package/foo-0.0.1.crate"), existing_file());
|
||||
assert_that(p.cargo("package").arg("-l").masquerade_as_nightly_cargo(),
|
||||
execs().with_status(0).with_stdout("\
|
||||
Cargo.lock
|
||||
Cargo.toml
|
||||
src[/]main.rs
|
||||
"));
|
||||
assert_that(p.cargo("package").masquerade_as_nightly_cargo(),
|
||||
execs().with_status(0).with_stdout(""));
|
||||
|
||||
let f = File::open(&p.root().join("target/package/foo-0.0.1.crate")).unwrap();
|
||||
let mut rdr = GzDecoder::new(f);
|
||||
let mut contents = Vec::new();
|
||||
rdr.read_to_end(&mut contents).unwrap();
|
||||
let mut ar = Archive::new(&contents[..]);
|
||||
for f in ar.entries().unwrap() {
|
||||
let f = f.unwrap();
|
||||
let fname = f.header().path_bytes();
|
||||
let fname = &*fname;
|
||||
assert!(fname == b"foo-0.0.1/Cargo.toml" ||
|
||||
fname == b"foo-0.0.1/Cargo.toml.orig" ||
|
||||
fname == b"foo-0.0.1/Cargo.lock" ||
|
||||
fname == b"foo-0.0.1/src/main.rs",
|
||||
"unexpected filename: {:?}", f.header().path())
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn package_lockfile_git_repo() {
|
||||
let p = project("foo").build();
|
||||
|
||||
// Create a Git repository containing a minimal Rust project.
|
||||
let _ = git::repo(&paths::root().join("foo"))
|
||||
.file("Cargo.toml", r#"
|
||||
cargo-features = ["publish-lockfile"]
|
||||
|
||||
[project]
|
||||
name = "foo"
|
||||
version = "0.0.1"
|
||||
license = "MIT"
|
||||
description = "foo"
|
||||
documentation = "foo"
|
||||
homepage = "foo"
|
||||
repository = "foo"
|
||||
publish-lockfile = true
|
||||
"#)
|
||||
.file("src/main.rs", "fn main() {}")
|
||||
.build();
|
||||
assert_that(p.cargo("package").arg("-l").masquerade_as_nightly_cargo(),
|
||||
execs().with_status(0).with_stdout("\
|
||||
Cargo.lock
|
||||
Cargo.toml
|
||||
src/main.rs
|
||||
"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn no_lock_file_with_library() {
|
||||
let p = project("foo")
|
||||
.file("Cargo.toml", r#"
|
||||
cargo-features = ["publish-lockfile"]
|
||||
|
||||
[project]
|
||||
name = "foo"
|
||||
version = "0.0.1"
|
||||
authors = []
|
||||
license = "MIT"
|
||||
description = "foo"
|
||||
publish-lockfile = true
|
||||
"#)
|
||||
.file("src/lib.rs", "")
|
||||
.build();
|
||||
|
||||
assert_that(p.cargo("package").masquerade_as_nightly_cargo(),
|
||||
execs().with_status(0));
|
||||
|
||||
let f = File::open(&p.root().join("target/package/foo-0.0.1.crate")).unwrap();
|
||||
let mut rdr = GzDecoder::new(f);
|
||||
let mut contents = Vec::new();
|
||||
rdr.read_to_end(&mut contents).unwrap();
|
||||
let mut ar = Archive::new(&contents[..]);
|
||||
for f in ar.entries().unwrap() {
|
||||
let f = f.unwrap();
|
||||
let fname = f.header().path().unwrap();
|
||||
assert!(!fname.ends_with("Cargo.lock"));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn lock_file_and_workspace() {
|
||||
let p = project("foo")
|
||||
.file("Cargo.toml", r#"
|
||||
[workspace]
|
||||
members = ["foo"]
|
||||
"#)
|
||||
.file("foo/Cargo.toml", r#"
|
||||
cargo-features = ["publish-lockfile"]
|
||||
|
||||
[package]
|
||||
name = "foo"
|
||||
version = "0.0.1"
|
||||
authors = []
|
||||
license = "MIT"
|
||||
description = "foo"
|
||||
publish-lockfile = true
|
||||
"#)
|
||||
.file("foo/src/main.rs", "fn main() {}")
|
||||
.build();
|
||||
|
||||
assert_that(p.cargo("package")
|
||||
.cwd(p.root().join("foo"))
|
||||
.masquerade_as_nightly_cargo(),
|
||||
execs().with_status(0));
|
||||
|
||||
let f = File::open(&p.root().join("target/package/foo-0.0.1.crate")).unwrap();
|
||||
let mut rdr = GzDecoder::new(f);
|
||||
let mut contents = Vec::new();
|
||||
rdr.read_to_end(&mut contents).unwrap();
|
||||
let mut ar = Archive::new(&contents[..]);
|
||||
assert!(
|
||||
ar.entries().unwrap()
|
||||
.into_iter()
|
||||
.any(|f|{
|
||||
let f = f.unwrap();
|
||||
let fname = f.header().path().unwrap();
|
||||
fname.ends_with("Cargo.lock")
|
||||
})
|
||||
);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user