Skip to content

Commit

Permalink
refactor: move plugin functionality from tauri-build to tauri-plugin (#…
Browse files Browse the repository at this point in the history
…8737)

* refactor: move plugin functionality from tauri-build to tauri-plugin

* fixes

* fix build

* move docs function

* autogenerated

* fix path
  • Loading branch information
lucasfernog committed Feb 3, 2024
1 parent 63d6d47 commit 0cdfda2
Show file tree
Hide file tree
Showing 35 changed files with 1,460 additions and 3,838 deletions.
2 changes: 1 addition & 1 deletion .changes/config.json
Expand Up @@ -217,7 +217,7 @@
"path": "./core/tauri-plugin",
"manager": "rust",
"dependencies": [
"tauri"
"tauri-utils"
],
"postversion": "node ../../.scripts/covector/sync-cli-metadata.js ${ pkg.pkg } ${ release.type }"
},
Expand Down
5 changes: 5 additions & 0 deletions .changes/move-tauri-build-plugin-fns.md
@@ -0,0 +1,5 @@
---
"tauri-build": patch:breaking
---

Moved `mobile::PluginBuilder`, `mobile::update_entitlements`, `config::plugin_config` and `mobile::update_android_manifest` to the new `tauri-plugin` crate.
4 changes: 0 additions & 4 deletions core/tauri-build/Cargo.toml
Expand Up @@ -43,10 +43,6 @@ glob = "0.3"
toml = "0.8"
schemars = { version = "0.8", features = [ "preserve_order" ] }

[target."cfg(target_os = \"macos\")".dependencies]
swift-rs = { version = "1.0.6", features = [ "build" ] }
plist = "1"

[features]
default = [ "config-json" ]
codegen = [ "tauri-codegen", "quote" ]
Expand Down
22 changes: 0 additions & 22 deletions core/tauri-build/src/config.rs

This file was deleted.

5 changes: 1 addition & 4 deletions core/tauri-build/src/lib.rs
Expand Up @@ -32,11 +32,8 @@ use std::{
mod acl;
#[cfg(feature = "codegen")]
mod codegen;
/// Tauri configuration functions.
pub mod config;
mod manifest;
/// Mobile build functions.
pub mod mobile;
mod mobile;
mod static_vcruntime;

#[cfg(feature = "codegen")]
Expand Down
269 changes: 2 additions & 267 deletions core/tauri-build/src/mobile.rs
Expand Up @@ -2,242 +2,11 @@
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT

use std::{
env::{var, var_os},
fs::{copy, create_dir, create_dir_all, read_to_string, remove_dir_all, write},
path::{Path, PathBuf},
};
use std::{fs::write, path::PathBuf};

use anyhow::{Context, Result};
use serde::{Deserialize, Serialize};

#[derive(Debug, Default, Deserialize, Serialize, Eq, PartialEq)]
pub(crate) struct PluginMetadata {
pub path: PathBuf,
}

#[derive(Default)]
pub struct PluginBuilder {
android_path: Option<PathBuf>,
ios_path: Option<PathBuf>,
}

impl PluginBuilder {
/// Creates a new builder for mobile plugin functionality.
pub fn new() -> Self {
Self::default()
}

/// Sets the Android project path.
pub fn android_path<P: Into<PathBuf>>(mut self, android_path: P) -> Self {
self.android_path.replace(android_path.into());
self
}

/// Sets the iOS project path.
pub fn ios_path<P: Into<PathBuf>>(mut self, ios_path: P) -> Self {
self.ios_path.replace(ios_path.into());
self
}

/// Injects the mobile templates in the given path relative to the manifest root.
pub fn run(self) -> Result<()> {
let target_os = var("CARGO_CFG_TARGET_OS").unwrap();
let mobile = target_os == "android" || target_os == "ios";
crate::cfg_alias("mobile", mobile);
crate::cfg_alias("desktop", !mobile);

match target_os.as_str() {
"android" => {
if let Some(path) = self.android_path {
let manifest_dir = var_os("CARGO_MANIFEST_DIR").map(PathBuf::from).unwrap();
let source = manifest_dir.join(path);

let tauri_library_path = std::env::var("DEP_TAURI_ANDROID_LIBRARY_PATH")
.expect("missing `DEP_TAURI_ANDROID_LIBRARY_PATH` environment variable. Make sure `tauri` is a dependency of the plugin.");
println!("cargo:rerun-if-env-changed=DEP_TAURI_ANDROID_LIBRARY_PATH");

create_dir_all(source.join(".tauri")).context("failed to create .tauri directory")?;
copy_folder(
Path::new(&tauri_library_path),
&source.join(".tauri").join("tauri-api"),
&[],
)
.context("failed to copy tauri-api to the plugin project")?;

println!("cargo:android_library_path={}", source.display());
}
}
#[cfg(target_os = "macos")]
"ios" => {
if let Some(path) = self.ios_path {
let manifest_dir = var_os("CARGO_MANIFEST_DIR").map(PathBuf::from).unwrap();
let tauri_library_path = std::env::var("DEP_TAURI_IOS_LIBRARY_PATH")
.expect("missing `DEP_TAURI_IOS_LIBRARY_PATH` environment variable. Make sure `tauri` is a dependency of the plugin.");

let tauri_dep_path = path.parent().unwrap().join(".tauri");
create_dir_all(&tauri_dep_path).context("failed to create .tauri directory")?;
copy_folder(
Path::new(&tauri_library_path),
&tauri_dep_path.join("tauri-api"),
&[".build", "Package.resolved", "Tests"],
)
.context("failed to copy tauri-api to the plugin project")?;
link_swift_library(&var("CARGO_PKG_NAME").unwrap(), manifest_dir.join(path));
}
}
_ => (),
}

Ok(())
}
}

#[cfg(target_os = "macos")]
#[doc(hidden)]
pub fn link_swift_library(name: &str, source: impl AsRef<Path>) {
let source = source.as_ref();

let sdk_root = std::env::var_os("SDKROOT");
std::env::remove_var("SDKROOT");

swift_rs::SwiftLinker::new(
&std::env::var("MACOSX_DEPLOYMENT_TARGET").unwrap_or_else(|_| "10.13".into()),
)
.with_ios(&std::env::var("IPHONEOS_DEPLOYMENT_TARGET").unwrap_or_else(|_| "13.0".into()))
.with_package(name, source)
.link();

if let Some(root) = sdk_root {
std::env::set_var("SDKROOT", root);
}
}

fn copy_folder(source: &Path, target: &Path, ignore_paths: &[&str]) -> Result<()> {
let _ = remove_dir_all(target);

for entry in walkdir::WalkDir::new(source) {
let entry = entry?;
let rel_path = entry.path().strip_prefix(source)?;
let rel_path_str = rel_path.to_string_lossy();
if ignore_paths
.iter()
.any(|path| rel_path_str.starts_with(path))
{
continue;
}
let dest_path = target.join(rel_path);

if entry.file_type().is_dir() {
create_dir(&dest_path)
.with_context(|| format!("failed to create directory {}", dest_path.display()))?;
} else {
copy(entry.path(), &dest_path).with_context(|| {
format!(
"failed to copy {} to {}",
entry.path().display(),
dest_path.display()
)
})?;
println!("cargo:rerun-if-changed={}", entry.path().display());
}
}

Ok(())
}

#[cfg(target_os = "macos")]
fn update_plist_file<P: AsRef<Path>, F: FnOnce(&mut plist::Dictionary)>(
path: P,
f: F,
) -> Result<()> {
use std::io::Cursor;

let path = path.as_ref();
if path.exists() {
let plist_str = read_to_string(path)?;
let mut plist = plist::Value::from_reader(Cursor::new(&plist_str))?;
if let Some(dict) = plist.as_dictionary_mut() {
f(dict);
let mut plist_buf = Vec::new();
let writer = Cursor::new(&mut plist_buf);
plist::to_writer_xml(writer, &plist)?;
let new_plist_str = String::from_utf8(plist_buf)?;
if new_plist_str != plist_str {
write(path, new_plist_str)?;
}
}
}

Ok(())
}

#[cfg(target_os = "macos")]
pub fn update_entitlements<F: FnOnce(&mut plist::Dictionary)>(f: F) -> Result<()> {
if let (Some(project_path), Ok(app_name)) = (
var_os("TAURI_IOS_PROJECT_PATH").map(PathBuf::from),
var("TAURI_IOS_APP_NAME"),
) {
update_plist_file(
project_path
.join(format!("{app_name}_iOS"))
.join(format!("{app_name}_iOS.entitlements")),
f,
)?;
}

Ok(())
}

fn xml_block_comment(id: &str) -> String {
format!("<!-- {id}. AUTO-GENERATED. DO NOT REMOVE. -->")
}

fn insert_into_xml(xml: &str, block_identifier: &str, parent_tag: &str, contents: &str) -> String {
let block_comment = xml_block_comment(block_identifier);

let mut rewritten = Vec::new();
let mut found_block = false;
let parent_closing_tag = format!("</{parent_tag}>");
for line in xml.split('\n') {
if line.contains(&block_comment) {
found_block = !found_block;
continue;
}

// found previous block which should be removed
if found_block {
continue;
}

if let Some(index) = line.find(&parent_closing_tag) {
let identation = " ".repeat(index + 4);
rewritten.push(format!("{}{}", identation, block_comment));
for l in contents.split('\n') {
rewritten.push(format!("{}{}", identation, l));
}
rewritten.push(format!("{}{}", identation, block_comment));
}

rewritten.push(line.to_string());
}

rewritten.join("\n")
}

pub fn update_android_manifest(block_identifier: &str, parent: &str, insert: String) -> Result<()> {
if let Some(project_path) = var_os("TAURI_ANDROID_PROJECT_PATH").map(PathBuf::from) {
let manifest_path = project_path.join("app/src/main/AndroidManifest.xml");
let manifest = read_to_string(&manifest_path)?;
let rewritten = insert_into_xml(&manifest, block_identifier, parent, &insert);
if rewritten != manifest {
write(manifest_path, rewritten)?;
}
}
Ok(())
}

pub(crate) fn generate_gradle_files(project_dir: PathBuf) -> Result<()> {
pub fn generate_gradle_files(project_dir: PathBuf) -> Result<()> {
let gradle_settings_path = project_dir.join("tauri.settings.gradle");
let app_build_gradle_path = project_dir.join("app").join("tauri.build.gradle.kts");

Expand Down Expand Up @@ -289,37 +58,3 @@ dependencies {"

Ok(())
}

#[cfg(test)]
mod tests {
#[test]
fn insert_into_xml() {
let manifest = r#"<manifest>
<application>
<intent-filter>
</intent-filter>
</application>
</manifest>"#;
let id = "tauritest";
let new = super::insert_into_xml(manifest, id, "application", "<something></something>");

let block_id_comment = super::xml_block_comment(id);
let expected = format!(
r#"<manifest>
<application>
<intent-filter>
</intent-filter>
{block_id_comment}
<something></something>
{block_id_comment}
</application>
</manifest>"#
);

assert_eq!(new, expected);

// assert it's still the same after an empty update
let new = super::insert_into_xml(&expected, id, "application", "<something></something>");
assert_eq!(new, expected);
}
}
12 changes: 9 additions & 3 deletions core/tauri-plugin/Cargo.toml
Expand Up @@ -11,22 +11,28 @@ rust-version = { workspace = true }

[features]
build = [
"dep:anyhow",
"dep:serde",
"dep:cargo_metadata",
"dep:serde_json",
"dep:glob",
"dep:toml",
"dep:plist",
"dep:walkdir",
]
runtime = []

[dependencies]
anyhow = { version = "1", optional = true }
serde = { version = "1", optional = true }
cargo_metadata = { version = "0.18", optional = true }
tauri = { version = "2.0.0-alpha.20", default-features = false, path = "../tauri" }
tauri-utils = { version = "2.0.0-alpha.13", default-features = false, path = "../tauri-utils" }
serde_json = { version = "1", optional = true }
glob = { version = "0.3", optional = true }
toml = { version = "0.8", optional = true }
schemars = { version = "0.8", features = [ "preserve_order" ] }
walkdir = { version = "1", optional = true }

[target."cfg(target_os = \"macos\")".dependencies]
plist = { version = "1", optional = true }

[package.metadata.docs.rs]
features = ["build", "runtime"]
Expand Down

0 comments on commit 0cdfda2

Please sign in to comment.