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

View file

@ -389,7 +389,7 @@ various features.
The following features are available, some of which are enabled by default:
| Feature | Enabled | Description |
| :---------: | :-----: | :--------------------------------------------------------- |
| :------------: | :-----: | :--------------------------------------------------------- |
| `send2` | Default | Support for Firefox Send v2 servers |
| `send3` | Default | Support for Firefox Send v3 servers |
| `clipboard` | Default | Support for copying links to the clipboard |
@ -397,6 +397,7 @@ The following features are available, some of which are enabled by default:
| `archive` | Default | Support for archiving and extracting uploads and downloads |
| `qrcode` | Default | Support for rendering a QR code for a share URL |
| `urlshorten` | Default | Support for shortening share URLs |
| `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
@ -454,6 +455,37 @@ empty.
At this time, no configuration or _dotfile_ file support is available.
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
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

View file

@ -1,5 +1,8 @@
extern crate directories;
#[cfg(feature = "infer-command")]
use std::ffi::OsString;
use clap::{App, AppSettings, Arg, ArgMatches};
use super::arg::{ArgApi, CmdArg};
@ -15,9 +18,13 @@ use super::subcmd::{
CmdDebug, CmdDelete, CmdDownload, CmdExists, CmdInfo, CmdParams, CmdPassword, CmdUpload,
CmdVersion,
};
#[cfg(feature = "infer-command")]
use crate::config::INFER_COMMANDS;
use crate::config::{CLIENT_TIMEOUT, CLIENT_TRANSFER_TIMEOUT};
#[cfg(feature = "history")]
use crate::util::app_history_file_path_string;
#[cfg(feature = "infer-command")]
use crate::util::bin_name;
#[cfg(feature = "history")]
lazy_static! {
@ -188,9 +195,40 @@ impl<'a: 'b, 'b> Handler<'a> {
/// Parse CLI arguments.
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
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};
/// 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;
#[cfg(not(feature = "send3"))]
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");
#[cfg(feature = "urlshorten")]
features.push("urlshorten");
#[cfg(feature = "infer-command")]
features.push("infer-command");
#[cfg(feature = "no-qcolor")]
features.push("no-color");
#[cfg(feature = "send2")]