1#![warn(missing_docs, clippy::unwrap_used)]
5
6pub mod args;
8pub mod config;
10pub mod error;
12pub 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
25const CONFIG_FILE: &str = "config.toml";
27
28pub 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 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 #[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}