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 std::fs;
21use std::io::IsTerminal;
22use std::io::{self, Read};
23
24/// Default name of the configuration file.
25const CONFIG_FILE: &str = "config.toml";
26
27/// Runs `rpaste`.
28pub fn run(args: Args) -> Result<()> {
29    let mut config = Config::default();
30    if let Some(ref config_path) = args.config {
31        config = toml::from_str(&fs::read_to_string(config_path)?)?
32    } else {
33        for path in [
34            dirs_next::home_dir().map(|p| p.join(".rustypaste").join(CONFIG_FILE)),
35            #[cfg(target_os = "macos")]
36            Some(config.retrieve_xdg_config_on_macos().join(CONFIG_FILE)),
37            dirs_next::config_dir().map(|p| p.join("rustypaste").join(CONFIG_FILE)),
38        ]
39        .iter()
40        .filter_map(|v| v.as_ref())
41        {
42            if path.exists() {
43                config = toml::from_str(&fs::read_to_string(path)?)?;
44                break;
45            }
46        }
47    }
48    config.parse_token_files();
49    config.update_from_args(&args);
50    if config.server.address.is_empty() {
51        return Err(Error::NoServerAddressError);
52    }
53
54    let uploader = Uploader::new(&config);
55    if args.print_server_version {
56        println!("rustypaste-server {}", uploader.retrieve_version()?.trim());
57        return Ok(());
58    }
59
60    if args.list_files {
61        let prettify = args.prettify
62            || config
63                .style
64                .as_ref()
65                .map(|style| style.prettify)
66                .unwrap_or(false);
67        uploader.retrieve_list(&mut io::stdout(), prettify)?;
68        return Ok(());
69    }
70
71    let mut results = Vec::new();
72    if let Some(ref url) = args.url {
73        results.push(uploader.upload_url(url));
74    } else if let Some(ref remote_url) = args.remote {
75        results.push(uploader.upload_remote_url(remote_url));
76    } else if !std::io::stdin().is_terminal() || args.files.contains(&String::from("-")) {
77        let mut buffer = Vec::new();
78        let mut stdin = io::stdin();
79        stdin.read_to_end(&mut buffer)?;
80        results.push(uploader.upload_stream(&*buffer));
81    } else {
82        for file in args.files.iter() {
83            if !args.delete {
84                results.push(uploader.upload_file(file))
85            } else {
86                results.push(uploader.delete_file(file))
87            }
88        }
89    }
90    let prettify = args.prettify
91        || config
92            .style
93            .as_ref()
94            .map(|style| style.prettify)
95            .unwrap_or(false);
96    let format_padding = prettify
97        .then(|| results.iter().map(|v| v.0.len()).max())
98        .flatten()
99        .unwrap_or(1);
100    for (data, result) in results.iter().map(|v| (v.0, v.1.as_ref())) {
101        let data = if prettify {
102            format!(
103                "{:p$} {} ",
104                data,
105                if result.is_ok() {
106                    "=>".green().bold()
107                } else {
108                    "=>".red().bold()
109                },
110                p = format_padding,
111            )
112        } else {
113            String::new()
114        };
115        match result {
116            Ok(url) => println!("{}{}", data, url.trim()),
117            Err(e) => eprintln!("{data}{e}"),
118        }
119    }
120
121    Ok(())
122}