//! Copyright (c) 2022-2026 GitDataAi All rights reserved. use gitks::bare::GitBare; use gitks::server::GitksService; #[allow(dead_code)] pub fn setup_service(dir: &std::path::Path) -> GitksService { GitksService::new(dir.to_path_buf()) } pub fn run_git(work_dir: &std::path::Path, args: &[&str]) -> duct::Expression { duct::cmd("git", { let work_str = work_dir.to_string_lossy().into_owned(); let mut v: Vec = vec!["-C".into(), work_str]; v.extend(args.iter().map(|s| s.to_string())); v }) .env("GIT_AUTHOR_NAME", "Test") .env("GIT_AUTHOR_EMAIL", "test@example.com") .env("GIT_COMMITTER_NAME", "Test") .env("GIT_COMMITTER_EMAIL", "test@example.com") } pub fn run(work_dir: &std::path::Path, args: &[&str]) { let result = run_git(work_dir, args) .stdout_capture() .stderr_capture() .unchecked() .run() .unwrap(); assert!( result.status.success(), "git {} failed: {}", args.join(" "), String::from_utf8_lossy(&result.stderr) ); } pub fn setup_bare_repo() -> (tempfile::TempDir, GitBare) { let dir = tempfile::tempdir().expect("create temp dir"); let bare_dir = dir.path().join("test-repo"); duct::cmd( "git", ["init", "--bare", bare_dir.to_string_lossy().as_ref()], ) .run() .expect("git init --bare"); let work_dir = dir.path().join("work"); duct::cmd( "git", [ "clone", bare_dir.to_string_lossy().as_ref(), work_dir.to_string_lossy().as_ref(), ], ) .run() .expect("clone"); run(&work_dir, &["checkout", "-b", "main"]); std::fs::write(work_dir.join("README.md"), "# Test\n").unwrap(); run(&work_dir, &["add", "."]); run(&work_dir, &["commit", "-m", "initial commit"]); run(&work_dir, &["branch", "feature"]); std::fs::write(work_dir.join("src.txt"), "source\n").unwrap(); run(&work_dir, &["add", "."]); run(&work_dir, &["commit", "-m", "second commit"]); std::fs::write(work_dir.join("README.md"), "# Test\n\nUpdated.\n").unwrap(); run(&work_dir, &["add", "."]); run(&work_dir, &["commit", "-m", "third commit"]); std::fs::create_dir_all(work_dir.join("src/lib")).unwrap(); std::fs::write(work_dir.join("src/lib/mod.rs"), "pub fn hello() {}\n").unwrap(); run(&work_dir, &["add", "."]); run(&work_dir, &["commit", "-m", "add nested file"]); run(&work_dir, &["tag", "v0.1.0"]); run( &work_dir, &["push", "-f", "origin", "main:main", "feature:feature"], ); run( &work_dir, &["push", "-f", "origin", "refs/tags/v0.1.0:refs/tags/v0.1.0"], ); duct::cmd( "git", [ "--git-dir", bare_dir.to_string_lossy().as_ref(), "symbolic-ref", "HEAD", "refs/heads/main", ], ) .run() .expect("set HEAD to main"); (dir, GitBare::new(bare_dir)) } #[allow(dead_code)] pub fn setup_bare_repo_with_conflict() -> (tempfile::TempDir, GitBare) { let dir = tempfile::tempdir().expect("create temp dir"); let bare_dir = dir.path().join("test-repo"); duct::cmd( "git", ["init", "--bare", bare_dir.to_string_lossy().as_ref()], ) .run() .expect("git init --bare"); let work_dir = dir.path().join("work"); duct::cmd( "git", [ "clone", bare_dir.to_string_lossy().as_ref(), work_dir.to_string_lossy().as_ref(), ], ) .run() .expect("clone"); run(&work_dir, &["checkout", "-b", "main"]); std::fs::write(work_dir.join("file.txt"), "base content\n").unwrap(); run(&work_dir, &["add", "."]); run(&work_dir, &["commit", "-m", "base commit"]); run(&work_dir, &["checkout", "-b", "branch-a"]); std::fs::write(work_dir.join("file.txt"), "branch A content\n").unwrap(); run(&work_dir, &["add", "."]); run(&work_dir, &["commit", "-m", "branch A change"]); run(&work_dir, &["checkout", "main"]); run(&work_dir, &["checkout", "-b", "branch-b"]); std::fs::write(work_dir.join("file.txt"), "branch B content\n").unwrap(); run(&work_dir, &["add", "."]); run(&work_dir, &["commit", "-m", "branch B change"]); run( &work_dir, &[ "push", "-f", "origin", "main:main", "branch-a:branch-a", "branch-b:branch-b", ], ); duct::cmd( "git", [ "--git-dir", bare_dir.to_string_lossy().as_ref(), "symbolic-ref", "HEAD", "refs/heads/main", ], ) .run() .expect("set HEAD to main"); (dir, GitBare::new(bare_dir)) } #[allow(dead_code)] pub fn get_oid(gb: &GitBare, rev: &str) -> String { let output = std::process::Command::new("git") .args([ "--git-dir", gb.bare_dir.to_string_lossy().as_ref(), "rev-parse", rev, ]) .output() .expect("git rev-parse"); assert!(output.status.success(), "git rev-parse {rev} failed"); String::from_utf8_lossy(&output.stdout).trim().to_string() } #[allow(dead_code)] pub fn get_main_oid(gb: &GitBare) -> String { get_oid(gb, "refs/heads/main") } #[allow(dead_code)] pub fn get_feature_oid(gb: &GitBare) -> String { get_oid(gb, "refs/heads/feature") } #[allow(dead_code)] pub fn oid_selector(hex: &str) -> Option { Some(gitks::pb::ObjectSelector { selector: Some(gitks::pb::object_selector::Selector::Oid(gitks::pb::Oid { hex: hex.to_string(), value: vec![], format: 0, })), }) } #[allow(dead_code)] pub fn rev_selector(rev: &str) -> Option { Some(gitks::pb::ObjectSelector { selector: Some(gitks::pb::object_selector::Selector::Revision( gitks::pb::ObjectName { revision: rev.to_string(), }, )), }) }