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