diff --git a/src/cargo/core/manifest.rs b/src/cargo/core/manifest.rs index 13801b7e2..c72ee2313 100644 --- a/src/cargo/core/manifest.rs +++ b/src/cargo/core/manifest.rs @@ -45,6 +45,7 @@ pub struct ManifestMetadata { pub authors: Vec, pub keywords: Vec, pub license: Option, + pub license_file: Option, pub description: Option, // not markdown pub readme: Option, // file, not contents pub homepage: Option, // url diff --git a/src/cargo/ops/cargo_package.rs b/src/cargo/ops/cargo_package.rs index 95bb5a717..0e6336aad 100644 --- a/src/cargo/ops/cargo_package.rs +++ b/src/cargo/ops/cargo_package.rs @@ -75,15 +75,15 @@ fn check_metadata(pkg: &Package, shell: &mut MultiShell) -> CargoResult<()> { let mut missing = vec![]; macro_rules! lacking { - ($($field: ident),*) => {{ + ($( $($field: ident)||* ),*) => {{ $( - if md.$field.as_ref().map_or(true, |s| s.is_empty()) { - missing.push(stringify!($field)) + if $(md.$field.as_ref().map_or(true, |s| s.is_empty()))&&* { + $(missing.push(stringify!($field).replace("_", "-"));)* } - )* + )* }} } - lacking!(description, license) + lacking!(description, license || license_file) if !missing.is_empty() { let mut things = missing.slice_to(missing.len() - 1).connect(", "); @@ -91,10 +91,10 @@ fn check_metadata(pkg: &Package, shell: &mut MultiShell) -> CargoResult<()> { if !things.is_empty() { things.push_str(" or "); } - things.push_str(*missing.last().unwrap()); + things.push_str(missing.last().unwrap().as_slice()); try!(shell.warn( - format!("Warning: manifest has no {things}. \ + format!("warning: manifest has no {things}. \ See http://doc.crates.io/manifest.html#package-metadata for more info.", things = things).as_slice())) } diff --git a/src/cargo/ops/registry.rs b/src/cargo/ops/registry.rs index e042d0765..3886b4d6c 100644 --- a/src/cargo/ops/registry.rs +++ b/src/cargo/ops/registry.rs @@ -1,5 +1,6 @@ use std::collections::HashMap; use std::io::File; +use std::io::fs::PathExtensions; use std::os; use term::color::BLACK; @@ -87,7 +88,7 @@ fn transmit(pkg: &Package, tarball: &Path, registry: &mut Registry) let manifest = pkg.get_manifest(); let ManifestMetadata { ref authors, ref description, ref homepage, ref documentation, - ref keywords, ref readme, ref repository, ref license, + ref keywords, ref readme, ref repository, ref license, ref license_file, } = *manifest.get_metadata(); let readme = match *readme { Some(ref readme) => { @@ -98,6 +99,15 @@ fn transmit(pkg: &Package, tarball: &Path, registry: &mut Registry) } None => None, }; + match *license_file { + Some(ref file) => { + if !pkg.get_root().join(file).exists() { + return Err(human(format!("the license file `{}` does not exist", + file))) + } + } + None => {} + } registry.publish(&NewCrate { name: pkg.get_name().to_string(), vers: pkg.get_version().to_string(), @@ -111,6 +121,7 @@ fn transmit(pkg: &Package, tarball: &Path, registry: &mut Registry) readme: readme, repository: repository.clone(), license: license.clone(), + license_file: license_file.clone(), }, tarball).map_err(|e| { human(e.to_string()) }) diff --git a/src/cargo/util/toml.rs b/src/cargo/util/toml.rs index e5a7fb1b4..82d240745 100644 --- a/src/cargo/util/toml.rs +++ b/src/cargo/util/toml.rs @@ -267,6 +267,7 @@ pub struct TomlProject { readme: Option, keywords: Option>, license: Option, + license_file: Option, repository: Option, } @@ -518,6 +519,7 @@ impl TomlManifest { readme: project.readme.clone(), authors: project.authors.clone(), license: project.license.clone(), + license_file: project.license_file.clone(), repository: project.repository.clone(), keywords: project.keywords.clone().unwrap_or(Vec::new()), }; @@ -541,6 +543,11 @@ impl TomlManifest { manifest.add_warning(format!(" For more information, see \ http://doc.crates.io/build-script.html")); } + if project.license_file.is_some() && project.license.is_some() { + manifest.add_warning(format!("warning: only one of `license` or \ + `license-file` is necessary")); + } + Ok((manifest, nested_paths)) } } diff --git a/src/doc/manifest.md b/src/doc/manifest.md index b25c69e00..f86484958 100644 --- a/src/doc/manifest.md +++ b/src/doc/manifest.md @@ -82,9 +82,14 @@ keywords = ["...", "..."] # This is a string description of the license for this package. Currently # crates.io will validate the license provided against a whitelist of known -# license identifiers from http://spdx.org/licenses/. Multiple licenses can +# license identifiers from http://spdx.org/licenses/. Multiple licenses can # be separated with a `/` license = "..." + +# If a project is using a nonstandard license, then this key may be specified in +# lieu of the above key and must point to a file relative to this manifest +# (similar to the readme key) +license-file = "..." ``` The [crates.io](https://crates.io) registry will render the description, display diff --git a/src/registry/lib.rs b/src/registry/lib.rs index 39f5965a7..d2952ae0c 100644 --- a/src/registry/lib.rs +++ b/src/registry/lib.rs @@ -55,6 +55,7 @@ pub struct NewCrate { pub readme: Option, pub keywords: Vec, pub license: Option, + pub license_file: Option, pub repository: Option, } diff --git a/tests/test_cargo_package.rs b/tests/test_cargo_package.rs index 57f2e64e9..c3f2eccad 100644 --- a/tests/test_cargo_package.rs +++ b/tests/test_cargo_package.rs @@ -80,8 +80,9 @@ test!(metadata_warning { verifying = VERIFYING, compiling = COMPILING, dir = p.url()).as_slice()) - .with_stderr("Warning: manifest has no description or license. See \ - http://doc.crates.io/manifest.html#package-metadata for more info.")); + .with_stderr("\ +warning: manifest has no description, license or license-file. See \ +http://doc.crates.io/manifest.html#package-metadata for more info.")); let p = project("one") .file("Cargo.toml", r#" @@ -104,8 +105,9 @@ test!(metadata_warning { verifying = VERIFYING, compiling = COMPILING, dir = p.url()).as_slice()) - .with_stderr("Warning: manifest has no description. See \ - http://doc.crates.io/manifest.html#package-metadata for more info.")); + .with_stderr("\ +warning: manifest has no description. See \ +http://doc.crates.io/manifest.html#package-metadata for more info.")); let p = project("both") .file("Cargo.toml", format!(r#" diff --git a/tests/test_cargo_registry.rs b/tests/test_cargo_registry.rs index 3fc4f7f8e..366453c7a 100644 --- a/tests/test_cargo_registry.rs +++ b/tests/test_cargo_registry.rs @@ -480,3 +480,22 @@ test!(login_with_no_cargo_dir { .env("HOME", Some(home)), execs().with_status(0)); }) + +test!(bad_license_file { + let p = project("all") + .file("Cargo.toml", r#" + [project] + name = "foo" + version = "0.0.1" + authors = [] + license-file = "foo" + description = "bar" + "#) + .file("src/main.rs", r#" + fn main() {} + "#); + assert_that(p.cargo_process("publish"), + execs().with_status(101) + .with_stderr("\ +the license file `foo` does not exist")); +})