use std::path::Path;
use std::process::{Command, Stdio};
use crate::config::RViewCmd;
use crate::error::{RkitError, RkitResult};
pub fn view_repo(repo_path: &Path, commands: Option<&[RViewCmd]>) -> RkitResult<()> {
if !repo_path.exists() {
log::error!("Repository not found: {}", repo_path.display());
return Err(RkitError::RepoNotFoundError(repo_path.to_path_buf()));
}
let git_dir = repo_path.join(".git");
if !git_dir.exists() {
log::error!("Not a git repository: {}", repo_path.display());
return Err(RkitError::InvalidPathError(format!(
"{} is not a git repository",
repo_path.display()
)));
}
if repo_path.read_dir().is_err() {
log::error!("No permission to read directory: {}", repo_path.display());
return Err(RkitError::PermissionError(format!(
"No permission to read directory: {}",
repo_path.display()
)));
}
if let Some(cmds) = commands {
for cmd in cmds {
let command_str = cmd.command.replace("{REPO}", &repo_path.to_string_lossy());
let parts: Vec<&str> = command_str.split_whitespace().collect();
if parts.is_empty() {
log::warn!("Empty command for label: {}", cmd.label);
continue;
}
println!("=== {} ===", cmd.label);
log::debug!("Running command for {}: {}", cmd.label, command_str);
let mut child = Command::new(parts[0])
.args(&parts[1..])
.stdout(Stdio::inherit())
.stderr(Stdio::inherit())
.spawn()
.map_err(|e| RkitError::ShellCommandError {
command: cmd.command.clone(),
source: e,
})?;
let status = child.wait().map_err(|e| RkitError::ShellCommandError {
command: cmd.command.clone(),
source: e,
})?;
if !status.success() {
log::warn!("Command '{}' exited with status: {}", cmd.command, status);
}
println!(); }
} else {
let readme_path = repo_path.join("README.md");
if readme_path.exists() {
log::info!("Displaying README for {}", repo_path.display());
println!("=== README ===");
let content =
std::fs::read_to_string(&readme_path).map_err(|e| RkitError::FileReadError {
path: readme_path,
source: e,
})?;
println!("{}", content);
} else {
log::info!("Listing directory contents for {}", repo_path.display());
println!("=== Directory Listing ===");
let child = Command::new("ls")
.arg("-la")
.arg(repo_path)
.stdout(if cfg!(test) {
Stdio::piped()
} else {
Stdio::inherit()
})
.stderr(if cfg!(test) {
Stdio::piped()
} else {
Stdio::inherit()
})
.spawn()
.map_err(|e| RkitError::ShellCommandError {
command: format!("ls -la {}", repo_path.display()),
source: e,
})?;
let output = child
.wait_with_output()
.map_err(|e| RkitError::ShellCommandError {
command: format!("ls -la {}", repo_path.display()),
source: e,
})?;
if !cfg!(test) && output.status.success() {
print!("{}", String::from_utf8_lossy(&output.stdout));
}
}
}
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
use std::fs;
use tempfile::tempdir;
#[test]
fn test_view_repo_not_found() {
let dir = tempdir().unwrap();
let missing = dir.path().join("missing");
let res = view_repo(&missing, None);
assert!(matches!(res, Err(RkitError::RepoNotFoundError(_))));
}
#[test]
fn test_view_repo_not_git() {
let dir = tempdir().unwrap();
let not_git = dir.path().join("not_git");
fs::create_dir_all(¬_git).unwrap();
let res = view_repo(¬_git, None);
assert!(matches!(res, Err(RkitError::InvalidPathError(_))));
}
#[test]
fn test_view_repo_no_permission() {
let dir = tempdir().unwrap();
let repo = dir.path().join("repo");
fs::create_dir_all(&repo).unwrap();
fs::create_dir_all(repo.join(".git")).unwrap();
#[cfg(unix)]
{
use std::os::unix::fs::PermissionsExt;
let original_perms = fs::metadata(&repo).unwrap().permissions();
let mut perms = original_perms.clone();
perms.set_mode(0o000);
if fs::set_permissions(&repo, perms).is_ok() {
let res = view_repo(&repo, None);
let got_permission_error = matches!(res, Err(RkitError::PermissionError(_)));
fs::set_permissions(&repo, original_perms).unwrap();
if got_permission_error {
assert!(got_permission_error);
} else {
assert!(res.is_ok() || res.is_err());
}
} else {
let res = view_repo(&repo, None);
assert!(res.is_ok());
}
}
#[cfg(not(unix))]
{
fs::remove_dir_all(&repo).unwrap();
std::fs::File::create(&repo).unwrap();
fs::create_dir_all(dir.path().join("repo_git")).unwrap();
let res = view_repo(&repo, None);
assert!(res.is_err()); }
}
#[test]
fn test_view_repo_readme() {
let dir = tempdir().unwrap();
let repo = dir.path().join("repo");
fs::create_dir_all(repo.join(".git")).unwrap();
let readme = repo.join("README.md");
fs::write(&readme, "Hello").unwrap();
let res = view_repo(&repo, None);
assert!(res.is_ok());
}
#[test]
fn test_view_repo_no_readme() {
let dir = tempdir().unwrap();
let repo = dir.path().join("repo");
fs::create_dir_all(repo.join(".git")).unwrap();
let res = view_repo(&repo, None);
assert!(res.is_ok());
}
}