Skip to content

Commit 174c80e

Browse files
committed
Refactor select_dep_pkg error handling
Create a local Error type that that wraps existing error handling code Giving the three error variants names improves readability and makes it easier to recognise duplicate code Move all string operations to create errors from 3 separate bail! calls into anyhow::anyhow! calls that are encapsulated in the From<> impl
1 parent b87ae28 commit 174c80e

File tree

1 file changed

+103
-54
lines changed

1 file changed

+103
-54
lines changed

src/cargo/ops/common_for_install_and_uninstall.rs

+103-54
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ use crate::ops::{self, CompileFilter, CompileOptions};
1717
use crate::sources::PathSource;
1818
use crate::util::errors::CargoResult;
1919
use crate::util::interning::InternedString;
20-
use crate::util::Config;
20+
use crate::util::{Config, OptVersionReq};
2121
use crate::util::{FileLock, Filesystem};
2222

2323
/// On-disk tracking for which package installed which binary.
@@ -522,25 +522,6 @@ pub fn path_source(source_id: SourceId, config: &Config) -> CargoResult<PathSour
522522
Ok(PathSource::new(&path, source_id, config))
523523
}
524524

525-
fn is_package_name_a_git_url(package_name: &InternedString) -> bool {
526-
if let Ok(url) = Url::parse(package_name) {
527-
if let Some(domain) = url.domain() {
528-
// REVIEW
529-
// Are there any other git services without "git"
530-
// in the domain?
531-
// bitbucket?
532-
// Is it possible to ask the cargo/crates team for
533-
// some stats where crates projects are currently hosted on
534-
return domain.contains("git");
535-
}
536-
}
537-
false
538-
}
539-
540-
fn was_git_url_miscategorised_as_a_registry_dep(dep: &Dependency) -> bool {
541-
return dep.source_id().is_registry() && is_package_name_a_git_url(&dep.package_name());
542-
}
543-
544525
/// Gets a Package based on command-line requirements.
545526
pub fn select_dep_pkg<T>(
546527
source: &mut T,
@@ -566,47 +547,115 @@ where
566547
Poll::Pending => source.block_until_ready()?,
567548
}
568549
};
569-
match deps.iter().map(|p| p.package_id()).max() {
570-
Some(pkgid) => {
571-
let pkg = Box::new(source).download_now(pkgid, config)?;
572-
Ok(pkg)
550+
if let Some(pkgid) = deps.iter().map(|p| p.package_id()).max() {
551+
let pkg = Box::new(source).download_now(pkgid, config)?;
552+
Ok(pkg)
553+
} else {
554+
let spe = SelectPackageError::new(dep, source);
555+
bail!(anyhow::Error::from(spe))
556+
}
557+
}
558+
559+
struct YankedInfo {
560+
package_name: InternedString,
561+
source_id: SourceId,
562+
}
563+
564+
struct PackageNotFound {
565+
package_name: InternedString,
566+
source_id: SourceId,
567+
// REVIEW make it a reference or is cloning ok?
568+
version_req: OptVersionReq,
569+
}
570+
571+
enum SelectPackageError {
572+
/// Return when the Package had been yanked from the Registry
573+
Yanked(YankedInfo),
574+
// Return when someone accidentally passed a git(hub|lab|ea) URL as the package name
575+
UrlTreatedAsPackageName(PackageNotFound),
576+
// Catch-all variant for all other errors
577+
CouldntFindInRegistry(PackageNotFound),
578+
}
579+
580+
fn is_package_name_a_git_url(package_name: &InternedString) -> bool {
581+
if let Ok(url) = Url::parse(package_name) {
582+
if let Some(domain) = url.domain() {
583+
// REVIEW
584+
// Are there any other git services without "git"
585+
// in the domain?
586+
// bitbucket?
587+
// Is it possible to ask the cargo/crates team for
588+
// some stats where crates projects are currently hosted on
589+
return domain.contains("git");
573590
}
574-
None => {
575-
let is_yanked: bool = if dep.version_req().is_exact() {
576-
let version: String = dep.version_req().to_string();
577-
PackageId::new(dep.package_name(), &version[1..], source.source_id())
578-
.map_or(false, |pkg_id| source.is_yanked(pkg_id).unwrap_or(false))
579-
} else {
580-
false
581-
};
582-
if is_yanked {
583-
bail!(
584-
"cannot install package `{}`, it has been yanked from {}",
585-
dep.package_name(),
586-
source.source_id()
587-
)
591+
}
592+
false
593+
}
594+
595+
fn was_git_url_miscategorised_as_a_registry_dep(dep: &Dependency) -> bool {
596+
return dep.source_id().is_registry() && is_package_name_a_git_url(&dep.package_name());
597+
}
598+
599+
impl SelectPackageError {
600+
fn new<T>(dep: Dependency, source: &mut T) -> Self
601+
where
602+
T: Source,
603+
{
604+
let is_yanked: bool = if dep.version_req().is_exact() {
605+
let version: String = dep.version_req().to_string();
606+
PackageId::new(dep.package_name(), &version[1..], source.source_id())
607+
.map_or(false, |pkg_id| source.is_yanked(pkg_id).unwrap_or(false))
608+
} else {
609+
false
610+
};
611+
if is_yanked {
612+
SelectPackageError::Yanked(YankedInfo {
613+
package_name: dep.package_name(),
614+
source_id: source.source_id(),
615+
})
616+
} else {
617+
if was_git_url_miscategorised_as_a_registry_dep(&dep) {
618+
SelectPackageError::UrlTreatedAsPackageName(PackageNotFound {
619+
package_name: dep.package_name(),
620+
source_id: source.source_id(),
621+
version_req: dep.version_req().clone(),
622+
})
588623
} else {
589-
if was_git_url_miscategorised_as_a_registry_dep(&dep) {
590-
bail!(
591-
"could not find `{}` in {} with version `{}`. Try adding `--git {}`",
592-
dep.package_name(),
593-
source.source_id(),
594-
dep.version_req(),
595-
dep.package_name(),
596-
)
597-
} else {
598-
bail!(
599-
"could not find `{}` in {} with version `{}`",
600-
dep.package_name(),
601-
source.source_id(),
602-
dep.version_req(),
603-
)
604-
}
624+
SelectPackageError::CouldntFindInRegistry(PackageNotFound {
625+
package_name: dep.package_name(),
626+
source_id: source.source_id(),
627+
version_req: dep.version_req().clone(),
628+
})
605629
}
606630
}
607631
}
608632
}
609633

634+
impl From<SelectPackageError> for anyhow::Error {
635+
fn from(err: SelectPackageError) -> Self {
636+
match err {
637+
SelectPackageError::Yanked(info) => anyhow::anyhow!(
638+
"cannot install package `{}`, it has been yanked from {}",
639+
info.package_name,
640+
info.source_id
641+
),
642+
SelectPackageError::UrlTreatedAsPackageName(pkg_not_found) => anyhow::anyhow!(
643+
"could not find `{}` in {} with version `{}`. Try adding `--git {}`",
644+
pkg_not_found.package_name,
645+
pkg_not_found.source_id,
646+
pkg_not_found.version_req,
647+
pkg_not_found.package_name,
648+
),
649+
SelectPackageError::CouldntFindInRegistry(pkg_not_found) => anyhow::anyhow!(
650+
"could not find `{}` in {} with version `{}`",
651+
pkg_not_found.package_name,
652+
pkg_not_found.source_id,
653+
pkg_not_found.version_req,
654+
),
655+
}
656+
}
657+
}
658+
610659
pub fn select_pkg<T, F>(
611660
source: &mut T,
612661
dep: Option<Dependency>,

0 commit comments

Comments
 (0)