up_rs/
lib.rs

1//! The `up` CLI command.
2
3// Max clippy pedanticness.
4#![deny(
5    // Try not to use `.unwrap()`. If you have confirmed the invariant or it's difficult to propagate an
6    // error properly, use `.expect()` with an explanation of the invariant.
7    clippy::unwrap_used,
8    // Using this macro for debugging is fine, but it shouldn't be checked in.
9    clippy::dbg_macro,
10    // This is an `.unwrap()` in a different guise.
11    clippy::indexing_slicing,
12    // Project doesn't use mod.rs anywhere, so enforce consistency.
13    clippy::mod_module_files,
14    // Splitting the implementation of a type makes the code harder to navigate.
15    clippy::multiple_inherent_impl,
16    // Separating literals is more readable.
17    clippy::unseparated_literal_suffix,
18    // `.to_owned()` is clearer for str -> String conversions.
19    clippy::str_to_string,
20    // `.clone()` is clearer from String -> String.
21    clippy::string_to_string,
22    // This macro should not be present in production code
23    clippy::todo,
24    // Documenting why unsafe things are okay is useful.
25    clippy::undocumented_unsafe_blocks,
26    // Removing these improves readability.
27    clippy::unnecessary_self_imports,
28    // Improves readability.
29    clippy::unneeded_field_pattern,
30    // If we can return a result, we should.
31    clippy::unwrap_in_result,
32    // Cargo manifest lints.
33    clippy::cargo,
34    // May regret adding this.
35    clippy::pedantic,
36    // Require a docstring for everything, may also regret adding this.
37    clippy::missing_docs_in_private_items,
38)]
39#![allow(
40    // This is covered by other lints anyway, and we want to allow ensure! for tests.
41    clippy::panic_in_result_fn,
42    // Done by downstream crates, not much that can be done for it.
43    clippy::multiple_crate_versions,
44    // Mostly not using this as a shared library.
45    clippy::missing_errors_doc,
46    // Not worth it IMHO.
47    clippy::case_sensitive_file_extension_comparisons,
48    // I find this often more readable.
49    clippy::module_name_repetitions,
50    // Not usually worth fixing.
51    clippy::needless_pass_by_value,
52    // Don't error in stable about nightly-only lints.
53    unknown_lints,
54    // https://github.com/yaahc/displaydoc/issues/46
55    non_local_definitions,
56)]
57
58use crate::config::UpConfig;
59use crate::opts::Opts;
60use crate::opts::SubCommand;
61use color_eyre::eyre::Result;
62use opts::DefaultsSubcommand;
63use opts::GenerateLib;
64use tasks::defaults;
65use tasks::TasksAction;
66use tasks::TasksDir;
67use tracing::trace;
68
69mod config;
70pub mod env;
71pub mod errors;
72pub mod exec;
73mod generate;
74pub mod opts;
75pub mod tasks;
76pub mod utils;
77
78/// The unique identifier of the up application on the system.
79pub const UP_BUNDLE_ID: &str = "co.fahn.up";
80
81/// Run `up` with provided [Opts][] struct.
82///
83/// # Errors
84///
85/// Errors if the relevant subcommand fails.
86///
87/// # Panics
88///
89/// Panics for unimplemented commands.
90///
91/// [Opts]: crate::opts::Opts
92pub fn run(opts: Opts) -> Result<()> {
93    match opts.cmd {
94        Some(SubCommand::Link(link_options)) => {
95            tasks::link::run(link_options, &opts.temp_dir)?;
96        }
97        Some(SubCommand::Git(git_options)) => {
98            tasks::git::update::update(&git_options.into())?;
99        }
100        Some(SubCommand::Defaults(defaults_options)) => match defaults_options.subcommand {
101            DefaultsSubcommand::Read(defaults_read_opts) => {
102                defaults::read(defaults_options.current_host, defaults_read_opts)?;
103            }
104            DefaultsSubcommand::Write(defaults_write_opts) => {
105                defaults::write(
106                    defaults_options.current_host,
107                    defaults_write_opts,
108                    &opts.temp_dir,
109                )?;
110            }
111        },
112        Some(SubCommand::Self_(cmd_opts)) => {
113            tasks::update_self::run(&cmd_opts)?;
114        }
115        Some(SubCommand::Generate(ref cmd_opts)) => match cmd_opts.lib {
116            Some(GenerateLib::Git(ref git_opts)) => {
117                generate::git::run_single(git_opts)?;
118            }
119            Some(GenerateLib::Defaults(ref defaults_opts)) => {
120                trace!("Options: {defaults_opts:?}");
121                // TODO(gib): implement defaults generation.
122                unimplemented!("Allow generating defaults yaml.");
123            }
124            None => {
125                let config = UpConfig::from(opts)?;
126                generate::run(&config)?;
127            }
128        },
129        Some(SubCommand::Completions(ref cmd_opts)) => {
130            tasks::completions::run(cmd_opts);
131        }
132        Some(SubCommand::Schema(ref cmd_opts)) => {
133            tasks::schema::run(cmd_opts)?;
134        }
135        Some(SubCommand::List(ref _cmd_opts)) => {
136            let config = UpConfig::from(opts)?;
137            tasks::run(&config, TasksDir::Tasks, TasksAction::List)?;
138        }
139        Some(SubCommand::Run(ref _cmd_opts)) => {
140            let config = UpConfig::from(opts)?;
141            tasks::run(&config, TasksDir::Tasks, TasksAction::Run)?;
142        }
143        None => {
144            let config = UpConfig::from(opts)?;
145            tasks::run(&config, TasksDir::Tasks, TasksAction::Run)?;
146        }
147    }
148    Ok(())
149}