diff --git a/ROADMAP.md b/ROADMAP.md index 357533f..02f64ec 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -32,6 +32,7 @@ Features: - Implement a quiet `-q` mode - Update all dependencies - Check all TODOs, solve them when possible +- Allow multi file uploads (select more than one file or directory) # Future releases - Color usage flag diff --git a/cli/src/action/debug.rs b/cli/src/action/debug.rs index 0bec54e..f6be25e 100644 --- a/cli/src/action/debug.rs +++ b/cli/src/action/debug.rs @@ -42,19 +42,19 @@ impl<'a> Debug<'a> { // The default host table.add_row(Row::new(vec![ - Cell::new("host:"), + Cell::new("Host:"), Cell::new(matcher_debug.host().as_str()), ])); // The history file table.add_row(Row::new(vec![ - Cell::new("history file:"), + Cell::new("History file:"), Cell::new(matcher_main.history().to_str().unwrap_or("?")), ])); // The default host table.add_row(Row::new(vec![ - Cell::new("default expiry:"), + Cell::new("Default expiry:"), Cell::new(&format_duration(Duration::seconds(SEND_DEFAULT_EXPIRE_TIME))), ])); diff --git a/cli/src/action/info.rs b/cli/src/action/info.rs index cf95cd6..201fcd3 100644 --- a/cli/src/action/info.rs +++ b/cli/src/action/info.rs @@ -122,14 +122,14 @@ impl<'a> Info<'a> { if let Some(metadata) = metadata { // The file name table.add_row(Row::new(vec![ - Cell::new("name:"), + Cell::new("Name:"), Cell::new(metadata.metadata().name()), ])); // The file size let size = metadata.size(); table.add_row(Row::new(vec![ - Cell::new("size:"), + Cell::new("Size:"), Cell::new( &if size >= 1024 { format!("{} ({} B)", format_bytes(size), size) @@ -148,13 +148,13 @@ impl<'a> Info<'a> { // The download count table.add_row(Row::new(vec![ - Cell::new("downloads:"), + Cell::new("Downloads:"), Cell::new(&format!("{} of {}", info.download_count(), info.download_limit())), ])); // The time to live table.add_row(Row::new(vec![ - Cell::new("expiry:"), + Cell::new("Expiry:"), Cell::new( &if ttl_millis >= 60 * 1000 { format!("{} ({}s)", format_duration(&ttl), ttl.num_seconds()) diff --git a/cli/src/action/upload.rs b/cli/src/action/upload.rs index d476774..36218bf 100644 --- a/cli/src/action/upload.rs +++ b/cli/src/action/upload.rs @@ -1,5 +1,3 @@ -// TODO: remove all expect unwraps, replace them with proper errors - extern crate tempfile; use std::fs::File; @@ -17,6 +15,12 @@ use ffsend_api::action::upload::{ use ffsend_api::config::{UPLOAD_SIZE_MAX, UPLOAD_SIZE_MAX_RECOMMENDED}; use ffsend_api::reader::ProgressReporter; use ffsend_api::reqwest::Client; +use prettytable::{ + cell::Cell, + format::FormatBuilder, + row::Row, + Table, +}; use self::tempfile::{ Builder as TempBuilder, NamedTempFile, @@ -89,7 +93,7 @@ impl<'a> Upload<'a> { } else if size > UPLOAD_SIZE_MAX_RECOMMENDED && !matcher_main.force() { // The file is larger than the recommended maximum, warn eprintln!( - "the file size is {}, bigger than the recommended maximum of {}", + "The file size is {}, bigger than the recommended maximum of {}", format_bytes(size), format_bytes(UPLOAD_SIZE_MAX_RECOMMENDED), ); @@ -135,9 +139,22 @@ impl<'a> Upload<'a> { #[cfg(feature = "archive")] { - // Archive the file if specified - if matcher_upload.archive() { - println!("Archiving file..."); + // Determine whether to archive, ask if a directory was selected + let mut archive = matcher_upload.archive(); + if !archive && path.is_dir() { + if prompt_yes( + "You've selected a directory, only a single file may be uploaded.\n\ + Archive the directory into a single file?", + Some(true), + &matcher_main, + ) { + archive = true; + } + } + + // Archive the selected file or directory + if archive { + eprintln!("Archiving..."); let archive_extention = ".tar"; // Create a new temporary file to write the archive to @@ -157,7 +174,6 @@ impl<'a> Upload<'a> { // Select the file name to use if not set if file_name.is_none() { - // TODO: use canonical path here file_name = Some( path.canonicalize() .map_err(|err| ArchiveError::FileName(Some(err)))? @@ -165,7 +181,7 @@ impl<'a> Upload<'a> { .ok_or(ArchiveError::FileName(None))? .to_str() .map(|s| s.to_owned()) - .expect("failed to create string from file name") + .ok_or(ArchiveError::FileName(None))? ); } @@ -198,10 +214,19 @@ impl<'a> Upload<'a> { params, ).invoke(&client, &progress_reporter)?; - // Get the download URL, and report it in the console + // Get the download URL, and report it in the console in a table let url = file.download_url(true); - println!("Download URL: {}", url); - println!("Owner token: {}", file.owner_token().unwrap()); + let mut table = Table::new(); + table.set_format(FormatBuilder::new().padding(0, 2).build()); + table.add_row(Row::new(vec![ + Cell::new("Share URL:"), + Cell::new(url.as_str()), + ])); + table.add_row(Row::new(vec![ + Cell::new("Owner token:"), + Cell::new(file.owner_token().unwrap()), + ])); + table.printstd(); // Add the file to the history manager #[cfg(feature = "history")] diff --git a/cli/src/progress.rs b/cli/src/progress.rs index 53ef9d0..d7a6d81 100644 --- a/cli/src/progress.rs +++ b/cli/src/progress.rs @@ -1,6 +1,6 @@ extern crate pbr; -use std::io::Stdout; +use std::io::{stderr, Stderr}; use std::time::Duration; use ffsend_api::reader::ProgressReporter; @@ -14,7 +14,7 @@ const PROGRESS_BAR_FPS_MILLIS: u64 = 200; /// A progress bar reporter. pub struct ProgressBar<'a> { - progress_bar: Option>, + progress_bar: Option>, msg_progress: &'a str, msg_finish: &'a str, } @@ -44,7 +44,7 @@ impl<'a> ProgressReporter for ProgressBar<'a> { /// Start the progress with the given total. fn start(&mut self, total: u64) { // Initialize the progress bar - let mut progress_bar = Pbr::new(total); + let mut progress_bar = Pbr::on(stderr(), total); progress_bar.set_max_refresh_rate( Some(Duration::from_millis(PROGRESS_BAR_FPS_MILLIS)) );