Skip to content

Commit f55b326

Browse files
committed
Auto merge of #5093 - alexcrichton:include-cargo-lock, r=matklad
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
2 parents 9f12fdb + a4a3302 commit f55b326

File tree

7 files changed

+267
-2
lines changed

7 files changed

+267
-2
lines changed

src/cargo/core/features.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,9 @@ features! {
162162

163163
// Renaming a package in the manifest via the `package` key
164164
[unstable] rename_dependency: bool,
165+
166+
// Whether a lock file is published with this crate
167+
[unstable] publish_lockfile: bool,
165168
}
166169
}
167170

src/cargo/core/manifest.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ pub struct Manifest {
3131
metadata: ManifestMetadata,
3232
profiles: Profiles,
3333
publish: Option<Vec<String>>,
34+
publish_lockfile: bool,
3435
replace: Vec<(PackageIdSpec, Dependency)>,
3536
patch: HashMap<Url, Vec<Dependency>>,
3637
workspace: WorkspaceConfig,
@@ -267,6 +268,7 @@ impl Manifest {
267268
metadata: ManifestMetadata,
268269
profiles: Profiles,
269270
publish: Option<Vec<String>>,
271+
publish_lockfile: bool,
270272
replace: Vec<(PackageIdSpec, Dependency)>,
271273
patch: HashMap<Url, Vec<Dependency>>,
272274
workspace: WorkspaceConfig,
@@ -291,6 +293,7 @@ impl Manifest {
291293
epoch,
292294
original,
293295
im_a_teapot,
296+
publish_lockfile,
294297
}
295298
}
296299

@@ -306,6 +309,7 @@ impl Manifest {
306309
pub fn warnings(&self) -> &[DelayedWarning] { &self.warnings }
307310
pub fn profiles(&self) -> &Profiles { &self.profiles }
308311
pub fn publish(&self) -> &Option<Vec<String>> { &self.publish }
312+
pub fn publish_lockfile(&self) -> bool { self.publish_lockfile }
309313
pub fn replace(&self) -> &[(PackageIdSpec, Dependency)] { &self.replace }
310314
pub fn original(&self) -> &TomlManifest { &self.original }
311315
pub fn patch(&self) -> &HashMap<Url, Vec<Dependency>> { &self.patch }

src/cargo/ops/cargo_package.rs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ use tar::{Archive, Builder, Header, EntryType};
1212
use core::{Package, Workspace, Source, SourceId};
1313
use sources::PathSource;
1414
use util::{self, internal, Config, FileLock};
15+
use util::paths;
1516
use util::errors::{CargoResult, CargoResultExt};
1617
use ops::{self, DefaultExecutor};
1718

@@ -28,6 +29,7 @@ pub struct PackageOpts<'cfg> {
2829

2930
pub fn package(ws: &Workspace,
3031
opts: &PackageOpts) -> CargoResult<Option<FileLock>> {
32+
ops::resolve_ws(ws)?;
3133
let pkg = ws.current()?;
3234
let config = ws.config();
3335

@@ -47,6 +49,9 @@ pub fn package(ws: &Workspace,
4749
let mut list: Vec<_> = src.list_files(pkg)?.iter().map(|file| {
4850
util::without_prefix(file, root).unwrap().to_path_buf()
4951
}).collect();
52+
if include_lockfile(&pkg) {
53+
list.push("Cargo.lock".into());
54+
}
5055
list.sort();
5156
for file in list.iter() {
5257
println!("{}", file.display());
@@ -91,6 +96,11 @@ pub fn package(ws: &Workspace,
9196
Ok(Some(dst))
9297
}
9398

99+
fn include_lockfile(pkg: &Package) -> bool {
100+
pkg.manifest().publish_lockfile() &&
101+
pkg.targets().iter().any(|t| t.is_example() || t.is_bin())
102+
}
103+
94104
// check that the package has some piece of metadata that a human can
95105
// use to tell what the package is about.
96106
fn check_metadata(pkg: &Package, config: &Config) -> CargoResult<()> {
@@ -265,6 +275,22 @@ fn tar(ws: &Workspace,
265275
})?;
266276
}
267277
}
278+
279+
if include_lockfile(pkg) {
280+
let toml = paths::read(&ws.root().join("Cargo.lock"))?;
281+
let path = format!("{}-{}{}Cargo.lock", pkg.name(), pkg.version(),
282+
path::MAIN_SEPARATOR);
283+
let mut header = Header::new_ustar();
284+
header.set_path(&path)?;
285+
header.set_entry_type(EntryType::file());
286+
header.set_mode(0o644);
287+
header.set_size(toml.len() as u64);
288+
header.set_cksum();
289+
ar.append(&header, toml.as_bytes()).chain_err(|| {
290+
internal("could not archive source file `Cargo.lock`")
291+
})?;
292+
}
293+
268294
let encoder = ar.into_inner()?;
269295
encoder.finish()?;
270296
Ok(())

src/cargo/ops/resolve.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ pub fn resolve_ws_precisely<'a>(ws: &Workspace<'a>,
6565

6666
Some(resolve)
6767
} else {
68-
None
68+
ops::load_pkg_lockfile(ws)?
6969
};
7070

7171
let method = if all_features {

src/cargo/util/toml/mod.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -426,6 +426,8 @@ pub struct TomlProject {
426426
exclude: Option<Vec<String>>,
427427
include: Option<Vec<String>>,
428428
publish: Option<VecStringOrBool>,
429+
#[serde(rename = "publish-lockfile")]
430+
publish_lockfile: Option<bool>,
429431
workspace: Option<String>,
430432
#[serde(rename = "im-a-teapot")]
431433
im_a_teapot: Option<bool>,
@@ -719,6 +721,14 @@ impl TomlManifest {
719721
None | Some(VecStringOrBool::Bool(true)) => None,
720722
};
721723

724+
let publish_lockfile = match project.publish_lockfile {
725+
Some(b) => {
726+
features.require(Feature::publish_lockfile())?;
727+
b
728+
}
729+
None => false,
730+
};
731+
722732
let epoch = if let Some(ref epoch) = project.rust {
723733
features.require(Feature::epoch()).chain_err(|| {
724734
"epoches are unstable"
@@ -739,6 +749,7 @@ impl TomlManifest {
739749
metadata,
740750
profiles,
741751
publish,
752+
publish_lockfile,
742753
replace,
743754
patch,
744755
workspace_config,

tests/testsuite/install.rs

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1011,3 +1011,66 @@ fn custom_target_dir_for_git_source() {
10111011
assert_that(&paths::root().join("target/release"),
10121012
existing_dir());
10131013
}
1014+
1015+
#[test]
1016+
fn install_respects_lock_file() {
1017+
Package::new("bar", "0.1.0").publish();
1018+
Package::new("bar", "0.1.1")
1019+
.file("src/lib.rs", "not rust")
1020+
.publish();
1021+
Package::new("foo", "0.1.0")
1022+
.dep("bar", "0.1")
1023+
.file("src/lib.rs", "")
1024+
.file("src/main.rs", "
1025+
extern crate foo;
1026+
extern crate bar;
1027+
fn main() {}
1028+
")
1029+
.file("Cargo.lock", r#"
1030+
[[package]]
1031+
name = "bar"
1032+
version = "0.1.0"
1033+
source = "registry+https://github.com/rust-lang/crates.io-index"
1034+
1035+
[[package]]
1036+
name = "foo"
1037+
version = "0.1.0"
1038+
dependencies = [
1039+
"bar 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
1040+
]
1041+
"#)
1042+
.publish();
1043+
1044+
assert_that(cargo_process("install").arg("foo"),
1045+
execs().with_status(0));
1046+
}
1047+
1048+
#[test]
1049+
fn lock_file_path_deps_ok() {
1050+
Package::new("bar", "0.1.0").publish();
1051+
1052+
Package::new("foo", "0.1.0")
1053+
.dep("bar", "0.1")
1054+
.file("src/lib.rs", "")
1055+
.file("src/main.rs", "
1056+
extern crate foo;
1057+
extern crate bar;
1058+
fn main() {}
1059+
")
1060+
.file("Cargo.lock", r#"
1061+
[[package]]
1062+
name = "bar"
1063+
version = "0.1.0"
1064+
1065+
[[package]]
1066+
name = "foo"
1067+
version = "0.1.0"
1068+
dependencies = [
1069+
"bar 0.1.0",
1070+
]
1071+
"#)
1072+
.publish();
1073+
1074+
assert_that(cargo_process("install").arg("foo"),
1075+
execs().with_status(0));
1076+
}

tests/testsuite/package.rs

Lines changed: 159 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -702,8 +702,9 @@ to proceed despite this, pass the `--allow-dirty` flag
702702
#[test]
703703
fn generated_manifest() {
704704
Package::new("abc", "1.0.0").publish();
705-
Package::new("def", "1.0.0").publish();
705+
Package::new("def", "1.0.0").alternative(true).publish();
706706
Package::new("ghi", "1.0.0").publish();
707+
707708
let p = project("foo")
708709
.file("Cargo.toml", r#"
709710
cargo-features = ["alternative-registries"]
@@ -995,3 +996,160 @@ Caused by:
995996
consider adding `cargo-features = [\"epoch\"]` to the manifest
996997
")));
997998
}
999+
1000+
#[test]
1001+
fn package_lockfile() {
1002+
let p = project("foo")
1003+
.file("Cargo.toml", r#"
1004+
cargo-features = ["publish-lockfile"]
1005+
1006+
[project]
1007+
name = "foo"
1008+
version = "0.0.1"
1009+
authors = []
1010+
license = "MIT"
1011+
description = "foo"
1012+
publish-lockfile = true
1013+
"#)
1014+
.file("src/main.rs", "fn main() {}")
1015+
.build();
1016+
1017+
assert_that(p.cargo("package").masquerade_as_nightly_cargo(),
1018+
execs().with_status(0).with_stderr(&format!("\
1019+
[WARNING] manifest has no documentation[..]
1020+
See [..]
1021+
[PACKAGING] foo v0.0.1 ({dir})
1022+
[VERIFYING] foo v0.0.1 ({dir})
1023+
[COMPILING] foo v0.0.1 ({dir}[..])
1024+
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
1025+
",
1026+
dir = p.url())));
1027+
assert_that(&p.root().join("target/package/foo-0.0.1.crate"), existing_file());
1028+
assert_that(p.cargo("package").arg("-l").masquerade_as_nightly_cargo(),
1029+
execs().with_status(0).with_stdout("\
1030+
Cargo.lock
1031+
Cargo.toml
1032+
src[/]main.rs
1033+
"));
1034+
assert_that(p.cargo("package").masquerade_as_nightly_cargo(),
1035+
execs().with_status(0).with_stdout(""));
1036+
1037+
let f = File::open(&p.root().join("target/package/foo-0.0.1.crate")).unwrap();
1038+
let mut rdr = GzDecoder::new(f);
1039+
let mut contents = Vec::new();
1040+
rdr.read_to_end(&mut contents).unwrap();
1041+
let mut ar = Archive::new(&contents[..]);
1042+
for f in ar.entries().unwrap() {
1043+
let f = f.unwrap();
1044+
let fname = f.header().path_bytes();
1045+
let fname = &*fname;
1046+
assert!(fname == b"foo-0.0.1/Cargo.toml" ||
1047+
fname == b"foo-0.0.1/Cargo.toml.orig" ||
1048+
fname == b"foo-0.0.1/Cargo.lock" ||
1049+
fname == b"foo-0.0.1/src/main.rs",
1050+
"unexpected filename: {:?}", f.header().path())
1051+
}
1052+
}
1053+
1054+
#[test]
1055+
fn package_lockfile_git_repo() {
1056+
let p = project("foo").build();
1057+
1058+
// Create a Git repository containing a minimal Rust project.
1059+
let _ = git::repo(&paths::root().join("foo"))
1060+
.file("Cargo.toml", r#"
1061+
cargo-features = ["publish-lockfile"]
1062+
1063+
[project]
1064+
name = "foo"
1065+
version = "0.0.1"
1066+
license = "MIT"
1067+
description = "foo"
1068+
documentation = "foo"
1069+
homepage = "foo"
1070+
repository = "foo"
1071+
publish-lockfile = true
1072+
"#)
1073+
.file("src/main.rs", "fn main() {}")
1074+
.build();
1075+
assert_that(p.cargo("package").arg("-l").masquerade_as_nightly_cargo(),
1076+
execs().with_status(0).with_stdout("\
1077+
Cargo.lock
1078+
Cargo.toml
1079+
src/main.rs
1080+
"));
1081+
}
1082+
1083+
#[test]
1084+
fn no_lock_file_with_library() {
1085+
let p = project("foo")
1086+
.file("Cargo.toml", r#"
1087+
cargo-features = ["publish-lockfile"]
1088+
1089+
[project]
1090+
name = "foo"
1091+
version = "0.0.1"
1092+
authors = []
1093+
license = "MIT"
1094+
description = "foo"
1095+
publish-lockfile = true
1096+
"#)
1097+
.file("src/lib.rs", "")
1098+
.build();
1099+
1100+
assert_that(p.cargo("package").masquerade_as_nightly_cargo(),
1101+
execs().with_status(0));
1102+
1103+
let f = File::open(&p.root().join("target/package/foo-0.0.1.crate")).unwrap();
1104+
let mut rdr = GzDecoder::new(f);
1105+
let mut contents = Vec::new();
1106+
rdr.read_to_end(&mut contents).unwrap();
1107+
let mut ar = Archive::new(&contents[..]);
1108+
for f in ar.entries().unwrap() {
1109+
let f = f.unwrap();
1110+
let fname = f.header().path().unwrap();
1111+
assert!(!fname.ends_with("Cargo.lock"));
1112+
}
1113+
}
1114+
1115+
#[test]
1116+
fn lock_file_and_workspace() {
1117+
let p = project("foo")
1118+
.file("Cargo.toml", r#"
1119+
[workspace]
1120+
members = ["foo"]
1121+
"#)
1122+
.file("foo/Cargo.toml", r#"
1123+
cargo-features = ["publish-lockfile"]
1124+
1125+
[package]
1126+
name = "foo"
1127+
version = "0.0.1"
1128+
authors = []
1129+
license = "MIT"
1130+
description = "foo"
1131+
publish-lockfile = true
1132+
"#)
1133+
.file("foo/src/main.rs", "fn main() {}")
1134+
.build();
1135+
1136+
assert_that(p.cargo("package")
1137+
.cwd(p.root().join("foo"))
1138+
.masquerade_as_nightly_cargo(),
1139+
execs().with_status(0));
1140+
1141+
let f = File::open(&p.root().join("target/package/foo-0.0.1.crate")).unwrap();
1142+
let mut rdr = GzDecoder::new(f);
1143+
let mut contents = Vec::new();
1144+
rdr.read_to_end(&mut contents).unwrap();
1145+
let mut ar = Archive::new(&contents[..]);
1146+
assert!(
1147+
ar.entries().unwrap()
1148+
.into_iter()
1149+
.any(|f|{
1150+
let f = f.unwrap();
1151+
let fname = f.header().path().unwrap();
1152+
fname.ends_with("Cargo.lock")
1153+
})
1154+
);
1155+
}

0 commit comments

Comments
 (0)