summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorDavid Lönnhager <david.l@mullvad.net>2020-04-17 10:57:22 +0200
committerDavid Lönnhager <david.l@mullvad.net>2020-04-17 10:57:22 +0200
commitd718db4b02b7a605e1d344eb718b8f9f28078aac (patch)
tree0e9eb7c90d8a63993b4e09df2c5968afe7db505e
parent0e23841e5ca9148ef6a52ef2b8d00fccc8b783f3 (diff)
parent3d6eef646d35c1fe78fbeb10d6871ab948dae5a4 (diff)
downloadmullvadvpn-d718db4b02b7a605e1d344eb718b8f9f28078aac.tar.xz
mullvadvpn-d718db4b02b7a605e1d344eb718b8f9f28078aac.zip
Merge branch 'add-shell-completion'
-rw-r--r--.gitignore1
-rw-r--r--CHANGELOG.md3
-rwxr-xr-xbuild.sh13
-rwxr-xr-xdist-assets/pkg-scripts/postinstall5
-rwxr-xr-xdist-assets/uninstall_macos.sh9
-rw-r--r--gui/tasks/distribution.js5
-rw-r--r--mullvad-cli/Cargo.toml4
-rw-r--r--mullvad-cli/src/main.rs62
8 files changed, 86 insertions, 16 deletions
diff --git a/.gitignore b/.gitignore
index 0e50984ec3..b235a6c73d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -25,6 +25,7 @@
/dist-assets/openvpn.exe
/dist-assets/sslocal
/dist-assets/sslocal.exe
+/dist-assets/shell-completions/
/windows/**/bin/
/windows/**/*.user
/android/keystore.properties
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 52f350561f..8f81b72df1 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -23,6 +23,9 @@ Line wrap the file at 100 chars. Th
## [Unreleased]
+### Added
+- Add shell completions for the mullvad CLI.
+
### Fixed
#### Windows
- Improve offline detection logic.
diff --git a/build.sh b/build.sh
index 5b22e97a19..9d58f3eb9b 100755
--- a/build.sh
+++ b/build.sh
@@ -134,6 +134,18 @@ fi
./wireguard/build-wireguard-go.sh
echo "Building Rust code in release mode using $RUSTC_VERSION..."
+
+if [[ ("$(uname -s)" == "Darwin") || ("$(uname -s)" == "Linux") ]]; then
+ pushd mullvad-cli
+ mkdir -p "$SCRIPT_DIR/dist-assets/shell-completions"
+ for sh in bash zsh; do
+ echo "Generating shell completion script for $sh..."
+ cargo +stable run $CARGO_ARGS --release --features shell-completions -- \
+ shell-completions "$sh" "$SCRIPT_DIR/dist-assets/shell-completions/"
+ done
+ popd
+fi
+
MULLVAD_ADD_MANIFEST="1" cargo +stable build $CARGO_ARGS --release
################################################################################
@@ -198,7 +210,6 @@ fi
./update-relays.sh
-
pushd "$SCRIPT_DIR/gui"
echo "Installing JavaScript dependencies..."
diff --git a/dist-assets/pkg-scripts/postinstall b/dist-assets/pkg-scripts/postinstall
index 51283fea35..803e9cf276 100755
--- a/dist-assets/pkg-scripts/postinstall
+++ b/dist-assets/pkg-scripts/postinstall
@@ -48,6 +48,8 @@ DAEMON_PLIST=$(cat <<-EOM
EOM
)
+ZSH_COMPLETIONS_DIR="/usr/local/share/zsh/site-functions/"
+
"$INSTALL_DIR/Mullvad VPN.app/Contents/Resources/mullvad-setup" prepare-restart || true
pkill -x "Mullvad VPN" || echo "Unable to kill GUI, not running?"
@@ -60,3 +62,6 @@ launchctl load -w $DAEMON_PLIST_PATH
mkdir -p /usr/local/bin
ln -sf "$INSTALL_DIR/Mullvad VPN.app/Contents/Resources/mullvad" /usr/local/bin/mullvad
ln -sf "$INSTALL_DIR/Mullvad VPN.app/Contents/Resources/mullvad-problem-report" /usr/local/bin/mullvad-problem-report
+
+mkdir -p "$ZSH_COMPLETIONS_DIR"
+ln -sf "$INSTALL_DIR/Mullvad VPN.app/Contents/Resources/_mullvad" "$ZSH_COMPLETIONS_DIR/_mullvad"
diff --git a/dist-assets/uninstall_macos.sh b/dist-assets/uninstall_macos.sh
index aec74760b4..9cf33ec5de 100755
--- a/dist-assets/uninstall_macos.sh
+++ b/dist-assets/uninstall_macos.sh
@@ -18,13 +18,16 @@ DAEMON_PLIST_PATH="/Library/LaunchDaemons/net.mullvad.daemon.plist"
sudo launchctl unload -w "$DAEMON_PLIST_PATH"
sudo rm -f "$DAEMON_PLIST_PATH"
-echo "Removing app from /Applications ..."
-sudo rm -rf /Applications/Mullvad\ VPN.app
-sudo pkgutil --forget net.mullvad.vpn || true
+echo "Removing shell completion symlink ..."
+sudo rm -f /usr/local/share/zsh/site-functions/_mullvad
echo "Removing CLI symlinks from /usr/local/bin/ ..."
sudo rm -f /usr/local/bin/mullvad /usr/local/bin/mullvad-problem-report
+echo "Removing app from /Applications ..."
+sudo rm -rf /Applications/Mullvad\ VPN.app
+sudo pkgutil --forget net.mullvad.vpn || true
+
read -p "Do you want to delete the log and cache files the app has created? (y/n) "
if [[ "$REPLY" =~ [Yy]$ ]]; then
sudo rm -rf /var/log/mullvad-vpn /var/root/Library/Caches/mullvad-vpn
diff --git a/gui/tasks/distribution.js b/gui/tasks/distribution.js
index 85069037a6..0a9a6ad465 100644
--- a/gui/tasks/distribution.js
+++ b/gui/tasks/distribution.js
@@ -53,6 +53,7 @@ const config = {
{ from: distAssets('binaries/x86_64-apple-darwin/openvpn'), to: '.' },
{ from: distAssets('binaries/x86_64-apple-darwin/sslocal'), to: '.' },
{ from: distAssets('uninstall_macos.sh'), to: './uninstall.sh' },
+ { from: distAssets('shell-completions/_mullvad'), to: '.' },
],
},
@@ -127,6 +128,8 @@ const config = {
'/opt/Mullvad VPN/resources/mullvad-daemon.conf',
distAssets('mullvad') + '=/usr/bin/',
distAssets('linux/problem-report-link') + '=/usr/bin/mullvad-problem-report',
+ distAssets('shell-completions/mullvad.bash') + '=/usr/share/bash-completion/completions/mullvad',
+ distAssets('shell-completions/_mullvad') + '=/usr/local/share/zsh/site-functions/_mullvad',
],
afterInstall: distAssets('linux/after-install.sh'),
afterRemove: distAssets('linux/after-remove.sh'),
@@ -147,6 +150,8 @@ const config = {
'/opt/Mullvad VPN/resources/mullvad-daemon.conf',
distAssets('mullvad') + '=/usr/bin/',
distAssets('linux/problem-report-link') + '=/usr/bin/mullvad-problem-report',
+ distAssets('shell-completions/mullvad.bash') + '=/usr/share/bash-completion/completions/mullvad',
+ distAssets('shell-completions/_mullvad') + '=/usr/local/share/zsh/site-functions/_mullvad',
],
afterInstall: distAssets('linux/after-install.sh'),
afterRemove: distAssets('linux/after-remove.sh'),
diff --git a/mullvad-cli/Cargo.toml b/mullvad-cli/Cargo.toml
index ec51a613e3..4deb3f5cbf 100644
--- a/mullvad-cli/Cargo.toml
+++ b/mullvad-cli/Cargo.toml
@@ -7,6 +7,10 @@ license = "GPL-3.0"
edition = "2018"
publish = false
+[features]
+default = []
+shell-completions = []
+
[[bin]]
name = "mullvad"
path = "src/main.rs"
diff --git a/mullvad-cli/src/main.rs b/mullvad-cli/src/main.rs
index b84307c475..3d8d2a4aef 100644
--- a/mullvad-cli/src/main.rs
+++ b/mullvad-cli/src/main.rs
@@ -1,13 +1,14 @@
#![deny(rust_2018_idioms)]
-use clap::{crate_authors, crate_description, crate_name};
+use clap::{crate_authors, crate_description};
use mullvad_ipc_client::{new_standalone_ipc_client, DaemonRpcClient};
-use std::io;
+use std::{collections::HashMap, io};
use talpid_types::ErrorExt;
mod cmds;
mod location;
+pub const BIN_NAME: &str = "mullvad";
pub const PRODUCT_VERSION: &str = include_str!(concat!(env!("OUT_DIR"), "/product-version.txt"));
pub type Result<T> = std::result::Result<T, Error>;
@@ -50,8 +51,53 @@ fn run() -> Result<()> {
env_logger::init();
let commands = cmds::get_commands();
+ let app = build_cli(&commands);
- let app = clap::App::new(crate_name!())
+ #[cfg(feature = "shell-completions")]
+ let app = app.subcommand(
+ clap::SubCommand::with_name("shell-completions")
+ .about("Generates completion scripts for your shell")
+ .arg(
+ clap::Arg::with_name("SHELL")
+ .required(true)
+ .possible_values(&clap::Shell::variants()[..])
+ .help("The shell to generate the script for"),
+ )
+ .arg(
+ clap::Arg::with_name("DIR")
+ .default_value("./")
+ .help("Output directory where the shell completions are written"),
+ ),
+ );
+
+ let app_matches = app.get_matches();
+ match app_matches.subcommand() {
+ #[cfg(feature = "shell-completions")]
+ ("shell-completions", Some(sub_matches)) => {
+ let shell = sub_matches
+ .value_of("SHELL")
+ .unwrap()
+ .parse()
+ .expect("Invalid shell");
+ let out_dir = sub_matches.value_of_os("DIR").unwrap();
+ build_cli(&commands).gen_completions(BIN_NAME, shell, out_dir);
+ Ok(())
+ }
+ (sub_name, Some(sub_matches)) => {
+ if let Some(cmd) = commands.get(sub_name) {
+ cmd.run(sub_matches)
+ } else {
+ unreachable!("No command matched");
+ }
+ }
+ (_, None) => {
+ unreachable!("No subcommand matches");
+ }
+ }
+}
+
+fn build_cli(commands: &HashMap<&'static str, Box<dyn Command>>) -> clap::App<'static, 'static> {
+ clap::App::new(BIN_NAME)
.version(PRODUCT_VERSION)
.author(crate_authors!())
.about(crate_description!())
@@ -60,15 +106,7 @@ fn run() -> Result<()> {
clap::AppSettings::DisableHelpSubcommand,
clap::AppSettings::VersionlessSubcommands,
])
- .subcommands(commands.values().map(|cmd| cmd.clap_subcommand()));
-
- let app_matches = app.get_matches();
- let (subcommand_name, subcommand_matches) = app_matches.subcommand();
- if let Some(cmd) = commands.get(subcommand_name) {
- cmd.run(subcommand_matches.expect("No command matched"))
- } else {
- unreachable!("No command matched");
- }
+ .subcommands(commands.values().map(|cmd| cmd.clap_subcommand()))
}
pub trait Command {