cargo/ops/registry/
login.rs

1//! Interacts with the registry [login API][1].
2//!
3//! This doesn't really call any web API at this moment. Instead, it's just an
4//! operation for `cargo login`.
5//!
6//! [1]: https://doc.rust-lang.org/nightly/cargo/reference/registry-web-api.html#login
7
8use std::io::IsTerminal;
9
10use crate::util::auth;
11use crate::util::auth::AuthorizationError;
12use crate::CargoResult;
13use crate::GlobalContext;
14use cargo_credential::LoginOptions;
15use cargo_credential::Secret;
16
17use super::get_source_id;
18use super::registry;
19use super::RegistryOrIndex;
20
21pub fn registry_login(
22    gctx: &GlobalContext,
23    token_from_cmdline: Option<Secret<&str>>,
24    reg_or_index: Option<&RegistryOrIndex>,
25    args: &[&str],
26) -> CargoResult<()> {
27    let source_ids = get_source_id(gctx, reg_or_index)?;
28
29    let login_url = match registry(
30        gctx,
31        &source_ids,
32        token_from_cmdline.clone(),
33        reg_or_index,
34        false,
35        None,
36    ) {
37        Ok((registry, _)) => Some(format!("{}/me", registry.host())),
38        Err(e) if e.is::<AuthorizationError>() => e
39            .downcast::<AuthorizationError>()
40            .unwrap()
41            .login_url
42            .map(|u| u.to_string()),
43        Err(e) => return Err(e),
44    };
45
46    let mut token_from_stdin = None;
47    let token = token_from_cmdline.or_else(|| {
48        if !std::io::stdin().is_terminal() {
49            let token = cargo_credential::read_line().unwrap_or_default();
50            if !token.is_empty() {
51                token_from_stdin = Some(token);
52            }
53        }
54        token_from_stdin.as_deref().map(Secret::from)
55    });
56
57    let options = LoginOptions {
58        token,
59        login_url: login_url.as_deref(),
60    };
61
62    auth::login(gctx, &source_ids.original, options, args)?;
63    Ok(())
64}