998f393ed0
- Implement ArchiveService for repository archive operations - Add BlameService for Git blame functionality - Create BranchService with full branch management capabilities - Integrate CommitService for commit operations and history - Add DiffService for generating diffs and patches - Implement MergeService with conflict resolution features - Add PackService for Git packfile operations - Create TagService for Git tag management - Add TreeService for Git tree operations - Implement comprehensive repository management functions - Add repository statistics and health checking capabilities - Include garbage collection and repacking operations - Add repository configuration management - Implement error handling and status conversion utilities - Add test suite covering all repository operations - Create utility functions for Git command execution - Add streaming response support for large data operations - Implement request resolution and validation helpers
158 lines
4.6 KiB
Rust
158 lines
4.6 KiB
Rust
use crate::pb::*;
|
|
|
|
use super::git_cmd;
|
|
|
|
pub(crate) fn maintenance_response(out: std::process::Output) -> RepositoryMaintenanceResponse {
|
|
RepositoryMaintenanceResponse {
|
|
ok: out.status.success(),
|
|
stdout: String::from_utf8_lossy(&out.stdout).into_owned(),
|
|
stderr: String::from_utf8_lossy(&out.stderr).into_owned(),
|
|
}
|
|
}
|
|
|
|
fn dir_size(path: &std::path::Path) -> u64 {
|
|
let mut total = 0u64;
|
|
if let Ok(entries) = std::fs::read_dir(path) {
|
|
for entry in entries.flatten() {
|
|
let p = entry.path();
|
|
if p.is_file() {
|
|
total += entry.metadata().map(|m| m.len()).unwrap_or(0);
|
|
} else if p.is_dir() {
|
|
total += dir_size(&p);
|
|
}
|
|
}
|
|
}
|
|
total
|
|
}
|
|
|
|
fn count_refs(gb: &crate::bare::GitBare) -> u64 {
|
|
let out = git_cmd(gb, &["for-each-ref", "--format=%(refname)"]).unwrap_or_else(|_| {
|
|
std::process::Output {
|
|
status: Default::default(),
|
|
stdout: Vec::new(),
|
|
stderr: Vec::new(),
|
|
}
|
|
});
|
|
String::from_utf8_lossy(&out.stdout)
|
|
.lines()
|
|
.filter(|l| !l.is_empty())
|
|
.count() as u64
|
|
}
|
|
|
|
fn file_len(path: &std::path::Path) -> u64 {
|
|
std::fs::metadata(path).map(|m| m.len()).unwrap_or(0)
|
|
}
|
|
|
|
pub(crate) fn get_statistics(gb: &crate::bare::GitBare) -> RepositoryStatistics {
|
|
let size_bytes = dir_size(&gb.bare_dir);
|
|
|
|
let mut loose_object_count: u64 = 0;
|
|
let mut packed_object_count: u64 = 0;
|
|
let mut packfile_count: u64 = 0;
|
|
if let Ok(out) = git_cmd(gb, &["count-objects", "-v"]) {
|
|
for line in String::from_utf8_lossy(&out.stdout).lines() {
|
|
let line = line.trim();
|
|
if let Some(v) = line.strip_prefix("count: ") {
|
|
loose_object_count = v.trim().parse().unwrap_or(0);
|
|
} else if let Some(v) = line.strip_prefix("in-pack: ") {
|
|
packed_object_count = v.trim().parse().unwrap_or(0);
|
|
} else if let Some(v) = line.strip_prefix("packs: ") {
|
|
packfile_count = v.trim().parse().unwrap_or(0);
|
|
}
|
|
}
|
|
}
|
|
|
|
let reference_count = count_refs(gb);
|
|
let commit_graph_size_bytes = file_len(&gb.bare_dir.join("objects/info/commit-graph"));
|
|
let multi_pack_index_size_bytes = file_len(&gb.bare_dir.join("objects/pack/multi-pack-index"));
|
|
|
|
RepositoryStatistics {
|
|
size_bytes,
|
|
loose_object_count,
|
|
packed_object_count,
|
|
packfile_count,
|
|
reference_count,
|
|
commit_graph_size_bytes,
|
|
multi_pack_index_size_bytes,
|
|
}
|
|
}
|
|
|
|
pub(crate) fn check_health(
|
|
gb: &crate::bare::GitBare,
|
|
connectivity_only: bool,
|
|
) -> Result<RepositoryHealthResponse, tonic::Status> {
|
|
let mut args: Vec<&str> = vec!["fsck"];
|
|
if connectivity_only {
|
|
args.push("--connectivity-only");
|
|
}
|
|
let out = git_cmd(gb, &args)?;
|
|
let text = String::from_utf8_lossy(&out.stdout);
|
|
let mut warnings = Vec::new();
|
|
let mut errors = Vec::new();
|
|
for line in text.lines() {
|
|
if line.starts_with("error:") {
|
|
errors.push(line.to_string());
|
|
} else if line.starts_with("warning:") {
|
|
warnings.push(line.to_string());
|
|
}
|
|
}
|
|
Ok(RepositoryHealthResponse {
|
|
ok: out.status.success(),
|
|
warnings,
|
|
errors,
|
|
statistics: None,
|
|
})
|
|
}
|
|
|
|
pub(crate) fn run_gc(
|
|
gb: &crate::bare::GitBare,
|
|
prune: bool,
|
|
aggressive: bool,
|
|
) -> Result<RepositoryMaintenanceResponse, tonic::Status> {
|
|
let mut args: Vec<&str> = vec!["gc"];
|
|
if prune {
|
|
args.push("--prune=now");
|
|
}
|
|
if aggressive {
|
|
args.push("--aggressive");
|
|
}
|
|
let out = git_cmd(gb, &args)?;
|
|
Ok(maintenance_response(out))
|
|
}
|
|
|
|
pub(crate) fn run_repack(
|
|
gb: &crate::bare::GitBare,
|
|
full: bool,
|
|
write_bitmaps: bool,
|
|
write_multi_pack_index: bool,
|
|
) -> Result<RepositoryMaintenanceResponse, tonic::Status> {
|
|
let mut args: Vec<&str> = vec!["repack", "-d"];
|
|
if full {
|
|
args.push("-a");
|
|
}
|
|
if write_bitmaps {
|
|
args.push("--write-bitmap-index");
|
|
}
|
|
if write_multi_pack_index {
|
|
args.push("--write-midx");
|
|
}
|
|
let out = git_cmd(gb, &args)?;
|
|
Ok(maintenance_response(out))
|
|
}
|
|
|
|
pub(crate) fn run_commit_graph_write(
|
|
gb: &crate::bare::GitBare,
|
|
split: bool,
|
|
replace: bool,
|
|
) -> Result<RepositoryMaintenanceResponse, tonic::Status> {
|
|
let mut args: Vec<&str> = vec!["commit-graph", "write"];
|
|
if split {
|
|
args.push("--split");
|
|
}
|
|
if !replace {
|
|
args.push("--append");
|
|
}
|
|
let out = git_cmd(gb, &args)?;
|
|
Ok(maintenance_response(out))
|
|
}
|