Add feature gate on publish field changes.
authorChris Swindle <christopher.swindle@metaswitch.com>
Tue, 31 Oct 2017 09:51:37 +0000 (09:51 +0000)
committerChris Swindle <christopher.swindle@metaswitch.com>
Tue, 31 Oct 2017 09:51:37 +0000 (09:51 +0000)
src/bin/package.rs
src/cargo/core/package.rs
src/cargo/ops/cargo_package.rs
src/cargo/ops/registry.rs
src/cargo/util/toml/mod.rs
tests/publish.rs

index 31e3330ad5f6a486528ff1823fc68a07cc4e6742..9c91583d0e8184f59c514410fa9bb096ff2acb09 100644 (file)
@@ -61,6 +61,7 @@ pub fn execute(options: Options, config: &mut Config) -> CliResult {
         allow_dirty: options.flag_allow_dirty,
         target: options.flag_target.as_ref().map(|t| &t[..]),
         jobs: options.flag_jobs,
+        registry: None,
     })?;
     Ok(())
 }
index 57e0f700e1d0d8e7a626370f65bd688093391ab0..1edc51b03eab391d5c95f076043712bc7877ef8e 100644 (file)
@@ -134,10 +134,10 @@ impl Package {
         }
     }
 
-    pub fn to_registry_toml(&self) -> String {
+    pub fn to_registry_toml(&self) -> CargoResult<String> {
         let manifest = self.manifest().original().prepare_for_publish();
-        let toml = toml::to_string(&manifest).unwrap();
-        format!("\
+        let toml = toml::to_string(&manifest)?;
+        Ok(format!("\
             # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO\n\
             #\n\
             # When uploading crates to the registry Cargo will automatically\n\
@@ -151,7 +151,7 @@ impl Package {
             # will likely look very different (and much more reasonable)\n\
             \n\
             {}\
-        ", toml)
+        ", toml))
     }
 }
 
index f12ce12f35a70decb723660756be0ac2cfe2d60b..04c3f6d971c29ee2ea6417781a0eec8a4f46e049 100644 (file)
@@ -23,13 +23,17 @@ pub struct PackageOpts<'cfg> {
     pub verify: bool,
     pub jobs: Option<u32>,
     pub target: Option<&'cfg str>,
+    pub registry: Option<String>,
 }
 
 pub fn package(ws: &Workspace,
                opts: &PackageOpts) -> CargoResult<Option<FileLock>> {
     let pkg = ws.current()?;
     let config = ws.config();
-    if !pkg.manifest().features().activated().is_empty() {
+
+    // Allow packaging if a registry has been provided, or if there are no nightly
+    // features enabled.
+    if opts.registry.is_none() && !pkg.manifest().features().activated().is_empty() {
         bail!("cannot package or publish crates which activate nightly-only \
                cargo features")
     }
@@ -251,7 +255,7 @@ fn tar(ws: &Workspace,
             })?;
 
             let mut header = Header::new_ustar();
-            let toml = pkg.to_registry_toml();
+            let toml = pkg.to_registry_toml()?;
             header.set_path(&path)?;
             header.set_entry_type(EntryType::file());
             header.set_mode(0o644);
index 2bd696a34ead23919a67626663f3d14889330327..a7e8ef82b72b89ddf5b1a5f28d0eef3257bd6ec1 100755 (executable)
@@ -69,6 +69,7 @@ pub fn publish(ws: &Workspace, opts: &PublishOpts) -> CargoResult<()> {
         allow_dirty: opts.allow_dirty,
         target: opts.target,
         jobs: opts.jobs,
+        registry: opts.registry.clone(),
     })?.unwrap();
 
     // Upload said tarball to the specified destination
index 622c2674c0ec81a6ae0851ff8fe5643447f6085a..d3f9864cd8c83dd5c8c4fc442d476295cead171b 100644 (file)
@@ -200,6 +200,8 @@ pub struct DetailedTomlDependency {
 
 #[derive(Debug, Deserialize, Serialize)]
 pub struct TomlManifest {
+    #[serde(rename = "cargo-features")]
+    cargo_features: Option<Vec<String>>,
     package: Option<Box<TomlProject>>,
     project: Option<Box<TomlProject>>,
     profile: Option<TomlProfiles>,
@@ -223,8 +225,6 @@ pub struct TomlManifest {
     patch: Option<BTreeMap<String, BTreeMap<String, TomlDependency>>>,
     workspace: Option<TomlWorkspace>,
     badges: Option<BTreeMap<String, BTreeMap<String, String>>>,
-    #[serde(rename = "cargo-features")]
-    cargo_features: Option<Vec<String>>,
 }
 
 #[derive(Deserialize, Serialize, Clone, Debug, Default)]
@@ -694,7 +694,12 @@ impl TomlManifest {
         };
         let profiles = build_profiles(&me.profile);
         let publish = match project.publish {
-            Some(VecStringOrBool::VecString(ref vecstring)) => Some(vecstring.clone()),
+            Some(VecStringOrBool::VecString(ref vecstring)) => {
+                features.require(Feature::alternative_registries()).chain_err(|| {
+                    "the `publish` manifest key is unstable for anything other than a value of true or false"
+                })?;
+                Some(vecstring.clone())
+            },
             Some(VecStringOrBool::Bool(false)) => Some(vec![]),
             _ => None,
         };
index 96aae5a3e04d82139b97efe3dc7d48ca65849311..d4af2e99a8570f45c044cdf71fe76670caf1969a 100755 (executable)
@@ -502,12 +502,48 @@ See [..]
     assert!(!publish::upload_path().join("api/v1/crates/new").exists());
 }
 
+#[test]
+fn block_publish_feature_not_enabled() {
+    publish::setup();
+
+    let p = project("foo")
+        .file("Cargo.toml", r#"
+            [project]
+            name = "foo"
+            version = "0.0.1"
+            authors = []
+            license = "MIT"
+            description = "foo"
+            publish = [
+                "test"
+            ]
+        "#)
+        .file("src/main.rs", "fn main() {}")
+        .build();
+
+    assert_that(p.cargo("publish").masquerade_as_nightly_cargo()
+                 .arg("--registry").arg("alternative").arg("-Zunstable-options"),
+                execs().with_status(101).with_stderr("\
+error: failed to parse manifest at `[..]`
+
+Caused by:
+  the `publish` manifest key is unstable for anything other than a value of true or false
+
+Caused by:
+  feature `alternative-registries` is required
+
+consider adding `cargo-features = [\"alternative-registries\"]` to the manifest
+"));
+}
+
 #[test]
 fn registry_not_in_publish_list() {
     publish::setup();
 
     let p = project("foo")
         .file("Cargo.toml", r#"
+            cargo-features = ["alternative-registries"]
+
             [project]
             name = "foo"
             version = "0.0.1"
@@ -535,6 +571,8 @@ fn publish_empty_list() {
 
     let p = project("foo")
         .file("Cargo.toml", r#"
+            cargo-features = ["alternative-registries"]
+
             [project]
             name = "foo"
             version = "0.0.1"
@@ -562,6 +600,8 @@ fn publish_allowed_registry() {
 
     let _ = repo(&paths::root().join("foo"))
         .file("Cargo.toml", r#"
+            cargo-features = ["alternative-registries"]
+
             [project]
             name = "foo"
             version = "0.0.1"
@@ -586,6 +626,8 @@ fn block_publish_no_registry() {
 
     let p = project("foo")
         .file("Cargo.toml", r#"
+            cargo-features = ["alternative-registries"]
+
             [project]
             name = "foo"
             version = "0.0.1"