mirror of
https://github.com/tauri-apps/tauri.git
synced 2024-12-25 11:43:06 +03:00
refactor(cli.rs): signer
and plugin
subcommands, use new clap derive syntax (#2928)
Co-authored-by: Lucas Nogueira <lucas@tauri.studio>
This commit is contained in:
parent
28aaec87e2
commit
1458ab3c53
5
.changes/cli.rs-refactor-signer.md
Normal file
5
.changes/cli.rs-refactor-signer.md
Normal file
@ -0,0 +1,5 @@
|
||||
---
|
||||
"cli.rs": patch
|
||||
---
|
||||
|
||||
The `generate` and `sign` commands are now available under a `signer` subcommand.
|
@ -293,7 +293,7 @@
|
||||
//! To generate your keys you need to use the Tauri cli.
|
||||
//!
|
||||
//! ```bash
|
||||
//! tauri sign -g -w ~/.tauri/myapp.key
|
||||
//! tauri signer sign -g -w ~/.tauri/myapp.key
|
||||
//! ```
|
||||
//!
|
||||
//! You have multiple options available
|
||||
@ -301,7 +301,7 @@
|
||||
//! Tauri updates signer.
|
||||
//!
|
||||
//! USAGE:
|
||||
//! tauri sign [FLAGS] [OPTIONS]
|
||||
//! tauri signer sign [FLAGS] [OPTIONS]
|
||||
//!
|
||||
//! FLAGS:
|
||||
//! --force Overwrite private key even if it exists on the specified path
|
||||
|
@ -280,14 +280,14 @@ The *Private key* (privkey) is used to sign your update and should NEVER be shar
|
||||
To generate your keys you need to use the Tauri cli.
|
||||
|
||||
```bash
|
||||
tauri sign -g -w ~/.tauri/myapp.key
|
||||
tauri signer sign -g -w ~/.tauri/myapp.key
|
||||
```
|
||||
|
||||
You have multiple options available
|
||||
```bash
|
||||
Tauri updates signer.
|
||||
USAGE:
|
||||
tauri sign [FLAGS] [OPTIONS]
|
||||
tauri signer sign [FLAGS] [OPTIONS]
|
||||
FLAGS:
|
||||
--force Overwrite private key even if it exists on the specified path
|
||||
-g, --generate Generate keypair to sign files
|
||||
|
@ -431,7 +431,7 @@ pub fn build_wix_app_installer(
|
||||
\pard\sa200\sl276\slmult1\f0\fs22\lang9 {}\par
|
||||
}}
|
||||
"#,
|
||||
license_contents.replace("\n", "\\par ")
|
||||
license_contents.replace('\n', "\\par ")
|
||||
);
|
||||
let rtf_output_path = settings
|
||||
.project_out_directory()
|
||||
|
268
tooling/cli.rs/Cargo.lock
generated
Executable file → Normal file
268
tooling/cli.rs/Cargo.lock
generated
Executable file → Normal file
@ -25,9 +25,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.43"
|
||||
version = "1.0.47"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "28ae2b3dec75a406790005a200b1bd89785afc02517a00ca99ecfe093ee9e6cf"
|
||||
checksum = "38d9ff5d688f1c13395289f67db01d4826b46dd694e7580accdc3e8430f2d98e"
|
||||
|
||||
[[package]]
|
||||
name = "ar"
|
||||
@ -75,9 +75,9 @@ checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.3.1"
|
||||
version = "1.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2da1976d75adbe5fbc88130ecd119529cf1cc6a93ae1546d8696ee66f0d21af1"
|
||||
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||
|
||||
[[package]]
|
||||
name = "bitness"
|
||||
@ -132,9 +132,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "bumpalo"
|
||||
version = "3.7.0"
|
||||
version = "3.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9c59e7af012c713f529e7a3ee57ce9b31ddd858d4b512923602f74608b009631"
|
||||
checksum = "8f1e260c3a9040a7c19a12468758f4c16f31a81a1fe087482be9570ec864bb6c"
|
||||
|
||||
[[package]]
|
||||
name = "byte-tools"
|
||||
@ -156,9 +156,9 @@ checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
|
||||
|
||||
[[package]]
|
||||
name = "bytes"
|
||||
version = "1.0.1"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b700ce4376041dcd0a327fd0097c41095743c4c8af8887265942faf1100bd040"
|
||||
checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8"
|
||||
|
||||
[[package]]
|
||||
name = "bzip2"
|
||||
@ -183,9 +183,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.0.69"
|
||||
version = "1.0.72"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e70cc2f62c6ce1868963827bd677764c62d07c3d9a3e1fb1177ee1a9ab199eb2"
|
||||
checksum = "22a9137b95ea06864e018375b72adfb7db6e6f68cfc8df5a04d00288050485ee"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
@ -229,9 +229,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "3.0.0-beta.5"
|
||||
version = "3.0.0-rc.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "feff3878564edb93745d58cf63e17b63f24142506e7a20c87a5521ed7bfb1d63"
|
||||
checksum = "79b70f999da60e6619a29b131739d2211ed4d4301f40372e94a8081422e9d6c7"
|
||||
dependencies = [
|
||||
"atty",
|
||||
"bitflags",
|
||||
@ -242,15 +242,13 @@ dependencies = [
|
||||
"strsim",
|
||||
"termcolor",
|
||||
"textwrap",
|
||||
"unicase",
|
||||
"yaml-rust",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_derive"
|
||||
version = "3.0.0-beta.5"
|
||||
version = "3.0.0-rc.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8b15c6b4f786ffb6192ffe65a36855bc1fc2444bcd0945ae16748dcd6ed7d0d3"
|
||||
checksum = "fe8c0f28022faaef0387fa54f8e33fee22b804a88bbd91303197da2ff8ca6a5d"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"proc-macro-error",
|
||||
@ -278,9 +276,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "combine"
|
||||
version = "4.6.0"
|
||||
version = "4.6.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a2d47c1b11006b87e492b53b313bb699ce60e16613c4dddaa91f8f7c220ab2fa"
|
||||
checksum = "b2b2f5d0ee456f3928812dfc8c6d9a1d592b98678f6d56db9b0cd2b7bc6c8db5"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"memchr",
|
||||
@ -303,9 +301,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "core-foundation"
|
||||
version = "0.9.1"
|
||||
version = "0.9.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0a89e2ae426ea83155dccf10c0fa6b1463ef6d5fcb44cee0b224a408fa640a62"
|
||||
checksum = "6888e10551bb93e424d8df1d07f1a8b4fceb0001a3a4b048bfc47554946f47b3"
|
||||
dependencies = [
|
||||
"core-foundation-sys",
|
||||
"libc",
|
||||
@ -313,18 +311,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "core-foundation-sys"
|
||||
version = "0.8.2"
|
||||
version = "0.8.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ea221b5284a47e40033bf9b66f35f984ec0ea2931eb03505246cd27a963f981b"
|
||||
|
||||
[[package]]
|
||||
name = "cpufeatures"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "66c99696f6c9dd7f35d486b9d04d7e6e202aa3e8c40d553f2fdf5e7e0c6a71ef"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc"
|
||||
|
||||
[[package]]
|
||||
name = "cpufeatures"
|
||||
@ -552,9 +541,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "flate2"
|
||||
version = "1.0.20"
|
||||
version = "1.0.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cd3aec53de10fe96d7d8c565eb17f2c687bb5518a2ec453b5b1252964526abe0"
|
||||
checksum = "1e6988e897c1c9c485f43b47a529cef42fde0547f9d8d41a7062518f1d8fc53f"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"crc32fast",
|
||||
@ -671,9 +660,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "gif"
|
||||
version = "0.11.2"
|
||||
version = "0.11.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5a668f699973d0f573d15749b7002a9ac9e1f9c6b220e7b165601334c173d8de"
|
||||
checksum = "c3a7187e78088aead22ceedeee99779455b23fc231fe13ec443f99bb71694e5b"
|
||||
dependencies = [
|
||||
"color_quant",
|
||||
"weezl",
|
||||
@ -687,9 +676,9 @@ checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574"
|
||||
|
||||
[[package]]
|
||||
name = "handlebars"
|
||||
version = "4.1.2"
|
||||
version = "4.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fd85ecabdb47308d28d3a4113224fefcab2510ccb4e463aee0a1362eb84c756a"
|
||||
checksum = "8ad84da8f63da982543fc85fcabaee2ad1fdd809d99d64a48887e2e942ddfe46"
|
||||
dependencies = [
|
||||
"log",
|
||||
"pest",
|
||||
@ -741,9 +730,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "http"
|
||||
version = "0.2.4"
|
||||
version = "0.2.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "527e8c9ac747e28542699a951517aa9a6945af506cd1f2e1b53a576c17b6cc11"
|
||||
checksum = "1323096b05d41827dadeaee54c9981958c0f94e670bc94ed80037d1a7b8b186b"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"fnv",
|
||||
@ -798,18 +787,18 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "include_dir"
|
||||
version = "0.7.0"
|
||||
version = "0.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0d7d2a17a8653f96bc15a7840946857891072b950c1c318473fa46bb4c1ac6cc"
|
||||
checksum = "7fe7734d776eb702d33f1b68730696db57c87facfd526d2044a308a0c8466318"
|
||||
dependencies = [
|
||||
"include_dir_macros",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "include_dir_macros"
|
||||
version = "0.7.0"
|
||||
version = "0.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d551dc625a699489a6903cd41dd91aef674a5126f3d28799a316d14e7b15fcf5"
|
||||
checksum = "253ba5156abc78673208f900dd686e1e000e6edc5633231d309acded2b66026d"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@ -865,9 +854,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "0.4.7"
|
||||
version = "0.4.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736"
|
||||
checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4"
|
||||
|
||||
[[package]]
|
||||
name = "jpeg-decoder"
|
||||
@ -880,9 +869,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "js-sys"
|
||||
version = "0.3.52"
|
||||
version = "0.3.55"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ce791b7ca6638aae45be056e068fc756d871eb3b3b10b8efa62d1c9cec616752"
|
||||
checksum = "7cc9ffccd38c451a86bf13657df244e9c3f37493cce8e5e21e940963777acc84"
|
||||
dependencies = [
|
||||
"wasm-bindgen",
|
||||
]
|
||||
@ -929,9 +918,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "kstring"
|
||||
version = "1.0.5"
|
||||
version = "1.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6e8d7e992938cc9078c8db5fd5bdc400e7f9da6efa384c280902a8922b676221"
|
||||
checksum = "8b310ccceade8121d7d77fee406160e457c2f4e7c7982d589da3499bc7ea4526"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
@ -956,9 +945,9 @@ checksum = "f98a04dce437184842841303488f70d0188c5f51437d2a834dc097eafa909a01"
|
||||
|
||||
[[package]]
|
||||
name = "libflate"
|
||||
version = "1.1.0"
|
||||
version = "1.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6d87eae36b3f680f7f01645121b782798b56ef33c53f83d1c66ba3a22b60bfe3"
|
||||
checksum = "16364af76ebb39b5869bb32c81fa93573267cd8c62bb3474e28d78fac3fb141e"
|
||||
dependencies = [
|
||||
"adler32",
|
||||
"crc32fast",
|
||||
@ -974,12 +963,6 @@ dependencies = [
|
||||
"rle-decode-fast",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "linked-hash-map"
|
||||
version = "0.5.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7fb9b38af92608140b86b693604b9ffcc5824240a484d1ecd4795bacb2fe88f3"
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.14"
|
||||
@ -1009,9 +992,9 @@ checksum = "490cc448043f947bae3cbee9c203358d62dbee0db12107a74be5c30ccfd09771"
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.4.0"
|
||||
version = "2.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b16bd47d9e329435e309c58469fe0791c2d0d1ba96ec0954152a5ae2b04387dc"
|
||||
checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a"
|
||||
|
||||
[[package]]
|
||||
name = "memoffset"
|
||||
@ -1213,9 +1196,9 @@ checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5"
|
||||
|
||||
[[package]]
|
||||
name = "openssl"
|
||||
version = "0.10.35"
|
||||
version = "0.10.38"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "549430950c79ae24e6d02e0b7404534ecf311d94cc9f861e9e4020187d13d885"
|
||||
checksum = "0c7ae222234c30df141154f159066c5093ff73b63204dcda7121eb082fc56a95"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"cfg-if 1.0.0",
|
||||
@ -1233,9 +1216,9 @@ checksum = "28988d872ab76095a6e6ac88d99b54fd267702734fd7ffe610ca27f533ddb95a"
|
||||
|
||||
[[package]]
|
||||
name = "openssl-sys"
|
||||
version = "0.9.65"
|
||||
version = "0.9.71"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7a7907e3bfa08bb85105209cdfcb6c63d109f8f6c1ed6ca318fff5c1853fbc1d"
|
||||
checksum = "7df13d165e607909b363a4757a6f133f8a818a74e9d3a98d09c6128e15fa4c73"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"cc",
|
||||
@ -1257,9 +1240,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "os_str_bytes"
|
||||
version = "4.2.0"
|
||||
version = "6.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "addaa943333a514159c80c97ff4a93306530d965d27e139188283cd13e06a799"
|
||||
checksum = "8e22443d1643a904602595ba1cd8f7d896afe56d26712531c5ff73a15b2fbf64"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
@ -1362,9 +1345,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "pkg-config"
|
||||
version = "0.3.19"
|
||||
version = "0.3.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3831453b3449ceb48b6d9c7ad7c96d5ea673e9b470a1dc578c2ce6521230884c"
|
||||
checksum = "12295df4f294471248581bc09bef3c38a5e46f1e36d6a37353621a0c6c357e1f"
|
||||
|
||||
[[package]]
|
||||
name = "png"
|
||||
@ -1380,9 +1363,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ppv-lite86"
|
||||
version = "0.2.10"
|
||||
version = "0.2.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857"
|
||||
checksum = "ed0cfbc8191465bed66e1718596ee0b0b35d5ee1f41c5df2189d0fe8bde535ba"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-error"
|
||||
@ -1410,9 +1393,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.28"
|
||||
version = "1.0.32"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5c7ed8b8c7b886ea3ed7dde405212185f423ab44682667c8c6dd14aa1d9f6612"
|
||||
checksum = "ba508cc11742c0dc5c1659771673afbab7a0efab23aa17e854cbab0837ed0b43"
|
||||
dependencies = [
|
||||
"unicode-xid",
|
||||
]
|
||||
@ -1435,9 +1418,9 @@ checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3"
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.9"
|
||||
version = "1.0.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7"
|
||||
checksum = "38bc8cc6a5f2e3655e0899c1b848643b2562f853f114bfec7be120678e3ace05"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
@ -1636,9 +1619,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rustls"
|
||||
version = "0.20.0"
|
||||
version = "0.20.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9b5ac6078ca424dc1d3ae2328526a76787fecc7f8011f520e3276730e711fc95"
|
||||
checksum = "dac4581f0fc0e0efd529d069e8189ec7b90b8e7680e21beb35141bdc45f36040"
|
||||
dependencies = [
|
||||
"log",
|
||||
"ring",
|
||||
@ -1688,9 +1671,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "schemars"
|
||||
version = "0.8.3"
|
||||
version = "0.8.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bc6ab463ae35acccb5cba66c0084c985257b797d288b6050cc2f6ac1b266cb78"
|
||||
checksum = "271ac0c667b8229adf70f0f957697c96fafd7486ab7481e15dc5e45e3e6a4368"
|
||||
dependencies = [
|
||||
"dyn-clone",
|
||||
"schemars_derive",
|
||||
@ -1700,9 +1683,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "schemars_derive"
|
||||
version = "0.8.3"
|
||||
version = "0.8.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "902fdfbcf871ae8f653bddf4b2c05905ddaabc08f69d32a915787e3be0d31356"
|
||||
checksum = "6ebda811090b257411540779860bc09bf321bc587f58d2c5864309d1566214e7"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@ -1731,7 +1714,7 @@ dependencies = [
|
||||
"hmac",
|
||||
"pbkdf2",
|
||||
"salsa20",
|
||||
"sha2 0.9.5",
|
||||
"sha2 0.9.8",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1746,9 +1729,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "security-framework"
|
||||
version = "2.3.1"
|
||||
version = "2.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "23a2ac85147a3a11d77ecf1bc7166ec0b92febfa4461c37944e180f319ece467"
|
||||
checksum = "525bc1abfda2e1998d152c45cf13e696f76d0a4972310b22fac1658b05df7c87"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"core-foundation",
|
||||
@ -1759,9 +1742,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "security-framework-sys"
|
||||
version = "2.3.0"
|
||||
version = "2.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7e4effb91b4b8b6fb7732e670b6cee160278ff8e6bf485c7805d9e319d76e284"
|
||||
checksum = "a9dd14d83160b528b7bfd66439110573efcfbe281b17fc2ca9f39f550d619c7e"
|
||||
dependencies = [
|
||||
"core-foundation-sys",
|
||||
"libc",
|
||||
@ -1775,18 +1758,18 @@ checksum = "568a8e6258aa33c13358f81fd834adb854c6f7c9468520910a9b1e8fac068012"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.127"
|
||||
version = "1.0.130"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f03b9878abf6d14e6779d3f24f07b2cfa90352cfec4acc5aab8f1ac7f146fae8"
|
||||
checksum = "f12d06de37cf59146fbdecab66aa99f9fe4f78722e3607577a5375d66bd0c913"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.127"
|
||||
version = "1.0.130"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a024926d3432516606328597e0f224a51355a493b49fdd67e9209187cbe55ecc"
|
||||
checksum = "d7bc1a1ab1961464eae040d96713baa5a724a8152c1222492465b54322ec508b"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@ -1806,9 +1789,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.66"
|
||||
version = "1.0.71"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "336b10da19a12ad094b59d870ebde26a45402e5b470add4b5fd03c5048a32127"
|
||||
checksum = "063bf466a64011ac24040a49009724ee60a57da1b437617ceb32e53ad61bfb19"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"ryu",
|
||||
@ -1828,9 +1811,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "serde_with_macros"
|
||||
version = "1.5.0"
|
||||
version = "1.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "98c1fcca18d55d1763e1c16873c4bde0ac3ef75179a28c7b372917e0494625be"
|
||||
checksum = "12e47be9471c72889ebafb5e14d5ff930d89ae7a67bbdb5f8abb564f845a927e"
|
||||
dependencies = [
|
||||
"darling",
|
||||
"proc-macro2",
|
||||
@ -1858,13 +1841,13 @@ checksum = "2579985fda508104f7587689507983eadd6a6e84dd35d6d115361f530916fa0d"
|
||||
|
||||
[[package]]
|
||||
name = "sha2"
|
||||
version = "0.9.5"
|
||||
version = "0.9.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b362ae5752fd2137731f9fa25fd4d9058af34666ca1966fb969119cc35719f12"
|
||||
checksum = "b69f9a4c9740d74c5baa3fd2e547f9525fa8088a8a958e0ca2409a514e33f5fa"
|
||||
dependencies = [
|
||||
"block-buffer 0.9.0",
|
||||
"cfg-if 1.0.0",
|
||||
"cpufeatures 0.1.5",
|
||||
"cpufeatures",
|
||||
"digest 0.9.0",
|
||||
"opaque-debug 0.3.0",
|
||||
]
|
||||
@ -1876,7 +1859,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "900d964dd36bb15bcf2f2b35694c072feab74969a54f2bbeec7a2d725d2bdcb6"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"cpufeatures 0.2.1",
|
||||
"cpufeatures",
|
||||
"digest 0.10.0",
|
||||
]
|
||||
|
||||
@ -1892,15 +1875,15 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "siphasher"
|
||||
version = "0.3.6"
|
||||
version = "0.3.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "729a25c17d72b06c68cb47955d44fda88ad2d3e7d77e025663fdd69b93dd71a1"
|
||||
checksum = "533494a8f9b724d33625ab53c6c4800f7cc445895924a8ef649222dcb76e938b"
|
||||
|
||||
[[package]]
|
||||
name = "slab"
|
||||
version = "0.4.4"
|
||||
version = "0.4.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c307a32c1c5c437f38c7fd45d753050587732ba8628319fbdf12a7e289ccc590"
|
||||
checksum = "9def91fd1e018fe007022791f865d0ccc9b3a0d5001e01aabb8b40e46000afb5"
|
||||
|
||||
[[package]]
|
||||
name = "spin"
|
||||
@ -1922,9 +1905,9 @@ checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.74"
|
||||
version = "1.0.81"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1873d832550d4588c3dbc20f01361ab00bfe741048f71e3fecf145a7cc18b29c"
|
||||
checksum = "f2afee18b8beb5a596ecb4a2dce128c719b4ba399d34126b9e4396e3f9860966"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@ -1933,9 +1916,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "sysctl"
|
||||
version = "0.4.2"
|
||||
version = "0.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "963488c73b34185a9028742c2be0219ed1d8558e59f85c3b466a4f54affba936"
|
||||
checksum = "feb3f7a32e17639e3705d2e05da40f485877cb97fdf0f3240e519e525e6cdb4d"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"byteorder",
|
||||
@ -2066,24 +2049,21 @@ name = "textwrap"
|
||||
version = "0.14.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0066c8d12af8b5acd21e00547c3797fde4e8677254a7ee429176ccebbe93dd80"
|
||||
dependencies = [
|
||||
"unicode-width",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.26"
|
||||
version = "1.0.30"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "93119e4feac1cbe6c798c34d3a53ea0026b0b1de6a120deef895137c0529bfe2"
|
||||
checksum = "854babe52e4df1653706b98fcfc05843010039b406875930a70e4d9644e5c417"
|
||||
dependencies = [
|
||||
"thiserror-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "1.0.26"
|
||||
version = "1.0.30"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "060d69a0afe7796bf42e9e2ff91f5ee691fb15c53d38b4b62a9a53eb23164745"
|
||||
checksum = "aa32fd3f627f367fe16f893e2597ae3c05020f8bba2666a4e6ea73d377e5714b"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@ -2113,9 +2093,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tinyvec"
|
||||
version = "1.3.1"
|
||||
version = "1.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "848a1e1181b9f6753b5e96a092749e29b11d19ede67dfbbd6c7dc7e0f49b5338"
|
||||
checksum = "2c1c1d5a42b6245520c249549ec267180beaffcc0615401ac8e31853d4b6d8d2"
|
||||
dependencies = [
|
||||
"tinyvec_macros",
|
||||
]
|
||||
@ -2158,9 +2138,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "typenum"
|
||||
version = "1.13.0"
|
||||
version = "1.14.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "879f6906492a7cd215bfa4cf595b600146ccfac0c79bcbd1f3000162af5e8b06"
|
||||
checksum = "b63708a265f51345575b27fe43f9500ad611579e764c79edbc2037b1121959ec"
|
||||
|
||||
[[package]]
|
||||
name = "ucd-trie"
|
||||
@ -2177,20 +2157,11 @@ dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicase"
|
||||
version = "2.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6"
|
||||
dependencies = [
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-bidi"
|
||||
version = "0.3.6"
|
||||
version = "0.3.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "246f4c42e67e7a4e3c6106ff716a5d067d4132a642840b242e357e468a2a0085"
|
||||
checksum = "1a01404663e3db436ed2746d9fefef640d868edae3cceb81c3b8d5732fda678f"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-normalization"
|
||||
@ -2209,9 +2180,9 @@ checksum = "8895849a949e7845e06bd6dc1aa51731a103c42707010a5b591c0038fb73385b"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-width"
|
||||
version = "0.1.8"
|
||||
version = "0.1.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3"
|
||||
checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-xid"
|
||||
@ -2227,9 +2198,9 @@ checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a"
|
||||
|
||||
[[package]]
|
||||
name = "ureq"
|
||||
version = "2.3.0"
|
||||
version = "2.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1dd912a3d096959150c4d71ac752e13f1683085922658c205b89b40fe8ebe07f"
|
||||
checksum = "c5c448dcb78ec38c7d59ec61f87f70a98ea19171e06c139357e012ee226fec90"
|
||||
dependencies = [
|
||||
"base64",
|
||||
"chunked_transfer",
|
||||
@ -2331,9 +2302,9 @@ checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6"
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen"
|
||||
version = "0.2.75"
|
||||
version = "0.2.78"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b608ecc8f4198fe8680e2ed18eccab5f0cd4caaf3d83516fa5fb2e927fda2586"
|
||||
checksum = "632f73e236b219150ea279196e54e610f5dbafa5d61786303d4da54f84e47fce"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"wasm-bindgen-macro",
|
||||
@ -2341,9 +2312,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-backend"
|
||||
version = "0.2.75"
|
||||
version = "0.2.78"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "580aa3a91a63d23aac5b6b267e2d13cb4f363e31dce6c352fca4752ae12e479f"
|
||||
checksum = "a317bf8f9fba2476b4b2c85ef4c4af8ff39c3c7f0cdfeed4f82c34a880aa837b"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"lazy_static",
|
||||
@ -2356,9 +2327,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro"
|
||||
version = "0.2.75"
|
||||
version = "0.2.78"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "171ebf0ed9e1458810dfcb31f2e766ad6b3a89dbda42d8901f2b268277e5f09c"
|
||||
checksum = "d56146e7c495528bf6587663bea13a8eb588d39b36b679d83972e1a2dbbdacf9"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"wasm-bindgen-macro-support",
|
||||
@ -2366,9 +2337,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro-support"
|
||||
version = "0.2.75"
|
||||
version = "0.2.78"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6c2657dd393f03aa2a659c25c6ae18a13a4048cebd220e147933ea837efc589f"
|
||||
checksum = "7803e0eea25835f8abdc585cd3021b3deb11543c6fe226dcd30b228857c5c5ab"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@ -2379,15 +2350,15 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-shared"
|
||||
version = "0.2.75"
|
||||
version = "0.2.78"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2e0c4a743a309662d45f4ede961d7afa4ba4131a59a639f29b0069c3798bbcc2"
|
||||
checksum = "0237232789cf037d5480773fe568aac745bfe2afbc11a863e97901780a6b47cc"
|
||||
|
||||
[[package]]
|
||||
name = "web-sys"
|
||||
version = "0.3.52"
|
||||
version = "0.3.55"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "01c70a82d842c9979078c772d4a1344685045f1a5628f677c2b2eab4dd7d2696"
|
||||
checksum = "38eb105f1c59d9eaa6b5cdc92b859d85b926e82cb2e0945cd0c9259faa6fe9fb"
|
||||
dependencies = [
|
||||
"js-sys",
|
||||
"wasm-bindgen",
|
||||
@ -2495,20 +2466,11 @@ dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "yaml-rust"
|
||||
version = "0.4.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85"
|
||||
dependencies = [
|
||||
"linked-hash-map",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zeroize"
|
||||
version = "1.4.1"
|
||||
version = "1.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "377db0846015f7ae377174787dd452e1c5f5a9050bc6f954911d01f116daa0cd"
|
||||
checksum = "d68d9dcec5f9b43a30d38c49f91dfedfaac384cb8f085faca366c26207dd1619"
|
||||
|
||||
[[package]]
|
||||
name = "zip"
|
||||
|
@ -18,7 +18,7 @@ name = "cargo-tauri"
|
||||
path = "src/main.rs"
|
||||
|
||||
[dependencies]
|
||||
clap = { version = "3.0.0-beta.5", features = [ "yaml" ] }
|
||||
clap = { version = "3.0.0-rc.0", features = [ "derive" ] }
|
||||
anyhow = "1.0"
|
||||
tauri-bundler = { version = "1.0.0-beta.4", path = "../bundler" }
|
||||
colored = "2.0"
|
||||
|
@ -2,11 +2,6 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
use anyhow::Context;
|
||||
#[cfg(target_os = "linux")]
|
||||
use heck::KebabCase;
|
||||
use tauri_bundler::bundle::{bundle_project, PackageType};
|
||||
|
||||
use crate::helpers::{
|
||||
app_paths::{app_dir, tauri_dir},
|
||||
command_env,
|
||||
@ -16,220 +11,227 @@ use crate::helpers::{
|
||||
updater_signature::sign_file_from_env_variables,
|
||||
Logger,
|
||||
};
|
||||
|
||||
use crate::Result;
|
||||
use anyhow::Context;
|
||||
use clap::Parser;
|
||||
#[cfg(target_os = "linux")]
|
||||
use heck::KebabCase;
|
||||
use std::{env::set_current_dir, fs::rename, path::PathBuf, process::Command};
|
||||
use tauri_bundler::bundle::{bundle_project, PackageType};
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct Build {
|
||||
#[derive(Debug, Parser)]
|
||||
#[clap(about = "Tauri build")]
|
||||
pub struct Options {
|
||||
/// Binary to use to build the application
|
||||
#[clap(short, long)]
|
||||
runner: Option<String>,
|
||||
/// Builds with the debug flag
|
||||
#[clap(short, long)]
|
||||
debug: bool,
|
||||
/// Enables verbose logging
|
||||
#[clap(short, long)]
|
||||
verbose: bool,
|
||||
/// Target triple to build against
|
||||
#[clap(short, long)]
|
||||
target: Option<String>,
|
||||
/// List of cargo features to activate
|
||||
#[clap(short, long)]
|
||||
features: Option<Vec<String>>,
|
||||
/// List of bundles to package
|
||||
#[clap(short, long)]
|
||||
bundles: Option<Vec<String>>,
|
||||
/// JSON string or path to JSON file to merge with tauri.conf.json
|
||||
#[clap(short, long)]
|
||||
config: Option<String>,
|
||||
}
|
||||
|
||||
impl Build {
|
||||
pub fn new() -> Self {
|
||||
Default::default()
|
||||
}
|
||||
pub fn command(options: Options) -> Result<()> {
|
||||
let logger = Logger::new("tauri:build");
|
||||
let merge_config = if let Some(config) = &options.config {
|
||||
Some(if config.starts_with('{') {
|
||||
config.to_string()
|
||||
} else {
|
||||
std::fs::read_to_string(&config)?
|
||||
})
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let config = get_config(merge_config.as_deref())?;
|
||||
|
||||
pub fn debug(mut self) -> Self {
|
||||
self.debug = true;
|
||||
self
|
||||
}
|
||||
let tauri_path = tauri_dir();
|
||||
set_current_dir(&tauri_path).with_context(|| "failed to change current working directory")?;
|
||||
|
||||
pub fn verbose(mut self) -> Self {
|
||||
self.verbose = true;
|
||||
self
|
||||
}
|
||||
let manifest = rewrite_manifest(config.clone())?;
|
||||
|
||||
pub fn runner(mut self, runner: String) -> Self {
|
||||
self.runner.replace(runner);
|
||||
self
|
||||
}
|
||||
let config_guard = config.lock().unwrap();
|
||||
let config_ = config_guard.as_ref().unwrap();
|
||||
|
||||
pub fn target(mut self, target: String) -> Self {
|
||||
self.target.replace(target);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn features(mut self, features: Vec<String>) -> Self {
|
||||
self.features.replace(features);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn bundles(mut self, bundles: Vec<String>) -> Self {
|
||||
self.bundles.replace(bundles);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn config(mut self, config: String) -> Self {
|
||||
self.config.replace(config);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn run(self) -> crate::Result<()> {
|
||||
let logger = Logger::new("tauri:build");
|
||||
let config = get_config(self.config.as_deref())?;
|
||||
|
||||
let tauri_path = tauri_dir();
|
||||
set_current_dir(&tauri_path).with_context(|| "failed to change current working directory")?;
|
||||
|
||||
let manifest = rewrite_manifest(config.clone())?;
|
||||
|
||||
let config_guard = config.lock().unwrap();
|
||||
let config_ = config_guard.as_ref().unwrap();
|
||||
|
||||
if let Some(before_build) = &config_.build.before_build_command {
|
||||
if !before_build.is_empty() {
|
||||
logger.log(format!("Running `{}`", before_build));
|
||||
#[cfg(target_os = "windows")]
|
||||
execute_with_output(
|
||||
Command::new("cmd")
|
||||
.arg("/C")
|
||||
.arg(before_build)
|
||||
.current_dir(app_dir())
|
||||
.envs(command_env(self.debug)),
|
||||
)
|
||||
.with_context(|| format!("failed to run `{}` with `cmd /C`", before_build))?;
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
execute_with_output(
|
||||
Command::new("sh")
|
||||
.arg("-c")
|
||||
.arg(before_build)
|
||||
.current_dir(app_dir())
|
||||
.envs(command_env(self.debug)),
|
||||
)
|
||||
.with_context(|| format!("failed to run `{}` with `sh -c`", before_build))?;
|
||||
}
|
||||
if let Some(before_build) = &config_.build.before_build_command {
|
||||
if !before_build.is_empty() {
|
||||
logger.log(format!("Running `{}`", before_build));
|
||||
#[cfg(target_os = "windows")]
|
||||
execute_with_output(
|
||||
Command::new("cmd")
|
||||
.arg("/C")
|
||||
.arg(before_build)
|
||||
.current_dir(app_dir())
|
||||
.envs(command_env(options.debug)),
|
||||
)
|
||||
.with_context(|| format!("failed to run `{}` with `cmd /C`", before_build))?;
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
execute_with_output(
|
||||
Command::new("sh")
|
||||
.arg("-c")
|
||||
.arg(before_build)
|
||||
.current_dir(app_dir())
|
||||
.envs(command_env(options.debug)),
|
||||
)
|
||||
.with_context(|| format!("failed to run `{}` with `sh -c`", before_build))?;
|
||||
}
|
||||
}
|
||||
|
||||
if let AppUrl::Url(url) = &config_.build.dist_dir {
|
||||
let web_asset_path = PathBuf::from(url);
|
||||
if !web_asset_path.exists() {
|
||||
return Err(anyhow::anyhow!(
|
||||
if let AppUrl::Url(url) = &config_.build.dist_dir {
|
||||
let web_asset_path = PathBuf::from(url);
|
||||
if !web_asset_path.exists() {
|
||||
return Err(anyhow::anyhow!(
|
||||
"Unable to find your web assets, did you forget to build your web app? Your distDir is set to \"{:?}\".",
|
||||
web_asset_path
|
||||
));
|
||||
}
|
||||
if web_asset_path.canonicalize()?.file_name() == Some(std::ffi::OsStr::new("src-tauri")) {
|
||||
return Err(anyhow::anyhow!(
|
||||
}
|
||||
if web_asset_path.canonicalize()?.file_name() == Some(std::ffi::OsStr::new("src-tauri")) {
|
||||
return Err(anyhow::anyhow!(
|
||||
"The configured distDir is the `src-tauri` folder.
|
||||
Please isolate your web assets on a separate folder and update `tauri.conf.json > build > distDir`.",
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
let mut out_folders = Vec::new();
|
||||
for folder in &["node_modules", "src-tauri", "target"] {
|
||||
if web_asset_path.join(folder).is_dir() {
|
||||
out_folders.push(folder.to_string());
|
||||
}
|
||||
let mut out_folders = Vec::new();
|
||||
for folder in &["node_modules", "src-tauri", "target"] {
|
||||
if web_asset_path.join(folder).is_dir() {
|
||||
out_folders.push(folder.to_string());
|
||||
}
|
||||
if !out_folders.is_empty() {
|
||||
return Err(anyhow::anyhow!(
|
||||
}
|
||||
if !out_folders.is_empty() {
|
||||
return Err(anyhow::anyhow!(
|
||||
"The configured distDir includes the `{:?}` {}. Please isolate your web assets on a separate folder and update `tauri.conf.json > build > distDir`.",
|
||||
out_folders,
|
||||
if out_folders.len() == 1 { "folder" }else { "folders" }
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let runner_from_config = config_.build.runner.clone();
|
||||
let runner = self
|
||||
.runner
|
||||
.or(runner_from_config)
|
||||
.unwrap_or_else(|| "cargo".to_string());
|
||||
let runner_from_config = config_.build.runner.clone();
|
||||
let runner = options
|
||||
.runner
|
||||
.or(runner_from_config)
|
||||
.unwrap_or_else(|| "cargo".to_string());
|
||||
|
||||
let mut cargo_features = config_.build.features.clone().unwrap_or_default();
|
||||
if let Some(features) = self.features {
|
||||
cargo_features.extend(features);
|
||||
}
|
||||
let mut cargo_features = config_.build.features.clone().unwrap_or_default();
|
||||
if let Some(features) = options.features {
|
||||
cargo_features.extend(features);
|
||||
}
|
||||
|
||||
crate::interface::rust::build_project(runner, &self.target, cargo_features, self.debug)
|
||||
.with_context(|| "failed to build app")?;
|
||||
crate::interface::rust::build_project(runner, &options.target, cargo_features, options.debug)
|
||||
.with_context(|| "failed to build app")?;
|
||||
|
||||
let app_settings = crate::interface::rust::AppSettings::new(config_)?;
|
||||
let app_settings = crate::interface::rust::AppSettings::new(config_)?;
|
||||
|
||||
let out_dir = app_settings
|
||||
.get_out_dir(self.target.clone(), self.debug)
|
||||
.with_context(|| "failed to get project out directory")?;
|
||||
if let Some(product_name) = config_.package.product_name.clone() {
|
||||
let bin_name = app_settings
|
||||
.cargo_package_settings()
|
||||
.name
|
||||
.clone()
|
||||
.expect("Cargo manifest must have the `package.name` field");
|
||||
#[cfg(windows)]
|
||||
let (bin_path, product_path) = {
|
||||
(
|
||||
out_dir.join(format!("{}.exe", bin_name)),
|
||||
out_dir.join(format!("{}.exe", product_name)),
|
||||
)
|
||||
};
|
||||
#[cfg(target_os = "macos")]
|
||||
let (bin_path, product_path) = { (out_dir.join(bin_name), out_dir.join(product_name)) };
|
||||
#[cfg(target_os = "linux")]
|
||||
let (bin_path, product_path) = {
|
||||
(
|
||||
out_dir.join(bin_name),
|
||||
out_dir.join(product_name.to_kebab_case()),
|
||||
)
|
||||
};
|
||||
rename(&bin_path, &product_path).with_context(|| {
|
||||
format!(
|
||||
"failed to rename `{}` to `{}`",
|
||||
bin_path.display(),
|
||||
product_path.display(),
|
||||
)
|
||||
})?;
|
||||
}
|
||||
let out_dir = app_settings
|
||||
.get_out_dir(options.target.clone(), options.debug)
|
||||
.with_context(|| "failed to get project out directory")?;
|
||||
if let Some(product_name) = config_.package.product_name.clone() {
|
||||
let bin_name = app_settings
|
||||
.cargo_package_settings()
|
||||
.name
|
||||
.clone()
|
||||
.expect("Cargo manifest must have the `package.name` field");
|
||||
#[cfg(windows)]
|
||||
let (bin_path, product_path) = {
|
||||
(
|
||||
out_dir.join(format!("{}.exe", bin_name)),
|
||||
out_dir.join(format!("{}.exe", product_name)),
|
||||
)
|
||||
};
|
||||
#[cfg(target_os = "macos")]
|
||||
let (bin_path, product_path) = { (out_dir.join(bin_name), out_dir.join(product_name)) };
|
||||
#[cfg(target_os = "linux")]
|
||||
let (bin_path, product_path) = {
|
||||
(
|
||||
out_dir.join(bin_name),
|
||||
out_dir.join(product_name.to_kebab_case()),
|
||||
)
|
||||
};
|
||||
rename(&bin_path, &product_path).with_context(|| {
|
||||
format!(
|
||||
"failed to rename `{}` to `{}`",
|
||||
bin_path.display(),
|
||||
product_path.display(),
|
||||
)
|
||||
})?;
|
||||
}
|
||||
|
||||
if config_.tauri.bundle.active {
|
||||
// move merge modules to the out dir so the bundler can load it
|
||||
#[cfg(windows)]
|
||||
{
|
||||
let arch = if let Some(t) = &self.target {
|
||||
if t.starts_with("x86_64") {
|
||||
"x86_64"
|
||||
} else if t.starts_with('i') {
|
||||
"x86"
|
||||
} else if t.starts_with("arm") {
|
||||
"arm"
|
||||
} else if t.starts_with("aarch64") {
|
||||
"aarch64"
|
||||
} else {
|
||||
panic!("Unexpected target triple {}", t)
|
||||
}
|
||||
} else if cfg!(target_arch = "x86") {
|
||||
"x86"
|
||||
} else {
|
||||
if config_.tauri.bundle.active {
|
||||
// move merge modules to the out dir so the bundler can load it
|
||||
#[cfg(windows)]
|
||||
{
|
||||
let arch = if let Some(t) = &options.target {
|
||||
if t.starts_with("x86_64") {
|
||||
"x86_64"
|
||||
};
|
||||
let (filename, vcruntime_msm) = if arch == "x86" {
|
||||
let _ = std::fs::remove_file(out_dir.join("Microsoft_VC142_CRT_x64.msm"));
|
||||
(
|
||||
"Microsoft_VC142_CRT_x86.msm",
|
||||
include_bytes!("../MergeModules/Microsoft_VC142_CRT_x86.msm").to_vec(),
|
||||
)
|
||||
} else if t.starts_with('i') {
|
||||
"x86"
|
||||
} else if t.starts_with("arm") {
|
||||
"arm"
|
||||
} else if t.starts_with("aarch64") {
|
||||
"aarch64"
|
||||
} else {
|
||||
let _ = std::fs::remove_file(out_dir.join("Microsoft_VC142_CRT_x86.msm"));
|
||||
(
|
||||
"Microsoft_VC142_CRT_x64.msm",
|
||||
include_bytes!("../MergeModules/Microsoft_VC142_CRT_x64.msm").to_vec(),
|
||||
)
|
||||
};
|
||||
std::fs::write(out_dir.join(filename), vcruntime_msm)?;
|
||||
}
|
||||
panic!("Unexpected target triple {}", t)
|
||||
}
|
||||
} else if cfg!(target_arch = "x86") {
|
||||
"x86"
|
||||
} else {
|
||||
"x86_64"
|
||||
};
|
||||
let (filename, vcruntime_msm) = if arch == "x86" {
|
||||
let _ = std::fs::remove_file(out_dir.join("Microsoft_VC142_CRT_x64.msm"));
|
||||
(
|
||||
"Microsoft_VC142_CRT_x86.msm",
|
||||
include_bytes!("../MergeModules/Microsoft_VC142_CRT_x86.msm").to_vec(),
|
||||
)
|
||||
} else {
|
||||
let _ = std::fs::remove_file(out_dir.join("Microsoft_VC142_CRT_x86.msm"));
|
||||
(
|
||||
"Microsoft_VC142_CRT_x64.msm",
|
||||
include_bytes!("../MergeModules/Microsoft_VC142_CRT_x64.msm").to_vec(),
|
||||
)
|
||||
};
|
||||
std::fs::write(out_dir.join(filename), vcruntime_msm)?;
|
||||
}
|
||||
|
||||
let package_types = if let Some(names) = self.bundles {
|
||||
let mut types = vec![];
|
||||
for name in names {
|
||||
if name == "none" {
|
||||
break;
|
||||
let package_types = if let Some(names) = options.bundles {
|
||||
let mut types = vec![];
|
||||
for name in names {
|
||||
if name == "none" {
|
||||
break;
|
||||
}
|
||||
match PackageType::from_short_name(&name) {
|
||||
Some(package_type) => {
|
||||
types.push(package_type);
|
||||
}
|
||||
None => {
|
||||
return Err(anyhow::anyhow!(format!(
|
||||
"Unsupported bundle format: {}",
|
||||
name
|
||||
)));
|
||||
}
|
||||
}
|
||||
}
|
||||
Some(types)
|
||||
} else if let Some(targets) = &config_.tauri.bundle.targets {
|
||||
let mut types = vec![];
|
||||
let targets = targets.to_vec();
|
||||
if !targets.contains(&"all".into()) {
|
||||
for name in targets {
|
||||
match PackageType::from_short_name(&name) {
|
||||
Some(package_type) => {
|
||||
types.push(package_type);
|
||||
@ -243,71 +245,52 @@ impl Build {
|
||||
}
|
||||
}
|
||||
Some(types)
|
||||
} else if let Some(targets) = &config_.tauri.bundle.targets {
|
||||
let mut types = vec![];
|
||||
let targets = targets.to_vec();
|
||||
if !targets.contains(&"all".into()) {
|
||||
for name in targets {
|
||||
match PackageType::from_short_name(&name) {
|
||||
Some(package_type) => {
|
||||
types.push(package_type);
|
||||
}
|
||||
None => {
|
||||
return Err(anyhow::anyhow!(format!(
|
||||
"Unsupported bundle format: {}",
|
||||
name
|
||||
)));
|
||||
}
|
||||
}
|
||||
}
|
||||
Some(types)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
None
|
||||
};
|
||||
}
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let settings = crate::interface::get_bundler_settings(
|
||||
app_settings,
|
||||
self.target.clone(),
|
||||
&manifest,
|
||||
config_,
|
||||
&out_dir,
|
||||
self.verbose,
|
||||
package_types,
|
||||
)
|
||||
.with_context(|| "failed to build bundler settings")?;
|
||||
let settings = crate::interface::get_bundler_settings(
|
||||
app_settings,
|
||||
options.target.clone(),
|
||||
&manifest,
|
||||
config_,
|
||||
&out_dir,
|
||||
options.verbose,
|
||||
package_types,
|
||||
)
|
||||
.with_context(|| "failed to build bundler settings")?;
|
||||
|
||||
settings.copy_resources(&out_dir)?;
|
||||
settings.copy_binaries(&out_dir)?;
|
||||
settings.copy_resources(&out_dir)?;
|
||||
settings.copy_binaries(&out_dir)?;
|
||||
|
||||
let bundles = bundle_project(settings).with_context(|| "failed to bundle project")?;
|
||||
let bundles = bundle_project(settings).with_context(|| "failed to bundle project")?;
|
||||
|
||||
// If updater is active and pubkey is available
|
||||
if config_.tauri.updater.active && config_.tauri.updater.pubkey.is_some() {
|
||||
// make sure we have our package builts
|
||||
let mut signed_paths = Vec::new();
|
||||
for elem in bundles
|
||||
.iter()
|
||||
.filter(|bundle| bundle.package_type == PackageType::Updater)
|
||||
{
|
||||
// we expect to have only one path in the vec but we iter if we add
|
||||
// another type of updater package who require multiple file signature
|
||||
for path in elem.bundle_paths.iter() {
|
||||
// sign our path from environment variables
|
||||
let (signature_path, _signature) = sign_file_from_env_variables(path)?;
|
||||
signed_paths.append(&mut vec![signature_path]);
|
||||
}
|
||||
}
|
||||
if !signed_paths.is_empty() {
|
||||
print_signed_updater_archive(&signed_paths)?;
|
||||
// If updater is active and pubkey is available
|
||||
if config_.tauri.updater.active && config_.tauri.updater.pubkey.is_some() {
|
||||
// make sure we have our package builts
|
||||
let mut signed_paths = Vec::new();
|
||||
for elem in bundles
|
||||
.iter()
|
||||
.filter(|bundle| bundle.package_type == PackageType::Updater)
|
||||
{
|
||||
// we expect to have only one path in the vec but we iter if we add
|
||||
// another type of updater package who require multiple file signature
|
||||
for path in elem.bundle_paths.iter() {
|
||||
// sign our path from environment variables
|
||||
let (signature_path, _signature) = sign_file_from_env_variables(path)?;
|
||||
signed_paths.append(&mut vec![signature_path]);
|
||||
}
|
||||
}
|
||||
if !signed_paths.is_empty() {
|
||||
print_signed_updater_archive(&signed_paths)?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn print_signed_updater_archive(output_paths: &[PathBuf]) -> crate::Result<()> {
|
||||
|
@ -1,206 +0,0 @@
|
||||
name: cargo-tauri
|
||||
bin_name: cargo tauri
|
||||
author: Tauri Programme within The Commons Conservancy.
|
||||
about: The Tauri command line interface.
|
||||
subcommands:
|
||||
- dev:
|
||||
about: Tauri dev.
|
||||
setting: TrailingVarArg
|
||||
args:
|
||||
- runner:
|
||||
short: r
|
||||
long: runner
|
||||
about: binary to use to run the application
|
||||
takes_value: true
|
||||
- config:
|
||||
short: c
|
||||
long: config
|
||||
about: JSON string or path to JSON file to merge with tauri.conf.json
|
||||
takes_value: true
|
||||
- exit-on-panic:
|
||||
short: e
|
||||
long: exit-on-panic
|
||||
about: Exit on panic
|
||||
- target:
|
||||
short: t
|
||||
long: target
|
||||
about: target triple to build against
|
||||
takes_value: true
|
||||
multiple_values: true
|
||||
- features:
|
||||
short: f
|
||||
long: features
|
||||
about: list of cargo features to activate
|
||||
takes_value: true
|
||||
multiple_values: true
|
||||
- args:
|
||||
about: Args passed to the binary
|
||||
index: 1
|
||||
takes_value: true
|
||||
multiple_values: true
|
||||
- release:
|
||||
long: release
|
||||
about: Run the code in release mode
|
||||
- build:
|
||||
about: Tauri build.
|
||||
args:
|
||||
- runner:
|
||||
short: r
|
||||
long: runner
|
||||
about: binary to use to build the application
|
||||
takes_value: true
|
||||
- debug:
|
||||
short: d
|
||||
long: debug
|
||||
about: Builds with the debug flag
|
||||
- verbose:
|
||||
short: v
|
||||
long: verbose
|
||||
about: Enables verbose logging
|
||||
- bundle:
|
||||
short: b
|
||||
long: bundle
|
||||
about: list of bundles to package
|
||||
takes_value: true
|
||||
multiple_values: true
|
||||
- config:
|
||||
short: c
|
||||
long: config
|
||||
about: JSON string or path to JSON file to merge with tauri.conf.json
|
||||
takes_value: true
|
||||
- target:
|
||||
short: t
|
||||
long: target
|
||||
about: target triple to build against
|
||||
takes_value: true
|
||||
multiple_values: true
|
||||
- features:
|
||||
short: f
|
||||
long: features
|
||||
about: list of cargo features to activate
|
||||
takes_value: true
|
||||
multiple_values: true
|
||||
- sign:
|
||||
about: Tauri updates signer.
|
||||
args:
|
||||
- generate:
|
||||
short: g
|
||||
long: generate
|
||||
about: Generate keypair to sign files
|
||||
- sign-file:
|
||||
long: sign-file
|
||||
about: Sign the specified file
|
||||
takes_value: true
|
||||
- private-key-path:
|
||||
short: f
|
||||
long: private-key-path
|
||||
about: Load the private key from a file
|
||||
takes_value: true
|
||||
conflicts_with: private-key
|
||||
- private-key:
|
||||
short: k
|
||||
long: private-key
|
||||
about: Load the private key from a string
|
||||
takes_value: true
|
||||
conflicts_with: private-key-path
|
||||
requires: sign-file
|
||||
- write-keys:
|
||||
short: w
|
||||
long: write-keys
|
||||
about: Write private key to a file
|
||||
takes_value: true
|
||||
requires: generate
|
||||
- password:
|
||||
short: p
|
||||
long: password
|
||||
about: Set private key password when signing
|
||||
takes_value: true
|
||||
conflicts_with: no-password
|
||||
- no-password:
|
||||
long: no-password
|
||||
about: Set empty password for your private key
|
||||
conflicts_with: password
|
||||
- force:
|
||||
long: force
|
||||
about: Overwrite private key even if it exists on the specified path
|
||||
requires: generate
|
||||
- info:
|
||||
about: Shows information about Tauri dependencies and project configuration.
|
||||
- init:
|
||||
about: Initializes a Tauri project.
|
||||
args:
|
||||
- ci:
|
||||
long: ci
|
||||
about: Skip prompting for values
|
||||
- force:
|
||||
short: f
|
||||
long: force
|
||||
about: Force init to overwrite the src-tauri folder
|
||||
- log:
|
||||
short: l
|
||||
long: log
|
||||
about: Enables logging
|
||||
- directory:
|
||||
short: d
|
||||
long: directory
|
||||
about: Set target directory for init
|
||||
takes_value: true
|
||||
- tauri-path:
|
||||
short: t
|
||||
long: tauri-path
|
||||
about: Path of the Tauri project to use (relative to the cwd)
|
||||
takes_value: true
|
||||
- app-name:
|
||||
short: A
|
||||
long: app-name
|
||||
about: Name of your Tauri application
|
||||
takes_value: true
|
||||
- window-title:
|
||||
short: W
|
||||
long: window-title
|
||||
about: Window title of your Tauri application
|
||||
takes_value: true
|
||||
- dist-dir:
|
||||
short: D
|
||||
long: dist-dir
|
||||
about: Web assets location, relative to <project-dir>/src-tauri
|
||||
takes_value: true
|
||||
- dev-path:
|
||||
short: P
|
||||
long: dev-path
|
||||
about: Url of your dev server
|
||||
takes_value: true
|
||||
- plugin:
|
||||
about: Manage Tauri plugins.
|
||||
subcommands:
|
||||
- init:
|
||||
about: Initializes a Tauri plugin project.
|
||||
args:
|
||||
- name:
|
||||
short: n
|
||||
long: name
|
||||
about: Name of your Tauri plugin
|
||||
takes_value: true
|
||||
required: true
|
||||
- directory:
|
||||
short: d
|
||||
long: directory
|
||||
about: Set target directory for init
|
||||
takes_value: true
|
||||
- tauri-path:
|
||||
short: t
|
||||
long: tauri-path
|
||||
about: Path of the Tauri project to use (relative to the cwd)
|
||||
takes_value: true
|
||||
- api:
|
||||
short: a
|
||||
long: api
|
||||
about: Initializes a Tauri plugin with TypeScript API.
|
||||
- author:
|
||||
long: author
|
||||
about: Author name.
|
||||
takes_value: true
|
||||
- tauri:
|
||||
long: tauri
|
||||
about: Initializes a Tauri core plugin (internal usage).
|
||||
setting: Hidden
|
@ -2,13 +2,17 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
use crate::helpers::{
|
||||
app_paths::{app_dir, tauri_dir},
|
||||
command_env,
|
||||
config::{get as get_config, reload as reload_config},
|
||||
manifest::{get_workspace_members, rewrite_manifest},
|
||||
Logger,
|
||||
use crate::{
|
||||
helpers::{
|
||||
app_paths::{app_dir, tauri_dir},
|
||||
command_env,
|
||||
config::{get as get_config, reload as reload_config},
|
||||
manifest::{get_workspace_members, rewrite_manifest},
|
||||
Logger,
|
||||
},
|
||||
Result,
|
||||
};
|
||||
use clap::{AppSettings, Parser};
|
||||
|
||||
use anyhow::Context;
|
||||
use notify::{watcher, DebouncedEvent, RecursiveMode, Watcher};
|
||||
@ -28,15 +32,201 @@ use std::{
|
||||
|
||||
static BEFORE_DEV: OnceCell<Mutex<Child>> = OnceCell::new();
|
||||
|
||||
#[derive(Debug, Parser)]
|
||||
#[clap(about = "Tauri dev")]
|
||||
#[clap(setting(AppSettings::TrailingVarArg))]
|
||||
pub struct Options {
|
||||
/// Binary to use to run the application
|
||||
#[clap(short, long)]
|
||||
runner: Option<String>,
|
||||
/// Target triple to build against
|
||||
#[clap(short, long)]
|
||||
target: Option<String>,
|
||||
/// List of cargo features to activate
|
||||
#[clap(short, long)]
|
||||
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)]
|
||||
config: Option<String>,
|
||||
/// Run the code in release mode
|
||||
#[clap(short, long)]
|
||||
release_mode: bool,
|
||||
/// Args passed to the binary
|
||||
args: Vec<String>,
|
||||
}
|
||||
|
||||
pub fn command(options: Options) -> Result<()> {
|
||||
let logger = Logger::new("tauri:dev");
|
||||
|
||||
let tauri_path = tauri_dir();
|
||||
set_current_dir(&tauri_path).with_context(|| "failed to change current working directory")?;
|
||||
let merge_config = if let Some(config) = &options.config {
|
||||
Some(if config.starts_with('{') {
|
||||
config.to_string()
|
||||
} else {
|
||||
std::fs::read_to_string(&config)?
|
||||
})
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let config = get_config(merge_config.as_deref())?;
|
||||
|
||||
let (settings, out_dir) = {
|
||||
let config_guard = config.lock().unwrap();
|
||||
let config_ = config_guard.as_ref().unwrap();
|
||||
let app_settings = crate::interface::rust::AppSettings::new(config_)?;
|
||||
let out_dir = app_settings
|
||||
.get_out_dir(options.target.clone(), true)
|
||||
.with_context(|| "failed to get project out directory")?;
|
||||
let settings = crate::interface::get_bundler_settings(
|
||||
app_settings,
|
||||
options.target.clone(),
|
||||
&Default::default(),
|
||||
config_,
|
||||
&out_dir,
|
||||
false,
|
||||
None,
|
||||
)
|
||||
.with_context(|| "failed to build bundler settings")?;
|
||||
(settings, out_dir)
|
||||
};
|
||||
settings.copy_resources(&out_dir)?;
|
||||
settings.copy_binaries(&out_dir)?;
|
||||
|
||||
if let Some(before_dev) = &config
|
||||
.lock()
|
||||
.unwrap()
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.build
|
||||
.before_dev_command
|
||||
{
|
||||
if !before_dev.is_empty() {
|
||||
logger.log(format!("Running `{}`", before_dev));
|
||||
#[cfg(target_os = "windows")]
|
||||
let child = Command::new("cmd")
|
||||
.arg("/C")
|
||||
.arg(before_dev)
|
||||
.current_dir(app_dir())
|
||||
.envs(command_env(true)) // development build always includes debug information
|
||||
.spawn()
|
||||
.with_context(|| format!("failed to run `{}` with `cmd /C`", before_dev))?;
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
let child = Command::new("sh")
|
||||
.arg("-c")
|
||||
.arg(before_dev)
|
||||
.current_dir(app_dir())
|
||||
.envs(command_env(true)) // development build always includes debug information
|
||||
.spawn()
|
||||
.with_context(|| format!("failed to run `{}` with `sh -c`", before_dev))?;
|
||||
BEFORE_DEV.set(Mutex::new(child)).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
let runner_from_config = config
|
||||
.lock()
|
||||
.unwrap()
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.build
|
||||
.runner
|
||||
.clone();
|
||||
let runner = options
|
||||
.runner
|
||||
.clone()
|
||||
.or(runner_from_config)
|
||||
.unwrap_or_else(|| "cargo".to_string());
|
||||
|
||||
{
|
||||
let (tx, rx) = channel();
|
||||
let mut watcher = watcher(tx, Duration::from_secs(1)).unwrap();
|
||||
watcher.watch(tauri_path.join("Cargo.toml"), RecursiveMode::Recursive)?;
|
||||
rewrite_manifest(config.clone())?;
|
||||
loop {
|
||||
if let Ok(DebouncedEvent::NoticeWrite(_)) = rx.recv() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut cargo_features = config
|
||||
.lock()
|
||||
.unwrap()
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.build
|
||||
.features
|
||||
.clone()
|
||||
.unwrap_or_default();
|
||||
if let Some(features) = &options.features {
|
||||
cargo_features.extend(features.clone());
|
||||
}
|
||||
|
||||
let (child_wait_tx, child_wait_rx) = channel();
|
||||
let child_wait_rx = Arc::new(Mutex::new(child_wait_rx));
|
||||
|
||||
let mut process = start_app(&options, &runner, &cargo_features, child_wait_rx.clone());
|
||||
|
||||
let (tx, rx) = channel();
|
||||
|
||||
let mut watcher = watcher(tx, Duration::from_secs(1)).unwrap();
|
||||
watcher.watch(tauri_path.join("src"), RecursiveMode::Recursive)?;
|
||||
watcher.watch(tauri_path.join("Cargo.toml"), RecursiveMode::Recursive)?;
|
||||
watcher.watch(tauri_path.join("tauri.conf.json"), RecursiveMode::Recursive)?;
|
||||
|
||||
for member in get_workspace_members()? {
|
||||
let workspace_path = tauri_path.join(member);
|
||||
watcher.watch(workspace_path.join("src"), RecursiveMode::Recursive)?;
|
||||
watcher.watch(workspace_path.join("Cargo.toml"), RecursiveMode::Recursive)?;
|
||||
}
|
||||
|
||||
loop {
|
||||
if let Ok(event) = rx.recv() {
|
||||
let event_path = match event {
|
||||
DebouncedEvent::Create(path) => Some(path),
|
||||
DebouncedEvent::Remove(path) => Some(path),
|
||||
DebouncedEvent::Rename(_, dest) => Some(dest),
|
||||
DebouncedEvent::Write(path) => Some(path),
|
||||
_ => None,
|
||||
};
|
||||
|
||||
if let Some(event_path) = event_path {
|
||||
if event_path.file_name() == Some(OsStr::new("tauri.conf.json")) {
|
||||
reload_config(merge_config.as_deref())?;
|
||||
rewrite_manifest(config.clone())?;
|
||||
} else {
|
||||
// When tauri.conf.json is changed, rewrite_manifest will be called
|
||||
// which will trigger the watcher again
|
||||
// So the app should only be started when a file other than tauri.conf.json is changed
|
||||
let _ = child_wait_tx.send(());
|
||||
process
|
||||
.kill()
|
||||
.with_context(|| "failed to kill app process")?;
|
||||
// wait for the process to exit
|
||||
loop {
|
||||
if let Ok(Some(_)) = process.try_wait() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
process = start_app(&options, &runner, &cargo_features, child_wait_rx.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn kill_before_dev_process() {
|
||||
if let Some(child) = BEFORE_DEV.get() {
|
||||
let mut child = child.lock().unwrap();
|
||||
#[cfg(windows)]
|
||||
let _ = Command::new("powershell")
|
||||
.arg("-NoProfile")
|
||||
.arg("-Command")
|
||||
.arg(format!("function Kill-Tree {{ Param([int]$ppid); Get-CimInstance Win32_Process | Where-Object {{ $_.ParentProcessId -eq $ppid }} | ForEach-Object {{ Kill-Tree $_.ProcessId }}; Stop-Process -Id $ppid }}; Kill-Tree {}", child.id()))
|
||||
.status();
|
||||
let _ = Command::new("powershell")
|
||||
.arg("-NoProfile")
|
||||
.arg("-Command")
|
||||
.arg(format!("function Kill-Tree {{ Param([int]$ppid); Get-CimInstance Win32_Process | Where-Object {{ $_.ParentProcessId -eq $ppid }} | ForEach-Object {{ Kill-Tree $_.ProcessId }}; Stop-Process -Id $ppid }}; Kill-Tree {}", child.id()))
|
||||
.status();
|
||||
#[cfg(not(windows))]
|
||||
let _ = Command::new("pkill")
|
||||
.args(&["-TERM", "-P"])
|
||||
@ -46,262 +236,59 @@ fn kill_before_dev_process() {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct Dev {
|
||||
runner: Option<String>,
|
||||
target: Option<String>,
|
||||
features: Option<Vec<String>>,
|
||||
exit_on_panic: bool,
|
||||
config: Option<String>,
|
||||
args: Vec<String>,
|
||||
release_mode: bool,
|
||||
}
|
||||
fn start_app(
|
||||
options: &Options,
|
||||
runner: &str,
|
||||
features: &[String],
|
||||
child_wait_rx: Arc<Mutex<Receiver<()>>>,
|
||||
) -> Arc<SharedChild> {
|
||||
let mut command = Command::new(runner);
|
||||
command.args(&["run", "--no-default-features"]);
|
||||
|
||||
impl Dev {
|
||||
pub fn new() -> Self {
|
||||
Default::default()
|
||||
if options.release_mode {
|
||||
command.args(&["--release"]);
|
||||
}
|
||||
|
||||
pub fn runner(mut self, runner: String) -> Self {
|
||||
self.runner.replace(runner);
|
||||
self
|
||||
if let Some(target) = &options.target {
|
||||
command.args(&["--target", target]);
|
||||
}
|
||||
|
||||
pub fn target(mut self, target: String) -> Self {
|
||||
self.target.replace(target);
|
||||
self
|
||||
if !features.is_empty() {
|
||||
command.args(&["--features", &features.join(",")]);
|
||||
}
|
||||
|
||||
pub fn features(mut self, features: Vec<String>) -> Self {
|
||||
self.features.replace(features);
|
||||
self
|
||||
if !options.args.is_empty() {
|
||||
command.arg("--").args(&options.args);
|
||||
}
|
||||
|
||||
pub fn config(mut self, config: String) -> Self {
|
||||
self.config.replace(config);
|
||||
self
|
||||
}
|
||||
let child =
|
||||
SharedChild::spawn(&mut command).unwrap_or_else(|_| panic!("failed to run {}", runner));
|
||||
let child_arc = Arc::new(child);
|
||||
|
||||
pub fn exit_on_panic(mut self, exit_on_panic: bool) -> Self {
|
||||
self.exit_on_panic = exit_on_panic;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn args(mut self, args: Vec<String>) -> Self {
|
||||
self.args = args;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn release_mode(mut self, release_mode: bool) -> Self {
|
||||
self.release_mode = release_mode;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn run(self) -> crate::Result<()> {
|
||||
let logger = Logger::new("tauri:dev");
|
||||
let tauri_path = tauri_dir();
|
||||
set_current_dir(&tauri_path).with_context(|| "failed to change current working directory")?;
|
||||
let merge_config = self.config.clone();
|
||||
let config = get_config(merge_config.as_deref())?;
|
||||
|
||||
let (settings, out_dir) = {
|
||||
let config_guard = config.lock().unwrap();
|
||||
let config_ = config_guard.as_ref().unwrap();
|
||||
let app_settings = crate::interface::rust::AppSettings::new(config_)?;
|
||||
let out_dir = app_settings
|
||||
.get_out_dir(self.target.clone(), true)
|
||||
.with_context(|| "failed to get project out directory")?;
|
||||
let settings = crate::interface::get_bundler_settings(
|
||||
app_settings,
|
||||
self.target.clone(),
|
||||
&Default::default(),
|
||||
config_,
|
||||
&out_dir,
|
||||
false,
|
||||
None,
|
||||
)
|
||||
.with_context(|| "failed to build bundler settings")?;
|
||||
(settings, out_dir)
|
||||
};
|
||||
settings.copy_resources(&out_dir)?;
|
||||
settings.copy_binaries(&out_dir)?;
|
||||
|
||||
if let Some(before_dev) = &config
|
||||
.lock()
|
||||
.unwrap()
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.build
|
||||
.before_dev_command
|
||||
{
|
||||
if !before_dev.is_empty() {
|
||||
logger.log(format!("Running `{}`", before_dev));
|
||||
#[cfg(target_os = "windows")]
|
||||
let child = Command::new("cmd")
|
||||
.arg("/C")
|
||||
.arg(before_dev)
|
||||
.current_dir(app_dir())
|
||||
.envs(command_env(true)) // development build always includes debug information
|
||||
.spawn()
|
||||
.with_context(|| format!("failed to run `{}` with `cmd /C`", before_dev))?;
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
let child = Command::new("sh")
|
||||
.arg("-c")
|
||||
.arg(before_dev)
|
||||
.current_dir(app_dir())
|
||||
.envs(command_env(true)) // development build always includes debug information
|
||||
.spawn()
|
||||
.with_context(|| format!("failed to run `{}` with `sh -c`", before_dev))?;
|
||||
BEFORE_DEV.set(Mutex::new(child)).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
let runner_from_config = config
|
||||
.lock()
|
||||
.unwrap()
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.build
|
||||
.runner
|
||||
.clone();
|
||||
let runner = self
|
||||
.runner
|
||||
.clone()
|
||||
.or(runner_from_config)
|
||||
.unwrap_or_else(|| "cargo".to_string());
|
||||
|
||||
{
|
||||
let (tx, rx) = channel();
|
||||
let mut watcher = watcher(tx, Duration::from_secs(1)).unwrap();
|
||||
watcher.watch(tauri_path.join("Cargo.toml"), RecursiveMode::Recursive)?;
|
||||
rewrite_manifest(config.clone())?;
|
||||
loop {
|
||||
if let Ok(DebouncedEvent::NoticeWrite(_)) = rx.recv() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut cargo_features = config
|
||||
.lock()
|
||||
.unwrap()
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.build
|
||||
.features
|
||||
.clone()
|
||||
.unwrap_or_default();
|
||||
if let Some(features) = &self.features {
|
||||
cargo_features.extend(features.clone());
|
||||
}
|
||||
|
||||
let (child_wait_tx, child_wait_rx) = channel();
|
||||
let child_wait_rx = Arc::new(Mutex::new(child_wait_rx));
|
||||
|
||||
let mut process = self.start_app(&runner, &cargo_features, child_wait_rx.clone());
|
||||
|
||||
let (tx, rx) = channel();
|
||||
|
||||
let mut watcher = watcher(tx, Duration::from_secs(1)).unwrap();
|
||||
watcher.watch(tauri_path.join("src"), RecursiveMode::Recursive)?;
|
||||
watcher.watch(tauri_path.join("Cargo.toml"), RecursiveMode::Recursive)?;
|
||||
watcher.watch(tauri_path.join("tauri.conf.json"), RecursiveMode::Recursive)?;
|
||||
|
||||
for member in get_workspace_members()? {
|
||||
let workspace_path = tauri_path.join(member);
|
||||
watcher.watch(workspace_path.join("src"), RecursiveMode::Recursive)?;
|
||||
watcher.watch(workspace_path.join("Cargo.toml"), RecursiveMode::Recursive)?;
|
||||
}
|
||||
|
||||
loop {
|
||||
if let Ok(event) = rx.recv() {
|
||||
let event_path = match event {
|
||||
DebouncedEvent::Create(path) => Some(path),
|
||||
DebouncedEvent::Remove(path) => Some(path),
|
||||
DebouncedEvent::Rename(_, dest) => Some(dest),
|
||||
DebouncedEvent::Write(path) => Some(path),
|
||||
_ => None,
|
||||
};
|
||||
|
||||
if let Some(event_path) = event_path {
|
||||
if event_path.file_name() == Some(OsStr::new("tauri.conf.json")) {
|
||||
reload_config(merge_config.as_deref())?;
|
||||
rewrite_manifest(config.clone())?;
|
||||
} else {
|
||||
// When tauri.conf.json is changed, rewrite_manifest will be called
|
||||
// which will trigger the watcher again
|
||||
// So the app should only be started when a file other than tauri.conf.json is changed
|
||||
let _ = child_wait_tx.send(());
|
||||
process
|
||||
.kill()
|
||||
.with_context(|| "failed to kill app process")?;
|
||||
// wait for the process to exit
|
||||
loop {
|
||||
if let Ok(Some(_)) = process.try_wait() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
process = self.start_app(&runner, &cargo_features, child_wait_rx.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn start_app(
|
||||
&self,
|
||||
runner: &str,
|
||||
features: &[String],
|
||||
child_wait_rx: Arc<Mutex<Receiver<()>>>,
|
||||
) -> Arc<SharedChild> {
|
||||
let mut command = Command::new(runner);
|
||||
command.args(&["run", "--no-default-features"]);
|
||||
|
||||
if self.release_mode {
|
||||
command.args(&["--release"]);
|
||||
}
|
||||
|
||||
if let Some(target) = &self.target {
|
||||
command.args(&["--target", target]);
|
||||
}
|
||||
|
||||
if !features.is_empty() {
|
||||
command.args(&["--features", &features.join(",")]);
|
||||
}
|
||||
|
||||
if !self.args.is_empty() {
|
||||
command.arg("--").args(&self.args);
|
||||
}
|
||||
|
||||
let child =
|
||||
SharedChild::spawn(&mut command).unwrap_or_else(|_| panic!("failed to run {}", runner));
|
||||
let child_arc = Arc::new(child);
|
||||
|
||||
let child_clone = child_arc.clone();
|
||||
let exit_on_panic = self.exit_on_panic;
|
||||
std::thread::spawn(move || {
|
||||
let status = child_clone.wait().expect("failed to wait on child");
|
||||
if exit_on_panic {
|
||||
// we exit if the status is a success code (app closed) or code is 101 (compilation error)
|
||||
// if the process wasn't killed by the file watcher
|
||||
if (status.success() || status.code() == Some(101))
|
||||
let child_clone = child_arc.clone();
|
||||
let exit_on_panic = options.exit_on_panic;
|
||||
std::thread::spawn(move || {
|
||||
let status = child_clone.wait().expect("failed to wait on child");
|
||||
if exit_on_panic {
|
||||
// we exit if the status is a success code (app closed) or code is 101 (compilation error)
|
||||
// if the process wasn't killed by the file watcher
|
||||
if (status.success() || status.code() == Some(101))
|
||||
// `child_wait_rx` indicates that the process was killed by the file watcher
|
||||
&& child_wait_rx
|
||||
.lock()
|
||||
.expect("failed to get child_wait_rx lock")
|
||||
.try_recv()
|
||||
.is_err()
|
||||
{
|
||||
kill_before_dev_process();
|
||||
exit(0);
|
||||
}
|
||||
} else if status.success() {
|
||||
// if we're no exiting on panic, we only exit if the status is a success code (app closed)
|
||||
{
|
||||
kill_before_dev_process();
|
||||
exit(0);
|
||||
}
|
||||
});
|
||||
} else if status.success() {
|
||||
// if we're no exiting on panic, we only exit if the status is a success code (app closed)
|
||||
kill_before_dev_process();
|
||||
exit(0);
|
||||
}
|
||||
});
|
||||
|
||||
child_arc
|
||||
}
|
||||
child_arc
|
||||
}
|
||||
|
@ -7,6 +7,8 @@ use crate::helpers::{
|
||||
config::get as get_config,
|
||||
framework::infer_from_package_json as infer_framework,
|
||||
};
|
||||
use crate::Result;
|
||||
use clap::Parser;
|
||||
use serde::Deserialize;
|
||||
|
||||
use std::{
|
||||
@ -76,8 +78,9 @@ enum PackageManager {
|
||||
Yarn,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct Info;
|
||||
#[derive(Debug, Parser)]
|
||||
#[clap(about = "Shows information about Tauri dependencies and project configuration")]
|
||||
pub struct Options;
|
||||
|
||||
fn crate_latest_version(name: &str) -> Option<String> {
|
||||
let url = format!("https://docs.rs/crate/{}/", name);
|
||||
@ -269,19 +272,19 @@ fn get_version(command: &str, args: &[&str]) -> crate::Result<Option<String>> {
|
||||
#[cfg(windows)]
|
||||
fn webview2_version() -> crate::Result<Option<String>> {
|
||||
let output = Command::new("powershell")
|
||||
.args(&["-NoProfile", "-Command"])
|
||||
.arg("Get-ItemProperty -Path 'HKLM:\\SOFTWARE\\WOW6432Node\\Microsoft\\EdgeUpdate\\Clients\\{F3017226-FE2A-4295-8BDF-00C3A9A7E4C5}' | ForEach-Object {$_.pv}")
|
||||
.output()?;
|
||||
.args(&["-NoProfile", "-Command"])
|
||||
.arg("Get-ItemProperty -Path 'HKLM:\\SOFTWARE\\WOW6432Node\\Microsoft\\EdgeUpdate\\Clients\\{F3017226-FE2A-4295-8BDF-00C3A9A7E4C5}' | ForEach-Object {$_.pv}")
|
||||
.output()?;
|
||||
let version = if output.status.success() {
|
||||
Some(String::from_utf8_lossy(&output.stdout).replace("\n", ""))
|
||||
Some(String::from_utf8_lossy(&output.stdout).replace('\n', ""))
|
||||
} else {
|
||||
// check 32bit installation
|
||||
let output = Command::new("powershell")
|
||||
.args(&["-NoProfile", "-Command"])
|
||||
.arg("Get-ItemProperty -Path 'HKLM:\\SOFTWARE\\Microsoft\\EdgeUpdate\\Clients\\{F3017226-FE2A-4295-8BDF-00C3A9A7E4C5}' | ForEach-Object {$_.pv}")
|
||||
.output()?;
|
||||
.args(&["-NoProfile", "-Command"])
|
||||
.arg("Get-ItemProperty -Path 'HKLM:\\SOFTWARE\\Microsoft\\EdgeUpdate\\Clients\\{F3017226-FE2A-4295-8BDF-00C3A9A7E4C5}' | ForEach-Object {$_.pv}")
|
||||
.output()?;
|
||||
if output.status.success() {
|
||||
Some(String::from_utf8_lossy(&output.stdout).replace("\n", ""))
|
||||
Some(String::from_utf8_lossy(&output.stdout).replace('\n', ""))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
@ -345,8 +348,8 @@ fn get_active_rust_toolchain() -> crate::Result<Option<String>> {
|
||||
let toolchain = if output.status.success() {
|
||||
Some(
|
||||
String::from_utf8_lossy(&output.stdout)
|
||||
.replace("\n", "")
|
||||
.replace("\r", ""),
|
||||
.replace('\n', "")
|
||||
.replace('\r', ""),
|
||||
)
|
||||
} else {
|
||||
None
|
||||
@ -444,297 +447,315 @@ impl VersionBlock {
|
||||
}
|
||||
}
|
||||
|
||||
impl Info {
|
||||
pub fn new() -> Self {
|
||||
Default::default()
|
||||
pub fn command(_options: Options) -> Result<()> {
|
||||
let os_info = os_info::get();
|
||||
InfoBlock {
|
||||
section: true,
|
||||
key: "Operating System",
|
||||
value: Some(format!(
|
||||
"{}, version {} {:?}",
|
||||
os_info.os_type(),
|
||||
os_info.version(),
|
||||
os_info.bitness()
|
||||
)),
|
||||
suffix: None,
|
||||
}
|
||||
.display();
|
||||
|
||||
#[cfg(windows)]
|
||||
VersionBlock::new("Webview2", webview2_version().unwrap_or_default()).display();
|
||||
#[cfg(windows)]
|
||||
VersionBlock::new(
|
||||
"Visual Studio Build Tools",
|
||||
build_tools_version()
|
||||
.map(|r| {
|
||||
let required_string = "(>= 2019 required)";
|
||||
let multiple_string =
|
||||
"(multiple versions might conflict; keep only 2019 if build errors occur)";
|
||||
r.map(|v| match v.len() {
|
||||
1 if v[0].as_str() < "2019" => format!("{} {}", v[0], required_string),
|
||||
1 if v[0].as_str() >= "2019" => v[0].clone(),
|
||||
_ if v.contains(&"2019".into()) => {
|
||||
format!("{} {}", v.join(", "), multiple_string)
|
||||
}
|
||||
_ => format!("{} {} {}", v.join(", "), required_string, multiple_string),
|
||||
})
|
||||
})
|
||||
.unwrap_or_default(),
|
||||
)
|
||||
.display();
|
||||
|
||||
let hook = panic::take_hook();
|
||||
panic::set_hook(Box::new(|_info| {
|
||||
// do nothing
|
||||
}));
|
||||
let app_dir = panic::catch_unwind(app_dir).map(Some).unwrap_or_default();
|
||||
panic::set_hook(hook);
|
||||
|
||||
let mut package_manager = PackageManager::Npm;
|
||||
if let Some(app_dir) = &app_dir {
|
||||
let file_names = read_dir(app_dir)
|
||||
.unwrap()
|
||||
.filter(|e| {
|
||||
e.as_ref()
|
||||
.unwrap()
|
||||
.metadata()
|
||||
.unwrap()
|
||||
.file_type()
|
||||
.is_file()
|
||||
})
|
||||
.map(|e| e.unwrap().file_name().to_string_lossy().into_owned())
|
||||
.collect::<Vec<String>>();
|
||||
package_manager = get_package_manager(&file_names)?;
|
||||
}
|
||||
|
||||
pub fn run(self) -> crate::Result<()> {
|
||||
let os_info = os_info::get();
|
||||
InfoBlock {
|
||||
section: true,
|
||||
key: "Operating System",
|
||||
value: Some(format!(
|
||||
"{}, version {} {:?}",
|
||||
os_info.os_type(),
|
||||
os_info.version(),
|
||||
os_info.bitness()
|
||||
)),
|
||||
suffix: None,
|
||||
}
|
||||
.display();
|
||||
|
||||
#[cfg(windows)]
|
||||
VersionBlock::new("Webview2", webview2_version().unwrap_or_default()).display();
|
||||
#[cfg(windows)]
|
||||
if let Some(node_version) = get_version("node", &[]).unwrap_or_default() {
|
||||
InfoBlock::new("Node.js environment").section().display();
|
||||
let metadata = serde_json::from_str::<VersionMetadata>(include_str!("../metadata.json"))?;
|
||||
VersionBlock::new(
|
||||
"Visual Studio Build Tools",
|
||||
build_tools_version()
|
||||
.map(|r| {
|
||||
let required_string = "(>= 2019 required)";
|
||||
let multiple_string =
|
||||
"(multiple versions might conflict; keep only 2019 if build errors occur)";
|
||||
r.map(|v| match v.len() {
|
||||
1 if v[0].as_str() < "2019" => format!("{} {}", v[0], required_string),
|
||||
1 if v[0].as_str() >= "2019" => v[0].clone(),
|
||||
_ if v.contains(&"2019".into()) => format!("{} {}", v.join(", "), multiple_string),
|
||||
_ => format!("{} {} {}", v.join(", "), required_string, multiple_string),
|
||||
})
|
||||
})
|
||||
.unwrap_or_default(),
|
||||
" Node.js",
|
||||
node_version.chars().skip(1).collect::<String>(),
|
||||
)
|
||||
.target_version(metadata.js_cli.node.replace(">= ", ""))
|
||||
.display();
|
||||
|
||||
let hook = panic::take_hook();
|
||||
panic::set_hook(Box::new(|_info| {
|
||||
// do nothing
|
||||
}));
|
||||
let app_dir = panic::catch_unwind(app_dir).map(Some).unwrap_or_default();
|
||||
panic::set_hook(hook);
|
||||
|
||||
let mut package_manager = PackageManager::Npm;
|
||||
if let Some(app_dir) = &app_dir {
|
||||
let file_names = read_dir(app_dir)
|
||||
.unwrap()
|
||||
.filter(|e| {
|
||||
e.as_ref()
|
||||
.unwrap()
|
||||
.metadata()
|
||||
.unwrap()
|
||||
.file_type()
|
||||
.is_file()
|
||||
})
|
||||
.map(|e| e.unwrap().file_name().to_string_lossy().into_owned())
|
||||
.collect::<Vec<String>>();
|
||||
package_manager = get_package_manager(&file_names)?;
|
||||
}
|
||||
|
||||
if let Some(node_version) = get_version("node", &[]).unwrap_or_default() {
|
||||
InfoBlock::new("Node.js environment").section().display();
|
||||
let metadata = serde_json::from_str::<VersionMetadata>(include_str!("../metadata.json"))?;
|
||||
VersionBlock::new(
|
||||
" Node.js",
|
||||
node_version.chars().skip(1).collect::<String>(),
|
||||
)
|
||||
.target_version(metadata.js_cli.node.replace(">= ", ""))
|
||||
VersionBlock::new(" @tauri-apps/cli", metadata.js_cli.version)
|
||||
.target_version(npm_latest_version(&package_manager, "@tauri-apps/cli").unwrap_or_default())
|
||||
.display();
|
||||
if let Some(app_dir) = &app_dir {
|
||||
VersionBlock::new(
|
||||
" @tauri-apps/api",
|
||||
npm_package_version(&package_manager, "@tauri-apps/api", app_dir).unwrap_or_default(),
|
||||
)
|
||||
.target_version(npm_latest_version(&package_manager, "@tauri-apps/api").unwrap_or_default())
|
||||
.display();
|
||||
|
||||
VersionBlock::new(" @tauri-apps/cli", metadata.js_cli.version)
|
||||
.target_version(npm_latest_version(&package_manager, "@tauri-apps/cli").unwrap_or_default())
|
||||
.display();
|
||||
if let Some(app_dir) = &app_dir {
|
||||
VersionBlock::new(
|
||||
" @tauri-apps/api",
|
||||
npm_package_version(&package_manager, "@tauri-apps/api", app_dir).unwrap_or_default(),
|
||||
)
|
||||
.target_version(npm_latest_version(&package_manager, "@tauri-apps/api").unwrap_or_default())
|
||||
.display();
|
||||
}
|
||||
|
||||
InfoBlock::new("Global packages").section().display();
|
||||
|
||||
VersionBlock::new(" npm", get_version("npm", &[]).unwrap_or_default()).display();
|
||||
VersionBlock::new(" pnpm", get_version("pnpm", &[]).unwrap_or_default()).display();
|
||||
VersionBlock::new(" yarn", get_version("yarn", &[]).unwrap_or_default()).display();
|
||||
}
|
||||
|
||||
InfoBlock::new("Rust environment").section().display();
|
||||
VersionBlock::new(
|
||||
" rustup",
|
||||
get_version("rustup", &[]).unwrap_or_default().map(|v| {
|
||||
let mut s = v.split(' ');
|
||||
s.next();
|
||||
s.next().unwrap().to_string()
|
||||
}),
|
||||
)
|
||||
.display();
|
||||
VersionBlock::new(
|
||||
" rustc",
|
||||
get_version("rustc", &[]).unwrap_or_default().map(|v| {
|
||||
let mut s = v.split(' ');
|
||||
s.next();
|
||||
s.next().unwrap().to_string()
|
||||
}),
|
||||
)
|
||||
.display();
|
||||
VersionBlock::new(
|
||||
" cargo",
|
||||
get_version("cargo", &[]).unwrap_or_default().map(|v| {
|
||||
let mut s = v.split(' ');
|
||||
s.next();
|
||||
s.next().unwrap().to_string()
|
||||
}),
|
||||
)
|
||||
.display();
|
||||
VersionBlock::new(
|
||||
" toolchain",
|
||||
get_active_rust_toolchain().unwrap_or_default(),
|
||||
)
|
||||
.display();
|
||||
InfoBlock::new("Global packages").section().display();
|
||||
|
||||
if let Some(app_dir) = app_dir {
|
||||
InfoBlock::new("App directory structure")
|
||||
.section()
|
||||
.display();
|
||||
for entry in read_dir(app_dir)? {
|
||||
let entry = entry?;
|
||||
if entry.path().is_dir() {
|
||||
println!("/{}", entry.path().file_name().unwrap().to_string_lossy());
|
||||
}
|
||||
}
|
||||
|
||||
InfoBlock::new("App").section().display();
|
||||
let tauri_dir = tauri_dir();
|
||||
let manifest: Option<CargoManifest> =
|
||||
if let Ok(manifest_contents) = read_to_string(tauri_dir.join("Cargo.toml")) {
|
||||
toml::from_str(&manifest_contents).ok()
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let lock: Option<CargoLock> =
|
||||
if let Ok(lock_contents) = read_to_string(tauri_dir.join("Cargo.lock")) {
|
||||
toml::from_str(&lock_contents).ok()
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let tauri_lock_packages: Vec<CargoLockPackage> = lock
|
||||
.as_ref()
|
||||
.map(|lock| {
|
||||
lock
|
||||
.package
|
||||
.iter()
|
||||
.filter(|p| p.name == "tauri")
|
||||
.cloned()
|
||||
.collect()
|
||||
})
|
||||
.unwrap_or_default();
|
||||
let (tauri_version_string, found_tauri_versions) =
|
||||
match (&manifest, &lock, tauri_lock_packages.len()) {
|
||||
(Some(_manifest), Some(_lock), 1) => {
|
||||
let tauri_lock_package = tauri_lock_packages.first().unwrap();
|
||||
(
|
||||
tauri_lock_package.version.clone(),
|
||||
vec![tauri_lock_package.version.clone()],
|
||||
)
|
||||
}
|
||||
(None, Some(_lock), 1) => {
|
||||
let tauri_lock_package = tauri_lock_packages.first().unwrap();
|
||||
(
|
||||
format!("{} (no manifest)", tauri_lock_package.version),
|
||||
vec![tauri_lock_package.version.clone()],
|
||||
)
|
||||
}
|
||||
_ => {
|
||||
let mut found_tauri_versions = Vec::new();
|
||||
let manifest_version = match manifest.and_then(|m| m.dependencies.get("tauri").cloned())
|
||||
{
|
||||
Some(tauri) => match tauri {
|
||||
CargoManifestDependency::Version(v) => {
|
||||
found_tauri_versions.push(v.clone());
|
||||
v
|
||||
}
|
||||
CargoManifestDependency::Package(p) => {
|
||||
if let Some(v) = p.version {
|
||||
found_tauri_versions.push(v.clone());
|
||||
v
|
||||
} else if let Some(p) = p.path {
|
||||
let manifest_path = tauri_dir.join(&p).join("Cargo.toml");
|
||||
let v = match read_to_string(&manifest_path)
|
||||
.map_err(|_| ())
|
||||
.and_then(|m| toml::from_str::<CargoManifest>(&m).map_err(|_| ()))
|
||||
{
|
||||
Ok(manifest) => manifest.package.version,
|
||||
Err(_) => "unknown version".to_string(),
|
||||
};
|
||||
format!("path:{:?} [{}]", p, v)
|
||||
} else {
|
||||
"unknown manifest".to_string()
|
||||
}
|
||||
}
|
||||
},
|
||||
None => "no manifest".to_string(),
|
||||
};
|
||||
|
||||
let lock_version = match (lock, tauri_lock_packages.is_empty()) {
|
||||
(Some(_lock), true) => tauri_lock_packages
|
||||
.iter()
|
||||
.map(|p| p.version.clone())
|
||||
.collect::<Vec<String>>()
|
||||
.join(", "),
|
||||
(Some(_lock), false) => "unknown lockfile".to_string(),
|
||||
_ => "no lockfile".to_string(),
|
||||
};
|
||||
|
||||
(
|
||||
format!("{} ({})", manifest_version, lock_version),
|
||||
found_tauri_versions,
|
||||
)
|
||||
}
|
||||
};
|
||||
|
||||
let tauri_version = found_tauri_versions
|
||||
.into_iter()
|
||||
.map(|v| semver::Version::parse(&v).unwrap())
|
||||
.max();
|
||||
let suffix = match (tauri_version, crate_latest_version("tauri")) {
|
||||
(Some(version), Some(target_version)) => {
|
||||
let target_version = semver::Version::parse(&target_version).unwrap();
|
||||
if version < target_version {
|
||||
Some(format!(" (outdated, latest: {})", target_version))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
_ => None,
|
||||
};
|
||||
InfoBlock::new(" tauri.rs")
|
||||
.value(tauri_version_string)
|
||||
.suffix(suffix)
|
||||
.display();
|
||||
|
||||
if let Ok(config) = get_config(None) {
|
||||
let config_guard = config.lock().unwrap();
|
||||
let config = config_guard.as_ref().unwrap();
|
||||
InfoBlock::new(" build-type")
|
||||
.value(if config.tauri.bundle.active {
|
||||
"bundle".to_string()
|
||||
} else {
|
||||
"build".to_string()
|
||||
})
|
||||
.display();
|
||||
InfoBlock::new(" CSP")
|
||||
.value(if let Some(security) = &config.tauri.security {
|
||||
security.csp.clone().unwrap_or_else(|| "unset".to_string())
|
||||
} else {
|
||||
"unset".to_string()
|
||||
})
|
||||
.display();
|
||||
InfoBlock::new(" distDir")
|
||||
.value(config.build.dist_dir.to_string())
|
||||
.display();
|
||||
InfoBlock::new(" devPath")
|
||||
.value(config.build.dev_path.to_string())
|
||||
.display();
|
||||
}
|
||||
if let Ok(package_json) = read_to_string(app_dir.join("package.json")) {
|
||||
let (framework, bundler) = infer_framework(&package_json);
|
||||
if let Some(framework) = framework {
|
||||
InfoBlock::new(" framework")
|
||||
.value(framework.to_string())
|
||||
.display();
|
||||
}
|
||||
if let Some(bundler) = bundler {
|
||||
InfoBlock::new(" bundler")
|
||||
.value(bundler.to_string())
|
||||
.display();
|
||||
}
|
||||
} else {
|
||||
println!("package.json not found");
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
VersionBlock::new(" npm", get_version("npm", &[]).unwrap_or_default()).display();
|
||||
VersionBlock::new(" pnpm", get_version("pnpm", &[]).unwrap_or_default()).display();
|
||||
VersionBlock::new(" yarn", get_version("yarn", &[]).unwrap_or_default()).display();
|
||||
}
|
||||
|
||||
InfoBlock::new("Rust environment").section().display();
|
||||
VersionBlock::new(
|
||||
" rustc",
|
||||
get_version("rustc", &[]).unwrap_or_default().map(|v| {
|
||||
let mut s = v.split(' ');
|
||||
s.next();
|
||||
s.next().unwrap().to_string()
|
||||
}),
|
||||
)
|
||||
.display();
|
||||
VersionBlock::new(
|
||||
" cargo",
|
||||
get_version("cargo", &[]).unwrap_or_default().map(|v| {
|
||||
let mut s = v.split(' ');
|
||||
s.next();
|
||||
s.next().unwrap().to_string()
|
||||
}),
|
||||
)
|
||||
.display();
|
||||
|
||||
InfoBlock::new("Rust environment").section().display();
|
||||
VersionBlock::new(
|
||||
" rustup",
|
||||
get_version("rustup", &[]).unwrap_or_default().map(|v| {
|
||||
let mut s = v.split(' ');
|
||||
s.next();
|
||||
s.next().unwrap().to_string()
|
||||
}),
|
||||
)
|
||||
.display();
|
||||
VersionBlock::new(
|
||||
" rustc",
|
||||
get_version("rustc", &[]).unwrap_or_default().map(|v| {
|
||||
let mut s = v.split(' ');
|
||||
s.next();
|
||||
s.next().unwrap().to_string()
|
||||
}),
|
||||
)
|
||||
.display();
|
||||
VersionBlock::new(
|
||||
" cargo",
|
||||
get_version("cargo", &[]).unwrap_or_default().map(|v| {
|
||||
let mut s = v.split(' ');
|
||||
s.next();
|
||||
s.next().unwrap().to_string()
|
||||
}),
|
||||
)
|
||||
.display();
|
||||
VersionBlock::new(
|
||||
" toolchain",
|
||||
get_active_rust_toolchain().unwrap_or_default(),
|
||||
)
|
||||
.display();
|
||||
|
||||
if let Some(app_dir) = app_dir {
|
||||
InfoBlock::new("App directory structure")
|
||||
.section()
|
||||
.display();
|
||||
for entry in read_dir(app_dir)? {
|
||||
let entry = entry?;
|
||||
if entry.path().is_dir() {
|
||||
println!("/{}", entry.path().file_name().unwrap().to_string_lossy());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
InfoBlock::new("App").section().display();
|
||||
let tauri_dir = tauri_dir();
|
||||
let manifest: Option<CargoManifest> =
|
||||
if let Ok(manifest_contents) = read_to_string(tauri_dir.join("Cargo.toml")) {
|
||||
toml::from_str(&manifest_contents).ok()
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let lock: Option<CargoLock> =
|
||||
if let Ok(lock_contents) = read_to_string(tauri_dir.join("Cargo.lock")) {
|
||||
toml::from_str(&lock_contents).ok()
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let tauri_lock_packages: Vec<CargoLockPackage> = lock
|
||||
.as_ref()
|
||||
.map(|lock| {
|
||||
lock
|
||||
.package
|
||||
.iter()
|
||||
.filter(|p| p.name == "tauri")
|
||||
.cloned()
|
||||
.collect()
|
||||
})
|
||||
.unwrap_or_default();
|
||||
let (tauri_version_string, found_tauri_versions) =
|
||||
match (&manifest, &lock, tauri_lock_packages.len()) {
|
||||
(Some(_manifest), Some(_lock), 1) => {
|
||||
let tauri_lock_package = tauri_lock_packages.first().unwrap();
|
||||
(
|
||||
tauri_lock_package.version.clone(),
|
||||
vec![tauri_lock_package.version.clone()],
|
||||
)
|
||||
}
|
||||
(None, Some(_lock), 1) => {
|
||||
let tauri_lock_package = tauri_lock_packages.first().unwrap();
|
||||
(
|
||||
format!("{} (no manifest)", tauri_lock_package.version),
|
||||
vec![tauri_lock_package.version.clone()],
|
||||
)
|
||||
}
|
||||
_ => {
|
||||
let mut found_tauri_versions = Vec::new();
|
||||
let manifest_version = match manifest.and_then(|m| m.dependencies.get("tauri").cloned()) {
|
||||
Some(tauri) => match tauri {
|
||||
CargoManifestDependency::Version(v) => {
|
||||
found_tauri_versions.push(v.clone());
|
||||
v
|
||||
}
|
||||
CargoManifestDependency::Package(p) => {
|
||||
if let Some(v) = p.version {
|
||||
found_tauri_versions.push(v.clone());
|
||||
v
|
||||
} else if let Some(p) = p.path {
|
||||
let manifest_path = tauri_dir.join(&p).join("Cargo.toml");
|
||||
let v = match read_to_string(&manifest_path)
|
||||
.map_err(|_| ())
|
||||
.and_then(|m| toml::from_str::<CargoManifest>(&m).map_err(|_| ()))
|
||||
{
|
||||
Ok(manifest) => manifest.package.version,
|
||||
Err(_) => "unknown version".to_string(),
|
||||
};
|
||||
format!("path:{:?} [{}]", p, v)
|
||||
} else {
|
||||
"unknown manifest".to_string()
|
||||
}
|
||||
}
|
||||
},
|
||||
None => "no manifest".to_string(),
|
||||
};
|
||||
|
||||
let lock_version = match (lock, tauri_lock_packages.is_empty()) {
|
||||
(Some(_lock), true) => tauri_lock_packages
|
||||
.iter()
|
||||
.map(|p| p.version.clone())
|
||||
.collect::<Vec<String>>()
|
||||
.join(", "),
|
||||
(Some(_lock), false) => "unknown lockfile".to_string(),
|
||||
_ => "no lockfile".to_string(),
|
||||
};
|
||||
|
||||
(
|
||||
format!("{} ({})", manifest_version, lock_version),
|
||||
found_tauri_versions,
|
||||
)
|
||||
}
|
||||
};
|
||||
|
||||
let tauri_version = found_tauri_versions
|
||||
.into_iter()
|
||||
.map(|v| semver::Version::parse(&v).unwrap())
|
||||
.max();
|
||||
let suffix = match (tauri_version, crate_latest_version("tauri")) {
|
||||
(Some(version), Some(target_version)) => {
|
||||
let target_version = semver::Version::parse(&target_version).unwrap();
|
||||
if version < target_version {
|
||||
Some(format!(" (outdated, latest: {})", target_version))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
_ => None,
|
||||
};
|
||||
InfoBlock::new(" tauri.rs")
|
||||
.value(tauri_version_string)
|
||||
.suffix(suffix)
|
||||
.display();
|
||||
|
||||
if let Ok(config) = get_config(None) {
|
||||
let config_guard = config.lock().unwrap();
|
||||
let config = config_guard.as_ref().unwrap();
|
||||
InfoBlock::new(" build-type")
|
||||
.value(if config.tauri.bundle.active {
|
||||
"bundle".to_string()
|
||||
} else {
|
||||
"build".to_string()
|
||||
})
|
||||
.display();
|
||||
InfoBlock::new(" CSP")
|
||||
.value(if let Some(security) = &config.tauri.security {
|
||||
security.csp.clone().unwrap_or_else(|| "unset".to_string())
|
||||
} else {
|
||||
"unset".to_string()
|
||||
})
|
||||
.display();
|
||||
InfoBlock::new(" distDir")
|
||||
.value(config.build.dist_dir.to_string())
|
||||
.display();
|
||||
InfoBlock::new(" devPath")
|
||||
.value(config.build.dev_path.to_string())
|
||||
.display();
|
||||
}
|
||||
|
||||
if let Some(app_dir) = app_dir {
|
||||
if let Ok(package_json) = read_to_string(app_dir.join("package.json")) {
|
||||
let (framework, bundler) = infer_framework(&package_json);
|
||||
if let Some(framework) = framework {
|
||||
InfoBlock::new(" framework")
|
||||
.value(framework.to_string())
|
||||
.display();
|
||||
}
|
||||
if let Some(bundler) = bundler {
|
||||
InfoBlock::new(" bundler")
|
||||
.value(bundler.to_string())
|
||||
.display();
|
||||
}
|
||||
} else {
|
||||
println!("package.json not found");
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn get_package_manager<T: AsRef<str>>(file_names: &[T]) -> crate::Result<PackageManager> {
|
||||
@ -771,9 +792,9 @@ fn get_package_manager<T: AsRef<str>>(file_names: &[T]) -> crate::Result<Package
|
||||
|
||||
if found.len() > 1 {
|
||||
return Err(anyhow::anyhow!(
|
||||
"only one package mangager should be used, but found {}\nplease remove unused package manager lock files",
|
||||
found.join(" and ")
|
||||
));
|
||||
"only one package mangager should be used, but found {}\nplease remove unused package manager lock files",
|
||||
found.join(" and ")
|
||||
));
|
||||
}
|
||||
|
||||
if use_npm {
|
||||
@ -784,70 +805,3 @@ fn get_package_manager<T: AsRef<str>>(file_names: &[T]) -> crate::Result<Package
|
||||
Ok(PackageManager::Yarn)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::info::get_package_manager;
|
||||
|
||||
#[test]
|
||||
fn no_package_manager_lock_file() -> crate::Result<()> {
|
||||
let file_names = vec!["package.json"];
|
||||
let pm = get_package_manager(&file_names);
|
||||
match pm {
|
||||
Ok(_) => Ok(()),
|
||||
Err(m) => Err(m),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn package_managers_npm_and_yarn() -> crate::Result<()> {
|
||||
let file_names = vec!["package.json", "package-lock.json", "yarn.lock"];
|
||||
let pm = get_package_manager(&file_names);
|
||||
match pm {
|
||||
Ok(_) => panic!("expected error"),
|
||||
Err(m) => assert_eq!(
|
||||
m.to_string().as_str(),
|
||||
"only one package mangager should be used, but found npm and yarn\nplease remove unused package manager lock files"
|
||||
),
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn package_managers_npm_and_pnpm() -> crate::Result<()> {
|
||||
let file_names = vec!["package.json", "package-lock.json", "pnpm-lock.yaml"];
|
||||
let pm = get_package_manager(&file_names);
|
||||
match pm {
|
||||
Ok(_) => panic!("expected error"),
|
||||
Err(m) => assert_eq!(
|
||||
m.to_string().as_str(),
|
||||
"only one package mangager should be used, but found npm and pnpm\nplease remove unused package manager lock files"
|
||||
),
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn package_managers_pnpm_and_yarn() -> crate::Result<()> {
|
||||
let file_names = vec!["package.json", "pnpm-lock.yaml", "yarn.lock"];
|
||||
let pm = get_package_manager(&file_names);
|
||||
match pm {
|
||||
Ok(_) => panic!("expected error"),
|
||||
Err(m) => assert_eq!(
|
||||
m.to_string().as_str(),
|
||||
"only one package mangager should be used, but found pnpm and yarn\nplease remove unused package manager lock files"
|
||||
),
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn package_managers_yarn() -> crate::Result<()> {
|
||||
let file_names = vec!["package.json", "yarn.lock"];
|
||||
let pm = get_package_manager(&file_names);
|
||||
match pm {
|
||||
Ok(_) => Ok(()),
|
||||
Err(m) => Err(m),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,144 +2,205 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
use std::{collections::BTreeMap, env::current_dir, fs::remove_dir_all, path::PathBuf};
|
||||
|
||||
use crate::{
|
||||
helpers::{resolve_tauri_path, template, Logger},
|
||||
helpers::{
|
||||
framework::{infer_from_package_json as infer_framework, Framework},
|
||||
resolve_tauri_path, template, Logger,
|
||||
},
|
||||
VersionMetadata,
|
||||
};
|
||||
use std::{
|
||||
collections::BTreeMap,
|
||||
env::current_dir,
|
||||
fmt::Display,
|
||||
fs::{read_to_string, remove_dir_all},
|
||||
path::PathBuf,
|
||||
str::FromStr,
|
||||
};
|
||||
|
||||
use crate::Result;
|
||||
use anyhow::Context;
|
||||
use clap::Parser;
|
||||
use dialoguer::Input;
|
||||
use handlebars::{to_json, Handlebars};
|
||||
use include_dir::{include_dir, Dir};
|
||||
use serde::Deserialize;
|
||||
|
||||
const TEMPLATE_DIR: Dir<'_> = include_dir!("templates/app");
|
||||
|
||||
pub struct Init {
|
||||
#[derive(Debug, Parser)]
|
||||
#[clap(about = "Initializes a Tauri project")]
|
||||
pub struct Options {
|
||||
/// Skip prompting for values
|
||||
#[clap(long)]
|
||||
ci: bool,
|
||||
/// Force init to overwrite the src-tauri folder
|
||||
#[clap(short, long)]
|
||||
force: bool,
|
||||
directory: PathBuf,
|
||||
/// Enables logging
|
||||
#[clap(short, long)]
|
||||
log: bool,
|
||||
/// Set target directory for init
|
||||
#[clap(short, long)]
|
||||
#[clap(default_value_t = current_dir().expect("failed to read cwd").display().to_string())]
|
||||
directory: String,
|
||||
/// Path of the Tauri project to use (relative to the cwd)
|
||||
#[clap(short, long)]
|
||||
tauri_path: Option<PathBuf>,
|
||||
/// Name of your Tauri application
|
||||
#[clap(short = 'A', long)]
|
||||
app_name: Option<String>,
|
||||
/// Window title of your Tauri application
|
||||
#[clap(short = 'W', long)]
|
||||
window_title: Option<String>,
|
||||
/// Web assets location, relative to <project-dir>/src-tauri
|
||||
#[clap(short = 'D', long)]
|
||||
dist_dir: Option<String>,
|
||||
/// Url of your dev server
|
||||
#[clap(short = 'P', long)]
|
||||
dev_path: Option<String>,
|
||||
}
|
||||
|
||||
impl Default for Init {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
force: false,
|
||||
directory: current_dir().expect("failed to read cwd"),
|
||||
tauri_path: None,
|
||||
app_name: None,
|
||||
window_title: None,
|
||||
dist_dir: None,
|
||||
dev_path: None,
|
||||
}
|
||||
}
|
||||
#[derive(Deserialize)]
|
||||
struct PackageJson {
|
||||
name: Option<String>,
|
||||
product_name: Option<String>,
|
||||
}
|
||||
|
||||
impl Init {
|
||||
pub fn new() -> Self {
|
||||
Default::default()
|
||||
}
|
||||
#[derive(Default)]
|
||||
struct InitDefaults {
|
||||
app_name: Option<String>,
|
||||
framework: Option<Framework>,
|
||||
}
|
||||
|
||||
pub fn force(mut self) -> Self {
|
||||
self.force = true;
|
||||
self
|
||||
}
|
||||
impl Options {
|
||||
fn load(mut self) -> Result<Self> {
|
||||
self.ci = self.ci || std::env::var("CI").is_ok();
|
||||
let package_json_path = PathBuf::from(&self.directory).join("package.json");
|
||||
|
||||
pub fn directory(mut self, directory: impl Into<PathBuf>) -> Self {
|
||||
self.directory = directory.into();
|
||||
self
|
||||
}
|
||||
|
||||
pub fn tauri_path(mut self, tauri_path: impl Into<PathBuf>) -> Self {
|
||||
self.tauri_path = Some(tauri_path.into());
|
||||
self
|
||||
}
|
||||
|
||||
pub fn app_name(mut self, app_name: impl Into<String>) -> Self {
|
||||
self.app_name = Some(app_name.into());
|
||||
self
|
||||
}
|
||||
|
||||
pub fn window_title(mut self, window_title: impl Into<String>) -> Self {
|
||||
self.window_title = Some(window_title.into());
|
||||
self
|
||||
}
|
||||
|
||||
pub fn dist_dir(mut self, dist_dir: impl Into<String>) -> Self {
|
||||
self.dist_dir = Some(dist_dir.into());
|
||||
self
|
||||
}
|
||||
|
||||
pub fn dev_path(mut self, dev_path: impl Into<String>) -> Self {
|
||||
self.dev_path = Some(dev_path.into());
|
||||
self
|
||||
}
|
||||
|
||||
pub fn run(self) -> crate::Result<()> {
|
||||
let logger = Logger::new("tauri:init");
|
||||
let template_target_path = self.directory.join("src-tauri");
|
||||
let metadata = serde_json::from_str::<VersionMetadata>(include_str!("../metadata.json"))?;
|
||||
if template_target_path.exists() && !self.force {
|
||||
logger.warn(format!(
|
||||
"Tauri dir ({:?}) not empty. Run `init --force` to overwrite.",
|
||||
template_target_path
|
||||
));
|
||||
let init_defaults = if package_json_path.exists() {
|
||||
let package_json_text = read_to_string(package_json_path)?;
|
||||
let package_json: PackageJson = serde_json::from_str(&package_json_text)?;
|
||||
let (framework, _) = infer_framework(&package_json_text);
|
||||
InitDefaults {
|
||||
app_name: package_json.product_name.or(package_json.name),
|
||||
framework,
|
||||
}
|
||||
} else {
|
||||
let (tauri_dep, tauri_build_dep) = if let Some(tauri_path) = self.tauri_path {
|
||||
(
|
||||
format!(
|
||||
r#"{{ path = {:?}, features = [ "api-all" ] }}"#,
|
||||
resolve_tauri_path(&tauri_path, "core/tauri")
|
||||
),
|
||||
format!(
|
||||
"{{ path = {:?} }}",
|
||||
resolve_tauri_path(&tauri_path, "core/tauri-build")
|
||||
),
|
||||
)
|
||||
} else {
|
||||
(
|
||||
format!(
|
||||
r#"{{ version = "{}", features = [ "api-all" ] }}"#,
|
||||
metadata.tauri
|
||||
),
|
||||
format!(r#"{{ version = "{}" }}"#, metadata.tauri_build),
|
||||
)
|
||||
};
|
||||
Default::default()
|
||||
};
|
||||
|
||||
let _ = remove_dir_all(&template_target_path);
|
||||
let handlebars = Handlebars::new();
|
||||
self.app_name = self.app_name.or(request_input(
|
||||
"What is your app name?",
|
||||
init_defaults.app_name.clone(),
|
||||
self.ci,
|
||||
)?);
|
||||
|
||||
let mut data = BTreeMap::new();
|
||||
data.insert("tauri_dep", to_json(tauri_dep));
|
||||
data.insert("tauri_build_dep", to_json(tauri_build_dep));
|
||||
data.insert(
|
||||
"dist_dir",
|
||||
to_json(self.dist_dir.unwrap_or_else(|| "../dist".to_string())),
|
||||
);
|
||||
data.insert(
|
||||
"dev_path",
|
||||
to_json(
|
||||
self
|
||||
.dev_path
|
||||
.unwrap_or_else(|| "http://localhost:4000".to_string()),
|
||||
),
|
||||
);
|
||||
data.insert(
|
||||
"app_name",
|
||||
to_json(self.app_name.unwrap_or_else(|| "Tauri App".to_string())),
|
||||
);
|
||||
data.insert(
|
||||
"window_title",
|
||||
to_json(self.window_title.unwrap_or_else(|| "Tauri".to_string())),
|
||||
);
|
||||
self.window_title = self.window_title.or(request_input(
|
||||
"What should the window title be?",
|
||||
init_defaults.app_name.clone(),
|
||||
self.ci,
|
||||
)?);
|
||||
|
||||
template::render(&handlebars, &data, &TEMPLATE_DIR, &self.directory)
|
||||
.with_context(|| "failed to render Tauri template")?;
|
||||
}
|
||||
self.dist_dir = self.dist_dir
|
||||
.or(request_input(
|
||||
r#"Whe re are your web assets (HTML/CSS/JS) located, relative to the "<current dir>/src-tauri/tauri.conf.json" file that will be created?"#,
|
||||
init_defaults.framework.as_ref().map(|f| f.dist_dir()),
|
||||
self.ci)?);
|
||||
|
||||
Ok(())
|
||||
self.dev_path = self.dev_path.or(request_input(
|
||||
"What is the url of your dev server?",
|
||||
init_defaults.framework.map(|f| f.dev_path()),
|
||||
self.ci,
|
||||
)?);
|
||||
|
||||
Ok(self)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn command(mut options: Options) -> Result<()> {
|
||||
options = options.load()?;
|
||||
let logger = Logger::new("tauri:init");
|
||||
|
||||
let template_target_path = PathBuf::from(&options.directory).join("src-tauri");
|
||||
let metadata = serde_json::from_str::<VersionMetadata>(include_str!("../metadata.json"))?;
|
||||
|
||||
if template_target_path.exists() && !options.force {
|
||||
logger.warn(format!(
|
||||
"Tauri dir ({:?}) not empty. Run `init --force` to overwrite.",
|
||||
template_target_path
|
||||
));
|
||||
} else {
|
||||
let (tauri_dep, tauri_build_dep) = if let Some(tauri_path) = options.tauri_path {
|
||||
(
|
||||
format!(
|
||||
r#"{{ path = {:?}, features = [ "api-all" ] }}"#,
|
||||
resolve_tauri_path(&tauri_path, "core/tauri")
|
||||
),
|
||||
format!(
|
||||
"{{ path = {:?} }}",
|
||||
resolve_tauri_path(&tauri_path, "core/tauri-build")
|
||||
),
|
||||
)
|
||||
} else {
|
||||
(
|
||||
format!(
|
||||
r#"{{ version = "{}", features = [ "api-all" ] }}"#,
|
||||
metadata.tauri
|
||||
),
|
||||
format!(r#"{{ version = "{}" }}"#, metadata.tauri_build),
|
||||
)
|
||||
};
|
||||
|
||||
let _ = remove_dir_all(&template_target_path);
|
||||
let handlebars = Handlebars::new();
|
||||
|
||||
let mut data = BTreeMap::new();
|
||||
data.insert("tauri_dep", to_json(tauri_dep));
|
||||
data.insert("tauri_build_dep", to_json(tauri_build_dep));
|
||||
data.insert(
|
||||
"dist_dir",
|
||||
to_json(options.dist_dir.unwrap_or_else(|| "../dist".to_string())),
|
||||
);
|
||||
data.insert(
|
||||
"dev_path",
|
||||
to_json(
|
||||
options
|
||||
.dev_path
|
||||
.unwrap_or_else(|| "http://localhost:4000".to_string()),
|
||||
),
|
||||
);
|
||||
data.insert(
|
||||
"app_name",
|
||||
to_json(options.app_name.unwrap_or_else(|| "Tauri App".to_string())),
|
||||
);
|
||||
data.insert(
|
||||
"window_title",
|
||||
to_json(options.window_title.unwrap_or_else(|| "Tauri".to_string())),
|
||||
);
|
||||
|
||||
template::render(&handlebars, &data, &TEMPLATE_DIR, &options.directory)
|
||||
.with_context(|| "failed to render Tauri template")?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn request_input<T>(prompt: &str, default: Option<T>, skip: bool) -> Result<Option<T>>
|
||||
where
|
||||
T: Clone + FromStr + Display,
|
||||
T::Err: Display + std::fmt::Debug,
|
||||
{
|
||||
if skip {
|
||||
Ok(default)
|
||||
} else {
|
||||
let mut builder = Input::new();
|
||||
builder.with_prompt(prompt);
|
||||
|
||||
if let Some(v) = default {
|
||||
builder.default(v);
|
||||
}
|
||||
|
||||
builder.interact_text().map(Some).map_err(Into::into)
|
||||
}
|
||||
}
|
||||
|
@ -358,12 +358,12 @@ pub fn get_workspace_dir(current_dir: &Path) -> PathBuf {
|
||||
}
|
||||
Err(e) => {
|
||||
logger.warn(format!(
|
||||
"Found `{}`, which may define a parent workspace, but \
|
||||
failed to parse it. If this is indeed a parent workspace, undefined behavior may occur: \
|
||||
\n {:#}",
|
||||
dir.display(),
|
||||
e
|
||||
));
|
||||
"Found `{}`, which may define a parent workspace, but \
|
||||
failed to parse it. If this is indeed a parent workspace, undefined behavior may occur: \
|
||||
\n {:#}",
|
||||
dir.display(),
|
||||
e
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,9 +3,6 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pub use anyhow::Result;
|
||||
use clap::{crate_version, load_yaml, App, AppSettings, ArgMatches};
|
||||
use dialoguer::Input;
|
||||
use serde::Deserialize;
|
||||
|
||||
mod build;
|
||||
mod dev;
|
||||
@ -14,324 +11,74 @@ mod info;
|
||||
mod init;
|
||||
mod interface;
|
||||
mod plugin;
|
||||
mod sign;
|
||||
mod signer;
|
||||
|
||||
use helpers::framework::{infer_from_package_json as infer_framework, Framework};
|
||||
use clap::{AppSettings, FromArgMatches, IntoApp, Parser, Subcommand};
|
||||
|
||||
use std::{env::current_dir, fs::read_to_string, path::PathBuf};
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[derive(serde::Deserialize)]
|
||||
pub struct VersionMetadata {
|
||||
tauri: String,
|
||||
#[serde(rename = "tauri-build")]
|
||||
tauri_build: String,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct PackageJson {
|
||||
name: Option<String>,
|
||||
product_name: Option<String>,
|
||||
#[derive(Parser)]
|
||||
#[clap(author, version, about, bin_name("cargo tauri"))]
|
||||
#[clap(global_setting(AppSettings::PropagateVersion))]
|
||||
#[clap(global_setting(AppSettings::UseLongFormatForHelpSubcommand))]
|
||||
#[clap(setting(AppSettings::SubcommandRequiredElseHelp))]
|
||||
struct Cli {
|
||||
#[clap(subcommand)]
|
||||
command: Commands,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct InitDefaults {
|
||||
app_name: Option<String>,
|
||||
framework: Option<Framework>,
|
||||
#[derive(Subcommand)]
|
||||
enum Commands {
|
||||
Build(build::Options),
|
||||
Dev(dev::Options),
|
||||
Info(info::Options),
|
||||
Init(init::Options),
|
||||
Plugin(plugin::Cli),
|
||||
Signer(signer::Cli),
|
||||
}
|
||||
|
||||
macro_rules! value_or_prompt {
|
||||
($init_runner: ident, $setter_fn: ident, $value: ident, $ci: ident, $prompt_message: expr, $prompt_default: expr) => {{
|
||||
let mut init_runner = $init_runner;
|
||||
if let Some(value) = $value {
|
||||
init_runner = init_runner.$setter_fn(value);
|
||||
} else if !$ci {
|
||||
let mut builder = Input::<String>::new();
|
||||
builder.with_prompt($prompt_message);
|
||||
if let Some(default) = $prompt_default {
|
||||
builder.default(default);
|
||||
}
|
||||
let input = builder.interact_text()?;
|
||||
init_runner = init_runner.$setter_fn(input);
|
||||
}
|
||||
init_runner
|
||||
}};
|
||||
}
|
||||
|
||||
fn get_config(config: &str) -> Result<String> {
|
||||
if config.starts_with('{') {
|
||||
Ok(config.into())
|
||||
} else {
|
||||
std::fs::read_to_string(&config).map_err(Into::into)
|
||||
}
|
||||
}
|
||||
|
||||
fn plugin_command(matches: &ArgMatches) -> Result<()> {
|
||||
if let Some(matches) = matches.subcommand_matches("init") {
|
||||
let api = matches.is_present("api");
|
||||
let plugin_name = matches.value_of("name").expect("name is required");
|
||||
let directory = matches.value_of("directory");
|
||||
let tauri_path = matches.value_of("tauri-path");
|
||||
let tauri = matches.is_present("tauri");
|
||||
let author = matches
|
||||
.value_of("author")
|
||||
.map(|p| p.to_string())
|
||||
.unwrap_or_else(|| {
|
||||
if tauri {
|
||||
"Tauri Programme within The Commons Conservancy".into()
|
||||
} else {
|
||||
"You".into()
|
||||
}
|
||||
});
|
||||
|
||||
let mut plugin_runner = plugin::Plugin::new()
|
||||
.plugin_name(plugin_name.to_string())
|
||||
.author(author);
|
||||
|
||||
if api {
|
||||
plugin_runner = plugin_runner.api();
|
||||
}
|
||||
if tauri {
|
||||
plugin_runner = plugin_runner.tauri();
|
||||
}
|
||||
if let Some(directory) = directory {
|
||||
plugin_runner = plugin_runner.directory(directory);
|
||||
}
|
||||
if let Some(tauri_path) = tauri_path {
|
||||
plugin_runner = plugin_runner.tauri_path(tauri_path);
|
||||
}
|
||||
|
||||
plugin_runner.run()
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn init_command(matches: &ArgMatches) -> Result<()> {
|
||||
let force = matches.is_present("force");
|
||||
let directory = matches.value_of("directory");
|
||||
let tauri_path = matches.value_of("tauri-path");
|
||||
let app_name = matches.value_of("app-name");
|
||||
let window_title = matches.value_of("window-title");
|
||||
let dist_dir = matches.value_of("dist-dir");
|
||||
let dev_path = matches.value_of("dev-path");
|
||||
let ci = matches.is_present("ci") || std::env::var("CI").is_ok();
|
||||
|
||||
let mut init_runner = init::Init::new();
|
||||
if force {
|
||||
init_runner = init_runner.force();
|
||||
}
|
||||
let base_directory = if let Some(directory) = directory {
|
||||
init_runner = init_runner.directory(directory);
|
||||
PathBuf::from(directory)
|
||||
} else {
|
||||
current_dir().expect("failed to read cwd")
|
||||
};
|
||||
if let Some(tauri_path) = tauri_path {
|
||||
init_runner = init_runner.tauri_path(tauri_path);
|
||||
}
|
||||
|
||||
let package_json_path = base_directory.join("package.json");
|
||||
let init_defaults = if package_json_path.exists() {
|
||||
let package_json_text = read_to_string(package_json_path)?;
|
||||
let package_json: PackageJson = serde_json::from_str(&package_json_text)?;
|
||||
let (framework, _) = infer_framework(&package_json_text);
|
||||
InitDefaults {
|
||||
app_name: package_json.product_name.or(package_json.name),
|
||||
framework,
|
||||
}
|
||||
} else {
|
||||
Default::default()
|
||||
};
|
||||
|
||||
init_runner = value_or_prompt!(
|
||||
init_runner,
|
||||
app_name,
|
||||
app_name,
|
||||
ci,
|
||||
"What is your app name?",
|
||||
init_defaults.app_name.clone()
|
||||
);
|
||||
init_runner = value_or_prompt!(
|
||||
init_runner,
|
||||
window_title,
|
||||
window_title,
|
||||
ci,
|
||||
"What should the window title be?",
|
||||
init_defaults.app_name.clone()
|
||||
);
|
||||
init_runner = value_or_prompt!(
|
||||
init_runner,
|
||||
dist_dir,
|
||||
dist_dir,
|
||||
ci,
|
||||
r#"Where are your web assets (HTML/CSS/JS) located, relative to the "<current dir>/src-tauri/tauri.conf.json" file that will be created?"#,
|
||||
init_defaults.framework.as_ref().map(|f| f.dist_dir())
|
||||
);
|
||||
init_runner = value_or_prompt!(
|
||||
init_runner,
|
||||
dev_path,
|
||||
dev_path,
|
||||
ci,
|
||||
"What is the url of your dev server?",
|
||||
init_defaults.framework.map(|f| f.dev_path())
|
||||
);
|
||||
|
||||
init_runner.run()
|
||||
}
|
||||
|
||||
fn dev_command(matches: &ArgMatches) -> Result<()> {
|
||||
let runner = matches.value_of("runner");
|
||||
let target = matches.value_of("target");
|
||||
let features: Vec<String> = matches
|
||||
.values_of("features")
|
||||
.map(|a| a.into_iter().map(|v| v.to_string()).collect())
|
||||
.unwrap_or_default();
|
||||
let exit_on_panic = matches.is_present("exit-on-panic");
|
||||
let config = matches.value_of("config");
|
||||
let args: Vec<String> = matches
|
||||
.values_of("args")
|
||||
.map(|a| a.into_iter().map(|v| v.to_string()).collect())
|
||||
.unwrap_or_default();
|
||||
let release_mode = matches.is_present("release");
|
||||
|
||||
let mut dev_runner = dev::Dev::new()
|
||||
.exit_on_panic(exit_on_panic)
|
||||
.args(args)
|
||||
.features(features)
|
||||
.release_mode(release_mode);
|
||||
|
||||
if let Some(runner) = runner {
|
||||
dev_runner = dev_runner.runner(runner.to_string());
|
||||
}
|
||||
if let Some(target) = target {
|
||||
dev_runner = dev_runner.target(target.to_string());
|
||||
}
|
||||
if let Some(config) = config {
|
||||
dev_runner = dev_runner.config(get_config(config)?);
|
||||
}
|
||||
|
||||
dev_runner.run()
|
||||
}
|
||||
|
||||
fn build_command(matches: &ArgMatches) -> Result<()> {
|
||||
let runner = matches.value_of("runner");
|
||||
let target = matches.value_of("target");
|
||||
let features: Vec<String> = matches
|
||||
.values_of("features")
|
||||
.map(|a| a.into_iter().map(|v| v.to_string()).collect())
|
||||
.unwrap_or_default();
|
||||
let debug = matches.is_present("debug");
|
||||
let verbose = matches.is_present("verbose");
|
||||
let bundles = matches.values_of_lossy("bundle");
|
||||
let config = matches.value_of("config");
|
||||
|
||||
let mut build_runner = build::Build::new().features(features);
|
||||
if let Some(runner) = runner {
|
||||
build_runner = build_runner.runner(runner.to_string());
|
||||
}
|
||||
if let Some(target) = target {
|
||||
build_runner = build_runner.target(target.to_string());
|
||||
}
|
||||
if debug {
|
||||
build_runner = build_runner.debug();
|
||||
}
|
||||
if verbose {
|
||||
build_runner = build_runner.verbose();
|
||||
}
|
||||
if let Some(bundles) = bundles {
|
||||
build_runner = build_runner.bundles(bundles);
|
||||
}
|
||||
if let Some(config) = config {
|
||||
build_runner = build_runner.config(get_config(config)?);
|
||||
}
|
||||
|
||||
build_runner.run()
|
||||
}
|
||||
|
||||
fn info_command() -> Result<()> {
|
||||
info::Info::new().run()
|
||||
}
|
||||
|
||||
fn sign_command(matches: &ArgMatches) -> Result<()> {
|
||||
let private_key = matches.value_of("private-key");
|
||||
let private_key_path = matches.value_of("private-key-path");
|
||||
let file = matches.value_of("sign-file");
|
||||
let password = matches.value_of("password");
|
||||
let no_password = matches.is_present("no-password");
|
||||
let write_keys = matches.value_of("write-keys");
|
||||
let force = matches.is_present("force");
|
||||
|
||||
// generate keypair
|
||||
if matches.is_present("generate") {
|
||||
let mut keygen_runner = sign::KeyGenerator::new();
|
||||
|
||||
if no_password {
|
||||
keygen_runner = keygen_runner.empty_password();
|
||||
}
|
||||
|
||||
if force {
|
||||
keygen_runner = keygen_runner.force();
|
||||
}
|
||||
|
||||
if let Some(write_keys) = write_keys {
|
||||
keygen_runner = keygen_runner.output_path(write_keys);
|
||||
}
|
||||
|
||||
if let Some(password) = password {
|
||||
keygen_runner = keygen_runner.password(password);
|
||||
}
|
||||
|
||||
return keygen_runner.generate_keys();
|
||||
}
|
||||
|
||||
// sign our binary / archive
|
||||
let mut sign_runner = sign::Signer::new();
|
||||
if let Some(private_key) = private_key {
|
||||
sign_runner = sign_runner.private_key(private_key);
|
||||
}
|
||||
|
||||
if let Some(private_key_path) = private_key_path {
|
||||
sign_runner = sign_runner.private_key_path(private_key_path);
|
||||
}
|
||||
|
||||
if let Some(file) = file {
|
||||
sign_runner = sign_runner.file_to_sign(file);
|
||||
}
|
||||
|
||||
if let Some(password) = password {
|
||||
sign_runner = sign_runner.password(password);
|
||||
}
|
||||
|
||||
if no_password {
|
||||
sign_runner = sign_runner.empty_password();
|
||||
}
|
||||
|
||||
sign_runner.run()
|
||||
fn format_error<I: IntoApp>(err: clap::Error) -> clap::Error {
|
||||
let mut app = I::into_app();
|
||||
err.format(&mut app)
|
||||
}
|
||||
|
||||
fn main() -> Result<()> {
|
||||
let yaml = load_yaml!("cli.yml");
|
||||
let app = App::from(yaml)
|
||||
.version(crate_version!())
|
||||
.setting(AppSettings::ArgRequiredElseHelp)
|
||||
.setting(AppSettings::PropagateVersion)
|
||||
.setting(AppSettings::SubcommandRequired)
|
||||
.arg(clap::Arg::new("cargo").hidden(true).possible_value("tauri"));
|
||||
let matches = app.get_matches();
|
||||
let matches = <Cli as IntoApp>::into_app()
|
||||
.arg(clap::Arg::new("cargo").hide(true).possible_value("tauri"))
|
||||
.get_matches();
|
||||
let res = <Cli as FromArgMatches>::from_arg_matches(&matches).map_err(format_error::<Cli>);
|
||||
let cli = match res {
|
||||
Ok(s) => s,
|
||||
Err(e) => e.exit(),
|
||||
};
|
||||
|
||||
if let Some(matches) = matches.subcommand_matches("init") {
|
||||
init_command(matches)?;
|
||||
} else if let Some(matches) = matches.subcommand_matches("plugin") {
|
||||
plugin_command(matches)?;
|
||||
} else if let Some(matches) = matches.subcommand_matches("dev") {
|
||||
dev_command(matches)?;
|
||||
} else if let Some(matches) = matches.subcommand_matches("build") {
|
||||
build_command(matches)?;
|
||||
} else if matches.subcommand_matches("info").is_some() {
|
||||
info_command()?;
|
||||
} else if let Some(matches) = matches.subcommand_matches("sign") {
|
||||
sign_command(matches)?;
|
||||
match cli.command {
|
||||
Commands::Build(options) => build::command(options)?,
|
||||
Commands::Dev(options) => dev::command(options)?,
|
||||
Commands::Info(options) => info::command(options)?,
|
||||
Commands::Init(options) => init::command(options)?,
|
||||
Commands::Plugin(cli) => plugin::command(cli)?,
|
||||
Commands::Signer(cli) => signer::command(cli)?,
|
||||
}
|
||||
|
||||
/*if let Some(matches) = matches.subcommand_matches("dev") {
|
||||
dev::command(matches)?;
|
||||
} else if let Some(matches) = matches.subcommand_matches("build") {
|
||||
build::command(matches)?;
|
||||
} else if let Some(matches) = matches.subcommand_matches("signer") {
|
||||
signer::command(matches)?;
|
||||
} else if let Some(_) = matches.subcommand_matches("info") {
|
||||
info::command()?;
|
||||
} else if let Some(matches) = matches.subcommand_matches("init") {
|
||||
init::command(matches)?;
|
||||
} else if let Some(matches) = matches.subcommand_matches("plugin") {
|
||||
plugin::command(matches)?;
|
||||
}*/
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -2,167 +2,29 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
use crate::{
|
||||
helpers::{resolve_tauri_path, template, Logger},
|
||||
VersionMetadata,
|
||||
};
|
||||
use anyhow::Context;
|
||||
use handlebars::{to_json, Handlebars};
|
||||
use heck::{KebabCase, SnakeCase};
|
||||
use include_dir::{include_dir, Dir};
|
||||
use clap::{AppSettings, Parser, Subcommand};
|
||||
|
||||
use std::{collections::BTreeMap, env::current_dir, fs::remove_dir_all, path::PathBuf};
|
||||
use crate::Result;
|
||||
|
||||
const BACKEND_PLUGIN_DIR: Dir<'_> = include_dir!("templates/plugin/backend");
|
||||
const API_PLUGIN_DIR: Dir<'_> = include_dir!("templates/plugin/with-api");
|
||||
mod init;
|
||||
|
||||
pub struct Plugin {
|
||||
plugin_name: String,
|
||||
api: bool,
|
||||
tauri: bool,
|
||||
directory: PathBuf,
|
||||
tauri_path: Option<PathBuf>,
|
||||
author: String,
|
||||
#[derive(Parser)]
|
||||
#[clap(author, version, about = "Manage Tauri plugins")]
|
||||
#[clap(setting(AppSettings::SubcommandRequiredElseHelp))]
|
||||
pub struct Cli {
|
||||
#[clap(subcommand)]
|
||||
command: Commands,
|
||||
}
|
||||
|
||||
impl Default for Plugin {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
plugin_name: "".into(),
|
||||
api: false,
|
||||
tauri: false,
|
||||
directory: current_dir().expect("failed to read cwd"),
|
||||
tauri_path: None,
|
||||
author: "".into(),
|
||||
}
|
||||
}
|
||||
#[derive(Subcommand)]
|
||||
enum Commands {
|
||||
Init(init::Options),
|
||||
}
|
||||
|
||||
impl Plugin {
|
||||
pub fn new() -> Self {
|
||||
Default::default()
|
||||
pub fn command(cli: Cli) -> Result<()> {
|
||||
match cli.command {
|
||||
Commands::Init(options) => init::command(options)?,
|
||||
}
|
||||
|
||||
pub fn plugin_name(mut self, plugin_name: String) -> Self {
|
||||
self.plugin_name = plugin_name;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn api(mut self) -> Self {
|
||||
self.api = true;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn tauri(mut self) -> Self {
|
||||
self.tauri = true;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn directory(mut self, directory: impl Into<PathBuf>) -> Self {
|
||||
self.directory = directory.into();
|
||||
self
|
||||
}
|
||||
|
||||
pub fn tauri_path(mut self, tauri_path: impl Into<PathBuf>) -> Self {
|
||||
self.tauri_path = Some(tauri_path.into());
|
||||
self
|
||||
}
|
||||
|
||||
pub fn author(mut self, author: String) -> Self {
|
||||
self.author = author;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn run(self) -> crate::Result<()> {
|
||||
let logger = Logger::new("tauri:init:plugin");
|
||||
let template_target_path = self.directory.join(&format!(
|
||||
"tauri-plugin-{}",
|
||||
self.plugin_name.to_kebab_case()
|
||||
));
|
||||
let metadata = serde_json::from_str::<VersionMetadata>(include_str!("../metadata.json"))?;
|
||||
if template_target_path.exists() {
|
||||
logger.warn(format!(
|
||||
"Plugin dir ({:?}) not empty.",
|
||||
template_target_path
|
||||
));
|
||||
} else {
|
||||
let (tauri_dep, tauri_example_dep, tauri_build_dep) =
|
||||
if let Some(tauri_path) = self.tauri_path {
|
||||
(
|
||||
format!(
|
||||
r#"{{ path = {:?} }}"#,
|
||||
resolve_tauri_path(&tauri_path, "core/tauri")
|
||||
),
|
||||
format!(
|
||||
r#"{{ path = {:?}, features = [ "api-all" ] }}"#,
|
||||
resolve_tauri_path(&tauri_path, "core/tauri")
|
||||
),
|
||||
format!(
|
||||
"{{ path = {:?} }}",
|
||||
resolve_tauri_path(&tauri_path, "core/tauri-build")
|
||||
),
|
||||
)
|
||||
} else {
|
||||
(
|
||||
format!(r#"{{ version = "{}" }}"#, metadata.tauri),
|
||||
format!(
|
||||
r#"{{ version = "{}", features = [ "api-all" ] }}"#,
|
||||
metadata.tauri
|
||||
),
|
||||
format!(r#"{{ version = "{}" }}"#, metadata.tauri_build),
|
||||
)
|
||||
};
|
||||
|
||||
let _ = remove_dir_all(&template_target_path);
|
||||
let handlebars = Handlebars::new();
|
||||
|
||||
let mut data = BTreeMap::new();
|
||||
data.insert("plugin_name_original", to_json(&self.plugin_name));
|
||||
data.insert("plugin_name", to_json(self.plugin_name.to_kebab_case()));
|
||||
data.insert(
|
||||
"plugin_name_snake_case",
|
||||
to_json(self.plugin_name.to_snake_case()),
|
||||
);
|
||||
data.insert("tauri_dep", to_json(tauri_dep));
|
||||
data.insert("tauri_example_dep", to_json(tauri_example_dep));
|
||||
data.insert("tauri_build_dep", to_json(tauri_build_dep));
|
||||
data.insert("author", to_json(self.author));
|
||||
|
||||
if self.tauri {
|
||||
data.insert(
|
||||
"license_template",
|
||||
to_json(
|
||||
"// Copyright {20\\d{2}(-20\\d{2})?} Tauri Programme within The Commons Conservancy
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// SPDX-License-Identifier: MIT\n\n"
|
||||
.replace(" ", "")
|
||||
.replace(" //", "//"),
|
||||
),
|
||||
);
|
||||
data.insert(
|
||||
"license_header",
|
||||
to_json(
|
||||
"// Copyright 2019-2021 Tauri Programme within The Commons Conservancy
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// SPDX-License-Identifier: MIT\n\n"
|
||||
.replace(" ", "")
|
||||
.replace(" //", "//"),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
template::render(
|
||||
&handlebars,
|
||||
&data,
|
||||
if self.api {
|
||||
&API_PLUGIN_DIR
|
||||
} else {
|
||||
&BACKEND_PLUGIN_DIR
|
||||
},
|
||||
&template_target_path,
|
||||
)
|
||||
.with_context(|| "failed to render Tauri template")?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
149
tooling/cli.rs/src/plugin/init.rs
Normal file
149
tooling/cli.rs/src/plugin/init.rs
Normal file
@ -0,0 +1,149 @@
|
||||
// Copyright 2019-2021 Tauri Programme within The Commons Conservancy
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
use crate::Result;
|
||||
use crate::{
|
||||
helpers::{resolve_tauri_path, template, Logger},
|
||||
VersionMetadata,
|
||||
};
|
||||
use anyhow::Context;
|
||||
use clap::{ArgSettings, Parser};
|
||||
use handlebars::{to_json, Handlebars};
|
||||
use heck::{KebabCase, SnakeCase};
|
||||
use include_dir::{include_dir, Dir};
|
||||
use std::{collections::BTreeMap, env::current_dir, fs::remove_dir_all, path::PathBuf};
|
||||
|
||||
const BACKEND_PLUGIN_DIR: Dir<'_> = include_dir!("templates/plugin/backend");
|
||||
const API_PLUGIN_DIR: Dir<'_> = include_dir!("templates/plugin/with-api");
|
||||
|
||||
#[derive(Debug, Parser)]
|
||||
#[clap(about = "Initializes a Tauri plugin project")]
|
||||
pub struct Options {
|
||||
/// Name of your Tauri plugin
|
||||
#[clap(short = 'n', long = "name")]
|
||||
plugin_name: String,
|
||||
/// Initializes a Tauri plugin with TypeScript API
|
||||
#[clap(short, long)]
|
||||
api: bool,
|
||||
/// Initializes a Tauri core plugin (internal usage)
|
||||
#[clap(short, long, hide(true))]
|
||||
#[clap(setting(ArgSettings::Hidden))]
|
||||
tauri: bool,
|
||||
/// Set target directory for init
|
||||
#[clap(short, long)]
|
||||
#[clap(default_value_t = current_dir().expect("failed to read cwd").display().to_string())]
|
||||
directory: String,
|
||||
/// Path of the Tauri project to use (relative to the cwd)
|
||||
#[clap(short, long)]
|
||||
tauri_path: Option<PathBuf>,
|
||||
/// Author name
|
||||
#[clap(short, long)]
|
||||
author: Option<String>,
|
||||
}
|
||||
|
||||
impl Options {
|
||||
fn load(&mut self) {
|
||||
if self.author.is_none() {
|
||||
self.author.replace(if self.tauri {
|
||||
"Tauri Programme within The Commons Conservancy".into()
|
||||
} else {
|
||||
"You".into()
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn command(mut options: Options) -> Result<()> {
|
||||
options.load();
|
||||
let logger = Logger::new("tauri:init:plugin");
|
||||
let template_target_path = PathBuf::from(options.directory).join(&format!(
|
||||
"tauri-plugin-{}",
|
||||
options.plugin_name.to_kebab_case()
|
||||
));
|
||||
let metadata = serde_json::from_str::<VersionMetadata>(include_str!("../../metadata.json"))?;
|
||||
if template_target_path.exists() {
|
||||
logger.warn(format!(
|
||||
"Plugin dir ({:?}) not empty.",
|
||||
template_target_path
|
||||
));
|
||||
} else {
|
||||
let (tauri_dep, tauri_example_dep, tauri_build_dep) =
|
||||
if let Some(tauri_path) = options.tauri_path {
|
||||
(
|
||||
format!(
|
||||
r#"{{ path = {:?} }}"#,
|
||||
resolve_tauri_path(&tauri_path, "core/tauri")
|
||||
),
|
||||
format!(
|
||||
r#"{{ path = {:?}, features = [ "api-all" ] }}"#,
|
||||
resolve_tauri_path(&tauri_path, "core/tauri")
|
||||
),
|
||||
format!(
|
||||
"{{ path = {:?} }}",
|
||||
resolve_tauri_path(&tauri_path, "core/tauri-build")
|
||||
),
|
||||
)
|
||||
} else {
|
||||
(
|
||||
format!(r#"{{ version = "{}" }}"#, metadata.tauri),
|
||||
format!(
|
||||
r#"{{ version = "{}", features = [ "api-all" ] }}"#,
|
||||
metadata.tauri
|
||||
),
|
||||
format!(r#"{{ version = "{}" }}"#, metadata.tauri_build),
|
||||
)
|
||||
};
|
||||
|
||||
let _ = remove_dir_all(&template_target_path);
|
||||
let handlebars = Handlebars::new();
|
||||
|
||||
let mut data = BTreeMap::new();
|
||||
data.insert("plugin_name_original", to_json(&options.plugin_name));
|
||||
data.insert("plugin_name", to_json(options.plugin_name.to_kebab_case()));
|
||||
data.insert(
|
||||
"plugin_name_snake_case",
|
||||
to_json(options.plugin_name.to_snake_case()),
|
||||
);
|
||||
data.insert("tauri_dep", to_json(tauri_dep));
|
||||
data.insert("tauri_example_dep", to_json(tauri_example_dep));
|
||||
data.insert("tauri_build_dep", to_json(tauri_build_dep));
|
||||
data.insert("author", to_json(options.author));
|
||||
|
||||
if options.tauri {
|
||||
data.insert(
|
||||
"license_template",
|
||||
to_json(
|
||||
"// Copyright {20\\d{2}(-20\\d{2})?} Tauri Programme within The Commons Conservancy
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// SPDX-License-Identifier: MIT\n\n"
|
||||
.replace(" ", "")
|
||||
.replace(" //", "//"),
|
||||
),
|
||||
);
|
||||
data.insert(
|
||||
"license_header",
|
||||
to_json(
|
||||
"// Copyright 2019-2021 Tauri Programme within The Commons Conservancy
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// SPDX-License-Identifier: MIT\n\n"
|
||||
.replace(" ", "")
|
||||
.replace(" //", "//"),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
template::render(
|
||||
&handlebars,
|
||||
&data,
|
||||
if options.api {
|
||||
&API_PLUGIN_DIR
|
||||
} else {
|
||||
&BACKEND_PLUGIN_DIR
|
||||
},
|
||||
&template_target_path,
|
||||
)
|
||||
.with_context(|| "failed to render Tauri template")?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
@ -1,140 +0,0 @@
|
||||
// Copyright 2019-2021 Tauri Programme within The Commons Conservancy
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
use crate::helpers::updater_signature::{
|
||||
generate_key, read_key_from_file, save_keypair, sign_file,
|
||||
};
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
use anyhow::Context;
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct Signer {
|
||||
private_key: Option<String>,
|
||||
password: Option<String>,
|
||||
file: Option<PathBuf>,
|
||||
}
|
||||
|
||||
impl Signer {
|
||||
pub fn new() -> Self {
|
||||
Default::default()
|
||||
}
|
||||
|
||||
pub fn private_key(mut self, private_key: &str) -> Self {
|
||||
self.private_key = Some(private_key.to_owned());
|
||||
self
|
||||
}
|
||||
|
||||
pub fn password(mut self, password: &str) -> Self {
|
||||
self.password = Some(password.to_owned());
|
||||
self
|
||||
}
|
||||
|
||||
pub fn empty_password(mut self) -> Self {
|
||||
self.password = Some("".to_owned());
|
||||
self
|
||||
}
|
||||
|
||||
pub fn file_to_sign(mut self, file_path: &str) -> Self {
|
||||
self.file = Some(Path::new(file_path).to_path_buf());
|
||||
self
|
||||
}
|
||||
|
||||
pub fn private_key_path(mut self, private_key: &str) -> Self {
|
||||
self.private_key =
|
||||
Some(read_key_from_file(Path::new(private_key)).expect("Unable to extract private key"));
|
||||
self
|
||||
}
|
||||
|
||||
pub fn run(self) -> crate::Result<()> {
|
||||
if self.private_key.is_none() {
|
||||
return Err(anyhow::anyhow!(
|
||||
"Key generation aborted: Unable to find the private key".to_string(),
|
||||
));
|
||||
}
|
||||
|
||||
if self.password.is_none() {
|
||||
return Err(anyhow::anyhow!(
|
||||
"Please use --no-password to set empty password or add --password <password> if your private key have a password.".to_string(),
|
||||
));
|
||||
}
|
||||
|
||||
let (manifest_dir, signature) = sign_file(
|
||||
self.private_key.unwrap(),
|
||||
self.password.unwrap(),
|
||||
self.file.unwrap(),
|
||||
)
|
||||
.with_context(|| "failed to sign file")?;
|
||||
|
||||
println!(
|
||||
"\nYour file was signed successfully, You can find the signature here:\n{}\n\nPublic signature:\n{}\n\nMake sure to include this into the signature field of your update server.",
|
||||
manifest_dir.display(),
|
||||
signature
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct KeyGenerator {
|
||||
password: Option<String>,
|
||||
output_path: Option<PathBuf>,
|
||||
force: bool,
|
||||
}
|
||||
|
||||
impl KeyGenerator {
|
||||
pub fn new() -> Self {
|
||||
Default::default()
|
||||
}
|
||||
|
||||
pub fn empty_password(mut self) -> Self {
|
||||
self.password = Some("".to_owned());
|
||||
self
|
||||
}
|
||||
|
||||
pub fn force(mut self) -> Self {
|
||||
self.force = true;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn password(mut self, password: &str) -> Self {
|
||||
self.password = Some(password.to_owned());
|
||||
self
|
||||
}
|
||||
|
||||
pub fn output_path(mut self, output_path: &str) -> Self {
|
||||
self.output_path = Some(Path::new(output_path).to_path_buf());
|
||||
self
|
||||
}
|
||||
|
||||
pub fn generate_keys(self) -> crate::Result<()> {
|
||||
let keypair = generate_key(self.password).expect("Failed to generate key");
|
||||
|
||||
if let Some(output_path) = self.output_path {
|
||||
let (secret_path, public_path) =
|
||||
save_keypair(self.force, output_path, &keypair.sk, &keypair.pk)
|
||||
.expect("Unable to write keypair");
|
||||
|
||||
println!(
|
||||
"\nYour keypair was generated successfully\nPrivate: {} (Keep it secret!)\nPublic: {}\n---------------------------",
|
||||
secret_path.display(),
|
||||
public_path.display()
|
||||
)
|
||||
} else {
|
||||
println!(
|
||||
"\nYour secret key was generated successfully - Keep it secret!\n{}\n\n",
|
||||
keypair.sk
|
||||
);
|
||||
println!(
|
||||
"Your public key was generated successfully:\n{}\n\nAdd the public key in your tauri.conf.json\n---------------------------\n",
|
||||
keypair.pk
|
||||
);
|
||||
}
|
||||
|
||||
println!("\nEnvironment variabled used to sign:\n`TAURI_PRIVATE_KEY` Path or String of your private key\n`TAURI_KEY_PASSWORD` Your private key password (optional)\n\nATTENTION: If you lose your private key OR password, you'll not be able to sign your update package and updates will not works.\n---------------------------\n");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
31
tooling/cli.rs/src/signer.rs
Normal file
31
tooling/cli.rs/src/signer.rs
Normal file
@ -0,0 +1,31 @@
|
||||
// Copyright 2019-2021 Tauri Programme within The Commons Conservancy
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
use crate::Result;
|
||||
use clap::{AppSettings, Parser, Subcommand};
|
||||
|
||||
mod generate;
|
||||
mod sign;
|
||||
|
||||
#[derive(Parser)]
|
||||
#[clap(author, version, about = "Tauri updater signer")]
|
||||
#[clap(setting(AppSettings::SubcommandRequiredElseHelp))]
|
||||
pub struct Cli {
|
||||
#[clap(subcommand)]
|
||||
command: Commands,
|
||||
}
|
||||
|
||||
#[derive(Subcommand)]
|
||||
enum Commands {
|
||||
Sign(sign::Options),
|
||||
Generate(generate::Options),
|
||||
}
|
||||
|
||||
pub fn command(cli: Cli) -> Result<()> {
|
||||
match cli.command {
|
||||
Commands::Sign(options) => sign::command(options)?,
|
||||
Commands::Generate(options) => generate::command(options)?,
|
||||
}
|
||||
Ok(())
|
||||
}
|
56
tooling/cli.rs/src/signer/generate.rs
Normal file
56
tooling/cli.rs/src/signer/generate.rs
Normal file
@ -0,0 +1,56 @@
|
||||
// Copyright 2019-2021 Tauri Programme within The Commons Conservancy
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
use crate::{
|
||||
helpers::updater_signature::{generate_key, save_keypair},
|
||||
Result,
|
||||
};
|
||||
use clap::Parser;
|
||||
use std::path::PathBuf;
|
||||
|
||||
#[derive(Debug, Parser)]
|
||||
#[clap(about = "Generate keypair to sign files")]
|
||||
pub struct Options {
|
||||
/// Set private key password when signing
|
||||
#[clap(short, long)]
|
||||
password: Option<String>,
|
||||
/// Write private key to a file
|
||||
#[clap(short, long)]
|
||||
write_keys: Option<PathBuf>,
|
||||
/// Overwrite private key even if it exists on the specified path
|
||||
#[clap(short, long)]
|
||||
force: bool,
|
||||
}
|
||||
|
||||
pub fn command(options: Options) -> Result<()> {
|
||||
if options.password.is_none() {
|
||||
println!("Generating new private key without password.")
|
||||
}
|
||||
let keypair = generate_key(options.password).expect("Failed to generate key");
|
||||
|
||||
if let Some(output_path) = options.write_keys {
|
||||
let (secret_path, public_path) =
|
||||
save_keypair(options.force, output_path, &keypair.sk, &keypair.pk)
|
||||
.expect("Unable to write keypair");
|
||||
|
||||
println!(
|
||||
"\nYour keypair was generated successfully\nPrivate: {} (Keep it secret!)\nPublic: {}\n---------------------------",
|
||||
secret_path.display(),
|
||||
public_path.display()
|
||||
)
|
||||
} else {
|
||||
println!(
|
||||
"\nYour secret key was generated successfully - Keep it secret!\n{}\n\n",
|
||||
keypair.sk
|
||||
);
|
||||
println!(
|
||||
"Your public key was generated successfully:\n{}\n\nAdd the public key in your tauri.conf.json\n---------------------------\n",
|
||||
keypair.pk
|
||||
);
|
||||
}
|
||||
|
||||
println!("\nEnvironment variabled used to sign:\n`TAURI_PRIVATE_KEY` Path or String of your private key\n`TAURI_KEY_PASSWORD` Your private key password (optional)\n\nATTENTION: If you lose your private key OR password, you'll not be able to sign your update package and updates will not works.\n---------------------------\n");
|
||||
|
||||
Ok(())
|
||||
}
|
61
tooling/cli.rs/src/signer/sign.rs
Normal file
61
tooling/cli.rs/src/signer/sign.rs
Normal file
@ -0,0 +1,61 @@
|
||||
// Copyright 2019-2021 Tauri Programme within The Commons Conservancy
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
use crate::{
|
||||
helpers::updater_signature::{read_key_from_file, sign_file},
|
||||
Result,
|
||||
};
|
||||
use anyhow::Context;
|
||||
use clap::Parser;
|
||||
|
||||
#[derive(Debug, Parser)]
|
||||
#[clap(about = "Sign a file")]
|
||||
pub struct Options {
|
||||
/// Load the private key from a file
|
||||
#[clap(short = 'k', long, conflicts_with("private_key_path"))]
|
||||
private_key: Option<String>,
|
||||
/// Load the private key from a string
|
||||
#[clap(short = 'f', long, conflicts_with("private_key"))]
|
||||
private_key_path: Option<PathBuf>,
|
||||
/// Set private key password when signing
|
||||
#[clap(short, long)]
|
||||
password: Option<String>,
|
||||
/// Sign the specified file
|
||||
#[clap(short, long)]
|
||||
file: Option<PathBuf>,
|
||||
}
|
||||
|
||||
pub fn command(mut options: Options) -> Result<()> {
|
||||
options.private_key = if let Some(private_key) = options.private_key_path {
|
||||
Some(read_key_from_file(Path::new(&private_key)).expect("Unable to extract private key"))
|
||||
} else {
|
||||
options.private_key
|
||||
};
|
||||
if options.private_key.is_none() {
|
||||
return Err(anyhow::anyhow!(
|
||||
"Key generation aborted: Unable to find the private key".to_string(),
|
||||
));
|
||||
}
|
||||
|
||||
if options.password.is_none() {
|
||||
println!("Signing without password.");
|
||||
}
|
||||
|
||||
let (manifest_dir, signature) = sign_file(
|
||||
options.private_key.unwrap(),
|
||||
options.password.unwrap(),
|
||||
options.file.unwrap(),
|
||||
)
|
||||
.with_context(|| "failed to sign file")?;
|
||||
|
||||
println!(
|
||||
"\nYour file was signed successfully, You can find the signature here:\n{}\n\nPublic signature:\n{}\n\nMake sure to include this into the signature field of your update server.",
|
||||
manifest_dir.display(),
|
||||
signature
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
Loading…
Reference in New Issue
Block a user