Auto merge of #9508 - dtolnay-contrib:semver, r=ehuss

Update to semver 1.0.0

I am working on a 1.0.0 of the `semver` crate some time this week. It would be good to confirm Cargo will be able to use it, beforehand!

It's a from-scratch rewrite, but https://github.com/dtolnay/semver/issues/237 has code to compare against 0.10.0 (currently used by Cargo) how every possible version requirement currently published to crates.io matches against every possible crate version. The differences are all broken syntax like `^0-.11.0` previously parsing with ".11.0" as a pre-release string (which is invalid, because pre-release are not allowed to contain empty dot-separated identifiers) and `~2.0-2.2` previously parsing with "2.2" as a pre-release string, when the user almost certainly meant `>=2.0, <=2.2`. I'm not sure how much of those you want to add code into Cargo to preserve behavior, but I would be happy to do it.
This commit is contained in:
bors 2021-05-27 22:34:28 +00:00
commit 2f3df16921
18 changed files with 148 additions and 255 deletions

View file

@ -50,7 +50,7 @@ num_cpus = "1.0"
opener = "0.4"
percent-encoding = "2.0"
rustfix = "0.5.0"
semver = { version = "0.10", features = ["serde"] }
semver = { version = "1.0", features = ["serde"] }
serde = { version = "1.0.123", features = ["derive"] }
serde_ignored = "0.1.0"
serde_json = { version = "1.0.30", features = ["raw_value"] }

View file

@ -506,7 +506,7 @@ pub trait ToDep {
impl ToDep for &'static str {
fn to_dep(self) -> Dependency {
Dependency::parse_no_deprecated(self, Some("1.0.0"), registry_loc()).unwrap()
Dependency::parse(self, Some("1.0.0"), registry_loc()).unwrap()
}
}
@ -626,7 +626,7 @@ pub fn dep(name: &str) -> Dependency {
dep_req(name, "*")
}
pub fn dep_req(name: &str, req: &str) -> Dependency {
Dependency::parse_no_deprecated(name, Some(req), registry_loc()).unwrap()
Dependency::parse(name, Some(req), registry_loc()).unwrap()
}
pub fn dep_req_kind(name: &str, req: &str, kind: DepKind, public: bool) -> Dependency {
let mut dep = dep_req(name, req);
@ -639,7 +639,7 @@ pub fn dep_loc(name: &str, location: &str) -> Dependency {
let url = location.into_url().unwrap();
let master = GitReference::Branch("master".to_string());
let source_id = SourceId::for_git(&url, master).unwrap();
Dependency::parse_no_deprecated(name, Some("1.0.0"), source_id).unwrap()
Dependency::parse(name, Some("1.0.0"), source_id).unwrap()
}
pub fn dep_kind(name: &str, kind: DepKind) -> Dependency {
dep(name).set_kind(kind).clone()

View file

@ -5,7 +5,6 @@ use std::path::PathBuf;
use cargo_platform::CfgExpr;
use cargo_util::{paths, ProcessBuilder};
use semver::Version;
use super::BuildContext;
use crate::core::compiler::{CompileKind, Metadata, Unit};
@ -316,10 +315,7 @@ impl<'cfg> Compilation<'cfg> {
.env("CARGO_PKG_VERSION_MAJOR", &pkg.version().major.to_string())
.env("CARGO_PKG_VERSION_MINOR", &pkg.version().minor.to_string())
.env("CARGO_PKG_VERSION_PATCH", &pkg.version().patch.to_string())
.env(
"CARGO_PKG_VERSION_PRE",
&pre_version_component(pkg.version()),
)
.env("CARGO_PKG_VERSION_PRE", pkg.version().pre.as_str())
.env("CARGO_PKG_VERSION", &pkg.version().to_string())
.env("CARGO_PKG_NAME", &*pkg.name())
.env(
@ -368,23 +364,6 @@ fn fill_rustc_tool_env(mut cmd: ProcessBuilder, unit: &Unit) -> ProcessBuilder {
cmd
}
fn pre_version_component(v: &Version) -> String {
if v.pre.is_empty() {
return String::new();
}
let mut ret = String::new();
for (i, x) in v.pre.iter().enumerate() {
if i != 0 {
ret.push('.')
};
ret.push_str(&x.to_string());
}
ret
}
fn target_runner(
bcx: &BuildContext<'_, '_>,
kind: CompileKind,

View file

@ -595,7 +595,7 @@ fn hash_rustc_version(bcx: &BuildContext<'_, '_>, hasher: &mut StableHasher) {
//
// This assumes that the first segment is the important bit ("nightly",
// "beta", "dev", etc.). Skip other parts like the `.3` in `-beta.3`.
vers.pre[0].hash(hasher);
vers.pre.split('.').next().hash(hasher);
// Keep "host" since some people switch hosts to implicitly change
// targets, (like gnu vs musl or gnu vs msvc). In the future, we may want
// to consider hashing `unit.kind.short_name()` instead.

View file

@ -47,7 +47,7 @@ pub fn resolve_std<'cfg>(
.iter()
.map(|&name| {
let source_path = SourceId::for_path(&src_path.join("library").join(name))?;
let dep = Dependency::parse_no_deprecated(name, None, source_path)?;
let dep = Dependency::parse(name, None, source_path)?;
Ok(dep)
})
.collect::<CargoResult<Vec<_>>>()?;

View file

@ -1,7 +1,5 @@
use anyhow::Context as _;
use cargo_platform::Platform;
use log::trace;
use semver::ReqParseError;
use semver::VersionReq;
use serde::ser;
use serde::Serialize;
@ -11,17 +9,17 @@ use std::rc::Rc;
use crate::core::{PackageId, SourceId, Summary};
use crate::util::errors::CargoResult;
use crate::util::interning::InternedString;
use crate::util::Config;
use crate::util::OptVersionReq;
/// Information about a dependency requested by a Cargo manifest.
/// Cheap to copy.
#[derive(PartialEq, Eq, Hash, Ord, PartialOrd, Clone, Debug)]
#[derive(PartialEq, Eq, Hash, Clone, Debug)]
pub struct Dependency {
inner: Rc<Inner>,
}
/// The data underlying a `Dependency`.
#[derive(PartialEq, Eq, Hash, Ord, PartialOrd, Clone, Debug)]
#[derive(PartialEq, Eq, Hash, Clone, Debug)]
struct Inner {
name: InternedString,
source_id: SourceId,
@ -32,7 +30,7 @@ struct Inner {
/// `registry` is specified. Or in the case of a crates.io dependency,
/// `source_id` will be crates.io and this will be None.
registry_id: Option<SourceId>,
req: VersionReq,
req: OptVersionReq,
specified_req: bool,
kind: DepKind,
only_match_name: bool,
@ -99,52 +97,6 @@ pub enum DepKind {
Build,
}
fn parse_req_with_deprecated(
name: InternedString,
req: &str,
extra: Option<(PackageId, &Config)>,
) -> CargoResult<VersionReq> {
match VersionReq::parse(req) {
Err(ReqParseError::DeprecatedVersionRequirement(requirement)) => {
let (inside, config) = match extra {
Some(pair) => pair,
None => return Err(ReqParseError::DeprecatedVersionRequirement(requirement).into()),
};
let msg = format!(
"\
parsed version requirement `{}` is no longer valid
Previous versions of Cargo accepted this malformed requirement,
but it is being deprecated. This was found when parsing the manifest
of {} {}, and the correct version requirement is `{}`.
This will soon become a hard error, so it's either recommended to
update to a fixed version or contact the upstream maintainer about
this warning.
",
req,
inside.name(),
inside.version(),
requirement
);
config.shell().warn(&msg)?;
Ok(requirement)
}
Err(e) => {
let err: CargoResult<VersionReq> = Err(e.into());
let v: VersionReq = err.with_context(|| {
format!(
"failed to parse the version requirement `{}` for dependency `{}`",
req, name
)
})?;
Ok(v)
}
Ok(v) => Ok(v),
}
}
impl ser::Serialize for DepKind {
fn serialize<S>(&self, s: S) -> Result<S::Ok, S::Error>
where
@ -165,36 +117,19 @@ impl Dependency {
name: impl Into<InternedString>,
version: Option<&str>,
source_id: SourceId,
inside: PackageId,
config: &Config,
) -> CargoResult<Dependency> {
let name = name.into();
let arg = Some((inside, config));
let (specified_req, version_req) = match version {
Some(v) => (true, parse_req_with_deprecated(name, v, arg)?),
None => (false, VersionReq::any()),
};
let mut ret = Dependency::new_override(name, source_id);
{
let ptr = Rc::make_mut(&mut ret.inner);
ptr.only_match_name = false;
ptr.req = version_req;
ptr.specified_req = specified_req;
}
Ok(ret)
}
/// Attempt to create a `Dependency` from an entry in the manifest.
pub fn parse_no_deprecated(
name: impl Into<InternedString>,
version: Option<&str>,
source_id: SourceId,
) -> CargoResult<Dependency> {
let name = name.into();
let (specified_req, version_req) = match version {
Some(v) => (true, parse_req_with_deprecated(name, v, None)?),
None => (false, VersionReq::any()),
Some(v) => match VersionReq::parse(v) {
Ok(req) => (true, OptVersionReq::Req(req)),
Err(err) => {
return Err(anyhow::Error::new(err).context(format!(
"failed to parse the version requirement `{}` for dependency `{}`",
v, name,
)))
}
},
None => (false, OptVersionReq::Any),
};
let mut ret = Dependency::new_override(name, source_id);
@ -214,7 +149,7 @@ impl Dependency {
name,
source_id,
registry_id: None,
req: VersionReq::any(),
req: OptVersionReq::Any,
kind: DepKind::Normal,
only_match_name: true,
optional: false,
@ -228,7 +163,7 @@ impl Dependency {
}
}
pub fn version_req(&self) -> &VersionReq {
pub fn version_req(&self) -> &OptVersionReq {
&self.inner.req
}
@ -365,7 +300,7 @@ impl Dependency {
/// Sets the version requirement for this dependency.
pub fn set_version_req(&mut self, req: VersionReq) -> &mut Dependency {
Rc::make_mut(&mut self.inner).req = req;
Rc::make_mut(&mut self.inner).req = OptVersionReq::Req(req);
self
}
@ -394,7 +329,7 @@ impl Dependency {
id
);
let me = Rc::make_mut(&mut self.inner);
me.req = VersionReq::exact(id.version());
me.req = OptVersionReq::exact(id.version());
// Only update the `precise` of this source to preserve other
// information about dependency's source which may not otherwise be

View file

@ -5,7 +5,7 @@ use crate::core::{Dependency, PackageId, Source, SourceId, SourceMap, Summary};
use crate::sources::config::SourceConfigMap;
use crate::util::errors::CargoResult;
use crate::util::interning::InternedString;
use crate::util::{profile, CanonicalUrl, Config};
use crate::util::{profile, CanonicalUrl, Config, VersionReqExt};
use anyhow::{bail, Context as _};
use log::{debug, trace};
use semver::VersionReq;

View file

@ -2,7 +2,7 @@ use std::fmt;
use crate::core::{Dependency, PackageId, Registry, Summary};
use crate::util::lev_distance::lev_distance;
use crate::util::Config;
use crate::util::{Config, VersionExt};
use anyhow::Error;
use super::context::Context;

View file

@ -396,7 +396,6 @@ impl<'cfg> Workspace<'cfg> {
.map(|(name, dep)| {
dep.to_dependency_split(
name,
/* pkg_id */ None,
source,
&mut nested_paths,
self.config,

View file

@ -8,7 +8,7 @@ use crate::core::{Dependency, Edition, Package, PackageId, Source, SourceId, Wor
use crate::ops::common_for_install_and_uninstall::*;
use crate::sources::{GitSource, PathSource, SourceConfigMap};
use crate::util::errors::CargoResult;
use crate::util::{Config, Filesystem, Rustc, ToSemver};
use crate::util::{Config, Filesystem, Rustc, ToSemver, VersionReqExt};
use crate::{drop_println, ops};
use anyhow::{bail, format_err, Context as _};
@ -180,11 +180,7 @@ fn install_one(
} else {
None
};
Some(Dependency::parse_no_deprecated(
krate,
vers.as_deref(),
source_id,
)?)
Some(Dependency::parse(krate, vers.as_deref(), source_id)?)
} else {
None
}

View file

@ -70,11 +70,11 @@ use crate::core::dependency::Dependency;
use crate::core::{PackageId, SourceId, Summary};
use crate::sources::registry::{RegistryData, RegistryPackage, INDEX_V_MAX};
use crate::util::interning::InternedString;
use crate::util::{internal, CargoResult, Config, Filesystem, ToSemver};
use crate::util::{internal, CargoResult, Config, Filesystem, OptVersionReq, ToSemver};
use anyhow::bail;
use cargo_util::paths;
use log::{debug, info};
use semver::{Version, VersionReq};
use semver::Version;
use std::collections::{HashMap, HashSet};
use std::convert::TryInto;
use std::fs;
@ -264,7 +264,7 @@ impl<'cfg> RegistryIndex<'cfg> {
/// Returns the hash listed for a specified `PackageId`.
pub fn hash(&mut self, pkg: PackageId, load: &mut dyn RegistryData) -> CargoResult<&str> {
let req = VersionReq::exact(pkg.version());
let req = OptVersionReq::exact(pkg.version());
let summary = self
.summaries(pkg.name(), &req, load)?
.next()
@ -285,7 +285,7 @@ impl<'cfg> RegistryIndex<'cfg> {
pub fn summaries<'a, 'b>(
&'a mut self,
name: InternedString,
req: &'b VersionReq,
req: &'b OptVersionReq,
load: &mut dyn RegistryData,
) -> CargoResult<impl Iterator<Item = &'a IndexSummary> + 'b>
where
@ -489,7 +489,7 @@ impl<'cfg> RegistryIndex<'cfg> {
}
pub fn is_yanked(&mut self, pkg: PackageId, load: &mut dyn RegistryData) -> CargoResult<bool> {
let req = VersionReq::exact(pkg.version());
let req = OptVersionReq::exact(pkg.version());
let found = self
.summaries(pkg.name(), &req, load)?
.any(|summary| summary.yanked);

View file

@ -168,7 +168,7 @@ use std::path::{Path, PathBuf};
use anyhow::Context as _;
use flate2::read::GzDecoder;
use log::debug;
use semver::{Version, VersionReq};
use semver::Version;
use serde::Deserialize;
use tar::Archive;
@ -179,7 +179,7 @@ use crate::sources::PathSource;
use crate::util::hex;
use crate::util::interning::InternedString;
use crate::util::into_url::IntoUrl;
use crate::util::{restricted_names, CargoResult, Config, Filesystem};
use crate::util::{restricted_names, CargoResult, Config, Filesystem, OptVersionReq};
const PACKAGE_SOURCE_LOCK: &str = ".cargo-ok";
pub const CRATES_IO_INDEX: &str = "https://github.com/rust-lang/crates.io-index";
@ -373,7 +373,7 @@ impl<'a> RegistryDependency<'a> {
default
};
let mut dep = Dependency::parse_no_deprecated(package.unwrap_or(name), Some(&req), id)?;
let mut dep = Dependency::parse(package.unwrap_or(name), Some(&req), id)?;
if package.is_some() {
dep.set_explicit_name_in_toml(name);
}
@ -671,7 +671,7 @@ impl<'cfg> RegistrySource<'cfg> {
// After we've loaded the package configure its summary's `checksum`
// field with the checksum we know for this `PackageId`.
let req = VersionReq::exact(package.version());
let req = OptVersionReq::exact(package.version());
let summary_with_cksum = self
.index
.summaries(package.name(), &req, &mut *self.ops)?

View file

@ -20,6 +20,7 @@ pub use self::progress::{Progress, ProgressStyle};
pub use self::queue::Queue;
pub use self::restricted_names::validate_package_name;
pub use self::rustc::Rustc;
pub use self::semver_ext::{OptVersionReq, VersionExt, VersionReqExt};
pub use self::to_semver::ToSemver;
pub use self::vcs::{existing_vcs_repo, FossilRepo, GitRepo, HgRepo, PijulRepo};
pub use self::workspace::{
@ -53,6 +54,7 @@ mod progress;
mod queue;
pub mod restricted_names;
pub mod rustc;
mod semver_ext;
pub mod to_semver;
pub mod toml;
mod vcs;

View file

@ -0,0 +1,76 @@
use semver::{Comparator, Op, Version, VersionReq};
use std::fmt::{self, Display};
#[derive(PartialEq, Eq, Hash, Clone, Debug)]
pub enum OptVersionReq {
Any,
Req(VersionReq),
}
pub trait VersionExt {
fn is_prerelease(&self) -> bool;
}
pub trait VersionReqExt {
fn exact(version: &Version) -> Self;
}
impl VersionExt for Version {
fn is_prerelease(&self) -> bool {
!self.pre.is_empty()
}
}
impl VersionReqExt for VersionReq {
fn exact(version: &Version) -> Self {
VersionReq {
comparators: vec![Comparator {
op: Op::Exact,
major: version.major,
minor: Some(version.minor),
patch: Some(version.patch),
pre: version.pre.clone(),
}],
}
}
}
impl OptVersionReq {
pub fn exact(version: &Version) -> Self {
OptVersionReq::Req(VersionReq::exact(version))
}
pub fn is_exact(&self) -> bool {
match self {
OptVersionReq::Any => false,
OptVersionReq::Req(req) => {
req.comparators.len() == 1 && {
let cmp = &req.comparators[0];
cmp.op == Op::Exact && cmp.minor.is_some() && cmp.patch.is_some()
}
}
}
}
pub fn matches(&self, version: &Version) -> bool {
match self {
OptVersionReq::Any => true,
OptVersionReq::Req(req) => req.matches(version),
}
}
}
impl Display for OptVersionReq {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
OptVersionReq::Any => formatter.write_str("*"),
OptVersionReq::Req(req) => Display::fmt(req, formatter),
}
}
}
impl From<VersionReq> for OptVersionReq {
fn from(req: VersionReq) -> Self {
OptVersionReq::Req(req)
}
}

View file

@ -13,7 +13,7 @@ impl ToSemver for Version {
impl<'a> ToSemver for &'a str {
fn to_semver(self) -> CargoResult<Version> {
match Version::parse(self) {
match Version::parse(self.trim()) {
Ok(v) => Ok(v),
Err(..) => Err(anyhow::format_err!("cannot parse '{}' as a semver", self)),
}

View file

@ -25,7 +25,9 @@ use crate::core::{GitReference, PackageIdSpec, SourceId, WorkspaceConfig, Worksp
use crate::sources::{CRATES_IO_INDEX, CRATES_IO_REGISTRY};
use crate::util::errors::{CargoResult, ManifestError};
use crate::util::interning::InternedString;
use crate::util::{self, config::ConfigRelativePath, validate_package_name, Config, IntoUrl};
use crate::util::{
self, config::ConfigRelativePath, validate_package_name, Config, IntoUrl, VersionReqExt,
};
mod targets;
use self::targets::targets;
@ -778,6 +780,30 @@ impl<'de> de::Deserialize<'de> for VecStringOrBool {
}
}
fn version_trim_whitespace<'de, D>(deserializer: D) -> Result<semver::Version, D::Error>
where
D: de::Deserializer<'de>,
{
struct Visitor;
impl<'de> de::Visitor<'de> for Visitor {
type Value = semver::Version;
fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.write_str("SemVer version")
}
fn visit_str<E>(self, string: &str) -> Result<Self::Value, E>
where
E: de::Error,
{
string.trim().parse().map_err(de::Error::custom)
}
}
deserializer.deserialize_str(Visitor)
}
/// Represents the `package`/`project` sections of a `Cargo.toml`.
///
/// Note that the order of the fields matters, since this is the order they
@ -790,6 +816,7 @@ pub struct TomlProject {
edition: Option<String>,
rust_version: Option<String>,
name: InternedString,
#[serde(deserialize_with = "version_trim_whitespace")]
version: semver::Version,
authors: Option<Vec<String>>,
build: Option<StringOrBool>,
@ -847,7 +874,6 @@ impl TomlProject {
}
struct Context<'a, 'b> {
pkgid: Option<PackageId>,
deps: &'a mut Vec<Dependency>,
source_id: SourceId,
nested_paths: &'a mut Vec<PathBuf>,
@ -1162,7 +1188,6 @@ impl TomlManifest {
{
let mut cx = Context {
pkgid: Some(pkgid),
deps: &mut deps,
source_id,
nested_paths: &mut nested_paths,
@ -1430,7 +1455,6 @@ impl TomlManifest {
let (replace, patch) = {
let mut cx = Context {
pkgid: None,
deps: &mut deps,
source_id,
nested_paths: &mut nested_paths,
@ -1626,7 +1650,6 @@ impl<P: ResolveToPath> TomlDependency<P> {
pub(crate) fn to_dependency_split(
&self,
name: &str,
pkgid: Option<PackageId>,
source_id: SourceId,
nested_paths: &mut Vec<PathBuf>,
config: &Config,
@ -1639,7 +1662,6 @@ impl<P: ResolveToPath> TomlDependency<P> {
self.to_dependency(
name,
&mut Context {
pkgid,
deps: &mut Vec::new(),
source_id,
nested_paths,
@ -1848,10 +1870,7 @@ impl<P: ResolveToPath> DetailedTomlDependency<P> {
};
let version = self.version.as_deref();
let mut dep = match cx.pkgid {
Some(id) => Dependency::parse(pkg_name, version, new_source_id, id, cx.config)?,
None => Dependency::parse_no_deprecated(pkg_name, version, new_source_id)?,
};
let mut dep = Dependency::parse(pkg_name, version, new_source_id)?;
dep.set_features(self.features.iter().flatten())
.set_default_features(
self.default_features

View file

@ -269,7 +269,7 @@ fn cargo_compile_with_invalid_version() {
[ERROR] failed to parse manifest at `[..]`
Caused by:
Expected dot for key `package.version`
unexpected end of input while parsing minor version number for key `package.version`
",
)
.run();
@ -544,7 +544,7 @@ Caused by:
failed to parse the version requirement `y` for dependency `crossbeam`
Caused by:
the given version requirement is invalid
unexpected character 'y' while parsing major version number
",
)
.run();

View file

@ -1695,119 +1695,6 @@ fn bump_version_dont_update_registry() {
.run();
}
#[cargo_test]
fn old_version_req() {
let p = project()
.file(
"Cargo.toml",
r#"
[project]
name = "bar"
version = "0.5.0"
authors = []
[dependencies]
remote = "0.2*"
"#,
)
.file("src/main.rs", "fn main() {}")
.build();
Package::new("remote", "0.2.0").publish();
p.cargo("build")
.with_stderr(
"\
warning: parsed version requirement `0.2*` is no longer valid
Previous versions of Cargo accepted this malformed requirement,
but it is being deprecated. This was found when parsing the manifest
of bar 0.5.0, and the correct version requirement is `0.2.*`.
This will soon become a hard error, so it's either recommended to
update to a fixed version or contact the upstream maintainer about
this warning.
warning: parsed version requirement `0.2*` is no longer valid
Previous versions of Cargo accepted this malformed requirement,
but it is being deprecated. This was found when parsing the manifest
of bar 0.5.0, and the correct version requirement is `0.2.*`.
This will soon become a hard error, so it's either recommended to
update to a fixed version or contact the upstream maintainer about
this warning.
[UPDATING] [..]
[DOWNLOADING] crates ...
[DOWNLOADED] [..]
[COMPILING] [..]
[COMPILING] [..]
[FINISHED] [..]
",
)
.run();
}
#[cargo_test]
fn old_version_req_upstream() {
let p = project()
.file(
"Cargo.toml",
r#"
[project]
name = "bar"
version = "0.5.0"
authors = []
[dependencies]
remote = "0.3"
"#,
)
.file("src/main.rs", "fn main() {}")
.build();
Package::new("remote", "0.3.0")
.file(
"Cargo.toml",
r#"
[project]
name = "remote"
version = "0.3.0"
authors = []
[dependencies]
bar = "0.2*"
"#,
)
.file("src/lib.rs", "")
.publish();
Package::new("bar", "0.2.0").publish();
p.cargo("build")
.with_stderr(
"\
[UPDATING] [..]
[DOWNLOADING] crates ...
[DOWNLOADED] [..]
warning: parsed version requirement `0.2*` is no longer valid
Previous versions of Cargo accepted this malformed requirement,
but it is being deprecated. This was found when parsing the manifest
of remote 0.3.0, and the correct version requirement is `0.2.*`.
This will soon become a hard error, so it's either recommended to
update to a fixed version or contact the upstream maintainer about
this warning.
[COMPILING] [..]
[COMPILING] [..]
[FINISHED] [..]
",
)
.run();
}
#[cargo_test]
fn toml_lies_but_index_is_truth() {
Package::new("foo", "0.2.0").publish();