refactor(cli): improve security of android dev/build (#5043)

This commit is contained in:
Lucas Fernandes Nogueira 2022-08-25 15:30:05 -03:00 committed by GitHub
parent 4a5f2ec1ae
commit 927ccc465d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 341 additions and 74 deletions

View File

@ -4222,7 +4222,7 @@ dependencies = [
[[package]] [[package]]
name = "wry" name = "wry"
version = "0.20.2" version = "0.20.2"
source = "git+https://github.com/tauri-apps/wry?branch=dev#b1e8560c3f13f2674528f6ca440ba476ddbef7c2" source = "git+https://github.com/tauri-apps/wry?branch=dev#83b6a8d06be8b1687296d2dfb4daeff3cc587714"
dependencies = [ dependencies = [
"block", "block",
"cocoa", "cocoa",

218
tooling/cli/Cargo.lock generated
View File

@ -85,6 +85,29 @@ version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b"
[[package]]
name = "async-channel"
version = "1.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e14485364214912d3b19cc3435dde4df66065127f05fa0d75c712f36f12c2f28"
dependencies = [
"concurrent-queue",
"event-listener",
"futures-core",
]
[[package]]
name = "async-task"
version = "4.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a40729d2133846d9ed0ea60a8b9541bccddab49cd30f0715a1da672fe9a2524"
[[package]]
name = "atomic-waker"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "065374052e7df7ee4047b1160cca5e1467a12351a40b3da123c870ba0b8eda2a"
[[package]] [[package]]
name = "attohttpc" name = "attohttpc"
version = "0.22.0" version = "0.22.0"
@ -187,6 +210,20 @@ dependencies = [
"byte-tools", "byte-tools",
] ]
[[package]]
name = "blocking"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c6ccb65d468978a086b69884437ded69a90faab3bbe6e67f242173ea728acccc"
dependencies = [
"async-channel",
"async-task",
"atomic-waker",
"fastrand",
"futures-lite",
"once_cell",
]
[[package]] [[package]]
name = "bstr" name = "bstr"
version = "0.2.17" version = "0.2.17"
@ -247,6 +284,12 @@ dependencies = [
"pkg-config", "pkg-config",
] ]
[[package]]
name = "cache-padded"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c1db59621ec70f09c5e9b597b220c7a2b43611f4710dc03ceb8748637775692c"
[[package]] [[package]]
name = "cargo-mobile" name = "cargo-mobile"
version = "0.1.0" version = "0.1.0"
@ -444,6 +487,15 @@ dependencies = [
"memchr", "memchr",
] ]
[[package]]
name = "concurrent-queue"
version = "1.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "af4780a44ab5696ea9e28294517f1fffb421a83a25af521333c838635509db9c"
dependencies = [
"cache-padded",
]
[[package]] [[package]]
name = "console" name = "console"
version = "0.15.0" version = "0.15.0"
@ -979,6 +1031,12 @@ dependencies = [
"libc", "libc",
] ]
[[package]]
name = "event-listener"
version = "2.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0"
[[package]] [[package]]
name = "exr" name = "exr"
version = "1.4.2" version = "1.4.2"
@ -1132,16 +1190,108 @@ dependencies = [
] ]
[[package]] [[package]]
name = "futures-core" name = "futures"
version = "0.3.21" version = "0.3.23"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0c09fd04b7e4073ac7156a9539b57a484a8ea920f79c7c675d05d289ab6110d3" checksum = "ab30e97ab6aacfe635fad58f22c2bb06c8b685f7421eb1e064a729e2a5f481fa"
dependencies = [
"futures-channel",
"futures-core",
"futures-executor",
"futures-io",
"futures-sink",
"futures-task",
"futures-util",
]
[[package]]
name = "futures-channel"
version = "0.3.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2bfc52cbddcfd745bf1740338492bb0bd83d76c67b445f91c5fb29fae29ecaa1"
dependencies = [
"futures-core",
"futures-sink",
]
[[package]]
name = "futures-core"
version = "0.3.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d2acedae88d38235936c3922476b10fced7b2b68136f5e3c03c2d5be348a1115"
[[package]]
name = "futures-executor"
version = "0.3.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d11aa21b5b587a64682c0094c2bdd4df0076c5324961a40cc3abd7f37930528"
dependencies = [
"futures-core",
"futures-task",
"futures-util",
]
[[package]]
name = "futures-io"
version = "0.3.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "93a66fc6d035a26a3ae255a6d2bca35eda63ae4c5512bef54449113f7a1228e5"
[[package]]
name = "futures-lite"
version = "1.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7694489acd39452c77daa48516b894c153f192c3578d5a839b62c58099fcbf48"
dependencies = [
"fastrand",
"futures-core",
"futures-io",
"memchr",
"parking",
"pin-project-lite",
"waker-fn",
]
[[package]]
name = "futures-macro"
version = "0.3.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0db9cce532b0eae2ccf2766ab246f114b56b9cf6d445e00c2549fbc100ca045d"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]] [[package]]
name = "futures-sink" name = "futures-sink"
version = "0.3.21" version = "0.3.23"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "21163e139fa306126e6eedaf49ecdb4588f939600f0b1e770f4205ee4b7fa868" checksum = "ca0bae1fe9752cf7fd9b0064c674ae63f97b37bc714d745cbde0afb7ec4e6765"
[[package]]
name = "futures-task"
version = "0.3.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "842fc63b931f4056a24d59de13fb1272134ce261816e063e634ad0c15cdc5306"
[[package]]
name = "futures-util"
version = "0.3.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0828a5471e340229c11c77ca80017937ce3c58cb788a17e5f1c2d5c485a9577"
dependencies = [
"futures-channel",
"futures-core",
"futures-io",
"futures-macro",
"futures-sink",
"futures-task",
"memchr",
"pin-project-lite",
"pin-utils",
"slab",
]
[[package]] [[package]]
name = "fxhash" name = "fxhash"
@ -1494,6 +1644,29 @@ dependencies = [
"cfg-if 1.0.0", "cfg-if 1.0.0",
] ]
[[package]]
name = "interprocess"
version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1c58ec7fbda1df9a93f587b780659db3c99f61f4be27f9c82c9b37684ffd0366"
dependencies = [
"blocking",
"cfg-if 1.0.0",
"futures",
"intmap",
"libc",
"once_cell",
"spinning",
"thiserror",
"winapi 0.3.9",
]
[[package]]
name = "intmap"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ae52f28f45ac2bc96edb7714de995cffc174a395fb0abf5bff453587c980d7b9"
[[package]] [[package]]
name = "io-lifetimes" name = "io-lifetimes"
version = "0.7.2" version = "0.7.2"
@ -2184,6 +2357,12 @@ version = "6.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "21326818e99cfe6ce1e524c2a805c189a99b5ae555a35d19f9a284b427d86afa" checksum = "21326818e99cfe6ce1e524c2a805c189a99b5ae555a35d19f9a284b427d86afa"
[[package]]
name = "parking"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "427c3892f9e783d91cc128285287e70a59e206ca452770ece88a76f7a3eddd72"
[[package]] [[package]]
name = "parking_lot" name = "parking_lot"
version = "0.12.1" version = "0.12.1"
@ -2409,6 +2588,18 @@ dependencies = [
"syn", "syn",
] ]
[[package]]
name = "pin-project-lite"
version = "0.2.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116"
[[package]]
name = "pin-utils"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
[[package]] [[package]]
name = "pkg-config" name = "pkg-config"
version = "0.3.25" version = "0.3.25"
@ -3120,6 +3311,15 @@ dependencies = [
"lock_api", "lock_api",
] ]
[[package]]
name = "spinning"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2d4f0e86297cad2658d92a707320d87bf4e6ae1050287f51d19b67ef3f153a7b"
dependencies = [
"lock_api",
]
[[package]] [[package]]
name = "stable_deref_trait" name = "stable_deref_trait"
version = "1.2.0" version = "1.2.0"
@ -3305,13 +3505,13 @@ dependencies = [
"colored 2.0.0", "colored 2.0.0",
"ctrlc", "ctrlc",
"dialoguer", "dialoguer",
"dirs-next",
"env_logger 0.9.0", "env_logger 0.9.0",
"glob", "glob",
"handlebars 4.3.1", "handlebars 4.3.1",
"heck 0.4.0", "heck 0.4.0",
"ignore", "ignore",
"include_dir", "include_dir",
"interprocess",
"json-patch", "json-patch",
"lazy_static", "lazy_static",
"libc", "libc",
@ -3798,6 +3998,12 @@ dependencies = [
"libc", "libc",
] ]
[[package]]
name = "waker-fn"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9d5b2c62b4012a3e1eca5a7e077d13b3bf498c4073e33ccd58626607748ceeca"
[[package]] [[package]]
name = "walkdir" name = "walkdir"
version = "2.3.2" version = "2.3.2"

View File

@ -30,7 +30,7 @@ path = "src/main.rs"
# cargo-mobile = { path = "../../../cargo-mobile/", default-features = false } # cargo-mobile = { path = "../../../cargo-mobile/", default-features = false }
cargo-mobile = { git = "https://github.com/tauri-apps/cargo-mobile", branch = "dev", default-features = false } cargo-mobile = { git = "https://github.com/tauri-apps/cargo-mobile", branch = "dev", default-features = false }
textwrap = { version = "0.11.0", features = ["term_size"] } textwrap = { version = "0.11.0", features = ["term_size"] }
dirs-next = "2.0" interprocess = "1"
thiserror = "1" thiserror = "1"
clap = { version = "3.2", features = [ "derive" ] } clap = { version = "3.2", features = [ "derive" ] }
anyhow = "1.0" anyhow = "1.0"

View File

@ -21,7 +21,7 @@ use clap::{Parser, Subcommand};
use super::{ use super::{
ensure_init, get_config, ensure_init, get_config,
init::{command as init_command, init_dot_cargo, Options as InitOptions}, init::{command as init_command, init_dot_cargo, Options as InitOptions},
log_finished, Target as MobileTarget, log_finished, read_options, CliOptions, Target as MobileTarget,
}; };
use crate::{helpers::config::get as get_tauri_config, Result}; use crate::{helpers::config::get as get_tauri_config, Result};
@ -96,6 +96,7 @@ pub fn command(cli: Cli) -> Result<()> {
} }
fn with_config<T>( fn with_config<T>(
cli_options: Option<CliOptions>,
f: impl FnOnce(&Config, &AndroidConfig, &AndroidMetadata) -> Result<T, Error>, f: impl FnOnce(&Config, &AndroidConfig, &AndroidMetadata) -> Result<T, Error>,
) -> Result<T, Error> { ) -> Result<T, Error> {
let (config, metadata) = { let (config, metadata) = {
@ -103,7 +104,10 @@ fn with_config<T>(
get_tauri_config(None).map_err(|e| Error::InvalidTauriConfig(e.to_string()))?; get_tauri_config(None).map_err(|e| Error::InvalidTauriConfig(e.to_string()))?;
let tauri_config_guard = tauri_config.lock().unwrap(); let tauri_config_guard = tauri_config.lock().unwrap();
let tauri_config_ = tauri_config_guard.as_ref().unwrap(); let tauri_config_ = tauri_config_guard.as_ref().unwrap();
get_config(tauri_config_) get_config(
tauri_config_,
cli_options.unwrap_or_else(|| read_options(tauri_config_, MobileTarget::Android)),
)
}; };
f(&config, config.android(), metadata.android()) f(&config, config.android(), metadata.android())
} }
@ -152,3 +156,13 @@ fn device_prompt<'a>(env: &'_ Env) -> Result<Device<'a>, PromptError<adb::device
fn detect_target_ok<'a>(env: &Env) -> Option<&'a Target<'a>> { fn detect_target_ok<'a>(env: &Env) -> Option<&'a Target<'a>> {
device_prompt(env).map(|device| device.target()).ok() device_prompt(env).map(|device| device.target()).ok()
} }
fn open_and_wait(config: &AndroidConfig) -> ! {
log::info!("Opening Android Studio");
if let Err(e) = os::open_file_with("Android Studio", config.project_dir()) {
log::error!("{}", e);
}
loop {
std::thread::sleep(std::time::Duration::from_secs(24 * 60 * 60));
}
}

View File

@ -33,7 +33,7 @@ pub fn command(options: Options) -> Result<()> {
}; };
let noise_level = NoiseLevel::Polite; let noise_level = NoiseLevel::Polite;
with_config(|root_conf, config, metadata| { with_config(None, |root_conf, config, metadata| {
ensure_init(config.project_dir(), MobileTarget::Android) ensure_init(config.project_dir(), MobileTarget::Android)
.map_err(|e| Error::ProjectNotInitialized(e.to_string()))?; .map_err(|e| Error::ProjectNotInitialized(e.to_string()))?;

View File

@ -1,6 +1,6 @@
use super::{ use super::{
delete_codegen_vars, ensure_init, env, init_dot_cargo, log_finished, with_config, Error, delete_codegen_vars, ensure_init, env, init_dot_cargo, log_finished, open_and_wait, with_config,
MobileTarget, Error, MobileTarget,
}; };
use crate::{ use crate::{
helpers::{config::get as get_tauri_config, flock}, helpers::{config::get as get_tauri_config, flock},
@ -48,6 +48,9 @@ pub struct Options {
/// Build AABs. /// Build AABs.
#[clap(long)] #[clap(long)]
pub aab: bool, pub aab: bool,
/// Open Android Studio
#[clap(short, long)]
pub open: bool,
} }
impl From<Options> for crate::build::Options { impl From<Options> for crate::build::Options {
@ -66,7 +69,7 @@ impl From<Options> for crate::build::Options {
pub fn command(options: Options) -> Result<()> { pub fn command(options: Options) -> Result<()> {
delete_codegen_vars(); delete_codegen_vars();
with_config(|root_conf, config, _metadata| { with_config(Some(Default::default()), |root_conf, config, _metadata| {
set_var("WRY_RUSTWEBVIEWCLIENT_CLASS_EXTENSION", ""); set_var("WRY_RUSTWEBVIEWCLIENT_CLASS_EXTENSION", "");
set_var("WRY_RUSTWEBVIEW_CLASS_INIT", ""); set_var("WRY_RUSTWEBVIEW_CLASS_INIT", "");
@ -76,7 +79,14 @@ pub fn command(options: Options) -> Result<()> {
let env = env()?; let env = env()?;
init_dot_cargo(root_conf, Some(&env)).map_err(Error::InitDotCargo)?; init_dot_cargo(root_conf, Some(&env)).map_err(Error::InitDotCargo)?;
run_build(options, config, env).map_err(|e| Error::BuildFailed(format!("{:#}", e))) let open = options.open;
run_build(options, config, env).map_err(|e| Error::BuildFailed(format!("{:#}", e)))?;
if open {
open_and_wait(config);
}
Ok(())
}) })
.map_err(Into::into) .map_err(Into::into)
} }

View File

@ -1,6 +1,6 @@
use super::{ use super::{
delete_codegen_vars, device_prompt, ensure_init, env, init_dot_cargo, with_config, Error, delete_codegen_vars, device_prompt, ensure_init, env, init_dot_cargo, open_and_wait, with_config,
MobileTarget, Error, MobileTarget,
}; };
use crate::{ use crate::{
helpers::{config::get as get_tauri_config, flock}, helpers::{config::get as get_tauri_config, flock},
@ -14,7 +14,6 @@ use cargo_mobile::{
android::config::{Config as AndroidConfig, Metadata as AndroidMetadata}, android::config::{Config as AndroidConfig, Metadata as AndroidMetadata},
config::Config, config::Config,
opts::{NoiseLevel, Profile}, opts::{NoiseLevel, Profile},
os,
}; };
use std::env::set_var; use std::env::set_var;
@ -65,7 +64,7 @@ impl From<Options> for crate::dev::Options {
pub fn command(options: Options) -> Result<()> { pub fn command(options: Options) -> Result<()> {
delete_codegen_vars(); delete_codegen_vars();
with_config(|root_conf, config, metadata| { with_config(Some(Default::default()), |root_conf, config, metadata| {
set_var( set_var(
"WRY_RUSTWEBVIEWCLIENT_CLASS_EXTENSION", "WRY_RUSTWEBVIEWCLIENT_CLASS_EXTENSION",
WEBVIEW_CLIENT_CLASS_EXTENSION, WEBVIEW_CLIENT_CLASS_EXTENSION,
@ -120,13 +119,13 @@ fn run_dev(
write_options(cli_options, &bundle_identifier, MobileTarget::Android)?; write_options(cli_options, &bundle_identifier, MobileTarget::Android)?;
if open { if open {
open_dev(config) open_and_wait(config)
} else { } else {
match run(options, root_conf, config, metadata) { match run(options, root_conf, config, metadata) {
Ok(c) => Ok(Box::new(c) as Box<dyn DevProcess>), Ok(c) => Ok(Box::new(c) as Box<dyn DevProcess>),
Err(Error::FailedToPromptForDevice(e)) => { Err(Error::FailedToPromptForDevice(e)) => {
log::error!("{}", e); log::error!("{}", e);
open_dev(config) open_and_wait(config)
} }
Err(e) => Err(e.into()), Err(e) => Err(e.into()),
} }
@ -135,16 +134,6 @@ fn run_dev(
) )
} }
fn open_dev(config: &AndroidConfig) -> ! {
log::info!("Opening Android Studio");
if let Err(e) = os::open_file_with("Android Studio", config.project_dir()) {
log::error!("{}", e);
}
loop {
std::thread::sleep(std::time::Duration::from_secs(24 * 60 * 60));
}
}
fn run( fn run(
options: MobileOptions, options: MobileOptions,
root_conf: &Config, root_conf: &Config,

View File

@ -3,7 +3,7 @@ use crate::Result;
use cargo_mobile::os; use cargo_mobile::os;
pub fn command() -> Result<()> { pub fn command() -> Result<()> {
with_config(|_, config, _metadata| { with_config(Some(Default::default()), |_, config, _metadata| {
ensure_init(config.project_dir(), MobileTarget::Android) ensure_init(config.project_dir(), MobileTarget::Android)
.map_err(|e| Error::ProjectNotInitialized(e.to_string()))?; .map_err(|e| Error::ProjectNotInitialized(e.to_string()))?;
os::open_file_with("Android Studio", config.project_dir()).map_err(Error::OpenFailed) os::open_file_with("Android Studio", config.project_dir()).map_err(Error::OpenFailed)

View File

@ -107,7 +107,7 @@ pub fn exec(
let tauri_config_guard = tauri_config.lock().unwrap(); let tauri_config_guard = tauri_config.lock().unwrap();
let tauri_config_ = tauri_config_guard.as_ref().unwrap(); let tauri_config_ = tauri_config_guard.as_ref().unwrap();
let (config, metadata) = get_config(tauri_config_); let (config, metadata) = get_config(tauri_config_, Default::default());
let asset_dir = config.app().asset_dir(); let asset_dir = config.app().asset_dir();
if !asset_dir.is_dir() { if !asset_dir.is_dir() {

View File

@ -20,7 +20,7 @@ use clap::{Parser, Subcommand};
use super::{ use super::{
ensure_init, env, get_config, ensure_init, env, get_config,
init::{command as init_command, init_dot_cargo, Options as InitOptions}, init::{command as init_command, init_dot_cargo, Options as InitOptions},
log_finished, Target as MobileTarget, log_finished, read_options, CliOptions, Target as MobileTarget,
}; };
use crate::{helpers::config::get as get_tauri_config, Result}; use crate::{helpers::config::get as get_tauri_config, Result};
@ -104,6 +104,7 @@ pub fn command(cli: Cli) -> Result<()> {
} }
fn with_config<T>( fn with_config<T>(
cli_options: Option<CliOptions>,
f: impl FnOnce(&Config, &AppleConfig, &AppleMetadata) -> Result<T, Error>, f: impl FnOnce(&Config, &AppleConfig, &AppleMetadata) -> Result<T, Error>,
) -> Result<T, Error> { ) -> Result<T, Error> {
let (config, metadata) = { let (config, metadata) = {
@ -111,7 +112,10 @@ fn with_config<T>(
get_tauri_config(None).map_err(|e| Error::InvalidTauriConfig(e.to_string()))?; get_tauri_config(None).map_err(|e| Error::InvalidTauriConfig(e.to_string()))?;
let tauri_config_guard = tauri_config.lock().unwrap(); let tauri_config_guard = tauri_config.lock().unwrap();
let tauri_config_ = tauri_config_guard.as_ref().unwrap(); let tauri_config_ = tauri_config_guard.as_ref().unwrap();
get_config(tauri_config_) get_config(
tauri_config_,
cli_options.unwrap_or_else(|| read_options(tauri_config_, MobileTarget::Ios)),
)
}; };
f(&config, config.apple(), metadata.apple()) f(&config, config.apple(), metadata.apple())
} }
@ -147,3 +151,13 @@ fn device_prompt<'a>(env: &'_ Env) -> Result<Device<'a>, PromptError<ios_deploy:
fn detect_target_ok<'a>(env: &Env) -> Option<&'a Target<'a>> { fn detect_target_ok<'a>(env: &Env) -> Option<&'a Target<'a>> {
device_prompt(env).map(|device| device.target()).ok() device_prompt(env).map(|device| device.target()).ok()
} }
fn open_and_wait(config: &AppleConfig) -> ! {
log::info!("Opening Xcode");
if let Err(e) = os::open_file_with("Xcode", config.project_dir()) {
log::error!("{}", e);
}
loop {
std::thread::sleep(std::time::Duration::from_secs(24 * 60 * 60));
}
}

View File

@ -1,6 +1,6 @@
use super::{ use super::{
detect_target_ok, ensure_init, env, init_dot_cargo, log_finished, with_config, Error, detect_target_ok, ensure_init, env, init_dot_cargo, log_finished, open_and_wait, with_config,
MobileTarget, Error, MobileTarget,
}; };
use crate::{ use crate::{
helpers::{config::get as get_tauri_config, flock}, helpers::{config::get as get_tauri_config, flock},
@ -44,6 +44,9 @@ pub struct Options {
/// Build number to append to the app version. /// Build number to append to the app version.
#[clap(long)] #[clap(long)]
pub build_number: Option<u32>, pub build_number: Option<u32>,
/// Open Xcode
#[clap(short, long)]
pub open: bool,
} }
impl From<Options> for crate::build::Options { impl From<Options> for crate::build::Options {
@ -61,14 +64,21 @@ impl From<Options> for crate::build::Options {
} }
pub fn command(options: Options) -> Result<()> { pub fn command(options: Options) -> Result<()> {
with_config(|root_conf, config, _metadata| { with_config(Some(Default::default()), |root_conf, config, _metadata| {
ensure_init(config.project_dir(), MobileTarget::Ios) ensure_init(config.project_dir(), MobileTarget::Ios)
.map_err(|e| Error::ProjectNotInitialized(e.to_string()))?; .map_err(|e| Error::ProjectNotInitialized(e.to_string()))?;
let env = env()?; let env = env()?;
init_dot_cargo(root_conf, None).map_err(Error::InitDotCargo)?; init_dot_cargo(root_conf, None).map_err(Error::InitDotCargo)?;
run_build(options, config, env).map_err(|e| Error::BuildFailed(format!("{:#}", e))) let open = options.open;
run_build(options, config, env).map_err(|e| Error::BuildFailed(format!("{:#}", e)))?;
if open {
open_and_wait(config);
}
Ok(())
}) })
.map_err(Into::into) .map_err(Into::into)
} }

View File

@ -1,4 +1,6 @@
use super::{device_prompt, ensure_init, env, init_dot_cargo, with_config, Error, MobileTarget}; use super::{
device_prompt, ensure_init, env, init_dot_cargo, open_and_wait, with_config, Error, MobileTarget,
};
use crate::{ use crate::{
helpers::{config::get as get_tauri_config, flock}, helpers::{config::get as get_tauri_config, flock},
interface::{AppSettings, Interface, MobileOptions, Options as InterfaceOptions}, interface::{AppSettings, Interface, MobileOptions, Options as InterfaceOptions},
@ -11,7 +13,6 @@ use cargo_mobile::{
apple::config::Config as AppleConfig, apple::config::Config as AppleConfig,
config::Config, config::Config,
opts::{NoiseLevel, Profile}, opts::{NoiseLevel, Profile},
os,
}; };
#[derive(Debug, Clone, Parser)] #[derive(Debug, Clone, Parser)]
@ -53,7 +54,7 @@ impl From<Options> for crate::dev::Options {
} }
pub fn command(options: Options) -> Result<()> { pub fn command(options: Options) -> Result<()> {
with_config(|root_conf, config, _metadata| { with_config(Some(Default::default()), |root_conf, config, _metadata| {
ensure_init(config.project_dir(), MobileTarget::Ios) ensure_init(config.project_dir(), MobileTarget::Ios)
.map_err(|e| Error::ProjectNotInitialized(e.to_string()))?; .map_err(|e| Error::ProjectNotInitialized(e.to_string()))?;
run_dev(options, root_conf, config).map_err(|e| Error::DevFailed(format!("{:#}", e))) run_dev(options, root_conf, config).map_err(|e| Error::DevFailed(format!("{:#}", e)))
@ -98,13 +99,13 @@ fn run_dev(options: Options, root_conf: &Config, config: &AppleConfig) -> Result
}; };
write_options(cli_options, &bundle_identifier, MobileTarget::Ios)?; write_options(cli_options, &bundle_identifier, MobileTarget::Ios)?;
if open { if open {
open_dev(config) open_and_wait(config)
} else { } else {
match run(options, root_conf, config) { match run(options, root_conf, config) {
Ok(c) => Ok(Box::new(c) as Box<dyn DevProcess>), Ok(c) => Ok(Box::new(c) as Box<dyn DevProcess>),
Err(Error::FailedToPromptForDevice(e)) => { Err(Error::FailedToPromptForDevice(e)) => {
log::error!("{}", e); log::error!("{}", e);
open_dev(config) open_and_wait(config)
} }
Err(e) => Err(e.into()), Err(e) => Err(e.into()),
} }
@ -113,16 +114,6 @@ fn run_dev(options: Options, root_conf: &Config, config: &AppleConfig) -> Result
) )
} }
fn open_dev(config: &AppleConfig) -> ! {
log::info!("Opening Xcode");
if let Err(e) = os::open_file_with("Xcode", config.project_dir()) {
log::error!("{}", e);
}
loop {
std::thread::sleep(std::time::Duration::from_secs(24 * 60 * 60));
}
}
fn run( fn run(
options: MobileOptions, options: MobileOptions,
root_conf: &Config, root_conf: &Config,

View File

@ -3,7 +3,7 @@ use crate::Result;
use cargo_mobile::os; use cargo_mobile::os;
pub fn command() -> Result<()> { pub fn command() -> Result<()> {
with_config(|_, config, _metadata| { with_config(Some(Default::default()), |_, config, _metadata| {
ensure_init(config.project_dir(), MobileTarget::Ios) ensure_init(config.project_dir(), MobileTarget::Ios)
.map_err(|e| Error::ProjectNotInitialized(e.to_string()))?; .map_err(|e| Error::ProjectNotInitialized(e.to_string()))?;
os::open_file_with("Xcode", config.project_dir()).map_err(Error::OpenFailed) os::open_file_with("Xcode", config.project_dir()).map_err(Error::OpenFailed)

View File

@ -46,7 +46,7 @@ pub fn command(options: Options) -> Result<()> {
let macos = macos_from_platform(&options.platform); let macos = macos_from_platform(&options.platform);
let noise_level = NoiseLevel::Polite; let noise_level = NoiseLevel::Polite;
with_config(|root_conf, config, metadata| { with_config(None, |root_conf, config, metadata| {
let env = env()?; let env = env()?;
init_dot_cargo(root_conf, None).map_err(Error::InitDotCargo)?; init_dot_cargo(root_conf, None).map_err(Error::InitDotCargo)?;
// The `PATH` env var Xcode gives us is missing any additions // The `PATH` env var Xcode gives us is missing any additions

View File

@ -17,9 +17,16 @@ use cargo_mobile::{
config::{app::Raw as RawAppConfig, metadata::Metadata, Config, Raw}, config::{app::Raw as RawAppConfig, metadata::Metadata, Config, Raw},
env::Error as EnvError, env::Error as EnvError,
}; };
use interprocess::local_socket::{LocalSocketListener, LocalSocketStream};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::{ use std::{
collections::HashMap, env::set_var, ffi::OsString, fmt::Write, path::PathBuf, process::ExitStatus, collections::HashMap,
env::set_var,
ffi::OsString,
fmt::Write,
io::{BufRead, BufReader, Write as _},
path::PathBuf,
process::ExitStatus,
}; };
#[cfg(not(windows))] #[cfg(not(windows))]
@ -63,7 +70,7 @@ impl DevProcess for DevChild {
} }
} }
#[derive(PartialEq, Eq)] #[derive(PartialEq, Eq, Copy, Clone)]
pub enum Target { pub enum Target {
Android, Android,
#[cfg(target_os = "macos")] #[cfg(target_os = "macos")]
@ -96,17 +103,15 @@ impl Target {
} }
} }
#[derive(Debug, Default, Serialize, Deserialize)] #[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct CliOptions { pub struct CliOptions {
pub features: Option<Vec<String>>, pub features: Option<Vec<String>>,
pub args: Vec<String>, pub args: Vec<String>,
pub vars: HashMap<String, OsString>, pub vars: HashMap<String, OsString>,
} }
fn options_path(bundle_identifier: &str, target: Target) -> PathBuf { fn options_local_socket_name(bundle_identifier: &str, target: Target) -> PathBuf {
let out_dir = dirs_next::cache_dir() let out_dir = std::env::temp_dir();
.or_else(dirs_next::home_dir)
.unwrap_or_else(std::env::temp_dir);
let out_dir = out_dir.join(".tauri").join(bundle_identifier); let out_dir = out_dir.join(".tauri").join(bundle_identifier);
let _ = std::fs::create_dir_all(&out_dir); let _ = std::fs::create_dir_all(&out_dir);
out_dir out_dir
@ -120,6 +125,7 @@ fn env_vars() -> HashMap<String, OsString> {
let k = k.to_string_lossy(); let k = k.to_string_lossy();
if (k.starts_with("TAURI") && k != "TAURI_PRIVATE_KEY" && k != "TAURI_KEY_PASSWORD") if (k.starts_with("TAURI") && k != "TAURI_PRIVATE_KEY" && k != "TAURI_KEY_PASSWORD")
|| k.starts_with("WRY") || k.starts_with("WRY")
|| k == "TMPDIR"
{ {
vars.insert(k.into_owned(), v); vars.insert(k.into_owned(), v);
} }
@ -139,23 +145,50 @@ pub fn write_options(
target: Target, target: Target,
) -> crate::Result<()> { ) -> crate::Result<()> {
options.vars.extend(env_vars()); options.vars.extend(env_vars());
std::fs::write( let name = options_local_socket_name(bundle_identifier, target);
options_path(bundle_identifier, target), let _ = std::fs::remove_file(&name);
&serde_json::to_string(&options)?, let value = serde_json::to_string(&options)?;
)?;
std::thread::spawn(move || {
let listener = LocalSocketListener::bind(name).expect("failed to start local socket");
for mut conn in listener.incoming().flatten() {
let _ = conn.write_all(value.as_bytes());
let _ = conn.write_all(b"\n");
}
});
Ok(()) Ok(())
} }
fn read_options(config: &TauriConfig, target: Target) -> crate::Result<CliOptions> { fn read_options(config: &TauriConfig, target: Target) -> CliOptions {
let data = std::fs::read_to_string(options_path(&config.tauri.bundle.identifier, target))?; let name = options_local_socket_name(&config.tauri.bundle.identifier, target);
let options: CliOptions = serde_json::from_str(&data)?; let conn = LocalSocketStream::connect(name).unwrap_or_else(|_| {
log::error!(
"failed to connect to local socket. You must keep the Tauri CLI alive with the `{cmd} dev` or `{cmd} build --open` commands.",
cmd = target.command_name()
);
std::process::exit(1);
});
conn
.set_nonblocking(true)
.expect("failed to set local socket stream to nonblocking");
let mut conn = BufReader::new(conn);
let mut buffer = String::new();
conn.read_line(&mut buffer).unwrap_or_else(|_| {
log::error!(
"failed to connect to local socket. You must keep the Tauri CLI alive with the `{cmd} dev` or `{cmd} build --open` commands.",
cmd = target.command_name()
);
std::process::exit(1);
});
let options: CliOptions = serde_json::from_str(&buffer).expect("invalid CLI options");
for (k, v) in &options.vars { for (k, v) in &options.vars {
set_var(k, v); set_var(k, v);
} }
Ok(options) options
} }
fn get_config(config: &TauriConfig) -> (Config, Metadata) { fn get_config(config: &TauriConfig, cli_options: CliOptions) -> (Config, Metadata) {
let mut s = config.tauri.bundle.identifier.rsplit('.'); let mut s = config.tauri.bundle.identifier.rsplit('.');
let app_name = s.next().unwrap_or("app").to_string(); let app_name = s.next().unwrap_or("app").to_string();
let mut domain = String::new(); let mut domain = String::new();
@ -191,8 +224,8 @@ fn get_config(config: &TauriConfig) -> (Config, Metadata) {
}; };
#[cfg(target_os = "macos")] #[cfg(target_os = "macos")]
let ios_options = read_options(config, Target::Ios).unwrap_or_default(); let ios_options = cli_options.clone();
let android_options = read_options(config, Target::Android).unwrap_or_default(); let android_options = cli_options;
let raw = Raw { let raw = Raw {
app: RawAppConfig { app: RawAppConfig {