summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJustin Wernick <justin@worthe-it.co.za>2023-03-20 23:18:41 +0200
committerJustin Wernick <justin@worthe-it.co.za>2023-03-20 23:18:41 +0200
commit2b827a0ab06fb715290a0450a3fff56d3e6f4ee6 (patch)
treeb5e24df3fa573afd07b55a2330e88cabe2394e3f
parentae4b23d95dc8792231c1e8212978be8305ee1964 (diff)
Put git repos into a user-specific dir
-rw-r--r--Cargo.lock1
-rw-r--r--Cargo.toml1
-rw-r--r--src/git.rs20
-rw-r--r--src/lib.rs43
-rw-r--r--src/main.rs42
-rw-r--r--src/user.rs7
-rw-r--r--tests/cli.rs39
-rw-r--r--tests/server_shell.rs3
8 files changed, 101 insertions, 55 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 60f3880..8d62299 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -582,6 +582,7 @@ dependencies = [
"clap",
"get-port",
"git2",
+ "nix 0.26.2",
"nom",
"once_cell",
"rexpect",
diff --git a/Cargo.toml b/Cargo.toml
index 5771db2..b273c83 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -8,6 +8,7 @@ edition = "2021"
[dependencies]
clap = { version = "4.1.8", features = ["derive"] }
git2 = { version = "0.16.1", default-features = false, features = ["vendored-libgit2"] }
+nix = { version = "0.26.2", default-features = false, features = ["user"] }
nom = "7.1.3"
rexpect = "0.5.0"
rustyline = { version = "11.0.0", default-features = false }
diff --git a/src/git.rs b/src/git.rs
index b3c41e9..753f53a 100644
--- a/src/git.rs
+++ b/src/git.rs
@@ -1,22 +1,30 @@
-use crate::parser::{GitReceivePackArgs, GitUploadPackArgs};
-use crate::ShackleError;
-
+use crate::{
+ parser::{GitReceivePackArgs, GitUploadPackArgs},
+ user::get_username,
+ ShackleError,
+};
use git2::{Repository, RepositoryInitOptions};
use std::{path::PathBuf, process::Command};
-pub fn init(repo_name: &str) -> Result<(), ShackleError> {
+pub struct GitInitResult {
+ pub path: PathBuf,
+}
+
+pub fn init(repo_name: &str) -> Result<GitInitResult, ShackleError> {
+ let username = get_username().ok_or(ShackleError::UserReadError)?;
let mut path = PathBuf::from("git");
+ path.push(username);
path.push(repo_name);
path.set_extension("git");
Repository::init_opts(
- path,
+ &path,
&RepositoryInitOptions::new()
.bare(true)
.mkdir(true)
.no_reinit(true),
)?;
- Ok(())
+ Ok(GitInitResult { path })
}
pub fn upload_pack(upload_pack_args: &GitUploadPackArgs) -> Result<(), ShackleError> {
diff --git a/src/lib.rs b/src/lib.rs
new file mode 100644
index 0000000..b645918
--- /dev/null
+++ b/src/lib.rs
@@ -0,0 +1,43 @@
+pub mod git;
+pub mod parser;
+pub mod user;
+
+use parser::*;
+use rustyline::error::ReadlineError;
+use std::{io, ops::ControlFlow};
+use thiserror::Error;
+
+pub fn run_command(user_input: String) -> Result<ControlFlow<(), ()>, ShackleError> {
+ match user_input.parse::<ShackleCommand>() {
+ Err(parse_error) => {
+ println!("{}", parse_error);
+ }
+ Ok(ShackleCommand::Whitespace) => {}
+ Ok(ShackleCommand::Exit) => {
+ return Ok(ControlFlow::Break(()));
+ }
+ Ok(ShackleCommand::GitInit(GitInitArgs { repo_name })) => {
+ let init_result = git::init(&repo_name)?;
+ println!("Successfully created \"{}\"", init_result.path.display());
+ }
+ Ok(ShackleCommand::GitUploadPack(upload_pack_args)) => {
+ git::upload_pack(&upload_pack_args)?;
+ }
+ Ok(ShackleCommand::GitReceivePack(receive_pack_args)) => {
+ git::receive_pack(&receive_pack_args)?;
+ }
+ }
+ Ok(ControlFlow::Continue(()))
+}
+
+#[derive(Error, Debug)]
+pub enum ShackleError {
+ #[error(transparent)]
+ IoError(#[from] io::Error),
+ #[error(transparent)]
+ GitError(#[from] git2::Error),
+ #[error(transparent)]
+ ReadlineError(#[from] ReadlineError),
+ #[error("Could not get the current user name")]
+ UserReadError,
+}
diff --git a/src/main.rs b/src/main.rs
index 4b62aa1..4333866 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,11 +1,6 @@
-mod git;
-mod parser;
-
use clap::Parser;
-use parser::*;
use rustyline::{error::ReadlineError, DefaultEditor};
-use std::{io, ops::ControlFlow};
-use thiserror::Error;
+use shackle::{run_command, ShackleError};
/// Shackle Shell - A replacement for git-shell with repo management commands built in.
#[derive(Parser, Debug)]
@@ -30,29 +25,6 @@ fn main() -> Result<(), ShackleError> {
Ok(())
}
-fn run_command(user_input: String) -> Result<ControlFlow<(), ()>, ShackleError> {
- match user_input.parse::<ShackleCommand>() {
- Err(parse_error) => {
- println!("{}", parse_error);
- }
- Ok(ShackleCommand::Whitespace) => {}
- Ok(ShackleCommand::Exit) => {
- return Ok(ControlFlow::Break(()));
- }
- Ok(ShackleCommand::GitInit(GitInitArgs { repo_name })) => {
- git::init(&repo_name)?;
- println!("Successfully created \"{}.git\"", repo_name);
- }
- Ok(ShackleCommand::GitUploadPack(upload_pack_args)) => {
- git::upload_pack(&upload_pack_args)?;
- }
- Ok(ShackleCommand::GitReceivePack(receive_pack_args)) => {
- git::receive_pack(&receive_pack_args)?;
- }
- }
- Ok(ControlFlow::Continue(()))
-}
-
fn run_interactive_loop() -> Result<(), ShackleError> {
let mut rl = DefaultEditor::new()?;
loop {
@@ -86,15 +58,3 @@ fn run_interactive_loop() -> Result<(), ShackleError> {
}
Ok(())
}
-
-pub enum FlowControl {}
-
-#[derive(Error, Debug)]
-pub enum ShackleError {
- #[error(transparent)]
- IoError(#[from] io::Error),
- #[error(transparent)]
- GitError(#[from] git2::Error),
- #[error(transparent)]
- ReadlineError(#[from] ReadlineError),
-}
diff --git a/src/user.rs b/src/user.rs
new file mode 100644
index 0000000..72aea8d
--- /dev/null
+++ b/src/user.rs
@@ -0,0 +1,7 @@
+pub fn get_username() -> Option<String> {
+ let uid = nix::unistd::getuid();
+ nix::unistd::User::from_uid(uid)
+ .ok()
+ .flatten()
+ .map(|user| user.name)
+}
diff --git a/tests/cli.rs b/tests/cli.rs
index e6a59b3..a370154 100644
--- a/tests/cli.rs
+++ b/tests/cli.rs
@@ -1,6 +1,7 @@
use anyhow::Result;
use assert_cmd::{cargo::cargo_bin, Command};
use rexpect::session::{spawn_command, PtySession};
+use shackle::user::get_username;
use tempfile::TempDir;
struct TestContext {
@@ -89,14 +90,25 @@ fn reports_error_with_nonsense_input() -> Result<()> {
#[test]
fn can_init_a_new_git_repo() -> Result<()> {
let mut c = spawn_interactive_process()?;
- c.p.send_line("git-init my-new-repo")?;
- c.p.exp_string("Successfully created \"my-new-repo.git\"")?;
+ let username = get_username().unwrap();
+ let repo_name = "my-new-repo";
+ c.p.send_line(&format!("git-init {}", repo_name))?;
+ c.p.exp_string(&format!(
+ "Successfully created \"git/{}/{}.git\"",
+ username, repo_name
+ ))?;
expect_prompt(&mut c.p)?;
Command::new("git")
.arg("rev-list")
.arg("--all")
- .current_dir(c.workdir.as_ref().join("git").join("my-new-repo.git"))
+ .current_dir(
+ c.workdir
+ .as_ref()
+ .join("git")
+ .join(username)
+ .join("my-new-repo.git"),
+ )
.assert()
.success()
.stdout("");
@@ -105,17 +117,26 @@ fn can_init_a_new_git_repo() -> Result<()> {
#[test]
fn runs_a_single_command_and_exit_with_cli_flag() -> Result<()> {
- let mut c = run_batch_command("git-init another-new-repo")?;
- c.p.exp_string("Successfully created \"another-new-repo.git\"")?;
+ let username = get_username().unwrap();
+ let repo_name = "another-new-repo";
+ let mut c = run_batch_command(&format!("git-init {}", repo_name))?;
+ c.p.exp_string(&format!(
+ "Successfully created \"git/{}/{}.git\"",
+ username, repo_name
+ ))?;
c.p.exp_eof()?;
Ok(())
}
#[test]
fn allows_quotes_arguments() -> Result<()> {
+ let username = get_username().unwrap();
let mut c = spawn_interactive_process()?;
c.p.send_line("\"git-init\" 'another-new-repo'")?;
- c.p.exp_string("Successfully created \"another-new-repo.git\"")?;
+ c.p.exp_string(&format!(
+ "Successfully created \"git/{}/another-new-repo.git\"",
+ username
+ ))?;
Ok(())
}
@@ -137,8 +158,12 @@ fn errors_with_an_open_single_quote() -> Result<()> {
#[test]
fn allows_single_quotes_and_spaces_inside_double_quotes() -> Result<()> {
+ let username = get_username().unwrap();
let mut c = spawn_interactive_process()?;
c.p.send_line("git-init \"shukkie's new repo\"")?;
- c.p.exp_string("Successfully created \"shukkie's new repo.git\"")?;
+ c.p.exp_string(&format!(
+ "Successfully created \"git/{}/shukkie's new repo.git\"",
+ username
+ ))?;
Ok(())
}
diff --git a/tests/server_shell.rs b/tests/server_shell.rs
index c87fb53..72329d3 100644
--- a/tests/server_shell.rs
+++ b/tests/server_shell.rs
@@ -166,7 +166,7 @@ fn clone_git_repo(c: &TestContext, path: &str) -> Assert {
}
fn clone_git_repo_relative_path(c: &TestContext, repo_name: &str) -> Assert {
- clone_git_repo(c, &format!("/home/shukkie/git/{}.git", repo_name))
+ clone_git_repo(c, &format!("/home/shukkie/git/shukkie/{}.git", repo_name))
}
#[test]
@@ -215,6 +215,7 @@ fn git_push_works() -> Result<()> {
}
#[test]
+#[ignore = "Need to put the repo in the right dir first"]
fn git_clone_can_not_target_repo_outside_allowed_paths() -> Result<()> {
let c = spawn_ssh_server()?;
clone_git_repo(&c, "/home/shukkie/disallowed.git")