Skip to content

Commit

Permalink
feat(cli): add tauri remove command (#11322)
Browse files Browse the repository at this point in the history
  • Loading branch information
ShaunSHamilton authored Nov 7, 2024
1 parent 8e8312b commit 6bf9179
Show file tree
Hide file tree
Showing 6 changed files with 133 additions and 6 deletions.
6 changes: 6 additions & 0 deletions .changes/cli-remove-command.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"tauri-cli": minor:feat
"@tauri-apps/cli": minor:feat
---

Add `tauri remove` to remove plugins from projects.
2 changes: 1 addition & 1 deletion crates/tauri-cli/src/acl/permission/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use crate::Result;
pub mod add;
mod ls;
mod new;
mod rm;
pub mod rm;

#[derive(Debug, Parser)]
#[clap(about = "Manage or create permissions for your app or plugin")]
Expand Down
29 changes: 24 additions & 5 deletions crates/tauri-cli/src/acl/permission/rm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,13 +46,15 @@ fn rm_permission_files(identifier: &str, dir: &Path) -> Result<()> {
permission_file.default = None;
} else {
let set_len = permission_file.set.len();
permission_file.set.retain(|s| s.identifier != identifier);
permission_file
.set
.retain(|s| !identifier_match(identifier, &s.identifier));
updated = permission_file.set.len() != set_len;

let permission_len = permission_file.permission.len();
permission_file
.permission
.retain(|s| s.identifier != identifier);
.retain(|s| !identifier_match(identifier, &s.identifier));
updated = updated || permission_file.permission.len() != permission_len;
}

Expand Down Expand Up @@ -84,7 +86,11 @@ fn rm_permission_from_capabilities(identifier: &str, dir: &Path) -> Result<()> {
if let Ok(mut value) = content.parse::<toml_edit::DocumentMut>() {
if let Some(permissions) = value.get_mut("permissions").and_then(|p| p.as_array_mut()) {
let prev_len = permissions.len();
permissions.retain(|p| p.as_str().map(|p| p != identifier).unwrap_or(false));
permissions.retain(|p| {
p.as_str()
.map(|p| !identifier_match(identifier, p))
.unwrap_or(false)
});
if prev_len != permissions.len() {
std::fs::write(&path, value.to_string())?;
log::info!(action = "Removed"; "permission from capability at {}", dunce::simplified(&path).display());
Expand All @@ -97,7 +103,11 @@ fn rm_permission_from_capabilities(identifier: &str, dir: &Path) -> Result<()> {
if let Ok(mut value) = serde_json::from_slice::<serde_json::Value>(&content) {
if let Some(permissions) = value.get_mut("permissions").and_then(|p| p.as_array_mut()) {
let prev_len = permissions.len();
permissions.retain(|p| p.as_str().map(|p| p != identifier).unwrap_or(false));
permissions.retain(|p| {
p.as_str()
.map(|p| !identifier_match(identifier, p))
.unwrap_or(false)
});
if prev_len != permissions.len() {
std::fs::write(&path, serde_json::to_vec_pretty(&value)?)?;
log::info!(action = "Removed"; "permission from capability at {}", dunce::simplified(&path).display());
Expand All @@ -113,11 +123,20 @@ fn rm_permission_from_capabilities(identifier: &str, dir: &Path) -> Result<()> {
Ok(())
}

fn identifier_match(identifier: &str, permission: &str) -> bool {
match identifier.split_once(':') {
Some((plugin_name, "*")) => permission.contains(plugin_name),
_ => permission == identifier,
}
}

#[derive(Debug, Parser)]
#[clap(about = "Remove a permission file, and its reference from any capability")]
pub struct Options {
/// Permission to remove.
identifier: String,
///
/// To remove all permissions for a given plugin, provide `<plugin-name>:*`
pub identifier: String,
}

pub fn command(options: Options) -> Result<()> {
Expand Down
30 changes: 30 additions & 0 deletions crates/tauri-cli/src/helpers/cargo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,3 +61,33 @@ pub fn install_one(options: CargoInstallOptions) -> crate::Result<()> {

Ok(())
}

#[derive(Debug, Default, Clone, Copy)]
pub struct CargoUninstallOptions<'a> {
pub name: &'a str,
pub cwd: Option<&'a std::path::Path>,
pub target: Option<&'a str>,
}

pub fn uninstall_one(options: CargoUninstallOptions) -> crate::Result<()> {
let mut cargo = Command::new("cargo");
cargo.arg("remove");

cargo.arg(options.name);

if let Some(target) = options.target {
cargo.args(["--target", target]);
}

if let Some(cwd) = options.cwd {
cargo.current_dir(cwd);
}

log::info!("Uninstalling Cargo dependency \"{}\"...", options.name);
let status = cargo.status().context("failed to run `cargo remove`")?;
if !status.success() {
anyhow::bail!("Failed to remove Cargo dependency");
}

Ok(())
}
3 changes: 3 additions & 0 deletions crates/tauri-cli/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ mod interface;
mod migrate;
mod mobile;
mod plugin;
mod remove;
mod signer;

use clap::{ArgAction, CommandFactory, FromArgMatches, Parser, Subcommand, ValueEnum};
Expand Down Expand Up @@ -146,6 +147,7 @@ enum Commands {
Migrate,
Info(info::Options),
Add(add::Options),
Remove(remove::Options),
Plugin(plugin::Cli),
Icon(icon::Options),
Signer(signer::Cli),
Expand Down Expand Up @@ -265,6 +267,7 @@ where
Commands::Bundle(options) => bundle::command(options, cli.verbose)?,
Commands::Dev(options) => dev::command(options)?,
Commands::Add(options) => add::command(options)?,
Commands::Remove(options) => remove::command(options)?,
Commands::Icon(options) => icon::command(options)?,
Commands::Info(options) => info::command(options)?,
Commands::Init(options) => init::command(options)?,
Expand Down
69 changes: 69 additions & 0 deletions crates/tauri-cli/src/remove.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
// Copyright 2019-2024 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT

use clap::Parser;

use crate::{
acl,
helpers::{
app_paths::{resolve_frontend_dir, tauri_dir},
cargo,
npm::PackageManager,
},
Result,
};

#[derive(Debug, Parser)]
#[clap(about = "Remove a tauri plugin from the project")]
pub struct Options {
/// The plugin to remove.
pub plugin: String,
}

pub fn command(options: Options) -> Result<()> {
crate::helpers::app_paths::resolve();
run(options)
}

pub fn run(options: Options) -> Result<()> {
let plugin = options.plugin;

let crate_name = format!("tauri-plugin-{plugin}");

let mut plugins = crate::helpers::plugins::known_plugins();
let metadata = plugins.remove(plugin.as_str()).unwrap_or_default();

let frontend_dir = resolve_frontend_dir();
let tauri_dir = tauri_dir();

let target_str = metadata
.desktop_only
.then_some(r#"cfg(not(any(target_os = "android", target_os = "ios")))"#)
.or_else(|| {
metadata
.mobile_only
.then_some(r#"cfg(any(target_os = "android", target_os = "ios"))"#)
});

cargo::uninstall_one(cargo::CargoUninstallOptions {
name: &crate_name,
cwd: Some(tauri_dir),
target: target_str,
})?;

if !metadata.rust_only {
if let Some(manager) = frontend_dir.map(PackageManager::from_project) {
let npm_name = format!("@tauri-apps/plugin-{plugin}");
manager.remove(&[npm_name], tauri_dir)?;
}

acl::permission::rm::command(acl::permission::rm::Options {
identifier: format!("{plugin}:*"),
})?;
}

log::info!("Now, you must manually remove the plugin from your Rust code.",);

Ok(())
}

0 comments on commit 6bf9179

Please sign in to comment.