mirror of
https://seed.radicle.dev/rad:z6cFWeWpnZNHh9rUW8phgA3b5yGt.git
synced 2026-10-18 19:10:31 +08:00
Merge remote-tracking branch 'origin/cloudhead/add-file-info-to-diff'
* origin/cloudhead/add-file-info-to-diff: Add file information to diff Signed-off-by: Fintan Halpenny <fintan.halpenny@gmail.com>
This commit is contained in:
@@ -22,6 +22,8 @@ use std::{borrow::Cow, path::PathBuf, string::FromUtf8Error};
|
||||
#[cfg(feature = "serde")]
|
||||
use serde::{ser, ser::SerializeStruct, Serialize, Serializer};
|
||||
|
||||
use git_ext::Oid;
|
||||
|
||||
pub mod git;
|
||||
|
||||
/// The serializable representation of a `git diff`.
|
||||
@@ -90,8 +92,13 @@ impl Diff {
|
||||
&self.stats
|
||||
}
|
||||
|
||||
fn insert_modified(&mut self, path: PathBuf, diff: DiffContent) {
|
||||
let diff = FileDiff::Modified(Modified { path, diff });
|
||||
fn insert_modified(&mut self, path: PathBuf, diff: DiffContent, old: DiffFile, new: DiffFile) {
|
||||
let diff = FileDiff::Modified(Modified {
|
||||
path,
|
||||
diff,
|
||||
old,
|
||||
new,
|
||||
});
|
||||
self.files.push(diff)
|
||||
}
|
||||
|
||||
@@ -113,13 +120,13 @@ impl Diff {
|
||||
self.files.push(diff);
|
||||
}
|
||||
|
||||
fn insert_added(&mut self, path: PathBuf, diff: DiffContent) {
|
||||
let diff = FileDiff::Added(Added { path, diff });
|
||||
fn insert_added(&mut self, path: PathBuf, diff: DiffContent, new: DiffFile) {
|
||||
let diff = FileDiff::Added(Added { path, diff, new });
|
||||
self.files.push(diff);
|
||||
}
|
||||
|
||||
fn insert_deleted(&mut self, path: PathBuf, diff: DiffContent) {
|
||||
let diff = FileDiff::Deleted(Deleted { path, diff });
|
||||
fn insert_deleted(&mut self, path: PathBuf, diff: DiffContent, old: DiffFile) {
|
||||
let diff = FileDiff::Deleted(Deleted { path, diff, old });
|
||||
self.files.push(diff);
|
||||
}
|
||||
}
|
||||
@@ -131,6 +138,7 @@ pub struct Added {
|
||||
/// The path to this file, relative to the repository root.
|
||||
pub path: PathBuf,
|
||||
pub diff: DiffContent,
|
||||
pub new: DiffFile,
|
||||
}
|
||||
|
||||
/// A file that was deleted within a [`Diff`].
|
||||
@@ -140,6 +148,7 @@ pub struct Deleted {
|
||||
/// The path to this file, relative to the repository root.
|
||||
pub path: PathBuf,
|
||||
pub diff: DiffContent,
|
||||
pub old: DiffFile,
|
||||
}
|
||||
|
||||
/// A file that was moved within a [`Diff`].
|
||||
@@ -199,6 +208,8 @@ impl Default for EofNewLine {
|
||||
pub struct Modified {
|
||||
pub path: PathBuf,
|
||||
pub diff: DiffContent,
|
||||
pub old: DiffFile,
|
||||
pub new: DiffFile,
|
||||
}
|
||||
|
||||
/// The set of changes for a given file.
|
||||
@@ -229,6 +240,44 @@ impl DiffContent {
|
||||
}
|
||||
}
|
||||
|
||||
/// File mode in a diff.
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize), serde(rename_all = "camelCase"))]
|
||||
pub enum FileMode {
|
||||
/// For regular files.
|
||||
Blob,
|
||||
/// For regular files that are executable.
|
||||
BlobExecutable,
|
||||
/// For directories.
|
||||
Tree,
|
||||
/// For symbolic links.
|
||||
Link,
|
||||
/// Used for Git submodules.
|
||||
Commit,
|
||||
}
|
||||
|
||||
impl From<FileMode> for u32 {
|
||||
fn from(m: FileMode) -> Self {
|
||||
git2::FileMode::from(m).into()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<FileMode> for i32 {
|
||||
fn from(m: FileMode) -> Self {
|
||||
git2::FileMode::from(m).into()
|
||||
}
|
||||
}
|
||||
|
||||
/// A modified file.
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize), serde(rename_all = "camelCase"))]
|
||||
pub struct DiffFile {
|
||||
/// File blob id.
|
||||
pub oid: Oid,
|
||||
/// File mode.
|
||||
pub mode: FileMode,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub enum FileDiff {
|
||||
Added(Added),
|
||||
|
||||
@@ -17,7 +17,18 @@
|
||||
|
||||
use std::convert::TryFrom;
|
||||
|
||||
use super::{Diff, DiffContent, EofNewLine, Hunk, Hunks, Line, Modification, Stats};
|
||||
use super::{
|
||||
Diff,
|
||||
DiffContent,
|
||||
DiffFile,
|
||||
EofNewLine,
|
||||
FileMode,
|
||||
Hunk,
|
||||
Hunks,
|
||||
Line,
|
||||
Modification,
|
||||
Stats,
|
||||
};
|
||||
|
||||
pub mod error {
|
||||
use std::path::PathBuf;
|
||||
@@ -42,6 +53,13 @@ pub mod error {
|
||||
MissingOldLineNo,
|
||||
}
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
#[non_exhaustive]
|
||||
pub enum FileMode {
|
||||
#[error("unknown file mode `{0:?}`")]
|
||||
Unknown(git2::FileMode),
|
||||
}
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
#[non_exhaustive]
|
||||
pub enum Modification {
|
||||
@@ -75,6 +93,8 @@ pub mod error {
|
||||
#[error(transparent)]
|
||||
Git(#[from] git2::Error),
|
||||
#[error(transparent)]
|
||||
FileMode(#[from] FileMode),
|
||||
#[error(transparent)]
|
||||
Hunk(#[from] Hunk),
|
||||
#[error(transparent)]
|
||||
Line(#[from] Modification),
|
||||
@@ -87,6 +107,44 @@ pub mod error {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> TryFrom<git2::DiffFile<'a>> for DiffFile {
|
||||
type Error = error::FileMode;
|
||||
|
||||
fn try_from(value: git2::DiffFile) -> Result<Self, Self::Error> {
|
||||
Ok(Self {
|
||||
mode: value.mode().try_into()?,
|
||||
oid: value.id().into(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<git2::FileMode> for FileMode {
|
||||
type Error = error::FileMode;
|
||||
|
||||
fn try_from(value: git2::FileMode) -> Result<Self, Self::Error> {
|
||||
match value {
|
||||
git2::FileMode::Blob => Ok(Self::Blob),
|
||||
git2::FileMode::BlobExecutable => Ok(Self::BlobExecutable),
|
||||
git2::FileMode::Commit => Ok(Self::Commit),
|
||||
git2::FileMode::Tree => Ok(Self::Tree),
|
||||
git2::FileMode::Link => Ok(Self::Link),
|
||||
_ => Err(error::FileMode::Unknown(value)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<FileMode> for git2::FileMode {
|
||||
fn from(m: FileMode) -> Self {
|
||||
match m {
|
||||
FileMode::Blob => git2::FileMode::Blob,
|
||||
FileMode::BlobExecutable => git2::FileMode::BlobExecutable,
|
||||
FileMode::Tree => git2::FileMode::Tree,
|
||||
FileMode::Link => git2::FileMode::Link,
|
||||
FileMode::Commit => git2::FileMode::Commit,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<git2::Patch<'_>> for DiffContent {
|
||||
type Error = error::Hunk;
|
||||
|
||||
@@ -192,16 +250,18 @@ fn created(
|
||||
delta: &git2::DiffDelta<'_>,
|
||||
) -> Result<(), error::Diff> {
|
||||
let diff_file = delta.new_file();
|
||||
let is_binary = diff_file.is_binary();
|
||||
let path = diff_file
|
||||
.path()
|
||||
.ok_or(error::Diff::PathUnavailable)?
|
||||
.to_path_buf();
|
||||
let new = DiffFile::try_from(diff_file)?;
|
||||
|
||||
let patch = git2::Patch::from_diff(git_diff, idx)?;
|
||||
if let Some(patch) = patch {
|
||||
diff.insert_added(path, DiffContent::try_from(patch)?);
|
||||
} else if diff_file.is_binary() {
|
||||
diff.insert_added(path, DiffContent::Binary);
|
||||
diff.insert_added(path, DiffContent::try_from(patch)?, new);
|
||||
} else if is_binary {
|
||||
diff.insert_added(path, DiffContent::Binary, new);
|
||||
} else {
|
||||
return Err(error::Diff::PatchUnavailable(path));
|
||||
}
|
||||
@@ -215,15 +275,18 @@ fn deleted(
|
||||
delta: &git2::DiffDelta<'_>,
|
||||
) -> Result<(), error::Diff> {
|
||||
let diff_file = delta.old_file();
|
||||
let is_binary = diff_file.is_binary();
|
||||
let path = diff_file
|
||||
.path()
|
||||
.ok_or(error::Diff::PathUnavailable)?
|
||||
.to_path_buf();
|
||||
let patch = git2::Patch::from_diff(git_diff, idx)?;
|
||||
let old = DiffFile::try_from(diff_file)?;
|
||||
|
||||
if let Some(patch) = patch {
|
||||
diff.insert_deleted(path, DiffContent::try_from(patch)?);
|
||||
} else if diff_file.is_binary() {
|
||||
diff.insert_deleted(path, DiffContent::Binary);
|
||||
diff.insert_deleted(path, DiffContent::try_from(patch)?, old);
|
||||
} else if is_binary {
|
||||
diff.insert_deleted(path, DiffContent::Binary, old);
|
||||
} else {
|
||||
return Err(error::Diff::PatchUnavailable(path));
|
||||
}
|
||||
@@ -242,12 +305,14 @@ fn modified(
|
||||
.ok_or(error::Diff::PathUnavailable)?
|
||||
.to_path_buf();
|
||||
let patch = git2::Patch::from_diff(git_diff, idx)?;
|
||||
let old = DiffFile::try_from(delta.old_file())?;
|
||||
let new = DiffFile::try_from(delta.new_file())?;
|
||||
|
||||
if let Some(patch) = patch {
|
||||
diff.insert_modified(path, DiffContent::try_from(patch)?);
|
||||
diff.insert_modified(path, DiffContent::try_from(patch)?, old, new);
|
||||
Ok(())
|
||||
} else if diff_file.is_binary() {
|
||||
diff.insert_modified(path, DiffContent::Binary);
|
||||
diff.insert_modified(path, DiffContent::Binary, old, new);
|
||||
Ok(())
|
||||
} else {
|
||||
Err(error::Diff::PatchUnavailable(path))
|
||||
|
||||
+56
-16
@@ -5,8 +5,10 @@ use radicle_surf::{
|
||||
Added,
|
||||
Diff,
|
||||
DiffContent,
|
||||
DiffFile,
|
||||
EofNewLine,
|
||||
FileDiff,
|
||||
FileMode,
|
||||
Hunk,
|
||||
Line,
|
||||
Modification,
|
||||
@@ -46,6 +48,10 @@ fn test_initial_diff() -> Result<(), Error> {
|
||||
.into(),
|
||||
eof: EofNewLine::default(),
|
||||
},
|
||||
new: DiffFile {
|
||||
oid: Oid::from_str("7f48df0118b1674f4ab0ed1717c1368091a5dddc").unwrap(),
|
||||
mode: FileMode::Blob,
|
||||
},
|
||||
})];
|
||||
|
||||
let expected_stats = Stats {
|
||||
@@ -78,7 +84,7 @@ fn test_diff_file() -> Result<(), Error> {
|
||||
"223aaf87d6ea62eef0014857640fd7c8dd0f80b5",
|
||||
)?;
|
||||
let expected_diff = FileDiff::Modified(Modified {
|
||||
path: path_buf,
|
||||
path: path_buf,
|
||||
diff: DiffContent::Plain {
|
||||
hunks: vec unit tests.\n".to_vec(), 2),
|
||||
]
|
||||
}].into(),
|
||||
],
|
||||
}]
|
||||
.into(),
|
||||
eof: EofNewLine::default(),
|
||||
},
|
||||
old: DiffFile {
|
||||
oid: Oid::from_str("7f48df0118b1674f4ab0ed1717c1368091a5dddc").unwrap(),
|
||||
mode: FileMode::Blob,
|
||||
},
|
||||
new: DiffFile {
|
||||
oid: Oid::from_str("5e07534cd74a6a9b2ccd2729b181c4ef26173a5e").unwrap(),
|
||||
mode: FileMode::Blob,
|
||||
},
|
||||
});
|
||||
assert_eq!(expected_diff, diff);
|
||||
|
||||
@@ -105,19 +120,28 @@ fn test_diff() -> Result<(), Error> {
|
||||
let diff = repo.diff(*parent_oid, oid)?;
|
||||
|
||||
let expected_files = vec unit tests.\n".to_vec(), 2),
|
||||
]
|
||||
}].into(),
|
||||
eof: EofNewLine::default(),
|
||||
},
|
||||
})];
|
||||
path: Path::new("README.md").to_path_buf(),
|
||||
diff: DiffContent::Plain {
|
||||
hunks: vec unit tests.\n".to_vec(), 2),
|
||||
],
|
||||
}]
|
||||
.into(),
|
||||
eof: EofNewLine::default(),
|
||||
},
|
||||
old: DiffFile {
|
||||
oid: Oid::from_str("7f48df0118b1674f4ab0ed1717c1368091a5dddc").unwrap(),
|
||||
mode: FileMode::Blob,
|
||||
},
|
||||
new: DiffFile {
|
||||
oid: Oid::from_str("5e07534cd74a6a9b2ccd2729b181c4ef26173a5e").unwrap(),
|
||||
mode: FileMode::Blob,
|
||||
},
|
||||
})];
|
||||
let expected_stats = Stats {
|
||||
files_changed: 1,
|
||||
insertions: 2,
|
||||
@@ -208,9 +232,17 @@ fn test_diff_serde() -> Result<(), Error> {
|
||||
}],
|
||||
"eof": "noneMissing",
|
||||
},
|
||||
"new": {
|
||||
"mode": "blob",
|
||||
"oid": "02f70f56ec62396ceaf38804c37e169e875ab291",
|
||||
},
|
||||
}],
|
||||
"deleted": [{
|
||||
"path": "text/arrows.txt",
|
||||
"old": {
|
||||
"mode": "blob",
|
||||
"oid": "95418c04010a3cc758fb3a37f9918465f147566f",
|
||||
},
|
||||
"diff": {
|
||||
"type": "plain",
|
||||
"hunks": [{
|
||||
@@ -288,6 +320,14 @@ fn test_diff_serde() -> Result<(), Error> {
|
||||
}],
|
||||
"eof": "noneMissing",
|
||||
},
|
||||
"new": {
|
||||
"mode": "blob",
|
||||
"oid": "b033ecf407a44922b28c942c696922a7d7daf06e",
|
||||
},
|
||||
"old": {
|
||||
"mode": "blob",
|
||||
"oid": "5e07534cd74a6a9b2ccd2729b181c4ef26173a5e",
|
||||
},
|
||||
}],
|
||||
"stats": {
|
||||
"deletions": 9,
|
||||
|
||||
Reference in New Issue
Block a user