mirror of
https://github.com/tauri-apps/tauri.git
synced 2024-11-28 03:47:37 +03:00
feat(tauri) add app CLI interface config (#670)
This commit is contained in:
parent
577a044bfa
commit
14a1ddfe18
7
.changes/arg_parsing_feature.md
Normal file
7
.changes/arg_parsing_feature.md
Normal file
@ -0,0 +1,7 @@
|
||||
---
|
||||
"tauri.js": minor
|
||||
"tauri": minor
|
||||
"tauri-api": minor
|
||||
---
|
||||
|
||||
Adds a command line interface option to tauri apps, configurable under tauri.conf.json > tauri > cli.
|
4
.github/workflows/check-on-push.yml
vendored
4
.github/workflows/check-on-push.yml
vendored
@ -21,8 +21,8 @@ jobs:
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
env:
|
||||
TAURI_DIST_DIR: ${{ runner.workspace }}/tauri/tauri/test/fixture/dist
|
||||
TAURI_DIR: ${{ runner.workspace }}/tauri/tauri/test/fixture/src-tauri
|
||||
TAURI_DIST_DIR: ${{ runner.workspace }}/tauri/tauri/examples/communication/dist
|
||||
TAURI_DIR: ${{ runner.workspace }}/tauri/tauri/examples/communication/src-tauri
|
||||
|
||||
eslint-check:
|
||||
runs-on: ubuntu-latest
|
||||
|
12
.github/workflows/release-cargo.yml
vendored
12
.github/workflows/release-cargo.yml
vendored
@ -58,8 +58,8 @@ jobs:
|
||||
if: env.PACKAGE_VERSION != env.PUBLISHED_VERSION
|
||||
working-directory: ${{ matrix.package.path }}
|
||||
env:
|
||||
TAURI_DIST_DIR: ${{ runner.workspace }}/tauri/tauri/test/fixture/dist
|
||||
TAURI_DIR: ${{ runner.workspace }}/tauri/tauri/test/fixture/src-tauri
|
||||
TAURI_DIST_DIR: ${{ runner.workspace }}/tauri/tauri/examples/communication/dist
|
||||
TAURI_DIR: ${{ runner.workspace }}/tauri/tauri/examples/communication/src-tauri
|
||||
run: |
|
||||
cargo package --no-verify
|
||||
echo "We will publish:" $PACKAGE_VERSION
|
||||
@ -68,8 +68,8 @@ jobs:
|
||||
if: env.PACKAGE_VERSION != env.PUBLISHED_VERSION
|
||||
working-directory: ${{ matrix.package.path }}
|
||||
env:
|
||||
TAURI_DIST_DIR: ${{ runner.workspace }}/tauri/tauri/test/fixture/dist
|
||||
TAURI_DIR: ${{ runner.workspace }}/tauri/tauri/test/fixture/src-tauri
|
||||
TAURI_DIST_DIR: ${{ runner.workspace }}/tauri/tauri/examples/communication/dist
|
||||
TAURI_DIR: ${{ runner.workspace }}/tauri/tauri/examples/communication/src-tauri
|
||||
run: |
|
||||
cargo install cargo-audit
|
||||
echo "# Cargo Audit" | tee -a ${{runner.workspace }}/notes.md
|
||||
@ -80,8 +80,8 @@ jobs:
|
||||
if: env.PACKAGE_VERSION != env.PUBLISHED_VERSION
|
||||
working-directory: ${{ matrix.package.path }}
|
||||
env:
|
||||
TAURI_DIST_DIR: ${{ runner.workspace }}/tauri/tauri/test/fixture/dist
|
||||
TAURI_DIR: ${{ runner.workspace }}/tauri/tauri/test/fixture/src-tauri
|
||||
TAURI_DIST_DIR: ${{ runner.workspace }}/tauri/tauri/examples/communication/dist
|
||||
TAURI_DIR: ${{ runner.workspace }}/tauri/tauri/examples/communication/src-tauri
|
||||
run: |
|
||||
echo "# Cargo Publish" | tee -a ${{runner.workspace }}/notes.md
|
||||
echo "\`\`\`" >> ${{runner.workspace }}/notes.md
|
||||
|
8
.github/workflows/test-on-pr.yml
vendored
8
.github/workflows/test-on-pr.yml
vendored
@ -27,14 +27,14 @@ jobs:
|
||||
cd ./tauri
|
||||
cargo build
|
||||
env:
|
||||
TAURI_DIST_DIR: ${{ runner.workspace }}/tauri/tauri/test/fixture/dist
|
||||
TAURI_DIR: ${{ runner.workspace }}/tauri/tauri/test/fixture/src-tauri
|
||||
TAURI_DIST_DIR: ${{ runner.workspace }}/tauri/tauri/examples/communication/dist
|
||||
TAURI_DIR: ${{ runner.workspace }}/tauri/tauri/examples/communication/src-tauri
|
||||
- name: test
|
||||
run: |
|
||||
cargo test
|
||||
env:
|
||||
TAURI_DIST_DIR: ${{ runner.workspace }}/tauri/tauri/test/fixture/dist
|
||||
TAURI_DIR: ${{ runner.workspace }}/tauri/tauri/test/fixture/src-tauri
|
||||
TAURI_DIST_DIR: ${{ runner.workspace }}/tauri/tauri/examples/communication/dist
|
||||
TAURI_DIR: ${{ runner.workspace }}/tauri/tauri/examples/communication/src-tauri
|
||||
|
||||
build-tauri-bundler:
|
||||
runs-on: ${{ matrix.platform }}
|
||||
|
12
cli/tauri.js/api/cli.js
Normal file
12
cli/tauri.js/api/cli.js
Normal file
@ -0,0 +1,12 @@
|
||||
import tauri from './tauri'
|
||||
|
||||
/**
|
||||
* gets the CLI matches
|
||||
*/
|
||||
function getMatches() {
|
||||
return tauri.cliMatches()
|
||||
}
|
||||
|
||||
export {
|
||||
getMatches
|
||||
}
|
@ -500,6 +500,10 @@ class Runner {
|
||||
tomlFeatures.push('edge')
|
||||
}
|
||||
|
||||
if (cfg.tauri.cli) {
|
||||
tomlFeatures.push('cli')
|
||||
}
|
||||
|
||||
if (typeof manifest.dependencies.tauri === 'string') {
|
||||
manifest.dependencies.tauri = {
|
||||
version: manifest.dependencies.tauri,
|
||||
|
@ -7,6 +7,7 @@ export default {
|
||||
},
|
||||
ctx: {},
|
||||
tauri: {
|
||||
cli: null,
|
||||
embeddedServer: {
|
||||
active: true
|
||||
},
|
||||
|
@ -1,6 +1,39 @@
|
||||
// TODO: Clean up types, properly mark which ones are optional
|
||||
// May need to have different types for each stage of config generation process
|
||||
|
||||
export interface CliArg {
|
||||
short?: string
|
||||
name: string
|
||||
description?: string
|
||||
longDescription?: string
|
||||
takesValue?: boolean
|
||||
multiple?: boolean
|
||||
possibleValues?: string[]
|
||||
minValues?: number
|
||||
maxValues?: number
|
||||
required?: boolean
|
||||
requiredUnless?: string
|
||||
requiredUnlessAll?: string[]
|
||||
requiredUnlessOne?: string[]
|
||||
conflictsWith?: string
|
||||
conflictsWithAll?: string
|
||||
requires?: string
|
||||
requiresAll?: string[]
|
||||
requiresIf?: [string, string]
|
||||
requiredIf?: [string, string]
|
||||
requireEquals?: boolean
|
||||
global?: boolean
|
||||
}
|
||||
|
||||
export interface CliConfig {
|
||||
args?: CliArg[]
|
||||
description?: string
|
||||
longDescription?: string
|
||||
beforeHelp?: string
|
||||
afterHelp?: string
|
||||
subcommands?: { [name: string]: CliConfig }
|
||||
}
|
||||
|
||||
export interface TauriConfig {
|
||||
build: {
|
||||
distDir: string
|
||||
@ -17,6 +50,7 @@ export interface TauriConfig {
|
||||
exitOnPanic?: boolean
|
||||
}
|
||||
tauri: {
|
||||
cli: CliConfig
|
||||
inlinedAssets: string[]
|
||||
devPath: string
|
||||
embeddedServer: {
|
||||
|
@ -655,6 +655,21 @@ window.tauri = {
|
||||
asset: assetName,
|
||||
assetType: assetType || 'unknown'
|
||||
})
|
||||
},
|
||||
|
||||
cliMatches: function () {
|
||||
<% if (tauri.cli) { %>
|
||||
return this.promisified({
|
||||
cmd: 'cliMatches'
|
||||
})
|
||||
<% } else { %>
|
||||
<% if (ctx.dev) { %>
|
||||
console.error('You must add the CLI args configuration under tauri.conf.json > tauri > cli')
|
||||
return __reject()
|
||||
<% } %>
|
||||
return __reject()
|
||||
<% } %>
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -11,7 +11,8 @@
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"types": ["src/types"]
|
||||
}
|
||||
},
|
||||
"resolveJsonModule": true
|
||||
},
|
||||
"include": ["src"]
|
||||
}
|
||||
|
@ -29,8 +29,13 @@ nfd = "0.0.4"
|
||||
attohttpc = {version = "0.14.0", features=["json", "form" ]}
|
||||
http = "0.2"
|
||||
tauri-utils = {version = "0.5", path = "../tauri-utils"}
|
||||
envmnt = "0.8.2"
|
||||
clap = { git = "https://github.com/clap-rs/clap", rev = "1a276f8", version = "3.0.0-beta.1", optional = true }
|
||||
|
||||
[dev-dependencies]
|
||||
quickcheck = "0.9.2"
|
||||
quickcheck_macros = "0.9.1"
|
||||
totems = "0.2.7"
|
||||
|
||||
[features]
|
||||
cli = ["clap"]
|
153
tauri-api/src/cli.rs
Normal file
153
tauri-api/src/cli.rs
Normal file
@ -0,0 +1,153 @@
|
||||
use crate::config::{Cli, Config};
|
||||
|
||||
use clap::{App, Arg, ArgMatches};
|
||||
use serde::Serialize;
|
||||
use serde_json::Value;
|
||||
use std::collections::HashMap;
|
||||
|
||||
#[macro_use]
|
||||
mod macros;
|
||||
|
||||
#[derive(Default, Debug, Serialize)]
|
||||
pub struct ArgData {
|
||||
value: Value,
|
||||
occurrences: u64,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Serialize)]
|
||||
pub struct SubcommandMatches {
|
||||
name: String,
|
||||
matches: Matches,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Serialize)]
|
||||
pub struct Matches {
|
||||
args: HashMap<String, ArgData>,
|
||||
subcommand: Option<Box<SubcommandMatches>>,
|
||||
}
|
||||
|
||||
impl Matches {
|
||||
pub(crate) fn set_arg(&mut self, name: String, value: ArgData) {
|
||||
self.args.insert(name, value);
|
||||
}
|
||||
|
||||
pub(crate) fn set_subcommand(&mut self, name: String, matches: Matches) {
|
||||
self.subcommand = Some(Box::new(SubcommandMatches { name, matches }));
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_matches(config: Config) -> Matches {
|
||||
let cli = config.tauri.cli.unwrap();
|
||||
|
||||
let about = cli
|
||||
.description()
|
||||
.unwrap_or(&crate_description!().to_string())
|
||||
.to_string();
|
||||
let app = get_app(crate_name!(), Some(&about), &cli);
|
||||
let matches = app.get_matches();
|
||||
get_matches_internal(&cli, &matches)
|
||||
}
|
||||
|
||||
fn get_matches_internal<T: Cli + 'static>(config: &T, matches: &ArgMatches) -> Matches {
|
||||
let mut cli_matches = Matches::default();
|
||||
map_matches(config, matches, &mut cli_matches);
|
||||
|
||||
let (subcommand_name, subcommand_matches_option) = matches.subcommand();
|
||||
if let Some(subcommand_matches) = subcommand_matches_option {
|
||||
let mut subcommand_cli_matches = Matches::default();
|
||||
map_matches(
|
||||
config.subcommands().unwrap().get(subcommand_name).unwrap(),
|
||||
subcommand_matches,
|
||||
&mut subcommand_cli_matches,
|
||||
);
|
||||
cli_matches.set_subcommand(subcommand_name.to_string(), subcommand_cli_matches);
|
||||
}
|
||||
|
||||
cli_matches
|
||||
}
|
||||
|
||||
fn map_matches<T: Cli + 'static>(config: &T, matches: &ArgMatches, cli_matches: &mut Matches) {
|
||||
if let Some(args) = config.args() {
|
||||
for arg in args {
|
||||
let occurrences = matches.occurrences_of(arg.name.clone());
|
||||
let value = if occurrences == 0 || !arg.takes_value.unwrap_or(false) {
|
||||
Value::Null
|
||||
} else if arg.multiple.unwrap_or(false) {
|
||||
matches
|
||||
.values_of(arg.name.clone())
|
||||
.map(|v| {
|
||||
let mut values = Vec::new();
|
||||
for value in v {
|
||||
values.push(Value::String(value.to_string()));
|
||||
}
|
||||
Value::Array(values)
|
||||
})
|
||||
.unwrap_or(Value::Null)
|
||||
} else {
|
||||
matches
|
||||
.value_of(arg.name.clone())
|
||||
.map(|v| Value::String(v.to_string()))
|
||||
.unwrap_or(Value::Null)
|
||||
};
|
||||
|
||||
cli_matches.set_arg(arg.name.clone(), ArgData { value, occurrences });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn get_app<'a, T: Cli + 'static>(name: &str, about: Option<&'a String>, config: &'a T) -> App<'a> {
|
||||
let mut app = App::new(name)
|
||||
.author(crate_authors!())
|
||||
.version(crate_version!());
|
||||
|
||||
if let Some(about) = about {
|
||||
app = app.about(&**about);
|
||||
}
|
||||
if let Some(long_description) = config.long_description() {
|
||||
app = app.long_about(&**long_description);
|
||||
}
|
||||
|
||||
if let Some(args) = config.args() {
|
||||
for arg in args {
|
||||
let arg_name = arg.name.as_ref();
|
||||
let mut clap_arg = Arg::new(arg_name).long(arg_name);
|
||||
|
||||
if let Some(short) = arg.short {
|
||||
clap_arg = clap_arg.short(short);
|
||||
}
|
||||
|
||||
clap_arg = bind_string_arg!(arg, clap_arg, description, about);
|
||||
clap_arg = bind_string_arg!(arg, clap_arg, long_description, long_about);
|
||||
clap_arg = bind_value_arg!(arg, clap_arg, takes_value);
|
||||
clap_arg = bind_value_arg!(arg, clap_arg, multiple);
|
||||
clap_arg = bind_value_arg!(arg, clap_arg, multiple_occurrences);
|
||||
clap_arg = bind_value_arg!(arg, clap_arg, number_of_values);
|
||||
clap_arg = bind_string_slice_arg!(arg, clap_arg, possible_values);
|
||||
clap_arg = bind_value_arg!(arg, clap_arg, min_values);
|
||||
clap_arg = bind_value_arg!(arg, clap_arg, max_values);
|
||||
clap_arg = bind_string_arg!(arg, clap_arg, required_unless, required_unless);
|
||||
clap_arg = bind_value_arg!(arg, clap_arg, required);
|
||||
clap_arg = bind_string_arg!(arg, clap_arg, required_unless, required_unless);
|
||||
clap_arg = bind_string_slice_arg!(arg, clap_arg, required_unless_all);
|
||||
clap_arg = bind_string_slice_arg!(arg, clap_arg, required_unless_one);
|
||||
clap_arg = bind_string_arg!(arg, clap_arg, conflicts_with, conflicts_with);
|
||||
clap_arg = bind_string_slice_arg!(arg, clap_arg, conflicts_with_all);
|
||||
clap_arg = bind_string_arg!(arg, clap_arg, requires, requires);
|
||||
clap_arg = bind_string_slice_arg!(arg, clap_arg, requires_all);
|
||||
clap_arg = bind_if_arg!(arg, clap_arg, requires_if);
|
||||
clap_arg = bind_if_arg!(arg, clap_arg, required_if);
|
||||
clap_arg = bind_value_arg!(arg, clap_arg, require_equals);
|
||||
|
||||
app = app.arg(clap_arg);
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(subcommands) = config.subcommands() {
|
||||
for (subcommand_name, subcommand) in subcommands {
|
||||
let clap_subcommand = get_app(&subcommand_name, subcommand.description(), subcommand);
|
||||
app = app.subcommand(clap_subcommand);
|
||||
}
|
||||
}
|
||||
|
||||
app
|
||||
}
|
45
tauri-api/src/cli/macros.rs
Normal file
45
tauri-api/src/cli/macros.rs
Normal file
@ -0,0 +1,45 @@
|
||||
macro_rules! bind_string_arg {
|
||||
($arg:expr, $clap_arg:expr, $arg_name:ident, $clap_field:ident) => {{
|
||||
let arg = $arg;
|
||||
let mut clap_arg = $clap_arg;
|
||||
if let Some(value) = &arg.$arg_name {
|
||||
clap_arg = clap_arg.$clap_field(value);
|
||||
}
|
||||
clap_arg
|
||||
}}
|
||||
}
|
||||
|
||||
macro_rules! bind_value_arg {
|
||||
($arg:expr, $clap_arg:expr, $field:ident) => {{
|
||||
let arg = $arg;
|
||||
let mut clap_arg = $clap_arg;
|
||||
if let Some(value) = arg.$field {
|
||||
clap_arg = clap_arg.$field(value);
|
||||
}
|
||||
clap_arg
|
||||
}}
|
||||
}
|
||||
|
||||
macro_rules! bind_string_slice_arg {
|
||||
($arg:expr, $clap_arg:expr, $field:ident) => {{
|
||||
let arg = $arg;
|
||||
let mut clap_arg = $clap_arg;
|
||||
if let Some(value) = &arg.$field {
|
||||
let v: Vec<&str> = value.iter().map(|x| &**x).collect();
|
||||
clap_arg = clap_arg.$field(&v);
|
||||
}
|
||||
clap_arg
|
||||
}}
|
||||
}
|
||||
|
||||
macro_rules! bind_if_arg {
|
||||
($arg:expr, $clap_arg:expr, $field:ident) => {{
|
||||
let arg = $arg;
|
||||
let mut clap_arg = $clap_arg;
|
||||
if let Some(value) = &arg.$field {
|
||||
let v: Vec<&str> = value.iter().map(|x| &**x).collect();
|
||||
clap_arg = clap_arg.$field(&v[0], &v[1]);
|
||||
}
|
||||
clap_arg
|
||||
}}
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
use serde::Deserialize;
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::{fs, path};
|
||||
|
||||
#[derive(PartialEq, Deserialize, Clone, Debug)]
|
||||
@ -67,6 +68,99 @@ fn default_embedded_server() -> EmbeddedServerConfig {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Deserialize, Clone, Debug, Default)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CliArg {
|
||||
pub short: Option<char>,
|
||||
pub name: String,
|
||||
pub description: Option<String>,
|
||||
pub long_description: Option<String>,
|
||||
pub takes_value: Option<bool>,
|
||||
pub multiple: Option<bool>,
|
||||
pub multiple_occurrences: Option<bool>,
|
||||
pub number_of_values: Option<u64>,
|
||||
pub possible_values: Option<Vec<String>>,
|
||||
pub min_values: Option<u64>,
|
||||
pub max_values: Option<u64>,
|
||||
pub required: Option<bool>,
|
||||
pub required_unless: Option<String>,
|
||||
pub required_unless_all: Option<Vec<String>>,
|
||||
pub required_unless_one: Option<Vec<String>>,
|
||||
pub conflicts_with: Option<String>,
|
||||
pub conflicts_with_all: Option<Vec<String>>,
|
||||
pub requires: Option<String>,
|
||||
pub requires_all: Option<Vec<String>>,
|
||||
pub requires_if: Option<Vec<String>>,
|
||||
pub required_if: Option<Vec<String>>,
|
||||
pub require_equals: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Deserialize, Clone, Debug)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CliSubcommand {
|
||||
description: Option<String>,
|
||||
long_description: Option<String>,
|
||||
before_help: Option<String>,
|
||||
after_help: Option<String>,
|
||||
args: Option<Vec<CliArg>>,
|
||||
subcommands: Option<HashMap<String, CliSubcommand>>,
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Deserialize, Clone, Debug)]
|
||||
#[serde(tag = "cli", rename_all = "camelCase")]
|
||||
pub struct CliConfig {
|
||||
description: Option<String>,
|
||||
long_description: Option<String>,
|
||||
before_help: Option<String>,
|
||||
after_help: Option<String>,
|
||||
args: Option<Vec<CliArg>>,
|
||||
subcommands: Option<HashMap<String, CliSubcommand>>,
|
||||
}
|
||||
|
||||
pub trait Cli {
|
||||
fn args(&self) -> Option<&Vec<CliArg>>;
|
||||
fn subcommands(&self) -> Option<&HashMap<String, CliSubcommand>>;
|
||||
fn description(&self) -> Option<&String>;
|
||||
fn long_description(&self) -> Option<&String>;
|
||||
fn before_help(&self) -> Option<&String>;
|
||||
fn after_help(&self) -> Option<&String>;
|
||||
}
|
||||
|
||||
macro_rules! impl_cli {
|
||||
( $($field_name:ident),+ $(,)?) => {
|
||||
$(
|
||||
impl Cli for $field_name {
|
||||
|
||||
fn args(&self) -> Option<&Vec<CliArg>> {
|
||||
self.args.as_ref()
|
||||
}
|
||||
|
||||
fn subcommands(&self) -> Option<&HashMap<String, CliSubcommand>> {
|
||||
self.subcommands.as_ref()
|
||||
}
|
||||
|
||||
fn description(&self) -> Option<&String> {
|
||||
self.description.as_ref()
|
||||
}
|
||||
|
||||
fn long_description(&self) -> Option<&String> {
|
||||
self.description.as_ref()
|
||||
}
|
||||
|
||||
fn before_help(&self) -> Option<&String> {
|
||||
self.before_help.as_ref()
|
||||
}
|
||||
|
||||
fn after_help(&self) -> Option<&String> {
|
||||
self.after_help.as_ref()
|
||||
}
|
||||
}
|
||||
)+
|
||||
}
|
||||
}
|
||||
|
||||
impl_cli!(CliSubcommand, CliConfig);
|
||||
|
||||
#[derive(PartialEq, Deserialize, Clone, Debug)]
|
||||
#[serde(tag = "tauri", rename_all = "camelCase")]
|
||||
pub struct TauriConfig {
|
||||
@ -74,6 +168,8 @@ pub struct TauriConfig {
|
||||
pub window: WindowConfig,
|
||||
#[serde(default = "default_embedded_server")]
|
||||
pub embedded_server: EmbeddedServerConfig,
|
||||
#[serde(default)]
|
||||
pub cli: Option<CliConfig>,
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Deserialize, Clone, Debug)]
|
||||
@ -100,6 +196,7 @@ fn default_tauri() -> TauriConfig {
|
||||
TauriConfig {
|
||||
window: default_window(),
|
||||
embedded_server: default_embedded_server(),
|
||||
cli: None,
|
||||
}
|
||||
}
|
||||
|
||||
@ -127,22 +224,74 @@ mod test {
|
||||
use super::*;
|
||||
// generate a test_config based on the test fixture
|
||||
fn create_test_config() -> Config {
|
||||
let mut subcommands = std::collections::HashMap::new();
|
||||
subcommands.insert(
|
||||
"update".to_string(),
|
||||
CliSubcommand {
|
||||
description: Some("Updates the app".to_string()),
|
||||
long_description: None,
|
||||
before_help: None,
|
||||
after_help: None,
|
||||
args: Some(vec![CliArg {
|
||||
short: Some('b'),
|
||||
name: "background".to_string(),
|
||||
description: Some("Update in background".to_string()),
|
||||
..Default::default()
|
||||
}]),
|
||||
subcommands: None,
|
||||
},
|
||||
);
|
||||
Config {
|
||||
tauri: TauriConfig {
|
||||
window: WindowConfig {
|
||||
width: 800,
|
||||
height: 600,
|
||||
resizable: true,
|
||||
title: String::from("Tauri App"),
|
||||
title: String::from("Tauri API Validation"),
|
||||
fullscreen: false,
|
||||
},
|
||||
embedded_server: EmbeddedServerConfig {
|
||||
host: String::from("http://127.0.0.1"),
|
||||
port: String::from("random"),
|
||||
},
|
||||
cli: Some(CliConfig {
|
||||
description: Some("Tauri communication example".to_string()),
|
||||
long_description: None,
|
||||
before_help: None,
|
||||
after_help: None,
|
||||
args: Some(vec![
|
||||
CliArg {
|
||||
short: Some('c'),
|
||||
name: "config".to_string(),
|
||||
takes_value: Some(true),
|
||||
description: Some("Config path".to_string()),
|
||||
..Default::default()
|
||||
},
|
||||
CliArg {
|
||||
short: Some('t'),
|
||||
name: "theme".to_string(),
|
||||
takes_value: Some(true),
|
||||
description: Some("App theme".to_string()),
|
||||
possible_values: Some(vec![
|
||||
"light".to_string(),
|
||||
"dark".to_string(),
|
||||
"system".to_string(),
|
||||
]),
|
||||
..Default::default()
|
||||
},
|
||||
CliArg {
|
||||
short: Some('v'),
|
||||
name: "verbose".to_string(),
|
||||
multiple_occurrences: Some(true),
|
||||
description: Some("Verbosity level".to_string()),
|
||||
..Default::default()
|
||||
},
|
||||
]),
|
||||
subcommands: Some(subcommands),
|
||||
}),
|
||||
},
|
||||
build: BuildConfig {
|
||||
dev_path: String::from("http://localhost:4000"),
|
||||
dev_path: String::from("../dist"),
|
||||
},
|
||||
}
|
||||
}
|
||||
@ -196,6 +345,7 @@ mod test {
|
||||
host: String::from("http://127.0.0.1"),
|
||||
port: String::from("random"),
|
||||
},
|
||||
cli: None,
|
||||
};
|
||||
|
||||
// create a build config
|
@ -4,6 +4,7 @@
|
||||
)]
|
||||
|
||||
pub mod command;
|
||||
pub mod config;
|
||||
pub mod dialog;
|
||||
pub mod dir;
|
||||
pub mod file;
|
||||
@ -13,6 +14,12 @@ pub mod rpc;
|
||||
pub mod tcp;
|
||||
pub mod version;
|
||||
|
||||
#[cfg(feature = "cli")]
|
||||
pub mod cli;
|
||||
#[cfg(feature = "cli")]
|
||||
#[macro_use]
|
||||
extern crate clap;
|
||||
|
||||
pub use tauri_utils::*;
|
||||
|
||||
pub use anyhow::Result;
|
||||
|
@ -39,6 +39,7 @@ tauri = {path = ".", features = [ "all-api", "edge" ]}
|
||||
serde = { version = "1.0", features = [ "derive" ] }
|
||||
|
||||
[features]
|
||||
cli = ["tauri-api/cli"]
|
||||
edge = ["web-view/edge"]
|
||||
embedded-server = ["tiny_http"]
|
||||
no-server = []
|
||||
@ -66,4 +67,3 @@ features = ["all-api"]
|
||||
[[example]]
|
||||
name = "communication"
|
||||
path = "examples/communication/src-tauri/src/main.rs"
|
||||
|
||||
|
5
tauri/examples/communication/dist/cli.js
vendored
Normal file
5
tauri/examples/communication/dist/cli.js
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
document.getElementById('cli-matches').addEventListener('click', function () {
|
||||
window.tauri.cliMatches()
|
||||
.then(registerResponse)
|
||||
.catch(registerResponse)
|
||||
})
|
535
tauri/examples/communication/dist/index.html
vendored
535
tauri/examples/communication/dist/index.html
vendored
@ -1,279 +1,312 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<style>
|
||||
* {
|
||||
font-family:Arial, Helvetica, sans-serif;
|
||||
}
|
||||
body {
|
||||
background: #889;
|
||||
}
|
||||
.logo-container {
|
||||
width: 95%;
|
||||
margin: 0px auto;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.logo-link {
|
||||
font-weight: 700;
|
||||
position: absolute;
|
||||
top:150px;
|
||||
right: 10px;
|
||||
}
|
||||
<head>
|
||||
<style>
|
||||
* {
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
}
|
||||
|
||||
.logo {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
cursor: pointer;
|
||||
position: fixed;
|
||||
z-index: 10;
|
||||
top:7px;
|
||||
right: 10px;
|
||||
}
|
||||
#response {
|
||||
position: absolute;
|
||||
left:10px;
|
||||
right:10px;
|
||||
top:440px;
|
||||
min-height:110px;
|
||||
background: #aab;
|
||||
font-family: 'Courier New', Courier, monospace;
|
||||
font-size: 12px;
|
||||
word-wrap: break-word;
|
||||
padding: 5px;
|
||||
border-radius:5px;
|
||||
overflow-y:auto;
|
||||
}
|
||||
body {
|
||||
background: #889;
|
||||
}
|
||||
|
||||
input, select {
|
||||
background: white;
|
||||
font-family: system-ui, sans-serif;
|
||||
border: 0;
|
||||
border-radius: 0.25rem;
|
||||
font-size: 1rem;
|
||||
line-height: 1.2;
|
||||
padding: 0.25rem 0.5rem;
|
||||
margin: 0.25rem;
|
||||
}
|
||||
.logo-container {
|
||||
width: 95%;
|
||||
margin: 0px auto;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
button:hover,
|
||||
button:focus {
|
||||
background: #0053ba;
|
||||
}
|
||||
.logo-link {
|
||||
font-weight: 700;
|
||||
position: absolute;
|
||||
top: 150px;
|
||||
right: 10px;
|
||||
}
|
||||
|
||||
button:focus {
|
||||
outline: 1px solid #fff;
|
||||
outline-offset: -4px;
|
||||
}
|
||||
.logo {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
cursor: pointer;
|
||||
position: fixed;
|
||||
z-index: 10;
|
||||
top: 7px;
|
||||
right: 10px;
|
||||
}
|
||||
|
||||
button:active {
|
||||
transform: scale(0.99);
|
||||
}
|
||||
.button {
|
||||
border: 0;
|
||||
border-radius: 0.25rem;
|
||||
background: #1E88E5;
|
||||
color: white;
|
||||
font-family: system-ui, sans-serif;
|
||||
font-size: 1rem;
|
||||
line-height: 1.2;
|
||||
white-space: nowrap;
|
||||
text-decoration: none;
|
||||
padding: 0.25rem 0.5rem;
|
||||
margin: 0.25rem;
|
||||
cursor: pointer;
|
||||
}
|
||||
.bottom {
|
||||
position:fixed;
|
||||
bottom:0;
|
||||
left:0;
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
padding: 5px;
|
||||
background: #333;
|
||||
color: #eef;
|
||||
}
|
||||
.dark-link {
|
||||
color: white;
|
||||
text-decoration: none!important;
|
||||
}
|
||||
#response {
|
||||
position: absolute;
|
||||
left: 10px;
|
||||
right: 10px;
|
||||
top: 440px;
|
||||
min-height: 110px;
|
||||
background: #aab;
|
||||
font-family: 'Courier New', Courier, monospace;
|
||||
font-size: 12px;
|
||||
word-wrap: break-word;
|
||||
padding: 5px;
|
||||
border-radius: 5px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.tabs-container {
|
||||
position:fixed;
|
||||
height: 400px;
|
||||
top:20px;
|
||||
left:10px;
|
||||
right:10px;
|
||||
z-index: 9;
|
||||
}
|
||||
.tabs {
|
||||
position: relative;
|
||||
min-height: 400px;
|
||||
clear: both;
|
||||
}
|
||||
.tab {
|
||||
float: left;
|
||||
}
|
||||
.tab > label {
|
||||
background: #eee;
|
||||
padding: 10px;
|
||||
border: 1px solid transparent;
|
||||
margin-left: -1px;
|
||||
position: relative;
|
||||
left: 1px;
|
||||
}
|
||||
.tabs > .tabber {
|
||||
border-top-left-radius: 5px;
|
||||
}
|
||||
.tabs > .tabber ~ .tabber {
|
||||
border-top-left-radius: none;
|
||||
}
|
||||
.tab [type=radio] {
|
||||
display: none;
|
||||
}
|
||||
.content {
|
||||
position: absolute;
|
||||
top: 28px;
|
||||
left: 0;
|
||||
background: #bbc;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
padding: 20px;
|
||||
border: 1px solid transparent;
|
||||
border-top-right-radius: 5px;
|
||||
border-bottom-left-radius: 5px;
|
||||
border-bottom-right-radius: 5px;
|
||||
}
|
||||
[type=radio]:checked ~ label {
|
||||
background: #bbc;
|
||||
border-bottom: 1px solid transparent;
|
||||
z-index: 2;
|
||||
}
|
||||
[type=radio]:checked ~ label ~ .content {
|
||||
z-index: 1;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="logo-container">
|
||||
<img src="icon.png" class="logo">
|
||||
</div>
|
||||
input,
|
||||
select {
|
||||
background: white;
|
||||
font-family: system-ui, sans-serif;
|
||||
border: 0;
|
||||
border-radius: 0.25rem;
|
||||
font-size: 1rem;
|
||||
line-height: 1.2;
|
||||
padding: 0.25rem 0.5rem;
|
||||
margin: 0.25rem;
|
||||
}
|
||||
|
||||
<div class="tabs-container">
|
||||
<div class="tabs">
|
||||
<div class="tab">
|
||||
<input type="radio" id="tab-1" name="tab-group-1" checked>
|
||||
<label class="tabber" for="tab-1">Messages</label>
|
||||
<div class="content">
|
||||
<button class="button" id="log">Call Log API</button>
|
||||
<button class="button" id="request">Call Request (async) API</button>
|
||||
<button class="button" id="event">Send event to Rust</button>
|
||||
button:hover,
|
||||
button:focus {
|
||||
background: #0053ba;
|
||||
}
|
||||
|
||||
<div style="margin-top: 24px">
|
||||
<input id="title" value="Awesome Tauri Example!">
|
||||
<button class="button" id="set-title">Set title</button>
|
||||
</div>
|
||||
button:focus {
|
||||
outline: 1px solid #fff;
|
||||
outline-offset: -4px;
|
||||
}
|
||||
|
||||
button:active {
|
||||
transform: scale(0.99);
|
||||
}
|
||||
|
||||
.button {
|
||||
border: 0;
|
||||
border-radius: 0.25rem;
|
||||
background: #1E88E5;
|
||||
color: white;
|
||||
font-family: system-ui, sans-serif;
|
||||
font-size: 1rem;
|
||||
line-height: 1.2;
|
||||
white-space: nowrap;
|
||||
text-decoration: none;
|
||||
padding: 0.25rem 0.5rem;
|
||||
margin: 0.25rem;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.bottom {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
padding: 5px;
|
||||
background: #333;
|
||||
color: #eef;
|
||||
}
|
||||
|
||||
.dark-link {
|
||||
color: white;
|
||||
text-decoration: none !important;
|
||||
}
|
||||
|
||||
.tabs-container {
|
||||
position: fixed;
|
||||
height: 400px;
|
||||
top: 20px;
|
||||
left: 10px;
|
||||
right: 10px;
|
||||
z-index: 9;
|
||||
}
|
||||
|
||||
.tabs {
|
||||
position: relative;
|
||||
min-height: 400px;
|
||||
clear: both;
|
||||
}
|
||||
|
||||
.tab {
|
||||
float: left;
|
||||
}
|
||||
|
||||
.tab>label {
|
||||
background: #eee;
|
||||
padding: 10px;
|
||||
border: 1px solid transparent;
|
||||
margin-left: -1px;
|
||||
position: relative;
|
||||
left: 1px;
|
||||
}
|
||||
|
||||
.tabs>.tabber {
|
||||
border-top-left-radius: 5px;
|
||||
}
|
||||
|
||||
.tabs>.tabber~.tabber {
|
||||
border-top-left-radius: none;
|
||||
}
|
||||
|
||||
.tab [type=radio] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.content {
|
||||
position: absolute;
|
||||
top: 28px;
|
||||
left: 0;
|
||||
background: #bbc;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
padding: 20px;
|
||||
border: 1px solid transparent;
|
||||
border-top-right-radius: 5px;
|
||||
border-bottom-left-radius: 5px;
|
||||
border-bottom-right-radius: 5px;
|
||||
}
|
||||
|
||||
[type=radio]:checked~label {
|
||||
background: #bbc;
|
||||
border-bottom: 1px solid transparent;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
[type=radio]:checked~label~.content {
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="logo-container">
|
||||
<img src="icon.png" class="logo">
|
||||
</div>
|
||||
|
||||
<div class="tabs-container">
|
||||
<div class="tabs">
|
||||
<div class="tab">
|
||||
<input type="radio" id="tab-1" name="tab-group-1" checked>
|
||||
<label class="tabber" for="tab-1">Messages</label>
|
||||
<div class="content">
|
||||
<button class="button" id="log">Call Log API</button>
|
||||
<button class="button" id="request">Call Request (async) API</button>
|
||||
<button class="button" id="event">Send event to Rust</button>
|
||||
|
||||
<div style="margin-top: 24px">
|
||||
<input id="title" value="Awesome Tauri Example!">
|
||||
<button class="button" id="set-title">Set title</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="tab">
|
||||
<input type="radio" id="tab-2" name="tab-group-1">
|
||||
<label class="tabber" for="tab-2">File System</label>
|
||||
<div class="content">
|
||||
<div style="margin-top: 24px">
|
||||
<select class="button" id="dir">
|
||||
<option value="">None</option>
|
||||
</select>
|
||||
<input id="path-to-read" placeholder="Type the path to read...">
|
||||
<button class="button" id="read">Read</button>
|
||||
</div>
|
||||
<div class="tab">
|
||||
<input type="radio" id="tab-2" name="tab-group-1">
|
||||
<label class="tabber" for="tab-2">File System</label>
|
||||
<div class="content">
|
||||
<div style="margin-top: 24px">
|
||||
<select class="button" id="dir">
|
||||
<option value="">None</option>
|
||||
</select>
|
||||
<input id="path-to-read" placeholder="Type the path to read...">
|
||||
<button class="button" id="read">Read</button>
|
||||
</div>
|
||||
<div style="margin-top: 24px">
|
||||
<input id="dialog-default-path" placeholder="Default path">
|
||||
<input id="dialog-filter" placeholder="Extensions filter">
|
||||
<div>
|
||||
<input type="checkbox" id="dialog-multiple">
|
||||
<label>Multiple</label>
|
||||
</div>
|
||||
<div>
|
||||
<input type="checkbox" id="dialog-directory">
|
||||
<label>Directory</label>
|
||||
</div>
|
||||
<div style="margin-top: 24px">
|
||||
<input id="dialog-default-path" placeholder="Default path">
|
||||
<input id="dialog-filter" placeholder="Extensions filter">
|
||||
<div>
|
||||
<input type="checkbox" id="dialog-multiple">
|
||||
<label>Multiple</label>
|
||||
</div>
|
||||
<div>
|
||||
<input type="checkbox" id="dialog-directory">
|
||||
<label>Directory</label>
|
||||
</div>
|
||||
|
||||
<button class="button" id="open-dialog">Open dialog</button>
|
||||
<button class="button" id="save-dialog">Open save dialog</button>
|
||||
</div>
|
||||
<button class="button" id="open-dialog">Open dialog</button>
|
||||
<button class="button" id="save-dialog">Open save dialog</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="tab">
|
||||
<input type="radio" id="tab-3" name="tab-group-1">
|
||||
<label class="tabber" for="tab-3">Communication</label>
|
||||
<div class="content">
|
||||
<div style="margin-top: 24px">
|
||||
<input id="url" value="https://tauri.studio">
|
||||
<button class="button" id="open-url">Open URL</button>
|
||||
</div>
|
||||
<div class="tab">
|
||||
<input type="radio" id="tab-3" name="tab-group-1">
|
||||
<label class="tabber" for="tab-3">Communication</label>
|
||||
<div class="content">
|
||||
<div style="margin-top: 24px">
|
||||
<input id="url" value="https://tauri.studio">
|
||||
<button class="button" id="open-url">Open URL</button>
|
||||
</div>
|
||||
|
||||
<div style="margin-top: 24px">
|
||||
<select class="button" id="request-method">
|
||||
<option value="GET">GET</option>
|
||||
<option value="POST">POST</option>
|
||||
<option value="PUT">PUT</option>
|
||||
<option value="PATCH">PATCH</option>
|
||||
<option value="DELETE">DELETE</option>
|
||||
</select>
|
||||
<input id="request-url" placeholder="Type the request URL...">
|
||||
<br/>
|
||||
<textarea id="request-body" placeholder="Request body" rows="5" style="width:100%;margin-right:10px;font-size:12px"></textarea>
|
||||
</br>
|
||||
<button class="button" id="make-request">Make request</button>
|
||||
</div>
|
||||
<div style="margin-top: 24px">
|
||||
<select class="button" id="request-method">
|
||||
<option value="GET">GET</option>
|
||||
<option value="POST">POST</option>
|
||||
<option value="PUT">PUT</option>
|
||||
<option value="PATCH">PATCH</option>
|
||||
<option value="DELETE">DELETE</option>
|
||||
</select>
|
||||
<input id="request-url" placeholder="Type the request URL...">
|
||||
<br />
|
||||
<textarea id="request-body" placeholder="Request body" rows="5"
|
||||
style="width:100%;margin-right:10px;font-size:12px"></textarea>
|
||||
</br>
|
||||
<button class="button" id="make-request">Make request</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="tab">
|
||||
<input type="radio" id="tab-4" name="tab-group-1">
|
||||
<label class="tabber" for="tab-4">CLI</label>
|
||||
<div class="content">
|
||||
<div style="margin-top: 24px">
|
||||
<button class="button" id="cli-matches">Get matches</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="response"></div>
|
||||
<div class="bottom">
|
||||
<a class="dark-link" target="_blank" href="https://tauri.studio">Tauri Documentation</a>
|
||||
<a class="dark-link" target="_blank" href="https://github.com/tauri-apps/tauri">Github Repo</a>
|
||||
<a class="dark-link" target="_blank" href="https://github.com/tauri-apps/tauri/tree/dev/tauri/examples/communication">Source for this App</a>
|
||||
</div>
|
||||
<script>
|
||||
function registerResponse (response) {
|
||||
document.getElementById('response').innerHTML = typeof response === 'object'
|
||||
? JSON.stringify(response)
|
||||
: response
|
||||
}
|
||||
</div>
|
||||
<div id="response"></div>
|
||||
<div class="bottom">
|
||||
<a class="dark-link" target="_blank" href="https://tauri.studio">Tauri Documentation</a>
|
||||
<a class="dark-link" target="_blank" href="https://github.com/tauri-apps/tauri">Github Repo</a>
|
||||
<a class="dark-link" target="_blank"
|
||||
href="https://github.com/tauri-apps/tauri/tree/dev/tauri/examples/communication">Source for this App</a>
|
||||
</div>
|
||||
<script>
|
||||
function registerResponse(response) {
|
||||
document.getElementById('response').innerHTML = typeof response === 'object' ?
|
||||
JSON.stringify(response) :
|
||||
response
|
||||
}
|
||||
|
||||
function addClickEnterHandler (button, input, handler) {
|
||||
button.addEventListener('click', handler)
|
||||
input.addEventListener('keyup', function (e) {
|
||||
if (e.keyCode === 13) {
|
||||
handler()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
window.tauri.listen('rust-event', function (res) {
|
||||
document.getElementById('response').innerHTML = JSON.stringify(res)
|
||||
function addClickEnterHandler(button, input, handler) {
|
||||
button.addEventListener('click', handler)
|
||||
input.addEventListener('keyup', function (e) {
|
||||
if (e.keyCode === 13) {
|
||||
handler()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
document.querySelector('.logo').addEventListener('click', function () {
|
||||
window.tauri.open('https://tauri.studio/')
|
||||
})
|
||||
window.tauri.listen('rust-event', function (res) {
|
||||
document.getElementById('response').innerHTML = JSON.stringify(res)
|
||||
})
|
||||
|
||||
document.querySelector('.logo').addEventListener('click', function () {
|
||||
window.tauri.open('https://tauri.studio/')
|
||||
})
|
||||
|
||||
var dirSelect = document.getElementById('dir')
|
||||
for (var key in window.tauri.Dir) {
|
||||
var value = window.tauri.Dir[key]
|
||||
var opt = document.createElement("option")
|
||||
opt.value = value
|
||||
opt.innerHTML = key
|
||||
dirSelect.appendChild(opt)
|
||||
}
|
||||
|
||||
</script>
|
||||
<script src="communication.js"></script>
|
||||
<script src="fs.js"></script>
|
||||
<script src="window.js"></script>
|
||||
<script src="dialog.js"></script>
|
||||
<script src="http.js"></script>
|
||||
<script src="cli.js"></script>
|
||||
</body>
|
||||
|
||||
var dirSelect = document.getElementById('dir')
|
||||
for (var key in window.tauri.Dir) {
|
||||
var value = window.tauri.Dir[key]
|
||||
var opt = document.createElement("option")
|
||||
opt.value = value
|
||||
opt.innerHTML = key
|
||||
dirSelect.appendChild(opt)
|
||||
}
|
||||
</script>
|
||||
<script src="communication.js"></script>
|
||||
<script src="fs.js"></script>
|
||||
<script src="window.js"></script>
|
||||
<script src="dialog.js"></script>
|
||||
<script src="http.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
File diff suppressed because one or more lines are too long
@ -24,7 +24,7 @@ icon = [
|
||||
[dependencies]
|
||||
serde_json = "1.0"
|
||||
serde = { version = "1.0", features = [ "derive" ] }
|
||||
tauri = { path = "../../..", features = [ "all-api", "edge" ] }
|
||||
tauri = { path = "../../..", features = [ "all-api", "edge", "cli" ] }
|
||||
|
||||
[target."cfg(windows)".build-dependencies]
|
||||
winres = "0.1"
|
||||
|
@ -5,6 +5,43 @@
|
||||
},
|
||||
"ctx": {},
|
||||
"tauri": {
|
||||
"cli": {
|
||||
"description": "Tauri communication example",
|
||||
"longDescription": null,
|
||||
"beforeHelp": null,
|
||||
"afterHelp": null,
|
||||
"args": [{
|
||||
"short": "c",
|
||||
"name": "config",
|
||||
"takesValue": true,
|
||||
"description": "Config path"
|
||||
}, {
|
||||
"short": "t",
|
||||
"name": "theme",
|
||||
"takesValue": true,
|
||||
"description": "App theme",
|
||||
"possibleValues": ["light", "dark", "system"]
|
||||
}, {
|
||||
"short": "v",
|
||||
"name": "verbose",
|
||||
"multipleOccurrences": true,
|
||||
"description": "Verbosity level"
|
||||
}],
|
||||
"subcommands": {
|
||||
"update": {
|
||||
"description": "Updates the app",
|
||||
"longDescription": null,
|
||||
"beforeHelp": null,
|
||||
"afterHelp": null,
|
||||
"args": [{
|
||||
"short": "b",
|
||||
"name": "background",
|
||||
"description": "Update in background"
|
||||
}],
|
||||
"subcommands": null
|
||||
}
|
||||
}
|
||||
},
|
||||
"embeddedServer": {
|
||||
"active": false
|
||||
},
|
||||
@ -31,4 +68,4 @@
|
||||
"active": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -570,6 +570,15 @@ window.tauri = {
|
||||
asset: assetName,
|
||||
assetType: assetType || 'unknown'
|
||||
})
|
||||
},
|
||||
|
||||
cliMatches: function () {
|
||||
|
||||
return this.promisified({
|
||||
cmd: 'cliMatches'
|
||||
})
|
||||
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -12,13 +12,22 @@ use web_view::{builder, Content, WebView};
|
||||
use super::App;
|
||||
#[cfg(feature = "embedded-server")]
|
||||
use crate::api::tcp::{get_available_port, port_is_available};
|
||||
use crate::config::{get, Config};
|
||||
use tauri_api::config::{get, Config};
|
||||
|
||||
#[cfg(feature = "cli")]
|
||||
use tauri_api::cli::get_matches;
|
||||
|
||||
// Main entry point function for running the Webview
|
||||
pub(crate) fn run(application: &mut App) -> crate::Result<()> {
|
||||
// get the tauri config struct
|
||||
let config = get()?;
|
||||
|
||||
#[cfg(feature = "cli")]
|
||||
{
|
||||
let matches = get_matches(config.clone());
|
||||
crate::cli::set_matches(matches)?;
|
||||
}
|
||||
|
||||
// setup the content using the config struct depending on the compile target
|
||||
let main_content = setup_content(config.clone())?;
|
||||
|
||||
@ -72,7 +81,10 @@ fn setup_content(config: Config) -> crate::Result<Content<String>> {
|
||||
let dev_dir = config.build.dev_path;
|
||||
let dev_path = Path::new(&dev_dir).join("index.tauri.html");
|
||||
if !dev_path.exists() {
|
||||
panic!("Couldn't find 'index.tauri.html' inside {}; did you forget to run 'tauri dev'?", dev_dir);
|
||||
panic!(
|
||||
"Couldn't find 'index.tauri.html' inside {}; did you forget to run 'tauri dev'?",
|
||||
dev_dir
|
||||
);
|
||||
}
|
||||
Ok(Content::Html(read_to_string(dev_path)?))
|
||||
}
|
||||
@ -280,8 +292,8 @@ mod test {
|
||||
#[cfg(not(feature = "embedded-server"))]
|
||||
use std::{env, fs::read_to_string, path::Path};
|
||||
|
||||
fn init_config() -> crate::config::Config {
|
||||
crate::config::get().expect("unable to setup default config")
|
||||
fn init_config() -> tauri_api::config::Config {
|
||||
tauri_api::config::get().expect("unable to setup default config")
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -289,6 +301,15 @@ mod test {
|
||||
let config = init_config();
|
||||
let _c = config.clone();
|
||||
|
||||
let tauri_dir = match option_env!("TAURI_DIR") {
|
||||
Some(d) => d.to_string(),
|
||||
None => env::current_dir()
|
||||
.unwrap()
|
||||
.into_os_string()
|
||||
.into_string()
|
||||
.expect("Unable to convert to normal String"),
|
||||
};
|
||||
env::set_current_dir(tauri_dir).expect("failed to change cwd");
|
||||
let res = super::setup_content(config);
|
||||
|
||||
#[cfg(feature = "embedded-server")]
|
||||
@ -320,17 +341,11 @@ mod test {
|
||||
match res {
|
||||
Ok(Content::Url(dp)) => assert_eq!(dp, _c.build.dev_path),
|
||||
Ok(Content::Html(s)) => {
|
||||
let dist_dir = match option_env!("TAURI_DIST_DIR") {
|
||||
Some(d) => d.to_string(),
|
||||
None => env::current_dir()
|
||||
.unwrap()
|
||||
.into_os_string()
|
||||
.into_string()
|
||||
.expect("Unable to convert to normal String"),
|
||||
};
|
||||
let dev_dir = _c.build.dev_path;
|
||||
let dev_path = Path::new(&dev_dir).join("index.tauri.html");
|
||||
assert_eq!(
|
||||
s,
|
||||
read_to_string(Path::new(&dist_dir).join("index.tauri.html")).unwrap()
|
||||
read_to_string(dev_path).expect("failed to read dev path")
|
||||
);
|
||||
}
|
||||
_ => assert!(false),
|
||||
|
14
tauri/src/cli.rs
Normal file
14
tauri/src/cli.rs
Normal file
@ -0,0 +1,14 @@
|
||||
use once_cell::sync::OnceCell;
|
||||
use tauri_api::cli::Matches;
|
||||
|
||||
static MATCHES: OnceCell<Matches> = OnceCell::new();
|
||||
|
||||
pub(crate) fn set_matches(matches: Matches) -> crate::Result<()> {
|
||||
MATCHES
|
||||
.set(matches)
|
||||
.map_err(|_| anyhow::anyhow!("failed to set once_cell matches"))
|
||||
}
|
||||
|
||||
pub fn get_matches() -> Option<&'static Matches> {
|
||||
MATCHES.get()
|
||||
}
|
@ -178,6 +178,16 @@ pub(crate) fn handle<T: 'static>(webview: &mut WebView<'_, T>, arg: &str) -> cra
|
||||
} => {
|
||||
load_asset(webview, asset, asset_type, callback, error)?;
|
||||
}
|
||||
#[cfg(feature = "cli")]
|
||||
CliMatches { callback, error } => crate::execute_promise(
|
||||
webview,
|
||||
move || match crate::cli::get_matches() {
|
||||
Some(matches) => Ok(serde_json::to_string(matches)?),
|
||||
None => Err(anyhow::anyhow!(r#""failed to get matches""#)),
|
||||
},
|
||||
callback,
|
||||
error,
|
||||
),
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
@ -160,4 +160,9 @@ pub enum Cmd {
|
||||
callback: String,
|
||||
error: String,
|
||||
},
|
||||
#[cfg(feature = "cli")]
|
||||
CliMatches {
|
||||
callback: String,
|
||||
error: String,
|
||||
},
|
||||
}
|
||||
|
@ -41,10 +41,7 @@ pub fn save<T: 'static>(
|
||||
) {
|
||||
crate::execute_promise_sync(
|
||||
webview,
|
||||
move || {
|
||||
save_file(options.filter, options.default_path)
|
||||
.map(map_response)
|
||||
},
|
||||
move || save_file(options.filter, options.default_path).map(map_response),
|
||||
callback,
|
||||
error,
|
||||
);
|
||||
|
@ -12,12 +12,12 @@ pub fn make_request<T: 'static>(
|
||||
webview,
|
||||
move || {
|
||||
let response_type = options.response_type.clone();
|
||||
request(options).map(|response| {
|
||||
match response_type.unwrap_or(ResponseType::Json) {
|
||||
request(options).map(
|
||||
|response| match response_type.unwrap_or(ResponseType::Json) {
|
||||
ResponseType::Text => format!(r#""{}""#, response),
|
||||
_ => response,
|
||||
}
|
||||
})
|
||||
},
|
||||
)
|
||||
},
|
||||
callback,
|
||||
error,
|
||||
|
@ -3,8 +3,8 @@ use std::collections::HashMap;
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
use lazy_static::lazy_static;
|
||||
use web_view::Handle;
|
||||
use once_cell::sync::Lazy;
|
||||
use web_view::Handle;
|
||||
|
||||
struct EventHandler {
|
||||
on_event: Box<dyn FnMut(Option<String>) + Send>,
|
||||
@ -74,10 +74,8 @@ pub fn on_event(event: String, data: Option<String>) {
|
||||
.lock()
|
||||
.expect("Failed to lock listeners: on_event()");
|
||||
|
||||
let key = event.clone();
|
||||
|
||||
if l.contains_key(&key) {
|
||||
let handler = l.get_mut(&key).expect("Failed to get mutable handler");
|
||||
if l.contains_key(&event) {
|
||||
let handler = l.get_mut(&event).expect("Failed to get mutable handler");
|
||||
(handler.on_event)(data);
|
||||
}
|
||||
}
|
||||
@ -151,4 +149,4 @@ mod test {
|
||||
assert!(l.contains_key(&key));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -5,11 +5,13 @@
|
||||
|
||||
#[cfg(any(feature = "embedded-server", feature = "no-server"))]
|
||||
pub mod assets;
|
||||
pub mod config;
|
||||
pub mod event;
|
||||
#[cfg(feature = "embedded-server")]
|
||||
pub mod server;
|
||||
|
||||
#[cfg(feature = "cli")]
|
||||
pub mod cli;
|
||||
|
||||
mod app;
|
||||
mod endpoints;
|
||||
#[allow(dead_code)]
|
||||
|
Loading…
Reference in New Issue
Block a user