char/sorcery
static-files based git repo viewer
git clone https://git.t4t.associates/char/sorcery
8f07a0e
main
1mod forge; 2mod refresh; 3mod ui; 4 5use std:: io::{ self , IsTerminal }; 6use std:: path:: PathBuf ; 7 8use anyhow::{ Result , bail}; 9use clap::{ Parser , Subcommand }; 10 11use refresh:: Refresh ; 12 13# [ derive ( Parser )] 14# [ command ( name = "sorcery-ssh" )] 15struct Cli { 16# [ arg ( long , env = "SORCERY_REPOSITORIES" , value_name = "DIR" )] 17repositories : PathBuf , 18# [ arg ( long , env = "SORCERY_SOCKET" , value_name = "PATH" )] 19socket : Option < PathBuf >, 20# [ arg ( long , env = "SORCERY_REFRESH_TOKEN_FILE" , value_name = "PATH" )] 21refresh_token_file : Option < PathBuf >, 22# [ arg ( long , env = "SORCERY_CLONE_URL_BASE" , value_name = "URL" )] 23clone_url_base : Option < String >, 24# [ arg ( long , env = "SORCERY_INSTANCE_NAME" , value_name = "NAME" )] 25instance_name : Option < String >, 26# [ command ( subcommand )] 27command : Option < Command >, 28} 29 30# [ derive ( Subcommand )] 31enum Command { 32/// Print or set a repository's description 33Describe { 34repo : String , 35# [ arg ( 36value_name = "TEXT" , 37trailing_var_arg = true , 38allow_hyphen_values = true 39)] 40text : Vec < String >, 41}, 42} 43 44fn main () ->Result <()> { 45let cli =Cli :: parse (); 46let refresh =Refresh :: from_files ( cli. socket , cli. refresh_token_file ) ?; 47 48match cli. command { 49Some ( Command :: Describe { repo, text}) =>{ 50let repo = forge:: find ( & cli. repositories , & repo) ?; 51if text. is_empty () { 52if let Some ( description) = repo. description { 53println! ( "{description}" ); 54} 55} else { 56let text = text. join ( " " ); 57 forge:: set_description ( & repo, & text) ?; 58if let Some ( refresh) =& refresh 59 &&let Err ( error) = refresh. send ( & repo. user , & repo. name ) 60{ 61eprintln! ( "sorcery-ssh: description saved, but refresh failed: {error:#}" ); 62} 63println! ( "{}" , text. trim ()); 64} 65Ok (()) 66} 67None =>{ 68if !io:: stdin (). is_terminal () || !io:: stdout (). is_terminal () { 69bail! ( "interactive session needs a terminal; try `ssh -t`" ); 70} 71let title = cli 72. instance_name 73. unwrap_or_else ( || cli. repositories . display (). to_string ()); 74 ui:: run ( cli. repositories , title, cli. clone_url_base , refresh) 75} 76} 77} 78 79# [ cfg ( test )] 80mod tests{ 81use super :: * ; 82 83# [ test ] 84fn description_consumes_the_remaining_ssh_command () { 85let cli =Cli :: try_parse_from ([ 86"sorcery-ssh" , 87"--repositories" , 88"/tmp/repos" , 89"describe" , 90"alice/repo" , 91"a" , 92"tiny" , 93"repo" , 94]) 95. unwrap (); 96let Some ( Command :: Describe { repo, text}) = cli. command else { 97panic! ( "expected describe command" ); 98}; 99assert_eq! ( repo, "alice/repo" ); 100assert_eq! ( text, [ "a" , "tiny" , "repo" ]); 101} 102}