Make `Id` a `Copy`

This commit is contained in:
Alexis Sellier 2022-09-27 14:13:20 +02:00
parent a20d16fc31
commit 27e39c0df5
No known key found for this signature in database
11 changed files with 78 additions and 77 deletions

View File

@ -108,7 +108,7 @@ fn drain<H: Handle>(stream: &UnixStream, handle: &H) -> Result<(), DrainError> {
}
fn fetch<W: Write, H: Handle>(id: Id, mut writer: W, handle: &H) -> Result<(), DrainError> {
match handle.fetch(id.clone()) {
match handle.fetch(id) {
Err(e) => {
return Err(DrainError::Client(e));
}

View File

@ -272,7 +272,7 @@ where
}
/// Get a project from storage, using the local node's key.
pub fn get(&self, proj: &Id) -> Result<Option<Doc<Verified>>, storage::Error> {
pub fn get(&self, proj: Id) -> Result<Option<Doc<Verified>>, storage::Error> {
self.storage.get(&self.node_id(), proj)
}
@ -306,12 +306,12 @@ where
&mut self.reactor
}
pub fn lookup(&self, id: &Id) -> Lookup {
pub fn lookup(&self, id: Id) -> Lookup {
Lookup {
local: self.storage.get(&self.node_id(), id).unwrap(),
remote: self
.routing
.get(id)
.get(&id)
.map_or(vec![], |r| r.iter().cloned().collect()),
}
}
@ -391,7 +391,7 @@ where
};
log::debug!("Found {} seeds for {}", seeds.len(), id);
let mut repo = match self.storage.repository(&id) {
let mut repo = match self.storage.repository(id) {
Ok(repo) => repo,
Err(err) => {
log::error!("Error opening repo for {}: {}", id, err);
@ -445,7 +445,7 @@ where
}
Command::AnnounceRefs(id) => {
let node = self.node_id();
let repo = self.storage.repository(&id).unwrap();
let repo = self.storage.repository(id).unwrap();
let remote = repo.remote(&node).unwrap();
let peers = self.sessions.negotiated().map(|(_, p)| p);
let refs = remote.refs.into();
@ -689,12 +689,12 @@ where
// TODO: Check that we're tracking this user as well.
if self.config.is_tracking(&message.id) {
// TODO: Check refs to see if we should try to fetch or not.
let updated = self.storage.fetch(&message.id, git).unwrap();
let updated = self.storage.fetch(message.id, git).unwrap();
let is_updated = !updated.is_empty();
self.reactor.event(Event::RefsFetched {
from: git.clone(),
project: message.id.clone(),
project: message.id,
updated,
});
@ -747,12 +747,12 @@ where
for proj_id in inventory {
let inventory = self
.routing
.entry(proj_id.clone())
.entry(*proj_id)
.or_insert_with(|| HashSet::with_hasher(self.rng.clone().into()));
// TODO: Fire an event on routing update.
if inventory.insert(from) && self.config.is_tracking(proj_id) {
self.storage.fetch(proj_id, remote).unwrap();
self.storage.fetch(*proj_id, remote).unwrap();
}
}
}

View File

@ -95,7 +95,7 @@ impl Reactor {
/// Relay a message to interested peers.
pub fn relay<'a>(&mut self, msg: Message, peers: impl IntoIterator<Item = &'a Session>) {
if let Message::RefsAnnouncement { message, .. } = &msg {
let id = message.id.clone();
let id = message.id;
let peers = peers.into_iter().filter(|p| {
if let Some(subscribe) = &p.subscribe {
subscribe.filter.contains(&id)

View File

@ -168,7 +168,7 @@ fn test_tracking() {
let proj_id: identity::Id = test::arbitrary::gen(1);
let (sender, receiver) = chan::bounded(1);
alice.command(Command::Track(proj_id.clone(), sender));
alice.command(Command::Track(proj_id, sender));
let policy_change = receiver
.recv()
.map_err(client::handle::Error::from)
@ -177,7 +177,7 @@ fn test_tracking() {
assert!(alice.config().is_tracking(&proj_id));
let (sender, receiver) = chan::bounded(1);
alice.command(Command::Untrack(proj_id.clone(), sender));
alice.command(Command::Untrack(proj_id, sender));
let policy_change = receiver
.recv()
.map_err(client::handle::Error::from)
@ -405,30 +405,30 @@ fn test_push_and_pull() {
// Bob tracks Alice's project.
let (sender, _) = chan::bounded(1);
bob.command(service::Command::Track(proj_id.clone(), sender));
bob.command(service::Command::Track(proj_id, sender));
// Eve tracks Alice's project.
let (sender, _) = chan::bounded(1);
eve.command(service::Command::Track(proj_id.clone(), sender));
eve.command(service::Command::Track(proj_id, sender));
// Neither of them have it in the beginning.
assert!(eve.get(&proj_id).unwrap().is_none());
assert!(bob.get(&proj_id).unwrap().is_none());
assert!(eve.get(proj_id).unwrap().is_none());
assert!(bob.get(proj_id).unwrap().is_none());
// Alice announces her refs.
// We now expect Eve to fetch Alice's project from Alice.
// Then we expect Bob to fetch Alice's project from Eve.
alice.command(service::Command::AnnounceRefs(proj_id.clone()));
alice.command(service::Command::AnnounceRefs(proj_id));
sim.run_while([&mut alice, &mut bob, &mut eve], |s| !s.is_settled());
assert!(eve
.storage()
.get(&alice.node_id(), &proj_id)
.get(&alice.node_id(), proj_id)
.unwrap()
.is_some());
assert!(bob
.storage()
.get(&alice.node_id(), &proj_id)
.get(&alice.node_id(), proj_id)
.unwrap()
.is_some());
assert_matches!(
@ -455,7 +455,7 @@ fn prop_inventory_exchange_dense() {
] {
for id in inv.keys() {
routing
.entry(id.clone())
.entry(*id)
.or_insert_with(|| HashSet::with_hasher(rng.clone().into()))
.insert(*peer);
}
@ -481,16 +481,16 @@ fn prop_inventory_exchange_dense() {
for (proj_id, remotes) in &routing {
for peer in peers.values() {
let lookup = peer.lookup(proj_id);
let lookup = peer.lookup(*proj_id);
if lookup.local.is_some() {
peer.get(proj_id)
peer.get(*proj_id)
.expect("There are no errors querying storage")
.expect("The project is available locally");
} else {
for remote in &lookup.remote {
peers[remote]
.get(proj_id)
.get(*proj_id)
.expect("There are no errors querying storage")
.expect("The project is available remotely");
}

View File

@ -11,7 +11,7 @@ fn main() -> anyhow::Result<()> {
let output = radicle::git::run(&cwd, &["push", "rad"])?;
println!("{}", output);
let project = profile.storage.repository(&id)?;
let project = profile.storage.repository(id)?;
let sigrefs = profile.storage.sign_refs(&project, &profile.signer)?;
profile.node()?.announce_refs(&id)?;

View File

@ -138,7 +138,7 @@ impl Doc<Verified> {
//
let (doc_oid, doc) = self.encode()?;
let id = Id::from(doc_oid);
let repo = storage.repository(&id).unwrap();
let repo = storage.repository(id).unwrap();
let tree = git::write_tree(*PATH, doc.as_slice(), repo.raw())?;
let oid = Doc::commit(remote, &tree, msg, &[], repo.raw())?;
@ -379,6 +379,8 @@ pub enum IdentityError {
InvalidSignature(PublicKey, crypto::Error),
#[error("quorum not reached: {0} signatures for a threshold of {1}")]
QuorumNotReached(usize, usize),
#[error("the identity branch was not found")]
NotFound,
}
#[derive(Clone, Debug, PartialEq, Eq)]
@ -421,7 +423,7 @@ impl Identity<Untrusted> {
pub fn load<R: ReadRepository>(
remote: &RemoteId,
repo: &R,
) -> Result<Option<Identity<Oid>>, IdentityError> {
) -> Result<Identity<Oid>, IdentityError> {
if let Some(head) = Doc::<Untrusted>::head(remote, repo)? {
let mut history = repo.revwalk(head)?.collect::<Vec<_>>();
@ -466,16 +468,16 @@ impl Identity<Untrusted> {
current = blob.id().into();
}
return Ok(Some(Identity {
return Ok(Identity {
root,
head,
current,
revision,
doc: trusted,
signatures: signatures.into_iter().collect(),
}));
});
}
Ok(None)
Err(IdentityError::NotFound)
}
}
@ -505,14 +507,14 @@ mod test {
fixtures::project(tempdir.path().join("copy"), &storage, &alice).unwrap();
// Bob and Eve fork the project from Alice.
rad::fork_remote(&id, alice.public_key(), &bob, &storage).unwrap();
rad::fork_remote(&id, alice.public_key(), &eve, &storage).unwrap();
rad::fork_remote(id, alice.public_key(), &bob, &storage).unwrap();
rad::fork_remote(id, alice.public_key(), &eve, &storage).unwrap();
// TODO: In some cases we want to get the repo and the project, but don't
// want to have to create a repository object twice. Perhaps there should
// be a way of getting a project from a repo.
let mut proj = storage.get(alice.public_key(), &id).unwrap().unwrap();
let repo = storage.repository(&id).unwrap();
let mut proj = storage.get(alice.public_key(), id).unwrap().unwrap();
let repo = storage.repository(id).unwrap();
// Make a change to the description and sign it.
proj.payload.description += "!";
@ -575,8 +577,7 @@ mod test {
let identity: Identity<Id> = Identity::load(alice.public_key(), &repo)
.unwrap()
.unwrap()
.verified(id.clone())
.verified(id)
.unwrap();
assert_eq!(identity.signatures.len(), 2);
@ -586,7 +587,7 @@ mod test {
assert_eq!(identity.head, head);
assert_eq!(identity.doc, proj);
let proj = storage.get(alice.public_key(), &id).unwrap().unwrap();
let proj = storage.get(alice.public_key(), id).unwrap().unwrap();
assert_eq!(proj.description, "Acme's repository!?");
}

View File

@ -17,7 +17,7 @@ pub enum IdError {
Multibase(#[from] multibase::Error),
}
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Id(git::Oid);
impl fmt::Display for Id {

View File

@ -100,7 +100,7 @@ pub enum ForkError {
/// Create a local tree for an existing project, from an existing remote.
pub fn fork_remote<G: Signer, S: storage::WriteStorage>(
proj: &Id,
proj: Id,
remote: &RemoteId,
signer: G,
storage: S,
@ -117,7 +117,7 @@ pub fn fork_remote<G: Signer, S: storage::WriteStorage>(
let me = signer.public_key();
let project = storage
.get(remote, proj)?
.ok_or_else(|| ForkError::NotFound(proj.clone()))?;
.ok_or(ForkError::NotFound(proj))?;
let repository = storage.repository(proj)?;
let raw = repository.raw();
@ -149,7 +149,7 @@ pub fn fork_remote<G: Signer, S: storage::WriteStorage>(
}
pub fn fork<G: Signer, S: storage::WriteStorage>(
proj: &Id,
proj: Id,
signer: &G,
storage: &S,
) -> Result<(), ForkError> {
@ -208,13 +208,13 @@ pub enum CloneError {
}
pub fn clone<P: AsRef<Path>, G: Signer, S: storage::WriteStorage, H: node::Handle>(
proj: &Id,
proj: Id,
path: P,
signer: &G,
storage: &S,
handle: &H,
) -> Result<git2::Repository, CloneError> {
let _ = handle.fetch(proj)?;
let _ = handle.fetch(&proj)?;
let _ = fork(proj, signer, storage)?;
let working = checkout(proj, signer.public_key(), path, storage)?;
@ -234,7 +234,7 @@ pub enum CloneUrlError {
}
pub fn clone_url<P: AsRef<Path>, G: Signer, S: storage::WriteStorage>(
proj: &Id,
proj: Id,
url: &git::Url,
path: P,
signer: &G,
@ -261,7 +261,7 @@ pub enum CheckoutError {
/// Checkout a project from storage as a working copy.
/// This effectively does a `git-clone` from storage.
pub fn checkout<P: AsRef<Path>, S: storage::ReadStorage>(
proj: &Id,
proj: Id,
remote: &RemoteId,
path: P,
storage: &S,
@ -270,14 +270,14 @@ pub fn checkout<P: AsRef<Path>, S: storage::ReadStorage>(
// TODO: Look into sharing object databases.
let project = storage
.get(remote, proj)?
.ok_or_else(|| CheckoutError::NotFound(proj.clone()))?;
.ok_or(CheckoutError::NotFound(proj))?;
let mut opts = git2::RepositoryInitOptions::new();
opts.no_reinit(true).description(&project.description);
let repo = git2::Repository::init_opts(path, &opts)?;
let default_branch = project.default_branch.as_str();
let url = storage.url(proj);
let url = storage.url(&proj);
// Configure and fetch all refs from remote.
git::configure_remote(&repo, REMOTE_NAME, remote, &url)?.fetch::<&str>(&[], None, None)?;
@ -341,9 +341,9 @@ mod tests {
)
.unwrap();
let project = storage.get(&public_key, &proj).unwrap().unwrap();
let project = storage.get(&public_key, proj).unwrap().unwrap();
let remotes: HashMap<_, _> = storage
.repository(&proj)
.repository(proj)
.unwrap()
.remotes()
.unwrap()
@ -385,10 +385,10 @@ mod tests {
.unwrap();
// Bob forks it and creates a checkout.
fork(&id, &bob, &storage).unwrap();
checkout(&id, bob_id, tempdir.path().join("copy"), &storage).unwrap();
fork(id, &bob, &storage).unwrap();
checkout(id, bob_id, tempdir.path().join("copy"), &storage).unwrap();
let bob_remote = storage.repository(&id).unwrap().remote(bob_id).unwrap();
let bob_remote = storage.repository(id).unwrap().remote(bob_id).unwrap();
assert_eq!(
bob_remote.refs.get(&refname!("master")),
@ -414,7 +414,7 @@ mod tests {
)
.unwrap();
let copy = checkout(&id, remote_id, tempdir.path().join("copy"), &storage).unwrap();
let copy = checkout(id, remote_id, tempdir.path().join("copy"), &storage).unwrap();
assert_eq!(
copy.head().unwrap().target(),

View File

@ -218,20 +218,20 @@ impl Remote<Verified> {
pub trait ReadStorage {
fn path(&self) -> &Path;
fn url(&self, proj: &Id) -> Url;
fn get(&self, remote: &RemoteId, proj: &Id) -> Result<Option<identity::Doc<Verified>>, Error>;
fn get(&self, remote: &RemoteId, proj: Id) -> Result<Option<identity::Doc<Verified>>, Error>;
fn inventory(&self) -> Result<Inventory, Error>;
}
pub trait WriteStorage: ReadStorage {
type Repository: WriteRepository;
fn repository(&self, proj: &Id) -> Result<Self::Repository, Error>;
fn repository(&self, proj: Id) -> Result<Self::Repository, Error>;
fn sign_refs<G: Signer>(
&self,
repository: &Self::Repository,
signer: G,
) -> Result<SignedRefs<Verified>, Error>;
fn fetch(&self, proj_id: &Id, remote: &Url) -> Result<Vec<RefUpdate>, FetchError>;
fn fetch(&self, proj_id: Id, remote: &Url) -> Result<Vec<RefUpdate>, FetchError>;
}
pub trait ReadRepository {
@ -280,7 +280,7 @@ where
self.deref().inventory()
}
fn get(&self, remote: &RemoteId, proj: &Id) -> Result<Option<identity::Doc<Verified>>, Error> {
fn get(&self, remote: &RemoteId, proj: Id) -> Result<Option<identity::Doc<Verified>>, Error> {
self.deref().get(remote, proj)
}
}
@ -292,7 +292,7 @@ where
{
type Repository = S::Repository;
fn repository(&self, proj: &Id) -> Result<Self::Repository, Error> {
fn repository(&self, proj: Id) -> Result<Self::Repository, Error> {
self.deref().repository(proj)
}
@ -304,7 +304,7 @@ where
self.deref().sign_refs(repository, signer)
}
fn fetch(&self, proj_id: &Id, remote: &Url) -> Result<Vec<RefUpdate>, FetchError> {
fn fetch(&self, proj_id: Id, remote: &Url) -> Result<Vec<RefUpdate>, FetchError> {
self.deref().fetch(proj_id, remote)
}
}

View File

@ -66,7 +66,7 @@ impl ReadStorage for Storage {
}
}
fn get(&self, remote: &RemoteId, proj: &Id) -> Result<Option<Doc<Verified>>, Error> {
fn get(&self, remote: &RemoteId, proj: Id) -> Result<Option<Doc<Verified>>, Error> {
// TODO: Don't create a repo here if it doesn't exist?
// Perhaps for checking we could have a `contains` method?
self.repository(proj)?
@ -82,8 +82,8 @@ impl ReadStorage for Storage {
impl WriteStorage for Storage {
type Repository = Repository;
fn repository(&self, proj: &Id) -> Result<Self::Repository, Error> {
Repository::open(paths::repository(self, proj))
fn repository(&self, proj: Id) -> Result<Self::Repository, Error> {
Repository::open(paths::repository(self, &proj))
}
fn sign_refs<G: Signer>(
@ -94,7 +94,7 @@ impl WriteStorage for Storage {
repository.sign_refs(signer)
}
fn fetch(&self, proj_id: &Id, remote: &Url) -> Result<Vec<RefUpdate>, FetchError> {
fn fetch(&self, proj_id: Id, remote: &Url) -> Result<Vec<RefUpdate>, FetchError> {
let mut repo = self.repository(proj_id).unwrap();
let mut path = remote.path.clone();
@ -139,7 +139,7 @@ impl Storage {
pub fn inspect(&self) -> Result<(), Error> {
for proj in self.projects()? {
let repo = self.repository(&proj)?;
let repo = self.repository(proj)?;
for r in repo.raw().references()? {
let r = r?;
@ -264,7 +264,7 @@ impl Repository {
Ok(())
}
pub fn identity(&self, remote: &RemoteId) -> Result<Option<Identity<Oid>>, IdentityError> {
pub fn identity(&self, remote: &RemoteId) -> Result<Identity<Oid>, IdentityError> {
Identity::load(remote, self)
}
@ -648,7 +648,7 @@ mod tests {
})
.unwrap();
let project = storage.repository(proj).unwrap();
let project = storage.repository(*proj).unwrap();
let remotes = project.remotes().unwrap();
// Strip the remote refs of sigrefs so we can compare them.
@ -671,7 +671,7 @@ mod tests {
let alice = fixtures::storage(tmp.path().join("alice"), alice_signer).unwrap();
let bob = Storage::open(tmp.path().join("bob")).unwrap();
let inventory = alice.inventory().unwrap();
let proj = inventory.first().unwrap();
let proj = *inventory.first().unwrap();
let repo = alice.repository(proj).unwrap();
let remotes = repo.remotes().unwrap().collect::<Vec<_>>();
let refname = git::refname!("heads/master");
@ -682,7 +682,7 @@ mod tests {
.unwrap()
.fetch(&git::Url {
scheme: git_url::Scheme::File,
path: paths::repository(&alice, proj)
path: paths::repository(&alice, &proj)
.to_string_lossy()
.into_owned()
.into(),
@ -734,11 +734,11 @@ mod tests {
};
// Have Bob fetch Alice's refs.
let updates = bob.repository(&proj_id).unwrap().fetch(&alice_url).unwrap();
let updates = bob.repository(proj_id).unwrap().fetch(&alice_url).unwrap();
// Three refs are created: the branch, the signature and the id.
assert_eq!(updates.len(), 3);
let alice_proj_storage = alice.repository(&proj_id).unwrap();
let alice_proj_storage = alice.repository(proj_id).unwrap();
let alice_head = proj_repo.find_commit(alice_head).unwrap();
let alice_head = git::commit(&proj_repo, &alice_head, &refname, "Making changes", "Alice")
.unwrap()
@ -747,7 +747,7 @@ mod tests {
alice.sign_refs(&alice_proj_storage, &alice_signer).unwrap();
// Have Bob fetch Alice's new commit.
let updates = bob.repository(&proj_id).unwrap().fetch(&alice_url).unwrap();
let updates = bob.repository(proj_id).unwrap().fetch(&alice_url).unwrap();
// The branch and signature refs are updated.
assert_matches!(
updates.as_slice(),
@ -755,7 +755,7 @@ mod tests {
);
// Bob's storage is updated.
let bob_repo = bob.repository(&proj_id).unwrap();
let bob_repo = bob.repository(proj_id).unwrap();
let bob_master = bob_repo.reference(alice_id, &refname).unwrap().unwrap();
assert_eq!(bob_master.target().unwrap(), alice_head);
@ -769,7 +769,7 @@ mod tests {
let storage = Storage::open(tmp.path()).unwrap();
let proj_id = arbitrary::gen::<Id>(1);
let alice = *signer.public_key();
let project = storage.repository(&proj_id).unwrap();
let project = storage.repository(proj_id).unwrap();
let backend = &project.backend;
let sig = git2::Signature::now(&alice.to_string(), "anonymous@radicle.xyz").unwrap();
let head = git::initial_commit(backend, &sig).unwrap();

View File

@ -44,8 +44,8 @@ impl ReadStorage for MockStorage {
}
}
fn get(&self, _remote: &RemoteId, proj: &Id) -> Result<Option<Doc<Verified>>, Error> {
Ok(self.inventory.get(proj).cloned())
fn get(&self, _remote: &RemoteId, proj: Id) -> Result<Option<Doc<Verified>>, Error> {
Ok(self.inventory.get(&proj).cloned())
}
fn inventory(&self) -> Result<Inventory, Error> {
@ -56,7 +56,7 @@ impl ReadStorage for MockStorage {
impl WriteStorage for MockStorage {
type Repository = MockRepository;
fn repository(&self, _proj: &Id) -> Result<Self::Repository, Error> {
fn repository(&self, _proj: Id) -> Result<Self::Repository, Error> {
Ok(MockRepository {})
}
@ -68,7 +68,7 @@ impl WriteStorage for MockStorage {
todo!()
}
fn fetch(&self, _proj_id: &Id, _remote: &Url) -> Result<Vec<RefUpdate>, FetchError> {
fn fetch(&self, _proj_id: Id, _remote: &Url) -> Result<Vec<RefUpdate>, FetchError> {
Ok(vec![])
}
}