diff --git a/radicle-node/src/runtime.rs b/radicle-node/src/runtime.rs index 4d86f7ec..9b3f853e 100644 --- a/radicle-node/src/runtime.rs +++ b/radicle-node/src/runtime.rs @@ -136,13 +136,7 @@ impl Runtime { let network = config.network; let rng = fastrand::Rng::new(); let clock = LocalTime::now(); - let storage = Storage::open( - home.storage(), - git::UserInfo { - alias: alias.clone(), - key: id, - }, - )?; + let storage = Storage::open(home.storage(), git::UserInfo { alias, key: id })?; let address_db = node_dir.join(ADDRESS_DB_FILE); let routing_db = node_dir.join(ROUTING_DB_FILE); let tracking_db = node_dir.join(TRACKING_DB_FILE); @@ -254,7 +248,6 @@ impl Runtime { scope, tracking_db, limit: FetchLimit::default(), - info: git::UserInfo { alias, key: nid }, local: nid, expiry: worker::garbage::Expiry::default(), }; diff --git a/radicle-node/src/worker.rs b/radicle-node/src/worker.rs index 3c49e3c0..513d020f 100644 --- a/radicle-node/src/worker.rs +++ b/radicle-node/src/worker.rs @@ -14,7 +14,7 @@ use radicle::identity::Id; use radicle::prelude::NodeId; use radicle::storage::refs::RefsAt; use radicle::storage::{ReadRepository, ReadStorage}; -use radicle::{crypto, git, Storage}; +use radicle::{crypto, Storage}; use radicle_fetch::FetchLimit; use crate::runtime::{thread, Handle}; @@ -159,8 +159,6 @@ pub struct FetchConfig { pub tracking_db: PathBuf, /// Data limits when fetching from a remote. pub limit: FetchLimit, - /// Information of the local peer. - pub info: git::UserInfo, /// Public key of the local peer. pub local: crypto::PublicKey, /// Configuration for `git gc` garbage collection. Defaults to `1 @@ -281,7 +279,6 @@ impl Worker { scope, tracking_db, limit, - info, local, expiry, } = &self.fetch_config; @@ -292,15 +289,7 @@ impl Worker { let tracked = radicle_fetch::Tracked::from_config(rid, &tracking)?; let blocked = radicle_fetch::BlockList::from_config(&tracking)?; - let handle = fetch::Handle::new( - rid, - *local, - info.clone(), - &self.storage, - tracked, - blocked, - channels, - )?; + let handle = fetch::Handle::new(rid, *local, &self.storage, tracked, blocked, channels)?; let result = handle.fetch(rid, &self.storage, *limit, remote, refs_at)?; if let Err(e) = garbage::collect(&self.storage, rid, *expiry) { diff --git a/radicle-node/src/worker/fetch.rs b/radicle-node/src/worker/fetch.rs index 0fbaaa65..c66447a6 100644 --- a/radicle-node/src/worker/fetch.rs +++ b/radicle-node/src/worker/fetch.rs @@ -3,9 +3,7 @@ pub mod error; use std::collections::HashSet; use radicle::crypto::PublicKey; -use radicle::git::UserInfo; use radicle::prelude::Id; -use radicle::storage::git::Repository; use radicle::storage::refs::RefsAt; use radicle::storage::{ReadStorage as _, RefUpdate, WriteRepository as _}; use radicle::Storage; @@ -35,7 +33,6 @@ impl Handle { pub fn new( rid: Id, local: PublicKey, - info: UserInfo, storage: &Storage, tracked: Tracked, blocked: BlockList, @@ -47,8 +44,7 @@ impl Handle { let handle = radicle_fetch::Handle::new(local, repo, tracked, blocked, channels)?; Ok(Handle::Pull { handle }) } else { - let tmp = tempfile::tempdir()?; - let repo = Repository::create(tmp.path(), rid, &info)?; + let (repo, tmp) = storage.lock_repository(rid)?; let handle = radicle_fetch::Handle::new(local, repo, tracked, blocked, channels)?; Ok(Handle::Clone { handle, tmp }) } diff --git a/radicle/src/storage/git.rs b/radicle/src/storage/git.rs index 78a91ac0..3ae20434 100644 --- a/radicle/src/storage/git.rs +++ b/radicle/src/storage/git.rs @@ -9,6 +9,7 @@ use std::{fs, io}; use crypto::{Signer, Verified}; use once_cell::sync::Lazy; +use tempfile::TempDir; use crate::crypto::Unverified; use crate::git; @@ -152,6 +153,27 @@ impl Storage { Ok(Self { path, info }) } + /// Create a [`Repository`] in a temporary directory. + /// + /// N.b. it is important to keep the [`TempDir`] in scope while + /// using the [`Repository`]. If it is dropped, any action on the + /// `Repository` will fail. + pub fn lock_repository(&self, rid: Id) -> Result<(Repository, TempDir), RepositoryError> { + if self.contains(&rid)? { + return Err(Error::Io(io::Error::new( + io::ErrorKind::AlreadyExists, + format!("refusing to create '{}.lock'", rid), + )) + .into()); + } + let tmp = tempfile::Builder::new() + .prefix(&rid.canonical()) + .suffix(".lock") + .tempdir_in(self.path()) + .map_err(Error::from)?; + Ok((Repository::create(tmp.path(), rid, &self.info)?, tmp)) + } + pub fn path(&self) -> &Path { self.path.as_path() } @@ -170,6 +192,12 @@ impl Storage { if path.file_name().to_string_lossy().starts_with('.') { continue; } + // Skip lock files. + if let Some(ext) = path.path().extension() { + if ext == "lock" { + continue; + } + } let rid = Id::try_from(path.file_name()).map_err(|_| Error::InvalidId(path.file_name()))?;