0.0.3-alpha.3

This commit is contained in:
2026-09-29 11:39:02 +02:00
parent 88a63b06cc
commit c3a825657d
14 changed files with 1209 additions and 29 deletions

View File

@@ -1,5 +1,5 @@
// file: crates/knowledge-git-lib/src/backend.rs
// version: 3
// version: 4
//! Physical source configuration, generated-state layout and controlled Git process runner.
@@ -51,6 +51,16 @@ impl crate::GitBackendConfig {
pub fn snapshots_path(&self) -> std::path::PathBuf {
return self.state_root.join("snapshots");
}
/// Return the directory reserved for temporary isolated write worktrees.
pub fn write_worktrees_path(&self) -> std::path::PathBuf {
return self.state_root.join("write-worktrees");
}
/// Return the controlled empty global Git configuration path.
pub fn empty_global_config_path(&self) -> std::path::PathBuf {
return self.state_root.join("empty-global.gitconfig");
}
}
/// Coarse physical source kind used by the backend.
@@ -155,7 +165,9 @@ impl crate::GitMirror {
#[derive(Clone, Debug, Eq, PartialEq)]
struct GitCommandSpec {
arguments: Vec<std::ffi::OsString>,
environment: Vec<(std::ffi::OsString, std::ffi::OsString)>,
executable: std::path::PathBuf,
global_config_path: std::path::PathBuf,
hooks_path: std::path::PathBuf,
operation: crate::GitOperation,
}
@@ -183,9 +195,20 @@ impl GitCommandRunner for SystemGitRunner {
command.env_remove("GIT_INDEX_FILE");
command.env_remove("GIT_OBJECT_DIRECTORY");
command.env_remove("GIT_WORK_TREE");
command.env_remove("GIT_AUTHOR_NAME");
command.env_remove("GIT_AUTHOR_EMAIL");
command.env_remove("GIT_COMMITTER_NAME");
command.env_remove("GIT_COMMITTER_EMAIL");
command.env_remove("GIT_CONFIG_GLOBAL");
command.env_remove("GIT_CONFIG_NOSYSTEM");
command.env("GIT_CONFIG_GLOBAL", &specification.global_config_path);
command.env("GIT_CONFIG_NOSYSTEM", "1");
command.env("GIT_CONFIG_COUNT", "1");
command.env("GIT_CONFIG_KEY_0", "core.hooksPath");
command.env("GIT_CONFIG_VALUE_0", &specification.hooks_path);
for (name, value) in &specification.environment {
command.env(name, value);
}
let output_result = command.output();
let output = match output_result {
Ok(value) => value,
@@ -246,7 +269,7 @@ impl crate::GitBackend {
source_id: &knowledge_domain_lib::SourceId,
revision: &knowledge_git_api::GitRevision,
) -> Result<std::path::PathBuf, crate::GitBackendError> {
if !is_safe_revision(revision.as_str()) {
if !crate::is_safe_revision(revision.as_str()) {
return Err(crate::GitBackendError::InvalidRevision);
}
let source_key = crate::GitSourceKey::from_source_id(source_id);
@@ -301,7 +324,7 @@ impl crate::GitBackend {
}
}
fn configured_source(&self, source_id: &knowledge_domain_lib::SourceId) -> Result<&crate::GitSourceConfig, crate::GitBackendError> {
pub(crate) fn configured_source(&self, source_id: &knowledge_domain_lib::SourceId) -> Result<&crate::GitSourceConfig, crate::GitBackendError> {
for source in &self.sources {
if source.source_id() == source_id {
return Ok(source);
@@ -310,16 +333,44 @@ impl crate::GitBackend {
return Err(crate::GitBackendError::SourceNotConfigured);
}
fn prepare_state_directories(&self) -> Result<(), crate::GitBackendError> {
for path in [self.config.hooks_path(), self.config.repositories_path(), self.config.snapshots_path()] {
pub(crate) fn prepare_state_directories(&self) -> Result<(), crate::GitBackendError> {
for path in [self.config.hooks_path(), self.config.repositories_path(), self.config.snapshots_path(), self.config.write_worktrees_path()] {
let create_result = std::fs::create_dir_all(path);
if create_result.is_err() {
return Err(crate::GitBackendError::StatePreparationFailed);
}
}
let config_path = self.config.empty_global_config_path();
if !config_path.exists() {
let write_result = std::fs::write(config_path, b"");
if write_result.is_err() {
return Err(crate::GitBackendError::StatePreparationFailed);
}
}
return Ok(());
}
pub(crate) fn run_controlled_git(
&self,
operation: crate::GitOperation,
arguments: Vec<std::ffi::OsString>,
environment: Vec<(std::ffi::OsString, std::ffi::OsString)>,
) -> Result<Vec<u8>, crate::GitBackendError> {
let specification = GitCommandSpec {
arguments,
environment,
executable: self.config.git_executable().to_path_buf(),
global_config_path: self.config.empty_global_config_path(),
hooks_path: self.config.hooks_path(),
operation,
};
let result = self.runner.run(&specification);
match result {
Ok(output) => return Ok(output.stdout),
Err(error) => return Err(error),
}
}
fn clone_mirror(&self, source: &crate::GitSourceConfig, repository_path: &std::path::Path) -> Result<(), crate::GitBackendError> {
let mut arguments = vec![std::ffi::OsString::from("clone"), std::ffi::OsString::from("--mirror")];
if source.source_kind == crate::GitSourceKind::Local {
@@ -330,7 +381,9 @@ impl crate::GitBackend {
arguments.push(repository_path.as_os_str().to_os_string());
let specification = GitCommandSpec {
arguments,
environment: Vec::new(),
executable: self.config.git_executable().to_path_buf(),
global_config_path: self.config.empty_global_config_path(),
hooks_path: self.config.hooks_path(),
operation: crate::GitOperation::CloneMirror,
};
@@ -349,7 +402,9 @@ impl crate::GitBackend {
std::ffi::OsString::from("rev-parse"),
std::ffi::OsString::from("--is-bare-repository"),
],
environment: Vec::new(),
executable: self.config.git_executable().to_path_buf(),
global_config_path: self.config.empty_global_config_path(),
hooks_path: self.config.hooks_path(),
operation: crate::GitOperation::InspectMirror,
};
@@ -390,7 +445,9 @@ impl crate::GitBackend {
std::ffi::OsString::from("update"),
std::ffi::OsString::from("--prune"),
],
environment: Vec::new(),
executable: self.config.git_executable().to_path_buf(),
global_config_path: self.config.empty_global_config_path(),
hooks_path: self.config.hooks_path(),
operation: crate::GitOperation::RefreshMirror,
};
@@ -427,7 +484,9 @@ impl crate::GitBackend {
std::ffi::OsString::from("--end-of-options"),
std::ffi::OsString::from(revision_expression),
],
environment: Vec::new(),
executable: self.config.git_executable().to_path_buf(),
global_config_path: self.config.empty_global_config_path(),
hooks_path: self.config.hooks_path(),
operation: crate::GitOperation::ResolveRevision,
};
@@ -443,7 +502,7 @@ impl crate::GitBackend {
return Err(crate::GitBackendError::UnexpectedGitOutput { operation: crate::GitOperation::ResolveRevision });
},
};
if !is_safe_revision(stdout) {
if !crate::is_safe_revision(stdout) {
return Err(crate::GitBackendError::UnexpectedGitOutput { operation: crate::GitOperation::ResolveRevision });
}
return Ok(knowledge_git_api::GitRevision::new(stdout));
@@ -459,7 +518,7 @@ impl crate::GitBackend {
Ok(_) => (),
Err(error) => return Err(error),
}
if !is_safe_revision(revision.as_str()) {
if !crate::is_safe_revision(revision.as_str()) {
return Err(crate::GitBackendError::InvalidRevision);
}
let mirror_result = self.inspect_mirror(source_id);
@@ -499,7 +558,9 @@ impl crate::GitBackend {
snapshot_path.as_os_str().to_os_string(),
std::ffi::OsString::from(revision.as_str()),
],
environment: Vec::new(),
executable: self.config.git_executable().to_path_buf(),
global_config_path: self.config.empty_global_config_path(),
hooks_path: self.config.hooks_path(),
operation: crate::GitOperation::CreateSnapshot,
};
@@ -527,7 +588,9 @@ impl crate::GitBackend {
std::ffi::OsString::from("--verify"),
std::ffi::OsString::from("HEAD"),
],
environment: Vec::new(),
executable: self.config.git_executable().to_path_buf(),
global_config_path: self.config.empty_global_config_path(),
hooks_path: self.config.hooks_path(),
operation: crate::GitOperation::InspectSnapshot,
};
@@ -552,7 +615,9 @@ impl crate::GitBackend {
std::ffi::OsString::from("--porcelain=v1"),
std::ffi::OsString::from("--untracked-files=all"),
],
environment: Vec::new(),
executable: self.config.git_executable().to_path_buf(),
global_config_path: self.config.empty_global_config_path(),
hooks_path: self.config.hooks_path(),
operation: crate::GitOperation::InspectSnapshot,
};
@@ -592,7 +657,7 @@ impl knowledge_git_api::GitRepository for crate::GitBackend {
}
}
fn is_safe_revision(value: &str) -> bool {
pub(crate) fn is_safe_revision(value: &str) -> bool {
if value.is_empty() {
return false;
}