diff --git a/Cargo.lock b/Cargo.lock index 56aadad0..462cf901 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1059,6 +1059,16 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "fs4" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d15c33be2d8e5bc0e6229c8c20905d69d6074c92c64c9b3485560b6d6dc1b68" +dependencies = [ + "rustix", + "windows-sys 0.52.0", +] + [[package]] name = "fsevent-sys" version = "4.1.0" @@ -4415,6 +4425,7 @@ name = "veryl-metadata" version = "0.6.0" dependencies = [ "directories", + "fs4", "git-repository", "log", "miette", diff --git a/crates/metadata/Cargo.toml b/crates/metadata/Cargo.toml index 22aa803b..72d9b708 100644 --- a/crates/metadata/Cargo.toml +++ b/crates/metadata/Cargo.toml @@ -16,6 +16,7 @@ edition = "2021" directories = "5.0" git-repository = {version = "0.35.0", optional = true, features = ["blocking-network-client", "blocking-http-transport-reqwest", "blocking-http-transport-reqwest-rust-tls"]} log = {workspace = true} +fs4 = { version = "0.8.0", features = ["sync"] } miette = {workspace = true} regex = {workspace = true} semver = {workspace = true} diff --git a/crates/metadata/src/lockfile.rs b/crates/metadata/src/lockfile.rs index 43ee70fe..4d9083a1 100644 --- a/crates/metadata/src/lockfile.rs +++ b/crates/metadata/src/lockfile.rs @@ -3,11 +3,12 @@ use crate::metadata::{Dependency, Metadata}; use crate::metadata_error::MetadataError; use crate::pubfile::{Pubfile, Release}; use crate::{utils, PathPair}; +use fs4::FileExt; use log::info; use semver::{Version, VersionReq}; use serde::{Deserialize, Serialize}; use std::collections::{HashMap, HashSet}; -use std::fs; +use std::fs::{self, File}; use std::path::Path; use std::str::FromStr; use url::Url; @@ -339,9 +340,11 @@ impl Lockfile { let uuid = Self::gen_uuid(url, "")?; let path = resolve_dir.join(uuid.simple().encode_lower(&mut Uuid::encode_buffer())); + let lock = Self::lock_dir("resolve")?; let git = Git::clone(url, &path)?; git.fetch()?; git.checkout(None)?; + Self::unlock_dir(lock)?; let toml = path.join("Veryl.pub"); let mut pubfile = Pubfile::load(toml)?; @@ -373,25 +376,42 @@ impl Lockfile { let toml = path.join("Veryl.toml"); if !path.exists() { + let lock = Self::lock_dir("dependencies")?; let git = Git::clone(url, &path)?; git.fetch()?; git.checkout(Some(revision))?; + Self::unlock_dir(lock)?; } else { let git = Git::open(&path)?; let ret = git.is_clean().map_or(false, |x| x); // If the existing path is not git repository, cleanup and re-try if !ret || !toml.exists() { + let lock = Self::lock_dir("dependencies")?; fs::remove_dir_all(&path)?; let git = Git::clone(url, &path)?; git.fetch()?; git.checkout(Some(revision))?; + Self::unlock_dir(lock)?; } } let metadata = Metadata::load(toml)?; Ok(metadata) } + + fn lock_dir(path: &str) -> Result { + let base_dir = Metadata::cache_dir().join(path); + let lock = base_dir.join("lock"); + let lock = File::create(lock)?; + lock.lock_exclusive()?; + Ok(lock) + } + + fn unlock_dir(lock: File) -> Result<(), MetadataError> { + lock.unlock()?; + Ok(()) + } } impl FromStr for Lockfile {