mirror of
https://github.com/tauri-apps/tauri.git
synced 2026-01-31 00:35:19 +01:00
feat(cli): add android dev and ios dev commands (#4982)
This commit is contained in:
committed by
GitHub
parent
f445f374a3
commit
6f0615044d
6
.changes/cli-mobile-dev.md
Normal file
6
.changes/cli-mobile-dev.md
Normal file
@@ -0,0 +1,6 @@
|
||||
---
|
||||
"cli.rs": minor
|
||||
"cli.js": minor
|
||||
---
|
||||
|
||||
Added `android dev` and `ios dev` commands.
|
||||
5
.changes/codegen-mobile-devurl.md
Normal file
5
.changes/codegen-mobile-devurl.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"tauri-codegen": patch
|
||||
---
|
||||
|
||||
Change `devPath` URL to use the local IP address on iOS and Android.
|
||||
5
.changes/dev-proxy.md
Normal file
5
.changes/dev-proxy.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"tauri": major
|
||||
---
|
||||
|
||||
**Breaking change:** Use the custom protocol as a proxy to the development server on all platforms except Linux.
|
||||
@@ -29,6 +29,8 @@ semver = "1"
|
||||
ico = "0.1"
|
||||
png = "0.17"
|
||||
json-patch = "0.2"
|
||||
local-ip-address = "0.4"
|
||||
url = "2"
|
||||
|
||||
[target."cfg(target_os = \"macos\")".dependencies]
|
||||
plist = "1"
|
||||
|
||||
@@ -122,7 +122,7 @@ enum Target {
|
||||
pub fn context_codegen(data: ContextData) -> Result<TokenStream, EmbeddedAssetsError> {
|
||||
let ContextData {
|
||||
dev,
|
||||
config,
|
||||
mut config,
|
||||
config_parent,
|
||||
root,
|
||||
} = data;
|
||||
@@ -155,6 +155,23 @@ pub fn context_codegen(data: ContextData) -> Result<TokenStream, EmbeddedAssetsE
|
||||
panic!("unknown codegen target");
|
||||
};
|
||||
|
||||
if dev && (target == Target::Ios || target == Target::Android) {
|
||||
if let AppUrl::Url(WindowUrl::External(url)) = &mut config.build.dev_path {
|
||||
let localhost = match url.host() {
|
||||
Some(url::Host::Domain(d)) => d == "localhost",
|
||||
Some(url::Host::Ipv4(i)) => {
|
||||
i == std::net::Ipv4Addr::LOCALHOST || i == std::net::Ipv4Addr::UNSPECIFIED
|
||||
}
|
||||
_ => false,
|
||||
};
|
||||
if localhost {
|
||||
if let Ok(ip) = local_ip_address::local_ip() {
|
||||
url.set_host(Some(&ip.to_string())).unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut options = AssetOptions::new(config.tauri.pattern.clone())
|
||||
.freeze_prototype(config.tauri.security.freeze_prototype)
|
||||
.dangerous_disable_asset_csp_modification(
|
||||
|
||||
@@ -431,6 +431,7 @@ impl ToTokens for EmbeddedAssets {
|
||||
|
||||
// we expect phf related items to be in path when generating the path code
|
||||
tokens.append_all(quote! {{
|
||||
#[allow(unused_imports)]
|
||||
use ::tauri::utils::assets::{CspHash, EmbeddedAssets, phf, phf::phf_map};
|
||||
EmbeddedAssets::new(phf_map! { #assets }, &[#global_hashes], phf_map! { #html_hashes })
|
||||
}});
|
||||
|
||||
@@ -2364,7 +2364,7 @@ fn default_dialog() -> bool {
|
||||
#[serde(rename_all = "camelCase", deny_unknown_fields)]
|
||||
pub struct IosConfig {
|
||||
/// The development team. This value is required for iOS development because code signing is enforced.
|
||||
/// The `APPLE_DEVELOPMENT_TEAM` environment variable can be set to overwrite it.
|
||||
/// The `TAURI_APPLE_DEVELOPMENT_TEAM` environment variable can be set to overwrite it.
|
||||
#[serde(alias = "development-team")]
|
||||
pub development_team: Option<String>,
|
||||
}
|
||||
|
||||
@@ -75,7 +75,7 @@ base64 = { version = "0.13", optional = true }
|
||||
clap = { version = "3", optional = true }
|
||||
reqwest = { version = "0.11", features = [ "json", "stream" ], optional = true }
|
||||
bytes = { version = "1", features = [ "serde" ], optional = true }
|
||||
attohttpc = { version = "0.20", features = [ "compress", "json", "form" ], optional = true }
|
||||
attohttpc = { version = "0.20", features = [ "compress", "json", "form" ] }
|
||||
open = { version = "3.0", optional = true }
|
||||
shared_child = { version = "1.0", optional = true }
|
||||
os_pipe = { version = "1.0", optional = true }
|
||||
@@ -146,7 +146,7 @@ updater = [
|
||||
"dialog-ask",
|
||||
"fs-extract-api"
|
||||
]
|
||||
http-api = [ "attohttpc" ]
|
||||
http-api = [ ]
|
||||
http-multipart = [ "attohttpc/multipart-form", "reqwest/multipart" ]
|
||||
shell-open-api = [ "open", "regex", "tauri-macros/shell-scope" ]
|
||||
fs-extract-api = [ "zip" ]
|
||||
|
||||
@@ -142,11 +142,6 @@ fn set_csp<R: Runtime>(
|
||||
Csp::DirectiveMap(csp).to_string()
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
fn set_html_csp(html: &str, csp: &str) -> String {
|
||||
html.replacen(tauri_utils::html::CSP_TOKEN, csp, 1)
|
||||
}
|
||||
|
||||
// inspired by https://github.com/rust-lang/rust/blob/1be5c8f90912c446ecbdc405cbc4a89f9acd20fd/library/alloc/src/str.rs#L260-L297
|
||||
fn replace_with_callback<F: FnMut() -> String>(
|
||||
original: &str,
|
||||
@@ -374,7 +369,13 @@ impl<R: Runtime> WindowManager<R> {
|
||||
/// Get the origin as it will be seen in the webview.
|
||||
fn get_browser_origin(&self) -> String {
|
||||
match self.base_path() {
|
||||
AppUrl::Url(WindowUrl::External(url)) => url.origin().ascii_serialization(),
|
||||
AppUrl::Url(WindowUrl::External(url)) => {
|
||||
if cfg!(dev) && !cfg!(target_os = "linux") {
|
||||
format_real_schema("tauri")
|
||||
} else {
|
||||
url.origin().ascii_serialization()
|
||||
}
|
||||
}
|
||||
_ => format_real_schema("tauri"),
|
||||
}
|
||||
}
|
||||
@@ -820,8 +821,12 @@ impl<R: Runtime> WindowManager<R> {
|
||||
>,
|
||||
) -> Box<dyn Fn(&HttpRequest) -> Result<HttpResponse, Box<dyn std::error::Error>> + Send + Sync>
|
||||
{
|
||||
#[cfg(dev)]
|
||||
let url = self.get_url().into_owned();
|
||||
#[cfg(not(dev))]
|
||||
let manager = self.clone();
|
||||
let window_origin = window_origin.to_string();
|
||||
|
||||
Box::new(move |request| {
|
||||
let path = request
|
||||
.uri()
|
||||
@@ -834,32 +839,47 @@ impl<R: Runtime> WindowManager<R> {
|
||||
// the `strip_prefix` only returns None when a request is made to `https://tauri.$P` on Windows
|
||||
// where `$P` is not `localhost/*`
|
||||
.unwrap_or_else(|| "".to_string());
|
||||
let asset = manager.get_asset(path)?;
|
||||
let mut builder = HttpResponseBuilder::new()
|
||||
.header("Access-Control-Allow-Origin", &window_origin)
|
||||
.mimetype(&asset.mime_type);
|
||||
if let Some(csp) = &asset.csp_header {
|
||||
builder = builder.header("Content-Security-Policy", csp);
|
||||
}
|
||||
let mut response = builder.body(asset.bytes)?;
|
||||
if let Some(handler) = &web_resource_request_handler {
|
||||
handler(request, &mut response);
|
||||
|
||||
// if it's an HTML file, we need to set the CSP meta tag on Linux
|
||||
#[cfg(target_os = "linux")]
|
||||
if let Some(response_csp) = response.headers().get("Content-Security-Policy") {
|
||||
let response_csp = String::from_utf8_lossy(response_csp.as_bytes());
|
||||
let body = set_html_csp(&String::from_utf8_lossy(response.body()), &response_csp);
|
||||
*response.body_mut() = body.as_bytes().to_vec();
|
||||
}
|
||||
} else {
|
||||
#[cfg(target_os = "linux")]
|
||||
{
|
||||
if let Some(csp) = &asset.csp_header {
|
||||
let body = set_html_csp(&String::from_utf8_lossy(response.body()), csp);
|
||||
*response.body_mut() = body.as_bytes().to_vec();
|
||||
let mut builder =
|
||||
HttpResponseBuilder::new().header("Access-Control-Allow-Origin", &window_origin);
|
||||
|
||||
#[cfg(dev)]
|
||||
let mut response = {
|
||||
let mut url = url.clone();
|
||||
url.set_path(&path);
|
||||
match attohttpc::get(url.as_str()).send() {
|
||||
Ok(r) => {
|
||||
for (name, value) in r.headers() {
|
||||
builder = builder.header(name, value);
|
||||
}
|
||||
builder.status(r.status()).body(r.bytes()?)?
|
||||
}
|
||||
Err(e) => {
|
||||
debug_eprintln!("Failed to request {}: {}", url.path(), e);
|
||||
return Err(Box::new(e));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#[cfg(not(dev))]
|
||||
let mut response = {
|
||||
let asset = manager.get_asset(path)?;
|
||||
builder = builder.mimetype(&asset.mime_type);
|
||||
if let Some(csp) = &asset.csp_header {
|
||||
builder = builder.header("Content-Security-Policy", csp);
|
||||
}
|
||||
builder.body(asset.bytes)?
|
||||
};
|
||||
if let Some(handler) = &web_resource_request_handler {
|
||||
handler(request, &mut response);
|
||||
}
|
||||
// if it's an HTML file, we need to set the CSP meta tag on Linux
|
||||
#[cfg(all(not(dev), target_os = "linux"))]
|
||||
if let Some(response_csp) = response.headers().get("Content-Security-Policy") {
|
||||
let response_csp = String::from_utf8_lossy(response_csp.as_bytes());
|
||||
let html = String::from_utf8_lossy(response.body());
|
||||
let body = html.replacen(tauri_utils::html::CSP_TOKEN, &response_csp, 1);
|
||||
*response.body_mut() = body.as_bytes().to_vec();
|
||||
}
|
||||
Ok(response)
|
||||
})
|
||||
@@ -1061,7 +1081,10 @@ impl<R: Runtime> WindowManager<R> {
|
||||
#[allow(unused_mut)] // mut url only for the data-url parsing
|
||||
let (is_local, mut url) = match &pending.webview_attributes.url {
|
||||
WindowUrl::App(path) => {
|
||||
#[cfg(target_os = "linux")]
|
||||
let url = self.get_url();
|
||||
#[cfg(not(target_os = "linux"))]
|
||||
let url: Cow<'_, Url> = Cow::Owned(Url::parse("tauri://localhost").unwrap());
|
||||
(
|
||||
true,
|
||||
// ignore "index.html" just to simplify the url
|
||||
@@ -1078,7 +1101,13 @@ impl<R: Runtime> WindowManager<R> {
|
||||
}
|
||||
WindowUrl::External(url) => {
|
||||
let config_url = self.get_url();
|
||||
(config_url.make_relative(url).is_some(), url.clone())
|
||||
let is_local = config_url.make_relative(url).is_some();
|
||||
let mut url = url.clone();
|
||||
if is_local && !cfg!(target_os = "linux") {
|
||||
url.set_scheme("tauri").unwrap();
|
||||
url.set_host(Some("localhost")).unwrap();
|
||||
}
|
||||
(is_local, url)
|
||||
}
|
||||
_ => unimplemented!(),
|
||||
};
|
||||
|
||||
44
examples/api/dist/assets/index.js
vendored
44
examples/api/dist/assets/index.js
vendored
File diff suppressed because one or more lines are too long
@@ -3,7 +3,7 @@
|
||||
"version": "1.0.0",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite --clearScreen false --port 5000",
|
||||
"dev": "vite --clearScreen false",
|
||||
"build": "vite build",
|
||||
"serve": "vite preview",
|
||||
"tauri": "node ../../tooling/cli/node/tauri.js"
|
||||
@@ -15,9 +15,10 @@
|
||||
"devDependencies": {
|
||||
"@iconify-json/codicon": "^1.1.10",
|
||||
"@iconify-json/ph": "^1.1.1",
|
||||
"@sveltejs/vite-plugin-svelte": "^1.0.0-next.49",
|
||||
"@sveltejs/vite-plugin-svelte": "^1.0.1",
|
||||
"internal-ip": "^7.0.0",
|
||||
"svelte": "^3.49.0",
|
||||
"unocss": "^0.39.3",
|
||||
"vite": "^2.9.12"
|
||||
"vite": "^3.0.9"
|
||||
}
|
||||
}
|
||||
|
||||
37
examples/api/src-tauri/Cargo.lock
generated
37
examples/api/src-tauri/Cargo.lock
generated
@@ -112,9 +112,7 @@ version = "0.1.0"
|
||||
dependencies = [
|
||||
"android_logger",
|
||||
"env_logger 0.9.0",
|
||||
"jni",
|
||||
"log",
|
||||
"mobile-entry-point",
|
||||
"paste",
|
||||
"serde",
|
||||
"serde_json",
|
||||
@@ -1659,6 +1657,18 @@ dependencies = [
|
||||
"safemem",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "local-ip-address"
|
||||
version = "0.4.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "74d6f43d42d775afa8073bfa6aba569b340a3635efa8c9f7702c9c6ed209692f"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"neli",
|
||||
"thiserror",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lock_api"
|
||||
version = "0.4.7"
|
||||
@@ -1808,17 +1818,6 @@ dependencies = [
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mobile-entry-point"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "81bef5a90018326583471cccca10424d7b3e770397b02f03276543cbb9b6a1a6"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "multipart"
|
||||
version = "0.18.0"
|
||||
@@ -1878,6 +1877,16 @@ dependencies = [
|
||||
"jni-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "neli"
|
||||
version = "0.5.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9053554eb5dcb7e10d9cdab1206965bde870eed5d0d341532ca035e3ba221508"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "new_debug_unreachable"
|
||||
version = "1.0.4"
|
||||
@@ -3243,6 +3252,7 @@ dependencies = [
|
||||
"brotli",
|
||||
"ico",
|
||||
"json-patch",
|
||||
"local-ip-address",
|
||||
"plist",
|
||||
"png 0.17.5",
|
||||
"proc-macro2",
|
||||
@@ -3255,6 +3265,7 @@ dependencies = [
|
||||
"tauri-utils",
|
||||
"thiserror",
|
||||
"time",
|
||||
"url",
|
||||
"uuid 1.1.2",
|
||||
"walkdir",
|
||||
]
|
||||
|
||||
@@ -45,11 +45,9 @@ tauri-runtime-wry = { path = "../../../core/tauri-runtime-wry/" }
|
||||
|
||||
[target.'cfg(target_os = "android")'.dependencies]
|
||||
android_logger = "0.9.0"
|
||||
jni = "0.19.0"
|
||||
paste = "1.0"
|
||||
|
||||
[target.'cfg(target_os = "ios")'.dependencies]
|
||||
mobile-entry-point = "0.1.0"
|
||||
env_logger = "0.9.0"
|
||||
|
||||
[features]
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
"$schema": "../../../tooling/cli/schema.json",
|
||||
"build": {
|
||||
"distDir": "../dist",
|
||||
"devPath": "http://localhost:5000",
|
||||
"beforeDevCommand": "yarn dev",
|
||||
"devPath": "http://localhost:5173",
|
||||
"beforeDevCommand": "yarn dev --host",
|
||||
"beforeBuildCommand": "yarn build"
|
||||
},
|
||||
"package": {
|
||||
|
||||
@@ -1,22 +1,30 @@
|
||||
import { defineConfig } from 'vite'
|
||||
import Unocss from 'unocss/vite'
|
||||
import { svelte } from '@sveltejs/vite-plugin-svelte'
|
||||
import { internalIpV4 } from 'internal-ip'
|
||||
|
||||
// https://vitejs.dev/config/
|
||||
export default defineConfig({
|
||||
plugins: [Unocss(), svelte()],
|
||||
build: {
|
||||
rollupOptions: {
|
||||
output: {
|
||||
entryFileNames: `assets/[name].js`,
|
||||
chunkFileNames: `assets/[name].js`,
|
||||
assetFileNames: `assets/[name].[ext]`
|
||||
export default defineConfig(async ({ command, mode }) => {
|
||||
const host = await internalIpV4()
|
||||
return {
|
||||
plugins: [Unocss(), svelte()],
|
||||
build: {
|
||||
rollupOptions: {
|
||||
output: {
|
||||
entryFileNames: `assets/[name].js`,
|
||||
chunkFileNames: `assets/[name].js`,
|
||||
assetFileNames: `assets/[name].[ext]`
|
||||
}
|
||||
}
|
||||
},
|
||||
server: {
|
||||
hmr: {
|
||||
host,
|
||||
port: 5183
|
||||
},
|
||||
fs: {
|
||||
allow: ['.', '../../tooling/api/dist']
|
||||
}
|
||||
}
|
||||
},
|
||||
server: {
|
||||
fs: {
|
||||
allow: ['.', '../../tooling/api/dist']
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
@@ -15,6 +15,11 @@
|
||||
resolved "https://registry.yarnpkg.com/@antfu/utils/-/utils-0.5.2.tgz#8c2d931ff927be0ebe740169874a3d4004ab414b"
|
||||
integrity sha512-CQkeV+oJxUazwjlHD0/3ZD08QWKuGQkhnrKo3e6ly5pd48VUpXbb77q0xMU4+vc2CkJnDS02Eq/M9ugyX20XZA==
|
||||
|
||||
"@esbuild/linux-loong64@0.14.54":
|
||||
version "0.14.54"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.14.54.tgz#de2a4be678bd4d0d1ffbb86e6de779cde5999028"
|
||||
integrity sha512-bZBrLAIX1kpWelV0XemxBZllyRmM6vgFQQG2GdNb+r3Fkp0FOh1NJSvekXDs7jq70k4euu1cryLMfU+mTXlEpw==
|
||||
|
||||
"@iconify-json/codicon@^1.1.10":
|
||||
version "1.1.10"
|
||||
resolved "https://registry.yarnpkg.com/@iconify-json/codicon/-/codicon-1.1.10.tgz#22fee909be51afebfbcc6cd57209064b5363f202"
|
||||
@@ -80,15 +85,15 @@
|
||||
estree-walker "^2.0.1"
|
||||
picomatch "^2.2.2"
|
||||
|
||||
"@sveltejs/vite-plugin-svelte@^1.0.0-next.49":
|
||||
version "1.0.0-next.49"
|
||||
resolved "https://registry.yarnpkg.com/@sveltejs/vite-plugin-svelte/-/vite-plugin-svelte-1.0.0-next.49.tgz#44cc00a19c6c23002516b66c5ab90ee66720df57"
|
||||
integrity sha512-AKh0Ka8EDgidnxWUs8Hh2iZLZovkETkefO99XxZ4sW4WGJ7VFeBx5kH/NIIGlaNHLcrIvK3CK0HkZwC3Cici0A==
|
||||
"@sveltejs/vite-plugin-svelte@^1.0.1":
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@sveltejs/vite-plugin-svelte/-/vite-plugin-svelte-1.0.1.tgz#7f468f03c933fcdfc60d4773671c73f33b9ef4d6"
|
||||
integrity sha512-PorCgUounn0VXcpeJu+hOweZODKmGuLHsLomwqSj+p26IwjjGffmYQfVHtiTWq+NqaUuuHWWG7vPge6UFw4Aeg==
|
||||
dependencies:
|
||||
"@rollup/pluginutils" "^4.2.1"
|
||||
debug "^4.3.4"
|
||||
deepmerge "^4.2.2"
|
||||
kleur "^4.1.4"
|
||||
kleur "^4.1.5"
|
||||
magic-string "^0.26.2"
|
||||
svelte-hmr "^0.14.12"
|
||||
|
||||
@@ -323,6 +328,13 @@ deepmerge@^4.2.2:
|
||||
resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.2.2.tgz#44d2ea3679b8f4d4ffba33f03d865fc1e7bf4955"
|
||||
integrity sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==
|
||||
|
||||
default-gateway@^6.0.3:
|
||||
version "6.0.3"
|
||||
resolved "https://registry.yarnpkg.com/default-gateway/-/default-gateway-6.0.3.tgz#819494c888053bdb743edbf343d6cdf7f2943a71"
|
||||
integrity sha512-fwSOJsbbNzZ/CUFpqFBqYfYNLj1NbMPm8MMCIzHjC83iSJRBEGmDUxU+WP661BaBQImeC2yHwXtz+P/O9o+XEg==
|
||||
dependencies:
|
||||
execa "^5.0.0"
|
||||
|
||||
defu@^6.0.0:
|
||||
version "6.0.0"
|
||||
resolved "https://registry.yarnpkg.com/defu/-/defu-6.0.0.tgz#b397a6709a2f3202747a3d9daf9446e41ad0c5fc"
|
||||
@@ -338,138 +350,139 @@ duplexer@^0.1.2:
|
||||
resolved "https://registry.yarnpkg.com/duplexer/-/duplexer-0.1.2.tgz#3abe43aef3835f8ae077d136ddce0f276b0400e6"
|
||||
integrity sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==
|
||||
|
||||
esbuild-android-64@0.14.47:
|
||||
version "0.14.47"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-android-64/-/esbuild-android-64-0.14.47.tgz#ef95b42c67bcf4268c869153fa3ad1466c4cea6b"
|
||||
integrity sha512-R13Bd9+tqLVFndncMHssZrPWe6/0Kpv2/dt4aA69soX4PRxlzsVpCvoJeFE8sOEoeVEiBkI0myjlkDodXlHa0g==
|
||||
esbuild-android-64@0.14.54:
|
||||
version "0.14.54"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-android-64/-/esbuild-android-64-0.14.54.tgz#505f41832884313bbaffb27704b8bcaa2d8616be"
|
||||
integrity sha512-Tz2++Aqqz0rJ7kYBfz+iqyE3QMycD4vk7LBRyWaAVFgFtQ/O8EJOnVmTOiDWYZ/uYzB4kvP+bqejYdVKzE5lAQ==
|
||||
|
||||
esbuild-android-arm64@0.14.47:
|
||||
version "0.14.47"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-android-arm64/-/esbuild-android-arm64-0.14.47.tgz#4ebd7ce9fb250b4695faa3ee46fd3b0754ecd9e6"
|
||||
integrity sha512-OkwOjj7ts4lBp/TL6hdd8HftIzOy/pdtbrNA4+0oVWgGG64HrdVzAF5gxtJufAPOsEjkyh1oIYvKAUinKKQRSQ==
|
||||
esbuild-android-arm64@0.14.54:
|
||||
version "0.14.54"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-android-arm64/-/esbuild-android-arm64-0.14.54.tgz#8ce69d7caba49646e009968fe5754a21a9871771"
|
||||
integrity sha512-F9E+/QDi9sSkLaClO8SOV6etqPd+5DgJje1F9lOWoNncDdOBL2YF59IhsWATSt0TLZbYCf3pNlTHvVV5VfHdvg==
|
||||
|
||||
esbuild-darwin-64@0.14.47:
|
||||
version "0.14.47"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-darwin-64/-/esbuild-darwin-64-0.14.47.tgz#e0da6c244f497192f951807f003f6a423ed23188"
|
||||
integrity sha512-R6oaW0y5/u6Eccti/TS6c/2c1xYTb1izwK3gajJwi4vIfNs1s8B1dQzI1UiC9T61YovOQVuePDcfqHLT3mUZJA==
|
||||
esbuild-darwin-64@0.14.54:
|
||||
version "0.14.54"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-darwin-64/-/esbuild-darwin-64-0.14.54.tgz#24ba67b9a8cb890a3c08d9018f887cc221cdda25"
|
||||
integrity sha512-jtdKWV3nBviOd5v4hOpkVmpxsBy90CGzebpbO9beiqUYVMBtSc0AL9zGftFuBon7PNDcdvNCEuQqw2x0wP9yug==
|
||||
|
||||
esbuild-darwin-arm64@0.14.47:
|
||||
version "0.14.47"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.47.tgz#cd40fd49a672fca581ed202834239dfe540a9028"
|
||||
integrity sha512-seCmearlQyvdvM/noz1L9+qblC5vcBrhUaOoLEDDoLInF/VQ9IkobGiLlyTPYP5dW1YD4LXhtBgOyevoIHGGnw==
|
||||
esbuild-darwin-arm64@0.14.54:
|
||||
version "0.14.54"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.54.tgz#3f7cdb78888ee05e488d250a2bdaab1fa671bf73"
|
||||
integrity sha512-OPafJHD2oUPyvJMrsCvDGkRrVCar5aVyHfWGQzY1dWnzErjrDuSETxwA2HSsyg2jORLY8yBfzc1MIpUkXlctmw==
|
||||
|
||||
esbuild-freebsd-64@0.14.47:
|
||||
version "0.14.47"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.47.tgz#8da6a14c095b29c01fc8087a16cb7906debc2d67"
|
||||
integrity sha512-ZH8K2Q8/Ux5kXXvQMDsJcxvkIwut69KVrYQhza/ptkW50DC089bCVrJZZ3sKzIoOx+YPTrmsZvqeZERjyYrlvQ==
|
||||
esbuild-freebsd-64@0.14.54:
|
||||
version "0.14.54"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.54.tgz#09250f997a56ed4650f3e1979c905ffc40bbe94d"
|
||||
integrity sha512-OKwd4gmwHqOTp4mOGZKe/XUlbDJ4Q9TjX0hMPIDBUWWu/kwhBAudJdBoxnjNf9ocIB6GN6CPowYpR/hRCbSYAg==
|
||||
|
||||
esbuild-freebsd-arm64@0.14.47:
|
||||
version "0.14.47"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.47.tgz#ad31f9c92817ff8f33fd253af7ab5122dc1b83f6"
|
||||
integrity sha512-ZJMQAJQsIOhn3XTm7MPQfCzEu5b9STNC+s90zMWe2afy9EwnHV7Ov7ohEMv2lyWlc2pjqLW8QJnz2r0KZmeAEQ==
|
||||
esbuild-freebsd-arm64@0.14.54:
|
||||
version "0.14.54"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.54.tgz#bafb46ed04fc5f97cbdb016d86947a79579f8e48"
|
||||
integrity sha512-sFwueGr7OvIFiQT6WeG0jRLjkjdqWWSrfbVwZp8iMP+8UHEHRBvlaxL6IuKNDwAozNUmbb8nIMXa7oAOARGs1Q==
|
||||
|
||||
esbuild-linux-32@0.14.47:
|
||||
version "0.14.47"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-linux-32/-/esbuild-linux-32-0.14.47.tgz#de085e4db2e692ea30c71208ccc23fdcf5196c58"
|
||||
integrity sha512-FxZOCKoEDPRYvq300lsWCTv1kcHgiiZfNrPtEhFAiqD7QZaXrad8LxyJ8fXGcWzIFzRiYZVtB3ttvITBvAFhKw==
|
||||
esbuild-linux-32@0.14.54:
|
||||
version "0.14.54"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-linux-32/-/esbuild-linux-32-0.14.54.tgz#e2a8c4a8efdc355405325033fcebeb941f781fe5"
|
||||
integrity sha512-1ZuY+JDI//WmklKlBgJnglpUL1owm2OX+8E1syCD6UAxcMM/XoWd76OHSjl/0MR0LisSAXDqgjT3uJqT67O3qw==
|
||||
|
||||
esbuild-linux-64@0.14.47:
|
||||
version "0.14.47"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-linux-64/-/esbuild-linux-64-0.14.47.tgz#2a9321bbccb01f01b04cebfcfccbabeba3658ba1"
|
||||
integrity sha512-nFNOk9vWVfvWYF9YNYksZptgQAdstnDCMtR6m42l5Wfugbzu11VpMCY9XrD4yFxvPo9zmzcoUL/88y0lfJZJJw==
|
||||
esbuild-linux-64@0.14.54:
|
||||
version "0.14.54"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-linux-64/-/esbuild-linux-64-0.14.54.tgz#de5fdba1c95666cf72369f52b40b03be71226652"
|
||||
integrity sha512-EgjAgH5HwTbtNsTqQOXWApBaPVdDn7XcK+/PtJwZLT1UmpLoznPd8c5CxqsH2dQK3j05YsB3L17T8vE7cp4cCg==
|
||||
|
||||
esbuild-linux-arm64@0.14.47:
|
||||
version "0.14.47"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.47.tgz#b9da7b6fc4b0ca7a13363a0c5b7bb927e4bc535a"
|
||||
integrity sha512-ywfme6HVrhWcevzmsufjd4iT3PxTfCX9HOdxA7Hd+/ZM23Y9nXeb+vG6AyA6jgq/JovkcqRHcL9XwRNpWG6XRw==
|
||||
esbuild-linux-arm64@0.14.54:
|
||||
version "0.14.54"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.54.tgz#dae4cd42ae9787468b6a5c158da4c84e83b0ce8b"
|
||||
integrity sha512-WL71L+0Rwv+Gv/HTmxTEmpv0UgmxYa5ftZILVi2QmZBgX3q7+tDeOQNqGtdXSdsL8TQi1vIaVFHUPDe0O0kdig==
|
||||
|
||||
esbuild-linux-arm@0.14.47:
|
||||
version "0.14.47"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-linux-arm/-/esbuild-linux-arm-0.14.47.tgz#56fec2a09b9561c337059d4af53625142aded853"
|
||||
integrity sha512-ZGE1Bqg/gPRXrBpgpvH81tQHpiaGxa8c9Rx/XOylkIl2ypLuOcawXEAo8ls+5DFCcRGt/o3sV+PzpAFZobOsmA==
|
||||
esbuild-linux-arm@0.14.54:
|
||||
version "0.14.54"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-linux-arm/-/esbuild-linux-arm-0.14.54.tgz#a2c1dff6d0f21dbe8fc6998a122675533ddfcd59"
|
||||
integrity sha512-qqz/SjemQhVMTnvcLGoLOdFpCYbz4v4fUo+TfsWG+1aOu70/80RV6bgNpR2JCrppV2moUQkww+6bWxXRL9YMGw==
|
||||
|
||||
esbuild-linux-mips64le@0.14.47:
|
||||
version "0.14.47"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.47.tgz#9db21561f8f22ed79ef2aedb7bbef082b46cf823"
|
||||
integrity sha512-mg3D8YndZ1LvUiEdDYR3OsmeyAew4MA/dvaEJxvyygahWmpv1SlEEnhEZlhPokjsUMfRagzsEF/d/2XF+kTQGg==
|
||||
esbuild-linux-mips64le@0.14.54:
|
||||
version "0.14.54"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.54.tgz#d9918e9e4cb972f8d6dae8e8655bf9ee131eda34"
|
||||
integrity sha512-qTHGQB8D1etd0u1+sB6p0ikLKRVuCWhYQhAHRPkO+OF3I/iSlTKNNS0Lh2Oc0g0UFGguaFZZiPJdJey3AGpAlw==
|
||||
|
||||
esbuild-linux-ppc64le@0.14.47:
|
||||
version "0.14.47"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.47.tgz#dc3a3da321222b11e96e50efafec9d2de408198b"
|
||||
integrity sha512-WER+f3+szmnZiWoK6AsrTKGoJoErG2LlauSmk73LEZFQ/iWC+KhhDsOkn1xBUpzXWsxN9THmQFltLoaFEH8F8w==
|
||||
esbuild-linux-ppc64le@0.14.54:
|
||||
version "0.14.54"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.54.tgz#3f9a0f6d41073fb1a640680845c7de52995f137e"
|
||||
integrity sha512-j3OMlzHiqwZBDPRCDFKcx595XVfOfOnv68Ax3U4UKZ3MTYQB5Yz3X1mn5GnodEVYzhtZgxEBidLWeIs8FDSfrQ==
|
||||
|
||||
esbuild-linux-riscv64@0.14.47:
|
||||
version "0.14.47"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.14.47.tgz#9bd6dcd3dca6c0357084ecd06e1d2d4bf105335f"
|
||||
integrity sha512-1fI6bP3A3rvI9BsaaXbMoaOjLE3lVkJtLxsgLHqlBhLlBVY7UqffWBvkrX/9zfPhhVMd9ZRFiaqXnB1T7BsL2g==
|
||||
esbuild-linux-riscv64@0.14.54:
|
||||
version "0.14.54"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.14.54.tgz#618853c028178a61837bc799d2013d4695e451c8"
|
||||
integrity sha512-y7Vt7Wl9dkOGZjxQZnDAqqn+XOqFD7IMWiewY5SPlNlzMX39ocPQlOaoxvT4FllA5viyV26/QzHtvTjVNOxHZg==
|
||||
|
||||
esbuild-linux-s390x@0.14.47:
|
||||
version "0.14.47"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.47.tgz#a458af939b52f2cd32fc561410d441a51f69d41f"
|
||||
integrity sha512-eZrWzy0xFAhki1CWRGnhsHVz7IlSKX6yT2tj2Eg8lhAwlRE5E96Hsb0M1mPSE1dHGpt1QVwwVivXIAacF/G6mw==
|
||||
esbuild-linux-s390x@0.14.54:
|
||||
version "0.14.54"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.54.tgz#d1885c4c5a76bbb5a0fe182e2c8c60eb9e29f2a6"
|
||||
integrity sha512-zaHpW9dziAsi7lRcyV4r8dhfG1qBidQWUXweUjnw+lliChJqQr+6XD71K41oEIC3Mx1KStovEmlzm+MkGZHnHA==
|
||||
|
||||
esbuild-netbsd-64@0.14.47:
|
||||
version "0.14.47"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.47.tgz#6388e785d7e7e4420cb01348d7483ab511b16aa8"
|
||||
integrity sha512-Qjdjr+KQQVH5Q2Q1r6HBYswFTToPpss3gqCiSw2Fpq/ua8+eXSQyAMG+UvULPqXceOwpnPo4smyZyHdlkcPppQ==
|
||||
esbuild-netbsd-64@0.14.54:
|
||||
version "0.14.54"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.54.tgz#69ae917a2ff241b7df1dbf22baf04bd330349e81"
|
||||
integrity sha512-PR01lmIMnfJTgeU9VJTDY9ZerDWVFIUzAtJuDHwwceppW7cQWjBBqP48NdeRtoP04/AtO9a7w3viI+PIDr6d+w==
|
||||
|
||||
esbuild-openbsd-64@0.14.47:
|
||||
version "0.14.47"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.47.tgz#309af806db561aa886c445344d1aacab850dbdc5"
|
||||
integrity sha512-QpgN8ofL7B9z8g5zZqJE+eFvD1LehRlxr25PBkjyyasakm4599iroUpaj96rdqRlO2ShuyqwJdr+oNqWwTUmQw==
|
||||
esbuild-openbsd-64@0.14.54:
|
||||
version "0.14.54"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.54.tgz#db4c8495287a350a6790de22edea247a57c5d47b"
|
||||
integrity sha512-Qyk7ikT2o7Wu76UsvvDS5q0amJvmRzDyVlL0qf5VLsLchjCa1+IAvd8kTBgUxD7VBUUVgItLkk609ZHUc1oCaw==
|
||||
|
||||
esbuild-sunos-64@0.14.47:
|
||||
version "0.14.47"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-sunos-64/-/esbuild-sunos-64-0.14.47.tgz#3f19612dcdb89ba6c65283a7ff6e16f8afbf8aaa"
|
||||
integrity sha512-uOeSgLUwukLioAJOiGYm3kNl+1wJjgJA8R671GYgcPgCx7QR73zfvYqXFFcIO93/nBdIbt5hd8RItqbbf3HtAQ==
|
||||
esbuild-sunos-64@0.14.54:
|
||||
version "0.14.54"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-sunos-64/-/esbuild-sunos-64-0.14.54.tgz#54287ee3da73d3844b721c21bc80c1dc7e1bf7da"
|
||||
integrity sha512-28GZ24KmMSeKi5ueWzMcco6EBHStL3B6ubM7M51RmPwXQGLe0teBGJocmWhgwccA1GeFXqxzILIxXpHbl9Q/Kw==
|
||||
|
||||
esbuild-windows-32@0.14.47:
|
||||
version "0.14.47"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-windows-32/-/esbuild-windows-32-0.14.47.tgz#a92d279c8458d5dc319abcfeb30aa49e8f2e6f7f"
|
||||
integrity sha512-H0fWsLTp2WBfKLBgwYT4OTfFly4Im/8B5f3ojDv1Kx//kiubVY0IQunP2Koc/fr/0wI7hj3IiBDbSrmKlrNgLQ==
|
||||
esbuild-windows-32@0.14.54:
|
||||
version "0.14.54"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-windows-32/-/esbuild-windows-32-0.14.54.tgz#f8aaf9a5667630b40f0fb3aa37bf01bbd340ce31"
|
||||
integrity sha512-T+rdZW19ql9MjS7pixmZYVObd9G7kcaZo+sETqNH4RCkuuYSuv9AGHUVnPoP9hhuE1WM1ZimHz1CIBHBboLU7w==
|
||||
|
||||
esbuild-windows-64@0.14.47:
|
||||
version "0.14.47"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-windows-64/-/esbuild-windows-64-0.14.47.tgz#2564c3fcf0c23d701edb71af8c52d3be4cec5f8a"
|
||||
integrity sha512-/Pk5jIEH34T68r8PweKRi77W49KwanZ8X6lr3vDAtOlH5EumPE4pBHqkCUdELanvsT14yMXLQ/C/8XPi1pAtkQ==
|
||||
esbuild-windows-64@0.14.54:
|
||||
version "0.14.54"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-windows-64/-/esbuild-windows-64-0.14.54.tgz#bf54b51bd3e9b0f1886ffdb224a4176031ea0af4"
|
||||
integrity sha512-AoHTRBUuYwXtZhjXZbA1pGfTo8cJo3vZIcWGLiUcTNgHpJJMC1rVA44ZereBHMJtotyN71S8Qw0npiCIkW96cQ==
|
||||
|
||||
esbuild-windows-arm64@0.14.47:
|
||||
version "0.14.47"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.47.tgz#86d9db1a22d83360f726ac5fba41c2f625db6878"
|
||||
integrity sha512-HFSW2lnp62fl86/qPQlqw6asIwCnEsEoNIL1h2uVMgakddf+vUuMcCbtUY1i8sst7KkgHrVKCJQB33YhhOweCQ==
|
||||
esbuild-windows-arm64@0.14.54:
|
||||
version "0.14.54"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.54.tgz#937d15675a15e4b0e4fafdbaa3a01a776a2be982"
|
||||
integrity sha512-M0kuUvXhot1zOISQGXwWn6YtS+Y/1RT9WrVIOywZnJHo3jCDyewAc79aKNQWFCQm+xNHVTq9h8dZKvygoXQQRg==
|
||||
|
||||
esbuild@^0.14.27:
|
||||
version "0.14.47"
|
||||
resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.14.47.tgz#0d6415f6bd8eb9e73a58f7f9ae04c5276cda0e4d"
|
||||
integrity sha512-wI4ZiIfFxpkuxB8ju4MHrGwGLyp1+awEHAHVpx6w7a+1pmYIq8T9FGEVVwFo0iFierDoMj++Xq69GXWYn2EiwA==
|
||||
esbuild@^0.14.47:
|
||||
version "0.14.54"
|
||||
resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.14.54.tgz#8b44dcf2b0f1a66fc22459943dccf477535e9aa2"
|
||||
integrity sha512-Cy9llcy8DvET5uznocPyqL3BFRrFXSVqbgpMJ9Wz8oVjZlh/zUSNbPRbov0VX7VxN2JH1Oa0uNxZ7eLRb62pJA==
|
||||
optionalDependencies:
|
||||
esbuild-android-64 "0.14.47"
|
||||
esbuild-android-arm64 "0.14.47"
|
||||
esbuild-darwin-64 "0.14.47"
|
||||
esbuild-darwin-arm64 "0.14.47"
|
||||
esbuild-freebsd-64 "0.14.47"
|
||||
esbuild-freebsd-arm64 "0.14.47"
|
||||
esbuild-linux-32 "0.14.47"
|
||||
esbuild-linux-64 "0.14.47"
|
||||
esbuild-linux-arm "0.14.47"
|
||||
esbuild-linux-arm64 "0.14.47"
|
||||
esbuild-linux-mips64le "0.14.47"
|
||||
esbuild-linux-ppc64le "0.14.47"
|
||||
esbuild-linux-riscv64 "0.14.47"
|
||||
esbuild-linux-s390x "0.14.47"
|
||||
esbuild-netbsd-64 "0.14.47"
|
||||
esbuild-openbsd-64 "0.14.47"
|
||||
esbuild-sunos-64 "0.14.47"
|
||||
esbuild-windows-32 "0.14.47"
|
||||
esbuild-windows-64 "0.14.47"
|
||||
esbuild-windows-arm64 "0.14.47"
|
||||
"@esbuild/linux-loong64" "0.14.54"
|
||||
esbuild-android-64 "0.14.54"
|
||||
esbuild-android-arm64 "0.14.54"
|
||||
esbuild-darwin-64 "0.14.54"
|
||||
esbuild-darwin-arm64 "0.14.54"
|
||||
esbuild-freebsd-64 "0.14.54"
|
||||
esbuild-freebsd-arm64 "0.14.54"
|
||||
esbuild-linux-32 "0.14.54"
|
||||
esbuild-linux-64 "0.14.54"
|
||||
esbuild-linux-arm "0.14.54"
|
||||
esbuild-linux-arm64 "0.14.54"
|
||||
esbuild-linux-mips64le "0.14.54"
|
||||
esbuild-linux-ppc64le "0.14.54"
|
||||
esbuild-linux-riscv64 "0.14.54"
|
||||
esbuild-linux-s390x "0.14.54"
|
||||
esbuild-netbsd-64 "0.14.54"
|
||||
esbuild-openbsd-64 "0.14.54"
|
||||
esbuild-sunos-64 "0.14.54"
|
||||
esbuild-windows-32 "0.14.54"
|
||||
esbuild-windows-64 "0.14.54"
|
||||
esbuild-windows-arm64 "0.14.54"
|
||||
|
||||
estree-walker@^2.0.1:
|
||||
version "2.0.2"
|
||||
resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-2.0.2.tgz#52f010178c2a4c117a7757cfe942adb7d2da4cac"
|
||||
integrity sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==
|
||||
|
||||
execa@^5.1.1:
|
||||
execa@^5.0.0, execa@^5.1.1:
|
||||
version "5.1.1"
|
||||
resolved "https://registry.yarnpkg.com/execa/-/execa-5.1.1.tgz#f80ad9cbf4298f7bd1d4c9555c21e93741c411dd"
|
||||
integrity sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==
|
||||
@@ -558,6 +571,26 @@ human-signals@^2.1.0:
|
||||
resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0"
|
||||
integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==
|
||||
|
||||
internal-ip@^7.0.0:
|
||||
version "7.0.0"
|
||||
resolved "https://registry.yarnpkg.com/internal-ip/-/internal-ip-7.0.0.tgz#5b1c6a9d7e188aa73a1b69717daf50c8d8ed774f"
|
||||
integrity sha512-qE4TeD4brqC45Vq/+VASeMiS1KRyfBkR6HT2sh9pZVVCzSjPkaCEfKFU+dL0PRv7NHJtvoKN2r82G6wTfzorkw==
|
||||
dependencies:
|
||||
default-gateway "^6.0.3"
|
||||
ipaddr.js "^2.0.1"
|
||||
is-ip "^3.1.0"
|
||||
p-event "^4.2.0"
|
||||
|
||||
ip-regex@^4.0.0:
|
||||
version "4.3.0"
|
||||
resolved "https://registry.yarnpkg.com/ip-regex/-/ip-regex-4.3.0.tgz#687275ab0f57fa76978ff8f4dddc8a23d5990db5"
|
||||
integrity sha512-B9ZWJxHHOHUhUjCPrMpLD4xEq35bUTClHM1S6CBU5ixQnkZmwipwgc96vAd7AAGM9TGHvJR+Uss+/Ak6UphK+Q==
|
||||
|
||||
ipaddr.js@^2.0.1:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-2.0.1.tgz#eca256a7a877e917aeb368b0a7497ddf42ef81c0"
|
||||
integrity sha512-1qTgH9NG+IIJ4yfKs2e6Pp1bZg8wbDbKHT21HrLIeYBTRLgMYKnMTPAuI3Lcs61nfx5h1xlXnbJtH1kX5/d/ng==
|
||||
|
||||
is-binary-path@~2.1.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09"
|
||||
@@ -584,6 +617,13 @@ is-glob@^4.0.1, is-glob@~4.0.1:
|
||||
dependencies:
|
||||
is-extglob "^2.1.1"
|
||||
|
||||
is-ip@^3.1.0:
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/is-ip/-/is-ip-3.1.0.tgz#2ae5ddfafaf05cb8008a62093cf29734f657c5d8"
|
||||
integrity sha512-35vd5necO7IitFPjd/YBeqwWnyDWbuLH9ZXQdMfDA8TEo7pv5X8yfrvVO3xbJbLUlERCMvf6X0hTUamQxCYJ9Q==
|
||||
dependencies:
|
||||
ip-regex "^4.0.0"
|
||||
|
||||
is-number@^7.0.0:
|
||||
version "7.0.0"
|
||||
resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b"
|
||||
@@ -604,10 +644,10 @@ jiti@^1.13.0:
|
||||
resolved "https://registry.yarnpkg.com/jiti/-/jiti-1.14.0.tgz#5350fff532a4d891ca4bcd700c47c1f40e6ee326"
|
||||
integrity sha512-4IwstlaKQc9vCTC+qUXLM1hajy2ImiL9KnLvVYiaHOtS/v3wRjhLlGl121AmgDgx/O43uKmxownJghS5XMya2A==
|
||||
|
||||
kleur@^4.1.4:
|
||||
version "4.1.4"
|
||||
resolved "https://registry.yarnpkg.com/kleur/-/kleur-4.1.4.tgz#8c202987d7e577766d039a8cd461934c01cda04d"
|
||||
integrity sha512-8QADVssbrFjivHWQU7KkMgptGTl6WAcSdlbBPY4uNF+mWr6DGcKrvY2w4FQJoXch7+fKMjj0dRrL75vk3k23OA==
|
||||
kleur@^4.1.5:
|
||||
version "4.1.5"
|
||||
resolved "https://registry.yarnpkg.com/kleur/-/kleur-4.1.5.tgz#95106101795f7050c6c650f350c683febddb1780"
|
||||
integrity sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==
|
||||
|
||||
kolorist@^1.5.1:
|
||||
version "1.5.1"
|
||||
@@ -710,6 +750,18 @@ onetime@^5.1.2:
|
||||
dependencies:
|
||||
mimic-fn "^2.1.0"
|
||||
|
||||
p-event@^4.2.0:
|
||||
version "4.2.0"
|
||||
resolved "https://registry.yarnpkg.com/p-event/-/p-event-4.2.0.tgz#af4b049c8acd91ae81083ebd1e6f5cae2044c1b5"
|
||||
integrity sha512-KXatOjCRXXkSePPb1Nbi0p0m+gQAwdlbhi4wQKJPI1HsMQS9g+Sqp2o+QHziPr7eYJyOZet836KoHEVM1mwOrQ==
|
||||
dependencies:
|
||||
p-timeout "^3.1.0"
|
||||
|
||||
p-finally@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae"
|
||||
integrity sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==
|
||||
|
||||
p-limit@^3.0.2:
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b"
|
||||
@@ -724,6 +776,13 @@ p-locate@^5.0.0:
|
||||
dependencies:
|
||||
p-limit "^3.0.2"
|
||||
|
||||
p-timeout@^3.1.0:
|
||||
version "3.2.0"
|
||||
resolved "https://registry.yarnpkg.com/p-timeout/-/p-timeout-3.2.0.tgz#c7e17abc971d2a7962ef83626b35d635acf23dfe"
|
||||
integrity sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg==
|
||||
dependencies:
|
||||
p-finally "^1.0.0"
|
||||
|
||||
path-exists@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3"
|
||||
@@ -764,10 +823,10 @@ picomatch@^2.2.2:
|
||||
resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.2.2.tgz#21f333e9b6b8eaff02468f5146ea406d345f4dad"
|
||||
integrity sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==
|
||||
|
||||
postcss@^8.4.13:
|
||||
version "8.4.14"
|
||||
resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.14.tgz#ee9274d5622b4858c1007a74d76e42e56fd21caf"
|
||||
integrity sha512-E398TUmfAYFPBSdzgeieK2Y1+1cpdxJx8yXbK/m57nRhKSmk1GB2tO4lbLBtlkfPQTDKfe4Xqv1ASWPpayPEig==
|
||||
postcss@^8.4.16:
|
||||
version "8.4.16"
|
||||
resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.16.tgz#33a1d675fac39941f5f445db0de4db2b6e01d43c"
|
||||
integrity sha512-ipHE1XBvKzm5xI7hiHCZJCSugxvsdq2mPnsq5+UF+VHCjiBvtDrlxJfMBToWaP9D5XlgNmcFGqoHmUn0EYEaRQ==
|
||||
dependencies:
|
||||
nanoid "^3.3.4"
|
||||
picocolors "^1.0.0"
|
||||
@@ -785,7 +844,7 @@ readdirp@~3.6.0:
|
||||
dependencies:
|
||||
picomatch "^2.2.1"
|
||||
|
||||
resolve@^1.22.0:
|
||||
resolve@^1.22.1:
|
||||
version "1.22.1"
|
||||
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.1.tgz#27cb2ebb53f91abb49470a928bba7558066ac177"
|
||||
integrity sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==
|
||||
@@ -799,10 +858,10 @@ reusify@^1.0.4:
|
||||
resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76"
|
||||
integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==
|
||||
|
||||
rollup@^2.59.0:
|
||||
version "2.75.7"
|
||||
resolved "https://registry.yarnpkg.com/rollup/-/rollup-2.75.7.tgz#221ff11887ae271e37dcc649ba32ce1590aaa0b9"
|
||||
integrity sha512-VSE1iy0eaAYNCxEXaleThdFXqZJ42qDBatAwrfnPlENEZ8erQ+0LYX4JXOLPceWfZpV1VtZwZ3dFCuOZiSyFtQ==
|
||||
"rollup@>=2.75.6 <2.77.0 || ~2.77.0":
|
||||
version "2.77.3"
|
||||
resolved "https://registry.yarnpkg.com/rollup/-/rollup-2.77.3.tgz#8f00418d3a2740036e15deb653bed1a90ee0cc12"
|
||||
integrity sha512-/qxNTG7FbmefJWoeeYJFbHehJ2HNWnjkAFRKzWN/45eNBBF/r8lo992CwcJXEzyVxs5FmfId+vTSTQDb+bxA+g==
|
||||
optionalDependencies:
|
||||
fsevents "~2.3.2"
|
||||
|
||||
@@ -926,15 +985,15 @@ unocss@^0.39.3:
|
||||
"@unocss/transformer-variant-group" "0.39.3"
|
||||
"@unocss/vite" "0.39.3"
|
||||
|
||||
vite@^2.9.12:
|
||||
version "2.9.12"
|
||||
resolved "https://registry.yarnpkg.com/vite/-/vite-2.9.12.tgz#b1d636b0a8ac636afe9d83e3792d4895509a941b"
|
||||
integrity sha512-suxC36dQo9Rq1qMB2qiRorNJtJAdxguu5TMvBHOc/F370KvqAe9t48vYp+/TbPKRNrMh/J55tOUmkuIqstZaew==
|
||||
vite@^3.0.9:
|
||||
version "3.0.9"
|
||||
resolved "https://registry.yarnpkg.com/vite/-/vite-3.0.9.tgz#45fac22c2a5290a970f23d66c1aef56a04be8a30"
|
||||
integrity sha512-waYABTM+G6DBTCpYAxvevpG50UOlZuynR0ckTK5PawNVt7ebX6X7wNXHaGIO6wYYFXSM7/WcuFuO2QzhBB6aMw==
|
||||
dependencies:
|
||||
esbuild "^0.14.27"
|
||||
postcss "^8.4.13"
|
||||
resolve "^1.22.0"
|
||||
rollup "^2.59.0"
|
||||
esbuild "^0.14.47"
|
||||
postcss "^8.4.16"
|
||||
resolve "^1.22.1"
|
||||
rollup ">=2.75.6 <2.77.0 || ~2.77.0"
|
||||
optionalDependencies:
|
||||
fsevents "~2.3.2"
|
||||
|
||||
|
||||
135
tooling/cli/Cargo.lock
generated
135
tooling/cli/Cargo.lock
generated
@@ -127,18 +127,6 @@ version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8a32fd6af2b5827bce66c29053ba0e7c42b9dcab01835835058558c10851a46b"
|
||||
|
||||
[[package]]
|
||||
name = "bicycle"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/BrainiumLLC/bicycle?rev=28080e0c6fa4067d9dd1b0f2b7322b6b32178e1f#28080e0c6fa4067d9dd1b0f2b7322b6b32178e1f"
|
||||
dependencies = [
|
||||
"handlebars 3.5.5",
|
||||
"log",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bit_field"
|
||||
version = "0.10.1"
|
||||
@@ -199,16 +187,6 @@ dependencies = [
|
||||
"byte-tools",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bossy"
|
||||
version = "0.2.1"
|
||||
source = "git+https://github.com/lucasfernog/bossy?branch=fix/winapi-features#83ee04daddbc9b985b5f8dcf54d7229f0542d41d"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"log",
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bstr"
|
||||
version = "0.2.17"
|
||||
@@ -272,13 +250,10 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "cargo-mobile"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/tauri-apps/cargo-mobile?branch=dev#32de2201d4a607c2d4b910cc2a33d052fe852bd8"
|
||||
source = "git+https://github.com/tauri-apps/cargo-mobile?branch=dev#9733784cbb8af4fe0accc634463ff58424c88e62"
|
||||
dependencies = [
|
||||
"bicycle",
|
||||
"bossy",
|
||||
"cocoa",
|
||||
"colored 1.9.3",
|
||||
"const-utf16",
|
||||
"core-foundation 0.7.0",
|
||||
"deunicode",
|
||||
"dunce",
|
||||
@@ -286,20 +261,20 @@ dependencies = [
|
||||
"english-numbers",
|
||||
"env_logger 0.7.1",
|
||||
"freedesktop_entry_parser",
|
||||
"handlebars 3.5.5",
|
||||
"heck 0.4.0",
|
||||
"hit",
|
||||
"home",
|
||||
"ignore",
|
||||
"indexmap",
|
||||
"java-properties",
|
||||
"lexical-core",
|
||||
"libc",
|
||||
"log",
|
||||
"objc",
|
||||
"objc_id",
|
||||
"once-cell-regex",
|
||||
"openssl",
|
||||
"path_abs",
|
||||
"reserved-names",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"structopt",
|
||||
@@ -307,8 +282,8 @@ dependencies = [
|
||||
"thiserror",
|
||||
"toml",
|
||||
"ureq",
|
||||
"windows 0.26.0",
|
||||
"yes-or-no",
|
||||
"winapi 0.3.9",
|
||||
"windows 0.39.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -483,12 +458,6 @@ dependencies = [
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "const-utf16"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "90feefab165fe011746e3be2f0708b7b180fcbd9f5054ff81a454d7bd93d8285"
|
||||
|
||||
[[package]]
|
||||
name = "constant_time_eq"
|
||||
version = "0.1.5"
|
||||
@@ -1334,18 +1303,6 @@ version = "0.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
|
||||
|
||||
[[package]]
|
||||
name = "hit"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0a8b280c3c6e2a2a51b3dde2f1071b28afff0ebce59e29443b1b391e7efe32fd"
|
||||
dependencies = [
|
||||
"bossy",
|
||||
"log",
|
||||
"once-cell-regex",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hmac"
|
||||
version = "0.12.1"
|
||||
@@ -2740,14 +2697,6 @@ dependencies = [
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "reserved-names"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/BrainiumLLC/reserved-names#cc46545db485b13851e9136280b7d8e5a95a9d18"
|
||||
dependencies = [
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ring"
|
||||
version = "0.16.20"
|
||||
@@ -3350,12 +3299,12 @@ version = "1.0.5"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"base64",
|
||||
"bossy",
|
||||
"cargo-mobile",
|
||||
"clap 3.2.7",
|
||||
"colored 2.0.0",
|
||||
"ctrlc",
|
||||
"dialoguer",
|
||||
"dirs-next",
|
||||
"env_logger 0.9.0",
|
||||
"glob",
|
||||
"handlebars 4.3.1",
|
||||
@@ -4009,19 +3958,6 @@ version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
|
||||
[[package]]
|
||||
name = "windows"
|
||||
version = "0.26.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "347cdcaae1addebdff584aea1f9fbc0426dedbe1315f1dcf30c7a9876401cd25"
|
||||
dependencies = [
|
||||
"windows_aarch64_msvc 0.26.0",
|
||||
"windows_i686_gnu 0.26.0",
|
||||
"windows_i686_msvc 0.26.0",
|
||||
"windows_x86_64_gnu 0.26.0",
|
||||
"windows_x86_64_msvc 0.26.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows"
|
||||
version = "0.37.0"
|
||||
@@ -4036,6 +3972,19 @@ dependencies = [
|
||||
"windows_x86_64_msvc 0.37.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows"
|
||||
version = "0.39.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f1c4bd0a50ac6020f65184721f758dba47bb9fbc2133df715ec74a237b26794a"
|
||||
dependencies = [
|
||||
"windows_aarch64_msvc 0.39.0",
|
||||
"windows_i686_gnu 0.39.0",
|
||||
"windows_i686_msvc 0.39.0",
|
||||
"windows_x86_64_gnu 0.39.0",
|
||||
"windows_x86_64_msvc 0.39.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-implement"
|
||||
version = "0.37.0"
|
||||
@@ -4065,12 +4014,6 @@ version = "0.37.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3263d25f1170419995b78ff10c06b949e8a986c35c208dc24333c64753a87169"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.26.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f7758986b022add546ae53ccad31f4852ce6bd2e2c2d3cc2b1d7d06dea0b90da"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.36.1"
|
||||
@@ -4084,10 +4027,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2623277cb2d1c216ba3b578c0f3cf9cdebeddb6e66b1b218bb33596ea7769c3a"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.26.0"
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.39.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "29261214caab8e589f61031ba1ccd5c3c25e61db2118a3aec4459f58ff798726"
|
||||
checksum = "ec7711666096bd4096ffa835238905bb33fb87267910e154b18b44eaabb340f2"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
@@ -4102,10 +4045,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d3925fd0b0b804730d44d4b6278c50f9699703ec49bcd628020f46f4ba07d9e1"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.26.0"
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.39.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "43984fb3b944743142112ae926e7adeccb60f35bb81d43114f4d0fe2871f60ba"
|
||||
checksum = "763fc57100a5f7042e3057e7e8d9bdd7860d330070251a73d003563a3bb49e1b"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
@@ -4120,10 +4063,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ce907ac74fe331b524c1298683efbf598bb031bc84d5e274db2083696d07c57c"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.26.0"
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.39.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2a80fc90e1ad19769e596a3f58d0776319059e21cac9069a5a2a791362ce7190"
|
||||
checksum = "7bc7cbfe58828921e10a9f446fcaaf649204dcfe6c1ddd712c5eebae6bda1106"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
@@ -4138,10 +4081,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2babfba0828f2e6b32457d5341427dcbb577ceef556273229959ac23a10af33d"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.26.0"
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.39.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dc24ddac19a0cf02ad2b32d8897f202fc1a13ef285e2d4774e6610783cc8398f"
|
||||
checksum = "6868c165637d653ae1e8dc4d82c25d4f97dd6605eaa8d784b5c6e0ab2a252b65"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
@@ -4155,6 +4098,12 @@ version = "0.37.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f4dd6dc7df2d84cf7b33822ed5b86318fb1781948e9663bacd047fc9dd52259d"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.39.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5e4d40883ae9cae962787ca76ba76390ffa29214667a111db9e0a1ad8377e809"
|
||||
|
||||
[[package]]
|
||||
name = "winreg"
|
||||
version = "0.10.1"
|
||||
@@ -4189,16 +4138,6 @@ version = "0.8.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d2d7d3948613f75c98fd9328cfdcc45acc4d360655289d0a7d4ec931392200a3"
|
||||
|
||||
[[package]]
|
||||
name = "yes-or-no"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/BrainiumLLC/yes-or-no#71d932693601fcf93ff906b90ad61f85b52117c5"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zeroize"
|
||||
version = "1.5.5"
|
||||
|
||||
@@ -26,14 +26,11 @@ include = [
|
||||
name = "cargo-tauri"
|
||||
path = "src/main.rs"
|
||||
|
||||
[patch.crates-io]
|
||||
bossy = { git = "https://github.com/lucasfernog/bossy", branch = "fix/winapi-features" }
|
||||
|
||||
[dependencies]
|
||||
# cargo-mobile = { path = "../../../cargo-mobile/", default-features = false }
|
||||
cargo-mobile = { git = "https://github.com/tauri-apps/cargo-mobile", branch = "dev", default-features = false }
|
||||
bossy = "0.2"
|
||||
textwrap = { version = "0.11.0", features = ["term_size"] }
|
||||
dirs-next = "2.0"
|
||||
thiserror = "1"
|
||||
clap = { version = "3.2", features = [ "derive" ] }
|
||||
anyhow = "1.0"
|
||||
|
||||
@@ -2433,7 +2433,7 @@
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"developmentTeam": {
|
||||
"description": "The development team. This value is required for iOS development because code signing is enforced. The `APPLE_DEVELOPMENT_TEAM` environment variable can be set to overwrite it.",
|
||||
"description": "The development team. This value is required for iOS development because code signing is enforced. The `TAURI_APPLE_DEVELOPMENT_TEAM` environment variable can be set to overwrite it.",
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
|
||||
@@ -83,6 +83,8 @@ pub fn command(mut options: Options) -> Result<()> {
|
||||
let config_guard = config.lock().unwrap();
|
||||
let config_ = config_guard.as_ref().unwrap();
|
||||
|
||||
let mut interface = AppInterface::new(config_)?;
|
||||
|
||||
let bundle_identifier_source = match config_.find_bundle_identifier_overwriter() {
|
||||
Some(source) if source == MERGE_CONFIG_EXTENSION_NAME => merge_config_path.unwrap_or(source),
|
||||
Some(source) => source,
|
||||
@@ -154,7 +156,6 @@ pub fn command(mut options: Options) -> Result<()> {
|
||||
list.extend(config_.build.features.clone().unwrap_or_default());
|
||||
}
|
||||
|
||||
let mut interface = AppInterface::new(config_)?;
|
||||
let app_settings = interface.app_settings();
|
||||
let interface_options = options.clone().into();
|
||||
|
||||
|
||||
@@ -49,7 +49,7 @@ pub struct Options {
|
||||
pub features: Option<Vec<String>>,
|
||||
/// Exit on panic
|
||||
#[clap(short, long)]
|
||||
exit_on_panic: bool,
|
||||
pub exit_on_panic: bool,
|
||||
/// JSON string or path to JSON file to merge with tauri.conf.json
|
||||
#[clap(short, long)]
|
||||
pub config: Option<String>,
|
||||
@@ -74,6 +74,15 @@ pub fn command(options: Options) -> Result<()> {
|
||||
}
|
||||
|
||||
fn command_internal(mut options: Options) -> Result<()> {
|
||||
let mut interface = setup(&mut options)?;
|
||||
let exit_on_panic = options.exit_on_panic;
|
||||
let no_watch = options.no_watch;
|
||||
interface.dev(options.into(), move |status, reason| {
|
||||
on_dev_exit(status, reason, exit_on_panic, no_watch)
|
||||
})
|
||||
}
|
||||
|
||||
pub fn setup(options: &mut Options) -> Result<AppInterface> {
|
||||
let tauri_path = tauri_dir();
|
||||
options.config = if let Some(config) = &options.config {
|
||||
Some(if config.starts_with('{') {
|
||||
@@ -89,6 +98,8 @@ fn command_internal(mut options: Options) -> Result<()> {
|
||||
|
||||
let config = get_config(options.config.as_deref())?;
|
||||
|
||||
let interface = AppInterface::new(config.lock().unwrap().as_ref().unwrap())?;
|
||||
|
||||
if let Some(before_dev) = config
|
||||
.lock()
|
||||
.unwrap()
|
||||
@@ -261,13 +272,7 @@ fn command_internal(mut options: Options) -> Result<()> {
|
||||
}
|
||||
}
|
||||
|
||||
let mut interface = AppInterface::new(config.lock().unwrap().as_ref().unwrap())?;
|
||||
|
||||
let exit_on_panic = options.exit_on_panic;
|
||||
let no_watch = options.no_watch;
|
||||
interface.dev(options.into(), move |status, reason| {
|
||||
on_dev_exit(status, reason, exit_on_panic, no_watch)
|
||||
})
|
||||
Ok(interface)
|
||||
}
|
||||
|
||||
fn on_dev_exit(status: ExitStatus, reason: ExitReason, exit_on_panic: bool, no_watch: bool) {
|
||||
|
||||
363
tooling/cli/src/helpers/flock.rs
Normal file
363
tooling/cli/src/helpers/flock.rs
Normal file
@@ -0,0 +1,363 @@
|
||||
// Copyright 2019-2021 Tauri Programme within The Commons Conservancy
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
// taken from https://github.com/rust-lang/cargo/blob/b0c9586f4cbf426914df47c65de38ea323772c74/src/cargo/util/flock.rs
|
||||
#![allow(dead_code)]
|
||||
|
||||
use std::fs::{create_dir_all, File, OpenOptions};
|
||||
use std::io;
|
||||
use std::io::{Read, Seek, SeekFrom, Write};
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
use crate::Result;
|
||||
use anyhow::Context as _;
|
||||
use sys::*;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct FileLock {
|
||||
f: Option<File>,
|
||||
path: PathBuf,
|
||||
state: State,
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Debug)]
|
||||
enum State {
|
||||
Unlocked,
|
||||
Shared,
|
||||
Exclusive,
|
||||
}
|
||||
|
||||
impl FileLock {
|
||||
/// Returns the underlying file handle of this lock.
|
||||
pub fn file(&self) -> &File {
|
||||
self.f.as_ref().unwrap()
|
||||
}
|
||||
|
||||
/// Returns the underlying path that this lock points to.
|
||||
///
|
||||
/// Note that special care must be taken to ensure that the path is not
|
||||
/// referenced outside the lifetime of this lock.
|
||||
pub fn path(&self) -> &Path {
|
||||
assert_ne!(self.state, State::Unlocked);
|
||||
&self.path
|
||||
}
|
||||
|
||||
/// Returns the parent path containing this file
|
||||
pub fn parent(&self) -> &Path {
|
||||
assert_ne!(self.state, State::Unlocked);
|
||||
self.path.parent().unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl Read for FileLock {
|
||||
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
||||
self.file().read(buf)
|
||||
}
|
||||
}
|
||||
|
||||
impl Seek for FileLock {
|
||||
fn seek(&mut self, to: SeekFrom) -> io::Result<u64> {
|
||||
self.file().seek(to)
|
||||
}
|
||||
}
|
||||
|
||||
impl Write for FileLock {
|
||||
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
||||
self.file().write(buf)
|
||||
}
|
||||
|
||||
fn flush(&mut self) -> io::Result<()> {
|
||||
self.file().flush()
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for FileLock {
|
||||
fn drop(&mut self) {
|
||||
if self.state != State::Unlocked {
|
||||
if let Some(f) = self.f.take() {
|
||||
let _ = unlock(&f);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Opens exclusive access to a file, returning the locked version of a
|
||||
/// file.
|
||||
///
|
||||
/// This function will create a file at `path` if it doesn't already exist
|
||||
/// (including intermediate directories), and then it will acquire an
|
||||
/// exclusive lock on `path`. If the process must block waiting for the
|
||||
/// lock, the `msg` is logged.
|
||||
///
|
||||
/// The returned file can be accessed to look at the path and also has
|
||||
/// read/write access to the underlying file.
|
||||
pub fn open_rw<P>(path: P, msg: &str) -> Result<FileLock>
|
||||
where
|
||||
P: AsRef<Path>,
|
||||
{
|
||||
open(
|
||||
path.as_ref(),
|
||||
OpenOptions::new().read(true).write(true).create(true),
|
||||
State::Exclusive,
|
||||
msg,
|
||||
)
|
||||
}
|
||||
|
||||
/// Opens shared access to a file, returning the locked version of a file.
|
||||
///
|
||||
/// This function will fail if `path` doesn't already exist, but if it does
|
||||
/// then it will acquire a shared lock on `path`. If the process must block
|
||||
/// waiting for the lock, the `msg` is logged.
|
||||
///
|
||||
/// The returned file can be accessed to look at the path and also has read
|
||||
/// access to the underlying file. Any writes to the file will return an
|
||||
/// error.
|
||||
pub fn open_ro<P>(path: P, msg: &str) -> Result<FileLock>
|
||||
where
|
||||
P: AsRef<Path>,
|
||||
{
|
||||
open(
|
||||
path.as_ref(),
|
||||
OpenOptions::new().read(true),
|
||||
State::Shared,
|
||||
msg,
|
||||
)
|
||||
}
|
||||
|
||||
fn open(path: &Path, opts: &OpenOptions, state: State, msg: &str) -> Result<FileLock> {
|
||||
// If we want an exclusive lock then if we fail because of NotFound it's
|
||||
// likely because an intermediate directory didn't exist, so try to
|
||||
// create the directory and then continue.
|
||||
let f = opts
|
||||
.open(&path)
|
||||
.or_else(|e| {
|
||||
if e.kind() == io::ErrorKind::NotFound && state == State::Exclusive {
|
||||
create_dir_all(path.parent().unwrap())?;
|
||||
Ok(opts.open(&path)?)
|
||||
} else {
|
||||
Err(anyhow::Error::from(e))
|
||||
}
|
||||
})
|
||||
.with_context(|| format!("failed to open: {}", path.display()))?;
|
||||
match state {
|
||||
State::Exclusive => {
|
||||
acquire(msg, path, &|| try_lock_exclusive(&f), &|| {
|
||||
lock_exclusive(&f)
|
||||
})?;
|
||||
}
|
||||
State::Shared => {
|
||||
acquire(msg, path, &|| try_lock_shared(&f), &|| lock_shared(&f))?;
|
||||
}
|
||||
State::Unlocked => {}
|
||||
}
|
||||
Ok(FileLock {
|
||||
f: Some(f),
|
||||
path: path.to_path_buf(),
|
||||
state,
|
||||
})
|
||||
}
|
||||
|
||||
/// Acquires a lock on a file in a "nice" manner.
|
||||
///
|
||||
/// Almost all long-running blocking actions in Cargo have a status message
|
||||
/// associated with them as we're not sure how long they'll take. Whenever a
|
||||
/// conflicted file lock happens, this is the case (we're not sure when the lock
|
||||
/// will be released).
|
||||
///
|
||||
/// This function will acquire the lock on a `path`, printing out a nice message
|
||||
/// to the console if we have to wait for it. It will first attempt to use `try`
|
||||
/// to acquire a lock on the crate, and in the case of contention it will emit a
|
||||
/// status message based on `msg` to `config`'s shell, and then use `block` to
|
||||
/// block waiting to acquire a lock.
|
||||
///
|
||||
/// Returns an error if the lock could not be acquired or if any error other
|
||||
/// than a contention error happens.
|
||||
fn acquire(
|
||||
msg: &str,
|
||||
path: &Path,
|
||||
lock_try: &dyn Fn() -> io::Result<()>,
|
||||
lock_block: &dyn Fn() -> io::Result<()>,
|
||||
) -> Result<()> {
|
||||
// File locking on Unix is currently implemented via `flock`, which is known
|
||||
// to be broken on NFS. We could in theory just ignore errors that happen on
|
||||
// NFS, but apparently the failure mode [1] for `flock` on NFS is **blocking
|
||||
// forever**, even if the "non-blocking" flag is passed!
|
||||
//
|
||||
// As a result, we just skip all file locks entirely on NFS mounts. That
|
||||
// should avoid calling any `flock` functions at all, and it wouldn't work
|
||||
// there anyway.
|
||||
//
|
||||
// [1]: https://github.com/rust-lang/cargo/issues/2615
|
||||
if is_on_nfs_mount(path) {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
match lock_try() {
|
||||
Ok(()) => return Ok(()),
|
||||
|
||||
// In addition to ignoring NFS which is commonly not working we also
|
||||
// just ignore locking on filesystems that look like they don't
|
||||
// implement file locking.
|
||||
Err(e) if error_unsupported(&e) => return Ok(()),
|
||||
|
||||
Err(e) => {
|
||||
if !error_contended(&e) {
|
||||
let e = anyhow::Error::from(e);
|
||||
let cx = format!("failed to lock file: {}", path.display());
|
||||
return Err(e.context(cx));
|
||||
}
|
||||
}
|
||||
}
|
||||
let msg = format!("waiting for file lock on {}", msg);
|
||||
log::info!(action = "Blocking"; "{}", &msg);
|
||||
|
||||
lock_block().with_context(|| format!("failed to lock file: {}", path.display()))?;
|
||||
return Ok(());
|
||||
|
||||
#[cfg(all(target_os = "linux", not(target_env = "musl")))]
|
||||
fn is_on_nfs_mount(path: &Path) -> bool {
|
||||
use std::ffi::CString;
|
||||
use std::mem;
|
||||
use std::os::unix::prelude::*;
|
||||
|
||||
let path = match CString::new(path.as_os_str().as_bytes()) {
|
||||
Ok(path) => path,
|
||||
Err(_) => return false,
|
||||
};
|
||||
|
||||
unsafe {
|
||||
let mut buf: libc::statfs = mem::zeroed();
|
||||
let r = libc::statfs(path.as_ptr(), &mut buf);
|
||||
|
||||
r == 0 && buf.f_type as u32 == libc::NFS_SUPER_MAGIC as u32
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(not(target_os = "linux"), target_env = "musl"))]
|
||||
fn is_on_nfs_mount(_path: &Path) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
mod sys {
|
||||
use std::fs::File;
|
||||
use std::io::{Error, Result};
|
||||
use std::os::unix::io::AsRawFd;
|
||||
|
||||
pub(super) fn lock_shared(file: &File) -> Result<()> {
|
||||
flock(file, libc::LOCK_SH)
|
||||
}
|
||||
|
||||
pub(super) fn lock_exclusive(file: &File) -> Result<()> {
|
||||
flock(file, libc::LOCK_EX)
|
||||
}
|
||||
|
||||
pub(super) fn try_lock_shared(file: &File) -> Result<()> {
|
||||
flock(file, libc::LOCK_SH | libc::LOCK_NB)
|
||||
}
|
||||
|
||||
pub(super) fn try_lock_exclusive(file: &File) -> Result<()> {
|
||||
flock(file, libc::LOCK_EX | libc::LOCK_NB)
|
||||
}
|
||||
|
||||
pub(super) fn unlock(file: &File) -> Result<()> {
|
||||
flock(file, libc::LOCK_UN)
|
||||
}
|
||||
|
||||
pub(super) fn error_contended(err: &Error) -> bool {
|
||||
err.raw_os_error().map_or(false, |x| x == libc::EWOULDBLOCK)
|
||||
}
|
||||
|
||||
pub(super) fn error_unsupported(err: &Error) -> bool {
|
||||
match err.raw_os_error() {
|
||||
// Unfortunately, depending on the target, these may or may not be the same.
|
||||
// For targets in which they are the same, the duplicate pattern causes a warning.
|
||||
#[allow(unreachable_patterns)]
|
||||
Some(libc::ENOTSUP | libc::EOPNOTSUPP) => true,
|
||||
Some(libc::ENOSYS) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "solaris"))]
|
||||
fn flock(file: &File, flag: libc::c_int) -> Result<()> {
|
||||
let ret = unsafe { libc::flock(file.as_raw_fd(), flag) };
|
||||
if ret < 0 {
|
||||
Err(Error::last_os_error())
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "solaris")]
|
||||
fn flock(file: &File, flag: libc::c_int) -> Result<()> {
|
||||
// Solaris lacks flock(), so simply succeed with a no-op
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
mod sys {
|
||||
use std::fs::File;
|
||||
use std::io::{Error, Result};
|
||||
use std::mem;
|
||||
use std::os::windows::io::AsRawHandle;
|
||||
|
||||
use winapi::shared::minwindef::DWORD;
|
||||
use winapi::shared::winerror::{ERROR_INVALID_FUNCTION, ERROR_LOCK_VIOLATION};
|
||||
use winapi::um::fileapi::{LockFileEx, UnlockFile};
|
||||
use winapi::um::minwinbase::{LOCKFILE_EXCLUSIVE_LOCK, LOCKFILE_FAIL_IMMEDIATELY};
|
||||
|
||||
pub(super) fn lock_shared(file: &File) -> Result<()> {
|
||||
lock_file(file, 0)
|
||||
}
|
||||
|
||||
pub(super) fn lock_exclusive(file: &File) -> Result<()> {
|
||||
lock_file(file, LOCKFILE_EXCLUSIVE_LOCK)
|
||||
}
|
||||
|
||||
pub(super) fn try_lock_shared(file: &File) -> Result<()> {
|
||||
lock_file(file, LOCKFILE_FAIL_IMMEDIATELY)
|
||||
}
|
||||
|
||||
pub(super) fn try_lock_exclusive(file: &File) -> Result<()> {
|
||||
lock_file(file, LOCKFILE_EXCLUSIVE_LOCK | LOCKFILE_FAIL_IMMEDIATELY)
|
||||
}
|
||||
|
||||
pub(super) fn error_contended(err: &Error) -> bool {
|
||||
err
|
||||
.raw_os_error()
|
||||
.map_or(false, |x| x == ERROR_LOCK_VIOLATION as i32)
|
||||
}
|
||||
|
||||
pub(super) fn error_unsupported(err: &Error) -> bool {
|
||||
err
|
||||
.raw_os_error()
|
||||
.map_or(false, |x| x == ERROR_INVALID_FUNCTION as i32)
|
||||
}
|
||||
|
||||
pub(super) fn unlock(file: &File) -> Result<()> {
|
||||
unsafe {
|
||||
let ret = UnlockFile(file.as_raw_handle(), 0, 0, !0, !0);
|
||||
if ret == 0 {
|
||||
Err(Error::last_os_error())
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn lock_file(file: &File, flags: DWORD) -> Result<()> {
|
||||
unsafe {
|
||||
let mut overlapped = mem::zeroed();
|
||||
let ret = LockFileEx(file.as_raw_handle(), flags, 0, !0, !0, &mut overlapped);
|
||||
if ret == 0 {
|
||||
Err(Error::last_os_error())
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
pub mod app_paths;
|
||||
pub mod config;
|
||||
pub mod flock;
|
||||
pub mod framework;
|
||||
pub mod template;
|
||||
pub mod updater_signature;
|
||||
|
||||
@@ -12,7 +12,12 @@ use std::{
|
||||
use crate::helpers::config::Config;
|
||||
use tauri_bundler::bundle::{PackageType, Settings, SettingsBuilder};
|
||||
|
||||
pub use rust::{Options, Rust as AppInterface};
|
||||
pub use rust::{MobileOptions, Options, Rust as AppInterface};
|
||||
|
||||
pub trait DevProcess {
|
||||
fn kill(&mut self) -> std::io::Result<()>;
|
||||
fn try_wait(&mut self) -> std::io::Result<Option<ExitStatus>>;
|
||||
}
|
||||
|
||||
pub trait AppSettings {
|
||||
fn get_package_settings(&self) -> tauri_bundler::PackageSettings;
|
||||
@@ -83,4 +88,9 @@ pub trait Interface: Sized {
|
||||
options: Options,
|
||||
on_exit: F,
|
||||
) -> crate::Result<()>;
|
||||
fn mobile_dev<R: Fn(MobileOptions) -> crate::Result<Box<dyn DevProcess>>>(
|
||||
&mut self,
|
||||
options: MobileOptions,
|
||||
runner: R,
|
||||
) -> crate::Result<()>;
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
ffi::OsStr,
|
||||
fs::{File, FileType},
|
||||
io::{Read, Write},
|
||||
@@ -10,7 +11,6 @@ use std::{
|
||||
process::ExitStatus,
|
||||
str::FromStr,
|
||||
sync::{
|
||||
atomic::{AtomicBool, Ordering},
|
||||
mpsc::{channel, sync_channel},
|
||||
Arc, Mutex,
|
||||
},
|
||||
@@ -24,13 +24,12 @@ use log::warn;
|
||||
use log::{debug, info};
|
||||
use notify::{watcher, DebouncedEvent, RecursiveMode, Watcher};
|
||||
use serde::Deserialize;
|
||||
use shared_child::SharedChild;
|
||||
use tauri_bundler::{
|
||||
AppCategory, BundleBinary, BundleSettings, DebianSettings, MacOsSettings, PackageSettings,
|
||||
UpdaterSettings, WindowsSettings,
|
||||
};
|
||||
|
||||
use super::{AppSettings, ExitReason, Interface};
|
||||
use super::{AppSettings, DevProcess, ExitReason, Interface};
|
||||
use crate::helpers::{
|
||||
app_paths::tauri_dir,
|
||||
config::{reload as reload_config, wix_settings, Config},
|
||||
@@ -40,7 +39,7 @@ mod desktop;
|
||||
mod manifest;
|
||||
use manifest::{rewrite_manifest, Manifest};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug, Default, Clone)]
|
||||
pub struct Options {
|
||||
pub runner: Option<String>,
|
||||
pub debug: bool,
|
||||
@@ -79,30 +78,13 @@ impl From<crate::dev::Options> for Options {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct DevChild {
|
||||
manually_killed_app: Arc<AtomicBool>,
|
||||
build_child: Arc<SharedChild>,
|
||||
app_child: Arc<Mutex<Option<Arc<SharedChild>>>>,
|
||||
}
|
||||
|
||||
impl DevChild {
|
||||
fn kill(&self) -> std::io::Result<()> {
|
||||
if let Some(child) = &*self.app_child.lock().unwrap() {
|
||||
child.kill()?;
|
||||
} else {
|
||||
self.build_child.kill()?;
|
||||
}
|
||||
self.manually_killed_app.store(true, Ordering::Relaxed);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn try_wait(&self) -> std::io::Result<Option<ExitStatus>> {
|
||||
if let Some(child) = &*self.app_child.lock().unwrap() {
|
||||
child.try_wait()
|
||||
} else {
|
||||
self.build_child.try_wait()
|
||||
}
|
||||
}
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct MobileOptions {
|
||||
pub debug: bool,
|
||||
pub features: Option<Vec<String>>,
|
||||
pub args: Vec<String>,
|
||||
pub config: Option<String>,
|
||||
pub no_watch: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
@@ -144,8 +126,10 @@ impl Interface for Rust {
|
||||
std::env::set_var("MACOSX_DEPLOYMENT_TARGET", minimum_system_version);
|
||||
}
|
||||
|
||||
let app_settings = RustAppSettings::new(config, manifest)?;
|
||||
|
||||
Ok(Self {
|
||||
app_settings: RustAppSettings::new(config, manifest)?,
|
||||
app_settings,
|
||||
config_features: config.build.features.clone().unwrap_or_default(),
|
||||
product_name: config.package.product_name.clone(),
|
||||
available_targets: None,
|
||||
@@ -173,28 +157,56 @@ impl Interface for Rust {
|
||||
|
||||
fn dev<F: Fn(ExitStatus, ExitReason) + Send + Sync + 'static>(
|
||||
&mut self,
|
||||
options: Options,
|
||||
mut options: Options,
|
||||
on_exit: F,
|
||||
) -> crate::Result<()> {
|
||||
let on_exit = Arc::new(on_exit);
|
||||
|
||||
let on_exit_ = on_exit.clone();
|
||||
let run_args = dev_options(
|
||||
&mut options.args,
|
||||
&mut options.features,
|
||||
self.app_settings.manifest.features(),
|
||||
);
|
||||
|
||||
if options.no_watch {
|
||||
let (tx, rx) = sync_channel(1);
|
||||
self.run_dev(options, move |status, reason| {
|
||||
self.run_dev(options, run_args, move |status, reason| {
|
||||
tx.send(()).unwrap();
|
||||
on_exit_(status, reason)
|
||||
on_exit(status, reason)
|
||||
})?;
|
||||
|
||||
rx.recv().unwrap();
|
||||
Ok(())
|
||||
} else {
|
||||
let child = self.run_dev(options.clone(), move |status, reason| {
|
||||
on_exit_(status, reason)
|
||||
})?;
|
||||
let config = options.config.clone();
|
||||
let run = Arc::new(|rust: &mut Rust| {
|
||||
let on_exit = on_exit.clone();
|
||||
rust.run_dev(options.clone(), run_args.clone(), move |status, reason| {
|
||||
on_exit(status, reason)
|
||||
})
|
||||
});
|
||||
self.run_dev_watcher(config, run)
|
||||
}
|
||||
}
|
||||
|
||||
self.run_dev_watcher(child, options, on_exit)
|
||||
fn mobile_dev<R: Fn(MobileOptions) -> crate::Result<Box<dyn DevProcess>>>(
|
||||
&mut self,
|
||||
mut options: MobileOptions,
|
||||
runner: R,
|
||||
) -> crate::Result<()> {
|
||||
dev_options(
|
||||
&mut options.args,
|
||||
&mut options.features,
|
||||
self.app_settings.manifest.features(),
|
||||
);
|
||||
|
||||
if options.no_watch {
|
||||
runner(options)?;
|
||||
Ok(())
|
||||
} else {
|
||||
let config = options.config.clone();
|
||||
let run = Arc::new(|_rust: &mut Rust| runner(options.clone()));
|
||||
self.run_dev_watcher(config, run)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -223,50 +235,54 @@ fn lookup<F: FnMut(FileType, PathBuf)>(dir: &Path, mut f: F) {
|
||||
}
|
||||
}
|
||||
|
||||
fn dev_options(
|
||||
args: &mut Vec<String>,
|
||||
features: &mut Option<Vec<String>>,
|
||||
manifest_features: HashMap<String, Vec<String>>,
|
||||
) -> Vec<String> {
|
||||
if !args.contains(&"--no-default-features".into()) {
|
||||
let enable_features: Vec<String> = manifest_features
|
||||
.get("default")
|
||||
.cloned()
|
||||
.unwrap_or_default()
|
||||
.into_iter()
|
||||
.filter(|feature| {
|
||||
if let Some(manifest_feature) = manifest_features.get(feature) {
|
||||
!manifest_feature.contains(&"tauri/custom-protocol".into())
|
||||
} else {
|
||||
feature != "tauri/custom-protocol"
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
args.push("--no-default-features".into());
|
||||
if !enable_features.is_empty() {
|
||||
features.get_or_insert(Vec::new()).extend(enable_features);
|
||||
}
|
||||
}
|
||||
|
||||
let mut dev_args = Vec::new();
|
||||
let mut run_args = Vec::new();
|
||||
let mut reached_run_args = false;
|
||||
for arg in args.clone() {
|
||||
if reached_run_args {
|
||||
run_args.push(arg);
|
||||
} else if arg == "--" {
|
||||
reached_run_args = true;
|
||||
} else {
|
||||
dev_args.push(arg);
|
||||
}
|
||||
}
|
||||
*args = dev_args;
|
||||
run_args
|
||||
}
|
||||
|
||||
impl Rust {
|
||||
fn run_dev<F: Fn(ExitStatus, ExitReason) + Send + Sync + 'static>(
|
||||
&mut self,
|
||||
mut options: Options,
|
||||
options: Options,
|
||||
run_args: Vec<String>,
|
||||
on_exit: F,
|
||||
) -> crate::Result<DevChild> {
|
||||
if !options.args.contains(&"--no-default-features".into()) {
|
||||
let manifest_features = self.app_settings.manifest.features();
|
||||
let enable_features: Vec<String> = manifest_features
|
||||
.get("default")
|
||||
.cloned()
|
||||
.unwrap_or_default()
|
||||
.into_iter()
|
||||
.filter(|feature| {
|
||||
if let Some(manifest_feature) = manifest_features.get(feature) {
|
||||
!manifest_feature.contains(&"tauri/custom-protocol".into())
|
||||
} else {
|
||||
feature != "tauri/custom-protocol"
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
options.args.push("--no-default-features".into());
|
||||
if !enable_features.is_empty() {
|
||||
options
|
||||
.features
|
||||
.get_or_insert(Vec::new())
|
||||
.extend(enable_features);
|
||||
}
|
||||
}
|
||||
|
||||
let mut args = Vec::new();
|
||||
let mut run_args = Vec::new();
|
||||
let mut reached_run_args = false;
|
||||
for arg in options.args.clone() {
|
||||
if reached_run_args {
|
||||
run_args.push(arg);
|
||||
} else if arg == "--" {
|
||||
reached_run_args = true;
|
||||
} else {
|
||||
args.push(arg);
|
||||
}
|
||||
}
|
||||
options.args = args;
|
||||
|
||||
) -> crate::Result<Box<dyn DevProcess>> {
|
||||
desktop::run_dev(
|
||||
options,
|
||||
run_args,
|
||||
@@ -276,14 +292,16 @@ impl Rust {
|
||||
self.product_name.clone(),
|
||||
on_exit,
|
||||
)
|
||||
.map(|c| Box::new(c) as Box<dyn DevProcess>)
|
||||
}
|
||||
|
||||
fn run_dev_watcher<F: Fn(ExitStatus, ExitReason) + Send + Sync + 'static>(
|
||||
fn run_dev_watcher<F: Fn(&mut Rust) -> crate::Result<Box<dyn DevProcess>>>(
|
||||
&mut self,
|
||||
child: DevChild,
|
||||
options: Options,
|
||||
on_exit: Arc<F>,
|
||||
config: Option<String>,
|
||||
run: Arc<F>,
|
||||
) -> crate::Result<()> {
|
||||
let child = run(self)?;
|
||||
|
||||
let process = Arc::new(Mutex::new(child));
|
||||
let (tx, rx) = channel();
|
||||
let tauri_path = tauri_dir();
|
||||
@@ -326,7 +344,7 @@ impl Rust {
|
||||
}
|
||||
|
||||
loop {
|
||||
let on_exit = on_exit.clone();
|
||||
let run = run.clone();
|
||||
if let Ok(event) = rx.recv() {
|
||||
let event_path = match event {
|
||||
DebouncedEvent::Create(path) => Some(path),
|
||||
@@ -338,7 +356,7 @@ impl Rust {
|
||||
|
||||
if let Some(event_path) = event_path {
|
||||
if event_path.file_name() == Some(OsStr::new("tauri.conf.json")) {
|
||||
let config = reload_config(options.config.as_deref())?;
|
||||
let config = reload_config(config.as_deref())?;
|
||||
self.app_settings.manifest =
|
||||
rewrite_manifest(config.lock().unwrap().as_ref().unwrap())?;
|
||||
} else {
|
||||
@@ -353,9 +371,7 @@ impl Rust {
|
||||
break;
|
||||
}
|
||||
}
|
||||
*p = self.run_dev(options.clone(), move |status, reason| {
|
||||
on_exit(status, reason)
|
||||
})?;
|
||||
*p = run(self)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
use super::{AppSettings, DevChild, ExitReason, Options, RustAppSettings, Target};
|
||||
use super::{AppSettings, DevProcess, ExitReason, Options, RustAppSettings, Target};
|
||||
use crate::CommandExt;
|
||||
|
||||
use anyhow::Context;
|
||||
#[cfg(target_os = "linux")]
|
||||
use heck::ToKebabCase;
|
||||
use shared_child::SharedChild;
|
||||
use std::{
|
||||
@@ -15,6 +16,34 @@ use std::{
|
||||
},
|
||||
};
|
||||
|
||||
pub struct DevChild {
|
||||
manually_killed_app: Arc<AtomicBool>,
|
||||
build_child: Option<Arc<SharedChild>>,
|
||||
app_child: Arc<Mutex<Option<Arc<SharedChild>>>>,
|
||||
}
|
||||
|
||||
impl DevProcess for DevChild {
|
||||
fn kill(&mut self) -> std::io::Result<()> {
|
||||
if let Some(child) = &*self.app_child.lock().unwrap() {
|
||||
child.kill()?;
|
||||
} else if let Some(child) = &self.build_child {
|
||||
child.kill()?;
|
||||
}
|
||||
self.manually_killed_app.store(true, Ordering::Relaxed);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn try_wait(&mut self) -> std::io::Result<Option<ExitStatus>> {
|
||||
if let Some(child) = &*self.app_child.lock().unwrap() {
|
||||
child.try_wait()
|
||||
} else if let Some(child) = &self.build_child {
|
||||
child.try_wait()
|
||||
} else {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn run_dev<F: Fn(ExitStatus, ExitReason) + Send + Sync + 'static>(
|
||||
options: Options,
|
||||
run_args: Vec<String>,
|
||||
@@ -23,7 +52,7 @@ pub fn run_dev<F: Fn(ExitStatus, ExitReason) + Send + Sync + 'static>(
|
||||
app_settings: &RustAppSettings,
|
||||
product_name: Option<String>,
|
||||
on_exit: F,
|
||||
) -> crate::Result<DevChild> {
|
||||
) -> crate::Result<impl DevProcess> {
|
||||
let bin_path = app_settings.app_binary_path(&options)?;
|
||||
|
||||
let manually_killed_app = Arc::new(AtomicBool::default());
|
||||
@@ -73,7 +102,7 @@ pub fn run_dev<F: Fn(ExitStatus, ExitReason) + Send + Sync + 'static>(
|
||||
|
||||
Ok(DevChild {
|
||||
manually_killed_app,
|
||||
build_child,
|
||||
build_child: Some(build_child),
|
||||
app_child,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ mod mobile;
|
||||
mod plugin;
|
||||
mod signer;
|
||||
|
||||
use clap::{FromArgMatches, IntoApp, Parser, Subcommand};
|
||||
use clap::{FromArgMatches, IntoApp, Parser, Subcommand, ValueEnum};
|
||||
use env_logger::fmt::Color;
|
||||
use env_logger::Builder;
|
||||
use log::{debug, log_enabled, Level};
|
||||
@@ -23,9 +23,33 @@ use std::io::{BufReader, Write};
|
||||
use std::process::{exit, Command, ExitStatus, Output, Stdio};
|
||||
use std::{
|
||||
ffi::OsString,
|
||||
fmt::Display,
|
||||
sync::{Arc, Mutex},
|
||||
};
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, ValueEnum)]
|
||||
pub enum RunMode {
|
||||
Desktop,
|
||||
#[cfg(target_os = "macos")]
|
||||
Ios,
|
||||
Android,
|
||||
}
|
||||
|
||||
impl Display for RunMode {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"{}",
|
||||
match self {
|
||||
Self::Desktop => "desktop",
|
||||
#[cfg(target_os = "macos")]
|
||||
Self::Ios => "iOS",
|
||||
Self::Android => "android",
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct VersionMetadata {
|
||||
tauri: String,
|
||||
|
||||
@@ -6,10 +6,11 @@ use cargo_mobile::{
|
||||
android::{
|
||||
adb,
|
||||
config::{Config as AndroidConfig, Metadata as AndroidMetadata},
|
||||
device::Device,
|
||||
device::{Device, RunError},
|
||||
env::{Env, Error as EnvError},
|
||||
target::{BuildError, Target},
|
||||
},
|
||||
config::Config,
|
||||
device::PromptError,
|
||||
opts::{NoiseLevel, Profile},
|
||||
os,
|
||||
@@ -19,12 +20,15 @@ use cargo_mobile::{
|
||||
use clap::{Parser, Subcommand};
|
||||
|
||||
use super::{
|
||||
ensure_init, get_config, get_metadata,
|
||||
ensure_init, get_config,
|
||||
init::{command as init_command, Options as InitOptions},
|
||||
Target as MobileTarget,
|
||||
write_options, CliOptions, DevChild, Target as MobileTarget,
|
||||
};
|
||||
use crate::{
|
||||
helpers::{config::get as get_tauri_config, flock},
|
||||
interface::{AppSettings, DevProcess, Interface, MobileOptions, Options as InterfaceOptions},
|
||||
Result,
|
||||
};
|
||||
use crate::helpers::config::get as get_tauri_config;
|
||||
use crate::Result;
|
||||
|
||||
pub(crate) mod project;
|
||||
|
||||
@@ -32,16 +36,24 @@ pub(crate) mod project;
|
||||
enum Error {
|
||||
#[error(transparent)]
|
||||
EnvInitFailed(EnvError),
|
||||
#[error(transparent)]
|
||||
InitDotCargo(super::init::Error),
|
||||
#[error("invalid tauri configuration: {0}")]
|
||||
InvalidTauriConfig(String),
|
||||
#[error("{0}")]
|
||||
ProjectNotInitialized(String),
|
||||
#[error(transparent)]
|
||||
OpenFailed(os::OpenFileError),
|
||||
#[error("{0}")]
|
||||
DevFailed(String),
|
||||
#[error(transparent)]
|
||||
BuildFailed(BuildError),
|
||||
#[error(transparent)]
|
||||
RunFailed(RunError),
|
||||
#[error("{0}")]
|
||||
TargetInvalid(String),
|
||||
#[error(transparent)]
|
||||
FailedToPromptForDevice(PromptError<adb::device_list::Error>),
|
||||
}
|
||||
|
||||
#[derive(Parser)]
|
||||
@@ -68,9 +80,44 @@ pub struct BuildOptions {
|
||||
value_parser(clap::builder::PossibleValuesParser::new(["aarch64", "armv7", "i686", "x86_64"]))
|
||||
)]
|
||||
targets: Option<Vec<String>>,
|
||||
/// Builds with the debug flag
|
||||
/// Builds with the release flag
|
||||
#[clap(short, long)]
|
||||
debug: bool,
|
||||
release: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Parser)]
|
||||
#[clap(about = "Android dev")]
|
||||
pub struct DevOptions {
|
||||
/// List of cargo features to activate
|
||||
#[clap(short, long, multiple_occurrences(true), multiple_values(true))]
|
||||
pub features: Option<Vec<String>>,
|
||||
/// Exit on panic
|
||||
#[clap(short, long)]
|
||||
exit_on_panic: bool,
|
||||
/// JSON string or path to JSON file to merge with tauri.conf.json
|
||||
#[clap(short, long)]
|
||||
pub config: Option<String>,
|
||||
/// Disable the file watcher
|
||||
#[clap(long)]
|
||||
pub no_watch: bool,
|
||||
/// Open Android Studio instead of trying to run on a connected device
|
||||
#[clap(short, long)]
|
||||
pub open: bool,
|
||||
}
|
||||
|
||||
impl From<DevOptions> for crate::dev::Options {
|
||||
fn from(options: DevOptions) -> Self {
|
||||
Self {
|
||||
runner: None,
|
||||
target: None,
|
||||
features: options.features,
|
||||
exit_on_panic: options.exit_on_panic,
|
||||
config: options.config,
|
||||
release_mode: false,
|
||||
args: Vec::new(),
|
||||
no_watch: options.no_watch,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Subcommand)]
|
||||
@@ -78,6 +125,7 @@ enum Commands {
|
||||
Init(InitOptions),
|
||||
/// Open project in Android Studio
|
||||
Open,
|
||||
Dev(DevOptions),
|
||||
#[clap(hide(true))]
|
||||
Build(BuildOptions),
|
||||
}
|
||||
@@ -87,76 +135,182 @@ pub fn command(cli: Cli) -> Result<()> {
|
||||
Commands::Init(options) => init_command(options, MobileTarget::Android)?,
|
||||
Commands::Open => open()?,
|
||||
Commands::Build(options) => build(options)?,
|
||||
Commands::Dev(options) => dev(options)?,
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn with_config(
|
||||
f: impl FnOnce(&AndroidConfig, &AndroidMetadata) -> Result<(), Error>,
|
||||
) -> Result<(), Error> {
|
||||
let tauri_config =
|
||||
get_tauri_config(None).map_err(|e| Error::InvalidTauriConfig(e.to_string()))?;
|
||||
let tauri_config_guard = tauri_config.lock().unwrap();
|
||||
let tauri_config_ = tauri_config_guard.as_ref().unwrap();
|
||||
let config = get_config(tauri_config_);
|
||||
let metadata = get_metadata(tauri_config_);
|
||||
f(config.android(), metadata.android())
|
||||
fn with_config<T>(
|
||||
f: impl FnOnce(&Config, &AndroidConfig, &AndroidMetadata) -> Result<T, Error>,
|
||||
) -> Result<T, Error> {
|
||||
let (config, metadata) = {
|
||||
let tauri_config =
|
||||
get_tauri_config(None).map_err(|e| Error::InvalidTauriConfig(e.to_string()))?;
|
||||
let tauri_config_guard = tauri_config.lock().unwrap();
|
||||
let tauri_config_ = tauri_config_guard.as_ref().unwrap();
|
||||
get_config(tauri_config_)
|
||||
};
|
||||
f(&config, config.android(), metadata.android())
|
||||
}
|
||||
|
||||
fn device_prompt<'a>(env: &'_ Env) -> Result<Device<'a>, PromptError<adb::device_list::Error>> {
|
||||
let device_list =
|
||||
adb::device_list(env).map_err(|cause| PromptError::detection_failed("Android", cause))?;
|
||||
if !device_list.is_empty() {
|
||||
let index = if device_list.len() > 1 {
|
||||
prompt::list(
|
||||
concat!("Detected ", "Android", " devices"),
|
||||
device_list.iter(),
|
||||
"device",
|
||||
None,
|
||||
"Device",
|
||||
)
|
||||
.map_err(|cause| PromptError::prompt_failed("Android", cause))?
|
||||
} else {
|
||||
0
|
||||
};
|
||||
let device = device_list.into_iter().nth(index).unwrap();
|
||||
println!(
|
||||
"Detected connected device: {} with target {:?}",
|
||||
device,
|
||||
device.target().triple,
|
||||
);
|
||||
Ok(device)
|
||||
} else {
|
||||
Err(PromptError::none_detected("Android"))
|
||||
}
|
||||
}
|
||||
|
||||
fn dev(options: DevOptions) -> Result<()> {
|
||||
with_config(|_, config, _metadata| {
|
||||
run_dev(options, config).map_err(|e| Error::DevFailed(e.to_string()))
|
||||
})
|
||||
.map_err(Into::into)
|
||||
}
|
||||
|
||||
fn run_dev(options: DevOptions, config: &AndroidConfig) -> Result<()> {
|
||||
let mut dev_options = options.clone().into();
|
||||
let mut interface = crate::dev::setup(&mut dev_options)?;
|
||||
|
||||
let bundle_identifier = {
|
||||
let tauri_config =
|
||||
get_tauri_config(None).map_err(|e| Error::InvalidTauriConfig(e.to_string()))?;
|
||||
let tauri_config_guard = tauri_config.lock().unwrap();
|
||||
let tauri_config_ = tauri_config_guard.as_ref().unwrap();
|
||||
tauri_config_.tauri.bundle.identifier.clone()
|
||||
};
|
||||
|
||||
let app_settings = interface.app_settings();
|
||||
let bin_path = app_settings.app_binary_path(&InterfaceOptions {
|
||||
debug: !dev_options.release_mode,
|
||||
..Default::default()
|
||||
})?;
|
||||
let out_dir = bin_path.parent().unwrap();
|
||||
let _lock = flock::open_rw(&out_dir.join("lock").with_extension("android"), "Android")?;
|
||||
|
||||
let open = options.open;
|
||||
interface.mobile_dev(
|
||||
MobileOptions {
|
||||
debug: true,
|
||||
features: options.features,
|
||||
args: Vec::new(),
|
||||
config: options.config,
|
||||
no_watch: options.no_watch,
|
||||
},
|
||||
|options| {
|
||||
let cli_options = CliOptions {
|
||||
features: options.features.clone(),
|
||||
args: options.args.clone(),
|
||||
vars: Default::default(),
|
||||
};
|
||||
write_options(cli_options, &bundle_identifier, MobileTarget::Android)?;
|
||||
|
||||
if open {
|
||||
open_dev(config)
|
||||
} else {
|
||||
match run(options) {
|
||||
Ok(c) => Ok(Box::new(c) as Box<dyn DevProcess>),
|
||||
Err(Error::FailedToPromptForDevice(e)) => {
|
||||
log::error!("{}", e);
|
||||
open_dev(config)
|
||||
}
|
||||
Err(e) => Err(e.into()),
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
fn open_dev(config: &AndroidConfig) -> ! {
|
||||
log::info!("Opening Android Studio");
|
||||
if let Err(e) = os::open_file_with("Android Studio", config.project_dir()) {
|
||||
log::error!("{}", e);
|
||||
}
|
||||
loop {
|
||||
std::thread::sleep(std::time::Duration::from_secs(24 * 60 * 60));
|
||||
}
|
||||
}
|
||||
|
||||
fn open() -> Result<()> {
|
||||
with_config(|config, _metadata| {
|
||||
with_config(|_, config, _metadata| {
|
||||
ensure_init(config.project_dir(), MobileTarget::Android)
|
||||
.map_err(|e| Error::ProjectNotInitialized(e.to_string()))?;
|
||||
os::open_file_with("Android Studio", config.project_dir()).map_err(Error::OpenFailed)
|
||||
})?;
|
||||
Ok(())
|
||||
})
|
||||
.map_err(Into::into)
|
||||
}
|
||||
|
||||
fn build(options: BuildOptions) -> Result<()> {
|
||||
fn run(options: MobileOptions) -> Result<DevChild, Error> {
|
||||
let profile = if options.debug {
|
||||
Profile::Debug
|
||||
} else {
|
||||
Profile::Release
|
||||
};
|
||||
|
||||
fn device_prompt<'a>(env: &'_ Env) -> Result<Device<'a>, PromptError<adb::device_list::Error>> {
|
||||
let device_list =
|
||||
adb::device_list(env).map_err(|cause| PromptError::detection_failed("Android", cause))?;
|
||||
if !device_list.is_empty() {
|
||||
let index = if device_list.len() > 1 {
|
||||
prompt::list(
|
||||
concat!("Detected ", "Android", " devices"),
|
||||
device_list.iter(),
|
||||
"device",
|
||||
None,
|
||||
"Device",
|
||||
)
|
||||
.map_err(|cause| PromptError::prompt_failed("Android", cause))?
|
||||
} else {
|
||||
0
|
||||
};
|
||||
let device = device_list.into_iter().nth(index).unwrap();
|
||||
println!(
|
||||
"Detected connected device: {} with target {:?}",
|
||||
device,
|
||||
device.target().triple,
|
||||
);
|
||||
Ok(device)
|
||||
} else {
|
||||
Err(PromptError::none_detected("Android"))
|
||||
}
|
||||
}
|
||||
with_config(|root_conf, config, metadata| {
|
||||
let build_app_bundle = metadata.asset_packs().is_some();
|
||||
|
||||
ensure_init(config.project_dir(), MobileTarget::Android)
|
||||
.map_err(|e| Error::ProjectNotInitialized(e.to_string()))?;
|
||||
|
||||
let env = Env::new().map_err(Error::EnvInitFailed)?;
|
||||
super::init::init_dot_cargo(root_conf, Some(&env)).map_err(Error::InitDotCargo)?;
|
||||
|
||||
device_prompt(&env)
|
||||
.map_err(Error::FailedToPromptForDevice)?
|
||||
.run(
|
||||
config,
|
||||
&env,
|
||||
NoiseLevel::Polite,
|
||||
profile,
|
||||
None,
|
||||
build_app_bundle,
|
||||
false,
|
||||
".MainActivity".into(),
|
||||
)
|
||||
.map_err(Error::RunFailed)
|
||||
})
|
||||
.map(|c| DevChild(Some(c)))
|
||||
}
|
||||
|
||||
fn build(options: BuildOptions) -> Result<()> {
|
||||
let profile = if options.release {
|
||||
Profile::Release
|
||||
} else {
|
||||
Profile::Debug
|
||||
};
|
||||
|
||||
fn detect_target_ok<'a>(env: &Env) -> Option<&'a Target<'a>> {
|
||||
device_prompt(env).map(|device| device.target()).ok()
|
||||
}
|
||||
|
||||
with_config(|config, metadata| {
|
||||
with_config(|root_conf, config, metadata| {
|
||||
ensure_init(config.project_dir(), MobileTarget::Android)
|
||||
.map_err(|e| Error::ProjectNotInitialized(e.to_string()))?;
|
||||
|
||||
let env = Env::new().map_err(Error::EnvInitFailed)?;
|
||||
super::init::init_dot_cargo(root_conf, Some(&env)).map_err(Error::InitDotCargo)?;
|
||||
|
||||
call_for_targets_with_fallback(
|
||||
options.targets.unwrap_or_default().iter(),
|
||||
@@ -164,18 +318,11 @@ fn build(options: BuildOptions) -> Result<()> {
|
||||
&env,
|
||||
|target: &Target| {
|
||||
target
|
||||
.build(
|
||||
config,
|
||||
metadata,
|
||||
&env,
|
||||
NoiseLevel::Polite,
|
||||
true.into(),
|
||||
profile,
|
||||
)
|
||||
.build(config, metadata, &env, NoiseLevel::Polite, true, profile)
|
||||
.map_err(Error::BuildFailed)
|
||||
},
|
||||
)
|
||||
.map_err(|e| Error::TargetInvalid(e.to_string()))?
|
||||
})?;
|
||||
Ok(())
|
||||
})
|
||||
.map_err(Into::into)
|
||||
}
|
||||
|
||||
@@ -6,11 +6,9 @@ use crate::helpers::template;
|
||||
use cargo_mobile::{
|
||||
android::{
|
||||
config::{Config, Metadata},
|
||||
env::Env,
|
||||
ndk,
|
||||
target::Target,
|
||||
},
|
||||
dot_cargo, os,
|
||||
bossy, os,
|
||||
target::TargetTrait as _,
|
||||
util::{
|
||||
self,
|
||||
@@ -42,8 +40,6 @@ pub enum Error {
|
||||
},
|
||||
#[error("failed to symlink asset directory")]
|
||||
AssetDirSymlinkFailed,
|
||||
#[error(transparent)]
|
||||
DotCargoGenFailed(ndk::MissingToolError),
|
||||
#[error("failed to copy {src} to {dest}: {cause}")]
|
||||
FileCopyFailed {
|
||||
src: PathBuf,
|
||||
@@ -57,10 +53,8 @@ pub enum Error {
|
||||
pub fn gen(
|
||||
config: &Config,
|
||||
metadata: &Metadata,
|
||||
env: &Env,
|
||||
(handlebars, mut map): (Handlebars, template::JsonMap),
|
||||
wrapper: &TextWrapper,
|
||||
dot_cargo: &mut dot_cargo::DotCargo,
|
||||
) -> Result<(), Error> {
|
||||
println!("Installing Android toolchains...");
|
||||
Target::install_all().map_err(Error::RustupFailed)?;
|
||||
@@ -138,7 +132,15 @@ pub fn gen(
|
||||
created_dirs.push(parent);
|
||||
}
|
||||
|
||||
fs::File::create(path)
|
||||
let mut options = fs::OpenOptions::new();
|
||||
|
||||
#[cfg(unix)]
|
||||
if path.file_name().unwrap() == OsStr::new("gradlew") {
|
||||
use std::os::unix::fs::OpenOptionsExt;
|
||||
options.mode(0o755);
|
||||
}
|
||||
|
||||
options.create_new(true).write(true).open(path)
|
||||
},
|
||||
)
|
||||
.map_err(|e| Error::TemplateProcessingFailed(e.to_string()))?;
|
||||
@@ -173,16 +175,5 @@ pub fn gen(
|
||||
os::ln::force_symlink_relative(config.app().asset_dir(), dest, ln::TargetStyle::Directory)
|
||||
.map_err(|_| Error::AssetDirSymlinkFailed)?;
|
||||
|
||||
{
|
||||
for target in Target::all().values() {
|
||||
dot_cargo.insert_target(
|
||||
target.triple.to_owned(),
|
||||
target
|
||||
.generate_cargo_config(config, env)
|
||||
.map_err(Error::DotCargoGenFailed)?,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -2,14 +2,16 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
use super::{get_config, get_metadata, Target};
|
||||
use crate::helpers::{app_paths::tauri_dir, config::get as get_tauri_config, template::JsonMap};
|
||||
use super::{get_config, Target};
|
||||
use crate::helpers::{config::get as get_tauri_config, template::JsonMap};
|
||||
use crate::Result;
|
||||
use cargo_mobile::{
|
||||
android,
|
||||
android::{self, env::Env as AndroidEnv, ndk, target::Target as AndroidTarget},
|
||||
bossy,
|
||||
config::Config,
|
||||
dot_cargo, opts,
|
||||
dot_cargo,
|
||||
os::code_command,
|
||||
target::TargetTrait as _,
|
||||
util::{
|
||||
self,
|
||||
cli::{Report, TextWrapper},
|
||||
@@ -18,12 +20,7 @@ use cargo_mobile::{
|
||||
use clap::Parser;
|
||||
use handlebars::{Context, Handlebars, Helper, HelperResult, Output, RenderContext, RenderError};
|
||||
|
||||
use std::{
|
||||
fs, io,
|
||||
path::{Path, PathBuf},
|
||||
};
|
||||
|
||||
use opts::{NonInteractive, OpenInEditor, ReinstallDeps, SkipDevTools};
|
||||
use std::{fs, io, path::PathBuf};
|
||||
|
||||
#[derive(Debug, Parser)]
|
||||
#[clap(about = "Initializes a Tauri Android project")]
|
||||
@@ -37,16 +34,7 @@ pub fn command(mut options: Options, target: Target) -> Result<()> {
|
||||
options.ci = options.ci || std::env::var("CI").is_ok();
|
||||
|
||||
let wrapper = TextWrapper::with_splitter(textwrap::termwidth(), textwrap::NoHyphenation);
|
||||
exec(
|
||||
target,
|
||||
&wrapper,
|
||||
options.ci.into(),
|
||||
SkipDevTools::Yes,
|
||||
ReinstallDeps::Yes,
|
||||
OpenInEditor::No,
|
||||
tauri_dir(),
|
||||
)
|
||||
.map_err(|e| anyhow::anyhow!("{:#}", e))?;
|
||||
exec(target, &wrapper, options.ci, true, true).map_err(|e| anyhow::anyhow!("{:#}", e))?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -64,6 +52,8 @@ pub enum Error {
|
||||
#[error(transparent)]
|
||||
DotCargoLoad(dot_cargo::LoadError),
|
||||
#[error(transparent)]
|
||||
DotCargoGenFailed(ndk::MissingToolError),
|
||||
#[error(transparent)]
|
||||
HostTargetTripleDetection(util::HostTargetTripleError),
|
||||
#[cfg(target_os = "macos")]
|
||||
#[error(transparent)]
|
||||
@@ -74,42 +64,9 @@ pub enum Error {
|
||||
AndroidInit(super::android::project::Error),
|
||||
#[error(transparent)]
|
||||
DotCargoWrite(dot_cargo::WriteError),
|
||||
#[error(transparent)]
|
||||
OpenInEditor(util::OpenInEditorError),
|
||||
}
|
||||
|
||||
pub fn exec(
|
||||
target: Target,
|
||||
wrapper: &TextWrapper,
|
||||
non_interactive: NonInteractive,
|
||||
skip_dev_tools: SkipDevTools,
|
||||
#[allow(unused_variables)] reinstall_deps: ReinstallDeps,
|
||||
open_in_editor: OpenInEditor,
|
||||
cwd: impl AsRef<Path>,
|
||||
) -> Result<Config, Error> {
|
||||
let cwd = cwd.as_ref();
|
||||
let tauri_config =
|
||||
get_tauri_config(None).map_err(|e| Error::InvalidTauriConfig(e.to_string()))?;
|
||||
let tauri_config_guard = tauri_config.lock().unwrap();
|
||||
let tauri_config_ = tauri_config_guard.as_ref().unwrap();
|
||||
|
||||
let config = get_config(tauri_config_);
|
||||
let metadata = get_metadata(tauri_config_);
|
||||
|
||||
let asset_dir = config.app().asset_dir();
|
||||
if !asset_dir.is_dir() {
|
||||
fs::create_dir_all(&asset_dir).map_err(|cause| Error::AssetDirCreation { asset_dir, cause })?;
|
||||
}
|
||||
if skip_dev_tools.no() && util::command_present("code").unwrap_or_default() {
|
||||
let mut command = code_command();
|
||||
command.add_args(&["--install-extension", "vadimcn.vscode-lldb"]);
|
||||
if non_interactive.yes() {
|
||||
command.add_arg("--force");
|
||||
}
|
||||
command
|
||||
.run_and_wait()
|
||||
.map_err(Error::LldbExtensionInstall)?;
|
||||
}
|
||||
pub fn init_dot_cargo(config: &Config, android_env: Option<&AndroidEnv>) -> Result<(), Error> {
|
||||
let mut dot_cargo = dot_cargo::DotCargo::load(config.app()).map_err(Error::DotCargoLoad)?;
|
||||
// Mysteriously, builds that don't specify `--target` seem to fight over
|
||||
// the build cache with builds that use `--target`! This means that
|
||||
@@ -124,6 +81,49 @@ pub fn exec(
|
||||
dot_cargo
|
||||
.set_default_target(util::host_target_triple().map_err(Error::HostTargetTripleDetection)?);
|
||||
|
||||
if let Some(env) = android_env {
|
||||
for target in AndroidTarget::all().values() {
|
||||
dot_cargo.insert_target(
|
||||
target.triple.to_owned(),
|
||||
target
|
||||
.generate_cargo_config(config.android(), env)
|
||||
.map_err(Error::DotCargoGenFailed)?,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
dot_cargo.write(config.app()).map_err(Error::DotCargoWrite)
|
||||
}
|
||||
|
||||
pub fn exec(
|
||||
target: Target,
|
||||
wrapper: &TextWrapper,
|
||||
non_interactive: bool,
|
||||
skip_dev_tools: bool,
|
||||
#[allow(unused_variables)] reinstall_deps: bool,
|
||||
) -> Result<Config, Error> {
|
||||
let tauri_config =
|
||||
get_tauri_config(None).map_err(|e| Error::InvalidTauriConfig(e.to_string()))?;
|
||||
let tauri_config_guard = tauri_config.lock().unwrap();
|
||||
let tauri_config_ = tauri_config_guard.as_ref().unwrap();
|
||||
|
||||
let (config, metadata) = get_config(tauri_config_);
|
||||
|
||||
let asset_dir = config.app().asset_dir();
|
||||
if !asset_dir.is_dir() {
|
||||
fs::create_dir_all(&asset_dir).map_err(|cause| Error::AssetDirCreation { asset_dir, cause })?;
|
||||
}
|
||||
if !skip_dev_tools && util::command_present("code").unwrap_or_default() {
|
||||
let mut command = code_command();
|
||||
command.add_args(&["--install-extension", "vadimcn.vscode-lldb"]);
|
||||
if non_interactive {
|
||||
command.add_arg("--force");
|
||||
}
|
||||
command
|
||||
.run_and_wait()
|
||||
.map_err(Error::LldbExtensionInstall)?;
|
||||
}
|
||||
|
||||
let (handlebars, mut map) = handlebars(&config);
|
||||
// TODO: make this a relative path
|
||||
map.insert(
|
||||
@@ -135,24 +135,26 @@ pub fn exec(
|
||||
);
|
||||
|
||||
// Generate Android Studio project
|
||||
if target == Target::Android {
|
||||
match android::env::Env::new() {
|
||||
Ok(env) => super::android::project::gen(
|
||||
config.android(),
|
||||
metadata.android(),
|
||||
&env,
|
||||
(handlebars, map),
|
||||
wrapper,
|
||||
&mut dot_cargo,
|
||||
)
|
||||
.map_err(Error::AndroidInit)?,
|
||||
let android_env = if target == Target::Android {
|
||||
match AndroidEnv::new() {
|
||||
Ok(env) => {
|
||||
super::android::project::gen(
|
||||
config.android(),
|
||||
metadata.android(),
|
||||
(handlebars, map),
|
||||
wrapper,
|
||||
)
|
||||
.map_err(Error::AndroidInit)?;
|
||||
Some(env)
|
||||
}
|
||||
Err(err) => {
|
||||
if err.sdk_or_ndk_issue() {
|
||||
Report::action_request(
|
||||
" to initialize Android environment; Android support won't be usable until you fix the issue below and re-run `cargo mobile init`!",
|
||||
" to initialize Android environment; Android support won't be usable until you fix the issue below and re-run `tauri android init`!",
|
||||
err,
|
||||
)
|
||||
.print(wrapper);
|
||||
None
|
||||
} else {
|
||||
return Err(Error::AndroidEnv(err));
|
||||
}
|
||||
@@ -173,20 +175,16 @@ pub fn exec(
|
||||
)
|
||||
.map_err(Error::IosInit)?;
|
||||
}
|
||||
}
|
||||
None
|
||||
};
|
||||
|
||||
dot_cargo
|
||||
.write(config.app())
|
||||
.map_err(Error::DotCargoWrite)?;
|
||||
init_dot_cargo(&config, android_env.as_ref())?;
|
||||
|
||||
Report::victory(
|
||||
"Project generated successfully!",
|
||||
"Make cool apps! 🌻 🐕 🎉",
|
||||
)
|
||||
.print(wrapper);
|
||||
if open_in_editor.yes() {
|
||||
util::open_in_editor(cwd).map_err(Error::OpenInEditor)?;
|
||||
}
|
||||
Ok(config)
|
||||
}
|
||||
|
||||
|
||||
@@ -2,24 +2,33 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
use crate::helpers::config::get as get_tauri_config;
|
||||
use cargo_mobile::{
|
||||
apple::{
|
||||
config::{Config as AppleConfig, Metadata as AppleMetadata},
|
||||
device::{Device, RunError},
|
||||
ios_deploy,
|
||||
target::{CompileLibError, Target},
|
||||
},
|
||||
config::Config,
|
||||
device::PromptError,
|
||||
env::{Env, Error as EnvError},
|
||||
opts::{NoiseLevel, Profile},
|
||||
os, util,
|
||||
util::prompt,
|
||||
};
|
||||
use clap::{Parser, Subcommand};
|
||||
|
||||
use super::{
|
||||
ensure_init, get_config, get_metadata,
|
||||
ensure_init, env_vars, get_config,
|
||||
init::{command as init_command, Options as InitOptions},
|
||||
Target as MobileTarget,
|
||||
write_options, CliOptions, DevChild, Target as MobileTarget,
|
||||
};
|
||||
use crate::Result;
|
||||
use crate::{
|
||||
helpers::{config::get as get_tauri_config, flock},
|
||||
interface::{AppSettings, DevProcess, Interface, MobileOptions, Options as InterfaceOptions},
|
||||
Result,
|
||||
};
|
||||
|
||||
use std::{collections::HashMap, ffi::OsStr, path::PathBuf};
|
||||
|
||||
pub(crate) mod project;
|
||||
@@ -28,12 +37,16 @@ pub(crate) mod project;
|
||||
enum Error {
|
||||
#[error(transparent)]
|
||||
EnvInitFailed(EnvError),
|
||||
#[error(transparent)]
|
||||
InitDotCargo(super::init::Error),
|
||||
#[error("invalid tauri configuration: {0}")]
|
||||
InvalidTauriConfig(String),
|
||||
#[error("{0}")]
|
||||
ProjectNotInitialized(String),
|
||||
#[error(transparent)]
|
||||
OpenFailed(os::OpenFileError),
|
||||
#[error("{0}")]
|
||||
DevFailed(String),
|
||||
#[error(transparent)]
|
||||
NoHomeDir(util::NoHomeDir),
|
||||
#[error("SDK root provided by Xcode was invalid. {sdk_root} doesn't exist or isn't a directory")]
|
||||
@@ -46,6 +59,10 @@ enum Error {
|
||||
ArchInvalid { arch: String },
|
||||
#[error(transparent)]
|
||||
CompileLibFailed(CompileLibError),
|
||||
#[error(transparent)]
|
||||
FailedToPromptForDevice(PromptError<ios_deploy::DeviceListError>),
|
||||
#[error(transparent)]
|
||||
RunFailed(RunError),
|
||||
}
|
||||
|
||||
#[derive(Parser)]
|
||||
@@ -80,10 +97,49 @@ pub struct XcodeScriptOptions {
|
||||
arches: Vec<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Parser)]
|
||||
#[clap(about = "iOS dev")]
|
||||
pub struct DevOptions {
|
||||
/// List of cargo features to activate
|
||||
#[clap(short, long, multiple_occurrences(true), multiple_values(true))]
|
||||
pub features: Option<Vec<String>>,
|
||||
/// Exit on panic
|
||||
#[clap(short, long)]
|
||||
exit_on_panic: bool,
|
||||
/// JSON string or path to JSON file to merge with tauri.conf.json
|
||||
#[clap(short, long)]
|
||||
pub config: Option<String>,
|
||||
/// Run the code in release mode
|
||||
#[clap(long = "release")]
|
||||
pub release_mode: bool,
|
||||
/// Disable the file watcher
|
||||
#[clap(long)]
|
||||
pub no_watch: bool,
|
||||
/// Open Xcode instead of trying to run on a connected device
|
||||
#[clap(short, long)]
|
||||
pub open: bool,
|
||||
}
|
||||
|
||||
impl From<DevOptions> for crate::dev::Options {
|
||||
fn from(options: DevOptions) -> Self {
|
||||
Self {
|
||||
runner: None,
|
||||
target: None,
|
||||
features: options.features,
|
||||
exit_on_panic: options.exit_on_panic,
|
||||
config: options.config,
|
||||
release_mode: options.release_mode,
|
||||
args: Vec::new(),
|
||||
no_watch: options.no_watch,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Subcommand)]
|
||||
enum Commands {
|
||||
Init(InitOptions),
|
||||
Open,
|
||||
Dev(DevOptions),
|
||||
#[clap(hide(true))]
|
||||
XcodeScript(XcodeScriptOptions),
|
||||
}
|
||||
@@ -92,31 +148,159 @@ pub fn command(cli: Cli) -> Result<()> {
|
||||
match cli.command {
|
||||
Commands::Init(options) => init_command(options, MobileTarget::Ios)?,
|
||||
Commands::Open => open()?,
|
||||
Commands::Dev(options) => dev(options)?,
|
||||
Commands::XcodeScript(options) => xcode_script(options)?,
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn with_config(
|
||||
f: impl FnOnce(&AppleConfig, &AppleMetadata) -> Result<(), Error>,
|
||||
) -> Result<(), Error> {
|
||||
let tauri_config =
|
||||
get_tauri_config(None).map_err(|e| Error::InvalidTauriConfig(e.to_string()))?;
|
||||
let tauri_config_guard = tauri_config.lock().unwrap();
|
||||
let tauri_config_ = tauri_config_guard.as_ref().unwrap();
|
||||
let config = get_config(tauri_config_);
|
||||
let metadata = get_metadata(tauri_config_);
|
||||
f(config.apple(), metadata.apple())
|
||||
fn with_config<T>(
|
||||
f: impl FnOnce(&Config, &AppleConfig, &AppleMetadata) -> Result<T, Error>,
|
||||
) -> Result<T, Error> {
|
||||
let (config, metadata) = {
|
||||
let tauri_config =
|
||||
get_tauri_config(None).map_err(|e| Error::InvalidTauriConfig(e.to_string()))?;
|
||||
let tauri_config_guard = tauri_config.lock().unwrap();
|
||||
let tauri_config_ = tauri_config_guard.as_ref().unwrap();
|
||||
get_config(tauri_config_)
|
||||
};
|
||||
f(&config, config.apple(), metadata.apple())
|
||||
}
|
||||
|
||||
fn env() -> Result<Env, Error> {
|
||||
let env = Env::new()
|
||||
.map_err(Error::EnvInitFailed)?
|
||||
.explicit_env_vars(env_vars());
|
||||
Ok(env)
|
||||
}
|
||||
|
||||
fn device_prompt<'a>(env: &'_ Env) -> 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))?
|
||||
} else {
|
||||
0
|
||||
};
|
||||
let device = device_list.into_iter().nth(index).unwrap();
|
||||
println!(
|
||||
"Detected connected device: {} with target {:?}",
|
||||
device,
|
||||
device.target().triple,
|
||||
);
|
||||
Ok(device)
|
||||
} else {
|
||||
Err(PromptError::none_detected("iOS"))
|
||||
}
|
||||
}
|
||||
|
||||
fn dev(options: DevOptions) -> Result<()> {
|
||||
with_config(|_, config, _metadata| {
|
||||
run_dev(options, config).map_err(|e| Error::DevFailed(e.to_string()))
|
||||
})
|
||||
.map_err(Into::into)
|
||||
}
|
||||
|
||||
fn run_dev(options: DevOptions, config: &AppleConfig) -> Result<()> {
|
||||
let mut dev_options = options.clone().into();
|
||||
let mut interface = crate::dev::setup(&mut dev_options)?;
|
||||
|
||||
let bundle_identifier = {
|
||||
let tauri_config =
|
||||
get_tauri_config(None).map_err(|e| Error::InvalidTauriConfig(e.to_string()))?;
|
||||
let tauri_config_guard = tauri_config.lock().unwrap();
|
||||
let tauri_config_ = tauri_config_guard.as_ref().unwrap();
|
||||
tauri_config_.tauri.bundle.identifier.clone()
|
||||
};
|
||||
|
||||
let app_settings = interface.app_settings();
|
||||
let bin_path = app_settings.app_binary_path(&InterfaceOptions {
|
||||
debug: !dev_options.release_mode,
|
||||
..Default::default()
|
||||
})?;
|
||||
let out_dir = bin_path.parent().unwrap();
|
||||
let _lock = flock::open_rw(&out_dir.join("lock").with_extension("ios"), "iOS")?;
|
||||
|
||||
let open = options.open;
|
||||
interface.mobile_dev(
|
||||
MobileOptions {
|
||||
debug: true,
|
||||
features: options.features,
|
||||
args: Vec::new(),
|
||||
config: options.config,
|
||||
no_watch: options.no_watch,
|
||||
},
|
||||
|options| {
|
||||
let cli_options = CliOptions {
|
||||
features: options.features.clone(),
|
||||
args: options.args.clone(),
|
||||
vars: Default::default(),
|
||||
};
|
||||
write_options(cli_options, &bundle_identifier, MobileTarget::Ios)?;
|
||||
if open {
|
||||
open_dev(config)
|
||||
} else {
|
||||
match run(options) {
|
||||
Ok(c) => Ok(Box::new(c) as Box<dyn DevProcess>),
|
||||
Err(Error::FailedToPromptForDevice(e)) => {
|
||||
log::error!("{}", e);
|
||||
open_dev(config)
|
||||
}
|
||||
Err(e) => Err(e.into()),
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
fn open_dev(config: &AppleConfig) -> ! {
|
||||
log::info!("Opening Xcode");
|
||||
if let Err(e) = os::open_file_with("Xcode", config.project_dir()) {
|
||||
log::error!("{}", e);
|
||||
}
|
||||
loop {
|
||||
std::thread::sleep(std::time::Duration::from_secs(24 * 60 * 60));
|
||||
}
|
||||
}
|
||||
|
||||
fn open() -> Result<()> {
|
||||
with_config(|config, _metadata| {
|
||||
with_config(|_, config, _metadata| {
|
||||
ensure_init(config.project_dir(), MobileTarget::Ios)
|
||||
.map_err(|e| Error::ProjectNotInitialized(e.to_string()))?;
|
||||
os::open_file_with("Xcode", config.project_dir()).map_err(Error::OpenFailed)
|
||||
})?;
|
||||
Ok(())
|
||||
})
|
||||
.map_err(Into::into)
|
||||
}
|
||||
|
||||
fn run(options: MobileOptions) -> Result<DevChild, Error> {
|
||||
let profile = if options.debug {
|
||||
Profile::Debug
|
||||
} else {
|
||||
Profile::Release
|
||||
};
|
||||
|
||||
with_config(|root_conf, config, _| {
|
||||
ensure_init(config.project_dir(), MobileTarget::Ios)
|
||||
.map_err(|e| Error::ProjectNotInitialized(e.to_string()))?;
|
||||
|
||||
let env = env()?;
|
||||
super::init::init_dot_cargo(root_conf, None).map_err(Error::InitDotCargo)?;
|
||||
|
||||
device_prompt(&env)
|
||||
.map_err(Error::FailedToPromptForDevice)?
|
||||
.run(config, &env, NoiseLevel::Polite, false, profile)
|
||||
.map_err(Error::RunFailed)
|
||||
})
|
||||
.map(|c| DevChild(Some(c)))
|
||||
}
|
||||
|
||||
fn xcode_script(options: XcodeScriptOptions) -> Result<()> {
|
||||
@@ -135,8 +319,9 @@ fn xcode_script(options: XcodeScriptOptions) -> Result<()> {
|
||||
let profile = profile_from_configuration(&options.configuration);
|
||||
let macos = macos_from_platform(&options.platform);
|
||||
|
||||
with_config(|config, metadata| {
|
||||
let env = Env::new().map_err(Error::EnvInitFailed)?;
|
||||
with_config(|root_conf, config, metadata| {
|
||||
let env = env()?;
|
||||
super::init::init_dot_cargo(root_conf, None).map_err(Error::InitDotCargo)?;
|
||||
// The `PATH` env var Xcode gives us is missing any additions
|
||||
// made by the user's profile, so we'll manually add cargo's
|
||||
// `PATH`.
|
||||
@@ -216,7 +401,7 @@ fn xcode_script(options: XcodeScriptOptions) -> Result<()> {
|
||||
config,
|
||||
metadata,
|
||||
NoiseLevel::Polite,
|
||||
true.into(),
|
||||
true,
|
||||
profile,
|
||||
&env,
|
||||
target_env,
|
||||
@@ -224,7 +409,6 @@ fn xcode_script(options: XcodeScriptOptions) -> Result<()> {
|
||||
.map_err(Error::CompileLibFailed)?;
|
||||
}
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
Ok(())
|
||||
})
|
||||
.map_err(Into::into)
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ use cargo_mobile::{
|
||||
deps, rust_version_check,
|
||||
target::Target,
|
||||
},
|
||||
opts,
|
||||
bossy,
|
||||
target::TargetTrait as _,
|
||||
util::{self, cli::TextWrapper, ln},
|
||||
};
|
||||
@@ -53,9 +53,9 @@ pub fn gen(
|
||||
metadata: &Metadata,
|
||||
(handlebars, mut map): (Handlebars, template::JsonMap),
|
||||
wrapper: &TextWrapper,
|
||||
non_interactive: opts::NonInteractive,
|
||||
skip_dev_tools: opts::SkipDevTools,
|
||||
reinstall_deps: opts::ReinstallDeps,
|
||||
non_interactive: bool,
|
||||
skip_dev_tools: bool,
|
||||
reinstall_deps: bool,
|
||||
) -> Result<(), Error> {
|
||||
println!("Installing iOS toolchains...");
|
||||
Target::install_all().map_err(Error::Rustup)?;
|
||||
|
||||
@@ -2,7 +2,10 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
use crate::helpers::{app_paths::tauri_dir, config::Config as TauriConfig};
|
||||
use crate::{
|
||||
helpers::{app_paths::tauri_dir, config::Config as TauriConfig},
|
||||
interface::DevProcess,
|
||||
};
|
||||
use anyhow::{bail, Result};
|
||||
#[cfg(target_os = "macos")]
|
||||
use cargo_mobile::apple::config::{
|
||||
@@ -10,15 +13,48 @@ use cargo_mobile::apple::config::{
|
||||
};
|
||||
use cargo_mobile::{
|
||||
android::config::{Metadata as AndroidMetadata, Raw as RawAndroidConfig},
|
||||
bossy,
|
||||
config::{app::Raw as RawAppConfig, metadata::Metadata, Config, Raw},
|
||||
};
|
||||
use std::path::PathBuf;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::{collections::HashMap, ffi::OsString, path::PathBuf, process::ExitStatus};
|
||||
|
||||
pub mod android;
|
||||
mod init;
|
||||
#[cfg(target_os = "macos")]
|
||||
pub mod ios;
|
||||
|
||||
pub struct DevChild(Option<bossy::Handle>);
|
||||
|
||||
impl Drop for DevChild {
|
||||
fn drop(&mut self) {
|
||||
// consume the handle since we're not waiting on it
|
||||
// just to prevent a log error
|
||||
// note that this doesn't leak any memory
|
||||
self.0.take().unwrap().leak();
|
||||
}
|
||||
}
|
||||
|
||||
impl DevProcess for DevChild {
|
||||
fn kill(&mut self) -> std::io::Result<()> {
|
||||
self
|
||||
.0
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.kill()
|
||||
.map_err(|_| std::io::Error::new(std::io::ErrorKind::Other, "failed to kill"))
|
||||
}
|
||||
|
||||
fn try_wait(&mut self) -> std::io::Result<Option<ExitStatus>> {
|
||||
self
|
||||
.0
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.try_wait()
|
||||
.map_err(|_| std::io::Error::new(std::io::ErrorKind::Other, "failed to wait"))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq)]
|
||||
pub enum Target {
|
||||
Android,
|
||||
@@ -44,13 +80,113 @@ impl Target {
|
||||
}
|
||||
}
|
||||
|
||||
fn get_metadata(_config: &TauriConfig) -> Metadata {
|
||||
Metadata {
|
||||
#[derive(Debug, Default, Serialize, Deserialize)]
|
||||
pub struct CliOptions {
|
||||
pub features: Option<Vec<String>>,
|
||||
pub args: Vec<String>,
|
||||
pub vars: HashMap<String, OsString>,
|
||||
}
|
||||
|
||||
fn options_path(bundle_identifier: &str, target: Target) -> PathBuf {
|
||||
let out_dir = dirs_next::cache_dir()
|
||||
.or_else(dirs_next::home_dir)
|
||||
.unwrap_or_else(std::env::temp_dir);
|
||||
let out_dir = out_dir.join(".tauri").join(bundle_identifier);
|
||||
let _ = std::fs::create_dir_all(&out_dir);
|
||||
out_dir
|
||||
.join("cli-options")
|
||||
.with_extension(target.command_name())
|
||||
}
|
||||
|
||||
fn env_vars() -> HashMap<String, OsString> {
|
||||
let mut vars = HashMap::new();
|
||||
for (k, v) in std::env::vars_os() {
|
||||
let k = k.to_string_lossy();
|
||||
if k.starts_with("TAURI") && k != "TAURI_PRIVATE_KEY" && k != "TAURI_KEY_PASSWORD" {
|
||||
vars.insert(k.into_owned(), v);
|
||||
}
|
||||
}
|
||||
vars
|
||||
}
|
||||
|
||||
/// Writes CLI options to be used later on the Xcode and Android Studio build commands
|
||||
pub fn write_options(
|
||||
mut options: CliOptions,
|
||||
bundle_identifier: &str,
|
||||
target: Target,
|
||||
) -> crate::Result<()> {
|
||||
options.vars.extend(env_vars());
|
||||
std::fs::write(
|
||||
options_path(bundle_identifier, target),
|
||||
&serde_json::to_string(&options)?,
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn read_options(config: &TauriConfig, target: Target) -> crate::Result<CliOptions> {
|
||||
let data = std::fs::read_to_string(options_path(&config.tauri.bundle.identifier, target))?;
|
||||
let options = serde_json::from_str(&data)?;
|
||||
Ok(options)
|
||||
}
|
||||
|
||||
fn get_config(config: &TauriConfig) -> (Config, Metadata) {
|
||||
let mut s = config.tauri.bundle.identifier.rsplit('.');
|
||||
let app_name = s.next().unwrap_or("app").to_string();
|
||||
let mut domain = String::new();
|
||||
for w in s {
|
||||
domain.push_str(w);
|
||||
domain.push('.');
|
||||
}
|
||||
domain.pop();
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
let ios_options = read_options(config, Target::Ios).unwrap_or_default();
|
||||
let android_options = read_options(config, Target::Android).unwrap_or_default();
|
||||
|
||||
let raw = Raw {
|
||||
app: RawAppConfig {
|
||||
name: app_name,
|
||||
stylized_name: config.package.product_name.clone(),
|
||||
domain,
|
||||
asset_dir: None,
|
||||
template_pack: None,
|
||||
},
|
||||
#[cfg(target_os = "macos")]
|
||||
apple: Some(RawAppleConfig {
|
||||
development_team: std::env::var("TAURI_APPLE_DEVELOPMENT_TEAM")
|
||||
.ok()
|
||||
.or_else(|| config.tauri.ios.development_team.clone())
|
||||
.expect("you must set `tauri > iOS > developmentTeam` config value or the `TAURI_APPLE_DEVELOPMENT_TEAM` environment variable"),
|
||||
project_dir: None,
|
||||
ios_no_default_features: None,
|
||||
ios_features: ios_options.features.clone(),
|
||||
macos_no_default_features: None,
|
||||
macos_features: None,
|
||||
bundle_version: None,
|
||||
bundle_version_short: None,
|
||||
ios_version: None,
|
||||
macos_version: None,
|
||||
use_legacy_build_system: None,
|
||||
plist_pairs: None,
|
||||
}),
|
||||
android: Some(RawAndroidConfig {
|
||||
min_sdk_version: None,
|
||||
vulkan_validation: None,
|
||||
project_dir: None,
|
||||
no_default_features: None,
|
||||
features: android_options.features.clone(),
|
||||
}),
|
||||
};
|
||||
let config = Config::from_raw(tauri_dir(), raw).unwrap();
|
||||
|
||||
let metadata = Metadata {
|
||||
#[cfg(target_os = "macos")]
|
||||
apple: AppleMetadata {
|
||||
supported: true,
|
||||
ios: ApplePlatform {
|
||||
features: None,
|
||||
no_default_features: false,
|
||||
cargo_args: Some(ios_options.args),
|
||||
features: ios_options.features,
|
||||
frameworks: None,
|
||||
valid_archs: None,
|
||||
vendor_frameworks: None,
|
||||
@@ -67,7 +203,9 @@ fn get_metadata(_config: &TauriConfig) -> Metadata {
|
||||
},
|
||||
android: AndroidMetadata {
|
||||
supported: true,
|
||||
features: None,
|
||||
no_default_features: false,
|
||||
cargo_args: Some(android_options.args),
|
||||
features: android_options.features,
|
||||
app_sources: None,
|
||||
app_plugins: None,
|
||||
project_dependencies: None,
|
||||
@@ -75,53 +213,9 @@ fn get_metadata(_config: &TauriConfig) -> Metadata {
|
||||
app_dependencies_platform: None,
|
||||
asset_packs: None,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn get_config(config: &TauriConfig) -> Config {
|
||||
let mut s = config.tauri.bundle.identifier.rsplit('.');
|
||||
let app_name = s.next().unwrap_or("app").to_string();
|
||||
let mut domain = String::new();
|
||||
for w in s {
|
||||
domain.push_str(w);
|
||||
domain.push('.');
|
||||
}
|
||||
domain.pop();
|
||||
let raw = Raw {
|
||||
app: RawAppConfig {
|
||||
name: app_name,
|
||||
stylized_name: config.package.product_name.clone(),
|
||||
domain,
|
||||
asset_dir: None,
|
||||
template_pack: None,
|
||||
},
|
||||
#[cfg(target_os = "macos")]
|
||||
apple: Some(RawAppleConfig {
|
||||
development_team: std::env::var("APPLE_DEVELOPMENT_TEAM")
|
||||
.ok()
|
||||
.or_else(|| config.tauri.ios.development_team.clone())
|
||||
.expect("you must set `tauri > iOS > developmentTeam` config value or the `APPLE_DEVELOPMENT_TEAM` environment variable"),
|
||||
project_dir: None,
|
||||
ios_no_default_features: None,
|
||||
ios_features: None,
|
||||
macos_no_default_features: None,
|
||||
macos_features: None,
|
||||
bundle_version: None,
|
||||
bundle_version_short: None,
|
||||
ios_version: None,
|
||||
macos_version: None,
|
||||
use_legacy_build_system: None,
|
||||
plist_pairs: None,
|
||||
}),
|
||||
android: Some(RawAndroidConfig {
|
||||
min_sdk_version: None,
|
||||
vulkan_validation: None,
|
||||
project_dir: None,
|
||||
no_default_features: None,
|
||||
features: None,
|
||||
}),
|
||||
};
|
||||
Config::from_raw(tauri_dir(), raw).unwrap()
|
||||
|
||||
(config, metadata)
|
||||
}
|
||||
|
||||
fn ensure_init(project_dir: PathBuf, target: Target) -> Result<()> {
|
||||
|
||||
@@ -40,6 +40,16 @@ android {
|
||||
}
|
||||
flavorDimensions.add("abi")
|
||||
productFlavors {
|
||||
create("universal") {
|
||||
dimension = "abi"
|
||||
ndk {
|
||||
abiFilters += listOf(
|
||||
{{~#each targets}}
|
||||
"{{this.abi}}",{{/each}}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
{{~#each targets}}
|
||||
|
||||
create("{{this.arch}}") {
|
||||
@@ -75,7 +85,9 @@ dependencies {
|
||||
|
||||
afterEvaluate {
|
||||
android.applicationVariants.all {
|
||||
productFlavors.forEach { _ ->
|
||||
tasks["mergeUniversalReleaseJniLibFolders"].dependsOn(tasks["rustBuildRelease"])
|
||||
tasks["mergeUniversalDebugJniLibFolders"].dependsOn(tasks["rustBuildDebug"])
|
||||
productFlavors.filter{ it.name != "universal" }.forEach { _ ->
|
||||
val archAndBuildType = name.capitalize()
|
||||
tasks["merge${archAndBuildType}JniLibFolders"].dependsOn(tasks["rustBuild${archAndBuildType}"])
|
||||
}
|
||||
|
||||
@@ -3,11 +3,8 @@
|
||||
package="{{reverse-domain app.domain}}.{{snake-case app.name}}">
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<application
|
||||
android:allowBackup="true"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:label="@string/app_name"
|
||||
android:roundIcon="@mipmap/ic_launcher_round"
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/Theme.{{snake-case app.name}}">
|
||||
<activity
|
||||
android:name=".MainActivity"
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
package {{reverse-domain app.domain}}.{{snake-case app.name}}
|
||||
|
||||
class MainActivity : TauriActivity() {}
|
||||
class MainActivity : TauriActivity()
|
||||
|
||||
@@ -10,7 +10,7 @@ class RustWebChromeClient: WebChromeClient() {
|
||||
if (url.endsWith("##")) {
|
||||
url = url.dropLast(2)
|
||||
}
|
||||
if (loadedUrl != url) {
|
||||
if (loadedUrl != url && progress >= 20) {
|
||||
loadedUrl = url
|
||||
runInitializationScripts()
|
||||
}
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@drawable/ic_launcher_background" />
|
||||
<foreground android:drawable="@drawable/ic_launcher_foreground" />
|
||||
</adaptive-icon>
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 2.8 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 1.7 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 3.8 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 5.8 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 7.6 KiB |
@@ -1,3 +1,3 @@
|
||||
<resources>
|
||||
<string name="app_name">qoo</string>
|
||||
<string name="app_name">{{app.stylized-name}}</string>
|
||||
</resources>
|
||||
@@ -2,10 +2,6 @@ plugins {
|
||||
`kotlin-dsl`
|
||||
}
|
||||
|
||||
kotlinDslPluginOptions {
|
||||
experimentalWarning.set(false)
|
||||
}
|
||||
|
||||
gradlePlugin {
|
||||
plugins {
|
||||
create("pluginsForCoolKids") {
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
package {{reverse-domain app.domain}}
|
||||
|
||||
import com.android.build.gradle.*
|
||||
import java.io.File
|
||||
import org.gradle.api.DefaultTask
|
||||
import org.gradle.api.GradleException
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.logging.LogLevel
|
||||
import org.gradle.api.tasks.Input
|
||||
import org.gradle.api.tasks.InputDirectory
|
||||
@@ -23,20 +21,11 @@ open class BuildTask : DefaultTask() {
|
||||
|
||||
@TaskAction
|
||||
fun build() {
|
||||
val rootDirRel = rootDirRel
|
||||
if (rootDirRel == null) {
|
||||
throw GradleException("rootDirRel cannot be null")
|
||||
}
|
||||
val target = target
|
||||
if (target == null) {
|
||||
throw GradleException("target cannot be null")
|
||||
}
|
||||
val release = release
|
||||
if (release == null) {
|
||||
throw GradleException("release cannot be null")
|
||||
}
|
||||
val rootDirRel = rootDirRel ?: throw GradleException("rootDirRel cannot be null")
|
||||
val target = target ?: throw GradleException("target cannot be null")
|
||||
val release = release ?: throw GradleException("release cannot be null")
|
||||
project.exec {
|
||||
workingDir(File(project.getProjectDir(), rootDirRel.getPath()))
|
||||
workingDir(File(project.projectDir, rootDirRel.path))
|
||||
executable("{{ tauri-binary }}")
|
||||
args(listOf("tauri", "android", "build"))
|
||||
if (project.logger.isEnabled(LogLevel.DEBUG)) {
|
||||
@@ -47,7 +36,7 @@ open class BuildTask : DefaultTask() {
|
||||
if (release) {
|
||||
args("--release")
|
||||
}
|
||||
args(listOf("--target", "${target}"))
|
||||
args(listOf("--target", target))
|
||||
}.assertNormalExitValue()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
package {{reverse-domain app.domain}}
|
||||
|
||||
import com.android.build.gradle.*
|
||||
import java.io.File
|
||||
import org.gradle.api.DefaultTask
|
||||
import org.gradle.api.GradleException
|
||||
import org.gradle.api.Plugin
|
||||
import org.gradle.api.Project
|
||||
import java.io.File
|
||||
import java.util.*
|
||||
|
||||
const val TASK_GROUP = "rust"
|
||||
|
||||
@@ -16,7 +16,7 @@ open class Config {
|
||||
}
|
||||
|
||||
open class RustPlugin : Plugin<Project> {
|
||||
internal lateinit var config: Config
|
||||
private lateinit var config: Config
|
||||
|
||||
override fun apply(project: Project) {
|
||||
config = project.extensions.create("rust", Config::class.java)
|
||||
@@ -28,17 +28,25 @@ open class RustPlugin : Plugin<Project> {
|
||||
throw GradleException("arches cannot be null")
|
||||
}
|
||||
for (profile in listOf("debug", "release")) {
|
||||
val buildTask = project.tasks.maybeCreate("rustBuild${profile.capitalize()}", DefaultTask::class.java).apply {
|
||||
val profileCapitalized = profile.capitalize(Locale.ROOT)
|
||||
val buildTask = project.tasks.maybeCreate(
|
||||
"rustBuild$profileCapitalized",
|
||||
DefaultTask::class.java
|
||||
).apply {
|
||||
group = TASK_GROUP
|
||||
description = "Build dynamic library in ${profile} mode for all targets"
|
||||
description = "Build dynamic library in $profile mode for all targets"
|
||||
}
|
||||
for (targetPair in config.targets!!.withIndex()) {
|
||||
val targetName = targetPair.value
|
||||
val targetArch = config.arches!![targetPair.index]
|
||||
val targetBuildTask = project.tasks.maybeCreate("rustBuild${targetArch.capitalize()}${profile.capitalize()}", BuildTask::class.java).apply {
|
||||
val targetArchCapitalized = targetArch.capitalize(Locale.ROOT)
|
||||
val targetBuildTask = project.tasks.maybeCreate(
|
||||
"rustBuild$targetArchCapitalized$profileCapitalized",
|
||||
BuildTask::class.java
|
||||
).apply {
|
||||
group = TASK_GROUP
|
||||
description = "Build dynamic library in ${profile} mode for $targetArch"
|
||||
rootDirRel = File(config.rootDirRel)
|
||||
description = "Build dynamic library in $profile mode for $targetArch"
|
||||
rootDirRel = config.rootDirRel?.let { File(it) }
|
||||
target = targetName
|
||||
release = profile == "release"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user