refactor(deps): replace git2 with system git and add vcs support

This commit is contained in:
2026-06-13 15:28:14 +08:00
parent 39fad31c4f
commit 838be72dd2
13 changed files with 415 additions and 212 deletions

View File

@@ -29,43 +29,5 @@ pub fn fetch_git_dep(
return Ok(());
}
let mut builder = git2::build::RepoBuilder::new();
if let Some(b) = branch {
builder.branch(b);
}
let repo = builder
.clone(url, target_dir)
.map_err(|e| format!("failed to clone {}: {}", url, e))?;
if let Some(t) = tag {
checkout_ref(&repo, &format!("refs/tags/{}", t))?;
} else if let Some(r) = rev {
checkout_ref(&repo, r)?;
}
Ok(())
}
#[allow(dead_code)]
fn checkout_ref(repo: &git2::Repository, reference_str: &str) -> Result<(), String> {
let (object, reference) = repo
.revparse_ext(reference_str)
.map_err(|e| format!("failed to find ref {}: {}", reference_str, e))?;
repo.checkout_tree(&object, None).map_err(|e| {
let ref_name = reference.as_ref().and_then(|r| r.name()).unwrap_or("HEAD");
format!("failed to checkout {}: {}", ref_name, e)
})?;
match reference {
Some(gref) => {
let ref_name = gref.name().unwrap_or("HEAD");
repo.set_head(ref_name)
}
None => repo.set_head_detached(object.id()),
}
.map_err(|e| format!("failed to set HEAD: {}", e))?;
Ok(())
crate::utils::git::git_clone_and_checkout(url, target_dir, branch, tag, rev)
}

View File

@@ -20,4 +20,5 @@ pub mod config;
pub mod deps;
pub mod registry;
pub mod runner;
pub mod vcs;
pub mod workspace;

32
src/core/vcs/git.rs Normal file
View File

@@ -0,0 +1,32 @@
// DCR — Cargo-like C/C++ project manager.
//
// Copyright (C) 2026 Dexoron (Bezotechestvo Vladimir) <main@dexoron.su>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
use std::fs;
use std::path::Path;
// creating git init and .gitignore
pub fn init(path: &Path) -> Result<(), String> {
crate::utils::git::git_init(path)?;
let gitignore_path = path.join(".gitignore");
if !gitignore_path.exists() {
fs::write(&gitignore_path, "/target\n")
.map_err(|e| format!("failed to create .gitignore: {}", e))?;
}
Ok(())
}

61
src/core/vcs/mod.rs Normal file
View File

@@ -0,0 +1,61 @@
// DCR — Cargo-like C/C++ project manager.
//
// Copyright (C) 2026 Dexoron (Bezotechestvo Vladimir) <main@dexoron.su>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
pub mod git;
use std::path::Path;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum VcsKind {
Git,
None,
}
impl VcsKind {
pub fn parse(s: &str) -> Result<Self, String> {
match s.to_lowercase().as_str() {
"git" => Ok(Self::Git),
"none" => Ok(Self::None),
_ => Err(format!("Unknown VCS: {}", s)),
}
}
}
pub fn init_vcs(kind: VcsKind, path: &Path) -> Result<(), String> {
match kind {
VcsKind::Git => git::init(path),
VcsKind::None => Ok(()),
}
}
// look for git repo in parents to avoid nested repos
pub fn find_existing_vcs(path: &Path) -> Option<VcsKind> {
let mut current = if path.is_file() {
path.parent()
} else {
Some(path)
};
while let Some(dir) = current {
if dir.join(".git").exists() {
return Some(VcsKind::Git);
}
current = dir.parent();
}
None
}