mirror of
https://github.com/cargo-bins/cargo-binstall.git
synced 2025-04-21 13:08:42 +00:00
Merge pull request #226 from NobodyXu/fix/metafile-update
Fix race condition when updating metafile
This commit is contained in:
commit
d21dde4889
5 changed files with 93 additions and 55 deletions
|
@ -1,6 +1,7 @@
|
||||||
|
use std::collections::BTreeSet;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use crate::{DesiredTargets, PkgOverride};
|
use crate::{metafiles, DesiredTargets, PkgOverride};
|
||||||
|
|
||||||
mod resolve;
|
mod resolve;
|
||||||
pub use resolve::*;
|
pub use resolve::*;
|
||||||
|
@ -16,3 +17,11 @@ pub struct Options {
|
||||||
pub cli_overrides: PkgOverride,
|
pub cli_overrides: PkgOverride,
|
||||||
pub desired_targets: DesiredTargets,
|
pub desired_targets: DesiredTargets,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// MetaData required to update MetaFiles.
|
||||||
|
pub struct MetaData {
|
||||||
|
pub bins: BTreeSet<String>,
|
||||||
|
pub cvs: metafiles::CrateVersionSource,
|
||||||
|
pub version_req: String,
|
||||||
|
pub target: String,
|
||||||
|
}
|
||||||
|
|
|
@ -1,18 +1,18 @@
|
||||||
use std::{collections::BTreeSet, path::PathBuf, process, sync::Arc};
|
use std::{path::PathBuf, process, sync::Arc};
|
||||||
|
|
||||||
use cargo_toml::Package;
|
use cargo_toml::Package;
|
||||||
use log::{debug, error, info};
|
use log::{debug, error, info};
|
||||||
use miette::{miette, IntoDiagnostic, Result, WrapErr};
|
use miette::{miette, IntoDiagnostic, Result, WrapErr};
|
||||||
use tokio::{process::Command, task::block_in_place};
|
use tokio::{process::Command, task::block_in_place};
|
||||||
|
|
||||||
use super::{Options, Resolution};
|
use super::{MetaData, Options, Resolution};
|
||||||
use crate::{bins, fetchers::Fetcher, *};
|
use crate::{bins, fetchers::Fetcher, *};
|
||||||
|
|
||||||
pub async fn install(
|
pub async fn install(
|
||||||
resolution: Resolution,
|
resolution: Resolution,
|
||||||
opts: Arc<Options>,
|
opts: Arc<Options>,
|
||||||
jobserver_client: LazyJobserverClient,
|
jobserver_client: LazyJobserverClient,
|
||||||
) -> Result<()> {
|
) -> Result<Option<MetaData>> {
|
||||||
match resolution {
|
match resolution {
|
||||||
Resolution::Fetch {
|
Resolution::Fetch {
|
||||||
fetcher,
|
fetcher,
|
||||||
|
@ -37,13 +37,15 @@ pub async fn install(
|
||||||
.ok_or_else(|| miette!("No viable targets found, try with `--targets`"))?;
|
.ok_or_else(|| miette!("No viable targets found, try with `--targets`"))?;
|
||||||
|
|
||||||
if !opts.dry_run {
|
if !opts.dry_run {
|
||||||
install_from_source(package, target, jobserver_client).await
|
install_from_source(package, target, jobserver_client)
|
||||||
|
.await
|
||||||
|
.map(|_| None)
|
||||||
} else {
|
} else {
|
||||||
info!(
|
info!(
|
||||||
"Dry-run: running `cargo install {} --version {} --target {target}`",
|
"Dry-run: running `cargo install {} --version {} --target {target}`",
|
||||||
package.name, package.version
|
package.name, package.version
|
||||||
);
|
);
|
||||||
Ok(())
|
Ok(None)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -56,7 +58,7 @@ async fn install_from_package(
|
||||||
version: String,
|
version: String,
|
||||||
bin_path: PathBuf,
|
bin_path: PathBuf,
|
||||||
bin_files: Vec<bins::BinFile>,
|
bin_files: Vec<bins::BinFile>,
|
||||||
) -> Result<()> {
|
) -> Result<Option<MetaData>> {
|
||||||
// Download package
|
// Download package
|
||||||
if opts.dry_run {
|
if opts.dry_run {
|
||||||
info!("Dry run, not downloading package");
|
info!("Dry run, not downloading package");
|
||||||
|
@ -90,7 +92,7 @@ async fn install_from_package(
|
||||||
|
|
||||||
if opts.dry_run {
|
if opts.dry_run {
|
||||||
info!("Dry run, not proceeding");
|
info!("Dry run, not proceeding");
|
||||||
return Ok(());
|
return Ok(None);
|
||||||
}
|
}
|
||||||
|
|
||||||
info!("Installing binaries...");
|
info!("Installing binaries...");
|
||||||
|
@ -106,25 +108,12 @@ async fn install_from_package(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let bins: BTreeSet<String> = bin_files.into_iter().map(|bin| bin.base_name).collect();
|
Ok(Some(MetaData {
|
||||||
|
bins: bin_files.into_iter().map(|bin| bin.base_name).collect(),
|
||||||
debug!("Writing .crates.toml");
|
cvs,
|
||||||
metafiles::v1::CratesToml::append(&cvs, bins.clone())?;
|
version_req: version,
|
||||||
|
target: fetcher.target().to_string(),
|
||||||
debug!("Writing .crates2.json");
|
}))
|
||||||
metafiles::v2::Crates2Json::append(
|
|
||||||
&cvs,
|
|
||||||
metafiles::v2::CrateInfo {
|
|
||||||
version_req: Some(version),
|
|
||||||
bins,
|
|
||||||
profile: "release".into(),
|
|
||||||
target: fetcher.target().to_string(),
|
|
||||||
rustc: format!("{} {}", env!("CARGO_PKG_NAME"), env!("CARGO_PKG_VERSION")),
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
)?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
49
src/main.rs
49
src/main.rs
|
@ -12,7 +12,7 @@ use log::{debug, error, info, warn, LevelFilter};
|
||||||
use miette::{miette, Result, WrapErr};
|
use miette::{miette, Result, WrapErr};
|
||||||
use simplelog::{ColorChoice, ConfigBuilder, TermLogger, TerminalMode};
|
use simplelog::{ColorChoice, ConfigBuilder, TermLogger, TerminalMode};
|
||||||
use tempfile::TempDir;
|
use tempfile::TempDir;
|
||||||
use tokio::{runtime::Runtime, task::JoinError};
|
use tokio::{runtime::Runtime, task::block_in_place};
|
||||||
|
|
||||||
use cargo_binstall::{binstall, *};
|
use cargo_binstall::{binstall, *};
|
||||||
|
|
||||||
|
@ -330,18 +330,45 @@ async fn entry(jobserver_client: LazyJobserverClient) -> Result<()> {
|
||||||
.collect()
|
.collect()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let mut metadata_vec = Vec::with_capacity(tasks.len());
|
||||||
for task in tasks {
|
for task in tasks {
|
||||||
await_task(task).await?;
|
if let Some(metadata) = await_task(task).await? {
|
||||||
|
metadata_vec.push(metadata);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if opts.no_cleanup {
|
block_in_place(|| {
|
||||||
// Consume temp_dir without removing it from fs.
|
debug!("Writing .crates.toml");
|
||||||
temp_dir.into_path();
|
metafiles::v1::CratesToml::append(
|
||||||
} else {
|
metadata_vec
|
||||||
temp_dir.close().unwrap_or_else(|err| {
|
.iter()
|
||||||
warn!("Failed to clean up some resources: {err}");
|
.map(|metadata| (&metadata.cvs, metadata.bins.clone())),
|
||||||
});
|
)?;
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
debug!("Writing .crates2.json");
|
||||||
|
metafiles::v2::Crates2Json::append(metadata_vec.into_iter().map(|metadata| {
|
||||||
|
(
|
||||||
|
metadata.cvs,
|
||||||
|
metafiles::v2::CrateInfo {
|
||||||
|
version_req: Some(metadata.version_req),
|
||||||
|
bins: metadata.bins,
|
||||||
|
profile: "release".into(),
|
||||||
|
target: metadata.target,
|
||||||
|
rustc: format!("{} {}", env!("CARGO_PKG_NAME"), env!("CARGO_PKG_VERSION")),
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}))?;
|
||||||
|
|
||||||
|
if opts.no_cleanup {
|
||||||
|
// Consume temp_dir without removing it from fs.
|
||||||
|
temp_dir.into_path();
|
||||||
|
} else {
|
||||||
|
temp_dir.close().unwrap_or_else(|err| {
|
||||||
|
warn!("Failed to clean up some resources: {err}");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
use std::{
|
use std::{
|
||||||
collections::{BTreeMap, BTreeSet},
|
collections::{BTreeMap, BTreeSet},
|
||||||
fs, io,
|
fs, io,
|
||||||
|
iter::IntoIterator,
|
||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
str::FromStr,
|
str::FromStr,
|
||||||
};
|
};
|
||||||
|
@ -44,11 +45,13 @@ impl CratesToml {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn append_to_path(
|
pub fn append_to_path<'a, Iter>(
|
||||||
path: impl AsRef<Path>,
|
path: impl AsRef<Path>,
|
||||||
cvs: &CrateVersionSource,
|
iter: Iter,
|
||||||
bins: BTreeSet<String>,
|
) -> Result<(), CratesTomlParseError>
|
||||||
) -> Result<(), CratesTomlParseError> {
|
where
|
||||||
|
Iter: IntoIterator<Item = (&'a CrateVersionSource, BTreeSet<String>)>,
|
||||||
|
{
|
||||||
let mut c1 = match Self::load_from_path(path.as_ref()) {
|
let mut c1 = match Self::load_from_path(path.as_ref()) {
|
||||||
Ok(c1) => c1,
|
Ok(c1) => c1,
|
||||||
Err(CratesTomlParseError::Io(io_err)) if io_err.kind() == io::ErrorKind::NotFound => {
|
Err(CratesTomlParseError::Io(io_err)) if io_err.kind() == io::ErrorKind::NotFound => {
|
||||||
|
@ -56,17 +59,19 @@ impl CratesToml {
|
||||||
}
|
}
|
||||||
Err(err) => return Err(err),
|
Err(err) => return Err(err),
|
||||||
};
|
};
|
||||||
c1.insert(cvs, bins);
|
for (cvs, bins) in iter {
|
||||||
|
c1.insert(cvs, bins);
|
||||||
|
}
|
||||||
c1.write_to_path(path.as_ref())?;
|
c1.write_to_path(path.as_ref())?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn append(
|
pub fn append<'a, Iter>(iter: Iter) -> Result<(), CratesTomlParseError>
|
||||||
cvs: &CrateVersionSource,
|
where
|
||||||
bins: BTreeSet<String>,
|
Iter: IntoIterator<Item = (&'a CrateVersionSource, BTreeSet<String>)>,
|
||||||
) -> Result<(), CratesTomlParseError> {
|
{
|
||||||
Self::append_to_path(Self::default_path()?, cvs, bins)
|
Self::append_to_path(Self::default_path()?, iter)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
use std::{
|
use std::{
|
||||||
collections::{BTreeMap, BTreeSet},
|
collections::{BTreeMap, BTreeSet},
|
||||||
fs, io,
|
fs, io,
|
||||||
|
iter::IntoIterator,
|
||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -66,11 +67,13 @@ impl Crates2Json {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn append_to_path(
|
pub fn append_to_path<Iter>(
|
||||||
path: impl AsRef<Path>,
|
path: impl AsRef<Path>,
|
||||||
cvs: &CrateVersionSource,
|
iter: Iter,
|
||||||
info: CrateInfo,
|
) -> Result<(), Crates2JsonParseError>
|
||||||
) -> Result<(), Crates2JsonParseError> {
|
where
|
||||||
|
Iter: IntoIterator<Item = (CrateVersionSource, CrateInfo)>,
|
||||||
|
{
|
||||||
let mut c2 = match Self::load_from_path(path.as_ref()) {
|
let mut c2 = match Self::load_from_path(path.as_ref()) {
|
||||||
Ok(c2) => c2,
|
Ok(c2) => c2,
|
||||||
Err(Crates2JsonParseError::Io(io_err)) if io_err.kind() == io::ErrorKind::NotFound => {
|
Err(Crates2JsonParseError::Io(io_err)) if io_err.kind() == io::ErrorKind::NotFound => {
|
||||||
|
@ -78,14 +81,19 @@ impl Crates2Json {
|
||||||
}
|
}
|
||||||
Err(err) => return Err(err),
|
Err(err) => return Err(err),
|
||||||
};
|
};
|
||||||
c2.insert(cvs, info);
|
for (cvs, info) in iter {
|
||||||
|
c2.insert(&cvs, info);
|
||||||
|
}
|
||||||
c2.write_to_path(path.as_ref())?;
|
c2.write_to_path(path.as_ref())?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn append(cvs: &CrateVersionSource, info: CrateInfo) -> Result<(), Crates2JsonParseError> {
|
pub fn append<Iter>(iter: Iter) -> Result<(), Crates2JsonParseError>
|
||||||
Self::append_to_path(Self::default_path()?, cvs, info)
|
where
|
||||||
|
Iter: IntoIterator<Item = (CrateVersionSource, CrateInfo)>,
|
||||||
|
{
|
||||||
|
Self::append_to_path(Self::default_path()?, iter)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue