diff --git a/Cargo.toml b/Cargo.toml index ba679d7..87f473b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,13 +1,13 @@ [workspace] members = [ - "git-ext", "git-ref-format", "git-trailers", - "git-types", "link-git", - "macros", + "radicle-git-ext", + "radicle-git-types", + "radicle-macros", + "radicle-std-ext", # TODO: port gitd-lib over # "cli/gitd-lib", - "std-ext", "test", ] diff --git a/git-ext/Cargo.toml b/radicle-git-ext/Cargo.toml similarity index 96% rename from git-ext/Cargo.toml rename to radicle-git-ext/Cargo.toml index 0410dce..a2b5a7b 100644 --- a/git-ext/Cargo.toml +++ b/radicle-git-ext/Cargo.toml @@ -38,4 +38,4 @@ features = ["derive"] optional = true [dependencies.radicle-std-ext] -path = "../std-ext" +path = "../radicle-std-ext" diff --git a/git-ext/src/blob.rs b/radicle-git-ext/src/blob.rs similarity index 100% rename from git-ext/src/blob.rs rename to radicle-git-ext/src/blob.rs diff --git a/git-ext/src/error.rs b/radicle-git-ext/src/error.rs similarity index 100% rename from git-ext/src/error.rs rename to radicle-git-ext/src/error.rs diff --git a/git-ext/src/lib.rs b/radicle-git-ext/src/lib.rs similarity index 100% rename from git-ext/src/lib.rs rename to radicle-git-ext/src/lib.rs diff --git a/git-ext/src/oid.rs b/radicle-git-ext/src/oid.rs similarity index 100% rename from git-ext/src/oid.rs rename to radicle-git-ext/src/oid.rs diff --git a/git-ext/src/reference.rs b/radicle-git-ext/src/reference.rs similarity index 100% rename from git-ext/src/reference.rs rename to radicle-git-ext/src/reference.rs diff --git a/git-ext/src/reference/iter.rs b/radicle-git-ext/src/reference/iter.rs similarity index 100% rename from git-ext/src/reference/iter.rs rename to radicle-git-ext/src/reference/iter.rs diff --git a/git-ext/src/reference/name.rs b/radicle-git-ext/src/reference/name.rs similarity index 100% rename from git-ext/src/reference/name.rs rename to radicle-git-ext/src/reference/name.rs diff --git a/git-ext/src/revwalk.rs b/radicle-git-ext/src/revwalk.rs similarity index 100% rename from git-ext/src/revwalk.rs rename to radicle-git-ext/src/revwalk.rs diff --git a/git-ext/src/transport.rs b/radicle-git-ext/src/transport.rs similarity index 100% rename from git-ext/src/transport.rs rename to radicle-git-ext/src/transport.rs diff --git a/git-ext/src/tree.rs b/radicle-git-ext/src/tree.rs similarity index 100% rename from git-ext/src/tree.rs rename to radicle-git-ext/src/tree.rs diff --git a/git-ext/t/Cargo.toml b/radicle-git-ext/t/Cargo.toml similarity index 100% rename from git-ext/t/Cargo.toml rename to radicle-git-ext/t/Cargo.toml diff --git a/git-ext/t/src/lib.rs b/radicle-git-ext/t/src/lib.rs similarity index 100% rename from git-ext/t/src/lib.rs rename to radicle-git-ext/t/src/lib.rs diff --git a/git-ext/t/src/tests.rs b/radicle-git-ext/t/src/tests.rs similarity index 100% rename from git-ext/t/src/tests.rs rename to radicle-git-ext/t/src/tests.rs diff --git a/git-types/Cargo.toml b/radicle-git-types/Cargo.toml similarity index 89% rename from git-types/Cargo.toml rename to radicle-git-types/Cargo.toml index 9598316..af3bc03 100644 --- a/git-types/Cargo.toml +++ b/radicle-git-types/Cargo.toml @@ -27,13 +27,13 @@ version = "0.13" features = ["std", "derive"] [dependencies.radicle-git-ext] -path = "../git-ext" +path = "../radicle-git-ext" [dependencies.radicle-macros] -path = "../macros" +path = "../radicle-macros" [dependencies.radicle-std-ext] -path = "../std-ext" +path = "../radicle-std-ext" [dependencies.serde] version = "1.0" diff --git a/git-types/src/lib.rs b/radicle-git-types/src/lib.rs similarity index 100% rename from git-types/src/lib.rs rename to radicle-git-types/src/lib.rs diff --git a/git-types/src/namespace.rs b/radicle-git-types/src/namespace.rs similarity index 100% rename from git-types/src/namespace.rs rename to radicle-git-types/src/namespace.rs diff --git a/git-types/src/reference.rs b/radicle-git-types/src/reference.rs similarity index 100% rename from git-types/src/reference.rs rename to radicle-git-types/src/reference.rs diff --git a/git-types/src/refspec.rs b/radicle-git-types/src/refspec.rs similarity index 100% rename from git-types/src/refspec.rs rename to radicle-git-types/src/refspec.rs diff --git a/git-types/src/remote.rs b/radicle-git-types/src/remote.rs similarity index 100% rename from git-types/src/remote.rs rename to radicle-git-types/src/remote.rs diff --git a/git-types/src/sealed.rs b/radicle-git-types/src/sealed.rs similarity index 100% rename from git-types/src/sealed.rs rename to radicle-git-types/src/sealed.rs diff --git a/git-types/src/urn.rs b/radicle-git-types/src/urn.rs similarity index 100% rename from git-types/src/urn.rs rename to radicle-git-types/src/urn.rs diff --git a/macros/Cargo.toml b/radicle-macros/Cargo.toml similarity index 92% rename from macros/Cargo.toml rename to radicle-macros/Cargo.toml index 1f60932..8a9b68b 100644 --- a/macros/Cargo.toml +++ b/radicle-macros/Cargo.toml @@ -17,4 +17,4 @@ quote = "1" syn = "1" [dependencies.radicle-git-ext] -path = "../git-ext" +path = "../radicle-git-ext" diff --git a/macros/src/lib.rs b/radicle-macros/src/lib.rs similarity index 100% rename from macros/src/lib.rs rename to radicle-macros/src/lib.rs diff --git a/std-ext/Cargo.toml b/radicle-std-ext/Cargo.toml similarity index 100% rename from std-ext/Cargo.toml rename to radicle-std-ext/Cargo.toml diff --git a/std-ext/src/lib.rs b/radicle-std-ext/src/lib.rs similarity index 100% rename from std-ext/src/lib.rs rename to radicle-std-ext/src/lib.rs diff --git a/std-ext/src/ops.rs b/radicle-std-ext/src/ops.rs similarity index 100% rename from std-ext/src/ops.rs rename to radicle-std-ext/src/ops.rs diff --git a/std-ext/src/result.rs b/radicle-std-ext/src/result.rs similarity index 100% rename from std-ext/src/result.rs rename to radicle-std-ext/src/result.rs diff --git a/test/Cargo.toml b/test/Cargo.toml index 0b4d5c7..ce6816c 100644 --- a/test/Cargo.toml +++ b/test/Cargo.toml @@ -12,7 +12,7 @@ test = true doc = false [dev-dependencies.git-ext-test] -path = "../git-ext/t" +path = "../radicle-git-ext/t" features = ["test"] [dev-dependencies.git-ref-format-test] diff --git a/test/it-helpers/Cargo.toml b/test/it-helpers/Cargo.toml deleted file mode 100644 index 04aa216..0000000 --- a/test/it-helpers/Cargo.toml +++ /dev/null @@ -1,48 +0,0 @@ -[package] -name = "it-helpers" -version = "0.1.0" -edition = "2021" -license = "GPL-3.0-or-later" -publish = false - -description = "Integration test helpers" - -[lib] -doctest = false -test = false - -[dependencies] -anyhow = "1" -futures = "0.3" -once_cell = "1.10" -tempfile = "3.3" -tokio = "1.13" -tracing = "0.1" -either = "1.6" - -[dependencies.git2] -version = "0.13.24" -default-features = false -features = ["vendored-libgit2"] - -# -# workspace dependencies -# - -[dependencies.git-ref-format] -path = "../../git-ref-format" - -[dependencies.librad] -path = "../../librad" - -[dependencies.link-async] -path = "../../link-async" - -[dependencies.lnk-clib] -path = "../../cli/lnk-clib" - -[dependencies.radicle-git-ext] -path = "../../git-ext" - -[dependencies.test-helpers] -path = "../test-helpers" diff --git a/test/it-helpers/src/git.rs b/test/it-helpers/src/git.rs deleted file mode 100644 index b59e537..0000000 --- a/test/it-helpers/src/git.rs +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright © 2019-2020 The Radicle Foundation -// -// This file is part of radicle-link, distributed under the GPLv3 with Radicle -// Linking Exception. For full terms see the included LICENSE file. - -use git_ref_format::Qualified; - -#[tracing::instrument(skip(repo))] -pub fn create_commit( - repo: &git2::Repository, - on_branch: Qualified, -) -> Result { - let empty_tree = { - let mut index = repo.index()?; - let oid = index.write_tree()?; - repo.find_tree(oid).unwrap() - }; - let author = git2::Signature::now("The Animal", "animal@muppets.com").unwrap(); - repo.commit( - Some(on_branch.as_str()), - &author, - &author, - "Initial commit", - &empty_tree, - &[], - ) -} diff --git a/test/it-helpers/src/lib.rs b/test/it-helpers/src/lib.rs deleted file mode 100644 index 5012de3..0000000 --- a/test/it-helpers/src/lib.rs +++ /dev/null @@ -1,10 +0,0 @@ -#[macro_use] -extern crate tracing; - -pub mod fixed; -pub mod git; -pub mod layout; -pub mod ssh; -pub mod testnet; -pub mod tmp; -pub mod working_copy; diff --git a/test/it-helpers/src/ssh.rs b/test/it-helpers/src/ssh.rs deleted file mode 100644 index 5ca2154..0000000 --- a/test/it-helpers/src/ssh.rs +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright © 2021 The Radicle Link Contributors -// -// This file is part of radicle-link, distributed under the GPLv3 with Radicle -// Linking Exception. For full terms see the included LICENSE file. - -use std::process::{Command, Stdio}; - -use lnk_clib::keys::ssh::SshAuthSock; -use test_helpers::tempdir::WithTmpDir; - -pub type TmpSshSock = WithTmpDir; - -pub fn ssh_auth_sock() -> TmpSshSock { - WithTmpDir::new(|path| -> anyhow::Result { - let sock = path.join("tmp.sock"); - Ok(SshAuthSock::Uds(sock)) - }) - .unwrap() -} - -/// Run a computation with a forked `ssh-agent` on a temporary file handle. -/// -/// Once the computation is finished, the `ssh-agent` is killed by getting its -/// PID and running the equivalent of `SSH_AGENT_PID= ssh-agent -k`. -/// This is a best effort of resource cleanup, but has no guarantees if the -/// parsing of the PID or the killin of the agent fail. -pub fn with_ssh_agent(callback: F) -> anyhow::Result -where - F: FnOnce(SshAuthSock) -> anyhow::Result, -{ - let sock = ssh_auth_sock(); - let path = match &*sock { - SshAuthSock::Uds(path) => path, - _ => unreachable!(), - }; - let agent = Command::new("ssh-agent").arg("-a").arg(path).output()?; - anyhow::ensure!(agent.status.success(), agent.status); - let pid = agent_pid(&agent.stdout)?; - let res = callback((*sock).clone()); - kill_agent_pid(pid)?; - res -} - -/// Kill the ssh-agent running on the given PID. -fn kill_agent_pid(pid: &str) -> anyhow::Result<()> { - debug!(pid = %pid, "killing ssh-agent"); - let status = Command::new("ssh-agent") - .env("SSH_AGENT_PID", pid) - .args(["-k"]) - .stdout(Stdio::null()) - .status()?; - debug!(status = %status, "status of killing agent"); - Ok(()) -} - -/// Get the PID of the launched ssh-agent. -/// -/// It gets the PID by stripping the output from the command using the text -/// `"echo Agent pid "`. -fn agent_pid(out: &[u8]) -> anyhow::Result<&str> { - const PREFIX: &str = "SSH_AGENT_PID="; - const SEP: u8 = b';'; - let pid = out - .split(|b| b == &SEP) - .find_map(|bs| std::str::from_utf8(bs).ok()?.trim().strip_prefix(PREFIX)) - .ok_or_else(|| anyhow::anyhow!("could not find SSH_AGENT_PID"))?; - Ok(pid) -} diff --git a/test/it-helpers/src/tmp.rs b/test/it-helpers/src/tmp.rs deleted file mode 100644 index 65077a9..0000000 --- a/test/it-helpers/src/tmp.rs +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright © 2021 The Radicle Link Contributors -// SPDX-License-Identifier: GPLv3-or-later - -use std::io; - -use librad::{git::storage::Storage, paths::Paths, SecretKey}; -use test_helpers::tempdir::WithTmpDir; - -pub type TmpPaths = WithTmpDir; - -pub fn paths() -> TmpPaths { - WithTmpDir::new(|path| -> Result<_, io::Error> { - let paths = Paths::from_root(path)?; - Ok::<_, io::Error>(paths) - }) - .unwrap() -} - -type TmpRepo = WithTmpDir; - -pub fn repo() -> anyhow::Result { - Ok(WithTmpDir::new(|path| { - let setup = || { - let repo = git2::Repository::init(path)?; - - // We need to set user info to _something_, but that doesn't have to - // be valid, as we're using a shared repo with many keys - let mut config = repo.config()?; - config.set_str("user.name", "shared")?; - config.set_str("user.email", "not.relevant@for.testing")?; - Ok(repo) - }; - setup().map_err(|e: git2::Error| io::Error::new(io::ErrorKind::Other, e)) - })?) -} - -pub type TmpStorage = WithTmpDir; - -pub fn storage(signer: SecretKey) -> TmpStorage { - WithTmpDir::new(|path| -> Result<_, io::Error> { - let paths = Paths::from_root(path)?; - let storage = - Storage::open(&paths, signer).map_err(|e| io::Error::new(io::ErrorKind::Other, e))?; - Ok::<_, io::Error>(storage) - }) - .unwrap() -} diff --git a/test/it-helpers/src/working_copy.rs b/test/it-helpers/src/working_copy.rs deleted file mode 100644 index ac32946..0000000 --- a/test/it-helpers/src/working_copy.rs +++ /dev/null @@ -1,301 +0,0 @@ -use git_ref_format::{lit, name, refspec, Qualified, RefStr, RefString}; - -use librad::{ - git::{ - local::url::LocalUrl, - types::{ - remote::{LocalFetchspec, LocalPushspec}, - Fetchspec, - Force, - Refspec, - Remote, - }, - }, - git_ext as ext, - net::{peer::Peer, protocol::RequestPullGuard}, - refspec_pattern, - PeerId, - Signer, -}; - -use crate::fixed::TestProject; - -/// A remote in the working copy -pub enum WorkingRemote { - /// A remote representing a remote peer, named `PeerId::encode_id` - Peer(PeerId), - /// A remote representing the local peer, named "rad" - Rad, -} - -impl From for WorkingRemote { - fn from(p: PeerId) -> Self { - WorkingRemote::Peer(p) - } -} - -impl WorkingRemote { - fn fetchspec(&self) -> Fetchspec { - match self { - Self::Peer(peer_id) => { - let name = RefString::try_from(format!("{}", peer_id)).expect("peer is refstring"); - let dst = RefString::from(Qualified::from(lit::refs_remotes(name.clone()))) - .with_pattern(refspec::STAR); - let src = RefString::from(Qualified::from(lit::refs_remotes(name))) - .and(name::HEADS) - .with_pattern(refspec::STAR); - let refspec = Refspec { - src, - dst, - force: Force::True, - }; - refspec.into_fetchspec() - }, - Self::Rad => { - let name = RefString::try_from("rad").unwrap(); - let src = - RefString::from_iter([name::REFS, name::HEADS]).with_pattern(refspec::STAR); - Refspec { - src, - dst: RefString::from(Qualified::from(lit::refs_remotes(name))) - .with_pattern(refspec::STAR), - force: Force::True, - } - .into_fetchspec() - }, - } - } - - fn remote_ref(&self, branch: &RefStr) -> RefString { - let name = match self { - Self::Rad => name::RAD.to_owned(), - Self::Peer(peer_id) => { - RefString::try_from(peer_id.to_string()).expect("peer id is refstring") - }, - }; - RefString::from(Qualified::from(lit::refs_remotes(name))).join(branch) - } -} - -/// A `WorkingCopy` for test driving interactions with the monorepo where one -/// needs to update the tree of a project. -/// -/// Remotes are named after the peer ID, except in the case of the remote -/// representing the local Peer ID - which is called "rad". -pub struct WorkingCopy<'a, S, G> { - repo: git2::Repository, - _repo_path: tempfile::TempDir, - peer: &'a Peer, - project: &'a TestProject, -} - -impl<'a, S, G> WorkingCopy<'a, S, G> -where - S: Signer + Clone, - G: RequestPullGuard, -{ - /// Create a new working copy. This initializes a git repository and then - /// fetches the state of the local peer into `refs/remotes/rad/*`. - pub fn new( - project: &'a TestProject, - peer: &'a Peer, - ) -> Result, anyhow::Error> { - let repo_path = tempfile::tempdir()?; - let repo = git2::Repository::init(repo_path.as_ref())?; - - let mut copy = WorkingCopy { - peer, - project, - repo, - _repo_path: repo_path, - }; - copy.fetch(WorkingRemote::Rad)?; - Ok(copy) - } - - /// Fetch changes from the monorepo into the working copy. The fetchspec - /// used depends on the peer ID. - /// - /// * If `from` is `WorkingRemote::Peer` then `refs/remotes//refs/*:refs/remotes//heads/*` - /// * If `from` is `WorkingRemote::Rad` then - /// `refs/heads/*:refs/remotes/rad/*` - /// - /// I.e. changes from remote peers end up in a remote called - /// `PeerId::encode_id` whilst changes from the local peer end up in a - /// remote called "rad". - pub fn fetch(&mut self, from: WorkingRemote) -> Result<(), anyhow::Error> { - let fetchspec = from.fetchspec(); - let url = LocalUrl::from(self.project.project.urn()); - let mut remote = Remote::rad_remote(url, fetchspec); - let _ = remote.fetch(self.peer.clone(), &self.repo, LocalFetchspec::Configured)?; - Ok(()) - } - - /// Push changes from `refs/heads/*` to the local peer - pub fn push(&mut self) -> Result<(), anyhow::Error> { - let url = LocalUrl::from(self.project.project.urn()); - let name = RefString::try_from("rad").unwrap(); - let fetchspec = Refspec { - src: RefString::from_iter([name::REFS, name::HEADS]).with_pattern(refspec::STAR), - dst: RefString::from(Qualified::from(lit::refs_remotes(name))) - .with_pattern(refspec::STAR), - force: Force::True, - } - .into_fetchspec(); - let mut remote = Remote::rad_remote(url, fetchspec); - let _ = remote.push( - self.peer.clone(), - &self.repo, - LocalPushspec::Matching { - pattern: refspec_pattern!("refs/heads/*"), - force: Force::True, - }, - )?; - Ok(()) - } - - /// Create a new commit on top of whichever commit is the head of - /// `on_branch`. If the branch does not exist this will create it. - pub fn commit( - &mut self, - message: &str, - on_branch: Qualified, - ) -> Result { - let branch_name = on_branch.non_empty_components().2; - let parent = match self.repo.find_branch(&branch_name, git2::BranchType::Local) { - Ok(b) => b.get().target().and_then(|o| self.repo.find_commit(o).ok()), - Err(e) if ext::error::is_not_found_err(&e) => None, - Err(e) => return Err(anyhow::Error::from(e)), - }; - let empty_tree = { - let mut index = self.repo.index()?; - let oid = index.write_tree()?; - self.repo.find_tree(oid).unwrap() - }; - let author = git2::Signature::now("The Animal", "animal@muppets.com").unwrap(); - let parents = match &parent { - Some(p) => vec![p], - None => Vec::new(), - }; - self.repo - .commit( - Some(&on_branch), - &author, - &author, - message, - &empty_tree, - &parents, - ) - .map_err(anyhow::Error::from) - } - - pub fn commit_and_push( - &mut self, - message: &str, - on_branch: Qualified, - ) -> Result { - let id = self.commit(message, on_branch)?; - self.push()?; - Ok(id) - } - - /// Create a branch at `refs/heads/` which tracks the given remote. - /// The remote branch name depends on `from`. - /// - /// * If `from` is `WorkingCopy::Rad` then `refs/remotes/rad/` - /// * If `from` is `WorkingCopy::Peer(peer_id)` then `refs/remotes//` - pub fn create_remote_tracking_branch( - &self, - from: WorkingRemote, - branch: &RefStr, - ) -> Result<(), anyhow::Error> { - let target = self - .repo - .find_reference(from.remote_ref(branch).as_str())? - .target() - .ok_or_else(|| anyhow::anyhow!("remote ref is not a direct reference"))?; - let commit = self.repo.find_commit(target)?; - self.repo.branch(branch.as_str(), &commit, false)?; - Ok(()) - } - - /// Fast forward the local branch `refs/heads/` to whatever is - /// pointed to by `refs/remotes//` - /// - /// * If `from` is `WorkingRemote::Peer(peer_id)` then `remote` is - /// `peer_id.encode_id()` - /// * If `from` is `WorkingRemote::Rad` then `remote` is `"rad"` - /// - /// # Errors - /// - /// * If the local branch does not exist - /// * If the remote branch does not exist - /// * If either of the branches does not point at a commit - /// * If the remote branch is not a descendant of the local branch - pub fn fast_forward_to(&self, from: WorkingRemote, branch: &RefStr) -> anyhow::Result<()> { - let remote_ref = from.remote_ref(branch); - let remote_target = self - .repo - .find_reference(&remote_ref)? - .target() - .ok_or_else(|| anyhow::anyhow!("remote ref had no target"))?; - let local_ref = RefString::from(Qualified::from(lit::refs_heads(branch))); - let local_target = self - .repo - .find_reference(&local_ref)? - .target() - .ok_or_else(|| anyhow::anyhow!("local ref had no target"))?; - if !self.repo.graph_descendant_of(remote_target, local_target)? { - anyhow::bail!("remote ref was not a descendant of local ref"); - } else { - self.repo - .reference(&local_ref, remote_target, true, "fast forward")?; - } - Ok(()) - } - - /// Create a new commit which merges `refs/heads/` and - /// `refs/remotes//` - /// - /// this will create a new commit with two parents, one for the remote - /// branch and one for the local branch - /// - /// # Errors - /// - /// * If the remote branch does not exist - /// * If the local branch does not exist - /// * If either of the references does not point to a commit - pub fn merge_remote(&self, remote: PeerId, branch: &RefStr) -> anyhow::Result { - let peer_branch = WorkingRemote::Peer(remote).remote_ref(branch); - let peer_commit = self - .repo - .find_reference(peer_branch.as_ref())? - .peel_to_commit()?; - let local_branch = Qualified::from(lit::refs_heads(branch)); - let local_commit = self - .repo - .find_reference(local_branch.as_ref())? - .peel_to_commit()?; - - let message = format!("merge {} into {}", peer_branch, local_branch); - let empty_tree = { - let mut index = self.repo.index()?; - let oid = index.write_tree()?; - self.repo.find_tree(oid).unwrap() - }; - let author = git2::Signature::now("The Animal", "animal@muppets.com").unwrap(); - let parents = vec![&peer_commit, &local_commit]; - self.repo - .commit( - Some(&local_branch), - &author, - &author, - &message, - &empty_tree, - &parents, - ) - .map_err(anyhow::Error::from) - } -}