Radish alpha
r
rad:z6cFWeWpnZNHh9rUW8phgA3b5yGt
Git libraries for Radicle
Radicle
Git
Merge remote-tracking branch 'han/doc-comments'
Fintan Halpenny committed 3 years ago
commit 761e14e7cccb46cda06c71af5e6cad24705df4aa
parent 858f13f
8 files changed +95 -76
modified radicle-surf/README.md
@@ -20,9 +20,3 @@ our [LICENSE](../LICENSE) file.
## The Community

Join our community disccussions at [radicle.community](https://radicle.community)!
-

-

-
# Example
-

-
To a taste for the capabilities of `radicle-surf` we provide an example below, but we also
-
keep our documentation and doc-tests up to date.
modified radicle-surf/examples/browsing.rs
@@ -51,10 +51,10 @@ fn main() {
fn print_directory(d: &Directory, repo: &Repository, indent_level: usize) {
    let indent = " ".repeat(indent_level * 4);
    println!("{}{}/", &indent, d.name());
-
    for entry in d.entries(repo).unwrap().entries() {
+
    for entry in d.entries(repo).unwrap() {
        match entry {
            directory::Entry::File(f) => println!("    {}{}", &indent, f.name()),
-
            directory::Entry::Directory(d) => print_directory(d, repo, indent_level + 1),
+
            directory::Entry::Directory(d) => print_directory(&d, repo, indent_level + 1),
        }
    }
}
modified radicle-surf/src/diff.rs
@@ -15,6 +15,8 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.

+
//! Types that represent diff(s) in a Git repo.
+

#![allow(dead_code, unused_variables, missing_docs)]

use std::path::PathBuf;
modified radicle-surf/src/file_system/directory.rs
@@ -44,6 +44,8 @@ pub mod error {
        Entry(#[from] Entry),
        #[error(transparent)]
        File(#[from] File),
+
        #[error("the path {0} is not valid")]
+
        InvalidPath(String),
    }

    #[derive(Debug, Error, PartialEq, Eq)]
@@ -178,6 +180,19 @@ impl Entries {
    }
}

+
impl Iterator for Entries {
+
    type Item = Entry;
+

+
    fn next(&mut self) -> Option<Self::Item> {
+
        // Can be improved when `pop_first()` is stable for BTreeMap.
+
        let next_key = match self.listing.keys().next() {
+
            Some(k) => k.clone(),
+
            None => return None,
+
        };
+
        self.listing.remove(&next_key)
+
    }
+
}
+

/// An `Entry` is either a [`File`] entry or a [`Directory`] entry.
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Entry {
@@ -228,6 +243,16 @@ impl Entry {
        }
    }

+
    /// Returns `true` if the `Entry` is a file.
+
    pub fn is_file(&self) -> bool {
+
        matches!(self, Entry::File(_))
+
    }
+

+
    /// Returns `true` if the `Entry` is a directory.
+
    pub fn is_directory(&self) -> bool {
+
        matches!(self, Entry::Directory(_))
+
    }
+

    pub(crate) fn from_entry(
        entry: &git2::TreeEntry,
        path: PathBuf,
@@ -366,14 +391,18 @@ impl Directory {
        P: AsRef<Path>,
    {
        // Search the path in git2 tree.
+
        let path = path.as_ref();
        let git2_tree = repo.find_tree(self.id)?;
        let entry = git2_tree
-
            .get_path(path.as_ref())
+
            .get_path(path)
            .map(Some)
            .or_matches::<git2::Error, _, _>(is_not_found_err, || Ok(None))?;
+
        let parent = path
+
            .parent()
+
            .ok_or_else(|| error::Directory::InvalidPath(path.to_string_lossy().to_string()))?;

        Ok(entry
-
            .and_then(|entry| Entry::from_entry(&entry, path.as_ref().to_path_buf()).transpose())
+
            .and_then(|entry| Entry::from_entry(&entry, parent.to_path_buf()).transpose())
            .transpose()
            .unwrap())
    }
@@ -396,13 +425,13 @@ impl Directory {
    /// Find the `Directory` found at `path`, if it exists.
    pub fn find_directory<P>(
        &self,
-
        path: P,
+
        path: &P,
        repo: &Repository,
    ) -> Result<Option<Self>, error::Directory>
    where
        P: AsRef<Path>,
    {
-
        Ok(match self.find_entry(&path, repo)? {
+
        Ok(match self.find_entry(path, repo)? {
            Some(Entry::Directory(d)) => Some(d),
            _ => None,
        })
modified radicle-surf/src/lib.rs
@@ -1,7 +1,7 @@
// This file is part of radicle-git
// <https://github.com/radicle-dev/radicle-git>
//
-
// Copyright (C) 2019-2020 The Radicle Team <dev@radicle.xyz>
+
// Copyright (C) 2019-2022 The Radicle Team <dev@radicle.xyz>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License version 3 or
@@ -15,65 +15,14 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.

-
//! Welcome to `radicle-surf`!
-
//!
//! `radicle-surf` is a library to describe a Git repository as a file system.
//! It aims to provide an easy-to-use API to browse a repository via the concept
//! of files and directories for any given revision. It also allows the user to
//! diff any two different revisions.
//!
-
//! One of the use cases would be to create a web GUI for interacting with a Git
-
//! repository (thinking GitHub, GitLab or similar systems).
-
//!
-
//! Let's start surfing (and apologies for the `expect`s):
-
//!
-
//! ```
-
//! use radicle_surf::git;
-
//! use radicle_surf::file_system::{Label, Path, SystemType};
-
//! use radicle_surf::file_system::unsound;
-
//! use pretty_assertions::assert_eq;
-
//! use std::str::FromStr;
-
//! # use std::error::Error;
-
//!
-
//! # fn main() -> Result<(), Box<dyn Error>> {
-
//! // We're going to point to this repo.
-
//! let repo = git::Repository::open("./data/git-platinum")?;
-
//!
-
//! // Get the snapshot of the directory for our current HEAD of history.
-
//! let directory = repo.root_dir("80ded66281a4de2889cc07293a8f10947c6d57fe")?;
-
//!
-
//! // Let's get a Path to the memory.rs file
-
//! let memory = unsound::path::new("src/memory.rs");
-
//!
-
//! // And assert that we can find it!
-
//! assert!(directory.find_file(memory).is_some());
-
//!
-
//! let root_contents = directory.list_directory();
-
//!
-
//! assert_eq!(root_contents, vec![
-
//!     SystemType::file(unsound::label::new(".i-am-well-hidden")),
-
//!     SystemType::file(unsound::label::new(".i-too-am-hidden")),
-
//!     SystemType::file(unsound::label::new("README.md")),
-
//!     SystemType::directory(unsound::label::new("bin")),
-
//!     SystemType::directory(unsound::label::new("src")),
-
//!     SystemType::directory(unsound::label::new("text")),
-
//!     SystemType::directory(unsound::label::new("this")),
-
//! ]);
-
//!
-
//! let src = directory
-
//!     .find_directory(Path::new(unsound::label::new("src")))
-
//!     .expect("failed to find src");
-
//! let src_contents = src.list_directory();
+
//! The main entry point of the API is [git::Repository].
//!
-
//! assert_eq!(src_contents, vec![
-
//!     SystemType::file(unsound::label::new("Eval.hs")),
-
//!     SystemType::file(unsound::label::new("Folder.svelte")),
-
//!     SystemType::file(unsound::label::new("memory.rs")),
-
//! ]);
-
//! #
-
//! # Ok(())
-
//! # }
-
//! ```
+
//! Let's start surfing!

pub extern crate git_ref_format;

modified radicle-surf/src/source/object/tree.rs
@@ -57,7 +57,7 @@ impl Tree {
            None => repo.root_dir(revision)?,
            Some(path) => repo
                .root_dir(revision)?
-
                .find_directory(path, repo)?
+
                .find_directory(&path, repo)?
                .ok_or_else(|| Error::PathNotFound(path.to_path_buf()))?,
        };

modified radicle-surf/t/src/file_system.rs
@@ -3,11 +3,10 @@

//! Unit tests for radicle_surf::file_system

-
#[cfg(test)]
mod directory {
    use git_ref_format::refname;
    use radicle_surf::{
-
        file_system::directory,
+
        file_system::{directory, Entry},
        git::{Branch, Repository},
    };
    use std::path::Path;
@@ -21,36 +20,79 @@ mod directory {

        // find_entry for a file.
        let path = Path::new("src/memory.rs");
-
        let entry = root.find_entry(path, &repo).unwrap();
+
        let entry = root.find_entry(&path, &repo).unwrap();
        assert!(matches!(entry, Some(directory::Entry::File(_))));

        // find_entry for a directory.
        let path = Path::new("this/is/a/really/deeply/nested/directory/tree");
-
        let entry = root.find_entry(path, &repo).unwrap();
+
        let entry = root.find_entry(&path, &repo).unwrap();
        assert!(matches!(entry, Some(directory::Entry::Directory(_))));

        // find_entry for a non-leaf directory and its relative path.
        let path = Path::new("text");
-
        let entry = root.find_entry(path, &repo).unwrap();
+
        let entry = root.find_entry(&path, &repo).unwrap();
        assert!(matches!(entry, Some(directory::Entry::Directory(_))));
        if let Some(directory::Entry::Directory(sub_dir)) = entry {
            let inner_path = Path::new("garden.txt");
-
            let inner_entry = sub_dir.find_entry(inner_path, &repo).unwrap();
+
            let inner_entry = sub_dir.find_entry(&inner_path, &repo).unwrap();
            assert!(matches!(inner_entry, Some(directory::Entry::File(_))));
        }

        // find_entry for non-existing file
        let path = Path::new("this/is/a/really/missing_file");
-
        let result = root.find_entry(path, &repo).unwrap();
+
        let result = root.find_entry(&path, &repo).unwrap();
        assert_eq!(result, None);

        // find_entry for absolute path: fail.
        let path = Path::new("/src/memory.rs");
-
        let result = root.find_entry(path, &repo);
+
        let result = root.find_entry(&path, &repo);
        assert!(result.is_err());
    }

    #[test]
+
    fn directory_find_file_and_directory() {
+
        let repo = Repository::open(GIT_PLATINUM).unwrap();
+
        // Get the snapshot of the directory for a given commit.
+
        let root = repo
+
            .root_dir(&"80ded66281a4de2889cc07293a8f10947c6d57fe")
+
            .unwrap();
+

+
        // Assert that we can find the memory.rs file!
+
        assert!(root
+
            .find_file(&Path::new("src/memory.rs"), &repo)
+
            .unwrap()
+
            .is_some());
+

+
        let root_contents: Vec<Entry> = root.entries(&repo).unwrap().collect();
+
        assert_eq!(root_contents.len(), 7);
+
        assert!(root_contents[0].is_file());
+
        assert!(root_contents[1].is_file());
+
        assert!(root_contents[2].is_file());
+
        assert_eq!(root_contents[0].name(), ".i-am-well-hidden");
+
        assert_eq!(root_contents[1].name(), ".i-too-am-hidden");
+
        assert_eq!(root_contents[2].name(), "README.md");
+

+
        assert!(root_contents[3].is_directory());
+
        assert!(root_contents[4].is_directory());
+
        assert!(root_contents[5].is_directory());
+
        assert!(root_contents[6].is_directory());
+
        assert_eq!(root_contents[3].name(), "bin");
+
        assert_eq!(root_contents[4].name(), "src");
+
        assert_eq!(root_contents[5].name(), "text");
+
        assert_eq!(root_contents[6].name(), "this");
+

+
        let src = root
+
            .find_directory(&Path::new("src"), &repo)
+
            .unwrap()
+
            .unwrap();
+
        let src_contents: Vec<Entry> = src.entries(&repo).unwrap().collect();
+
        assert_eq!(src_contents.len(), 3);
+
        assert_eq!(src_contents[0].name(), "Eval.hs");
+
        assert_eq!(src_contents[1].name(), "Folder.svelte");
+
        assert_eq!(src_contents[2].name(), "memory.rs");
+
    }
+

+
    #[test]
    fn directory_size() {
        let repo = Repository::open(GIT_PLATINUM).unwrap();
        let root = repo.root_dir(&Branch::local(refname!("master"))).unwrap();
@@ -64,7 +106,7 @@ mod directory {
         */

        let path = Path::new("src");
-
        let entry = root.find_entry(path, &repo).unwrap();
+
        let entry = root.find_entry(&path, &repo).unwrap();
        assert!(matches!(entry, Some(directory::Entry::Directory(_))));
        if let Some(directory::Entry::Directory(d)) = entry {
            assert_eq!(16297, d.size(&repo).unwrap());
modified radicle-surf/t/src/lib.rs
@@ -3,3 +3,6 @@

#[cfg(test)]
mod git;
+

+
#[cfg(test)]
+
mod file_system;