Merge remote-tracking branch 'origin/fix/serialize-tree'

* origin/fix/serialize-tree:
  radicle-surf: serialize type for any kind of line
  surf: testing an added file
  surf: test serialization of tree
  surf: fix directory construction
  surf: fix path serialization for tree and blob

Signed-off-by: Fintan Halpenny <fintan.halpenny@gmail.com>
This commit is contained in:
Fintan Halpenny
2022-12-19 11:28:13 +00:00
8 changed files with 173 additions and 23 deletions
+76 -10
View File
@@ -238,23 +238,15 @@ impl Serialize for Line {
/// Either the modification of a single [`Line`], or just contextual
/// information.
#[cfg_attr(
feature = "serde",
derive(Serialize),
serde(tag = "type", rename_all = "camelCase")
)]
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum Modification {
/// A lines is an addition in a file.
#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
Addition(Addition),
/// A lines is a deletion in a file.
#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
Deletion(Deletion),
/// A contextual line in a file, i.e. there were no changes to the line.
#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
Context {
line: Line,
line_no_old: u32,
@@ -262,22 +254,96 @@ pub enum Modification {
},
}
#[cfg(feature = "serde")]
impl Serialize for Modification {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
use serde::ser::SerializeMap as _;
const NAME: &str = "Modification";
const ADDITION: &str = "Addition";
const DELETION: &str = "Deletion";
const CONTEXT: &str = "Context";
match self {
Modification::Addition(addition) => {
let mut map = serializer.serialize_map(Some(3))?;
map.serialize_entry("line", &addition.line)?;
map.serialize_entry("lineNo", &addition.line_no)?;
map.serialize_entry("type", "addition")?;
map.end()
},
Modification::Deletion(deletion) => {
let mut map = serializer.serialize_map(Some(3))?;
map.serialize_entry("line", &deletion.line)?;
map.serialize_entry("lineNo", &deletion.line_no)?;
map.serialize_entry("type", "deletion")?;
map.end()
},
Modification::Context {
line,
line_no_old,
line_no_new,
} => {
let mut map = serializer.serialize_map(Some(4))?;
map.serialize_entry("line", line)?;
map.serialize_entry("lineNoOld", line_no_old)?;
map.serialize_entry("lineNoNew", line_no_new)?;
map.serialize_entry("type", "context")?;
map.end()
},
}
}
}
/// A addition of a [`Line`] at the `line_no`.
#[cfg_attr(feature = "serde", derive(Serialize), serde(rename_all = "camelCase"))]
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Addition {
pub line: Line,
pub line_no: u32,
}
#[cfg(feature = "serde")]
impl Serialize for Addition {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
use serde::ser::SerializeStruct as _;
let mut s = serializer.serialize_struct("Addition", 3)?;
s.serialize_field("line", &self.line)?;
s.serialize_field("lineNo", &self.line_no)?;
s.serialize_field("type", "addition")?;
s.end()
}
}
/// A deletion of a [`Line`] at the `line_no`.
#[cfg_attr(feature = "serde", derive(Serialize), serde(rename_all = "camelCase"))]
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Deletion {
pub line: Line,
pub line_no: u32,
}
#[cfg(feature = "serde")]
impl Serialize for Deletion {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
use serde::ser::SerializeStruct as _;
let mut s = serializer.serialize_struct("Deletion", 3)?;
s.serialize_field("line", &self.line)?;
s.serialize_field("lineNo", &self.line_no)?;
s.serialize_field("type", "deletion")?;
s.end()
}
}
impl Modification {
pub fn addition(line: impl Into<Line>, line_no: u32) -> Self {
Self::Addition(Addition {
+3 -2
View File
@@ -352,10 +352,11 @@ impl Directory {
let mut entries = BTreeMap::new();
let mut error = None;
let path = self.path();
// Walks only the first level of entries.
tree.walk(git2::TreeWalkMode::PreOrder, |path, entry| {
match Entry::from_entry(entry, Path::new(path).to_path_buf()) {
tree.walk(git2::TreeWalkMode::PreOrder, |_, entry| {
match Entry::from_entry(entry, path.clone()) {
Ok(Some(entry)) => match entry {
Entry::File(_) => {
entries.insert(entry.name().clone(), entry);
+1 -1
View File
@@ -47,7 +47,7 @@ pub struct Commit {
}
/// Representation of a code commit.
#[derive(Clone)]
#[derive(Clone, Debug)]
pub struct Header {
/// Identifier of the commit in the form of a sha1 hash. Often referred to
/// as oid or object id.
+1 -1
View File
@@ -103,7 +103,7 @@ impl Serialize for Blob {
state.serialize_field("content", &self.content)?;
state.serialize_field("lastCommit", &self.commit)?;
state.serialize_field("name", &self.file.name())?;
state.serialize_field("path", &self.file.location())?;
state.serialize_field("path", &self.file.path())?;
state.end()
}
}
+4 -3
View File
@@ -33,6 +33,7 @@ use crate::{
};
/// Result of a directory listing, carries other trees and blobs.
#[derive(Clone, Debug)]
pub struct Tree {
pub directory: Directory,
pub commit: Option<commit::Header>,
@@ -95,7 +96,7 @@ impl Serialize for Tree {
state.serialize_field("entries", &self.entries)?;
state.serialize_field("lastCommit", &self.commit)?;
state.serialize_field("name", &self.directory.name())?;
state.serialize_field("path", &self.directory.location())?;
state.serialize_field("path", &self.directory.path())?;
state.end()
}
}
@@ -126,14 +127,14 @@ impl Serialize for TreeEntry {
{
const FIELDS: usize = 4;
let mut state = serializer.serialize_struct("TreeEntry", FIELDS)?;
state.serialize_field("path", &self.entry.location())?;
state.serialize_field("path", &self.entry.path())?;
state.serialize_field("name", &self.entry.name())?;
state.serialize_field("lastCommit", &None::<commit::Header>)?;
state.serialize_field(
"kind",
match self.entry {
directory::Entry::File(_) => "blob",
directory::Entry::Directory(_) => "directory",
directory::Entry::Directory(_) => "tree",
},
)?;
state.end()
+46 -6
View File
@@ -5,11 +5,12 @@ use radicle_surf::{
diff::{
Added,
Addition,
Deleted,
Deletion,
Diff,
EofNewLine,
FileDiff,
Hunk,
Hunks,
Line,
Modification,
Modified,
@@ -152,9 +153,26 @@ fn test_diff_serde() {
let diff = Diff {
added: vec![ Added {
path: Path::new("LICENSE").to_path_buf(),
diff: FileDiff::Plain { hunks: Hunks::default() }
diff: FileDiff::Plain {
hunks: vec![Hunk {
header: Line::from(b"@@ -0,0 +1,1".to_vec()),
lines: vec![
Addition { line: Line::from(b"MIT".to_vec()), line_no: 1 }
]
}].into()
}
}],
deleted: vec![ Deleted {
path: Path::new("DCO").to_path_buf(),
diff: FileDiff::Plain {
hunks: vec![Hunk {
header: Line::from(b"@@ -0,0 +1,1".to_vec()),
lines: vec![
Deletion { line: Line::from(b"TODO".to_vec()), line_no: 1 }
]
}].into()
}
}],
deleted: vec![],
moved: vec![ Moved {
old_path: Path::new("CONTRIBUTING").to_path_buf(),
new_path: Path::new("CONTRIBUTING.md").to_path_buf(),
@@ -184,12 +202,34 @@ fn test_diff_serde() {
let eof: Option<u8> = None;
let json = serde_json::json!({
"added": [{"path": "LICENSE", "diff": {
"added": [{
"path": "LICENSE",
"diff": {
"type": "plain",
"hunks": []
"hunks": [{
"header": "@@ -0,0 +1,1",
"lines": [{
"line": "MIT",
"lineNo": 1,
"type": "addition",
}]
}]
},
}],
"deleted": [{
"path": "DCO",
"diff": {
"type": "plain",
"hunks": [{
"header": "@@ -0,0 +1,1",
"lines": [{
"line": "TODO",
"lineNo": 1,
"type": "deletion",
}]
}]
},
}],
"deleted": [],
"moved": [{ "oldPath": "CONTRIBUTING", "newPath": "CONTRIBUTING.md" }],
"copied": [],
"modified": [{
+3
View File
@@ -6,3 +6,6 @@ mod git;
#[cfg(test)]
mod file_system;
#[cfg(test)]
mod source;
+39
View File
@@ -0,0 +1,39 @@
use std::path::Path;
use git_ref_format::refname;
use radicle_surf::{git::Repository, source};
use serde_json::json;
const GIT_PLATINUM: &str = "../data/git-platinum";
#[test]
fn tree_serialization() {
let repo = Repository::open(GIT_PLATINUM).unwrap();
let tree = source::Tree::new(
&repo,
&refname!("refs/heads/master"),
Some(&Path::new("src")),
)
.unwrap();
let expected = json!({
"entries": [
{
"kind": "blob",
"lastCommit": null,
"name": "Eval.hs",
"path": "src/Eval.hs"
},
{
"kind": "blob",
"lastCommit": null,
"name": "memory.rs",
"path": "src/memory.rs"
}
],
"lastCommit": null,
"name": "src",
"path": "src"
});
assert_eq!(serde_json::to_value(tree).unwrap(), expected)
}