You are an expert in writing code in many different languages. Your goal is to perform code completion for the following code, keeping in mind the rest of the code and the file meta data.
    Metadata details:
    filename: publish.rs
    path of file: ./repos/cargo/src/cargo/ops/registry
    
    the code of the file until where you have to start completion: //! Interacts with the registry [publish API][1].
//!
//! [1]: https://doc.rust-lang.org/nightly/cargo/reference/registry-web-api.html#publish

use std::collections::BTreeMap;
use std::collections::HashSet;
use std::fs::File;
use std::time::Duration;

use anyhow::bail;
use anyhow::Context as _;
use cargo_credential::Operation;
use cargo_credential::Secret;
use cargo_util::paths;
use crates_io::NewCrate;
use crates_io::NewCrateDependency;
use crates_io::Registry;

use crate::core::dependency::DepKind;
use crate::core::manifest::ManifestMetadata;
use crate::core::resolver::CliFeatures;
use crate::core::Dependency;
use crate::core::Package;
use crate::core::PackageIdSpecQuery;
use crate::core::SourceId;
use crate::core::Workspace;
use crate::ops;
use crate::ops::PackageOpts;
use crate::ops::Packages;
use crate::sources::source::QueryKind;
use crate::sources::SourceConfigMap;
use crate::sources::CRATES_IO_REGISTRY;
use crate::util::auth;
use crate::util::cache_lock::CacheLockMode;
use crate::util::context::JobsConfig;
use crate::util::Progress;
use crate::util::ProgressStyle;
use crate::CargoResult;
use crate::GlobalContext;

use super::super::check_dep_has_version;
use super::RegistryOrIndex;

pub struct PublishOpts<'gctx> {
    pub gctx: &'gctx GlobalContext,
    pub token: Option<Secret<String>>,
    pub reg_or_index: Option<RegistryOrIndex>,
    pub verify: bool,
    pub allow_dirty: bool,
    pub jobs: Option<JobsConfig>,
    pub keep_going: bool,
    pub to_publish: ops::Packages,
    pub targets: Vec<String>,
    pub dry_run: bool,
    pub cli_features: CliFeatures,
}

pub fn publish(ws: &Workspace<'_>, opts: &PublishOpts<'_>) -> CargoResult<()> {
    let specs = opts.to_publish.to_package_id_specs(ws)?;
    if specs.len() > 1 {
        bail!("the `-p` argument must be specified to select a single package to publish")
    }
    if Packages::Default == opts.to_publish && ws.is_virtual() {
        bail!("the `-p` argument must be specified in the root of a virtual workspace")
    }
    let member_ids = ws.members().map(|p| p.package_id());
    // Check that the spec matches exactly one member.
    specs[0].query(member_ids)?;
    let mut pkgs = ws.members_with_features(&specs, &opts.cli_features)?;
    // In `members_with_features_old`, it will add "current" package (determined by the cwd)
    // So we need filter
    pkgs = pkgs
        .into_iter()
        .filter(|(m, _)| specs.iter().any(|spec| spec.matches(m.package_id())))
        .collect();
    // Double check. It is safe theoretically, unless logic has updated.
    assert_eq!(pkgs.len(), 1);

    let (pkg, cli_features) = pkgs.pop().unwrap();

    let mut publish_registry = match opts.reg_or_index.as_ref() {
        Some(RegistryOrIndex::Registry(registry)) => Some(registry.clone()),
        _ => None,
    };
    if let Some(ref allowed_registries) = *pkg.publish() {
        if publish_registry.is_none() && allowed_registries.len() == 1 {
            // If there is only one allowed registry, push to that one directly,
            // even though there is no registry specified in the command.
            let default_registry = &allowed_registries[0];
            if default_registry != CRATES_IO_REGISTRY {
                // Don't change the registry for crates.io and don't warn the user.
                // crates.io will be defaulted even without this.
                opts.gctx.shell().note(&format!(
                    "found `{}` as only allowed registry. Publishing to it automatically.",
                    default_registry
                ))?;
                publish_registry = Some(default_registry.clone());
            }
        }

        let reg_name = publish_registry
            .clone()
            .unwrap_or_else(|| CRATES_IO_REGISTRY.to_string());
        if allowed_registries.is_empty() {
            bail!(
                "`{}` cannot be published.\n\
                 `package.publish` must be set to `true` or a non-empty list in Cargo.toml to publish.",
                pkg.name(),
            );
        } else if !allowed_registries.contains(&reg_name) {
            bail!(
                "`{}` cannot be published.\n\
                 The registry `{}` is not listed in the `package.publish` value in Cargo.toml.",
                pkg.name(),
                reg_name
            );
        }
    }
    // This is only used to confirm that we can create a token before we build the package.
    // This causes the credential provider to be called an extra time, but keeps the same order of errors.
    let ver = pkg.version().to_string();
    let operation = Operation::Read;

    let reg_or_index = match opts.reg_or_index.clone() {
        Some(RegistryOrIndex::Registry(_)) | None => {
  
    
pub fn publish(ws: &Workspace<'_>, opts: &PublishOpts<'_>) -> CargoResult<()> {
    let specs = opts.to_publish.to_package_id_specs(ws)?;
    if specs.len() > 1 {
        bail!("the `-p` argument must be specified to select a single package to publish")
    }
    if Packages::Default == opts.to_publish && ws.is_virtual() {
        bail!("the `-p` argument must be specified in the root of a virtual workspace")
    }
    let member_ids = ws.members().map(|p| p.package_id());
    // Check that the spec matches exactly one member.
    specs[0].query(member_ids)?;
    let mut pkgs = ws.members_with_features(&specs, &opts.cli_features)?;
    // In `members_with_features_old`, it will add "current" package (determined by the cwd)
    // So we need filter
    pkgs = pkgs
        .into_iter()
        .filter(|(m, _)| specs.iter().any(|spec| spec.matches(m.package_id())))
        .collect();
    // Double check. It is safe theoretically, unless logic has updated.
    assert_eq!(pkgs.len(), 1);

    let (pkg, cli_features) = pkgs.pop().unwrap();

    let mut publish_registry = match opts.reg_or_index.as_ref() {
        Some(RegistryOrIndex::Registry(registry)) => Some(registry.clone()),
        _ => None,
    };
    if let Some(ref allowed_registries) = *pkg.publish() {
        if publish_registry.is_none() && allowed_registries.len() == 1 {
            // If there is only one allowed registry, push to that one directly,
            // even though there is no registry specified in the command.
            let default_registry = &allowed_registries[0];
            if default_registry != CRATES_IO_REGISTRY {
                // Don't change the registry for crates.io and don't warn the user.
                // crates.io will be defaulted even without this.
                opts.gctx.shell().note(&format!(
                    "found `{}` as only allowed registry. Publishing to it automatically.",
                    default_registry
                ))?;
                publish_registry = Some(default_registry.clone());
            }
        }

        let reg_name = publish_registry
            .clone()
            .unwrap_or_else(|| CRATES_IO_REGISTRY.to_string());
        if allowed_registries.is_empty() {
            bail!(
                "`{}` cannot be published.\n\
                 `package.publish` must be set to `true` or a non-empty list in Cargo.toml to publish.",
                pkg.name(),
            );
        } else if !allowed_registries.contains(&reg_name) {
            bail!(
                "`{}` cannot be published.\n\
                 The registry `{}` is not listed in the `package.publish` value in Cargo.toml.",
                pkg.name(),
                reg_name
            );
        }
    }
    // This is only used to confirm that we can create a token before we build the package.
    // This causes the credential provider to be called an extra time, but keeps the same order of errors.
    let ver = pkg.version().to_string();
    let operation = Operation::Read;

    let reg_or_index = match opts.reg_or_index.clone() {
        Some(RegistryOrIndex::Registry(_)) | None => {
            publish_registry.map(RegistryOrIndex::Registry)
        }
        val => val,
    };
    let (mut registry, reg_ids) = super::registry(
        opts.gctx,
        opts.token.as_ref().map(Secret::as_deref),
        reg_or_index.as_ref(),
        true,
        Some(operation).filter(|_| !opts.dry_run),
    )?;
    verify_dependencies(pkg, &registry, reg_ids.original)?;

    // Prepare a tarball, with a non-suppressible warning if metadata
    // is missing since this is being put online.
    let tarball = ops::package_one(
        ws,
        pkg,
        &PackageOpts {
            gctx: opts.gctx,
            verify: opts.verify,
            list: false,
            check_metadata: true,
            allow_dirty: opts.allow_dirty,
            to_package: Packages::Default,
            targets: opts.targets.clone(),
            jobs: opts.jobs.clone(),
            keep_going: opts.keep_going,
            cli_features,
        },
    )?
    .unwrap();

    if !opts.dry_run {
        let hash = cargo_util::Sha256::new()
            .update_file(tarball.file())?
            .finish_hex();
        let operation = Operation::Publish {
            name: pkg.name().as_str(),
            vers: &ver,
            cksum: &hash,
        };
        registry.set_token(Some(auth::auth_token(
            &opts.gctx,
            &reg_ids.original,
            None,
            operation,
            vec![],
            false,
        )?));
    }

    opts.gctx
        .shell()
        .status("Uploading", pkg.package_id().to_string())?;
    transmit(
        opts.gctx,
        pkg,
        tarball.file(),
        &mut registry,
        reg_ids.original,
        opts.dry_run,
    )?;
    if !opts.dry_run {
        const DEFAULT_TIMEOUT: u64 = 60;
        let timeout = if opts.gctx.cli_unstable().publish_timeout {
            let timeout: Option<u64> = opts.gctx.get("publish.timeout")?;
            timeout.unwrap_or(DEFAULT_TIMEOUT)
        } else {
            DEFAULT_TIMEOUT
        };
        if 0 < timeout {
            let timeout = Duration::from_secs(timeout);
            wait_for_publish(opts.gctx, reg_ids.original, pkg, timeout)?;
        }
    }

    Ok(())
}