this repo has no description
5
fork

Configure Feed

Select the types of activity you want to include in your feed.

at 9492ba66b273325db34e393a50965c13cc44af4c 231 lines 7.3 kB view raw
1fn help() { 2 println!("Help: tangled-on-commit 3Listen for commits on a specified repository and execute a shell command. 4 5CLI Arguments: 6 `tangled-on-commit (-h | --help)` 7 Displays this message 8 9 `tangled-on-commit` 10 No specified handle, repo, or command. Falls back to config/env 11 12 `tangled-on-commit SHELL` 13 Uses config/env for handle and repo 14 15 `tangled-on-commit @HANDLE SHELL` 16 Uses config/env for repo 17 18 `tangled-on-commit REPO SHELL` 19 Uses config/env for handle 20 21 `tangled-on-commit @HANDLE/REPO SHELL` 22 `tangled-on-commit HANDLE REPO SHELL` 23 No config/env 24 25JSON: 26 Loads the file `tangled-on-commit.json` from cwd if it exists. 27 Reads keys \"handle\", \"repo_name\", and \"shell\". 28 Unknown keys are ignored and any key can be ommitted 29 JSON is used if the arguments aren't passed to the CLI 30 31Env: 32 Loads the environment variables `TANGLED_ON_COMMIT_HANDLE` and `TANGLED_ON_COMMIT_REPO_NAME` 33 Shell cannot be set by environment variables. 34 Env variables are used if relevant keys are ommitted an arguments aren't passed to the CLI. 35") 36} 37 38#[derive(Debug)] 39struct Config { 40 handle: String, 41 repo_name: String, 42 shell: String, 43} 44 45fn load_config() -> Result<Config, ()> { 46 // load config from cli args if present 47 // if omitted, fallback to a local `tangled-on-commit.json` file 48 // if key omitted or file not found, fall back to env 49 // if env omitted, error out and quit 50 // note: shell is not loaded from env (to avoid the user unknowingly executing scripts) 51 52 // if any args are `-h` || `--help` display help and quit 53 for arg in std::env::args() { 54 if arg == "-h" || arg == "--help" { 55 help(); 56 return Err(()); 57 } 58 } 59 60 // if 0 args are passed, skip 61 // if 1 arg is passed, its the shell command 62 // if 2 args are passed: 63 // if arg 1 starts in @ its a handle 64 // if it contains a / the contents after the slash is the reponame 65 // else its the reponame 66 // arg 2 is always the shell command 67 // if 3 args are passed its handle repo shell 68 // if more args are passed its an error 69 70 let mut handle: Option<String> = None; 71 let mut repo_name: Option<String> = None; 72 let mut shell: Option<String> = None; 73 match std::env::args().collect::<Vec<_>>().len() { 74 // 0 args (std env args includes this script) 75 1 => {} 76 2 => { 77 shell = Some( 78 std::env::args() 79 .last() 80 .expect("Invalid state: 2 `Some` std::env::args() but found no Some values"), 81 ) 82 } 83 3 => { 84 // load args and consume first 85 let mut args = std::env::args(); 86 args.next(); 87 88 if let Some(val) = args.next() { 89 if val.starts_with("@") { 90 if val.contains("/") { 91 let entries: Vec<_> = val.split("/").collect(); 92 if entries.len() != 2 { 93 return Err(()); 94 } 95 handle = Some(entries[0][1..].to_string()); 96 repo_name = Some(entries[1].to_string()); 97 } else { 98 handle = Some(val[1..].to_string()); 99 } 100 } else { 101 repo_name = Some(val) 102 }; 103 } 104 shell = Some( 105 args.next() 106 .expect("Invalid state: 3 `Some` std::env::args() but only found 2"), 107 ); 108 } 109 4 => { 110 // load args and consume first 111 let mut args = std::env::args(); 112 args.next(); 113 114 handle = Some( 115 args.next() 116 .expect("Invalid state: 4 `Some` std::env::args() but only found 1"), 117 ); 118 repo_name = Some( 119 args.next() 120 .expect("Invalid state: 4 `Some` std::env::args() but only found 2"), 121 ); 122 shell = Some( 123 args.next() 124 .expect("Invalid state: 4 `Some` std::env::args() but only found 3"), 125 ); 126 } 127 _ => { 128 // err 129 } 130 } 131 132 if let Some(ref handle) = handle 133 && let Some(ref repo_name) = repo_name 134 && let Some(ref shell) = shell 135 { 136 return Ok(Config { 137 handle: handle.to_string(), 138 repo_name: repo_name.to_string(), 139 shell: shell.to_string(), 140 }); 141 } 142 143 // now load config 144 if let Ok(file) = std::fs::read_to_string("./tangled-on-commit.json") { 145 if let Ok(parsed) = json::parse(&file) { 146 if handle.is_none() 147 && let Some(json_handle) = parsed["handle"].as_str() 148 { 149 handle = Some(String::from(json_handle)) 150 } 151 if repo_name.is_none() 152 && let Some(json_repo_name) = parsed["repo_name"].as_str() 153 { 154 repo_name = Some(String::from(json_repo_name)) 155 } 156 if shell.is_none() 157 && let Some(json_shell) = parsed["shell"].as_str() 158 { 159 shell = Some(String::from(json_shell)) 160 } 161 } 162 } 163 164 if let Some(ref handle) = handle 165 && let Some(ref repo_name) = repo_name 166 && let Some(ref shell) = shell 167 { 168 return Ok(Config { 169 handle: handle.to_string(), 170 repo_name: repo_name.to_string(), 171 shell: shell.to_string(), 172 }); 173 } 174 175 // now load from env 176 if handle.is_none() 177 && let Ok(env_handle) = std::env::var("TANGLED_ON_COMMIT_HANDLE") 178 { 179 handle = Some(String::from(env_handle)) 180 } 181 if repo_name.is_none() 182 && let Ok(env_repo_name) = std::env::var("TANGLED_ON_COMMIT_REPO_NAME") 183 { 184 repo_name = Some(String::from(env_repo_name)) 185 } 186 187 if let Some(ref handle) = handle 188 && let Some(ref repo_name) = repo_name 189 && let Some(ref shell) = shell 190 { 191 return Ok(Config { 192 handle: handle.to_string(), 193 repo_name: repo_name.to_string(), 194 shell: shell.to_string(), 195 }); 196 } 197 198 // couldnt resolve every value 199 // print an error and quit 200 println!("Unable to find a value for every setting. Missing values for:"); 201 if handle.is_none() {println!("- handle");} 202 if repo_name.is_none() {println!("- repo_name");} 203 if shell.is_none() {println!("- shell");} 204 println!("\nRun `tangled-on-commit --help` to see the help message"); 205 return Err(()); 206} 207 208fn main() -> Result<(), ()> { 209 // load configuration 210 let config = match load_config() { 211 Ok(res) => res, 212 Err(_) => { 213 // q 214 return Err(()); 215 } 216 }; 217 println!("{:#?}", config); 218 219 // resolve handle to did 220 // resolve did+repoName to knotserver 221 222 // connect to /events on knotserver 223 224 // on event: 225 // parse json 226 // validate meets expected schema (allow unknown vals) 227 // filter by did and reponame 228 // exec shell command in user shell (/bin/sh as fallback) 229 230 return Ok(()); 231}