Something went wrong. Try again.
Listen to git commits for a specific repo and run a shell command
Something went wrong. Try again.
6.9 kB · 215 lines
Rust
at master
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216fn help() { println!( "Help: tangled-on-commitListen for commits on a specified repository and execute a shell command.
CLI Arguments: `tangled-on-commit (-h | --help)` Displays this message
`tangled-on-commit` No specified handle, repo, or command. Falls back to config/env
`tangled-on-commit SHELL` Uses config/env for handle and repo
`tangled-on-commit @HANDLE SHELL` Uses config/env for repo
`tangled-on-commit REPO SHELL` Uses config/env for handle
`tangled-on-commit @HANDLE/REPO SHELL` `tangled-on-commit HANDLE REPO SHELL` No config/env
JSON: Loads the file `tangled-on-commit.json` from cwd if it exists. Reads keys \"handle\", \"repo_name\", and \"shell\". Unknown keys are ignored and any key can be ommitted JSON is used if the arguments aren't passed to the CLI
Env: Loads the environment variables `TANGLED_ON_COMMIT_HANDLE` and `TANGLED_ON_COMMIT_REPO_NAME` Shell cannot be set by environment variables. Env variables are used if relevant keys are ommitted an arguments aren't passed to the CLI." )}
#[derive(Debug)]pub struct Config { pub handle: String, pub repo_name: String, pub shell: String,}
pub fn load_config() -> Result<Config, ()> { // load config from cli args if present // if omitted, fallback to a local `tangled-on-commit.json` file // if key omitted or file not found, fall back to env // if env omitted, error out and quit // note: shell is not loaded from env (to avoid the user unknowingly executing scripts)
// if any args are `-h` || `--help` display help and quit for arg in std::env::args() { if arg == "-h" || arg == "--help" { help(); return Err(()); } }
// if 0 args are passed, skip // if 1 arg is passed, its the shell command // if 2 args are passed: // if arg 1 starts in @ its a handle // if it contains a / the contents after the slash is the reponame // else its the reponame // arg 2 is always the shell command // if 3 args are passed its handle repo shell // if more args are passed its an error
let mut handle: Option<String> = None; let mut repo_name: Option<String> = None; let mut shell: Option<String> = None; match std::env::args().collect::<Vec<_>>().len() { // 0 args (std env args includes this script) 1 => {} 2 => { shell = Some( std::env::args() .last() .expect("Invalid state: 2 `Some` std::env::args() but found no Some values"), ) } 3 => { // load args and consume first let mut args = std::env::args(); args.next();
if let Some(val) = args.next() { if val.starts_with("@") { if val.contains("/") { let entries: Vec<_> = val.split("/").collect(); if entries.len() != 2 { println!("Invalid argument: `{}` is malformed", val); return Err(()); } handle = Some(entries[0][1..].to_string()); repo_name = Some(entries[1].to_string()); } else { handle = Some(val[1..].to_string()); } } else { repo_name = Some(val) }; } shell = Some( args.next() .expect("Invalid state: 3 `Some` std::env::args() but only found 2"), ); } 4 => { // load args and consume first let mut args = std::env::args(); args.next();
handle = Some( args.next() .expect("Invalid state: 4 `Some` std::env::args() but only found 1"), ); repo_name = Some( args.next() .expect("Invalid state: 4 `Some` std::env::args() but only found 2"), ); shell = Some( args.next() .expect("Invalid state: 4 `Some` std::env::args() but only found 3"), ); } _ => { // err } }
if let Some(ref handle) = handle && let Some(ref repo_name) = repo_name && let Some(ref shell) = shell { return Ok(Config { handle: handle.to_string(), repo_name: repo_name.to_string(), shell: shell.to_string(), }); }
// now load config if let Ok(file) = std::fs::read_to_string("./tangled-on-commit.json") { if let Ok(parsed) = json::parse(&file) { if handle.is_none() && let Some(json_handle) = parsed["handle"].as_str() { handle = Some(String::from(json_handle)) } if repo_name.is_none() && let Some(json_repo_name) = parsed["repo_name"].as_str() { repo_name = Some(String::from(json_repo_name)) } if shell.is_none() && let Some(json_shell) = parsed["shell"].as_str() { shell = Some(String::from(json_shell)) } } }
if let Some(ref handle) = handle && let Some(ref repo_name) = repo_name && let Some(ref shell) = shell { return Ok(Config { handle: handle.to_string(), repo_name: repo_name.to_string(), shell: shell.to_string(), }); }
// now load from env if handle.is_none() && let Ok(env_handle) = std::env::var("TANGLED_ON_COMMIT_HANDLE") { handle = Some(String::from(env_handle)) } if repo_name.is_none() && let Ok(env_repo_name) = std::env::var("TANGLED_ON_COMMIT_REPO_NAME") { repo_name = Some(String::from(env_repo_name)) }
if let Some(ref handle) = handle && let Some(ref repo_name) = repo_name && let Some(ref shell) = shell { return Ok(Config { handle: handle.to_string(), repo_name: repo_name.to_string(), shell: shell.to_string(), }); }
// couldnt resolve every value // print an error and quit println!("Unable to find a value for every setting. Missing values for:"); if handle.is_none() { println!("- handle"); } if repo_name.is_none() { println!("- repo_name"); } if shell.is_none() { println!("- shell"); } println!("\nRun `tangled-on-commit --help` to see the help message"); return Err(());}