main.rs 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683
  1. // extern crate clap;
  2. use clap::{Command, command, Arg, value_parser, ArgAction, ValueEnum, builder::PossibleValue};
  3. use clap_complete::{generate, Generator, Shell};
  4. use std::env;
  5. use std::io;
  6. mod lib;
  7. #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
  8. enum HumanBool {
  9. Yes,
  10. No
  11. }
  12. impl ValueEnum for HumanBool {
  13. fn value_variants<'a>() -> &'a [Self] {
  14. &[HumanBool::Yes, HumanBool::No]
  15. }
  16. fn to_possible_value<'a>(&self) -> Option<PossibleValue> {
  17. Some(match self {
  18. HumanBool::Yes => PossibleValue::new("YES"),
  19. HumanBool::No => PossibleValue::new("NO")
  20. })
  21. }
  22. }
  23. impl std::fmt::Display for HumanBool {
  24. fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
  25. self.to_possible_value()
  26. .expect("Values cannot be skipped")
  27. .get_name()
  28. .fmt(f)
  29. }
  30. }
  31. impl std::str::FromStr for HumanBool {
  32. type Err = String;
  33. fn from_str(s: &str) -> Result<Self, Self::Err> {
  34. for variant in Self::value_variants() {
  35. if variant.to_possible_value().unwrap().matches(s, false) {
  36. return Ok(*variant)
  37. }
  38. }
  39. Err(format!("Invalid Variant: {}", s))
  40. }
  41. }
  42. use crate::lib::{
  43. config::{
  44. find_config_file,
  45. read_configuration_file,
  46. write_configuration_file,
  47. Config
  48. },
  49. repository,
  50. action,
  51. group,
  52. repotype,
  53. run
  54. };
  55. fn build_cli() -> Command {
  56. command!()
  57. .propagate_version(true)
  58. .subcommand_required(true)
  59. .author("Samuel W. Flint <swflint@flintfam.org>")
  60. .about("Synchronize directories flexibly")
  61. .arg(Arg::new("config")
  62. .short('c')
  63. .long("config")
  64. .value_name("FILE")
  65. .help("Set a custom configuration file"))
  66. .subcommand(Command::new("run")
  67. .aliases(["sync", "rr"])
  68. .about("Run synchronization or command for repositories and groups.")
  69. .arg(Arg::new("repo")
  70. .action(ArgAction::Append)
  71. .value_name("REPO_OR_GROUP")
  72. .help("Name or names of repositories/groups to sync"))
  73. .arg(Arg::new("command")
  74. .short('C')
  75. .long("command")
  76. .value_name("COMMAND")
  77. .help("Run named COMMAND in each specified repository")))
  78. .subcommand(Command::new("repository")
  79. .about("Create and manage repositories")
  80. .visible_aliases(["repo", "r"])
  81. .subcommand_required(true)
  82. .subcommand(Command::new("list")
  83. .about("List repositories"))
  84. .subcommand(Command::new("register")
  85. .about("Register the current directory as a repository")
  86. .arg(Arg::new("type")
  87. .required(true)
  88. .value_name("TYPE")
  89. .help("Type of repository"))
  90. .arg(Arg::new("repo")
  91. .long("name")
  92. .short('n')
  93. .value_name("REPO")
  94. .help("Name of repository"))
  95. .arg(Arg::new("options")
  96. .action(ArgAction::Append)
  97. .value_name("OPTION=VALUE")
  98. .help("Type-specific options, in option=value form")))
  99. .subcommand(Command::new("config")
  100. .about("Configure repository")
  101. .arg(Arg::new("repo")
  102. .value_name("REPO")
  103. .required(true)
  104. .help("Name of repository to configure"))
  105. .arg(Arg::new("autocreate")
  106. .short('a')
  107. .long("autocreate")
  108. .value_name("YES/NO")
  109. .help("Set autocreation")
  110. .value_parser(value_parser!(HumanBool)))
  111. .arg(Arg::new("disable")
  112. .short('D')
  113. .long("disable")
  114. .value_name("YES/NO")
  115. .help("Disable repository")
  116. .value_parser(value_parser!(HumanBool)))
  117. .arg(Arg::new("options")
  118. .action(ArgAction::Append)
  119. .value_name("OPTION=VALUE")
  120. .help("Type-specific options, in option=value form")))
  121. .subcommand(Command::new("remove")
  122. .visible_aliases(["rm"])
  123. .about("Remove a repository")
  124. .arg(Arg::new("repo")
  125. .help("Name of repository")
  126. .value_name("REPO")
  127. .required(true)))
  128. .subcommand(Command::new("show")
  129. .visible_aliases(["describe"])
  130. .about("Show information about a repository")
  131. .arg(Arg::new("repo")
  132. .help("Name of repository")
  133. .value_name("REPO")
  134. .required(true))))
  135. .subcommand(Command::new("group")
  136. .about("Create and manage groups of repositories")
  137. .subcommand_required(true)
  138. .subcommand(Command::new("create")
  139. .about("Create a group")
  140. .arg(Arg::new("group")
  141. .help("Name of group")
  142. .required(true)
  143. .value_name("GROUP")))
  144. .subcommand(Command::new("delete")
  145. .visible_aliases(["drop"])
  146. .about("Delete a group.")
  147. .arg(Arg::new("group")
  148. .help("Name of group")
  149. .required(true)
  150. .value_name("GROUP")))
  151. .subcommand(Command::new("add")
  152. .about("Add a repo to a group")
  153. .arg(Arg::new("group")
  154. .help("Name of group")
  155. .required(true)
  156. .value_name("GROUP"))
  157. .arg(Arg::new("repo")
  158. .value_name("NAME")
  159. .required(true)
  160. .help("Name of repository"))
  161. )
  162. .subcommand(Command::new("act")
  163. .about("Add an action to a group")
  164. .arg(Arg::new("group")
  165. .help("Name of group")
  166. .required(true)
  167. .value_name("GROUP"))
  168. .arg(Arg::new("action")
  169. .help("Name of action")
  170. .required(true)
  171. .value_name("ACTION")))
  172. .subcommand(Command::new("remove")
  173. .about("Remove a repo from a group")
  174. .arg(Arg::new("group")
  175. .help("Name of group")
  176. .required(true)
  177. .value_name("GROUP"))
  178. .arg(Arg::new("action")
  179. .help("Name of action")
  180. .required(true)
  181. .value_name("ACTION")))
  182. .subcommand(Command::new("show")
  183. .about("Show information about a group")
  184. .arg(Arg::new("group")
  185. .help("Name of group")
  186. .required(true)
  187. .value_name("GROUP")))
  188. .subcommand(Command::new("list")
  189. .about("List known groups")))
  190. .subcommand(Command::new("type")
  191. .about("Create and manage repository types")
  192. .subcommand_required(true)
  193. .subcommand(Command::new("create")
  194. .about("Create a new repository type")
  195. .arg(Arg::new("type")
  196. .help("Name of type")
  197. .required(true)
  198. .value_name("TYPE"))
  199. .arg(Arg::new("description")
  200. .short('d')
  201. .long("description")
  202. .help("Description of repository type")
  203. .value_name("DESCRIPTION"))
  204. .arg(Arg::new("create")
  205. .short('c')
  206. .long("create")
  207. .help("Creation command")
  208. .value_name("COMMAND"))
  209. .arg(Arg::new("inward")
  210. .short('i')
  211. .long("inward")
  212. .help("Inward sync command")
  213. .value_name("COMMAND"))
  214. .arg(Arg::new("outward")
  215. .short('o')
  216. .long("outward")
  217. .help("Outward sync command")
  218. .value_name("COMMAND"))
  219. .arg(Arg::new("status")
  220. .short('s')
  221. .long("status")
  222. .help("Status command")
  223. .value_name("COMMAND"))
  224. .arg(Arg::new("pre_inward")
  225. .long("pre-inward")
  226. .help("Pre-inward command")
  227. .value_name("COMMAND"))
  228. .arg(Arg::new("post_inward")
  229. .long("post-inward")
  230. .help("Post-inward command")
  231. .value_name("COMMAND"))
  232. .arg(Arg::new("post_outward")
  233. .long("post-outward")
  234. .help("Post-outward command")
  235. .value_name("COMMAND"))
  236. )
  237. .subcommand(Command::new("config")
  238. .about("Configure a repository type")
  239. .arg(Arg::new("type")
  240. .help("Name of type")
  241. .required(true)
  242. .value_name("TYPE"))
  243. .arg(Arg::new("description")
  244. .short('d')
  245. .long("description")
  246. .help("Description of repository type")
  247. .value_name("DESCRIPTION"))
  248. .arg(Arg::new("create")
  249. .short('c')
  250. .long("create")
  251. .help("Creation command")
  252. .value_name("COMMAND"))
  253. .arg(Arg::new("inward")
  254. .short('i')
  255. .long("inward")
  256. .help("Inward sync command")
  257. .value_name("COMMAND"))
  258. .arg(Arg::new("outward")
  259. .short('o')
  260. .long("outward")
  261. .help("Outward sync command")
  262. .value_name("COMMAND"))
  263. .arg(Arg::new("status")
  264. .short('s')
  265. .long("status")
  266. .help("Status command")
  267. .value_name("COMMAND"))
  268. .arg(Arg::new("pre_inward")
  269. .long("pre-inward")
  270. .help("Pre-inward command")
  271. .value_name("COMMAND"))
  272. .arg(Arg::new("post_inward")
  273. .long("post-inward")
  274. .help("Post-inward command")
  275. .value_name("COMMAND"))
  276. .arg(Arg::new("post_outward")
  277. .long("post-outward")
  278. .help("Post-outward command")
  279. .value_name("COMMAND")))
  280. .subcommand(Command::new("command")
  281. .about("Manage commands in a repository type")
  282. .subcommand_required(true)
  283. .subcommand(Command::new("add")
  284. .about("Add a command to a repository type")
  285. .arg(Arg::new("type")
  286. .help("Name of type")
  287. .required(true)
  288. .value_name("TYPE"))
  289. .arg(Arg::new("name")
  290. .help("Name of command")
  291. .required(true)
  292. .value_name("NAME"))
  293. .arg(Arg::new("command")
  294. .help("Command")
  295. .required(true)
  296. .value_name("COMMAND")))
  297. .subcommand(Command::new("change")
  298. .about("Change a command in a repository type")
  299. .arg(Arg::new("type")
  300. .help("Name of type")
  301. .required(true)
  302. .value_name("TYPE"))
  303. .arg(Arg::new("name")
  304. .help("Name of command")
  305. .required(true)
  306. .value_name("NAME"))
  307. .arg(Arg::new("command")
  308. .help("Command")
  309. .required(true)
  310. .value_name("COMMAND")))
  311. .subcommand(Command::new("remove")
  312. .about("Remove a command from a repository type")
  313. .arg(Arg::new("type")
  314. .help("Name of type")
  315. .required(true)
  316. .value_name("TYPE"))
  317. .arg(Arg::new("name")
  318. .help("Name of command")
  319. .required(true)
  320. .value_name("NAME")))
  321. )
  322. .subcommand(Command::new("show")
  323. .about("Show information about a repository type")
  324. .arg(Arg::new("type")
  325. .help("Name of type")
  326. .required(true)
  327. .value_name("TYPE")))
  328. .subcommand(Command::new("list")
  329. .about("List known repository types")))
  330. .subcommand(Command::new("action")
  331. .about("Create and manage actions")
  332. .subcommand_required(true)
  333. .subcommand(Command::new("create")
  334. .about("Create a new action")
  335. .arg(Arg::new("action")
  336. .help("Name of action")
  337. .required(true)
  338. .value_name("ACTION"))
  339. .arg(Arg::new("command")
  340. .help("Command")
  341. .required(true)
  342. .value_name("COMMAND"))
  343. .arg(Arg::new("description")
  344. .help("Description of action")
  345. .long("description")
  346. .short('d')
  347. .value_name("DESCRIPTION")))
  348. .subcommand(Command::new("config")
  349. .about("Configure an action")
  350. .arg(Arg::new("action")
  351. .help("Name of action")
  352. .required(true)
  353. .value_name("ACTION"))
  354. .arg(Arg::new("disable")
  355. .short('D')
  356. .long("disable")
  357. .value_name("YES/NO")
  358. .help("Disable action")
  359. .value_parser(value_parser!(HumanBool)))
  360. .arg(Arg::new("command")
  361. .help("Command")
  362. .long("command")
  363. .short('c')
  364. .value_name("COMMAND"))
  365. .arg(Arg::new("description")
  366. .help("Description of action")
  367. .long("description")
  368. .short('d')
  369. .value_name("DESCRIPTION")))
  370. .subcommand(Command::new("show")
  371. .about("Show information about an action")
  372. .arg(Arg::new("action")
  373. .help("Name of action")
  374. .required(true)
  375. .value_name("ACTION")))
  376. .subcommand(Command::new("list")
  377. .about("List known actions")))
  378. .subcommand(Command::new("completion")
  379. .about("Generate completions for command.")
  380. .arg(Arg::new("shell")
  381. .value_name("SHELL")
  382. .help("Which shell to generate completions for")
  383. .required(true)
  384. .value_parser(value_parser!(Shell))))
  385. }
  386. fn print_completions<G: Generator>(gen: G, cmd: &mut Command) {
  387. generate(gen, cmd, cmd.get_name().to_string(), &mut io::stdout());
  388. }
  389. fn main() {
  390. let matches = build_cli().get_matches();
  391. let config_file = find_config_file(matches.get_one::<String>("config"));
  392. let mut configuration: Config = read_configuration_file(&config_file);
  393. if matches.get_one::<String>("config").is_some() {
  394. configuration.is_not_default = true;
  395. configuration.base_path = config_file.canonicalize().unwrap().parent().unwrap().to_path_buf();
  396. }
  397. match matches.subcommand() {
  398. Some(("completion", subm)) => {
  399. let mut cmd = build_cli();
  400. if let Some(generator) = subm.get_one::<Shell>("shell").copied() {
  401. print_completions(generator, &mut cmd);
  402. }
  403. }
  404. Some(("run", subm)) => {
  405. let repos: Vec<&str> = subm.get_many::<String>("repo")
  406. .expect("At least one repository/group must be specified.")
  407. .map(|s| s.as_str()).collect();
  408. if let Some(command) = subm.get_one::<String>("command") {
  409. run::run_with_command(&configuration, command, repos);
  410. } else {
  411. run::run(&configuration, repos);
  412. }
  413. }
  414. Some(("repository", subm)) => {
  415. match subm.subcommand() {
  416. Some(("register", subm)) => {
  417. let type_name = subm.get_one::<String>("type").expect("A type name must be provided").to_string();
  418. let location = match configuration.is_not_default {
  419. true => env::current_dir().unwrap().strip_prefix(&configuration.base_path).unwrap().to_path_buf(),
  420. _ => env::current_dir().unwrap()
  421. };
  422. let location_str = location.to_str().unwrap().to_string();
  423. let name = match subm.get_one::<String>("name") {
  424. Some(name) => name.to_string(),
  425. None => location.file_name().unwrap().to_str().unwrap().to_string()
  426. };
  427. let mut option_strings: Vec<String> = Vec::new();
  428. match subm.get_many::<String>("options") {
  429. Some(option) => {
  430. for string in option {
  431. option_strings.push(string.to_string())
  432. }
  433. }
  434. None => {}
  435. }
  436. repository::register(&mut configuration, &name, location_str, type_name, option_strings);
  437. }
  438. Some(("config", subm)) => {
  439. let repo = subm.get_one::<String>("repo").expect("A repository name must be provided").to_string();
  440. if let Some(options) = subm.get_many::<String>("options") {
  441. let mut option_strings: Vec<String> = Vec::new();
  442. for str_thing in options {
  443. option_strings.push(str_thing.to_string())
  444. }
  445. repository::update_options(&mut configuration, &repo, option_strings);
  446. }
  447. match subm.get_one::<HumanBool>("autocreate") {
  448. Some(HumanBool::Yes) => repository::update_autocreate(&mut configuration, &repo, true),
  449. Some(HumanBool::No) => repository::update_autocreate(&mut configuration, &repo, false),
  450. _ => {}
  451. }
  452. match subm.get_one::<HumanBool>("disable") {
  453. Some(HumanBool::Yes) => repository::update_disabled(&mut configuration, &repo, true),
  454. Some(HumanBool::No) => repository::update_disabled(&mut configuration, &repo, false),
  455. _ => {}
  456. }
  457. }
  458. Some(("remove", subm)) => {
  459. let repo = subm.get_one::<String>("repo").expect("A repository name must be provided").to_string();
  460. repository::remove_repo(&mut configuration, &repo);
  461. }
  462. Some(("list", _subm)) => {
  463. for key in configuration.repositories.keys() {
  464. println!(" - {}", key);
  465. }
  466. }
  467. Some(("show", subm)) => {
  468. let repo = subm.get_one::<String>("repo").expect("A repository name must be provided").to_string();
  469. let repository = configuration.repositories.get(&repo);
  470. match repository {
  471. Some(repository) => println!("{}", repository),
  472. None => eprintln!("No known repository named \"{}\".", repo)
  473. }
  474. }
  475. _ => {
  476. panic!("This should never happen...")
  477. }
  478. }
  479. }
  480. Some(("group", subm)) => {
  481. match subm.subcommand() {
  482. Some(("create", subm)) => {
  483. let group = subm.get_one::<String>("group").expect("A group name must be provided.").to_string();
  484. group::add(&mut configuration, &group);
  485. }
  486. Some(("delete", subm)) => {
  487. let group = subm.get_one::<String>("group").expect("A group name must be provided.").to_string();
  488. group::remove_group(&mut configuration, &group);
  489. }
  490. Some(("add", subm)) => {
  491. let group = subm.get_one::<String>("group").expect("A group name must be provided.").to_string();
  492. let repo = subm.get_one::<String>("repo").expect("A repository name must be provided.").to_string();
  493. group::add_repo(&mut configuration, &group, &repo)
  494. }
  495. Some(("act", subm)) => {
  496. let group = subm.get_one::<String>("group").expect("A group name must be provided.").to_string();
  497. let action = subm.get_one::<String>("action").expect("An action name must be provided").to_string();
  498. group::add_action(&mut configuration, &group, &action);
  499. }
  500. Some(("remove", subm)) => {
  501. let group = subm.get_one::<String>("group").expect("A group name must be provided.").to_string();
  502. let repo = subm.get_one::<String>("repo").expect("A repository name must be provided.").to_string();
  503. group::remove_repo(&mut configuration, &group, &repo)
  504. }
  505. Some(("show", subm)) => {
  506. let group_name = subm.get_one::<String>("group").expect("A group name must be provided.").to_string();
  507. let group = configuration.groups.get(&group_name);
  508. match group {
  509. Some(group) => println!("{}", group),
  510. None => eprintln!("No known group named \"{}\".", group_name)
  511. }
  512. }
  513. Some(("list", _subm)) => {}
  514. _ => {
  515. panic!("This should never happen...")
  516. }
  517. }
  518. }
  519. Some(("type", subm)) => {
  520. match subm.subcommand() {
  521. Some(("create", subm)) => {
  522. let tname = subm.get_one::<String>("type").expect("A type name must be provided").to_string();
  523. let temp_string = "".to_string();
  524. let description = subm.get_one::<String>("description").unwrap_or(&temp_string);
  525. let create = subm.get_one::<String>("create").unwrap_or(&temp_string);
  526. let inward = subm.get_one::<String>("inward").unwrap_or(&temp_string);
  527. let outward = subm.get_one::<String>("outward").unwrap_or(&temp_string);
  528. let status = subm.get_one::<String>("status").unwrap_or(&temp_string);
  529. let pre_inward = subm.get_one::<String>("pre_inward").unwrap_or(&temp_string);
  530. let post_inward = subm.get_one::<String>("post_inward").unwrap_or(&temp_string);
  531. let post_outward = subm.get_one::<String>("post_outward").unwrap_or(&temp_string);
  532. repotype::add(&mut configuration, &tname, &description, &create, &inward, &outward, &status, &pre_inward, &post_inward, &post_outward);
  533. }
  534. Some(("config", subm)) => {
  535. let tname = subm.get_one::<String>("type").expect("A type name must be provided").to_string();
  536. match subm.get_one::<String>("description") {
  537. Some(description) => repotype::update_description(&mut configuration, &tname, &description.to_string()),
  538. _ => {}
  539. }
  540. match subm.get_one::<String>("create") {
  541. Some(create) => repotype::update_create(&mut configuration, &tname, &create.to_string()),
  542. _ => {}
  543. }
  544. match subm.get_one::<String>("inward") {
  545. Some(inward) => repotype::update_inward(&mut configuration, &tname, &inward.to_string()),
  546. _ => {}
  547. }
  548. match subm.get_one::<String>("outward") {
  549. Some(outward) => repotype::update_outward(&mut configuration, &tname, &outward.to_string()),
  550. _ => {}
  551. }
  552. match subm.get_one::<String>("status") {
  553. Some(status) => repotype::update_status(&mut configuration, &tname, &status.to_string()),
  554. _ => {}
  555. }
  556. match subm.get_one::<String>("pre_inward") {
  557. Some(pre_inward) => repotype::update_pre_inward(&mut configuration, &tname, &pre_inward.to_string()),
  558. _ => {}
  559. }
  560. match subm.get_one::<String>("post_inward") {
  561. Some(post_inward) => repotype::update_post_inward(&mut configuration, &tname, &post_inward.to_string()),
  562. _ => {}
  563. }
  564. match subm.get_one::<String>("post_outward") {
  565. Some(post_outward) => repotype::update_post_outward(&mut configuration, &tname, &post_outward.to_string()),
  566. _ => {}
  567. }
  568. }
  569. Some(("command", subm)) => {
  570. match subm.subcommand() {
  571. Some(("add", subm)) => {
  572. let type_name = subm.get_one::<String>("type").expect("A type name is required").to_string();
  573. let name = subm.get_one::<String>("name").expect("A name is required").to_string();
  574. let command = subm.get_one::<String>("command").expect("A command is required").to_string();
  575. repotype::add_command(&mut configuration, &type_name, &name, &command);
  576. },
  577. Some(("change", subm)) => {
  578. let type_name = subm.get_one::<String>("type").expect("A type name is required").to_string();
  579. let name = subm.get_one::<String>("name").expect("A name is required").to_string();
  580. let command = subm.get_one::<String>("command").expect("A command is required").to_string();
  581. repotype::change_command(&mut configuration, &type_name, &name, &command);
  582. },
  583. Some(("remove", subm)) => {
  584. let type_name = subm.get_one::<String>("type").expect("A type name is required").to_string();
  585. let name = subm.get_one::<String>("name").expect("A name is required").to_string();
  586. repotype::remove_command(&mut configuration, &type_name, &name);
  587. },
  588. _ => panic!("Something has gone horribly wrong...")
  589. }
  590. }
  591. Some(("show", subm)) => {
  592. let tname = subm.get_one::<String>("type").expect("A type name is required").to_string();
  593. let repo_type = configuration.repo_types.get(&tname);
  594. match repo_type {
  595. Some(repo_type) => println!("{}", repo_type),
  596. None => eprintln!("No known repo type named \"{}\".", tname)
  597. }
  598. }
  599. Some(("list", _subm)) => {
  600. for key in configuration.repo_types.keys() {
  601. println!(" - {}", key);
  602. }
  603. }
  604. _ => {
  605. panic!("This should never happen...")
  606. }
  607. }
  608. }
  609. Some(("action", subm)) => {
  610. match subm.subcommand() {
  611. Some(("create", subm)) => {
  612. let name = subm.get_one::<String>("action").expect("An action name is required").to_string();
  613. let command = subm.get_one::<String>("command").expect("A command is required").to_string();
  614. let temp_string = "".to_string();
  615. let description = subm.get_one::<String>("Description").unwrap_or(&temp_string);
  616. action::add(&mut configuration, &name, &description, &command);
  617. }
  618. Some(("config", subm)) => {
  619. let name = subm.get_one::<String>("action").expect("An action name is required").to_string();
  620. match subm.get_one::<HumanBool>("disabled") {
  621. Some(HumanBool::Yes) => action::update_disabled(&mut configuration, &name, true),
  622. Some(HumanBool::No) => action::update_disabled(&mut configuration, &name, false),
  623. _ => {}
  624. }
  625. match subm.get_one::<String>("command") {
  626. Some(command) => action::update_command(&mut configuration, &name, &command.to_string()),
  627. _ => {}
  628. }
  629. match subm.get_one::<String>("description") {
  630. Some(description) => action::update_description(&mut configuration, &name, &description.to_string()),
  631. _ => {}
  632. }
  633. }
  634. Some(("show", subm)) => {
  635. let name = subm.get_one::<String>("action").expect("An action name is required").to_string();
  636. let action = configuration.actions.get(&name);
  637. match action {
  638. Some(action) => println!("{}", action),
  639. None => eprintln!("No known action named \"{}\".", name)
  640. }
  641. }
  642. Some(("list", _subm)) => {
  643. for key in configuration.actions.keys() {
  644. println!(" - {}", key);
  645. }
  646. }
  647. _ => {
  648. panic!("This should never happen...")
  649. }
  650. }
  651. }
  652. _ => {
  653. panic!("This should never happen...")
  654. }
  655. }
  656. match write_configuration_file(config_file, configuration) {
  657. Err(err) => panic!("Error writing configuration: {}.", err),
  658. _ => {}
  659. }
  660. }