feat(cli/migrate): add plugins to Cargo.toml (#8951)

* feat(cli/migrate): add plugins to Cargo.toml

closes #8933

* small cleanup

---------

Co-authored-by: Lucas Nogueira <lucas@tauri.studio>
This commit is contained in:
Amr Bashir 2024-02-26 18:29:16 +02:00 committed by GitHub
parent bc5b5e671a
commit 9be314f07a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 134 additions and 97 deletions

View File

@ -0,0 +1,6 @@
---
'tauri-cli': 'patch:enhance'
'@tauri-apps/cli': 'patch:enhance'
---
Add plugins to `Cargo.toml` when using `tauri migrate`

View File

@ -22,16 +22,16 @@ use std::{collections::HashMap, process::Command};
#[clap(about = "Add a tauri plugin to the project")]
pub struct Options {
/// The plugin to add.
plugin: String,
pub plugin: String,
/// Git tag to use.
#[clap(short, long)]
tag: Option<String>,
pub tag: Option<String>,
/// Git rev to use.
#[clap(short, long)]
rev: Option<String>,
pub rev: Option<String>,
/// Git branch to use.
#[clap(short, long)]
branch: Option<String>,
pub branch: Option<String>,
}
pub fn command(options: Options) -> Result<()> {

View File

@ -14,24 +14,12 @@ use tauri_utils::{
};
use std::{
collections::HashSet,
fs::{create_dir_all, write},
path::Path,
};
macro_rules! move_allowlist_object {
($plugins: ident, $value: expr, $plugin: literal, $field: literal) => {{
if $value != Default::default() {
$plugins
.entry($plugin)
.or_insert_with(|| Value::Object(Default::default()))
.as_object_mut()
.unwrap()
.insert($field.into(), serde_json::to_value($value.clone())?);
}
}};
}
pub fn migrate(tauri_dir: &Path) -> Result<()> {
pub fn migrate(tauri_dir: &Path) -> Result<MigratedConfig> {
if let Ok((mut config, config_path)) =
tauri_utils_v1::config::parse::parse_value(tauri_dir.join("tauri.conf.json"))
{
@ -50,7 +38,7 @@ pub fn migrate(tauri_dir: &Path) -> Result<()> {
.into_iter()
.map(|p| PermissionEntry::PermissionRef(p.to_string().try_into().unwrap()))
.collect();
permissions.extend(migrated.permissions);
permissions.extend(migrated.permissions.clone());
let capabilities_path = config_path.parent().unwrap().join("capabilities");
create_dir_all(&capabilities_path)?;
@ -73,18 +61,23 @@ pub fn migrate(tauri_dir: &Path) -> Result<()> {
],
})?,
)?;
return Ok(migrated);
}
Ok(())
Ok(Default::default())
}
struct MigratedConfig {
permissions: Vec<PermissionEntry>,
#[derive(Default)]
pub struct MigratedConfig {
pub permissions: Vec<PermissionEntry>,
pub plugins: HashSet<String>,
}
fn migrate_config(config: &mut Value) -> Result<MigratedConfig> {
let mut migrated = MigratedConfig {
permissions: Vec::new(),
plugins: HashSet::new(),
};
if let Some(config) = config.as_object_mut() {
@ -101,8 +94,9 @@ fn migrate_config(config: &mut Value) -> Result<MigratedConfig> {
if let Some(tauri_config) = config.get_mut("tauri").and_then(|c| c.as_object_mut()) {
// allowlist
if let Some(allowlist) = tauri_config.remove("allowlist") {
let allowlist = process_allowlist(tauri_config, &mut plugins, allowlist)?;
let allowlist = process_allowlist(tauri_config, allowlist)?;
let permissions = allowlist_to_permissions(allowlist);
migrated.plugins = plugins_from_permissions(&permissions);
migrated.permissions = permissions;
}
@ -178,8 +172,11 @@ fn process_build(config: &mut Map<String, Value>) {
if let Some(dist_dir) = build_config.remove("distDir") {
build_config.insert("frontendDist".into(), dist_dir);
}
if let Some(dist_dir) = build_config.remove("devPath") {
build_config.insert("devUrl".into(), dist_dir);
if let Some(dev_path) = build_config.remove("devPath") {
let is_url = url::Url::parse(dev_path.as_str().unwrap_or_default()).is_ok();
if is_url {
build_config.insert("devUrl".into(), dev_path);
}
}
if let Some(with_global_tauri) = build_config.remove("withGlobalTauri") {
config
@ -282,13 +279,10 @@ fn process_security(security: &mut Map<String, Value>) -> Result<()> {
fn process_allowlist(
tauri_config: &mut Map<String, Value>,
plugins: &mut Map<String, Value>,
allowlist: Value,
) -> Result<tauri_utils_v1::config::AllowlistConfig> {
let allowlist: tauri_utils_v1::config::AllowlistConfig = serde_json::from_value(allowlist)?;
move_allowlist_object!(plugins, allowlist.shell.open, "shell", "open");
if allowlist.protocol.asset_scope != Default::default() {
let security = tauri_config
.entry("security")
@ -524,6 +518,34 @@ fn process_updater(
Ok(())
}
const KNOWN_PLUGINS: &[&str] = &[
"fs",
"shell",
"dialog",
"http",
"notification",
"global-shortcut",
"os",
"process",
"clipboard-manager",
];
fn plugins_from_permissions(permissions: &Vec<PermissionEntry>) -> HashSet<String> {
let mut plugins = HashSet::new();
for permission in permissions {
let permission = permission.identifier().get();
for plugin in KNOWN_PLUGINS {
if permission.starts_with(plugin) {
plugins.insert(plugin.to_string());
break;
}
}
}
plugins
}
#[cfg(test)]
mod test {
fn migrate(original: &serde_json::Value) -> serde_json::Value {
@ -846,4 +868,22 @@ mod test {
"connect-src migration failed"
);
}
#[test]
fn migrate_invalid_url_dev_path() {
let original = serde_json::json!({
"build": {
"devPath": "../src",
"distDir": "../src"
}
});
let migrated = migrate(&original);
assert!(migrated["build"].get("devUrl").is_none());
assert_eq!(
migrated["build"]["distDir"],
original["build"]["frontendDist"]
);
}
}

View File

@ -11,7 +11,7 @@ use toml_edit::{Document, Entry, Item, Table, TableLike, Value};
use std::{fs::File, io::Write, path::Path};
const CRATE_TYPES: &[&str] = &["staticlib", "cdylib", "rlib"];
const CRATE_TYPES: [&str; 3] = ["lib", "staticlib", "cdylib"];
pub fn migrate(tauri_dir: &Path) -> Result<()> {
let manifest_path = tauri_dir.join("Cargo.toml");
@ -57,34 +57,34 @@ fn migrate_manifest(manifest: &mut Document) -> Result<()> {
migrate_dependency(build_dependencies, "tauri-build", &version, &[]);
let lib = manifest
if let Some(lib) = manifest
.as_table_mut()
.entry("lib")
.or_insert(Item::Table(Table::new()))
.as_table_mut()
.expect("manifest lib isn't a table");
match lib.entry("crate-type") {
Entry::Occupied(mut e) => {
if let Item::Value(Value::Array(types)) = e.get_mut() {
let mut crate_types_to_add = CRATE_TYPES.to_vec();
for t in types.iter() {
// type is already in the manifest, skip adding it
if let Some(i) = crate_types_to_add
.iter()
.position(|ty| Some(ty) == t.as_str().as_ref())
{
crate_types_to_add.remove(i);
.get_mut("lib")
.and_then(|l| l.as_table_mut())
{
match lib.entry("crate-type") {
Entry::Occupied(mut e) => {
if let Item::Value(Value::Array(types)) = e.get_mut() {
let mut crate_types_to_add = CRATE_TYPES.to_vec();
for t in types.iter() {
// type is already in the manifest, skip adding it
if let Some(i) = crate_types_to_add
.iter()
.position(|ty| Some(ty) == t.as_str().as_ref())
{
crate_types_to_add.remove(i);
}
}
for t in crate_types_to_add {
types.push(t);
}
}
for t in crate_types_to_add {
types.push(t);
}
}
}
Entry::Vacant(e) => {
let mut arr = toml_edit::Array::new();
arr.extend(CRATE_TYPES.to_vec());
e.insert(Item::Value(arr.into()));
Entry::Vacant(e) => {
let mut arr = toml_edit::Array::new();
arr.extend(CRATE_TYPES.to_vec());
e.insert(Item::Value(arr.into()));
}
}
}
@ -265,35 +265,6 @@ mod tests {
}
}
fn migrate_lib(toml: &str) {
let mut manifest = toml.parse::<toml_edit::Document>().expect("invalid toml");
super::migrate_manifest(&mut manifest).expect("failed to migrate manifest");
let lib = manifest
.as_table()
.get("lib")
.expect("missing manifest lib")
.as_table()
.expect("manifest lib isn't a table");
let crate_types = lib
.get("crate-type")
.expect("missing lib crate-type")
.as_array()
.expect("crate-type must be an array");
let mut not_added_crate_types = super::CRATE_TYPES.to_vec();
for t in crate_types {
let t = t.as_str().expect("crate-type must be a string");
if let Some(i) = not_added_crate_types.iter().position(|ty| ty == &t) {
not_added_crate_types.remove(i);
}
}
assert!(
not_added_crate_types.is_empty(),
"missing crate-type: {not_added_crate_types:?}"
);
}
#[test]
fn migrate_table() {
migrate_deps(|features| {
@ -332,22 +303,32 @@ mod tests {
})
}
#[test]
fn migrate_missing_lib() {
migrate_lib("[dependencies]");
}
#[test]
fn migrate_missing_crate_types() {
migrate_lib("[lib]");
}
#[test]
fn migrate_add_crate_types() {
migrate_lib(
r#"
let toml = r#"
[lib]
crate-type = ["something"]"#,
);
crate-type = ["something"]"#;
let mut manifest = toml.parse::<toml_edit::Document>().expect("invalid toml");
super::migrate_manifest(&mut manifest).expect("failed to migrate manifest");
if let Some(crate_types) = manifest
.as_table()
.get("lib")
.and_then(|l| l.get("crate-type"))
.and_then(|c| c.as_array())
{
let mut not_added_crate_types = super::CRATE_TYPES.to_vec();
for t in crate_types {
let t = t.as_str().expect("crate-type must be a string");
if let Some(i) = not_added_crate_types.iter().position(|ty| ty == &t) {
not_added_crate_types.remove(i);
}
}
assert!(
not_added_crate_types.is_empty(),
"missing crate-type: {not_added_crate_types:?}"
);
}
}
}

View File

@ -15,9 +15,19 @@ pub fn command() -> Result<()> {
let tauri_dir = tauri_dir();
let app_dir = app_dir();
config::migrate(&tauri_dir)?;
let migrated = config::migrate(&tauri_dir)?;
manifest::migrate(&tauri_dir)?;
frontend::migrate(app_dir, &tauri_dir)?;
// Add plugins
for plugin in migrated.plugins {
crate::add::command(crate::add::Options {
plugin,
branch: None,
tag: None,
rev: None,
})?
}
Ok(())
}