mirror of
https://github.com/cargo-bins/cargo-binstall.git
synced 2025-04-24 22:30:03 +00:00
Feature: Check for installed crates in cargo_install_v1_manifest (#582)
* Add & Impl new fn `CratesToml::collect_into_crates_versions` to iterate over crates listed in cargo_crates_v1, accessing their names and versions. * Re-export `CompactString`, `Version` & `Url` in binstalk-manifests for convenience * Fix `CratesToml::load_from_path`: Wrap `File` in `FileLock::new_shared` to avoid concurrent write while reading the file. * Filter out installed crates in cargo_install_v1_metadata * Make match in `filter_out_installed_crates` more explicit * Add new test `cargo_crates_v1::test::test_loading` * Optimize `CratesToml`: Use `Vec` instead of `BTreeMap` since we cannot simply call `BTreeMap::get` to find an entry for a crate anyway. This also accidentally fixed the CI. * Impl new API `CratesToml::remove` * Fix`CratesToml::append_to_path` by removing previous records of the crates that are just updated. Signed-off-by: Jiahao XU <Jiahao_XU@outlook.com>
This commit is contained in:
parent
887ebb6f6f
commit
39f175be04
3 changed files with 164 additions and 23 deletions
|
@ -1,4 +1,4 @@
|
|||
use std::{fs, path::PathBuf, sync::Arc, time::Duration};
|
||||
use std::{collections::BTreeMap, fs, io, path::PathBuf, sync::Arc, time::Duration};
|
||||
|
||||
use binstalk::{
|
||||
errors::BinstallError,
|
||||
|
@ -12,7 +12,10 @@ use binstalk::{
|
|||
},
|
||||
};
|
||||
use binstalk_manifests::{
|
||||
binstall_crates_v1::Records, cargo_crates_v1::CratesToml, cargo_toml_binstall::PkgOverride,
|
||||
binstall_crates_v1::Records as BinstallCratesV1Records,
|
||||
cargo_crates_v1::{CratesToml, CratesTomlParseError},
|
||||
cargo_toml_binstall::PkgOverride,
|
||||
CompactString, Version,
|
||||
};
|
||||
use crates_io_api::AsyncClient as CratesIoApiClient;
|
||||
use log::LevelFilter;
|
||||
|
@ -167,7 +170,7 @@ pub async fn install_crates(args: Args, jobserver_client: LazyJobserverClient) -
|
|||
}
|
||||
|
||||
block_in_place(|| {
|
||||
if let Some(mut records) = metadata {
|
||||
if let Some((mut cargo_binstall_metadata, _)) = metadata {
|
||||
// The cargo manifest path is already created when loading
|
||||
// metadata.
|
||||
|
||||
|
@ -176,9 +179,9 @@ pub async fn install_crates(args: Args, jobserver_client: LazyJobserverClient) -
|
|||
|
||||
debug!("Writing binstall/crates-v1.json");
|
||||
for metadata in metadata_vec {
|
||||
records.replace(metadata);
|
||||
cargo_binstall_metadata.replace(metadata);
|
||||
}
|
||||
records.overwrite()?;
|
||||
cargo_binstall_metadata.overwrite()?;
|
||||
}
|
||||
|
||||
if no_cleanup {
|
||||
|
@ -194,11 +197,13 @@ pub async fn install_crates(args: Args, jobserver_client: LazyJobserverClient) -
|
|||
})
|
||||
}
|
||||
|
||||
type Metadata = (BinstallCratesV1Records, BTreeMap<CompactString, Version>);
|
||||
|
||||
/// Return (install_path, cargo_roots, metadata, temp_dir)
|
||||
fn compute_paths_and_load_manifests(
|
||||
roots: Option<PathBuf>,
|
||||
install_path: Option<PathBuf>,
|
||||
) -> Result<(PathBuf, PathBuf, Option<Records>, tempfile::TempDir)> {
|
||||
) -> Result<(PathBuf, PathBuf, Option<Metadata>, tempfile::TempDir)> {
|
||||
block_in_place(|| {
|
||||
// Compute cargo_roots
|
||||
let cargo_roots = install_path::get_cargo_roots_path(roots).ok_or_else(|| {
|
||||
|
@ -218,12 +223,40 @@ fn compute_paths_and_load_manifests(
|
|||
|
||||
// Load metadata
|
||||
let metadata = if !custom_install_path {
|
||||
// Read cargo_binstall_metadata
|
||||
let metadata_dir = cargo_roots.join("binstall");
|
||||
fs::create_dir_all(&metadata_dir).map_err(BinstallError::Io)?;
|
||||
let manifest_path = metadata_dir.join("crates-v1.json");
|
||||
|
||||
debug!("Reading {}", manifest_path.display());
|
||||
Some(Records::load_from_path(&manifest_path)?)
|
||||
debug!(
|
||||
"Reading {} from {}",
|
||||
"cargo_binstall_metadata",
|
||||
manifest_path.display()
|
||||
);
|
||||
|
||||
let cargo_binstall_metadata = BinstallCratesV1Records::load_from_path(&manifest_path)?;
|
||||
|
||||
// Read cargo_install_v1_metadata
|
||||
let manifest_path = cargo_roots.join(".crates.toml");
|
||||
|
||||
debug!(
|
||||
"Reading {} from {}",
|
||||
"cargo_install_v1_metadata",
|
||||
manifest_path.display()
|
||||
);
|
||||
|
||||
let cargo_install_v1_metadata = match CratesToml::load_from_path(&manifest_path) {
|
||||
Ok(metadata) => metadata.collect_into_crates_versions()?,
|
||||
Err(CratesTomlParseError::Io(io_err))
|
||||
if io_err.kind() == io::ErrorKind::NotFound =>
|
||||
{
|
||||
// .crates.toml does not exist, create an empty BTreeMap
|
||||
Default::default()
|
||||
}
|
||||
Err(err) => Err(err)?,
|
||||
};
|
||||
|
||||
Some((cargo_binstall_metadata, cargo_install_v1_metadata))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
@ -247,30 +280,42 @@ fn compute_paths_and_load_manifests(
|
|||
fn filter_out_installed_crates(
|
||||
crate_names: Vec<CrateName>,
|
||||
force: bool,
|
||||
metadata: Option<&Records>,
|
||||
metadata: Option<&Metadata>,
|
||||
) -> impl Iterator<Item = (CrateName, Option<semver::Version>)> + '_ {
|
||||
CrateName::dedup(crate_names)
|
||||
.filter_map(move |crate_name| {
|
||||
let name = &crate_name.name;
|
||||
|
||||
let curr_version = metadata
|
||||
.and_then(|metadata| {
|
||||
metadata
|
||||
.0
|
||||
.get(name)
|
||||
.map(|crate_info| &crate_info.current_version)
|
||||
.into_iter()
|
||||
.chain(metadata.1.get(name))
|
||||
// Since the cargo_install_v1_metadata could be out of sync
|
||||
// from cargo_binstall_metadata, it is better to obtain
|
||||
// the version from both of them and takes the larger one.
|
||||
.max()
|
||||
});
|
||||
|
||||
match (
|
||||
force,
|
||||
metadata.and_then(|records| records.get(&crate_name.name)),
|
||||
curr_version,
|
||||
&crate_name.version_req,
|
||||
) {
|
||||
(false, Some(metadata), Some(version_req))
|
||||
if version_req.is_latest_compatible(&metadata.current_version) =>
|
||||
(false, Some(curr_version), Some(version_req))
|
||||
if version_req.is_latest_compatible(curr_version) =>
|
||||
{
|
||||
debug!("Bailing out early because we can assume wanted is already installed from metafile");
|
||||
info!(
|
||||
"{} v{} is already installed, use --force to override",
|
||||
crate_name.name, metadata.current_version
|
||||
);
|
||||
info!("{name} v{curr_version} is already installed, use --force to override");
|
||||
None
|
||||
}
|
||||
|
||||
// we have to assume that the version req could be *,
|
||||
// and therefore a remote upgraded version could exist
|
||||
(false, Some(metadata), _) => {
|
||||
Some((crate_name, Some(metadata.current_version.clone())))
|
||||
// The version req is "*" thus a remote upgraded version could exist
|
||||
(false, Some(curr_version), None) => {
|
||||
Some((crate_name, Some(curr_version.clone())))
|
||||
}
|
||||
|
||||
_ => Some((crate_name, None)),
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue