@@ 3,7 3,7 @@ pub fn diffs<'a>(commit: git2::Commit<'a>, repo: &'a git2::Repository) -> Option
Ok(tree) => match commit.parent(0) {
Ok(parent) => match parent.tree() {
Ok(parent_tree) => {
- match repo.diff_tree_to_tree(Some(&tree), Some(&parent_tree), None) {
+ match repo.diff_tree_to_tree(Some(&parent_tree), Some(&tree), None) {
Ok(diff) => Some(diff),
Err(_) => None,
}
@@ 16,6 16,7 @@ use crate::repository::log;
use crate::repository::raw;
use crate::repository::summary;
use crate::repository::tree;
+use crate::repository::commit;
use crate::utils::own_pathbuf::PathBufWithDotfiles;
use rocket_dyn_templates::Template;
@@ 36,6 37,8 @@ fn rocket() -> _ {
log::log_main,
log::log,
blame::blames,
+ commit::commit,
+ commit::patch
],
)
.attach(Template::fairing())
@@ 0,0 1,162 @@
+use crate::config::CONFIG;
+use crate::git::blame::blame;
+use crate::git::commits::get_commits;
+use crate::git::file::file;
+use crate::git::diffs::diffs;
+use serde_derive::Serialize;
+use git2::DiffLineType::*;
+
+use crate::utils::repo_config::repo_config;
+use crate::PathBufWithDotfiles;
+use rocket_dyn_templates::{context, Template};
+use std::ffi::OsStr;
+use std::path::Path;
+use syntect::highlighting::ThemeSet;
+use syntect::html::highlighted_html_for_string;
+use syntect::parsing::SyntaxSet;
+use git2::Delta::*;
+
+#[get("/<repo>/commit/<oid>", rank = 2)]
+pub fn commit(repo: String, oid: String) -> Option<Template> {
+ let mut repo_path = CONFIG.git_location.clone();
+ repo_path.push(format!("{}.git", repo));
+ let repo_clone = repo.clone();
+ let repo = git2::Repository::open(repo_path).ok()?;
+ let commit = repo.find_commit(git2::Oid::from_str(&oid).ok()?).ok()?;
+ let diff = diffs(commit.clone(), &repo)?;
+ let stats = diff.stats().ok()?;
+ Some(Template::render(
+ "repository/commit",
+ context! {
+ title: format!("{} :: {}", oid, repo_clone.clone()),
+ repo: repo_clone.clone(),
+ config: repo_config(repo_clone.clone()),
+ domain: CONFIG.domain.to_string(),
+ active: "log",
+ payment: CONFIG.payment_link.clone(),
+ mailing_list: CONFIG.mailing_list.clone(),
+ commit: match get_commits(repo_clone.clone(), 1, Some(oid.clone()), None) {
+ Some(x) => match x.clone().get(0) {
+ Some(x) => Some(x.clone()),
+ None => None
+ }
+ None => None
+ },
+ parent: match commit.parent_id(0) {
+ Ok(parent) => {
+ match get_commits(repo_clone.clone(), 1, Some(parent.to_string()), None) {
+ Some(x) => Some(x.first()?.clone()),
+ None => None
+ }
+ },
+ Err(_) => None
+ },
+ files_changed: stats.files_changed(),
+ insertions: stats.insertions(),
+ deletions: stats.deletions(),
+ files: {
+ let mut items = Vec::new();
+ let mut x = 0;
+ for i in diff.deltas() {
+ let patch = git2::Patch::from_diff(&diff, x).ok()??;
+ let hunk_n = patch.num_hunks();
+ let mut hunks = Vec::new();
+ for y in 0..hunk_n {
+ let hunk = patch.hunk(y).ok()?;
+ let line_n = patch.num_lines_in_hunk(y).ok()?;
+ let mut lines = Vec::new();
+ for z in 0..line_n {
+ let line = patch.line_in_hunk(y, z).ok()?;
+ lines.push(Lines {
+ line_n: z,
+ class: match line.origin_value() {
+ Addition => "text-success",
+ Deletion => "text-danger",
+ AddEOFNL => "text-success",
+ DeleteEOFNL => "text-danger",
+ _ => ""
+ }.to_string(),
+ types: line.origin(),
+ line: std::str::from_utf8(line.content()).ok()?.to_string()
+ });
+ }
+ let header = std::str::from_utf8(hunk.0.header()).ok()?.to_string();
+ let mut first_line = header.split("@@").collect::<Vec<&str>>();
+ for _ in 0..2 {
+ first_line.remove(0);
+ }
+ hunks.push(Hunk {
+ hunk_n: y,
+ first: hunk.0.old_start(),
+ second: hunk.0.old_lines(),
+ third: hunk.0.new_start(),
+ fourth: hunk.0.new_lines(),
+ first_line: first_line.join("@@"),
+ lines
+ });
+ }
+ items.push(Files {
+ beging_path: (*i.old_file().path()?).display().to_string(),
+ end_path: (*i.new_file().path()?).display().to_string(),
+ status: match i.status() {
+ Added => 'A',
+ Deleted => 'D',
+ Modified => 'M',
+ Renamed => 'R',
+ Copied => 'C',
+ Ignored => 'I',
+ Typechange => 'T',
+ Conflicted => 'C',
+ _ => ' ',
+ },
+ insertions: patch.line_stats().ok()?.1,
+ deletions: patch.line_stats().ok()?.2,
+ hunks
+ });
+ x+=1;
+ }
+ items
+ },
+ }
+ ))
+}
+
+#[get("/<repo>/patch/<oid>", rank = 2)]
+pub fn patch(repo: String, oid: String) -> Option<Vec<u8>> {
+ let mut repo_path = CONFIG.git_location.clone();
+ repo_path.push(format!("{}.git", repo));
+ let repo_clone = repo.clone();
+ let repo = git2::Repository::open(repo_path).ok()?;
+ let commit = repo.find_commit(git2::Oid::from_str(&oid).ok()?).ok()?;
+ let diff = diffs(commit, &repo)?;
+ None
+}
+
+#[derive(Serialize, Clone)]
+pub struct Files {
+ beging_path: String,
+ end_path: String,
+ status: char,
+ insertions: usize,
+ deletions: usize,
+ hunks: Vec<Hunk>
+}
+
+#[derive(Serialize, Clone)]
+pub struct Hunk {
+ hunk_n: usize,
+ first: u32,
+ second: u32,
+ third: u32,
+ fourth: u32,
+ first_line: String,
+ lines: Vec<Lines>
+}
+
+#[derive(Serialize, Clone)]
+pub struct Lines {
+ line_n: usize,
+ class: String,
+ types: char,
+ line: String
+}