feat(cli): add option to run on specific iOS simulator/device (#5098)

This commit is contained in:
Lucas Fernandes Nogueira 2022-08-30 16:09:06 -03:00 committed by GitHub
parent 9f9e3ae54d
commit 68e80ffaa9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 119 additions and 24 deletions

View File

@ -293,7 +293,7 @@ checksum = "c1db59621ec70f09c5e9b597b220c7a2b43611f4710dc03ceb8748637775692c"
[[package]]
name = "cargo-mobile"
version = "0.1.0"
source = "git+https://github.com/tauri-apps/cargo-mobile?branch=dev#909edf9337ec0cb42c76e0a34af61e99b15ccfe0"
source = "git+https://github.com/tauri-apps/cargo-mobile?branch=dev#ff88cc91fbf008ee0b9b33c8e4bcb5c9b5b743e6"
dependencies = [
"cocoa",
"colored 1.9.3",

View File

@ -28,7 +28,7 @@ name = "cargo-tauri"
path = "src/main.rs"
[dependencies]
#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 }
textwrap = { version = "0.11.0", features = ["term_size"] }
interprocess = "1"

View File

@ -209,7 +209,7 @@ fn emulator_prompt(
0
};
Ok(emulator_list.iter().nth(index).cloned().unwrap())
Ok(emulator_list.into_iter().nth(index).unwrap())
}
}

View File

@ -9,7 +9,7 @@ use cargo_mobile::{
Raw as RawAppleConfig,
},
device::Device,
ios_deploy,
ios_deploy, simctl,
target::Target,
},
config::app::App,
@ -31,6 +31,11 @@ use crate::{
Result,
};
use std::{
thread::{sleep, spawn},
time::Duration,
};
mod build;
mod dev;
mod open;
@ -121,19 +126,30 @@ fn with_config<T>(
f(&app, &config, &metadata, cli_options)
}
fn device_prompt<'a>(env: &'_ Env) -> Result<Device<'a>, PromptError<ios_deploy::DeviceListError>> {
fn ios_deploy_device_prompt<'a>(
env: &'_ Env,
target: Option<&str>,
) -> Result<Device<'a>, PromptError<ios_deploy::DeviceListError>> {
let device_list =
ios_deploy::device_list(env).map_err(|cause| PromptError::detection_failed("iOS", cause))?;
if !device_list.is_empty() {
let index = if device_list.len() > 1 {
prompt::list(
concat!("Detected ", "iOS", " devices"),
device_list.iter(),
"device",
None,
"Device",
)
.map_err(|cause| PromptError::prompt_failed("iOS", cause))?
if let Some(t) = target {
let t = t.to_lowercase();
device_list
.iter()
.position(|d| d.name().to_lowercase().starts_with(&t))
.unwrap_or_default()
} else {
prompt::list(
concat!("Detected ", "iOS", " devices"),
device_list.iter(),
"device",
None,
"Device",
)
.map_err(|cause| PromptError::prompt_failed("iOS", cause))?
}
} else {
0
};
@ -149,8 +165,55 @@ fn device_prompt<'a>(env: &'_ Env) -> Result<Device<'a>, PromptError<ios_deploy:
}
}
fn simulator_prompt(
env: &'_ Env,
target: Option<&str>,
) -> Result<simctl::Device, PromptError<simctl::DeviceListError>> {
let simulator_list = simctl::device_list(env)
.map_err(|cause| PromptError::detection_failed("iOS Simulator", cause))?;
if !simulator_list.is_empty() {
let index = if simulator_list.len() > 1 {
if let Some(t) = target {
let t = t.to_lowercase();
simulator_list
.iter()
.position(|d| d.name().to_lowercase().starts_with(&t))
.unwrap_or_default()
} else {
prompt::list(
concat!("Detected ", "iOS", " simulators"),
simulator_list.iter(),
"simulator",
None,
"Simulator",
)
.map_err(|cause| PromptError::prompt_failed("iOS Simulator", cause))?
}
} else {
0
};
let device = simulator_list.into_iter().nth(index).unwrap();
Ok(device)
} else {
Err(PromptError::none_detected("iOS Simulator"))
}
}
fn device_prompt<'a>(env: &'_ Env, target: Option<&str>) -> Result<Device<'a>> {
if let Ok(device) = ios_deploy_device_prompt(env, target) {
Ok(device)
} else {
let simulator = simulator_prompt(env, target)?;
let handle = simulator.start(env)?;
spawn(move || {
let _ = handle.wait();
});
Ok(simulator.into())
}
}
fn detect_target_ok<'a>(env: &Env) -> Option<&'a Target<'a>> {
device_prompt(env).map(|device| device.target()).ok()
device_prompt(env, None).map(|device| device.target()).ok()
}
fn open_and_wait(config: &AppleConfig, env: &Env) -> ! {
@ -159,6 +222,6 @@ fn open_and_wait(config: &AppleConfig, env: &Env) -> ! {
log::error!("{}", e);
}
loop {
std::thread::sleep(std::time::Duration::from_secs(24 * 60 * 60));
sleep(Duration::from_secs(24 * 60 * 60));
}
}

View File

@ -10,13 +10,17 @@ use crate::{
use clap::Parser;
use cargo_mobile::{
apple::{config::Config as AppleConfig, device::RunError as DeviceRunError, ios_deploy},
apple::{config::Config as AppleConfig, device::RunError as DeviceRunError, simctl},
config::app::App,
device::PromptError,
env::Env,
opts::{NoiseLevel, Profile},
};
use std::{
thread::{sleep, spawn},
time::Duration,
};
#[derive(Debug, Clone, Parser)]
#[clap(about = "iOS dev")]
pub struct Options {
@ -38,6 +42,8 @@ pub struct Options {
/// Open Xcode instead of trying to run on a connected device
#[clap(short, long)]
pub open: bool,
/// Runs on the given device name
pub device: Option<String>,
}
impl From<Options> for crate::dev::Options {
@ -92,9 +98,29 @@ fn run_dev(
let env = env()?;
init_dot_cargo(app, None)?;
if let Some(device) = &options.device {
let simulators = simctl::device_list(&env).unwrap_or_default();
for simulator in simulators {
if simulator
.name()
.to_lowercase()
.starts_with(&device.to_lowercase())
{
log::info!("Starting simulator {}", simulator.name());
let handle = simulator.start(&env)?;
spawn(move || {
let _ = handle.wait();
});
sleep(Duration::from_secs(3));
break;
}
}
}
let open = options.open;
let exit_on_panic = options.exit_on_panic;
let no_watch = options.no_watch;
let device = options.device;
interface.mobile_dev(
MobileOptions {
debug: true,
@ -115,7 +141,7 @@ fn run_dev(
if open {
open_and_wait(config, &env)
} else {
match run(options, config, &env, noise_level) {
match run(device.as_deref(), options, config, &env, noise_level) {
Ok(c) => {
crate::dev::wait_dev_process(c.clone(), move |status, reason| {
crate::dev::on_app_exit(status, reason, exit_on_panic, no_watch)
@ -135,12 +161,13 @@ fn run_dev(
#[derive(Debug, thiserror::Error)]
enum RunError {
#[error(transparent)]
FailedToPromptForDevice(PromptError<ios_deploy::DeviceListError>),
#[error("{0}")]
FailedToPromptForDevice(String),
#[error(transparent)]
RunFailed(DeviceRunError),
}
fn run(
device: Option<&str>,
options: MobileOptions,
config: &AppleConfig,
env: &Env,
@ -154,8 +181,8 @@ fn run(
let non_interactive = true; // ios-deploy --noninteractive (quit when app crashes or exits)
device_prompt(env)
.map_err(RunError::FailedToPromptForDevice)?
device_prompt(env, device)
.map_err(|e| RunError::FailedToPromptForDevice(e.to_string()))?
.run(config, env, noise_level, non_interactive, profile)
.map(DevChild::new)
.map_err(RunError::RunFailed)

View File

@ -50,7 +50,11 @@ pub fn gen(
let ios_pods = metadata.ios().pods().unwrap_or_default();
let macos_pods = metadata.macos().pods().unwrap_or_default();
let default_archs = [String::from("arm64"), String::from("x86_64")];
let default_archs = [
String::from("arm64"),
String::from("arm64-sim"),
String::from("x86_64"),
];
map.insert("file-groups", &source_dirs);
map.insert("ios-frameworks", metadata.ios().frameworks());

View File

@ -100,6 +100,7 @@ pub fn command(options: Options) -> Result<()> {
// Set target-specific flags
let triple = match arch.as_str() {
"arm64" => "aarch64_apple_ios",
"arm64-sim" => "aarch64_apple_ios_sim",
"x86_64" => "x86_64_apple_ios",
_ => {
return Err(anyhow::anyhow!(

View File

@ -72,7 +72,7 @@ targets:
ARCHS: [{{join ios-valid-archs}}]
VALID_ARCHS: {{~#each ios-valid-archs}} {{this}} {{/each}}
LIBRARY_SEARCH_PATHS[sdk=iphoneos*]: $(inherited) "{{prefix-path "target/aarch64-apple-ios/$(CONFIGURATION)"}}"
LIBRARY_SEARCH_PATHS[sdk=iphonesimulator*]: $(inherited) "{{prefix-path "target/x86_64-apple-ios/$(CONFIGURATION)"}}"
LIBRARY_SEARCH_PATHS[sdk=iphonesimulator*]: $(inherited) "{{prefix-path "target/aarch64-apple-ios-sim/$(CONFIGURATION)"}}"
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES: true
groups: [app]
dependencies: