mirror of
https://github.com/dexoron/dcr.git
synced 2026-10-21 11:48:36 +00:00
refactor(deps): replace git2 with system git and add vcs support
This commit is contained in:
151
Cargo.lock
generated
151
Cargo.lock
generated
@@ -63,8 +63,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "556e016178bb5662a08681bbe0f00f8e17631781a4dfc8c45e466e4b185ec27f"
|
checksum = "556e016178bb5662a08681bbe0f00f8e17631781a4dfc8c45e466e4b185ec27f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"find-msvc-tools",
|
"find-msvc-tools",
|
||||||
"jobserver",
|
|
||||||
"libc",
|
|
||||||
"shlex",
|
"shlex",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -112,12 +110,10 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dcr"
|
name = "dcr"
|
||||||
version = "0.7.2"
|
version = "0.7.3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ctrlc",
|
"ctrlc",
|
||||||
"git2",
|
|
||||||
"glob",
|
"glob",
|
||||||
"openssl",
|
|
||||||
"reqwest",
|
"reqwest",
|
||||||
"self-replace",
|
"self-replace",
|
||||||
"serde",
|
"serde",
|
||||||
@@ -193,21 +189,6 @@ version = "0.1.5"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2"
|
checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "foreign-types"
|
|
||||||
version = "0.3.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1"
|
|
||||||
dependencies = [
|
|
||||||
"foreign-types-shared",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "foreign-types-shared"
|
|
||||||
version = "0.1.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "form_urlencoded"
|
name = "form_urlencoded"
|
||||||
version = "1.2.2"
|
version = "1.2.2"
|
||||||
@@ -316,21 +297,6 @@ dependencies = [
|
|||||||
"wasip3",
|
"wasip3",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "git2"
|
|
||||||
version = "0.20.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "7b88256088d75a56f8ecfa070513a775dd9107f6530ef14919dac831af9cfe2b"
|
|
||||||
dependencies = [
|
|
||||||
"bitflags",
|
|
||||||
"libc",
|
|
||||||
"libgit2-sys",
|
|
||||||
"log",
|
|
||||||
"openssl-probe",
|
|
||||||
"openssl-sys",
|
|
||||||
"url",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "glob"
|
name = "glob"
|
||||||
version = "0.3.3"
|
version = "0.3.3"
|
||||||
@@ -589,16 +555,6 @@ version = "1.0.18"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682"
|
checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "jobserver"
|
|
||||||
version = "0.1.34"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33"
|
|
||||||
dependencies = [
|
|
||||||
"getrandom 0.3.4",
|
|
||||||
"libc",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "js-sys"
|
name = "js-sys"
|
||||||
version = "0.3.99"
|
version = "0.3.99"
|
||||||
@@ -623,46 +579,6 @@ version = "0.2.186"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66"
|
checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "libgit2-sys"
|
|
||||||
version = "0.18.5+1.9.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "005d6ae6eac1912906073e069f7db60b1fa98e052a68227824afe3e3a1c59ca2"
|
|
||||||
dependencies = [
|
|
||||||
"cc",
|
|
||||||
"libc",
|
|
||||||
"libssh2-sys",
|
|
||||||
"libz-sys",
|
|
||||||
"openssl-sys",
|
|
||||||
"pkg-config",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "libssh2-sys"
|
|
||||||
version = "0.3.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "220e4f05ad4a218192533b300327f5150e809b54c4ec83b5a1d91833601811b9"
|
|
||||||
dependencies = [
|
|
||||||
"cc",
|
|
||||||
"libc",
|
|
||||||
"libz-sys",
|
|
||||||
"openssl-sys",
|
|
||||||
"pkg-config",
|
|
||||||
"vcpkg",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "libz-sys"
|
|
||||||
version = "1.1.29"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "85bc9657773828b90eeb625adff10eeac83cc21bbfd8e23a03eaa8a33c9e28d9"
|
|
||||||
dependencies = [
|
|
||||||
"cc",
|
|
||||||
"libc",
|
|
||||||
"pkg-config",
|
|
||||||
"vcpkg",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "linux-raw-sys"
|
name = "linux-raw-sys"
|
||||||
version = "0.12.1"
|
version = "0.12.1"
|
||||||
@@ -737,59 +653,6 @@ version = "1.21.4"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50"
|
checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "openssl"
|
|
||||||
version = "0.10.80"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "a45fa2aa886c42762255da344f0a0d313e254066c46aad76f300c3d3da62d967"
|
|
||||||
dependencies = [
|
|
||||||
"bitflags",
|
|
||||||
"cfg-if",
|
|
||||||
"foreign-types",
|
|
||||||
"libc",
|
|
||||||
"openssl-macros",
|
|
||||||
"openssl-sys",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "openssl-macros"
|
|
||||||
version = "0.1.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "openssl-probe"
|
|
||||||
version = "0.1.6"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "openssl-src"
|
|
||||||
version = "300.6.0+3.6.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "a8e8cbfd3a4a8c8f089147fd7aaa33cf8c7450c4d09f8f80698a0cf093abeff4"
|
|
||||||
dependencies = [
|
|
||||||
"cc",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "openssl-sys"
|
|
||||||
version = "0.9.116"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "f28a22dc7140cda5f096e5e7724a6962ca81a7f8bfd2979f9b18c11af56318c4"
|
|
||||||
dependencies = [
|
|
||||||
"cc",
|
|
||||||
"libc",
|
|
||||||
"openssl-src",
|
|
||||||
"pkg-config",
|
|
||||||
"vcpkg",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "percent-encoding"
|
name = "percent-encoding"
|
||||||
version = "2.3.2"
|
version = "2.3.2"
|
||||||
@@ -802,12 +665,6 @@ version = "0.2.17"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd"
|
checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "pkg-config"
|
|
||||||
version = "0.3.33"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "19f132c84eca552bf34cab8ec81f1c1dcc229b811638f9d283dceabe58c5569e"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "potential_utf"
|
name = "potential_utf"
|
||||||
version = "0.1.5"
|
version = "0.1.5"
|
||||||
@@ -1466,12 +1323,6 @@ version = "1.0.4"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be"
|
checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "vcpkg"
|
|
||||||
version = "0.2.15"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "version_check"
|
name = "version_check"
|
||||||
version = "0.9.5"
|
version = "0.9.5"
|
||||||
|
|||||||
17
Cargo.toml
17
Cargo.toml
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "dcr"
|
name = "dcr"
|
||||||
version = "0.7.2"
|
version = "0.7.3"
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
build = "build.rs"
|
build = "build.rs"
|
||||||
description = "DCR is a utility for managing C/C++ projects in a Cargo-like style."
|
description = "DCR is a utility for managing C/C++ projects in a Cargo-like style."
|
||||||
@@ -69,21 +69,6 @@ toml = "1.0.3"
|
|||||||
serde_json = "1"
|
serde_json = "1"
|
||||||
ctrlc = "3"
|
ctrlc = "3"
|
||||||
|
|
||||||
[features]
|
|
||||||
default = ["vendored"]
|
|
||||||
vendored = [
|
|
||||||
"git2/vendored-libgit2",
|
|
||||||
"git2/vendored-openssl",
|
|
||||||
"openssl/vendored",
|
|
||||||
]
|
|
||||||
|
|
||||||
[target.'cfg(not(windows))'.dependencies]
|
|
||||||
git2 = "0.20.4"
|
|
||||||
openssl = "0.10"
|
|
||||||
|
|
||||||
[target.'cfg(windows)'.dependencies]
|
|
||||||
git2 = "0.20.4"
|
|
||||||
|
|
||||||
[profile.release]
|
[profile.release]
|
||||||
opt-level = "z"
|
opt-level = "z"
|
||||||
lto = "thin"
|
lto = "thin"
|
||||||
|
|||||||
33
build.rs
33
build.rs
@@ -18,4 +18,37 @@
|
|||||||
fn main() {
|
fn main() {
|
||||||
let target = std::env::var("TARGET").unwrap_or_else(|_| "unknown-target".to_string());
|
let target = std::env::var("TARGET").unwrap_or_else(|_| "unknown-target".to_string());
|
||||||
println!("cargo:rustc-env=DCR_TARGET={target}");
|
println!("cargo:rustc-env=DCR_TARGET={target}");
|
||||||
|
|
||||||
|
// Let's try to retrieve the commit hash for the version
|
||||||
|
let commit = std::process::Command::new("git")
|
||||||
|
.args(["rev-parse", "--short", "HEAD"])
|
||||||
|
.output()
|
||||||
|
.ok()
|
||||||
|
.and_then(|o| {
|
||||||
|
if o.status.success() {
|
||||||
|
String::from_utf8(o.stdout)
|
||||||
|
.ok()
|
||||||
|
.map(|s| s.trim().to_string())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Check if there are any uncommitted changes in the repository
|
||||||
|
let is_dirty = std::process::Command::new("git")
|
||||||
|
.args(["status", "--porcelain"])
|
||||||
|
.output()
|
||||||
|
.ok()
|
||||||
|
.map(|o| o.status.success() && !o.stdout.is_empty())
|
||||||
|
.unwrap_or(false);
|
||||||
|
|
||||||
|
if let Some(commit_hash) = commit {
|
||||||
|
let dirty_suffix = if is_dirty { "-dirty" } else { "" };
|
||||||
|
println!(
|
||||||
|
"cargo:rustc-env=DCR_GIT_INFO= (git {}{})",
|
||||||
|
commit_hash, dirty_suffix
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
println!("cargo:rustc-env=DCR_GIT_INFO=");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
|
|
||||||
use crate::config::FILE_MAIN_C;
|
use crate::config::FILE_MAIN_C;
|
||||||
use crate::core::config::{Config, validate_package_name};
|
use crate::core::config::{Config, validate_package_name};
|
||||||
|
use crate::core::vcs::VcsKind;
|
||||||
use crate::utils::fs::check_dir;
|
use crate::utils::fs::check_dir;
|
||||||
use crate::utils::log::{error, warn};
|
use crate::utils::log::{error, warn};
|
||||||
use crate::utils::text::{BOLD_CYAN, BOLD_GREEN, colored, printc};
|
use crate::utils::text::{BOLD_CYAN, BOLD_GREEN, colored, printc};
|
||||||
@@ -27,7 +28,7 @@ use toml::Value;
|
|||||||
pub fn init(args: &[String]) -> i32 {
|
pub fn init(args: &[String]) -> i32 {
|
||||||
if args.first().is_some_and(|a| a == "--help") {
|
if args.first().is_some_and(|a| a == "--help") {
|
||||||
printc("USAGE:", BOLD_GREEN);
|
printc("USAGE:", BOLD_GREEN);
|
||||||
printc(" dcr init", BOLD_CYAN);
|
printc(" dcr init [--vcs <git|none>]", BOLD_CYAN);
|
||||||
println!();
|
println!();
|
||||||
printc("DESCRIPTION:", BOLD_GREEN);
|
printc("DESCRIPTION:", BOLD_GREEN);
|
||||||
println!(" Initializes the current directory as a DCR project.");
|
println!(" Initializes the current directory as a DCR project.");
|
||||||
@@ -35,7 +36,25 @@ pub fn init(args: &[String]) -> i32 {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if !args.is_empty() {
|
let mut vcs_str = None;
|
||||||
|
let mut clean_args = Vec::new();
|
||||||
|
let mut iter = args.iter();
|
||||||
|
while let Some(arg) = iter.next() {
|
||||||
|
if arg == "--vcs" {
|
||||||
|
if let Some(val) = iter.next() {
|
||||||
|
vcs_str = Some(val.clone());
|
||||||
|
} else {
|
||||||
|
error("--vcs requires a value");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
} else if let Some(stripped) = arg.strip_prefix("--vcs=") {
|
||||||
|
vcs_str = Some(stripped.to_string());
|
||||||
|
} else {
|
||||||
|
clean_args.push(arg.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !clean_args.is_empty() {
|
||||||
warn("Command does not support additional arguments");
|
warn("Command does not support additional arguments");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@@ -106,6 +125,40 @@ pub fn init(args: &[String]) -> i32 {
|
|||||||
colored("src/main.c", BOLD_CYAN)
|
colored("src/main.c", BOLD_CYAN)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// settings VCS
|
||||||
|
let mut vcs_kind = VcsKind::Git;
|
||||||
|
if let Some(ref vcs_val) = vcs_str {
|
||||||
|
match VcsKind::parse(vcs_val) {
|
||||||
|
Ok(kind) => vcs_kind = kind,
|
||||||
|
Err(e) => {
|
||||||
|
error(&e);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if let Ok(cwd_path) = std::env::current_dir()
|
||||||
|
&& crate::core::vcs::find_existing_vcs(&cwd_path).is_some()
|
||||||
|
{
|
||||||
|
vcs_kind = VcsKind::None;
|
||||||
|
}
|
||||||
|
|
||||||
|
if vcs_kind == VcsKind::Git {
|
||||||
|
if crate::utils::git::is_git_available() {
|
||||||
|
let project_path = std::path::Path::new(".");
|
||||||
|
if let Err(e) = crate::core::vcs::init_vcs(vcs_kind, project_path) {
|
||||||
|
warn(&format!("Failed to initialize git repository: {}", e));
|
||||||
|
} else {
|
||||||
|
println!(
|
||||||
|
" {} Initialized git repository",
|
||||||
|
colored("✔", BOLD_GREEN)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
warn(
|
||||||
|
"Git is not installed or not found in PATH. Skipping Git repository initialization.",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
println!(
|
println!(
|
||||||
"Project `{}` successfully created\n",
|
"Project `{}` successfully created\n",
|
||||||
colored(project_name.as_str(), BOLD_GREEN)
|
colored(project_name.as_str(), BOLD_GREEN)
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
|
|
||||||
use crate::config::FILE_MAIN_C;
|
use crate::config::FILE_MAIN_C;
|
||||||
use crate::core::config::{Config, validate_package_name};
|
use crate::core::config::{Config, validate_package_name};
|
||||||
|
use crate::core::vcs::VcsKind;
|
||||||
use crate::utils::fs::check_dir;
|
use crate::utils::fs::check_dir;
|
||||||
use crate::utils::log::{error, warn};
|
use crate::utils::log::{error, warn};
|
||||||
use crate::utils::text::{BOLD_CYAN, BOLD_GREEN, colored, printc};
|
use crate::utils::text::{BOLD_CYAN, BOLD_GREEN, colored, printc};
|
||||||
@@ -27,7 +28,7 @@ use toml::Value;
|
|||||||
pub fn new(args: &[String]) -> i32 {
|
pub fn new(args: &[String]) -> i32 {
|
||||||
if args.first().is_some_and(|a| a == "--help") {
|
if args.first().is_some_and(|a| a == "--help") {
|
||||||
printc("USAGE:", BOLD_GREEN);
|
printc("USAGE:", BOLD_GREEN);
|
||||||
printc(" dcr new <name>", BOLD_CYAN);
|
printc(" dcr new <name> [--vcs <git|none>]", BOLD_CYAN);
|
||||||
println!();
|
println!();
|
||||||
printc("DESCRIPTION:", BOLD_GREEN);
|
printc("DESCRIPTION:", BOLD_GREEN);
|
||||||
println!(" Creates a new C/C++ project with the given name.");
|
println!(" Creates a new C/C++ project with the given name.");
|
||||||
@@ -37,16 +38,34 @@ pub fn new(args: &[String]) -> i32 {
|
|||||||
|
|
||||||
let items = check_dir(None).unwrap_or_default();
|
let items = check_dir(None).unwrap_or_default();
|
||||||
|
|
||||||
if args.is_empty() {
|
let mut vcs_str = None;
|
||||||
|
let mut clean_args = Vec::new();
|
||||||
|
let mut iter = args.iter();
|
||||||
|
while let Some(arg) = iter.next() {
|
||||||
|
if arg == "--vcs" {
|
||||||
|
if let Some(val) = iter.next() {
|
||||||
|
vcs_str = Some(val.clone());
|
||||||
|
} else {
|
||||||
|
error("--vcs requires a value");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
} else if let Some(stripped) = arg.strip_prefix("--vcs=") {
|
||||||
|
vcs_str = Some(stripped.to_string());
|
||||||
|
} else {
|
||||||
|
clean_args.push(arg.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if clean_args.is_empty() {
|
||||||
error("Project name not specified");
|
error("Project name not specified");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
if args.len() > 1 {
|
if clean_args.len() > 1 {
|
||||||
warn("Command does not support additional arguments");
|
warn("Command does not support additional arguments");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
let project_name = &args[0];
|
let project_name = &clean_args[0];
|
||||||
println!(
|
println!(
|
||||||
"Creating a Project `{}`...",
|
"Creating a Project `{}`...",
|
||||||
colored(project_name, BOLD_CYAN)
|
colored(project_name, BOLD_CYAN)
|
||||||
@@ -127,6 +146,40 @@ pub fn new(args: &[String]) -> i32 {
|
|||||||
colored("src/main.c", BOLD_CYAN)
|
colored("src/main.c", BOLD_CYAN)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// settings VCS
|
||||||
|
let mut vcs_kind = VcsKind::Git;
|
||||||
|
if let Some(ref vcs_val) = vcs_str {
|
||||||
|
match VcsKind::parse(vcs_val) {
|
||||||
|
Ok(kind) => vcs_kind = kind,
|
||||||
|
Err(e) => {
|
||||||
|
error(&e);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if let Ok(cwd) = std::env::current_dir()
|
||||||
|
&& crate::core::vcs::find_existing_vcs(&cwd).is_some()
|
||||||
|
{
|
||||||
|
vcs_kind = VcsKind::None;
|
||||||
|
}
|
||||||
|
|
||||||
|
if vcs_kind == VcsKind::Git {
|
||||||
|
if crate::utils::git::is_git_available() {
|
||||||
|
let project_path = std::path::Path::new(project_name);
|
||||||
|
if let Err(e) = crate::core::vcs::init_vcs(vcs_kind, project_path) {
|
||||||
|
warn(&format!("Failed to initialize git repository: {}", e));
|
||||||
|
} else {
|
||||||
|
println!(
|
||||||
|
" {} Initialized git repository",
|
||||||
|
colored("✔", BOLD_GREEN)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
warn(
|
||||||
|
"Git is not installed or not found in PATH. Skipping Git repository initialization.",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
println!(
|
println!(
|
||||||
"Project `{}` successfully created\n",
|
"Project `{}` successfully created\n",
|
||||||
colored(project_name, BOLD_GREEN)
|
colored(project_name, BOLD_GREEN)
|
||||||
|
|||||||
@@ -29,43 +29,5 @@ pub fn fetch_git_dep(
|
|||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut builder = git2::build::RepoBuilder::new();
|
crate::utils::git::git_clone_and_checkout(url, target_dir, branch, tag, rev)
|
||||||
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(())
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,4 +20,5 @@ pub mod config;
|
|||||||
pub mod deps;
|
pub mod deps;
|
||||||
pub mod registry;
|
pub mod registry;
|
||||||
pub mod runner;
|
pub mod runner;
|
||||||
|
pub mod vcs;
|
||||||
pub mod workspace;
|
pub mod workspace;
|
||||||
|
|||||||
32
src/core/vcs/git.rs
Normal file
32
src/core/vcs/git.rs
Normal 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
61
src/core/vcs/mod.rs
Normal 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
|
||||||
|
}
|
||||||
@@ -44,7 +44,12 @@ fn main() {
|
|||||||
"clean" => cli::clean::clean(rest),
|
"clean" => cli::clean::clean(rest),
|
||||||
"gen" => cli::r#gen::r#gen(rest),
|
"gen" => cli::r#gen::r#gen(rest),
|
||||||
"--version" => {
|
"--version" => {
|
||||||
println!("dcr {} ({})", env!("CARGO_PKG_VERSION"), env!("DCR_TARGET"));
|
println!(
|
||||||
|
"dcr {}{} ({})",
|
||||||
|
env!("CARGO_PKG_VERSION"),
|
||||||
|
env!("DCR_GIT_INFO"),
|
||||||
|
env!("DCR_TARGET")
|
||||||
|
);
|
||||||
0
|
0
|
||||||
}
|
}
|
||||||
"--help" => cli::help::help(),
|
"--help" => cli::help::help(),
|
||||||
|
|||||||
112
src/utils/git.rs
Normal file
112
src/utils/git.rs
Normal file
@@ -0,0 +1,112 @@
|
|||||||
|
// 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::path::Path;
|
||||||
|
use std::process::Command;
|
||||||
|
|
||||||
|
// checking installed git on system
|
||||||
|
pub fn is_git_available() -> bool {
|
||||||
|
Command::new("git")
|
||||||
|
.arg("--version")
|
||||||
|
.output()
|
||||||
|
.map(|o| o.status.success())
|
||||||
|
.unwrap_or(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
// warning of git not in system
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn warn_if_git_missing() {
|
||||||
|
if !is_git_available() {
|
||||||
|
crate::utils::log::warn(
|
||||||
|
"Git is not installed or not found in PATH. Some features (like dependency cloning and VCS initialization) may fail.",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// init repo in folder
|
||||||
|
pub fn git_init(path: &Path) -> Result<(), String> {
|
||||||
|
if !is_git_available() {
|
||||||
|
return Err("git executable not found in PATH".to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
let status = Command::new("git")
|
||||||
|
.arg("init")
|
||||||
|
.current_dir(path)
|
||||||
|
.status()
|
||||||
|
.map_err(|e| format!("failed to execute git init: {}", e))?;
|
||||||
|
|
||||||
|
if !status.success() {
|
||||||
|
return Err("git init failed".to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clone the dependency and switch to the branch/tag/commit
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn git_clone_and_checkout(
|
||||||
|
url: &str,
|
||||||
|
target_dir: &Path,
|
||||||
|
branch: Option<&str>,
|
||||||
|
tag: Option<&str>,
|
||||||
|
rev: Option<&str>,
|
||||||
|
) -> Result<(), String> {
|
||||||
|
if !is_git_available() {
|
||||||
|
return Err("git executable not found in PATH".to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut args = vec!["clone"];
|
||||||
|
|
||||||
|
if let Some(b) = branch {
|
||||||
|
args.push("--branch");
|
||||||
|
args.push(b);
|
||||||
|
args.push("--single-branch");
|
||||||
|
} else if let Some(t) = tag {
|
||||||
|
args.push("--branch");
|
||||||
|
args.push(t);
|
||||||
|
args.push("--single-branch");
|
||||||
|
}
|
||||||
|
|
||||||
|
args.push(url);
|
||||||
|
|
||||||
|
let target_dir_str = target_dir.to_string_lossy().to_string();
|
||||||
|
args.push(&target_dir_str);
|
||||||
|
|
||||||
|
let status = Command::new("git")
|
||||||
|
.args(&args)
|
||||||
|
.status()
|
||||||
|
.map_err(|e| format!("failed to execute git clone: {}", e))?;
|
||||||
|
|
||||||
|
if !status.success() {
|
||||||
|
return Err(format!("git clone of {} failed", url));
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(r) = rev {
|
||||||
|
let checkout_status = Command::new("git")
|
||||||
|
.arg("checkout")
|
||||||
|
.arg(r)
|
||||||
|
.current_dir(target_dir)
|
||||||
|
.status()
|
||||||
|
.map_err(|e| format!("failed to execute git checkout: {}", e))?;
|
||||||
|
|
||||||
|
if !checkout_status.success() {
|
||||||
|
return Err(format!("git checkout to revision {} failed", r));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
@@ -17,5 +17,6 @@
|
|||||||
|
|
||||||
pub mod build;
|
pub mod build;
|
||||||
pub mod fs;
|
pub mod fs;
|
||||||
|
pub mod git;
|
||||||
pub mod log;
|
pub mod log;
|
||||||
pub mod text;
|
pub mod text;
|
||||||
|
|||||||
@@ -99,6 +99,60 @@ fn new_creates_project_layout() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn is_git_in_path() -> bool {
|
||||||
|
std::process::Command::new("git")
|
||||||
|
.arg("--version")
|
||||||
|
.output()
|
||||||
|
.map(|o| o.status.success())
|
||||||
|
.unwrap_or(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn new_vcs_options_work() {
|
||||||
|
// 1. Test --vcs none
|
||||||
|
let dir = unique_sandbox_dir("new_vcs_none");
|
||||||
|
let out = run_dcr(&["new", "hello_none", "--vcs", "none"], &dir);
|
||||||
|
assert!(out.status.success(), "dcr new --vcs none should succeed");
|
||||||
|
let project_dir = dir.join("hello_none");
|
||||||
|
assert!(project_dir.is_dir());
|
||||||
|
assert!(!project_dir.join(".git").exists());
|
||||||
|
assert!(!project_dir.join(".gitignore").exists());
|
||||||
|
|
||||||
|
// 2. Test --vcs git
|
||||||
|
if is_git_in_path() {
|
||||||
|
let dir = unique_sandbox_dir("new_vcs_git");
|
||||||
|
let out = run_dcr(&["new", "hello_git", "--vcs", "git"], &dir);
|
||||||
|
assert!(out.status.success(), "dcr new --vcs git should succeed");
|
||||||
|
let project_dir = dir.join("hello_git");
|
||||||
|
assert!(project_dir.is_dir());
|
||||||
|
assert!(project_dir.join(".git").is_dir());
|
||||||
|
assert!(project_dir.join(".gitignore").is_file());
|
||||||
|
let gitignore = std::fs::read_to_string(project_dir.join(".gitignore")).unwrap();
|
||||||
|
assert!(gitignore.contains("/target"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn init_vcs_options_work() {
|
||||||
|
// 1. Test --vcs none
|
||||||
|
let dir = unique_sandbox_dir("init_vcs_none");
|
||||||
|
let out = run_dcr(&["init", "--vcs", "none"], &dir);
|
||||||
|
assert!(out.status.success(), "dcr init --vcs none should succeed");
|
||||||
|
assert!(!dir.join(".git").exists());
|
||||||
|
assert!(!dir.join(".gitignore").exists());
|
||||||
|
|
||||||
|
// 2. Test --vcs git
|
||||||
|
if is_git_in_path() {
|
||||||
|
let dir = unique_sandbox_dir("init_vcs_git");
|
||||||
|
let out = run_dcr(&["init", "--vcs", "git"], &dir);
|
||||||
|
assert!(out.status.success(), "dcr init --vcs git should succeed");
|
||||||
|
assert!(dir.join(".git").is_dir());
|
||||||
|
assert!(dir.join(".gitignore").is_file());
|
||||||
|
let gitignore = std::fs::read_to_string(dir.join(".gitignore")).unwrap();
|
||||||
|
assert!(gitignore.contains("/target"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn init_and_clean_remove_target() {
|
fn init_and_clean_remove_target() {
|
||||||
let dir = unique_sandbox_dir("init");
|
let dir = unique_sandbox_dir("init");
|
||||||
|
|||||||
Reference in New Issue
Block a user