Skip to content

Commit dcb4ef9

Browse files
committed
Auto merge of #14448 - stupendoussuperpowers:bail, r=epage
bail before packaging on same version Fixes #3662. Cleaned up commits from #14338.
2 parents 64c4b6d + 6ede1e2 commit dcb4ef9

File tree

9 files changed

+117
-38
lines changed

9 files changed

+117
-38
lines changed

src/cargo/ops/registry/login.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ pub fn registry_login(
3434
false,
3535
None,
3636
) {
37-
Ok(registry) => Some(format!("{}/me", registry.host())),
37+
Ok((registry, _)) => Some(format!("{}/me", registry.host())),
3838
Err(e) if e.is::<AuthorizationError>() => e
3939
.downcast::<AuthorizationError>()
4040
.unwrap()

src/cargo/ops/registry/mod.rs

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -120,14 +120,14 @@ impl RegistryCredentialConfig {
120120
/// `registry`, or `index` are set, then uses `crates-io`.
121121
/// * `force_update`: If `true`, forces the index to be updated.
122122
/// * `token_required`: If `true`, the token will be set.
123-
fn registry(
124-
gctx: &GlobalContext,
123+
fn registry<'gctx>(
124+
gctx: &'gctx GlobalContext,
125125
source_ids: &RegistrySourceIds,
126126
token_from_cmdline: Option<Secret<&str>>,
127127
reg_or_index: Option<&RegistryOrIndex>,
128128
force_update: bool,
129129
token_required: Option<Operation<'_>>,
130-
) -> CargoResult<Registry> {
130+
) -> CargoResult<(Registry, RegistrySource<'gctx>)> {
131131
let is_index = reg_or_index.map(|v| v.is_index()).unwrap_or_default();
132132
if is_index && token_required.is_some() && token_from_cmdline.is_none() {
133133
bail!("command-line argument --index requires --token to be specified");
@@ -136,9 +136,9 @@ fn registry(
136136
auth::cache_token_from_commandline(gctx, &source_ids.original, token);
137137
}
138138

139+
let mut src = RegistrySource::remote(source_ids.replacement, &HashSet::new(), gctx)?;
139140
let cfg = {
140141
let _lock = gctx.acquire_package_cache_lock(CacheLockMode::DownloadExclusive)?;
141-
let mut src = RegistrySource::remote(source_ids.replacement, &HashSet::new(), gctx)?;
142142
// Only update the index if `force_update` is set.
143143
if force_update {
144144
src.invalidate_cache()
@@ -170,11 +170,9 @@ fn registry(
170170
None
171171
};
172172
let handle = http_handle(gctx)?;
173-
Ok(Registry::new_handle(
174-
api_host,
175-
token,
176-
handle,
177-
cfg.auth_required,
173+
Ok((
174+
Registry::new_handle(api_host, token, handle, cfg.auth_required),
175+
src,
178176
))
179177
}
180178

src/cargo/ops/registry/owner.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ pub fn modify_owners(gctx: &GlobalContext, opts: &OwnersOptions) -> CargoResult<
3636

3737
let operation = Operation::Owners { name: &name };
3838
let source_ids = super::get_source_id(gctx, opts.reg_or_index.as_ref())?;
39-
let mut registry = super::registry(
39+
let (mut registry, _) = super::registry(
4040
gctx,
4141
&source_ids,
4242
opts.token.as_ref().map(Secret::as_deref),

src/cargo/ops/registry/publish.rs

Lines changed: 43 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,13 @@ use crate::core::PackageIdSpecQuery;
3131
use crate::core::SourceId;
3232
use crate::core::Workspace;
3333
use crate::ops;
34+
use crate::ops::registry::RegistrySourceIds;
3435
use crate::ops::PackageOpts;
3536
use crate::ops::Packages;
3637
use crate::ops::RegistryOrIndex;
3738
use crate::sources::source::QueryKind;
3839
use crate::sources::source::Source;
40+
use crate::sources::RegistrySource;
3941
use crate::sources::SourceConfigMap;
4042
use crate::sources::CRATES_IO_REGISTRY;
4143
use crate::util::auth;
@@ -45,6 +47,7 @@ use crate::util::toml::prepare_for_publish;
4547
use crate::util::Graph;
4648
use crate::util::Progress;
4749
use crate::util::ProgressStyle;
50+
use crate::util::VersionExt as _;
4851
use crate::CargoResult;
4952
use crate::GlobalContext;
5053

@@ -115,7 +118,7 @@ pub fn publish(ws: &Workspace<'_>, opts: &PublishOpts<'_>) -> CargoResult<()> {
115118
// This is only used to confirm that we can create a token before we build the package.
116119
// This causes the credential provider to be called an extra time, but keeps the same order of errors.
117120
let source_ids = super::get_source_id(opts.gctx, reg_or_index.as_ref())?;
118-
let mut registry = super::registry(
121+
let (mut registry, mut source) = super::registry(
119122
opts.gctx,
120123
&source_ids,
121124
opts.token.as_ref().map(Secret::as_deref),
@@ -124,9 +127,15 @@ pub fn publish(ws: &Workspace<'_>, opts: &PublishOpts<'_>) -> CargoResult<()> {
124127
Some(Operation::Read).filter(|_| !opts.dry_run),
125128
)?;
126129

127-
// Validate all the packages before publishing any of them.
128-
for (pkg, _) in &pkgs {
129-
verify_dependencies(pkg, &registry, source_ids.original)?;
130+
{
131+
let _lock = opts
132+
.gctx
133+
.acquire_package_cache_lock(CacheLockMode::DownloadExclusive)?;
134+
135+
for (pkg, _) in &pkgs {
136+
verify_unpublished(pkg, &mut source, &source_ids)?;
137+
verify_dependencies(pkg, &registry, source_ids.original)?;
138+
}
130139
}
131140

132141
let pkg_dep_graph = ops::cargo_package::package_with_dep_graph(
@@ -355,6 +364,36 @@ fn poll_one_package(
355364
Ok(!summaries.is_empty())
356365
}
357366

367+
fn verify_unpublished(
368+
pkg: &Package,
369+
source: &mut RegistrySource<'_>,
370+
source_ids: &RegistrySourceIds,
371+
) -> CargoResult<()> {
372+
let query = Dependency::parse(
373+
pkg.name(),
374+
Some(&pkg.version().to_exact_req().to_string()),
375+
source_ids.replacement,
376+
)?;
377+
let duplicate_query = loop {
378+
match source.query_vec(&query, QueryKind::Exact) {
379+
std::task::Poll::Ready(res) => {
380+
break res?;
381+
}
382+
std::task::Poll::Pending => source.block_until_ready()?,
383+
}
384+
};
385+
if !duplicate_query.is_empty() {
386+
bail!(
387+
"crate {}@{} already exists on {}",
388+
pkg.name(),
389+
pkg.version(),
390+
source.describe()
391+
);
392+
}
393+
394+
Ok(())
395+
}
396+
358397
fn verify_dependencies(
359398
pkg: &Package,
360399
registry: &Registry,

src/cargo/ops/registry/search.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ pub fn search(
2121
limit: u32,
2222
) -> CargoResult<()> {
2323
let source_ids = super::get_source_id(gctx, reg_or_index.as_ref())?;
24-
let mut registry =
24+
let (mut registry, _) =
2525
super::registry(gctx, &source_ids, None, reg_or_index.as_ref(), false, None)?;
2626
let (crates, total_crates) = registry.search(query, limit).with_context(|| {
2727
format!(

src/cargo/ops/registry/yank.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ pub fn yank(
4747
}
4848
};
4949
let source_ids = super::get_source_id(gctx, reg_or_index.as_ref())?;
50-
let mut registry = super::registry(
50+
let (mut registry, _) = super::registry(
5151
gctx,
5252
&source_ids,
5353
token.as_ref().map(Secret::as_deref),

tests/testsuite/credential_process.rs

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -544,6 +544,31 @@ You may press ctrl-c [..]
544544
.with_stderr_data(output)
545545
.run();
546546

547+
let output_non_independent = r#"[UPDATING] `alternative` index
548+
{"v":1,"registry":{"index-url":"[..]","name":"alternative"},"kind":"get","operation":"read"}
549+
[PACKAGING] foo v0.1.1 ([ROOT]/foo)
550+
[PACKAGED] 3 files, [FILE_SIZE]B ([FILE_SIZE]B compressed)
551+
[UPLOADING] foo v0.1.1 ([ROOT]/foo)
552+
{"v":1,"registry":{"index-url":"[..]","name":"alternative"},"kind":"get","operation":"publish","name":"foo","vers":"0.1.1","cksum":"[..]"}
553+
[UPLOADED] foo v0.1.1 to registry `alternative`
554+
[NOTE] waiting [..]
555+
You may press ctrl-c [..]
556+
[PUBLISHED] foo v0.1.1 at registry `alternative`
557+
"#;
558+
559+
p.change_file(
560+
"Cargo.toml",
561+
r#"
562+
[package]
563+
name = "foo"
564+
version = "0.1.1"
565+
edition = "2015"
566+
description = "foo"
567+
license = "MIT"
568+
homepage = "https://example.com/"
569+
"#,
570+
);
571+
547572
p.change_file(
548573
".cargo/config.toml",
549574
&format!(
@@ -557,7 +582,7 @@ You may press ctrl-c [..]
557582
);
558583

559584
p.cargo("publish --registry alternative --no-verify")
560-
.with_stderr_data(output)
585+
.with_stderr_data(output_non_independent)
561586
.run();
562587
}
563588

tests/testsuite/publish.rs

Lines changed: 32 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,37 @@ You may press ctrl-c to skip waiting; the crate should be available shortly.
130130
validate_upload_foo();
131131
}
132132

133+
#[cargo_test]
134+
fn duplicate_version() {
135+
let registry_dupl = RegistryBuilder::new().http_api().http_index().build();
136+
Package::new("foo", "0.0.1").publish();
137+
138+
let p = project()
139+
.file(
140+
"Cargo.toml",
141+
r#"
142+
[package]
143+
name = "foo"
144+
version = "0.0.1"
145+
authors = []
146+
license = "MIT"
147+
description = "foo"
148+
"#,
149+
)
150+
.file("src/main.rs", "fn main() {}")
151+
.build();
152+
153+
p.cargo("publish")
154+
.replace_crates_io(registry_dupl.index_url())
155+
.with_status(101)
156+
.with_stderr_data(str![[r#"
157+
[UPDATING] crates.io index
158+
[ERROR] crate foo@0.0.1 already exists on crates.io index
159+
160+
"#]])
161+
.run();
162+
}
163+
133164
// Check that the `token` key works at the root instead of under a
134165
// `[registry]` table.
135166
#[cargo_test]
@@ -3848,22 +3879,7 @@ You may press ctrl-c to skip waiting; the crate should be available shortly.
38483879
.with_status(101)
38493880
.with_stderr_data(str![[r#"
38503881
[UPDATING] crates.io index
3851-
[PACKAGING] a v0.0.1 ([ROOT]/foo/a)
3852-
[PACKAGED] 3 files, [FILE_SIZE]B ([FILE_SIZE]B compressed)
3853-
[PACKAGING] b v0.0.1 ([ROOT]/foo/b)
3854-
[PACKAGED] 3 files, [FILE_SIZE]B ([FILE_SIZE]B compressed)
3855-
[VERIFYING] a v0.0.1 ([ROOT]/foo/a)
3856-
[COMPILING] a v0.0.1 ([ROOT]/foo/target/package/a-0.0.1)
3857-
[FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s
3858-
[VERIFYING] b v0.0.1 ([ROOT]/foo/b)
3859-
[UPDATING] crates.io index
3860-
[ERROR] failed to verify package tarball
3861-
3862-
Caused by:
3863-
failed to get `a` as a dependency of package `b v0.0.1 ([ROOT]/foo/target/package/b-0.0.1)`
3864-
3865-
Caused by:
3866-
found a package in the remote registry and the local overlay: a@0.0.1
3882+
[ERROR] crate a@0.0.1 already exists on crates.io index
38673883
38683884
"#]])
38693885
.run();

tests/testsuite/registry_auth.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -565,9 +565,10 @@ fn token_not_logged() {
565565
// 2. config.json again for verification
566566
// 3. /index/3/b/bar
567567
// 4. /dl/bar/1.0.0/download
568-
// 5. /api/v1/crates/new
569-
// 6. config.json for the "wait for publish"
570-
// 7. /index/3/f/foo for the "wait for publish"
571-
assert_eq!(authorizations.len(), 7);
568+
// 5. /index/3/f/foo for checking duplicate version
569+
// 6. /api/v1/crates/new
570+
// 7. config.json for the "wait for publish"
571+
// 8. /index/3/f/foo for the "wait for publish"
572+
assert_eq!(authorizations.len(), 8);
572573
assert!(!log.contains("a-unique_token"));
573574
}

0 commit comments

Comments
 (0)