    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93

    //! Interacts with the registry [owners API][1].
    //!
    //! [1]: https://doc.rust-lang.org/nightly/cargo/reference/registry-web-api.html#owners

    use anyhow::Context as _;

    use crate::core::Workspace;
    use crate::drop_print;
    use crate::drop_println;
    use crate::util::auth;
    use crate::util::auth::Secret;
    use crate::util::important_paths::find_root_manifest_for_wd;
    use crate::CargoResult;
    use crate::Config;

    pub struct OwnersOptions {
        pub krate: Option<String>,
        pub token: Option<Secret<String>>,
        pub index: Option<String>,
        pub to_add: Option<Vec<String>>,
        pub to_remove: Option<Vec<String>>,
        pub list: bool,
        pub registry: Option<String>,
    }

    pub fn modify_owners(config: &Config, opts: &OwnersOptions) -> CargoResult<()> {
        let name = match opts.krate {
            Some(ref name) => name.clone(),
            None => {
                let manifest_path = find_root_manifest_for_wd(config.cwd())?;
                let ws = Workspace::new(&manifest_path, config)?;
                ws.current()?.package_id().name().to_string()
            }
        };

        let mutation = auth::Mutation::Owners { name: &name };

        let (mut registry, _) = super::registry(
            config,
            opts.token.as_ref().map(Secret::as_deref),
            opts.index.as_deref(),
            opts.registry.as_deref(),
            true,
            Some(mutation),
        )?;

        if let Some(ref v) = opts.to_add {
            let v = v.iter().map(|s| &s[..]).collect::<Vec<_>>();
            let msg = registry.add_owners(&name, &v).with_context(|| {
                format!(
                    "failed to invite owners to crate `{}` on registry at {}",
                    name,
                    registry.host()
                )
            })?;

            config.shell().status("Owner", msg)?;
        }

        if let Some(ref v) = opts.to_remove {
            let v = v.iter().map(|s| &s[..]).collect::<Vec<_>>();
            config
                .shell()
                .status("Owner", format!("removing {:?} from crate {}", v, name))?;
            registry.remove_owners(&name, &v).with_context(|| {
                format!(
                    "failed to remove owners from crate `{}` on registry at {}",
                    name,
                    registry.host()
                )
            })?;
        }

        if opts.list {
            let owners = registry.list_owners(&name).with_context(|| {
                format!(
                    "failed to list owners of crate `{}` on registry at {}",
                    name,
                    registry.host()
                )
            })?;
            for owner in owners.iter() {
                drop_print!(config, "{}", owner.login);
                match (owner.name.as_ref(), owner.email.as_ref()) {
                    (Some(name), Some(email)) => drop_println!(config, " ({} <{}>)", name, email),
                    (Some(s), None) | (None, Some(s)) => drop_println!(config, " ({})", s),
                    (None, None) => drop_println!(config),
                }
            }
        }

        Ok(())
    }