mirror of
https://github.com/tauri-apps/tauri.git
synced 2024-12-29 22:13:34 +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: MIT
|
||||
|
||||
use std::path::Path;
|
||||
|
||||
use clap::{Parser, Subcommand};
|
||||
|
||||
use crate::Result;
|
||||
@ -9,6 +11,7 @@ use crate::Result;
|
||||
mod android;
|
||||
mod init;
|
||||
mod ios;
|
||||
mod new;
|
||||
|
||||
#[derive(Parser)]
|
||||
#[clap(
|
||||
@ -25,6 +28,7 @@ pub struct Cli {
|
||||
|
||||
#[derive(Subcommand)]
|
||||
enum Commands {
|
||||
New(new::Options),
|
||||
Init(init::Options),
|
||||
Android(android::Cli),
|
||||
Ios(ios::Cli),
|
||||
@ -32,6 +36,7 @@ enum Commands {
|
||||
|
||||
pub fn command(cli: Cli) -> Result<()> {
|
||||
match cli.command {
|
||||
Commands::New(options) => new::command(options)?,
|
||||
Commands::Init(options) => init::command(options)?,
|
||||
Commands::Android(cli) => android::command(cli)?,
|
||||
Commands::Ios(cli) => ios::command(cli)?,
|
||||
@ -39,3 +44,30 @@ pub fn command(cli: Cli) -> Result<()> {
|
||||
|
||||
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)]
|
||||
enum Commands {
|
||||
Add(AddOptions),
|
||||
Init(InitOptions),
|
||||
}
|
||||
|
||||
#[derive(Debug, Parser)]
|
||||
#[clap(about = "Adds the Android project to an existing Tauri plugin")]
|
||||
pub struct AddOptions {
|
||||
#[clap(about = "Initializes the Android project for an existing Tauri plugin")]
|
||||
pub struct InitOptions {
|
||||
/// Name of your Tauri plugin. Must match the current plugin's name.
|
||||
#[clap(short = 'n', long = "name")]
|
||||
plugin_name: String,
|
||||
/// If not specified, it will be infered from the current directory.
|
||||
plugin_name: Option<String>,
|
||||
/// The output directory.
|
||||
#[clap(short, long)]
|
||||
#[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<()> {
|
||||
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);
|
||||
if out_dir.join("android").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(
|
||||
"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,
|
||||
)?
|
||||
@ -62,7 +67,7 @@ pub fn command(cli: Cli) -> Result<()> {
|
||||
let handlebars = Handlebars::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();
|
||||
template::render_with_generator(
|
||||
@ -114,7 +119,7 @@ pub fn init<R: Runtime>() -> TauriPlugin<R> {{
|
||||
.build()
|
||||
}}
|
||||
"#,
|
||||
name = options.plugin_name,
|
||||
name = plugin_name,
|
||||
identifier = plugin_id
|
||||
);
|
||||
|
||||
|
@ -11,7 +11,7 @@ use anyhow::Context;
|
||||
use clap::Parser;
|
||||
use dialoguer::Input;
|
||||
use handlebars::{to_json, Handlebars};
|
||||
use heck::{AsKebabCase, ToKebabCase, ToPascalCase, ToSnakeCase};
|
||||
use heck::{ToKebabCase, ToPascalCase, ToSnakeCase};
|
||||
use include_dir::{include_dir, Dir};
|
||||
use log::warn;
|
||||
use std::{
|
||||
@ -29,25 +29,34 @@ pub const TEMPLATE_DIR: Dir<'_> = include_dir!("templates/plugin");
|
||||
#[derive(Debug, Parser)]
|
||||
#[clap(about = "Initializes a Tauri plugin project")]
|
||||
pub struct Options {
|
||||
/// Name of your Tauri plugin
|
||||
#[clap(short = 'n', long = "name")]
|
||||
plugin_name: String,
|
||||
/// Name of your Tauri plugin.
|
||||
/// If not specified, it will be infered from the current directory.
|
||||
pub(crate) plugin_name: Option<String>,
|
||||
/// Initializes a Tauri plugin without the TypeScript API
|
||||
#[clap(long)]
|
||||
no_api: bool,
|
||||
pub(crate) no_api: bool,
|
||||
/// Initializes a Tauri core plugin (internal usage)
|
||||
#[clap(long, hide(true))]
|
||||
tauri: bool,
|
||||
pub(crate) tauri: bool,
|
||||
/// Set target directory for init
|
||||
#[clap(short, long)]
|
||||
#[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)
|
||||
#[clap(short, long)]
|
||||
tauri_path: Option<PathBuf>,
|
||||
pub(crate) tauri_path: Option<PathBuf>,
|
||||
/// Author name
|
||||
#[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 {
|
||||
@ -64,12 +73,15 @@ impl Options {
|
||||
|
||||
pub fn command(mut options: Options) -> Result<()> {
|
||||
options.load();
|
||||
let template_target_path = PathBuf::from(options.directory).join(format!(
|
||||
"tauri-plugin-{}",
|
||||
AsKebabCase(&options.plugin_name)
|
||||
));
|
||||
|
||||
let plugin_name = match 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()?;
|
||||
if template_target_path.exists() {
|
||||
if std::fs::read_dir(&template_target_path)?.count() > 0 {
|
||||
warn!("Plugin dir ({:?}) not empty.", template_target_path);
|
||||
} else {
|
||||
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);
|
||||
|
||||
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_example_dep", to_json(tauri_example_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(
|
||||
"What should be the Android Package ID for your plugin?",
|
||||
Some(format!("com.plugin.{}", options.plugin_name)),
|
||||
false,
|
||||
false,
|
||||
)?
|
||||
.unwrap();
|
||||
let plugin_id = if options.android || options.mobile {
|
||||
let plugin_id = request_input(
|
||||
"What should be the Android Package ID for your plugin?",
|
||||
Some(format!("com.plugin.{}", plugin_name)),
|
||||
false,
|
||||
false,
|
||||
)?
|
||||
.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();
|
||||
template::render_with_generator(
|
||||
@ -157,13 +174,18 @@ pub fn command(mut options: Options) -> Result<()> {
|
||||
}
|
||||
}
|
||||
"android" => {
|
||||
return generate_android_out_file(
|
||||
&path,
|
||||
&template_target_path,
|
||||
&plugin_id.replace('.', "/"),
|
||||
&mut created_dirs,
|
||||
);
|
||||
if options.android || options.mobile {
|
||||
return generate_android_out_file(
|
||||
&path,
|
||||
&template_target_path,
|
||||
&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" => {
|
||||
if options.no_api {
|
||||
return Ok(None);
|
||||
|
@ -29,15 +29,15 @@ pub struct Cli {
|
||||
|
||||
#[derive(Subcommand)]
|
||||
enum Commands {
|
||||
Add(AddOptions),
|
||||
Init(InitOptions),
|
||||
}
|
||||
|
||||
#[derive(Debug, Parser)]
|
||||
#[clap(about = "Adds the iOS project to an existing Tauri plugin")]
|
||||
pub struct AddOptions {
|
||||
#[clap(about = "Initializes the iOS project for an existing Tauri plugin")]
|
||||
pub struct InitOptions {
|
||||
/// Name of your Tauri plugin. Must match the current plugin's name.
|
||||
#[clap(short = 'n', long = "name")]
|
||||
plugin_name: String,
|
||||
/// If not specified, it will be infered from the current directory.
|
||||
plugin_name: Option<String>,
|
||||
/// The output directory.
|
||||
#[clap(short, long)]
|
||||
#[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<()> {
|
||||
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);
|
||||
if out_dir.join("ios").exists() {
|
||||
return Err(anyhow::anyhow!("ios folder already exists"));
|
||||
@ -55,7 +60,7 @@ pub fn command(cli: Cli) -> Result<()> {
|
||||
let handlebars = Handlebars::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();
|
||||
template::render_with_generator(
|
||||
@ -111,7 +116,7 @@ pub fn init<R: Runtime>() -> TauriPlugin<R> {{
|
||||
.build()
|
||||
}}
|
||||
"#,
|
||||
name = options.plugin_name,
|
||||
name = plugin_name,
|
||||
);
|
||||
|
||||
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