瀏覽代碼

feat: add `android open` and `ios open` commands (#4946)

Lucas Fernandes Nogueira 3 年之前
父節點
當前提交
a9c8e565c6

+ 6 - 0
.changes/mobile-open.md

@@ -0,0 +1,6 @@
+---
+"cli.rs": minor
+"cli.js": minor
+---
+
+Added `android open` and `ios open` commands.

+ 1 - 1
tooling/cli/Cargo.lock

@@ -272,7 +272,7 @@ dependencies = [
 [[package]]
 name = "cargo-mobile"
 version = "0.1.0"
-source = "git+https://github.com/tauri-apps/cargo-mobile?branch=feat/library#d2b3f7248657c60dcc0669303329b802f04a6291"
+source = "git+https://github.com/tauri-apps/cargo-mobile?branch=feat/library#c1365b7e90d341d67cf40f4d2f5532e932631907"
 dependencies = [
  "bicycle",
  "bossy",

+ 1 - 1
tooling/cli/Cargo.toml

@@ -30,7 +30,7 @@ path = "src/main.rs"
 bossy = { git = "https://github.com/lucasfernog/bossy", branch = "fix/winapi-features" }
 
 [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 = "feat/library", default-features = false }
 bossy = "0.2"
 textwrap = { version = "0.11.0", features = ["term_size"] }

+ 52 - 2
tooling/cli/src/mobile/android.rs

@@ -2,13 +2,37 @@
 // SPDX-License-Identifier: Apache-2.0
 // SPDX-License-Identifier: MIT
 
+use cargo_mobile::{
+  android::config::{Config as AndroidConfig, Metadata as AndroidMetadata},
+  config::{metadata::Metadata, Config},
+  os,
+  util::cli::TextWrapper,
+};
 use clap::{Parser, Subcommand};
 
-use super::init::{command as init_command, Options as InitOptions, Target as InitTarget};
+use super::{
+  ensure_init,
+  init::{command as init_command, Options as InitOptions},
+  Target,
+};
 use crate::Result;
 
 pub(crate) mod project;
 
+#[derive(Debug, thiserror::Error)]
+enum Error {
+  #[error("{0}")]
+  ProjectNotInitialized(String),
+  #[error(transparent)]
+  ConfigFailed(cargo_mobile::config::LoadOrGenError),
+  #[error(transparent)]
+  MetadataFailed(cargo_mobile::config::metadata::Error),
+  #[error("Android is marked as unsupported in your configuration file")]
+  Unsupported,
+  #[error(transparent)]
+  OpenFailed(os::OpenFileError),
+}
+
 #[derive(Parser)]
 #[clap(
   author,
@@ -25,12 +49,38 @@ pub struct Cli {
 #[derive(Subcommand)]
 enum Commands {
   Init(InitOptions),
+  Open,
 }
 
 pub fn command(cli: Cli) -> Result<()> {
   match cli.command {
-    Commands::Init(options) => init_command(options, InitTarget::Android)?,
+    Commands::Init(options) => init_command(options, Target::Android)?,
+    Commands::Open => open()?,
+  }
+
+  Ok(())
+}
+
+fn with_config(
+  wrapper: &TextWrapper,
+  f: impl FnOnce(&AndroidConfig, &AndroidMetadata) -> Result<(), Error>,
+) -> Result<(), Error> {
+  let (config, _origin) =
+    Config::load_or_gen(".", true.into(), wrapper).map_err(Error::ConfigFailed)?;
+  let metadata = Metadata::load(config.app().root_dir()).map_err(Error::MetadataFailed)?;
+  if metadata.android().supported() {
+    f(config.android(), metadata.android())
+  } else {
+    Err(Error::Unsupported)
   }
+}
 
+fn open() -> Result<()> {
+  let wrapper = TextWrapper::with_splitter(textwrap::termwidth(), textwrap::NoHyphenation);
+  with_config(&wrapper, |config, _metadata| {
+    ensure_init(config.project_dir(), Target::Android)
+      .map_err(|e| Error::ProjectNotInitialized(e.to_string()))?;
+    os::open_file_with("Android Studio", config.project_dir()).map_err(Error::OpenFailed)
+  })?;
   Ok(())
 }

+ 1 - 7
tooling/cli/src/mobile/init.rs

@@ -2,6 +2,7 @@
 // SPDX-License-Identifier: Apache-2.0
 // SPDX-License-Identifier: MIT
 
+use super::Target;
 use crate::helpers::{app_paths::tauri_dir, template::JsonMap};
 use crate::Result;
 use cargo_mobile::{
@@ -89,13 +90,6 @@ pub enum Error {
   OpenInEditor(util::OpenInEditorError),
 }
 
-#[derive(PartialEq, Eq)]
-pub enum Target {
-  Android,
-  #[cfg(target_os = "macos")]
-  Ios,
-}
-
 pub fn exec(
   target: Target,
   wrapper: &TextWrapper,

+ 52 - 2
tooling/cli/src/mobile/ios.rs

@@ -2,13 +2,37 @@
 // SPDX-License-Identifier: Apache-2.0
 // SPDX-License-Identifier: MIT
 
+use cargo_mobile::{
+  apple::config::{Config as AppleConfig, Metadata as AppleMetadata},
+  config::{metadata::Metadata, Config},
+  os,
+  util::cli::TextWrapper,
+};
 use clap::{Parser, Subcommand};
 
-use super::init::{command as init_command, Options as InitOptions, Target as InitTarget};
+use super::{
+  ensure_init,
+  init::{command as init_command, Options as InitOptions},
+  Target,
+};
 use crate::Result;
 
 pub(crate) mod project;
 
+#[derive(Debug, thiserror::Error)]
+enum Error {
+  #[error("{0}")]
+  ProjectNotInitialized(String),
+  #[error(transparent)]
+  ConfigFailed(cargo_mobile::config::LoadOrGenError),
+  #[error(transparent)]
+  MetadataFailed(cargo_mobile::config::metadata::Error),
+  #[error("iOS is marked as unsupported in your configuration file")]
+  Unsupported,
+  #[error(transparent)]
+  OpenFailed(os::OpenFileError),
+}
+
 #[derive(Parser)]
 #[clap(
   author,
@@ -25,12 +49,38 @@ pub struct Cli {
 #[derive(Subcommand)]
 enum Commands {
   Init(InitOptions),
+  Open,
 }
 
 pub fn command(cli: Cli) -> Result<()> {
   match cli.command {
-    Commands::Init(options) => init_command(options, InitTarget::Ios)?,
+    Commands::Init(options) => init_command(options, Target::Ios)?,
+    Commands::Open => open()?,
+  }
+
+  Ok(())
+}
+
+fn with_config(
+  wrapper: &TextWrapper,
+  f: impl FnOnce(&AppleConfig, &AppleMetadata) -> Result<(), Error>,
+) -> Result<(), Error> {
+  let (config, _origin) =
+    Config::load_or_gen(".", true.into(), wrapper).map_err(Error::ConfigFailed)?;
+  let metadata = Metadata::load(config.app().root_dir()).map_err(Error::MetadataFailed)?;
+  if metadata.apple().supported() {
+    f(config.apple(), metadata.apple())
+  } else {
+    Err(Error::Unsupported)
   }
+}
 
+fn open() -> Result<()> {
+  let wrapper = TextWrapper::with_splitter(textwrap::termwidth(), textwrap::NoHyphenation);
+  with_config(&wrapper, |config, _metadata| {
+    ensure_init(config.project_dir(), Target::Ios)
+      .map_err(|e| Error::ProjectNotInitialized(e.to_string()))?;
+    os::open_file_with("Xcode", config.project_dir()).map_err(Error::OpenFailed)
+  })?;
   Ok(())
 }

+ 41 - 0
tooling/cli/src/mobile/mod.rs

@@ -2,7 +2,48 @@
 // SPDX-License-Identifier: Apache-2.0
 // SPDX-License-Identifier: MIT
 
+use anyhow::{bail, Result};
+use std::path::PathBuf;
+
 pub mod android;
 mod init;
 #[cfg(target_os = "macos")]
 pub mod ios;
+
+#[derive(PartialEq, Eq)]
+pub enum Target {
+  Android,
+  #[cfg(target_os = "macos")]
+  Ios,
+}
+
+impl Target {
+  fn ide_name(&self) -> &'static str {
+    match self {
+      Self::Android => "Android Studio",
+      #[cfg(target_os = "macos")]
+      Self::Ios => "Xcode",
+    }
+  }
+
+  fn command_name(&self) -> &'static str {
+    match self {
+      Self::Android => "android",
+      #[cfg(target_os = "macos")]
+      Self::Ios => "ios",
+    }
+  }
+}
+
+fn ensure_init(project_dir: PathBuf, target: Target) -> Result<()> {
+  if !project_dir.exists() {
+    bail!(
+      "{} project directory {} doesn't exist. Please run `tauri {} init` and try again.",
+      target.ide_name(),
+      project_dir.display(),
+      target.command_name(),
+    )
+  } else {
+    Ok(())
+  }
+}