cargo_whatfeatures/
lib.rs1mod args;
7mod client;
8mod features;
9mod printer;
10mod registry;
11mod util;
12
13#[doc(inline)]
14pub use client::{Client, Version};
15
16#[doc(hidden)]
18pub use client::json;
19
20#[doc(inline)]
21pub use registry::{Crate, Registry, YankState};
22
23#[doc(inline)]
24pub use args::{Args, PkgId};
25
26#[doc(inline)]
27pub use printer::*;
28
29#[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Eq, Ord, Hash)]
32pub enum OfflineError {
34    List,
36    Latest,
38    CacheMiss,
40}
41
42impl OfflineError {
43    pub fn to_error(&self) -> anyhow::Error {
45        let err = match self {
46            Self::List => {
47                "must be able to connect to https://crates.io to list versions"
48            }
49            Self::Latest =>{
50                "cannot find that crate cached, you must be able to connect to https://crates.io to get the latest version"
51            } ,
52            Self::CacheMiss => {
53                "crate not found in local registry or cache. must be able to connect to https://crates.io to fetch it"
54            },
55        };
56        anyhow::anyhow!(err)
57    }
58}
59
60#[derive(Debug)]
61pub enum Lookup {
63    Partial(Version),
65    LocalCache(features::Workspace),
67    Workspace(features::Workspace),
69}
70
71pub fn lookup(pkg_id: &PkgId, client: &Option<Client>, is_local: bool) -> anyhow::Result<Lookup> {
73    match pkg_id {
74        PkgId::Remote { name, semver } => {
76            let client = match &client {
77                Some(client) => client,
78                None => {
79                    return Registry::from_local()?
80                        .maybe_latest(&name)
81                        .ok_or_else(|| OfflineError::Latest.to_error())?
82                        .get_features()
83                        .map(Lookup::LocalCache)
84                }
85            };
86
87            let pkg = match semver {
88                Some(semver) => client.get_version(name, semver),
89                None => client.get_latest(name),
90            }
91            .map_err(|_err| cannot_find(pkg_id))?;
92
93            Ok(Lookup::Partial(pkg))
94        }
95
96        PkgId::Local(path) if !is_local => Crate::from_path(path).map(Lookup::Workspace),
98        PkgId::Local(path) => Crate::from_local(path).map(Lookup::Workspace),
99    }
100}
101
102fn cannot_find(pkg_id: &PkgId) -> anyhow::Error {
103    anyhow::anyhow!(
104        "cannot find a crate matching '{}'. maybe it was yanked?",
105        pkg_id
106    )
107}