feat(toml): Allow versionless packages

This defaults the version to `0.0.0` for most of cargo.

It is an error to lack a version and have a package publishable.
That means you have to add `publish = false`.
This commit is contained in:
Ed Page 2023-10-04 12:33:35 -05:00
parent 0b5ebd445b
commit 1923b5b862
6 changed files with 290 additions and 45 deletions

View File

@ -550,11 +550,17 @@ impl TomlManifest {
let version = package let version = package
.version .version
.clone() .clone()
.resolve("version", || inherit()?.version())?; .map(|version| version.resolve("version", || inherit()?.version()))
.transpose()?;
package.version = MaybeWorkspace::Defined(version.clone()); package.version = version.clone().map(MaybeWorkspace::Defined);
let pkgid = package.to_package_id(source_id, version)?; let pkgid = package.to_package_id(
source_id,
version
.clone()
.unwrap_or_else(|| semver::Version::new(0, 0, 0)),
)?;
let edition = if let Some(edition) = package.edition.clone() { let edition = if let Some(edition) = package.edition.clone() {
let edition: Edition = edition let edition: Edition = edition
@ -1009,6 +1015,10 @@ impl TomlManifest {
None | Some(VecStringOrBool::Bool(true)) => None, None | Some(VecStringOrBool::Bool(true)) => None,
}; };
if version.is_none() && publish != Some(vec![]) {
bail!("`package.publish` requires `package.version` be specified");
}
if summary.features().contains_key("default-features") { if summary.features().contains_key("default-features") {
warnings.push( warnings.push(
"`default-features = [\"..\"]` was found in [features]. \ "`default-features = [\"..\"]` was found in [features]. \
@ -1659,7 +1669,7 @@ pub struct TomlPackage {
edition: Option<MaybeWorkspaceString>, edition: Option<MaybeWorkspaceString>,
rust_version: Option<MaybeWorkspaceRustVersion>, rust_version: Option<MaybeWorkspaceRustVersion>,
name: InternedString, name: InternedString,
version: MaybeWorkspaceSemverVersion, version: Option<MaybeWorkspaceSemverVersion>,
authors: Option<MaybeWorkspaceVecString>, authors: Option<MaybeWorkspaceVecString>,
build: Option<StringOrBool>, build: Option<StringOrBool>,
metabuild: Option<StringOrVec>, metabuild: Option<StringOrVec>,

View File

@ -109,6 +109,8 @@ resolve dependencies, and for guidelines on setting your own version. See the
[SemVer compatibility] chapter for more details on exactly what constitutes a [SemVer compatibility] chapter for more details on exactly what constitutes a
breaking change. breaking change.
This field is optional and defaults to `0.0.0`.
[Resolver]: resolver.md [Resolver]: resolver.md
[SemVer compatibility]: semver.md [SemVer compatibility]: semver.md

View File

@ -1506,22 +1506,17 @@ fn versionless_package() {
[package] [package]
name = "foo" name = "foo"
description = "foo" description = "foo"
publish = false
"#, "#,
) )
.file("src/lib.rs", "") .file("src/lib.rs", "")
.build(); .build();
p.cargo("check") p.cargo("check")
.with_stderr( .with_stderr(
r#"error: failed to parse manifest at `[CWD]/Cargo.toml` "\
[CHECKING] foo v0.0.0 ([CWD])
Caused by: [FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
TOML parse error at line 2, column 17 ",
|
2 | [package]
| ^^^^^^^^^^^^^^^^^^^^^^^^^
missing field `version`
"#,
) )
.with_status(101)
.run(); .run();
} }

View File

@ -4273,6 +4273,7 @@ fn versionless_packages() {
r#" r#"
[package] [package]
name = "bar" name = "bar"
publish = false
[dependencies] [dependencies]
foobar = "0.0.1" foobar = "0.0.1"
@ -4285,6 +4286,7 @@ fn versionless_packages() {
r#" r#"
[package] [package]
name = "baz" name = "baz"
publish = false
[dependencies] [dependencies]
foobar = "0.0.1" foobar = "0.0.1"
@ -4295,20 +4297,247 @@ fn versionless_packages() {
Package::new("foobar", "0.0.1").publish(); Package::new("foobar", "0.0.1").publish();
p.cargo("metadata -q --format-version 1") p.cargo("metadata -q --format-version 1")
.with_stderr( .with_json(
r#"error: failed to load manifest for workspace member `[CWD]/bar` r#"
{
Caused by: "packages": [
failed to parse manifest at `[CWD]/bar/Cargo.toml` {
"name": "bar",
Caused by: "version": "0.0.0",
TOML parse error at line 2, column 17 "id": "bar 0.0.0 [..]",
| "license": null,
2 | [package] "license_file": null,
| ^^^^^^^^^^^^^^^^^^^^^^^^^ "description": null,
missing field `version` "source": null,
"dependencies": [
{
"name": "baz",
"source": null,
"req": "*",
"kind": null,
"rename": null,
"optional": false,
"uses_default_features": true,
"features": [],
"target": null,
"registry": null,
"path": "[..]/baz"
},
{
"name": "foobar",
"source": "registry+https://github.com/rust-lang/crates.io-index",
"req": "^0.0.1",
"kind": null,
"rename": null,
"optional": false,
"uses_default_features": true,
"features": [],
"target": null,
"registry": null
}
],
"targets": [
{
"kind": [
"lib"
],
"crate_types": [
"lib"
],
"name": "bar",
"src_path": "[..]/bar/src/lib.rs",
"edition": "2015",
"doc": true,
"doctest": true,
"test": true
}
],
"features": {},
"manifest_path": "[..]/bar/Cargo.toml",
"metadata": null,
"publish": [],
"authors": [],
"categories": [],
"keywords": [],
"readme": null,
"repository": null,
"homepage": null,
"documentation": null,
"edition": "2015",
"links": null,
"default_run": null,
"rust_version": null
},
{
"name": "baz",
"version": "0.0.0",
"id": "baz 0.0.0 [..]",
"license": null,
"license_file": null,
"description": null,
"source": null,
"dependencies": [
{
"name": "foobar",
"source": "registry+https://github.com/rust-lang/crates.io-index",
"req": "^0.0.1",
"kind": null,
"rename": null,
"optional": false,
"uses_default_features": true,
"features": [],
"target": null,
"registry": null
}
],
"targets": [
{
"kind": [
"lib"
],
"crate_types": [
"lib"
],
"name": "baz",
"src_path": "[..]/baz/src/lib.rs",
"edition": "2015",
"doc": true,
"doctest": true,
"test": true
}
],
"features": {},
"manifest_path": "[..]/baz/Cargo.toml",
"metadata": null,
"publish": [],
"authors": [],
"categories": [],
"keywords": [],
"readme": null,
"repository": null,
"homepage": null,
"documentation": null,
"edition": "2015",
"links": null,
"default_run": null,
"rust_version": null
},
{
"name": "foobar",
"version": "0.0.1",
"id": "foobar 0.0.1 [..]",
"license": null,
"license_file": null,
"description": null,
"source": "registry+https://github.com/rust-lang/crates.io-index",
"dependencies": [],
"targets": [
{
"kind": [
"lib"
],
"crate_types": [
"lib"
],
"name": "foobar",
"src_path": "[..]/foobar-0.0.1/src/lib.rs",
"edition": "2015",
"doc": true,
"doctest": true,
"test": true
}
],
"features": {},
"manifest_path": "[..]/foobar-0.0.1/Cargo.toml",
"metadata": null,
"publish": null,
"authors": [],
"categories": [],
"keywords": [],
"readme": null,
"repository": null,
"homepage": null,
"documentation": null,
"edition": "2015",
"links": null,
"default_run": null,
"rust_version": null
}
],
"workspace_members": [
"bar 0.0.0 [..]",
"baz 0.0.0 [..]"
],
"workspace_default_members": [
"bar 0.0.0 [..]",
"baz 0.0.0 [..]"
],
"resolve": {
"nodes": [
{
"id": "bar 0.0.0 [..]",
"dependencies": [
"baz 0.0.0 [..]",
"foobar 0.0.1 [..]"
],
"deps": [
{
"name": "baz",
"pkg": "baz 0.0.0 [..]",
"dep_kinds": [
{
"kind": null,
"target": null
}
]
},
{
"name": "foobar",
"pkg": "foobar 0.0.1 [..]",
"dep_kinds": [
{
"kind": null,
"target": null
}
]
}
],
"features": []
},
{
"id": "baz 0.0.0 [..]",
"dependencies": [
"foobar 0.0.1 [..]"
],
"deps": [
{
"name": "foobar",
"pkg": "foobar 0.0.1 [..]",
"dep_kinds": [
{
"kind": null,
"target": null
}
]
}
],
"features": []
},
{
"id": "foobar 0.0.1 [..]",
"dependencies": [],
"deps": [],
"features": []
}
],
"root": null
},
"target_directory": "[..]/foo/target",
"version": 1,
"workspace_root": "[..]",
"metadata": null
}
"#, "#,
) )
.with_status(101)
.run(); .run();
} }

View File

@ -3105,6 +3105,7 @@ fn versionless_package() {
[package] [package]
name = "foo" name = "foo"
description = "foo" description = "foo"
publish = false
"#, "#,
) )
.file("src/main.rs", r#"fn main() { println!("hello"); }"#) .file("src/main.rs", r#"fn main() { println!("hello"); }"#)
@ -3112,16 +3113,23 @@ fn versionless_package() {
p.cargo("package") p.cargo("package")
.with_stderr( .with_stderr(
r#"error: failed to parse manifest at `[CWD]/Cargo.toml` "\
warning: manifest has no license, license-file, documentation, homepage or repository.
Caused by: See https://doc.rust-lang.org/cargo/reference/manifest.html#package-metadata for more info.
TOML parse error at line 2, column 17 Packaging foo v0.0.0 ([CWD])
| Verifying foo v0.0.0 ([CWD])
2 | [package] Compiling foo v0.0.0 ([CWD]/target/package/foo-0.0.0)
| ^^^^^^^^^^^^^^^^^^^^^^^^^ Finished dev [unoptimized + debuginfo] target(s) in [..]s
missing field `version` Packaged 4 files, [..]B ([..]B compressed)
"#, ",
) )
.with_status(101)
.run(); .run();
let f = File::open(&p.root().join("target/package/foo-0.0.0.crate")).unwrap();
validate_crate_contents(
f,
"foo-0.0.0.crate",
&["Cargo.lock", "Cargo.toml", "Cargo.toml.orig", "src/main.rs"],
&[],
);
} }

View File

@ -3007,6 +3007,9 @@ Caused by:
#[cargo_test] #[cargo_test]
fn versionless_package() { fn versionless_package() {
// Use local registry for faster test times since no publish will occur
let registry = registry::init();
let p = project() let p = project()
.file( .file(
"Cargo.toml", "Cargo.toml",
@ -3020,17 +3023,15 @@ fn versionless_package() {
.build(); .build();
p.cargo("publish") p.cargo("publish")
.replace_crates_io(registry.index_url())
.with_status(101)
.with_stderr( .with_stderr(
r#"error: failed to parse manifest at `[CWD]/Cargo.toml` "\
error: failed to parse manifest at `[CWD]/Cargo.toml`
Caused by: Caused by:
TOML parse error at line 2, column 17 `package.publish` requires `package.version` be specified
| ",
2 | [package]
| ^^^^^^^^^^^^^^^^^^^^^^^^^
missing field `version`
"#,
) )
.with_status(101)
.run(); .run();
} }