mirror of
https://github.com/tauri-apps/tauri.git
synced 2025-01-01 15:36:14 +03:00
Co-authored-by: Lucas Fernandes Nogueira <lucas@tauri.app>
This commit is contained in:
parent
713f84db2b
commit
4caa1cca99
12
.changes/cli-plugin-init.md
Normal file
12
.changes/cli-plugin-init.md
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
---
|
||||||
|
'tauri-cli': 'patch:breaking'
|
||||||
|
'@tauri-apps/cli': 'patch:breaking'
|
||||||
|
---
|
||||||
|
|
||||||
|
The `tauri plugin` subcommand is receving a couple of consitency and quality of life improvements:
|
||||||
|
|
||||||
|
- Renamed `tauri plugin android/ios add` command to `tauri plugin android/ios init` to match the `tauri plugin init` command.
|
||||||
|
- Removed the `-n/--name` argument from the `tauri plugin init`, `tauri plugin android/ios init`, and is now parsed from the first positional argument.
|
||||||
|
- Added `tauri plugin new` to create a plugin in a new directory.
|
||||||
|
- Changed `tauri plugin init` to initalize a plugin in an existing directory (defaults to current directory) instead of creating a new one.
|
||||||
|
- Changed `tauri plugin init` to NOT generate mobile projects by default, you can opt-in to generate them using `--android` and `--ios` flags or `--mobile` flag or initalize them later using `tauri plugin android/ios init`.
|
@ -2,6 +2,8 @@
|
|||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
use std::path::Path;
|
||||||
|
|
||||||
use clap::{Parser, Subcommand};
|
use clap::{Parser, Subcommand};
|
||||||
|
|
||||||
use crate::Result;
|
use crate::Result;
|
||||||
@ -9,6 +11,7 @@ use crate::Result;
|
|||||||
mod android;
|
mod android;
|
||||||
mod init;
|
mod init;
|
||||||
mod ios;
|
mod ios;
|
||||||
|
mod new;
|
||||||
|
|
||||||
#[derive(Parser)]
|
#[derive(Parser)]
|
||||||
#[clap(
|
#[clap(
|
||||||
@ -25,6 +28,7 @@ pub struct Cli {
|
|||||||
|
|
||||||
#[derive(Subcommand)]
|
#[derive(Subcommand)]
|
||||||
enum Commands {
|
enum Commands {
|
||||||
|
New(new::Options),
|
||||||
Init(init::Options),
|
Init(init::Options),
|
||||||
Android(android::Cli),
|
Android(android::Cli),
|
||||||
Ios(ios::Cli),
|
Ios(ios::Cli),
|
||||||
@ -32,6 +36,7 @@ enum Commands {
|
|||||||
|
|
||||||
pub fn command(cli: Cli) -> Result<()> {
|
pub fn command(cli: Cli) -> Result<()> {
|
||||||
match cli.command {
|
match cli.command {
|
||||||
|
Commands::New(options) => new::command(options)?,
|
||||||
Commands::Init(options) => init::command(options)?,
|
Commands::Init(options) => init::command(options)?,
|
||||||
Commands::Android(cli) => android::command(cli)?,
|
Commands::Android(cli) => android::command(cli)?,
|
||||||
Commands::Ios(cli) => ios::command(cli)?,
|
Commands::Ios(cli) => ios::command(cli)?,
|
||||||
@ -39,3 +44,30 @@ pub fn command(cli: Cli) -> Result<()> {
|
|||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn infer_plugin_name<P: AsRef<Path>>(directory: P) -> Result<String> {
|
||||||
|
let dir = directory.as_ref();
|
||||||
|
let cargo_toml_path = dir.join("Cargo.toml");
|
||||||
|
let name = if cargo_toml_path.exists() {
|
||||||
|
let contents = std::fs::read(cargo_toml_path)?;
|
||||||
|
let cargo_toml: toml::Value = toml::from_slice(&contents)?;
|
||||||
|
cargo_toml
|
||||||
|
.get("package")
|
||||||
|
.and_then(|v| v.get("name"))
|
||||||
|
.map(|v| v.as_str().unwrap_or_default())
|
||||||
|
.unwrap_or_default()
|
||||||
|
.to_string()
|
||||||
|
} else {
|
||||||
|
dir
|
||||||
|
.file_name()
|
||||||
|
.unwrap_or_default()
|
||||||
|
.to_string_lossy()
|
||||||
|
.to_string()
|
||||||
|
};
|
||||||
|
Ok(
|
||||||
|
name
|
||||||
|
.strip_prefix("tauri-plugin-")
|
||||||
|
.unwrap_or(&name)
|
||||||
|
.to_string(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
@ -28,15 +28,15 @@ pub struct Cli {
|
|||||||
|
|
||||||
#[derive(Subcommand)]
|
#[derive(Subcommand)]
|
||||||
enum Commands {
|
enum Commands {
|
||||||
Add(AddOptions),
|
Init(InitOptions),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Parser)]
|
#[derive(Debug, Parser)]
|
||||||
#[clap(about = "Adds the Android project to an existing Tauri plugin")]
|
#[clap(about = "Initializes the Android project for an existing Tauri plugin")]
|
||||||
pub struct AddOptions {
|
pub struct InitOptions {
|
||||||
/// Name of your Tauri plugin. Must match the current plugin's name.
|
/// Name of your Tauri plugin. Must match the current plugin's name.
|
||||||
#[clap(short = 'n', long = "name")]
|
/// If not specified, it will be infered from the current directory.
|
||||||
plugin_name: String,
|
plugin_name: Option<String>,
|
||||||
/// The output directory.
|
/// The output directory.
|
||||||
#[clap(short, long)]
|
#[clap(short, long)]
|
||||||
#[clap(default_value_t = current_dir().expect("failed to read cwd").to_string_lossy().into_owned())]
|
#[clap(default_value_t = current_dir().expect("failed to read cwd").to_string_lossy().into_owned())]
|
||||||
@ -45,7 +45,12 @@ pub struct AddOptions {
|
|||||||
|
|
||||||
pub fn command(cli: Cli) -> Result<()> {
|
pub fn command(cli: Cli) -> Result<()> {
|
||||||
match cli.command {
|
match cli.command {
|
||||||
Commands::Add(options) => {
|
Commands::Init(options) => {
|
||||||
|
let plugin_name = match options.plugin_name {
|
||||||
|
None => super::infer_plugin_name(std::env::current_dir()?)?,
|
||||||
|
Some(name) => name,
|
||||||
|
};
|
||||||
|
|
||||||
let out_dir = PathBuf::from(options.out_dir);
|
let out_dir = PathBuf::from(options.out_dir);
|
||||||
if out_dir.join("android").exists() {
|
if out_dir.join("android").exists() {
|
||||||
return Err(anyhow::anyhow!("android folder already exists"));
|
return Err(anyhow::anyhow!("android folder already exists"));
|
||||||
@ -53,7 +58,7 @@ pub fn command(cli: Cli) -> Result<()> {
|
|||||||
|
|
||||||
let plugin_id = super::init::request_input(
|
let plugin_id = super::init::request_input(
|
||||||
"What should be the Android Package ID for your plugin?",
|
"What should be the Android Package ID for your plugin?",
|
||||||
Some(format!("com.plugin.{}", options.plugin_name)),
|
Some(format!("com.plugin.{}", plugin_name)),
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
)?
|
)?
|
||||||
@ -62,7 +67,7 @@ pub fn command(cli: Cli) -> Result<()> {
|
|||||||
let handlebars = Handlebars::new();
|
let handlebars = Handlebars::new();
|
||||||
|
|
||||||
let mut data = BTreeMap::new();
|
let mut data = BTreeMap::new();
|
||||||
super::init::plugin_name_data(&mut data, &options.plugin_name);
|
super::init::plugin_name_data(&mut data, &plugin_name);
|
||||||
|
|
||||||
let mut created_dirs = Vec::new();
|
let mut created_dirs = Vec::new();
|
||||||
template::render_with_generator(
|
template::render_with_generator(
|
||||||
@ -114,7 +119,7 @@ pub fn init<R: Runtime>() -> TauriPlugin<R> {{
|
|||||||
.build()
|
.build()
|
||||||
}}
|
}}
|
||||||
"#,
|
"#,
|
||||||
name = options.plugin_name,
|
name = plugin_name,
|
||||||
identifier = plugin_id
|
identifier = plugin_id
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -11,7 +11,7 @@ use anyhow::Context;
|
|||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
use dialoguer::Input;
|
use dialoguer::Input;
|
||||||
use handlebars::{to_json, Handlebars};
|
use handlebars::{to_json, Handlebars};
|
||||||
use heck::{AsKebabCase, ToKebabCase, ToPascalCase, ToSnakeCase};
|
use heck::{ToKebabCase, ToPascalCase, ToSnakeCase};
|
||||||
use include_dir::{include_dir, Dir};
|
use include_dir::{include_dir, Dir};
|
||||||
use log::warn;
|
use log::warn;
|
||||||
use std::{
|
use std::{
|
||||||
@ -29,25 +29,34 @@ pub const TEMPLATE_DIR: Dir<'_> = include_dir!("templates/plugin");
|
|||||||
#[derive(Debug, Parser)]
|
#[derive(Debug, Parser)]
|
||||||
#[clap(about = "Initializes a Tauri plugin project")]
|
#[clap(about = "Initializes a Tauri plugin project")]
|
||||||
pub struct Options {
|
pub struct Options {
|
||||||
/// Name of your Tauri plugin
|
/// Name of your Tauri plugin.
|
||||||
#[clap(short = 'n', long = "name")]
|
/// If not specified, it will be infered from the current directory.
|
||||||
plugin_name: String,
|
pub(crate) plugin_name: Option<String>,
|
||||||
/// Initializes a Tauri plugin without the TypeScript API
|
/// Initializes a Tauri plugin without the TypeScript API
|
||||||
#[clap(long)]
|
#[clap(long)]
|
||||||
no_api: bool,
|
pub(crate) no_api: bool,
|
||||||
/// Initializes a Tauri core plugin (internal usage)
|
/// Initializes a Tauri core plugin (internal usage)
|
||||||
#[clap(long, hide(true))]
|
#[clap(long, hide(true))]
|
||||||
tauri: bool,
|
pub(crate) tauri: bool,
|
||||||
/// Set target directory for init
|
/// Set target directory for init
|
||||||
#[clap(short, long)]
|
#[clap(short, long)]
|
||||||
#[clap(default_value_t = current_dir().expect("failed to read cwd").display().to_string())]
|
#[clap(default_value_t = current_dir().expect("failed to read cwd").display().to_string())]
|
||||||
directory: String,
|
pub(crate) directory: String,
|
||||||
/// Path of the Tauri project to use (relative to the cwd)
|
/// Path of the Tauri project to use (relative to the cwd)
|
||||||
#[clap(short, long)]
|
#[clap(short, long)]
|
||||||
tauri_path: Option<PathBuf>,
|
pub(crate) tauri_path: Option<PathBuf>,
|
||||||
/// Author name
|
/// Author name
|
||||||
#[clap(short, long)]
|
#[clap(short, long)]
|
||||||
author: Option<String>,
|
pub(crate) author: Option<String>,
|
||||||
|
/// Whether to initialize an Android project for the plugin.
|
||||||
|
#[clap(long)]
|
||||||
|
pub(crate) android: bool,
|
||||||
|
/// Whether to initialize an iOS project for the plugin.
|
||||||
|
#[clap(long)]
|
||||||
|
pub(crate) ios: bool,
|
||||||
|
/// Whether to initialize Android and iOS projects for the plugin.
|
||||||
|
#[clap(long)]
|
||||||
|
pub(crate) mobile: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Options {
|
impl Options {
|
||||||
@ -64,12 +73,15 @@ impl Options {
|
|||||||
|
|
||||||
pub fn command(mut options: Options) -> Result<()> {
|
pub fn command(mut options: Options) -> Result<()> {
|
||||||
options.load();
|
options.load();
|
||||||
let template_target_path = PathBuf::from(options.directory).join(format!(
|
|
||||||
"tauri-plugin-{}",
|
let plugin_name = match options.plugin_name {
|
||||||
AsKebabCase(&options.plugin_name)
|
None => super::infer_plugin_name(&options.directory)?,
|
||||||
));
|
Some(name) => name,
|
||||||
|
};
|
||||||
|
|
||||||
|
let template_target_path = PathBuf::from(options.directory);
|
||||||
let metadata = crates_metadata()?;
|
let metadata = crates_metadata()?;
|
||||||
if template_target_path.exists() {
|
if std::fs::read_dir(&template_target_path)?.count() > 0 {
|
||||||
warn!("Plugin dir ({:?}) not empty.", template_target_path);
|
warn!("Plugin dir ({:?}) not empty.", template_target_path);
|
||||||
} else {
|
} else {
|
||||||
let (tauri_dep, tauri_example_dep, tauri_build_dep) =
|
let (tauri_dep, tauri_example_dep, tauri_build_dep) =
|
||||||
@ -101,7 +113,7 @@ pub fn command(mut options: Options) -> Result<()> {
|
|||||||
handlebars.register_escape_fn(handlebars::no_escape);
|
handlebars.register_escape_fn(handlebars::no_escape);
|
||||||
|
|
||||||
let mut data = BTreeMap::new();
|
let mut data = BTreeMap::new();
|
||||||
plugin_name_data(&mut data, &options.plugin_name);
|
plugin_name_data(&mut data, &plugin_name);
|
||||||
data.insert("tauri_dep", to_json(tauri_dep));
|
data.insert("tauri_dep", to_json(tauri_dep));
|
||||||
data.insert("tauri_example_dep", to_json(tauri_example_dep));
|
data.insert("tauri_example_dep", to_json(tauri_example_dep));
|
||||||
data.insert("tauri_build_dep", to_json(tauri_build_dep));
|
data.insert("tauri_build_dep", to_json(tauri_build_dep));
|
||||||
@ -120,15 +132,20 @@ pub fn command(mut options: Options) -> Result<()> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let plugin_id = request_input(
|
let plugin_id = if options.android || options.mobile {
|
||||||
"What should be the Android Package ID for your plugin?",
|
let plugin_id = request_input(
|
||||||
Some(format!("com.plugin.{}", options.plugin_name)),
|
"What should be the Android Package ID for your plugin?",
|
||||||
false,
|
Some(format!("com.plugin.{}", plugin_name)),
|
||||||
false,
|
false,
|
||||||
)?
|
false,
|
||||||
.unwrap();
|
)?
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
data.insert("android_package_id", to_json(&plugin_id));
|
data.insert("android_package_id", to_json(&plugin_id));
|
||||||
|
Some(plugin_id)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
let mut created_dirs = Vec::new();
|
let mut created_dirs = Vec::new();
|
||||||
template::render_with_generator(
|
template::render_with_generator(
|
||||||
@ -157,13 +174,18 @@ pub fn command(mut options: Options) -> Result<()> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
"android" => {
|
"android" => {
|
||||||
return generate_android_out_file(
|
if options.android || options.mobile {
|
||||||
&path,
|
return generate_android_out_file(
|
||||||
&template_target_path,
|
&path,
|
||||||
&plugin_id.replace('.', "/"),
|
&template_target_path,
|
||||||
&mut created_dirs,
|
&plugin_id.as_ref().unwrap().replace('.', "/"),
|
||||||
);
|
&mut created_dirs,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return Ok(None);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
"ios" if !(options.ios || options.mobile) => return Ok(None),
|
||||||
"webview-dist" | "webview-src" | "package.json" => {
|
"webview-dist" | "webview-src" | "package.json" => {
|
||||||
if options.no_api {
|
if options.no_api {
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
|
@ -29,15 +29,15 @@ pub struct Cli {
|
|||||||
|
|
||||||
#[derive(Subcommand)]
|
#[derive(Subcommand)]
|
||||||
enum Commands {
|
enum Commands {
|
||||||
Add(AddOptions),
|
Init(InitOptions),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Parser)]
|
#[derive(Debug, Parser)]
|
||||||
#[clap(about = "Adds the iOS project to an existing Tauri plugin")]
|
#[clap(about = "Initializes the iOS project for an existing Tauri plugin")]
|
||||||
pub struct AddOptions {
|
pub struct InitOptions {
|
||||||
/// Name of your Tauri plugin. Must match the current plugin's name.
|
/// Name of your Tauri plugin. Must match the current plugin's name.
|
||||||
#[clap(short = 'n', long = "name")]
|
/// If not specified, it will be infered from the current directory.
|
||||||
plugin_name: String,
|
plugin_name: Option<String>,
|
||||||
/// The output directory.
|
/// The output directory.
|
||||||
#[clap(short, long)]
|
#[clap(short, long)]
|
||||||
#[clap(default_value_t = current_dir().expect("failed to read cwd").to_string_lossy().into_owned())]
|
#[clap(default_value_t = current_dir().expect("failed to read cwd").to_string_lossy().into_owned())]
|
||||||
@ -46,7 +46,12 @@ pub struct AddOptions {
|
|||||||
|
|
||||||
pub fn command(cli: Cli) -> Result<()> {
|
pub fn command(cli: Cli) -> Result<()> {
|
||||||
match cli.command {
|
match cli.command {
|
||||||
Commands::Add(options) => {
|
Commands::Init(options) => {
|
||||||
|
let plugin_name = match options.plugin_name {
|
||||||
|
None => super::infer_plugin_name(std::env::current_dir()?)?,
|
||||||
|
Some(name) => name,
|
||||||
|
};
|
||||||
|
|
||||||
let out_dir = PathBuf::from(options.out_dir);
|
let out_dir = PathBuf::from(options.out_dir);
|
||||||
if out_dir.join("ios").exists() {
|
if out_dir.join("ios").exists() {
|
||||||
return Err(anyhow::anyhow!("ios folder already exists"));
|
return Err(anyhow::anyhow!("ios folder already exists"));
|
||||||
@ -55,7 +60,7 @@ pub fn command(cli: Cli) -> Result<()> {
|
|||||||
let handlebars = Handlebars::new();
|
let handlebars = Handlebars::new();
|
||||||
|
|
||||||
let mut data = BTreeMap::new();
|
let mut data = BTreeMap::new();
|
||||||
super::init::plugin_name_data(&mut data, &options.plugin_name);
|
super::init::plugin_name_data(&mut data, &plugin_name);
|
||||||
|
|
||||||
let mut created_dirs = Vec::new();
|
let mut created_dirs = Vec::new();
|
||||||
template::render_with_generator(
|
template::render_with_generator(
|
||||||
@ -111,7 +116,7 @@ pub fn init<R: Runtime>() -> TauriPlugin<R> {{
|
|||||||
.build()
|
.build()
|
||||||
}}
|
}}
|
||||||
"#,
|
"#,
|
||||||
name = options.plugin_name,
|
name = plugin_name,
|
||||||
);
|
);
|
||||||
|
|
||||||
log::info!("iOS project added");
|
log::info!("iOS project added");
|
||||||
|
67
tooling/cli/src/plugin/new.rs
Normal file
67
tooling/cli/src/plugin/new.rs
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
// Copyright 2019-2023 Tauri Programme within The Commons Conservancy
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
use crate::Result;
|
||||||
|
use clap::Parser;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
#[derive(Debug, Parser)]
|
||||||
|
#[clap(about = "Initializes a Tauri plugin project")]
|
||||||
|
pub struct Options {
|
||||||
|
/// Name of your Tauri plugin
|
||||||
|
plugin_name: String,
|
||||||
|
/// Initializes a Tauri plugin without the TypeScript API
|
||||||
|
#[clap(long)]
|
||||||
|
no_api: bool,
|
||||||
|
/// Initializes a Tauri core plugin (internal usage)
|
||||||
|
#[clap(long, hide(true))]
|
||||||
|
tauri: bool,
|
||||||
|
/// Set target directory for init
|
||||||
|
#[clap(short, long)]
|
||||||
|
directory: Option<String>,
|
||||||
|
/// Path of the Tauri project to use (relative to the cwd)
|
||||||
|
#[clap(short, long)]
|
||||||
|
tauri_path: Option<PathBuf>,
|
||||||
|
/// Author name
|
||||||
|
#[clap(short, long)]
|
||||||
|
author: Option<String>,
|
||||||
|
/// Whether to initialize an Android project for the plugin.
|
||||||
|
#[clap(long)]
|
||||||
|
android: bool,
|
||||||
|
/// Whether to initialize an iOS project for the plugin.
|
||||||
|
#[clap(long)]
|
||||||
|
ios: bool,
|
||||||
|
/// Whether to initialize Android and iOS projects for the plugin.
|
||||||
|
#[clap(long)]
|
||||||
|
mobile: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Options> for super::init::Options {
|
||||||
|
fn from(o: Options) -> Self {
|
||||||
|
Self {
|
||||||
|
plugin_name: Some(o.plugin_name),
|
||||||
|
no_api: o.no_api,
|
||||||
|
tauri: o.tauri,
|
||||||
|
directory: o.directory.unwrap(),
|
||||||
|
tauri_path: o.tauri_path,
|
||||||
|
author: o.author,
|
||||||
|
android: o.android,
|
||||||
|
ios: o.ios,
|
||||||
|
mobile: o.mobile,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn command(mut options: Options) -> Result<()> {
|
||||||
|
let cwd = std::env::current_dir()?;
|
||||||
|
if let Some(dir) = &options.directory {
|
||||||
|
std::fs::create_dir_all(cwd.join(dir))?;
|
||||||
|
} else {
|
||||||
|
let target = cwd.join(format!("tauri-plugin-{}", options.plugin_name));
|
||||||
|
std::fs::create_dir_all(&target)?;
|
||||||
|
options.directory.replace(target.display().to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
super::init::command(options.into())
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user