Implement subcommand inferring based on calling name with feature flag

See issue timvisee/ffsend#24
This commit is contained in:
timvisee 2019-03-17 17:29:44 +01:00
parent 1fc189d4d9
commit a6deb9155b
No known key found for this signature in database
GPG key ID: B8DB720BC383E172
5 changed files with 109 additions and 15 deletions

View file

@ -50,7 +50,7 @@ name = "ffsend"
path = "src/main.rs" path = "src/main.rs"
[features] [features]
default = ["archive", "clipboard", "history", "send2", "send3", "qrcode", "urlshorten"] default = ["archive", "clipboard", "history", "infer-command", "qrcode", "send2", "send3", "urlshorten"]
# Compile with file archiving support # Compile with file archiving support
archive = ["tar"] archive = ["tar"]
@ -58,9 +58,6 @@ archive = ["tar"]
# Compile with file history support # Compile with file history support
history = [] history = []
# Compile without colored output support
no-color = ["colored/no-color"]
# Support for Firefox Send v2 # Support for Firefox Send v2
send2 = ["ffsend-api/send2"] send2 = ["ffsend-api/send2"]
@ -73,6 +70,12 @@ qrcode = ["qr2term"]
# Support for shortening share URLs # Support for shortening share URLs
urlshorten = ["urlshortener"] urlshorten = ["urlshortener"]
# Support for inferring subcommand when linking binary
infer-command = []
# Compile without colored output support
no-color = ["colored/no-color"]
[dependencies] [dependencies]
chbs = "0.0.8" chbs = "0.0.8"
chrono = "0.4" chrono = "0.4"

View file

@ -388,16 +388,17 @@ Different use flags are available for `ffsend` to toggle whether to include
various features. various features.
The following features are available, some of which are enabled by default: The following features are available, some of which are enabled by default:
| Feature | Enabled | Description | | Feature | Enabled | Description |
| :---------: | :-----: | :--------------------------------------------------------- | | :------------: | :-----: | :--------------------------------------------------------- |
| `send2` | Default | Support for Firefox Send v2 servers | | `send2` | Default | Support for Firefox Send v2 servers |
| `send3` | Default | Support for Firefox Send v3 servers | | `send3` | Default | Support for Firefox Send v3 servers |
| `clipboard` | Default | Support for copying links to the clipboard | | `clipboard` | Default | Support for copying links to the clipboard |
| `history` | Default | Support for tracking files in history | | `history` | Default | Support for tracking files in history |
| `archive` | Default | Support for archiving and extracting uploads and downloads | | `archive` | Default | Support for archiving and extracting uploads and downloads |
| `qrcode` | Default | Support for rendering a QR code for a share URL | | `qrcode` | Default | Support for rendering a QR code for a share URL |
| `urlshorten`| Default | Support for shortening share URLs | | `urlshorten` | Default | Support for shortening share URLs |
| `no-color` | | Compile without color support in error and help messages | | `infer-command`| Default | Support for inferring subcommand based on binary name |
| `no-color` | | Compile without color support in error and help messages |
To enable features during building or installation, specify them with To enable features during building or installation, specify them with
`--features <features...>` when using `cargo`. `--features <features...>` when using `cargo`.
@ -454,6 +455,37 @@ empty.
At this time, no configuration or _dotfile_ file support is available. At this time, no configuration or _dotfile_ file support is available.
This will be something added in a later release. This will be something added in a later release.
### Binary for each subcommand: `ffput`, `ffget`
`ffsend` supports having a separate binary for a single subcommand, such as
having `ffput` and `ffget` just for uploading and downloading through `ffsend`.
This allows simple commands like:
```bash
ffput my-file.txt
ffget https://send.firefox.com/#sample-share-url
```
This works for a predefined list of binary names:
* `ffput` -> `ffsend upload ...`
* `ffget` -> `ffsend download ...`
* `ffdel` -> `ffsend delete ...`
* _This list is defined in [`src/config.rs`](./src/config.rs) as `INFER_COMMANDS`_
Symbolic or hard links may be created having these names for this functionality
(similar to [`busybox`](https://en.wikipedia.org/wiki/BusyBox#Single_binary)),
so you don't have to clone the `ffsend` binary for each subcommand.
On Linux and macOS you can use the following commands for setting up these
symbolic links in the current directory:
```bash
ln -s $(which ffsend) ./ffput
ln -s $(which ffsend) ./ffget
```
Support for this feature is only available when `ffsend` is compiled with the
[`infer-command`](#compile-features--use-flags) feature flag.
This is usually enabled by default.
To verify support is available with an existing installation, make sure the
feature is listed when invoking `ffsend debug`.
## Security ## Security
In short; the `ffsend` tool and the [Send][send] service can be considered In short; the `ffsend` tool and the [Send][send] service can be considered
secure, and may be used to share sensitive files. Note though that the secure, and may be used to share sensitive files. Note though that the

View file

@ -1,5 +1,8 @@
extern crate directories; extern crate directories;
#[cfg(feature = "infer-command")]
use std::ffi::OsString;
use clap::{App, AppSettings, Arg, ArgMatches}; use clap::{App, AppSettings, Arg, ArgMatches};
use super::arg::{ArgApi, CmdArg}; use super::arg::{ArgApi, CmdArg};
@ -15,9 +18,13 @@ use super::subcmd::{
CmdDebug, CmdDelete, CmdDownload, CmdExists, CmdInfo, CmdParams, CmdPassword, CmdUpload, CmdDebug, CmdDelete, CmdDownload, CmdExists, CmdInfo, CmdParams, CmdPassword, CmdUpload,
CmdVersion, CmdVersion,
}; };
#[cfg(feature = "infer-command")]
use crate::config::INFER_COMMANDS;
use crate::config::{CLIENT_TIMEOUT, CLIENT_TRANSFER_TIMEOUT}; use crate::config::{CLIENT_TIMEOUT, CLIENT_TRANSFER_TIMEOUT};
#[cfg(feature = "history")] #[cfg(feature = "history")]
use crate::util::app_history_file_path_string; use crate::util::app_history_file_path_string;
#[cfg(feature = "infer-command")]
use crate::util::bin_name;
#[cfg(feature = "history")] #[cfg(feature = "history")]
lazy_static! { lazy_static! {
@ -188,9 +195,40 @@ impl<'a: 'b, 'b> Handler<'a> {
/// Parse CLI arguments. /// Parse CLI arguments.
pub fn parse() -> Handler<'a> { pub fn parse() -> Handler<'a> {
// Obtain the program arguments
#[allow(unused_mut)]
let mut args: Vec<_> = ::std::env::args_os().collect();
// Infer subcommand based on binary name
#[cfg(feature = "infer-command")]
Self::infer_subcommand(&mut args);
// Build the application CLI definition, get the matches // Build the application CLI definition, get the matches
Handler { Handler {
matches: Handler::build().get_matches(), matches: Handler::build().get_matches_from(args),
}
}
/// Infer subcommand when the binary has a predefined name,
/// modifying the given program arguments.
///
/// If no subcommand could be inferred, the `args` list leaves unchanged.
/// See `crate::config::INFER_COMMANDS` for a list of commands.
///
/// When the `ffsend` binary is called with such a name, the corresponding subcommand is
/// automatically inserted as argument. This also works when calling binaries through symbolic
/// or hard links.
#[cfg(feature = "infer-command")]
fn infer_subcommand(args: &mut Vec<OsString>) {
// Get the name of the called binary
let name = bin_name();
// Infer subcommands
for (bin, subcmd) in INFER_COMMANDS.iter() {
if &name == bin {
args.insert(1, subcmd.into());
break;
}
} }
} }

View file

@ -1,3 +1,6 @@
#[cfg(feature = "infer-command")]
use std::collections::HashMap;
use ffsend_api::api::{DesiredVersion, Version}; use ffsend_api::api::{DesiredVersion, Version};
/// The timeout for the Send client for generic requests, `0` to disable. /// The timeout for the Send client for generic requests, `0` to disable.
@ -15,3 +18,19 @@ pub const API_VERSION_DESIRED_DEFAULT: DesiredVersion = DesiredVersion::Assume(A
pub const API_VERSION_ASSUME: Version = Version::V3; pub const API_VERSION_ASSUME: Version = Version::V3;
#[cfg(not(feature = "send3"))] #[cfg(not(feature = "send3"))]
pub const API_VERSION_ASSUME: Version = Version::V2; pub const API_VERSION_ASSUME: Version = Version::V2;
#[cfg(feature = "infer-command")]
lazy_static! {
/// Hashmap holding binary names to infer subcommands for.
///
/// When the `ffsend` binary is called with such a name, the corresponding subcommand is
/// automatically inserted as argument. This also works when calling binaries through symbolic
/// or hard links.
pub static ref INFER_COMMANDS: HashMap<&'static str, &'static str> = {
let mut m = HashMap::new();
m.insert("ffput", "upload");
m.insert("ffget", "download");
m.insert("ffdel", "delete");
m
};
}

View file

@ -849,6 +849,8 @@ pub fn features_list() -> Vec<&'static str> {
features.push("qrcode"); features.push("qrcode");
#[cfg(feature = "urlshorten")] #[cfg(feature = "urlshorten")]
features.push("urlshorten"); features.push("urlshorten");
#[cfg(feature = "infer-command")]
features.push("infer-command");
#[cfg(feature = "no-qcolor")] #[cfg(feature = "no-qcolor")]
features.push("no-color"); features.push("no-color");
#[cfg(feature = "send2")] #[cfg(feature = "send2")]