Support --registry and more options from .cargo/config.toml (#1195)

Fixed #885

Now we can take advantage of new argument `--registry` and
env overrides:
 - `CARGO_REGISTRIES_DEFAULT` if `--registry` is not specified
 - `CARGO_REGISTRIES_{registry_name}_INDEX` for the registry index url

We can also read from `.cargo/config.toml` for:
 - default registry and registries configurations
 - additional CA bundle `http.cainfo`

Signed-off-by: Jiahao XU <Jiahao_XU@outlook.com>
This commit is contained in:
Jiahao XU 2023-07-10 13:37:41 +10:00 committed by GitHub
parent d280e122ca
commit 7dea40a99a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 297 additions and 63 deletions

View file

@ -223,10 +223,28 @@ pub struct Args {
#[clap(help_heading = "Options", long, alias = "roots")]
pub root: Option<PathBuf>,
/// The URL of the registry index to use
/// The URL of the registry index to use.
///
/// Cannot be used with `--registry`.
#[clap(help_heading = "Options", long)]
pub index: Option<Registry>,
/// Name of the registry to use. Registry names are defined in Cargo config
/// files <https://doc.rust-lang.org/cargo/reference/config.html>.
///
/// If not specified in cmdline or via environment variable, the default
/// registry is used, which is defined by the
/// `registry.default` config key in `.cargo/config.toml` which defaults
/// to crates-io.
///
/// If it is set, then it will try to read environment variable
/// `CARGO_REGISTRIES_{registry_name}_INDEX` for index url and fallback to
/// reading from `registries.<name>.index`.
///
/// Cannot be used with `--index`.
#[clap(help_heading = "Options", long, env = "CARGO_REGISTRY_DEFAULT")]
pub registry: Option<CompactString>,
/// This option will be passed through to all `cargo-install` invocations.
///
/// It will require `Cargo.lock` to be up to date.
@ -421,6 +439,18 @@ You cannot use --manifest-path and --git. Do one or the other."#
.exit();
}
if opts.index.is_some() && opts.registry.is_some() {
command
.error(
ErrorKind::ArgumentConflict,
format_args!(
r#"Multiple override options for registry.
You cannot use --index and --registry. Do one or the other."#
),
)
.exit();
}
if opts.crate_names.len() > 1 {
let option = if opts.version_req.is_some() {
"version"

View file

@ -1,4 +1,5 @@
use std::{
borrow::Cow,
env, fs,
future::Future,
path::{Path, PathBuf},
@ -16,12 +17,14 @@ use binstalk::{
remote::{Certificate, Client},
tasks::AutoAbortJoinHandle,
},
home::cargo_home,
ops::{
self,
resolve::{CrateName, Resolution, ResolutionFetch, VersionReqExt},
CargoTomlFetchOverride, Options, Resolver,
},
};
use binstalk_manifests::cargo_config::Config;
use binstalk_manifests::cargo_toml_binstall::PkgOverride;
use file_format::FileFormat;
use log::LevelFilter;
@ -56,10 +59,19 @@ pub fn install_crates(
})
.collect();
// Load .cargo/config.toml
let cargo_home = cargo_home().map_err(BinstallError::from)?;
let mut config = Config::load_from_path(cargo_home.join("config.toml"))?;
// Compute paths
let cargo_root = args.root;
let (install_path, mut manifests, temp_dir) =
compute_paths_and_load_manifests(cargo_root.clone(), args.install_path, args.no_track)?;
let (install_path, mut manifests, temp_dir) = compute_paths_and_load_manifests(
cargo_root.clone(),
args.install_path,
args.no_track,
cargo_home,
&mut config,
)?;
// Remove installed crates
let mut crate_names =
@ -83,12 +95,17 @@ pub fn install_crates(
// Initialize reqwest client
let rate_limit = args.rate_limit;
let mut http = config.http.take();
let client = Client::new(
concat!(env!("CARGO_PKG_NAME"), "/", env!("CARGO_PKG_VERSION")),
args.min_tls_version.map(|v| v.into()),
Duration::from_millis(rate_limit.duration.get()),
rate_limit.request_count,
read_root_certs(args.root_certificates),
read_root_certs(
args.root_certificates,
http.as_mut().and_then(|http| http.cainfo.take()),
),
)
.map_err(BinstallError::from)?;
@ -127,7 +144,27 @@ pub fn install_crates(
client,
gh_api_client,
jobserver_client,
registry: args.index.unwrap_or_default(),
registry: if let Some(index) = args.index {
index
} else if let Some(registry_name) = args
.registry
.or_else(|| config.registry.map(|registry| registry.default))
{
env::var(format!("CARGO_REGISTRIES_{registry_name}_INDEX"))
.map(Cow::Owned)
.or_else(|_| {
config
.registries
.as_ref()
.and_then(|registries| registries.get(&registry_name))
.map(|registry| Cow::Borrowed(registry.index.as_str()))
.ok_or_else(|| BinstallError::UnknownRegistryName(registry_name))
})?
.parse()
.map_err(BinstallError::from)?
} else {
Default::default()
},
});
// Destruct args before any async function to reduce size of the future
@ -225,9 +262,13 @@ fn do_read_root_cert(path: &Path) -> Result<Option<Certificate>, BinstallError>
open_cert(&buffer).map_err(From::from).map(Some)
}
fn read_root_certs(root_certificate_paths: Vec<PathBuf>) -> impl Iterator<Item = Certificate> {
fn read_root_certs(
root_certificate_paths: Vec<PathBuf>,
config_cainfo: Option<PathBuf>,
) -> impl Iterator<Item = Certificate> {
root_certificate_paths
.into_iter()
.chain(config_cainfo)
.filter_map(|path| match do_read_root_cert(&path) {
Ok(optional_cert) => optional_cert,
Err(err) => {
@ -245,12 +286,15 @@ fn compute_paths_and_load_manifests(
roots: Option<PathBuf>,
install_path: Option<PathBuf>,
no_track: bool,
cargo_home: PathBuf,
config: &mut Config,
) -> Result<(PathBuf, Option<Manifests>, tempfile::TempDir)> {
// Compute cargo_roots
let cargo_roots = install_path::get_cargo_roots_path(roots).ok_or_else(|| {
error!("No viable cargo roots path found of specified, try `--roots`");
miette!("No cargo roots path found or specified")
})?;
let cargo_roots =
install_path::get_cargo_roots_path(roots, cargo_home, config).ok_or_else(|| {
error!("No viable cargo roots path found of specified, try `--roots`");
miette!("No cargo roots path found or specified")
})?;
// Compute install directory
let (install_path, custom_install_path) =

View file

@ -3,11 +3,14 @@ use std::{
path::{Path, PathBuf},
};
use binstalk::home::cargo_home;
use binstalk_manifests::cargo_config::Config;
use tracing::debug;
pub fn get_cargo_roots_path(cargo_roots: Option<PathBuf>) -> Option<PathBuf> {
pub fn get_cargo_roots_path(
cargo_roots: Option<PathBuf>,
cargo_home: PathBuf,
config: &mut Config,
) -> Option<PathBuf> {
if let Some(p) = cargo_roots {
Some(p)
} else if let Some(p) = var_os("CARGO_INSTALL_ROOT") {
@ -15,24 +18,12 @@ pub fn get_cargo_roots_path(cargo_roots: Option<PathBuf>) -> Option<PathBuf> {
let p = PathBuf::from(p);
debug!("using CARGO_INSTALL_ROOT ({})", p.display());
Some(p)
} else if let Ok(cargo_home) = cargo_home() {
let config_path = cargo_home.join("config.toml");
if let Some(root) = Config::load_from_path(&config_path)
.ok()
.and_then(|config| config.install.root)
{
debug!(
"using `install.root` {} from config {}",
root.display(),
config_path.display()
);
Some(root)
} else {
debug!("using ({}) as cargo home", cargo_home.display());
Some(cargo_home)
}
} else if let Some(root) = config.install.take().and_then(|install| install.root) {
debug!("using `install.root` {} from cargo config", root.display());
Some(root)
} else {
None
debug!("using ({}) as cargo home", cargo_home.display());
Some(cargo_home)
}
}