Skip to main content

rustypaste_cli/
lib.rs

1//! A CLI tool for [`rustypaste`].
2//!
3//! [`rustypaste`]: https://github.com/orhun/rustypaste
4#![warn(missing_docs, clippy::unwrap_used)]
5
6/// Command-line argument parser.
7pub mod args;
8/// Configuration file parser.
9pub mod config;
10/// Custom error implementation.
11pub mod error;
12/// Upload handler.
13pub mod upload;
14
15use crate::args::Args;
16use crate::config::Config;
17use crate::error::{Error, Result};
18use crate::upload::Uploader;
19use colored::Colorize;
20use etcetera::BaseStrategy;
21use std::fs;
22use std::io::IsTerminal;
23use std::io::{self, Read};
24
25/// Default name of the configuration file.
26const CONFIG_FILE: &str = "config.toml";
27
28/// Runs `rpaste`.
29pub fn run(args: Args) -> Result<()> {
30    let mut config = Config::default();
31    if let Some(ref config_path) = args.config {
32        config = toml::from_str(&fs::read_to_string(config_path)?)?
33    } else {
34        // cannot panic - see https://github.com/lunacookies/etcetera/issues/42
35        let strategy = etcetera::choose_base_strategy()
36            .expect("cannot determine current OS's default strategy (layout)");
37        for path in [
38            strategy.config_dir().join("rustypaste").join(CONFIG_FILE),
39            // paths for backwards compatibility
40            #[cfg(target_family = "unix")]
41            strategy
42                .home_dir()
43                .to_path_buf()
44                .join(".rustypaste")
45                .join(CONFIG_FILE),
46            #[cfg(target_os = "macos")]
47            strategy
48                .home_dir()
49                .to_path_buf()
50                .join("Library/Application Support/rustypaste")
51                .join(CONFIG_FILE),
52        ]
53        .iter()
54        {
55            if path.exists() {
56                config = toml::from_str(&fs::read_to_string(path)?)?;
57                break;
58            }
59        }
60    }
61    config.parse_token_files();
62    config.update_from_args(&args);
63    if config.server.address.is_empty() {
64        return Err(Error::NoServerAddressError);
65    }
66
67    let uploader = Uploader::new(&config);
68    if args.print_server_version {
69        println!("rustypaste-server {}", uploader.retrieve_version()?.trim());
70        return Ok(());
71    }
72
73    if args.list_files {
74        let prettify = args.prettify
75            || config
76                .style
77                .as_ref()
78                .map(|style| style.prettify)
79                .unwrap_or(false);
80        uploader.retrieve_list(&mut io::stdout(), prettify)?;
81        return Ok(());
82    }
83
84    let mut results = Vec::new();
85    if let Some(ref url) = args.url {
86        results.push(uploader.upload_url(url));
87    } else if let Some(ref remote_url) = args.remote {
88        results.push(uploader.upload_remote_url(remote_url));
89    } else if !std::io::stdin().is_terminal() || args.files.contains(&String::from("-")) {
90        let mut buffer = Vec::new();
91        let mut stdin = io::stdin();
92        stdin.read_to_end(&mut buffer)?;
93        results.push(uploader.upload_stream(&*buffer));
94    } else {
95        for file in args.files.iter() {
96            if !args.delete {
97                results.push(uploader.upload_file(file))
98            } else {
99                results.push(uploader.delete_file(file))
100            }
101        }
102    }
103    let prettify = args.prettify
104        || config
105            .style
106            .as_ref()
107            .map(|style| style.prettify)
108            .unwrap_or(false);
109    let format_padding = prettify
110        .then(|| results.iter().map(|v| v.0.len()).max())
111        .flatten()
112        .unwrap_or(1);
113    for (data, result) in results.iter().map(|v| (v.0, v.1.as_ref())) {
114        let data = if prettify {
115            format!(
116                "{:p$} {} ",
117                data,
118                if result.is_ok() {
119                    "=>".green().bold()
120                } else {
121                    "=>".red().bold()
122                },
123                p = format_padding,
124            )
125        } else {
126            String::new()
127        };
128        match result {
129            Ok(url) => println!("{}{}", data, url.trim()),
130            Err(e) => eprintln!("{data}{e}"),
131        }
132    }
133
134    Ok(())
135}