* chore(tauri) bump versions to 0.5.0 * fix(tauri) correct dependency versions version updates Co-authored-by: lucasfernog <lucas@tauri.studio>
|
@ -65,6 +65,12 @@ jobs:
|
|||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: install webkit2gtk (ubuntu only)
|
||||
if: matrix.platform == 'ubuntu-latest'
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y webkit2gtk-4.0
|
||||
- run: cargo install --path ./cli/tauri-bundler --force
|
||||
- name: test
|
||||
timeout-minutes: 15
|
||||
run: |
|
||||
|
|
|
@ -8,8 +8,8 @@ IF "%cd%\"=="%~dp0" (
|
|||
)
|
||||
|
||||
rem setup relative paths from root folder
|
||||
set "TAURI_DIST_DIR=%~1tauri\test\fixture\dist"
|
||||
set "TAURI_DIR=%~1tauri\test\fixture\src-tauri"
|
||||
set "TAURI_DIST_DIR=%~1tauri\examples\communication\dist"
|
||||
set "TAURI_DIR=%~1tauri\examples\communication\src-tauri"
|
||||
rem convert relative path to absolute path and re-set it into the enviroment var
|
||||
for /F "delims=" %%F IN ("%TAURI_DIST_DIR%") DO SET "TAURI_DIST_DIR=%%~fF"
|
||||
for /F "delims=" %%F IN ("%TAURI_DIR%") DO SET "TAURI_DIR=%%~fF"
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
Write-Output "Setting up enviromental Variables"
|
||||
# setup relative paths
|
||||
$dist_path = "tauri\test\fixture\dist"
|
||||
$src_path = "tauri\test\fixture\src-tauri"
|
||||
$dist_path = "tauri\examples\communication\dist"
|
||||
$src_path = "tauri\examples\communication\src-tauri"
|
||||
|
||||
# check to see if path variables are directories
|
||||
if ((Test-Path $dist_path -PathType Any) -Or (Test-Path $src_path -PathType Any)) {
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
# Note: Script must be run like this `. .init_env.sh` to setup variables for your current shell
|
||||
# define relative paths
|
||||
|
||||
DistPath='tauri/test/fixture/dist'
|
||||
SrcPath='tauri/test/fixture/src-tauri'
|
||||
DistPath='tauri/examples/communication/dist'
|
||||
SrcPath='tauri/examples/communication/src-tauri'
|
||||
|
||||
echo "Setting up enviroment Variables"
|
||||
|
||||
|
|
|
@ -20,6 +20,9 @@ Tauri is a tool for building tiny, blazing fast binaries for all major desktop p
|
|||
| tauri.js CLI | [![](https://img.shields.io/npm/v/tauri.svg)](https://www.npmjs.com/package/tauri) |✅|✅|✅|
|
||||
| tauri core | [![](https://img.shields.io/crates/v/tauri.svg)](https://crates.io/crates/tauri) |✅|✅|✅|
|
||||
| tauri bundler | [![](https://img.shields.io/crates/v/tauri-bundler.svg)](https://crates.io/crates/tauri-bundler) |✅|✅|✅ |
|
||||
| tauri api | [![](https://img.shields.io/crates/v/tauri-api.svg)](https://crates.io/crates/tauri-api) |✅|✅|✅ |
|
||||
| tauri updater | [![](https://img.shields.io/crates/v/tauri-updater.svg)](https://crates.io/crates/tauri-updater) |✅|✅|✅ |
|
||||
| tauri utils | [![](https://img.shields.io/crates/v/tauri-utils.svg)](https://crates.io/crates/tauri-utils) |✅|✅|✅ |
|
||||
|
||||
## Who Tauri is For
|
||||
Because of the way Tauri has been built and can be extended, developers
|
||||
|
|
|
@ -2,7 +2,7 @@ workspace = {}
|
|||
|
||||
[package]
|
||||
name = "tauri-bundler"
|
||||
version = "0.4.4"
|
||||
version = "0.5.0"
|
||||
authors = ["George Burton <burtonageo@gmail.com>", "Lucas Fernandes Gonçalves Nogueira <lucas@quasar.dev>", "Daniel Thompson-Yvetot <denjell@sfosc.org>", "Tensor Programming <tensordeveloper@gmail.com>"]
|
||||
license = "MIT/Apache-2.0"
|
||||
keywords = ["bundle", "cargo", "tauri"]
|
||||
|
@ -18,7 +18,7 @@ dirs = "2.0.2"
|
|||
error-chain = "0.12"
|
||||
glob = "0.3.0"
|
||||
icns = "0.3"
|
||||
image = "0.22.5"
|
||||
image = "0.23.2"
|
||||
libflate = "0.1"
|
||||
md5 = "0.7.0"
|
||||
msi = "0.2"
|
||||
|
@ -34,7 +34,7 @@ uuid = { version = "0.8", features = ["v5"] }
|
|||
walkdir = "2"
|
||||
|
||||
[target.'cfg(target_os = "windows")'.dependencies]
|
||||
attohttpc = { version = "0.11.1" }
|
||||
attohttpc = { version = "0.12.0" }
|
||||
regex = { version = "1" }
|
||||
|
||||
[target.'cfg(not(target_os = "linux"))'.dependencies]
|
||||
|
|
|
@ -23,7 +23,7 @@ use crate::{ResultExt, Settings};
|
|||
|
||||
use ar;
|
||||
use icns;
|
||||
use image::png::{PNGDecoder, PNGEncoder};
|
||||
use image::png::{PngDecoder};
|
||||
use image::{self, GenericImageView, ImageDecoder};
|
||||
use libflate::gzip;
|
||||
use md5;
|
||||
|
@ -32,7 +32,6 @@ use tar;
|
|||
use walkdir::WalkDir;
|
||||
|
||||
use std::collections::BTreeSet;
|
||||
use std::convert::TryInto;
|
||||
use std::ffi::OsStr;
|
||||
use std::fs::{self, File};
|
||||
use std::io::{self, Write};
|
||||
|
@ -298,9 +297,9 @@ fn generate_icon_files(settings: &Settings, data_dir: &PathBuf) -> crate::Result
|
|||
if icon_path.extension() != Some(OsStr::new("png")) {
|
||||
continue;
|
||||
}
|
||||
let decoder = PNGDecoder::new(File::open(&icon_path)?)?;
|
||||
let width = decoder.dimensions().0.try_into()?;
|
||||
let height = decoder.dimensions().1.try_into()?;
|
||||
let decoder = PngDecoder::new(File::open(&icon_path)?)?;
|
||||
let width = decoder.dimensions().0;
|
||||
let height = decoder.dimensions().1;
|
||||
let is_high_density = common::is_retina(&icon_path);
|
||||
if !sizes.contains(&(width, height, is_high_density)) {
|
||||
sizes.insert((width, height, is_high_density));
|
||||
|
@ -333,8 +332,10 @@ fn generate_icon_files(settings: &Settings, data_dir: &PathBuf) -> crate::Result
|
|||
if !sizes.contains(&(width, height, is_high_density)) {
|
||||
sizes.insert((width, height, is_high_density));
|
||||
let dest_path = get_dest_path(width, height, is_high_density);
|
||||
let encoder = PNGEncoder::new(common::create_file(&dest_path)?);
|
||||
encoder.encode(&icon.raw_pixels(), width, height, icon.color())?;
|
||||
icon.write_to(
|
||||
&mut common::create_file(&dest_path)?,
|
||||
image::ImageOutputFormat::Png
|
||||
)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -375,7 +375,7 @@ fn create_icns_file(
|
|||
}
|
||||
|
||||
for (icon, next_size_down, density) in images_to_resize {
|
||||
let icon = icon.resize_exact(next_size_down, next_size_down, image::Lanczos3);
|
||||
let icon = icon.resize_exact(next_size_down, next_size_down, image::imageops::FilterType::Lanczos3);
|
||||
add_icon_to_family(icon, density, &mut family)?;
|
||||
}
|
||||
|
||||
|
@ -395,14 +395,14 @@ fn create_icns_file(
|
|||
/// Converts an image::DynamicImage into an icns::Image.
|
||||
fn make_icns_image(img: image::DynamicImage) -> io::Result<icns::Image> {
|
||||
let pixel_format = match img.color() {
|
||||
image::ColorType::RGBA(8) => icns::PixelFormat::RGBA,
|
||||
image::ColorType::RGB(8) => icns::PixelFormat::RGB,
|
||||
image::ColorType::GrayA(8) => icns::PixelFormat::GrayAlpha,
|
||||
image::ColorType::Gray(8) => icns::PixelFormat::Gray,
|
||||
image::ColorType::Rgba8 => icns::PixelFormat::RGBA,
|
||||
image::ColorType::Rgb8 => icns::PixelFormat::RGB,
|
||||
image::ColorType::La8 => icns::PixelFormat::GrayAlpha,
|
||||
image::ColorType::L8 => icns::PixelFormat::Gray,
|
||||
_ => {
|
||||
let msg = format!("unsupported ColorType: {:?}", img.color());
|
||||
return Err(io::Error::new(io::ErrorKind::InvalidData, msg));
|
||||
}
|
||||
};
|
||||
icns::Image::from_data(pixel_format, img.width(), img.height(), img.raw_pixels())
|
||||
icns::Image::from_data(pixel_format, img.width(), img.height(), img.to_bytes())
|
||||
}
|
||||
|
|
|
@ -90,7 +90,7 @@ pub enum BuildArtifact {
|
|||
Example(String),
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize)]
|
||||
#[derive(Clone, Debug, Deserialize, Default)]
|
||||
struct BundleSettings {
|
||||
// General settings:
|
||||
name: Option<String>,
|
||||
|
@ -200,20 +200,31 @@ impl Settings {
|
|||
None
|
||||
};
|
||||
let cargo_settings = CargoSettings::load(¤t_dir)?;
|
||||
let tauri_config = super::tauri_config::get();
|
||||
|
||||
let package = match cargo_settings.package {
|
||||
Some(package_info) => package_info,
|
||||
None => bail!("No 'package' info found in 'Cargo.toml'"),
|
||||
};
|
||||
let workspace_dir = Settings::get_workspace_dir(¤t_dir);
|
||||
let target_dir = Settings::get_target_dir(&workspace_dir, &target, is_release, &build_artifact);
|
||||
let bundle_settings = if let Some(bundle_settings) = package
|
||||
.metadata
|
||||
.as_ref()
|
||||
.and_then(|metadata| metadata.bundle.as_ref())
|
||||
{
|
||||
bundle_settings.clone()
|
||||
} else {
|
||||
bail!("No [package.metadata.bundle] section in Cargo.toml");
|
||||
let bundle_settings = match tauri_config {
|
||||
Ok(config) => merge_settings(BundleSettings::default(), config.tauri.bundle),
|
||||
Err(e) => {
|
||||
let error_message = e.to_string();
|
||||
if !error_message.contains("No such file or directory") {
|
||||
bail!("Failed to read Tauri config: {}", error_message);
|
||||
}
|
||||
if let Some(bundle_settings) = package
|
||||
.metadata
|
||||
.as_ref()
|
||||
.and_then(|metadata| metadata.bundle.as_ref())
|
||||
{
|
||||
bundle_settings.clone()
|
||||
} else {
|
||||
bail!("No [package.metadata.bundle] section in Cargo.toml");
|
||||
}
|
||||
}
|
||||
};
|
||||
let (bundle_settings, binary_name) = match build_artifact {
|
||||
BuildArtifact::Main => (bundle_settings, package.name.clone()),
|
||||
|
@ -235,12 +246,6 @@ impl Settings {
|
|||
|
||||
let bundle_settings = add_external_bin(bundle_settings)?;
|
||||
|
||||
let tauri_config = super::tauri_config::get();
|
||||
let merged_bundle_settings = match tauri_config {
|
||||
Ok(config) => merge_settings(bundle_settings, config.tauri.bundle),
|
||||
Err(_) => bundle_settings,
|
||||
};
|
||||
|
||||
Ok(Settings {
|
||||
package,
|
||||
package_type,
|
||||
|
@ -251,7 +256,7 @@ impl Settings {
|
|||
project_out_directory: target_dir,
|
||||
binary_path,
|
||||
binary_name,
|
||||
bundle_settings: merged_bundle_settings,
|
||||
bundle_settings,
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# Webpack output
|
||||
dist
|
||||
/dist
|
||||
|
||||
# Logs
|
||||
logs
|
||||
|
@ -69,9 +69,3 @@ config.json
|
|||
|
||||
# rust compiled folders
|
||||
target
|
||||
|
||||
|
||||
# doing this because of how our tests currently (naively) drop the tauri.conf.json in that folder
|
||||
# todo: needs a proper fic
|
||||
tauri.conf.json
|
||||
src-tauri
|
|
@ -0,0 +1,32 @@
|
|||
import tauri from './tauri'
|
||||
|
||||
/**
|
||||
* @name openDialog
|
||||
* @description Open a file/directory selection dialog
|
||||
* @param {String} [options]
|
||||
* @param {String} [options.filter]
|
||||
* @param {String} [options.defaultPath]
|
||||
* @param {Boolean} [options.multiple=false]
|
||||
* @param {Boolean} [options.directory=false]
|
||||
* @returns {Promise<String|String[]>} promise resolving to the select path(s)
|
||||
*/
|
||||
function open (options = {}) {
|
||||
return tauri.openDialog(options)
|
||||
}
|
||||
|
||||
/**
|
||||
* @name save
|
||||
* @description Open a file/directory save dialog
|
||||
* @param {String} [options]
|
||||
* @param {String} [options.filter]
|
||||
* @param {String} [options.defaultPath]
|
||||
* @returns {Promise<String>} promise resolving to the select path
|
||||
*/
|
||||
function save (options = {}) {
|
||||
return tauri.saveDialog(options)
|
||||
}
|
||||
|
||||
export {
|
||||
open,
|
||||
save
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
import tauri from './tauri'
|
||||
|
||||
/**
|
||||
* The event handler callback
|
||||
* @callback eventCallback
|
||||
* @param {object} event
|
||||
* @param {string} event.type
|
||||
* @param {any} [event.payload]
|
||||
*/
|
||||
|
||||
/**
|
||||
* listen to an event from the backend
|
||||
*
|
||||
* @param {string} event the event name
|
||||
* @param {eventCallback} handler the event handler callback
|
||||
*/
|
||||
function listen (event, handler) {
|
||||
tauri.listen(event, handler)
|
||||
}
|
||||
|
||||
/**
|
||||
* emits an event to the backend
|
||||
*
|
||||
* @param {string} event the event name
|
||||
* @param {string} [payload] the event payload
|
||||
*/
|
||||
function emit (event, payload) {
|
||||
tauri.emit(event, payload)
|
||||
}
|
||||
|
||||
export {
|
||||
listen,
|
||||
emit
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
/**
|
||||
* @typedef {number} BaseDirectory
|
||||
*/
|
||||
/**
|
||||
* @enum {BaseDirectory}
|
||||
*/
|
||||
const Dir = {
|
||||
Audio: 1,
|
||||
Cache: 2,
|
||||
Config: 3,
|
||||
Data: 4,
|
||||
LocalData: 5,
|
||||
Desktop: 6,
|
||||
Document: 7,
|
||||
Download: 8,
|
||||
Executable: 9,
|
||||
Font: 10,
|
||||
Home: 11,
|
||||
Picture: 12,
|
||||
Public: 13,
|
||||
Runtime: 14,
|
||||
Template: 15,
|
||||
Video: 16,
|
||||
Resource: 17,
|
||||
App: 18
|
||||
}
|
||||
|
||||
export {
|
||||
Dir
|
||||
}
|
|
@ -0,0 +1,140 @@
|
|||
import tauri from './tauri'
|
||||
import { Dir } from './dir'
|
||||
|
||||
/**
|
||||
* reads a file as text
|
||||
*
|
||||
* @param {string} filePath path to the file
|
||||
* @param {object} [options] configuration object
|
||||
* @param {BaseDirectory} [options.dir] base directory
|
||||
* @return {Promise<string>}
|
||||
*/
|
||||
function readTextFile (filePath, options = {}) {
|
||||
return tauri.readTextFile(filePath, options)
|
||||
}
|
||||
|
||||
/**
|
||||
* reads a file as binary
|
||||
*
|
||||
* @param {string} filePath path to the file
|
||||
* @param {object} [options] configuration object
|
||||
* @param {BaseDirectory} [options.dir] base directory
|
||||
* @return {Promise<int[]>}
|
||||
*/
|
||||
function readBinaryFile (filePath, options = {}) {
|
||||
return tauri.readBinaryFile(filePath, options)
|
||||
}
|
||||
|
||||
/**
|
||||
* writes a text file
|
||||
*
|
||||
* @param {object} file
|
||||
* @param {string} file.path path of the file
|
||||
* @param {string} file.contents contents of the file
|
||||
* @param {object} [options] configuration object
|
||||
* @param {BaseDirectory} [options.dir] base directory
|
||||
* @return {Promise<void>}
|
||||
*/
|
||||
function writeFile (file, options = {}) {
|
||||
return tauri.writeFile(file, options)
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef {object} FileEntry
|
||||
* @property {string} path
|
||||
* @property {boolean} is_dir
|
||||
* @property {string} name
|
||||
*/
|
||||
|
||||
/**
|
||||
* list directory files
|
||||
*
|
||||
* @param {string} dir path to the directory to read
|
||||
* @param {object} [options] configuration object
|
||||
* @param {boolean} [options.recursive] whether to list dirs recursively or not
|
||||
* @param {BaseDirectory} [options.dir] base directory
|
||||
* @return {Promise<FileEntry[]>}
|
||||
*/
|
||||
function readDir (dir, options = {}) {
|
||||
return tauri.readDir(dir, options)
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a directory
|
||||
* If one of the path's parent components doesn't exist
|
||||
* and the `recursive` option isn't set to true, it will be rejected
|
||||
*
|
||||
* @param {string} dir path to the directory to create
|
||||
* @param {object} [options] configuration object
|
||||
* @param {boolean} [options.recursive] whether to create the directory's parent components or not
|
||||
* @param {BaseDirectory} [options.dir] base directory
|
||||
* @return {Promise<void>}
|
||||
*/
|
||||
function createDir (dir, options = {}) {
|
||||
return tauri.createDir(dir, options)
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a directory
|
||||
* If the directory is not empty and the `recursive` option isn't set to true, it will be rejected
|
||||
*
|
||||
* @param {string} dir path to the directory to remove
|
||||
* @param {object} [options] configuration object
|
||||
* @param {boolean} [options.recursive] whether to remove all of the directory's content or not
|
||||
* @param {BaseDirectory} [options.dir] base directory
|
||||
* @return {Promise<void>}
|
||||
*/
|
||||
function removeDir (dir, options = {}) {
|
||||
return tauri.removeDir(dir, options)
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy file
|
||||
*
|
||||
* @param {string} source
|
||||
* @param {string} destination
|
||||
* @param {object} [options] configuration object
|
||||
* @param {BaseDirectory} [options.dir] base directory
|
||||
* @return {Promise<void>}
|
||||
*/
|
||||
function copyFile (source, destination, options = {}) {
|
||||
return tauri.copyFile(source, destination, options)
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a file
|
||||
*
|
||||
* @param {string} file path to the file to remove
|
||||
* @param {object} [options] configuration object
|
||||
* @param {BaseDirectory} [options.dir] base directory
|
||||
* @return {Promise<void>}
|
||||
*/
|
||||
function removeFile (file, options = {}) {
|
||||
return tauri.removeFile(file, options)
|
||||
}
|
||||
|
||||
/**
|
||||
* Renames a file
|
||||
*
|
||||
* @param {string} oldPath
|
||||
* @param {string} newPath
|
||||
* @param {object} [options] configuration object
|
||||
* @param {BaseDirectory} [options.dir] base directory
|
||||
* @return {Promise<void>}
|
||||
*/
|
||||
function renameFile (oldPath, newPath, options = {}) {
|
||||
return tauri.renameFile(oldPath, newPath, options)
|
||||
}
|
||||
|
||||
export {
|
||||
Dir,
|
||||
readTextFile,
|
||||
readBinaryFile,
|
||||
writeFile,
|
||||
readDir,
|
||||
createDir,
|
||||
removeDir,
|
||||
copyFile,
|
||||
removeFile,
|
||||
renameFile
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
import tauri from './tauri'
|
||||
|
||||
export default tauri
|
|
@ -0,0 +1,16 @@
|
|||
import tauri from './tauri'
|
||||
|
||||
/**
|
||||
* spawns a process
|
||||
*
|
||||
* @param {string} command the name of the cmd to execute e.g. 'mkdir' or 'node'
|
||||
* @param {(string[]|string)} [args] command args
|
||||
* @return {Promise<string>} promise resolving to the stdout text
|
||||
*/
|
||||
function execute (command, args) {
|
||||
return tauri.execute(command, args)
|
||||
}
|
||||
|
||||
export {
|
||||
execute
|
||||
}
|
|
@ -2,7 +2,7 @@ const cache = {}
|
|||
let initialized = false
|
||||
|
||||
const proxy = new Proxy({
|
||||
__consume () {
|
||||
__consume() {
|
||||
for (const key in cache) {
|
||||
if (key in window.tauri) {
|
||||
const queue = cache[key]
|
||||
|
@ -21,10 +21,11 @@ const proxy = new Proxy({
|
|||
}
|
||||
}
|
||||
initialized = true
|
||||
}
|
||||
},
|
||||
Dir: require('./fs/dir').Dir
|
||||
}, {
|
||||
get (obj, prop) {
|
||||
if (prop === '__consume') {
|
||||
get(obj, prop) {
|
||||
if (prop === '__consume' || prop === 'Dir') {
|
||||
return obj[prop]
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
import tauri from './tauri'
|
||||
|
||||
/**
|
||||
* sets the window title
|
||||
*
|
||||
* @param {string} title the new title
|
||||
*/
|
||||
function setTitle (title) {
|
||||
tauri.setTitle(title)
|
||||
}
|
||||
|
||||
/**
|
||||
* opens an URL on the user default browser
|
||||
*
|
||||
* @param {string} url the URL to open
|
||||
*/
|
||||
function open (url) {
|
||||
tauri.open(url)
|
||||
}
|
||||
|
||||
export {
|
||||
setTitle,
|
||||
open
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
module.exports = {
|
||||
presets: [
|
||||
['@babel/preset-env', {
|
||||
targets: {
|
||||
node: 'current'
|
||||
},
|
||||
modules: 'commonjs'
|
||||
}],
|
||||
'@babel/preset-typescript'
|
||||
]
|
||||
};
|
|
@ -3,7 +3,8 @@ const parseArgs = require('minimist')
|
|||
const argv = parseArgs(process.argv.slice(2), {
|
||||
alias: {
|
||||
h: 'help',
|
||||
d: 'debug'
|
||||
d: 'debug',
|
||||
t: 'target'
|
||||
},
|
||||
boolean: ['h', 'd']
|
||||
})
|
||||
|
@ -16,10 +17,17 @@ if (argv.help) {
|
|||
$ tauri build
|
||||
Options
|
||||
--help, -h Displays this message
|
||||
--debug, -d Builds with the debug flag
|
||||
--target, -t Comma-separated list of target triples to build against
|
||||
`)
|
||||
process.exit(0)
|
||||
}
|
||||
|
||||
const build = require('../dist/api/build')
|
||||
|
||||
build({ ctx: { debug: argv.debug } })
|
||||
build({
|
||||
ctx: {
|
||||
debug: argv.debug,
|
||||
target: argv.target
|
||||
}
|
||||
})
|
||||
|
|
|
@ -2,9 +2,10 @@ const parseArgs = require('minimist')
|
|||
|
||||
const argv = parseArgs(process.argv.slice(2), {
|
||||
alias: {
|
||||
h: 'help'
|
||||
h: 'help',
|
||||
e: 'exit-on-panic'
|
||||
},
|
||||
boolean: ['h']
|
||||
boolean: ['h', 'e']
|
||||
})
|
||||
|
||||
if (argv.help) {
|
||||
|
@ -21,4 +22,8 @@ if (argv.help) {
|
|||
|
||||
const dev = require('../dist/api/dev')
|
||||
|
||||
dev()
|
||||
dev({
|
||||
ctx: {
|
||||
exitOnPanic: argv['exit-on-panic']
|
||||
}
|
||||
})
|
||||
|
|
|
@ -28,15 +28,21 @@ module.exports = {
|
|||
'<rootDir>/test/jest/__tests__/**/*.spec.js',
|
||||
'<rootDir>/test/jest/__tests__/**/*.test.js'
|
||||
],
|
||||
moduleFileExtensions: ['js', 'json'],
|
||||
testPathIgnorePatterns: [
|
||||
'(build|dev).spec.js'
|
||||
],
|
||||
moduleFileExtensions: ['ts', 'js', 'json'],
|
||||
moduleNameMapper: {
|
||||
'^~/(.*)$': '<rootDir>/$1',
|
||||
'^bin/(.*)$': '<rootDir>/bin/$1',
|
||||
'^helpers/(.*)$': '<rootDir>/helpers/$1',
|
||||
'^api/(.*)$': '<rootDir>/api/$1',
|
||||
'^templates/(.*)$': '<rootDir>/templates/$1',
|
||||
'^helpers/(.*)$': '<rootDir>/src/helpers/$1',
|
||||
'^api/(.*)$': '<rootDir>/src/api/$1',
|
||||
'^templates/(.*)$': '<rootDir>/src/templates/$1',
|
||||
'^test/(.*)$': '<rootDir>/test/$1',
|
||||
'../../package.json': '<rootDir>/package.json'
|
||||
},
|
||||
transform: {}
|
||||
"transform": {
|
||||
"templates[\\\\/](tauri|mutation-observer)\.js": "./test/jest/raw-loader-transformer.js",
|
||||
"\\.(js|ts)$": "babel-jest"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "tauri",
|
||||
"version": "0.4.5",
|
||||
"version": "0.5.0",
|
||||
"description": "Multi-binding collection of libraries and templates for building Tauri apps",
|
||||
"bin": {
|
||||
"tauri": "./bin/tauri.js"
|
||||
|
@ -57,17 +57,20 @@
|
|||
"imagemin-zopfli": "6.0.0",
|
||||
"is-png": "2.0.0",
|
||||
"isbinaryfile": "4.0.4",
|
||||
"jsdom": "16.2.0",
|
||||
"jsdom": "16.2.1",
|
||||
"lodash": "4.17.15",
|
||||
"minimist": "1.2.0",
|
||||
"minimist": "1.2.4",
|
||||
"ms": "2.1.2",
|
||||
"png2icons": "2.0.1",
|
||||
"read-chunk": "3.2.0",
|
||||
"sharp": "0.24.1",
|
||||
"sharp": "0.25.1",
|
||||
"webpack-merge": "4.2.2",
|
||||
"webpack-shell-plugin": "0.5.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "7.8.7",
|
||||
"@babel/preset-env": "7.8.7",
|
||||
"@babel/preset-typescript": "7.8.3",
|
||||
"@types/cross-spawn": "6.0.1",
|
||||
"@types/fs-extra": "8.1.0",
|
||||
"@types/imagemin": "7.0.0",
|
||||
|
@ -77,8 +80,9 @@
|
|||
"@types/ms": "0.7.31",
|
||||
"@types/sharp": "0.24.0",
|
||||
"@types/webpack-merge": "4.1.5",
|
||||
"@typescript-eslint/eslint-plugin": "2.21.0",
|
||||
"@typescript-eslint/parser": "2.21.0",
|
||||
"@typescript-eslint/eslint-plugin": "2.23.0",
|
||||
"@typescript-eslint/parser": "2.23.0",
|
||||
"babel-jest": "25.1.0",
|
||||
"dotenv": "8.2.0",
|
||||
"eslint": "6.8.0",
|
||||
"eslint-config-standard-with-typescript": "14.0.0",
|
||||
|
@ -89,15 +93,16 @@
|
|||
"eslint-plugin-security": "1.4.0",
|
||||
"eslint-plugin-standard": "4.0.1",
|
||||
"husky": "4.2.3",
|
||||
"is-running": "2.1.0",
|
||||
"jest": "25.1.0",
|
||||
"jest-mock-process": "1.3.2",
|
||||
"lint-staged": "10.0.8",
|
||||
"lockfile-lint": "4.0.0",
|
||||
"promise": "8.0.3",
|
||||
"lockfile-lint": "4.1.0",
|
||||
"promise": "8.1.0",
|
||||
"raw-loader": "4.0.0",
|
||||
"ts-loader": "6.2.1",
|
||||
"typescript": "3.8.3",
|
||||
"webpack": "4.41.6",
|
||||
"webpack": "4.42.0",
|
||||
"webpack-cli": "3.3.11",
|
||||
"webpack-node-externals": "1.7.2"
|
||||
},
|
||||
|
|
|
@ -3,7 +3,12 @@ import merge from 'webpack-merge'
|
|||
import Runner from '../runner'
|
||||
import getTauriConfig from '../helpers/tauri-config'
|
||||
|
||||
module.exports = async (config: TauriConfig): Promise<void> => {
|
||||
interface BuildResult {
|
||||
promise: Promise<void>
|
||||
runner: Runner
|
||||
}
|
||||
|
||||
module.exports = (config: TauriConfig): BuildResult => {
|
||||
const tauri = new Runner()
|
||||
const tauriConfig = getTauriConfig(
|
||||
merge(
|
||||
|
@ -16,5 +21,8 @@ module.exports = async (config: TauriConfig): Promise<void> => {
|
|||
) as TauriConfig
|
||||
)
|
||||
|
||||
return tauri.build(tauriConfig)
|
||||
return {
|
||||
runner: tauri,
|
||||
promise: tauri.build(tauriConfig)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,12 @@ import merge from 'webpack-merge'
|
|||
import Runner from '../runner'
|
||||
import getTauriConfig from '../helpers/tauri-config'
|
||||
|
||||
module.exports = async (config: TauriConfig): Promise<void> => {
|
||||
interface DevResult {
|
||||
promise: Promise<void>
|
||||
runner: Runner
|
||||
}
|
||||
|
||||
module.exports = (config: TauriConfig): DevResult => {
|
||||
const tauri = new Runner()
|
||||
const tauriConfig = getTauriConfig(
|
||||
merge(
|
||||
|
@ -17,5 +22,8 @@ module.exports = async (config: TauriConfig): Promise<void> => {
|
|||
) as TauriConfig
|
||||
)
|
||||
|
||||
return tauri.run(tauriConfig)
|
||||
return {
|
||||
runner: tauri,
|
||||
promise: tauri.run(tauriConfig)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ import os from 'os'
|
|||
import path from 'path'
|
||||
import { appDir, tauriDir } from '../helpers/app-paths'
|
||||
import { TauriConfig } from './../types/config'
|
||||
import nonWebpackRequire from '../helpers/non-webpack-require'
|
||||
|
||||
interface DirInfo {
|
||||
path: string
|
||||
|
@ -115,7 +116,7 @@ function printAppInfo(tauriDir: string): void {
|
|||
return chalk.red('unset')
|
||||
}
|
||||
const configPath = path.join(tauriDir, 'tauri.conf.json')
|
||||
const config = __non_webpack_require__(configPath) as TauriConfig
|
||||
const config = nonWebpackRequire(configPath) as TauriConfig
|
||||
printInfo({ key: ' mode', value: tauriMode(config) })
|
||||
printInfo({
|
||||
key: ' build-type',
|
||||
|
@ -175,7 +176,8 @@ module.exports = () => {
|
|||
printInfo({ key: 'App directory structure', section: true })
|
||||
|
||||
const tree = dirTree(appDir)
|
||||
for (const artifact of tree.children ?? []) {
|
||||
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
|
||||
for (const artifact of tree.children || []) {
|
||||
if (artifact.type === 'folder') {
|
||||
console.log(`/${artifact.name}`)
|
||||
}
|
||||
|
|
|
@ -179,7 +179,7 @@ const tauricon = (exports.tauricon = {
|
|||
return typeof image === 'object'
|
||||
},
|
||||
version: function() {
|
||||
return __non_webpack_require__('../../package.json').version
|
||||
return require('../../package.json').version
|
||||
},
|
||||
make: async function(
|
||||
src: string = path.resolve(appDir, 'app-icon.png'),
|
||||
|
@ -227,7 +227,8 @@ const tauricon = (exports.tauricon = {
|
|||
try {
|
||||
const pngImage = sharpSrc.resize(pvar[1], pvar[1])
|
||||
if (pvar[2]) {
|
||||
const rgb = hexToRgb(options.background_color) ?? {
|
||||
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
|
||||
const rgb = hexToRgb(options.background_color) || {
|
||||
r: undefined,
|
||||
g: undefined,
|
||||
b: undefined
|
||||
|
@ -292,7 +293,8 @@ const tauricon = (exports.tauricon = {
|
|||
) {
|
||||
let output
|
||||
let block = false
|
||||
const rgb = hexToRgb(options.background_color) ?? {
|
||||
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
|
||||
const rgb = hexToRgb(options.background_color) || {
|
||||
r: undefined,
|
||||
g: undefined,
|
||||
b: undefined
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
import { ensureDirSync, writeFileSync } from 'fs-extra'
|
||||
import { template } from 'lodash'
|
||||
import { template } from 'lodash'
|
||||
import path from 'path'
|
||||
import { TauriConfig } from './types/config'
|
||||
|
||||
export const generate = (outDir: string, cfg: TauriConfig): void => {
|
||||
// this MUST be from the templates repo
|
||||
const apiTemplate = require('!!raw-loader!!../templates/tauri.js').default
|
||||
const apiTemplate = require('../templates/tauri.js').default
|
||||
const compiledApi = template(apiTemplate)
|
||||
|
||||
ensureDirSync(outDir)
|
||||
|
|
|
@ -1,21 +1,23 @@
|
|||
import { existsSync } from 'fs'
|
||||
import { join, normalize, resolve, sep } from 'path'
|
||||
import logger from './logger'
|
||||
const warn = logger('tauri', 'red')
|
||||
|
||||
const getAppDir = (): string => {
|
||||
let dir = process.cwd()
|
||||
let count = 0
|
||||
|
||||
// only go up three folders max
|
||||
while (dir.length > 0 && dir.endsWith(sep) && count <= 2) {
|
||||
if (existsSync(join(dir, 'tauri.conf.json'))) {
|
||||
while (dir.length > 0 && !dir.endsWith(sep) && count <= 2) {
|
||||
if (existsSync(join(dir, 'src-tauri', 'tauri.conf.json'))) {
|
||||
return dir
|
||||
}
|
||||
count++
|
||||
dir = normalize(join(dir, '..'))
|
||||
}
|
||||
|
||||
// just return the current directory
|
||||
return process.cwd()
|
||||
warn('Couldn\'t find recognize the current folder as a part of a Tauri project')
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
const appDir = getAppDir()
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
// this function has been moved to a module so we can mock it
|
||||
export default (path: string): any => {
|
||||
return __non_webpack_require__(path)
|
||||
}
|
|
@ -19,7 +19,8 @@ export const spawn = (
|
|||
// TODO: move to execa?
|
||||
const runner = crossSpawn(cmd, params, {
|
||||
stdio: 'inherit',
|
||||
cwd
|
||||
cwd,
|
||||
env: process.env
|
||||
})
|
||||
|
||||
runner.on('close', code => {
|
||||
|
@ -29,7 +30,8 @@ export const spawn = (
|
|||
log(`Command "${cmd}" failed with exit code: ${code}`)
|
||||
}
|
||||
|
||||
onClose?.(code)
|
||||
// eslint-disable-next-line @typescript-eslint/prefer-optional-chain
|
||||
onClose && onClose(code)
|
||||
})
|
||||
|
||||
return runner.pid
|
||||
|
@ -42,7 +44,7 @@ export const spawnSync = (
|
|||
cmd: string,
|
||||
params: string[],
|
||||
cwd: string,
|
||||
onFail: () => void
|
||||
onFail?: () => void
|
||||
): void => {
|
||||
log(`[sync] Running "${cmd} ${params.join(' ')}"`)
|
||||
log()
|
||||
|
@ -60,7 +62,8 @@ export const spawnSync = (
|
|||
if (runner.status === null) {
|
||||
warn(`⚠️ Please globally install "${cmd}"`)
|
||||
}
|
||||
onFail?.()
|
||||
// eslint-disable-next-line @typescript-eslint/prefer-optional-chain
|
||||
onFail && onFail()
|
||||
process.exit(1)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ import { TauriConfig } from 'types'
|
|||
import merge from 'webpack-merge'
|
||||
import logger from '../helpers/logger'
|
||||
import * as appPaths from './app-paths'
|
||||
import nonWebpackRequire from '../helpers/non-webpack-require'
|
||||
|
||||
const error = logger('ERROR:', 'red')
|
||||
|
||||
|
@ -20,8 +21,8 @@ const getTauriConfig = (cfg: Partial<TauriConfig>): TauriConfig => {
|
|||
)
|
||||
process.exit(1)
|
||||
}
|
||||
const tauriConf = __non_webpack_require__(tauriConfPath)
|
||||
const pkg = __non_webpack_require__(pkgPath)
|
||||
const tauriConf = nonWebpackRequire(tauriConfPath)
|
||||
const pkg = nonWebpackRequire(pkgPath)
|
||||
|
||||
const config = merge(
|
||||
{
|
||||
|
|
|
@ -1,26 +1,27 @@
|
|||
import Inliner from '@tauri-apps/tauri-inliner'
|
||||
import toml from '@tauri-apps/toml'
|
||||
import toml, { JsonMap } from '@tauri-apps/toml'
|
||||
import chokidar, { FSWatcher } from 'chokidar'
|
||||
import { existsSync, readFileSync, writeFileSync } from 'fs-extra'
|
||||
import { JSDOM } from 'jsdom'
|
||||
import { debounce, template } from 'lodash'
|
||||
import path from 'path'
|
||||
import * as entry from './entry'
|
||||
import { appDir, tauriDir } from './helpers/app-paths'
|
||||
import { tauriDir } from './helpers/app-paths'
|
||||
import logger from './helpers/logger'
|
||||
import onShutdown from './helpers/on-shutdown'
|
||||
import { spawn } from './helpers/spawn'
|
||||
const getTauriConfig = require('./helpers/tauri-config')
|
||||
import { spawn, spawnSync } from './helpers/spawn'
|
||||
import { TauriConfig } from './types/config'
|
||||
import getTauriConfig from './helpers/tauri-config'
|
||||
|
||||
const log = logger('app:tauri', 'green')
|
||||
const warn = logger('app:tauri (template)', 'red')
|
||||
const warn = logger('app:tauri (runner)', 'red')
|
||||
|
||||
class Runner {
|
||||
pid: number
|
||||
tauriWatcher?: FSWatcher
|
||||
devPath?: string
|
||||
killPromise?: Function
|
||||
ranBeforeDevCommand?: boolean
|
||||
|
||||
constructor() {
|
||||
this.pid = 0
|
||||
|
@ -43,9 +44,15 @@ class Runner {
|
|||
}
|
||||
}
|
||||
|
||||
this.__manipulateToml(toml => {
|
||||
this.__whitelistApi(cfg, toml)
|
||||
})
|
||||
if (!this.ranBeforeDevCommand && cfg.build.beforeDevCommand) {
|
||||
this.ranBeforeDevCommand = true // prevent calling it twice on recursive call on our watcher
|
||||
const [command, ...args] = cfg.build.beforeDevCommand.split(' ')
|
||||
spawnSync(command, args, tauriDir)
|
||||
}
|
||||
|
||||
const tomlContents = this.__getManifest()
|
||||
this.__whitelistApi(cfg, tomlContents)
|
||||
this.__rewriteManifest(tomlContents)
|
||||
|
||||
entry.generate(tauriDir, cfg)
|
||||
|
||||
|
@ -67,11 +74,27 @@ class Runner {
|
|||
cargoArgs: ['run'].concat(
|
||||
features.length ? ['--features', ...features] : []
|
||||
),
|
||||
dev: true
|
||||
dev: true,
|
||||
exitOnPanic: cfg.ctx.exitOnPanic
|
||||
})
|
||||
}
|
||||
|
||||
// Start watching for tauri app changes
|
||||
// eslint-disable-next-line security/detect-non-literal-fs-filename
|
||||
|
||||
let tauriPaths: string[] = []
|
||||
// @ts-ignore
|
||||
if (tomlContents.dependencies.tauri.path) {
|
||||
// @ts-ignore
|
||||
const tauriPath = path.resolve(tauriDir, tomlContents.dependencies.tauri.path)
|
||||
tauriPaths = [
|
||||
tauriPath,
|
||||
`${tauriPath}-api`,
|
||||
`${tauriPath}-updater`,
|
||||
`${tauriPath}-utils`
|
||||
]
|
||||
}
|
||||
|
||||
// eslint-disable-next-line security/detect-non-literal-fs-filename
|
||||
this.tauriWatcher = chokidar
|
||||
.watch(
|
||||
|
@ -79,18 +102,25 @@ class Runner {
|
|||
path.join(tauriDir, 'src'),
|
||||
path.join(tauriDir, 'Cargo.toml'),
|
||||
path.join(tauriDir, 'build.rs'),
|
||||
path.join(appDir, 'tauri.conf.json')
|
||||
],
|
||||
path.join(tauriDir, 'tauri.conf.json'),
|
||||
...tauriPaths
|
||||
].concat(runningDevServer ? [] : [devPath]),
|
||||
{
|
||||
ignoreInitial: true
|
||||
ignoreInitial: true,
|
||||
ignored: runningDevServer ? null : path.join(devPath, 'index.tauri.html')
|
||||
}
|
||||
)
|
||||
.on(
|
||||
'change',
|
||||
debounce((path: string) => {
|
||||
this.__stopCargo()
|
||||
debounce((changedPath: string) => {
|
||||
if (changedPath.startsWith(path.join(tauriDir, 'target'))) {
|
||||
return
|
||||
}
|
||||
(this.pid ? this.__stopCargo() : Promise.resolve())
|
||||
.then(() => {
|
||||
if (path.includes('tauri.conf.json')) {
|
||||
const shouldTriggerRun = changedPath.includes('tauri.conf.json') ||
|
||||
changedPath.startsWith(devPath)
|
||||
if (shouldTriggerRun) {
|
||||
this.run(getTauriConfig({ ctx: cfg.ctx })).catch(e => {
|
||||
throw e
|
||||
})
|
||||
|
@ -111,9 +141,14 @@ class Runner {
|
|||
}
|
||||
|
||||
async build(cfg: TauriConfig): Promise<void> {
|
||||
this.__manipulateToml(toml => {
|
||||
this.__whitelistApi(cfg, toml)
|
||||
})
|
||||
if (cfg.build.beforeBuildCommand) {
|
||||
const [command, ...args] = cfg.build.beforeBuildCommand.split(' ')
|
||||
spawnSync(command, args, tauriDir)
|
||||
}
|
||||
|
||||
const tomlContents = this.__getManifest()
|
||||
this.__whitelistApi(cfg, tomlContents)
|
||||
this.__rewriteManifest(tomlContents)
|
||||
|
||||
entry.generate(tauriDir, cfg)
|
||||
|
||||
|
@ -135,8 +170,8 @@ class Runner {
|
|||
.concat(target ? ['--target', target] : [])
|
||||
})
|
||||
|
||||
if (cfg.ctx.debug || !cfg.ctx.targetName) {
|
||||
// on debug mode or if no target specified,
|
||||
if (!cfg.ctx.target) {
|
||||
// if no target specified,
|
||||
// build only for the current platform
|
||||
await buildFn()
|
||||
} else {
|
||||
|
@ -160,15 +195,16 @@ class Runner {
|
|||
reject(new Error('Could not find index.html in dist dir.'))
|
||||
}
|
||||
|
||||
const rewriteHtml = (html: string, interceptor?: (dom: JSDOM) => void) => {
|
||||
const rewriteHtml = (html: string, interceptor?: (dom: JSDOM) => void): void => {
|
||||
const dom = new JSDOM(html)
|
||||
const document = dom.window.document
|
||||
if (interceptor !== undefined) {
|
||||
interceptor(dom)
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
|
||||
if (!((cfg.ctx.dev && cfg.build.devPath.startsWith('http')) || cfg.tauri.embeddedServer.active)) {
|
||||
const mutationObserverTemplate = require('!!raw-loader!!../templates/mutation-observer').default
|
||||
const mutationObserverTemplate = require('../templates/mutation-observer').default
|
||||
const compiledMutationObserver = template(mutationObserverTemplate)
|
||||
|
||||
const bodyMutationObserverScript = document.createElement('script')
|
||||
|
@ -212,7 +248,7 @@ class Runner {
|
|||
})
|
||||
}
|
||||
|
||||
if (cfg.tauri.embeddedServer.active || !cfg.tauri.inliner.active) {
|
||||
if ((!cfg.ctx.dev && cfg.tauri.embeddedServer.active) || !cfg.tauri.inliner.active) {
|
||||
rewriteHtml(readFileSync(indexPath).toString(), domInterceptor)
|
||||
resolve(inlinedAssets)
|
||||
} else {
|
||||
|
@ -236,22 +272,22 @@ class Runner {
|
|||
this.tauriWatcher && this.tauriWatcher.close()
|
||||
this.__stopCargo()
|
||||
.then(resolve)
|
||||
.catch(e => {
|
||||
console.error(e)
|
||||
})
|
||||
.catch(reject)
|
||||
})
|
||||
}
|
||||
|
||||
async __runCargoCommand({
|
||||
cargoArgs,
|
||||
extraArgs,
|
||||
dev = false
|
||||
dev = false,
|
||||
exitOnPanic = true
|
||||
}: {
|
||||
cargoArgs: string[]
|
||||
extraArgs?: string[]
|
||||
dev?: boolean
|
||||
exitOnPanic?: boolean
|
||||
}): Promise<void> {
|
||||
return new Promise(resolve => {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.pid = spawn(
|
||||
'cargo',
|
||||
|
||||
|
@ -260,11 +296,20 @@ class Runner {
|
|||
tauriDir,
|
||||
|
||||
code => {
|
||||
if (dev && !exitOnPanic && code === 101) {
|
||||
this.pid = 0
|
||||
resolve()
|
||||
return
|
||||
}
|
||||
|
||||
if (code) {
|
||||
warn()
|
||||
warn('⚠️ [FAIL] Cargo CLI has failed')
|
||||
warn()
|
||||
reject(new Error('Cargo failed with status code ' + code.toString()))
|
||||
process.exit(1)
|
||||
} else if (!dev) {
|
||||
resolve()
|
||||
}
|
||||
|
||||
if (this.killPromise) {
|
||||
|
@ -276,10 +321,14 @@ class Runner {
|
|||
warn()
|
||||
process.exit(0)
|
||||
}
|
||||
|
||||
resolve()
|
||||
}
|
||||
)
|
||||
|
||||
resolve()
|
||||
if (dev) {
|
||||
resolve()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -295,18 +344,27 @@ class Runner {
|
|||
|
||||
return new Promise((resolve, reject) => {
|
||||
this.killPromise = resolve
|
||||
process.kill(pid)
|
||||
try {
|
||||
process.kill(pid)
|
||||
} catch (e) {
|
||||
reject(e)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
__manipulateToml(callback: (tomlContents: object) => void): void {
|
||||
const tomlPath = path.join(tauriDir, 'Cargo.toml')
|
||||
const tomlFile = readFileSync(tomlPath)
|
||||
// @ts-ignore
|
||||
__getManifestPath(): string {
|
||||
return path.join(tauriDir, 'Cargo.toml')
|
||||
}
|
||||
|
||||
__getManifest(): JsonMap {
|
||||
const tomlPath = this.__getManifestPath()
|
||||
const tomlFile = readFileSync(tomlPath).toString()
|
||||
const tomlContents = toml.parse(tomlFile)
|
||||
return tomlContents
|
||||
}
|
||||
|
||||
callback(tomlContents)
|
||||
|
||||
__rewriteManifest(tomlContents: JsonMap): void {
|
||||
const tomlPath = this.__getManifestPath()
|
||||
const output = toml.stringify(tomlContents)
|
||||
writeFileSync(tomlPath, output)
|
||||
}
|
||||
|
@ -320,10 +378,15 @@ class Runner {
|
|||
if (cfg.tauri.whitelist.all) {
|
||||
tomlFeatures.push('all-api')
|
||||
} else {
|
||||
const toKebabCase = (value: string): string => {
|
||||
return value.replace(/([a-z])([A-Z])/g, '$1-$2')
|
||||
.replace(/\s+/g, '-')
|
||||
.toLowerCase()
|
||||
}
|
||||
const whitelist = Object.keys(cfg.tauri.whitelist).filter(
|
||||
w => cfg.tauri.whitelist[String(w)] === true
|
||||
w => cfg.tauri.whitelist[String(w)]
|
||||
)
|
||||
tomlFeatures.push(...whitelist)
|
||||
tomlFeatures.push(...whitelist.map(toKebabCase))
|
||||
}
|
||||
|
||||
if (cfg.tauri.edge.active) {
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
export default {
|
||||
build: {
|
||||
distDir: '../dist',
|
||||
devPath: 'http://localhost:4000'
|
||||
devPath: 'http://localhost:4000',
|
||||
beforeDevCommand: '',
|
||||
beforeBuildCommand: ''
|
||||
},
|
||||
ctx: {},
|
||||
tauri: {
|
||||
|
@ -15,7 +17,7 @@ export default {
|
|||
resources: [],
|
||||
externalBin: [],
|
||||
copyright: '',
|
||||
category: '',
|
||||
category: 'DeveloperTool',
|
||||
shortDescription: '',
|
||||
longDescription: '',
|
||||
deb: {
|
||||
|
@ -31,7 +33,11 @@ export default {
|
|||
all: true
|
||||
},
|
||||
window: {
|
||||
title: 'Tauri App'
|
||||
title: 'Tauri App',
|
||||
width: 800,
|
||||
height: 600,
|
||||
resizable: true,
|
||||
fullscreen: false
|
||||
},
|
||||
security: {
|
||||
csp: "default-src blob: data: filesystem: ws: http: https: 'unsafe-eval' 'unsafe-inline'"
|
||||
|
|
|
@ -62,8 +62,14 @@ Run \`tauri init --force template\` to overwrite.`)
|
|||
if (!force) return false
|
||||
}
|
||||
|
||||
const resolveTauriPath = (tauriPath: string): string => {
|
||||
const resolvedPath = tauriPath.startsWith('/') || /^\S:/g.test(tauriPath)
|
||||
? join(tauriPath, 'tauri') // we received a full path as argument
|
||||
: join('..', tauriPath, 'tauri') // we received a relative path
|
||||
return resolvedPath.replace(/\\/g, '/')
|
||||
}
|
||||
const tauriDep = tauriPath
|
||||
? `{ path = "${join('..', tauriPath, 'tauri')}" }`
|
||||
? `{ path = "${resolveTauriPath(tauriPath)}" }`
|
||||
: null
|
||||
|
||||
try {
|
||||
|
|
|
@ -5,6 +5,8 @@ export interface TauriConfig {
|
|||
build: {
|
||||
distDir: string
|
||||
devPath: string
|
||||
beforeDevCommand?: string
|
||||
beforeBuildCommand?: string
|
||||
}
|
||||
ctx: {
|
||||
prod?: boolean
|
||||
|
@ -12,6 +14,7 @@ export interface TauriConfig {
|
|||
target: string
|
||||
debug?: boolean
|
||||
targetName: string
|
||||
exitOnPanic?: boolean
|
||||
}
|
||||
bundle: {}
|
||||
tauri: {
|
||||
|
|
|
@ -10,7 +10,9 @@ fn main() {
|
|||
.invoke_handler(|_webview, arg| {
|
||||
use cmd::Cmd::*;
|
||||
match serde_json::from_str(arg) {
|
||||
Err(_) => {}
|
||||
Err(e) => {
|
||||
Err(e.to_string())
|
||||
}
|
||||
Ok(command) => {
|
||||
match command {
|
||||
// definitions for your custom commands from Cmd here
|
||||
|
@ -19,6 +21,7 @@ fn main() {
|
|||
println!("{}", argument);
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
})
|
||||
|
|
|
@ -72,6 +72,33 @@ function _defineProperty(obj, key, value) { if (key in obj) { Object.definePrope
|
|||
|
||||
function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
|
||||
|
||||
/**
|
||||
* @typedef {number} BaseDirectory
|
||||
*/
|
||||
/**
|
||||
* @enum {BaseDirectory}
|
||||
*/
|
||||
var Dir = {
|
||||
Audio: 1,
|
||||
Cache: 2,
|
||||
Config: 3,
|
||||
Data: 4,
|
||||
LocalData: 5,
|
||||
Desktop: 6,
|
||||
Document: 7,
|
||||
Download: 8,
|
||||
Executable: 9,
|
||||
Font: 10,
|
||||
Home: 11,
|
||||
Picture: 12,
|
||||
Public: 13,
|
||||
Runtime: 14,
|
||||
Template: 15,
|
||||
Video: 16,
|
||||
Resource: 17,
|
||||
App: 18
|
||||
}
|
||||
|
||||
<% if (ctx.dev) { %>
|
||||
/**
|
||||
* @name return __whitelistWarning
|
||||
|
@ -103,6 +130,7 @@ var __reject = function () {
|
|||
}
|
||||
|
||||
window.tauri = {
|
||||
Dir: Dir,
|
||||
<% if (ctx.dev) { %>
|
||||
/**
|
||||
* @name invoke
|
||||
|
@ -153,7 +181,7 @@ window.tauri = {
|
|||
this.invoke({
|
||||
cmd: 'emit',
|
||||
event: evt,
|
||||
payload: payload || ''
|
||||
payload: payload
|
||||
});
|
||||
<% } else { %>
|
||||
<% if (ctx.dev) { %>
|
||||
|
@ -212,14 +240,17 @@ window.tauri = {
|
|||
* @description Accesses a non-binary file on the user's filesystem
|
||||
* and returns the content. Permissions based on the app's PID owner
|
||||
* @param {String} path
|
||||
* @param {Object} [options]
|
||||
* @param {BaseDirectory} [options.dir]
|
||||
* @returns {*|Promise<any>|Promise}
|
||||
*/
|
||||
<% } %>
|
||||
readTextFile: function readTextFile(path) {
|
||||
readTextFile: function readTextFile(path, options) {
|
||||
<% if (tauri.whitelist.readTextFile === true || tauri.whitelist.all === true) { %>
|
||||
return this.promisified({
|
||||
cmd: 'readTextFile',
|
||||
path: path
|
||||
path: path,
|
||||
options: options
|
||||
});
|
||||
<% } else { %>
|
||||
<% if (ctx.dev) { %>
|
||||
|
@ -235,14 +266,17 @@ window.tauri = {
|
|||
* @description Accesses a binary file on the user's filesystem
|
||||
* and returns the content. Permissions based on the app's PID owner
|
||||
* @param {String} path
|
||||
* @param {Object} [options]
|
||||
* @param {BaseDirectory} [options.dir]
|
||||
* @returns {*|Promise<any>|Promise}
|
||||
*/
|
||||
<% } %>
|
||||
readBinaryFile: function readBinaryFile(path) {
|
||||
readBinaryFile: function readBinaryFile(path, options) {
|
||||
<% if (tauri.whitelist.readBinaryFile === true || tauri.whitelist.all === true) { %>
|
||||
return this.promisified({
|
||||
cmd: 'readBinaryFile',
|
||||
path: path
|
||||
path: path,
|
||||
options: options
|
||||
});
|
||||
<% } else { %>
|
||||
<% if (ctx.dev) { %>
|
||||
|
@ -260,17 +294,20 @@ window.tauri = {
|
|||
* @param {Object} cfg
|
||||
* @param {String} cfg.file
|
||||
* @param {String|Binary} cfg.contents
|
||||
* @param {Object} [options]
|
||||
* @param {BaseDirectory} [options.dir]
|
||||
*/
|
||||
<% } %>
|
||||
writeFile: function writeFile(cfg) {
|
||||
writeFile: function writeFile(cfg, options) {
|
||||
<% if (tauri.whitelist.writeFile === true || tauri.whitelist.all === true) { %>
|
||||
if (_typeof(cfg) === 'object') {
|
||||
Object.freeze(cfg);
|
||||
}
|
||||
this.invoke({
|
||||
return this.promisified({
|
||||
cmd: 'writeFile',
|
||||
file: cfg.file,
|
||||
contents: cfg.contents
|
||||
contents: cfg.contents,
|
||||
options: options
|
||||
});
|
||||
<% } else { %>
|
||||
<% if (ctx.dev) { %>
|
||||
|
@ -282,22 +319,26 @@ window.tauri = {
|
|||
|
||||
<% if (ctx.dev) { %>
|
||||
/**
|
||||
* @name listFiles
|
||||
* @description Get the files in a path.
|
||||
* @name readDir
|
||||
* @description Reads a directory
|
||||
* Permissions based on the app's PID owner
|
||||
* @param {String} path
|
||||
* @param {Object} [options]
|
||||
* @param {Boolean} [options.recursive]
|
||||
* @param {BaseDirectory} [options.dir]
|
||||
* @returns {*|Promise<any>|Promise}
|
||||
*/
|
||||
<% } %>
|
||||
listFiles: function listFiles(path) {
|
||||
<% if (tauri.whitelist.listFiles === true || tauri.whitelist.all === true) { %>
|
||||
readDir: function readDir(path, options) {
|
||||
<% if (tauri.whitelist.readDir === true || tauri.whitelist.all === true) { %>
|
||||
return this.promisified({
|
||||
cmd: 'listFiles',
|
||||
path: path
|
||||
cmd: 'readDir',
|
||||
path: path,
|
||||
options: options
|
||||
});
|
||||
<% } else { %>
|
||||
<% if (ctx.dev) { %>
|
||||
return __whitelistWarning('listDirs')
|
||||
return __whitelistWarning('readDir')
|
||||
<% } %>
|
||||
return __reject()
|
||||
<% } %>
|
||||
|
@ -305,22 +346,134 @@ window.tauri = {
|
|||
|
||||
<% if (ctx.dev) { %>
|
||||
/**
|
||||
* @name listDirs
|
||||
* @description Get the directories in a path.
|
||||
* @name createDir
|
||||
* @description Creates a directory
|
||||
* Permissions based on the app's PID owner
|
||||
* @param {String} path
|
||||
* @param {Object} [options]
|
||||
* @param {Boolean} [options.recursive]
|
||||
* @param {BaseDirectory} [options.dir]
|
||||
* @returns {*|Promise<any>|Promise}
|
||||
*/
|
||||
<% } %>
|
||||
listDirs: function listDirs(path) {
|
||||
<% if (tauri.whitelist.listDirs === true || tauri.whitelist.all === true) { %>
|
||||
createDir: function createDir(path, options) {
|
||||
<% if (tauri.whitelist.createDir === true || tauri.whitelist.all === true) { %>
|
||||
return this.promisified({
|
||||
cmd: 'listDirs',
|
||||
path: path
|
||||
cmd: 'createDir',
|
||||
path: path,
|
||||
options: options
|
||||
});
|
||||
<% } else { %>
|
||||
<% if (ctx.dev) { %>
|
||||
return __whitelistWarning('listDirs')
|
||||
return __whitelistWarning('createDir')
|
||||
<% } %>
|
||||
return __reject()
|
||||
<% } %>
|
||||
},
|
||||
|
||||
<% if (ctx.dev) { %>
|
||||
/**
|
||||
* @name removeDir
|
||||
* @description Removes a directory
|
||||
* Permissions based on the app's PID owner
|
||||
* @param {String} path
|
||||
* @param {Object} [options]
|
||||
* @param {Boolean} [options.recursive]
|
||||
* @param {BaseDirectory} [options.dir]
|
||||
* @returns {*|Promise<any>|Promise}
|
||||
*/
|
||||
<% } %>
|
||||
removeDir: function removeDir(path, options) {
|
||||
<% if (tauri.whitelist.removeDir === true || tauri.whitelist.all === true) { %>
|
||||
return this.promisified({
|
||||
cmd: 'removeDir',
|
||||
path: path,
|
||||
options: options
|
||||
});
|
||||
<% } else { %>
|
||||
<% if (ctx.dev) { %>
|
||||
return __whitelistWarning('removeDir')
|
||||
<% } %>
|
||||
return __reject()
|
||||
<% } %>
|
||||
},
|
||||
|
||||
<% if (ctx.dev) { %>
|
||||
/**
|
||||
* @name copyFile
|
||||
* @description Copy file
|
||||
* Permissions based on the app's PID owner
|
||||
* @param {String} source
|
||||
* @param {String} destination
|
||||
* @param {Object} [options]
|
||||
* @param {BaseDirectory} [options.dir]
|
||||
* @returns {*|Promise<any>|Promise}
|
||||
*/
|
||||
<% } %>
|
||||
copyFile: function copyFile(source, destination, options) {
|
||||
<% if (tauri.whitelist.copyFile === true || tauri.whitelist.all === true) { %>
|
||||
return this.promisified({
|
||||
cmd: 'copyFile',
|
||||
source: source,
|
||||
destination: destination,
|
||||
options: options
|
||||
});
|
||||
<% } else { %>
|
||||
<% if (ctx.dev) { %>
|
||||
return __whitelistWarning('copyFile')
|
||||
<% } %>
|
||||
return __reject()
|
||||
<% } %>
|
||||
},
|
||||
|
||||
<% if (ctx.dev) { %>
|
||||
/**
|
||||
* @name removeFile
|
||||
* @description Removes a file
|
||||
* Permissions based on the app's PID owner
|
||||
* @param {String} path
|
||||
* @param {Object} [options]
|
||||
* @param {BaseDirectory} [options.dir]
|
||||
* @returns {*|Promise<any>|Promise}
|
||||
*/
|
||||
<% } %>
|
||||
removeFile: function removeFile(path, options) {
|
||||
<% if (tauri.whitelist.removeFile === true || tauri.whitelist.all === true) { %>
|
||||
return this.promisified({
|
||||
cmd: 'removeFile',
|
||||
path: path,
|
||||
options: options
|
||||
});
|
||||
<% } else { %>
|
||||
<% if (ctx.dev) { %>
|
||||
return __whitelistWarning('removeFile')
|
||||
<% } %>
|
||||
return __reject()
|
||||
<% } %>
|
||||
},
|
||||
|
||||
<% if (ctx.dev) { %>
|
||||
/**
|
||||
* @name renameFile
|
||||
* @description Renames a file
|
||||
* Permissions based on the app's PID owner
|
||||
* @param {String} path
|
||||
* @param {Object} [options]
|
||||
* @param {BaseDirectory} [options.dir]
|
||||
* @returns {*|Promise<any>|Promise}
|
||||
*/
|
||||
<% } %>
|
||||
renameFile: function renameFile(oldPath, newPath, options) {
|
||||
<% if (tauri.whitelist.renameFile === true || tauri.whitelist.all === true) { %>
|
||||
return this.promisified({
|
||||
cmd: 'renameFile',
|
||||
old_path: oldPath,
|
||||
new_path: newPath,
|
||||
options: options
|
||||
});
|
||||
<% } else { %>
|
||||
<% if (ctx.dev) { %>
|
||||
return __whitelistWarning('renameFile')
|
||||
<% } %>
|
||||
return __reject()
|
||||
<% } %>
|
||||
|
@ -398,24 +551,64 @@ window.tauri = {
|
|||
<% } %>
|
||||
},
|
||||
|
||||
bridge: function bridge(command, payload) {
|
||||
<% if (tauri.whitelist.bridge === true || tauri.whitelist.all === true) { %>
|
||||
|
||||
if (_typeof(payload) === 'object') {
|
||||
Object.freeze(payload);
|
||||
}
|
||||
|
||||
return this.promisified({
|
||||
cmd: 'bridge',
|
||||
command: command,
|
||||
payload: _typeof(payload) === 'object' ? [payload] : payload
|
||||
});
|
||||
<% if (ctx.dev) { %>
|
||||
/**
|
||||
* @name openDialog
|
||||
* @description Open a file/directory selection dialog
|
||||
* @param {String} [options]
|
||||
* @param {String} [options.filter]
|
||||
* @param {String} [options.defaultPath]
|
||||
* @param {Boolean} [options.multiple=false]
|
||||
* @param {Boolean} [options.directory=false]
|
||||
* @returns {Promise<String|String[]>} promise resolving to the select path(s)
|
||||
*/
|
||||
<% } %>
|
||||
openDialog: function openDialog(options) {
|
||||
<% if (tauri.whitelist.openDialog === true || tauri.whitelist.all === true) { %>
|
||||
var opts = options || {}
|
||||
if (_typeof(options) === 'object') {
|
||||
opts.default_path = opts.defaultPath
|
||||
Object.freeze(options);
|
||||
}
|
||||
return this.promisified({
|
||||
cmd: 'openDialog',
|
||||
options: opts
|
||||
});
|
||||
<% } else { %>
|
||||
<% if (ctx.dev) { %>
|
||||
return __whitelistWarning('bridge')
|
||||
<% if (ctx.dev) { %>
|
||||
return __whitelistWarning('openDialog')
|
||||
<% } %>
|
||||
return __reject()
|
||||
<% } %>
|
||||
},
|
||||
|
||||
<% if (ctx.dev) { %>
|
||||
/**
|
||||
* @name saveDialog
|
||||
* @description Open a file/directory save dialog
|
||||
* @param {String} [options]
|
||||
* @param {String} [options.filter]
|
||||
* @param {String} [options.defaultPath]
|
||||
* @returns {Promise<String>} promise resolving to the select path
|
||||
*/
|
||||
<% } %>
|
||||
saveDialog: function saveDialog(options) {
|
||||
<% if (tauri.whitelist.saveDialog === true || tauri.whitelist.all === true) { %>
|
||||
var opts = options || {}
|
||||
if (_typeof(options) === 'object') {
|
||||
opts.default_path = opts.defaultPath
|
||||
Object.freeze(options);
|
||||
}
|
||||
return this.promisified({
|
||||
cmd: 'saveDialog',
|
||||
options: opts
|
||||
});
|
||||
<% } else { %>
|
||||
<% if (ctx.dev) { %>
|
||||
return __whitelistWarning('saveDialog')
|
||||
<% } %>
|
||||
return __reject()
|
||||
<% } %>
|
||||
return __reject()
|
||||
<% } %>
|
||||
},
|
||||
|
||||
loadAsset: function loadAsset(assetName, assetType) {
|
||||
|
|
|
@ -0,0 +1,72 @@
|
|||
const path = require('path')
|
||||
const fixtureSetup = require('../fixtures/app-test-setup')
|
||||
const appDir = path.join(fixtureSetup.fixtureDir, 'app')
|
||||
const distDir = path.join(appDir, 'dist')
|
||||
|
||||
const spawn = require('helpers/spawn').spawn
|
||||
|
||||
function runBuildTest(tauriConfig) {
|
||||
fixtureSetup.initJest('app')
|
||||
const build = require('api/build')
|
||||
return new Promise(async (resolve, reject) => {
|
||||
try {
|
||||
let success = false
|
||||
const server = fixtureSetup.startServer(() => {
|
||||
success = true
|
||||
// wait for the app process to be killed
|
||||
setTimeout(resolve, 2000)
|
||||
})
|
||||
const result = build(tauriConfig)
|
||||
await result.promise
|
||||
|
||||
const artifactFolder = tauriConfig.ctx.debug ? 'debug' : 'release'
|
||||
const artifactPath = path.resolve(appDir, `src-tauri/target/${artifactFolder}/app`)
|
||||
|
||||
const appPid = spawn(
|
||||
process.platform === 'win32' ? `${artifactPath}.exe` : artifactPath.replace(`${artifactFolder}/app`, `${artifactFolder}/./app`),
|
||||
[],
|
||||
null
|
||||
)
|
||||
|
||||
setTimeout(() => {
|
||||
if (!success) {
|
||||
server.close(() => {
|
||||
try {
|
||||
process.kill(appPid)
|
||||
} catch {}
|
||||
reject("App didn't reply")
|
||||
})
|
||||
}
|
||||
}, 2500)
|
||||
} catch (error) {
|
||||
reject(error)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
describe('Tauri Build', () => {
|
||||
const build = {
|
||||
devPath: distDir,
|
||||
distDir: distDir
|
||||
}
|
||||
|
||||
it.each`
|
||||
mode | flag
|
||||
${'embedded-server'} | ${'debug'}
|
||||
${'embedded-server'} | ${'release'}
|
||||
${'no-server'} | ${'debug'}
|
||||
${'no-server'} | ${'release'}
|
||||
`('works with the $mode $flag mode', ({ mode, flag }) => {
|
||||
return runBuildTest({
|
||||
build,
|
||||
ctx: {
|
||||
debug: flag === 'debug'
|
||||
},
|
||||
tauri: {
|
||||
embeddedServer: {
|
||||
active: mode === 'embedded-server'
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
|
@ -0,0 +1,96 @@
|
|||
const path = require('path')
|
||||
const fixtureSetup = require('../fixtures/app-test-setup')
|
||||
const distDir = path.resolve(fixtureSetup.fixtureDir, 'app', 'dist')
|
||||
|
||||
function startDevServer() {
|
||||
const http = require('http')
|
||||
const { statSync, createReadStream } = require('fs')
|
||||
const app = http.createServer((req, res) => {
|
||||
if (req.method === 'GET') {
|
||||
if (req.url === '/') {
|
||||
const indexPath = path.join(distDir, 'index.html')
|
||||
const stat = statSync(indexPath)
|
||||
res.writeHead(200, {
|
||||
'Content-Type': 'text/html',
|
||||
'Content-Length': stat.size
|
||||
})
|
||||
createReadStream(indexPath).pipe(res)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const port = 7001
|
||||
|
||||
const server = app.listen(port)
|
||||
return {
|
||||
server,
|
||||
url: `http://localhost:${port}`
|
||||
}
|
||||
}
|
||||
|
||||
function runDevTest(tauriConfig) {
|
||||
fixtureSetup.initJest('app')
|
||||
const dev = require('api/dev')
|
||||
return new Promise(async (resolve, reject) => {
|
||||
try {
|
||||
const { promise, runner } = dev(tauriConfig)
|
||||
|
||||
const isRunning = require('is-running')
|
||||
let success = false
|
||||
const checkIntervalId = setInterval(async () => {
|
||||
if (!isRunning(runner.pid) && !success) {
|
||||
server.close(() => reject("App didn't reply"))
|
||||
}
|
||||
}, 2000)
|
||||
|
||||
const server = fixtureSetup.startServer(async () => {
|
||||
success = true
|
||||
clearInterval(checkIntervalId)
|
||||
// wait for the app process to be killed
|
||||
setTimeout(async () => {
|
||||
try {
|
||||
await runner.stop()
|
||||
} catch {}
|
||||
resolve()
|
||||
}, 2000)
|
||||
})
|
||||
await promise
|
||||
} catch (error) {
|
||||
reject(error)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
describe('Tauri Dev', () => {
|
||||
const build = {
|
||||
distDir: distDir
|
||||
}
|
||||
|
||||
const devServer = startDevServer()
|
||||
|
||||
it.each`
|
||||
url
|
||||
${devServer.url}
|
||||
${distDir}
|
||||
`('works with dev pointing to $url', ({ url }) => {
|
||||
const runningDevServer = url.startsWith('http')
|
||||
const promise = runDevTest({
|
||||
build: {
|
||||
...build,
|
||||
devPath: url
|
||||
},
|
||||
ctx: {
|
||||
debug: true,
|
||||
dev: true
|
||||
}
|
||||
})
|
||||
|
||||
promise.then(() => {
|
||||
if (runningDevServer) {
|
||||
devServer.server.close()
|
||||
}
|
||||
})
|
||||
|
||||
return promise
|
||||
})
|
||||
})
|
|
@ -1,4 +1,3 @@
|
|||
// eslint-disable-next-line node/no-missing-require
|
||||
const { tauri } = require('bin/tauri')
|
||||
|
||||
describe('[CLI] tauri.js', () => {
|
||||
|
@ -27,6 +26,7 @@ describe('[CLI] tauri.js', () => {
|
|||
|
||||
it('will pass on an available command', async () => {
|
||||
jest.spyOn(console, 'log')
|
||||
jest.mock('fs')
|
||||
tauri('init')
|
||||
expect(console.log.mock.calls[0][0].split('.')[0]).toBe('[tauri]: running init')
|
||||
jest.clearAllMocks()
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
const tauricon = require('~/dist/api/tauricon.js')
|
||||
const appTestSetup = require('../fixtures/app-test-setup')
|
||||
appTestSetup.initJest('app')
|
||||
|
||||
const tauricon = require('api/tauricon')
|
||||
|
||||
describe('[CLI] tauri-icon internals', () => {
|
||||
it('tells you the version', () => {
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
const fixtureSetup = require('../fixtures/app-test-setup')
|
||||
const { resolve } = require('path')
|
||||
const { rmdirSync, existsSync, writeFileSync, readFileSync } = require('fs')
|
||||
|
||||
describe('[CLI] tauri.js template', () => {
|
||||
it('init a project and builds it', done => {
|
||||
const cwd = process.cwd()
|
||||
try {
|
||||
const fixturePath = resolve(__dirname, '../fixtures/empty')
|
||||
const tauriFixturePath = resolve(fixturePath, 'src-tauri')
|
||||
|
||||
fixtureSetup.initJest('empty')
|
||||
|
||||
process.chdir(fixturePath)
|
||||
|
||||
const init = require('api/init')
|
||||
init({
|
||||
directory: process.cwd(),
|
||||
force: true,
|
||||
tauriPath: resolve(__dirname, '../../../../..')
|
||||
})
|
||||
|
||||
process.chdir(tauriFixturePath)
|
||||
|
||||
const manifestPath = resolve(tauriFixturePath, 'Cargo.toml')
|
||||
const manifestFile = readFileSync(manifestPath).toString()
|
||||
writeFileSync(manifestPath, `workspace = { }\n\n${manifestFile}`)
|
||||
} catch (e) {
|
||||
done(e)
|
||||
}
|
||||
|
||||
const build = require('api/build')
|
||||
build().promise.then(() => {
|
||||
process.chdir(cwd)
|
||||
done()
|
||||
}).catch(done)
|
||||
})
|
||||
})
|
|
@ -0,0 +1,71 @@
|
|||
const path = require('path')
|
||||
const process = require('process')
|
||||
|
||||
const mockFixtureDir = path.resolve(__dirname, '../fixtures')
|
||||
|
||||
module.exports.fixtureDir = mockFixtureDir
|
||||
|
||||
module.exports.initJest = (mockFixture) => {
|
||||
jest.setTimeout(720000)
|
||||
jest.mock('helpers/non-webpack-require', () => {
|
||||
return path => {
|
||||
const value = require('fs').readFileSync(path).toString()
|
||||
if (path.endsWith('.json')) {
|
||||
return JSON.parse(value)
|
||||
}
|
||||
return value
|
||||
}
|
||||
})
|
||||
|
||||
jest.mock('helpers/app-paths', () => {
|
||||
const path = require('path')
|
||||
const appDir = path.join(mockFixtureDir, mockFixture)
|
||||
const tauriDir = path.join(appDir, 'src-tauri')
|
||||
return {
|
||||
appDir,
|
||||
tauriDir,
|
||||
resolve: {
|
||||
app: dir => path.join(appDir, dir),
|
||||
tauri: dir => path.join(tauriDir, dir)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
jest.spyOn(process, 'exit').mockImplementation(() => {})
|
||||
}
|
||||
|
||||
module.exports.startServer = (onReply) => {
|
||||
const http = require('http')
|
||||
const app = http.createServer((req, res) => {
|
||||
// Set CORS headers
|
||||
res.setHeader('Access-Control-Allow-Origin', '*')
|
||||
res.setHeader('Access-Control-Request-Method', '*')
|
||||
res.setHeader('Access-Control-Allow-Methods', 'OPTIONS, GET')
|
||||
res.setHeader('Access-Control-Allow-Headers', '*')
|
||||
|
||||
if (req.method === 'OPTIONS') {
|
||||
res.writeHead(200)
|
||||
res.end()
|
||||
return
|
||||
}
|
||||
|
||||
if (req.method === 'POST') {
|
||||
if (req.url === '/reply') {
|
||||
let body = ''
|
||||
req.on('data', chunk => {
|
||||
body += chunk.toString()
|
||||
})
|
||||
req.on('end', () => {
|
||||
expect(JSON.parse(body)).toStrictEqual({
|
||||
msg: 'TEST'
|
||||
})
|
||||
server.close(onReply)
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const port = 7000
|
||||
const server = app.listen(port)
|
||||
return server
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
dist/index.tauri.html
|
|
@ -0,0 +1,24 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<body>
|
||||
<script>
|
||||
function notify(route, args) {
|
||||
var xhr = new XMLHttpRequest()
|
||||
xhr.open('POST', 'http://localhost:7000/' + route)
|
||||
xhr.setRequestHeader('Content-type', 'application/json')
|
||||
xhr.send(JSON.stringify(args))
|
||||
}
|
||||
|
||||
window.onTauriInit = function () {
|
||||
window.tauri.listen('reply', function (res) {
|
||||
notify('reply', res.payload)
|
||||
})
|
||||
window.tauri.emit('hello')
|
||||
}
|
||||
setTimeout(function () {
|
||||
window.tauri.invoke({ cmd: 'exit' })
|
||||
}, 1000)
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
|
@ -0,0 +1,54 @@
|
|||
const express = require('express')
|
||||
const cors = require('cors')
|
||||
const app = express()
|
||||
app.use(cors())
|
||||
app.use(express.json())
|
||||
const port = 7000
|
||||
let appPid
|
||||
|
||||
app.post('/reply', (req, res) => {
|
||||
if (req.body && req.body.msg !== 'TEST') {
|
||||
throw new Error(`unexpected reply ${JSON.stringify(req.body)}`)
|
||||
}
|
||||
console.log('App event replied')
|
||||
exit(0)
|
||||
})
|
||||
|
||||
const server = app.listen(port, () => console.log(`Test listening on port ${port}!`))
|
||||
|
||||
const exit = code => {
|
||||
server.close()
|
||||
process.kill(appPid)
|
||||
process.exit(code)
|
||||
}
|
||||
|
||||
const path = require('path')
|
||||
const dist = path.resolve(__dirname, 'dist')
|
||||
|
||||
const build = require('../cli/tauri.js/dist/api/build')
|
||||
build({
|
||||
build: {
|
||||
devPath: dist
|
||||
},
|
||||
ctx: {
|
||||
debug: true
|
||||
},
|
||||
tauri: {
|
||||
embeddedServer: {
|
||||
active: true
|
||||
}
|
||||
}
|
||||
}).then(() => {
|
||||
const spawn = require('../cli/tauri.js/dist/helpers/spawn').spawn
|
||||
const artifactPath = path.resolve(__dirname, 'src-tauri/target/debug/app')
|
||||
appPid = spawn(
|
||||
process.platform === 'win32' ? `${artifactPath}.exe` : artifactPath.replace('debug/app', 'debug/./app'),
|
||||
[],
|
||||
null
|
||||
)
|
||||
|
||||
// if it didn't reply, throw an error
|
||||
setTimeout(() => {
|
||||
throw new Error("App didn't reply")
|
||||
}, 2000)
|
||||
})
|
|
@ -0,0 +1,22 @@
|
|||
{
|
||||
"name": "test",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"tauri:prod": "tauri",
|
||||
"tauri:source": "node ../../../../bin/tauri",
|
||||
"tauri:source:init": "yarn tauri:source init --tauriPath ..",
|
||||
"tauri:prod:init": "yarn tauri:prod init",
|
||||
"tauri:source:dev": "yarn tauri:source dev",
|
||||
"tauri:prod:dev": "yarn tauri:prod dev",
|
||||
"tauri:source:build": "yarn tauri:source build",
|
||||
"tauri:prod:build": "yarn tauri:prod build"
|
||||
},
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"cors": "^2.8.5",
|
||||
"express": "^4.17.1"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
# Generated by Cargo
|
||||
# will have compiled files and executables
|
||||
/target/
|
||||
|
||||
# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
|
||||
# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html
|
||||
Cargo.lock
|
||||
|
||||
# These are backup files generated by rustfmt
|
||||
**/*.rs.bk
|
||||
|
||||
tauri.js
|
||||
config.json
|
||||
bundle.json
|
|
@ -0,0 +1,39 @@
|
|||
workspace = { }
|
||||
|
||||
[package]
|
||||
name = "app"
|
||||
version = "0.1.0"
|
||||
description = "A Tauri App"
|
||||
author = [ "Daniel Thompson-Yvetot" ]
|
||||
license = ""
|
||||
repository = ""
|
||||
default-run = "app"
|
||||
edition = "2018"
|
||||
|
||||
[package.metadata.bundle]
|
||||
identifier = "com.tauri.dev"
|
||||
icon = [
|
||||
"icons/32x32.png",
|
||||
"icons/128x128.png",
|
||||
"icons/128x128@2x.png",
|
||||
"icons/icon.icns",
|
||||
"icons/icon.ico"
|
||||
]
|
||||
|
||||
[dependencies]
|
||||
serde_json = "1.0.48"
|
||||
serde = "1.0"
|
||||
serde_derive = "1.0"
|
||||
tiny_http = "0.6"
|
||||
phf = "0.8.0"
|
||||
includedir = "0.5.0"
|
||||
tauri = { path = "../../../../../../../tauri", features = [ "all-api", "edge" ] }
|
||||
|
||||
[features]
|
||||
dev-server = [ "tauri/dev-server" ]
|
||||
embedded-server = [ "tauri/embedded-server" ]
|
||||
no-server = [ "tauri/no-server" ]
|
||||
|
||||
[[bin]]
|
||||
name = "app"
|
||||
path = "src/main.rs"
|
After Width: | Height: | Size: 13 KiB |
After Width: | Height: | Size: 30 KiB |
After Width: | Height: | Size: 2.0 KiB |
After Width: | Height: | Size: 10 KiB |
After Width: | Height: | Size: 14 KiB |
After Width: | Height: | Size: 16 KiB |
After Width: | Height: | Size: 33 KiB |
After Width: | Height: | Size: 1.7 KiB |
After Width: | Height: | Size: 38 KiB |
After Width: | Height: | Size: 3.2 KiB |
After Width: | Height: | Size: 6.0 KiB |
After Width: | Height: | Size: 8.1 KiB |
After Width: | Height: | Size: 3.7 KiB |
After Width: | Height: | Size: 57 KiB |
After Width: | Height: | Size: 76 KiB |
|
@ -0,0 +1,13 @@
|
|||
max_width = 100
|
||||
hard_tabs = false
|
||||
tab_spaces = 2
|
||||
newline_style = "Auto"
|
||||
use_small_heuristics = "Default"
|
||||
reorder_imports = true
|
||||
reorder_modules = true
|
||||
remove_nested_parens = true
|
||||
edition = "2018"
|
||||
merge_derives = true
|
||||
use_try_shorthand = false
|
||||
use_field_init_shorthand = false
|
||||
force_explicit_abi = true
|
|
@ -0,0 +1,8 @@
|
|||
#[derive(Deserialize)]
|
||||
#[serde(tag = "cmd", rename_all = "camelCase")]
|
||||
pub enum Cmd {
|
||||
// your custom commands
|
||||
// multiple arguments are allowed
|
||||
// note that rename_all = "camelCase": you need to use "myCustomCommand" on JS
|
||||
Exit { },
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
mod cmd;
|
||||
|
||||
#[macro_use]
|
||||
extern crate serde_derive;
|
||||
extern crate serde_json;
|
||||
|
||||
fn main() {
|
||||
tauri::AppBuilder::new()
|
||||
.setup(|_webview| {
|
||||
let handle = _webview.handle();
|
||||
tauri::event::listen(String::from("hello"), move |_| {
|
||||
tauri::event::emit(&handle, String::from("reply"), "{ msg: 'TEST' }".to_string());
|
||||
});
|
||||
})
|
||||
.invoke_handler(|webview, arg| {
|
||||
use cmd::Cmd::*;
|
||||
match serde_json::from_str(arg) {
|
||||
Err(_) => {}
|
||||
Ok(command) => {
|
||||
match command {
|
||||
// definitions for your custom commands from Cmd here
|
||||
Exit { } => {
|
||||
webview.exit();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
.build()
|
||||
.run();
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"tauri": {
|
||||
"whitelist": {
|
||||
"all": true
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,381 @@
|
|||
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
|
||||
# yarn lockfile v1
|
||||
|
||||
|
||||
accepts@~1.3.7:
|
||||
version "1.3.7"
|
||||
resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.7.tgz#531bc726517a3b2b41f850021c6cc15eaab507cd"
|
||||
integrity sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==
|
||||
dependencies:
|
||||
mime-types "~2.1.24"
|
||||
negotiator "0.6.2"
|
||||
|
||||
array-flatten@1.1.1:
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2"
|
||||
integrity sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=
|
||||
|
||||
body-parser@1.19.0:
|
||||
version "1.19.0"
|
||||
resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.19.0.tgz#96b2709e57c9c4e09a6fd66a8fd979844f69f08a"
|
||||
integrity sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==
|
||||
dependencies:
|
||||
bytes "3.1.0"
|
||||
content-type "~1.0.4"
|
||||
debug "2.6.9"
|
||||
depd "~1.1.2"
|
||||
http-errors "1.7.2"
|
||||
iconv-lite "0.4.24"
|
||||
on-finished "~2.3.0"
|
||||
qs "6.7.0"
|
||||
raw-body "2.4.0"
|
||||
type-is "~1.6.17"
|
||||
|
||||
bytes@3.1.0:
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.0.tgz#f6cf7933a360e0588fa9fde85651cdc7f805d1f6"
|
||||
integrity sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==
|
||||
|
||||
content-disposition@0.5.3:
|
||||
version "0.5.3"
|
||||
resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.3.tgz#e130caf7e7279087c5616c2007d0485698984fbd"
|
||||
integrity sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==
|
||||
dependencies:
|
||||
safe-buffer "5.1.2"
|
||||
|
||||
content-type@~1.0.4:
|
||||
version "1.0.4"
|
||||
resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b"
|
||||
integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==
|
||||
|
||||
cookie-signature@1.0.6:
|
||||
version "1.0.6"
|
||||
resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c"
|
||||
integrity sha1-4wOogrNCzD7oylE6eZmXNNqzriw=
|
||||
|
||||
cookie@0.4.0:
|
||||
version "0.4.0"
|
||||
resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.0.tgz#beb437e7022b3b6d49019d088665303ebe9c14ba"
|
||||
integrity sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==
|
||||
|
||||
cors@^2.8.5:
|
||||
version "2.8.5"
|
||||
resolved "https://registry.yarnpkg.com/cors/-/cors-2.8.5.tgz#eac11da51592dd86b9f06f6e7ac293b3df875d29"
|
||||
integrity sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==
|
||||
dependencies:
|
||||
object-assign "^4"
|
||||
vary "^1"
|
||||
|
||||
debug@2.6.9:
|
||||
version "2.6.9"
|
||||
resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
|
||||
integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==
|
||||
dependencies:
|
||||
ms "2.0.0"
|
||||
|
||||
depd@~1.1.2:
|
||||
version "1.1.2"
|
||||
resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9"
|
||||
integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=
|
||||
|
||||
destroy@~1.0.4:
|
||||
version "1.0.4"
|
||||
resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80"
|
||||
integrity sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=
|
||||
|
||||
ee-first@1.1.1:
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d"
|
||||
integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=
|
||||
|
||||
encodeurl@~1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59"
|
||||
integrity sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=
|
||||
|
||||
escape-html@~1.0.3:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988"
|
||||
integrity sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=
|
||||
|
||||
etag@~1.8.1:
|
||||
version "1.8.1"
|
||||
resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887"
|
||||
integrity sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=
|
||||
|
||||
express@^4.17.1:
|
||||
version "4.17.1"
|
||||
resolved "https://registry.yarnpkg.com/express/-/express-4.17.1.tgz#4491fc38605cf51f8629d39c2b5d026f98a4c134"
|
||||
integrity sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==
|
||||
dependencies:
|
||||
accepts "~1.3.7"
|
||||
array-flatten "1.1.1"
|
||||
body-parser "1.19.0"
|
||||
content-disposition "0.5.3"
|
||||
content-type "~1.0.4"
|
||||
cookie "0.4.0"
|
||||
cookie-signature "1.0.6"
|
||||
debug "2.6.9"
|
||||
depd "~1.1.2"
|
||||
encodeurl "~1.0.2"
|
||||
escape-html "~1.0.3"
|
||||
etag "~1.8.1"
|
||||
finalhandler "~1.1.2"
|
||||
fresh "0.5.2"
|
||||
merge-descriptors "1.0.1"
|
||||
methods "~1.1.2"
|
||||
on-finished "~2.3.0"
|
||||
parseurl "~1.3.3"
|
||||
path-to-regexp "0.1.7"
|
||||
proxy-addr "~2.0.5"
|
||||
qs "6.7.0"
|
||||
range-parser "~1.2.1"
|
||||
safe-buffer "5.1.2"
|
||||
send "0.17.1"
|
||||
serve-static "1.14.1"
|
||||
setprototypeof "1.1.1"
|
||||
statuses "~1.5.0"
|
||||
type-is "~1.6.18"
|
||||
utils-merge "1.0.1"
|
||||
vary "~1.1.2"
|
||||
|
||||
finalhandler@~1.1.2:
|
||||
version "1.1.2"
|
||||
resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.2.tgz#b7e7d000ffd11938d0fdb053506f6ebabe9f587d"
|
||||
integrity sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==
|
||||
dependencies:
|
||||
debug "2.6.9"
|
||||
encodeurl "~1.0.2"
|
||||
escape-html "~1.0.3"
|
||||
on-finished "~2.3.0"
|
||||
parseurl "~1.3.3"
|
||||
statuses "~1.5.0"
|
||||
unpipe "~1.0.0"
|
||||
|
||||
forwarded@~0.1.2:
|
||||
version "0.1.2"
|
||||
resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.2.tgz#98c23dab1175657b8c0573e8ceccd91b0ff18c84"
|
||||
integrity sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=
|
||||
|
||||
fresh@0.5.2:
|
||||
version "0.5.2"
|
||||
resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7"
|
||||
integrity sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=
|
||||
|
||||
http-errors@1.7.2:
|
||||
version "1.7.2"
|
||||
resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.2.tgz#4f5029cf13239f31036e5b2e55292bcfbcc85c8f"
|
||||
integrity sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==
|
||||
dependencies:
|
||||
depd "~1.1.2"
|
||||
inherits "2.0.3"
|
||||
setprototypeof "1.1.1"
|
||||
statuses ">= 1.5.0 < 2"
|
||||
toidentifier "1.0.0"
|
||||
|
||||
http-errors@~1.7.2:
|
||||
version "1.7.3"
|
||||
resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.3.tgz#6c619e4f9c60308c38519498c14fbb10aacebb06"
|
||||
integrity sha512-ZTTX0MWrsQ2ZAhA1cejAwDLycFsd7I7nVtnkT3Ol0aqodaKW+0CTZDQ1uBv5whptCnc8e8HeRRJxRs0kmm/Qfw==
|
||||
dependencies:
|
||||
depd "~1.1.2"
|
||||
inherits "2.0.4"
|
||||
setprototypeof "1.1.1"
|
||||
statuses ">= 1.5.0 < 2"
|
||||
toidentifier "1.0.0"
|
||||
|
||||
iconv-lite@0.4.24:
|
||||
version "0.4.24"
|
||||
resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b"
|
||||
integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==
|
||||
dependencies:
|
||||
safer-buffer ">= 2.1.2 < 3"
|
||||
|
||||
inherits@2.0.3:
|
||||
version "2.0.3"
|
||||
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de"
|
||||
integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=
|
||||
|
||||
inherits@2.0.4:
|
||||
version "2.0.4"
|
||||
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
|
||||
integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
|
||||
|
||||
ipaddr.js@1.9.0:
|
||||
version "1.9.0"
|
||||
resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.0.tgz#37df74e430a0e47550fe54a2defe30d8acd95f65"
|
||||
integrity sha512-M4Sjn6N/+O6/IXSJseKqHoFc+5FdGJ22sXqnjTpdZweHK64MzEPAyQZyEU3R/KRv2GLoa7nNtg/C2Ev6m7z+eA==
|
||||
|
||||
media-typer@0.3.0:
|
||||
version "0.3.0"
|
||||
resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748"
|
||||
integrity sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=
|
||||
|
||||
merge-descriptors@1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61"
|
||||
integrity sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=
|
||||
|
||||
methods@~1.1.2:
|
||||
version "1.1.2"
|
||||
resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee"
|
||||
integrity sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=
|
||||
|
||||
mime-db@1.42.0:
|
||||
version "1.42.0"
|
||||
resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.42.0.tgz#3e252907b4c7adb906597b4b65636272cf9e7bac"
|
||||
integrity sha512-UbfJCR4UAVRNgMpfImz05smAXK7+c+ZntjaA26ANtkXLlOe947Aag5zdIcKQULAiF9Cq4WxBi9jUs5zkA84bYQ==
|
||||
|
||||
mime-types@~2.1.24:
|
||||
version "2.1.25"
|
||||
resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.25.tgz#39772d46621f93e2a80a856c53b86a62156a6437"
|
||||
integrity sha512-5KhStqB5xpTAeGqKBAMgwaYMnQik7teQN4IAzC7npDv6kzeU6prfkR67bc87J1kWMPGkoaZSq1npmexMgkmEVg==
|
||||
dependencies:
|
||||
mime-db "1.42.0"
|
||||
|
||||
mime@1.6.0:
|
||||
version "1.6.0"
|
||||
resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1"
|
||||
integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==
|
||||
|
||||
ms@2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
|
||||
integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=
|
||||
|
||||
ms@2.1.1:
|
||||
version "2.1.1"
|
||||
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a"
|
||||
integrity sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==
|
||||
|
||||
negotiator@0.6.2:
|
||||
version "0.6.2"
|
||||
resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb"
|
||||
integrity sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==
|
||||
|
||||
object-assign@^4:
|
||||
version "4.1.1"
|
||||
resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
|
||||
integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=
|
||||
|
||||
on-finished@~2.3.0:
|
||||
version "2.3.0"
|
||||
resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947"
|
||||
integrity sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=
|
||||
dependencies:
|
||||
ee-first "1.1.1"
|
||||
|
||||
parseurl@~1.3.3:
|
||||
version "1.3.3"
|
||||
resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4"
|
||||
integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==
|
||||
|
||||
path-to-regexp@0.1.7:
|
||||
version "0.1.7"
|
||||
resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c"
|
||||
integrity sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=
|
||||
|
||||
proxy-addr@~2.0.5:
|
||||
version "2.0.5"
|
||||
resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.5.tgz#34cbd64a2d81f4b1fd21e76f9f06c8a45299ee34"
|
||||
integrity sha512-t/7RxHXPH6cJtP0pRG6smSr9QJidhB+3kXu0KgXnbGYMgzEnUxRQ4/LDdfOwZEMyIh3/xHb8PX3t+lfL9z+YVQ==
|
||||
dependencies:
|
||||
forwarded "~0.1.2"
|
||||
ipaddr.js "1.9.0"
|
||||
|
||||
qs@6.7.0:
|
||||
version "6.7.0"
|
||||
resolved "https://registry.yarnpkg.com/qs/-/qs-6.7.0.tgz#41dc1a015e3d581f1621776be31afb2876a9b1bc"
|
||||
integrity sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==
|
||||
|
||||
range-parser@~1.2.1:
|
||||
version "1.2.1"
|
||||
resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031"
|
||||
integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==
|
||||
|
||||
raw-body@2.4.0:
|
||||
version "2.4.0"
|
||||
resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.4.0.tgz#a1ce6fb9c9bc356ca52e89256ab59059e13d0332"
|
||||
integrity sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==
|
||||
dependencies:
|
||||
bytes "3.1.0"
|
||||
http-errors "1.7.2"
|
||||
iconv-lite "0.4.24"
|
||||
unpipe "1.0.0"
|
||||
|
||||
safe-buffer@5.1.2:
|
||||
version "5.1.2"
|
||||
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d"
|
||||
integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==
|
||||
|
||||
"safer-buffer@>= 2.1.2 < 3":
|
||||
version "2.1.2"
|
||||
resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
|
||||
integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==
|
||||
|
||||
send@0.17.1:
|
||||
version "0.17.1"
|
||||
resolved "https://registry.yarnpkg.com/send/-/send-0.17.1.tgz#c1d8b059f7900f7466dd4938bdc44e11ddb376c8"
|
||||
integrity sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==
|
||||
dependencies:
|
||||
debug "2.6.9"
|
||||
depd "~1.1.2"
|
||||
destroy "~1.0.4"
|
||||
encodeurl "~1.0.2"
|
||||
escape-html "~1.0.3"
|
||||
etag "~1.8.1"
|
||||
fresh "0.5.2"
|
||||
http-errors "~1.7.2"
|
||||
mime "1.6.0"
|
||||
ms "2.1.1"
|
||||
on-finished "~2.3.0"
|
||||
range-parser "~1.2.1"
|
||||
statuses "~1.5.0"
|
||||
|
||||
serve-static@1.14.1:
|
||||
version "1.14.1"
|
||||
resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.14.1.tgz#666e636dc4f010f7ef29970a88a674320898b2f9"
|
||||
integrity sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==
|
||||
dependencies:
|
||||
encodeurl "~1.0.2"
|
||||
escape-html "~1.0.3"
|
||||
parseurl "~1.3.3"
|
||||
send "0.17.1"
|
||||
|
||||
setprototypeof@1.1.1:
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.1.tgz#7e95acb24aa92f5885e0abef5ba131330d4ae683"
|
||||
integrity sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==
|
||||
|
||||
"statuses@>= 1.5.0 < 2", statuses@~1.5.0:
|
||||
version "1.5.0"
|
||||
resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c"
|
||||
integrity sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=
|
||||
|
||||
toidentifier@1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.0.tgz#7e1be3470f1e77948bc43d94a3c8f4d7752ba553"
|
||||
integrity sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==
|
||||
|
||||
type-is@~1.6.17, type-is@~1.6.18:
|
||||
version "1.6.18"
|
||||
resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131"
|
||||
integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==
|
||||
dependencies:
|
||||
media-typer "0.3.0"
|
||||
mime-types "~2.1.24"
|
||||
|
||||
unpipe@1.0.0, unpipe@~1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec"
|
||||
integrity sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=
|
||||
|
||||
utils-merge@1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713"
|
||||
integrity sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=
|
||||
|
||||
vary@^1, vary@~1.1.2:
|
||||
version "1.1.2"
|
||||
resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc"
|
||||
integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=
|
|
@ -0,0 +1,2 @@
|
|||
src-tauri
|
||||
dist/index.tauri.html
|
|
@ -0,0 +1,6 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<body>
|
||||
<div></div>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1 @@
|
|||
{}
|
|
@ -0,0 +1,3 @@
|
|||
module.exports = {
|
||||
process: content => `module.exports = {default: ${JSON.stringify(content)}}`
|
||||
}
|
|
@ -7,8 +7,9 @@ module.exports = {
|
|||
'api/dev': './src/api/dev.ts',
|
||||
'api/init': './src/api/init.ts',
|
||||
'api/tauricon': './src/api/tauricon.ts',
|
||||
'api/info': './src/api/info.ts',
|
||||
'helpers/tauri-config': './src/helpers/tauri-config.ts',
|
||||
'api/info': './src/api/info.ts'
|
||||
'helpers/spawn': './src/helpers/spawn.ts'
|
||||
},
|
||||
mode: process.env.NODE_ENV || 'development',
|
||||
devtool: 'source-map',
|
||||
|
@ -18,6 +19,10 @@ module.exports = {
|
|||
test: /\.tsx?$/,
|
||||
use: 'ts-loader',
|
||||
exclude: /node_modules/
|
||||
},
|
||||
{
|
||||
test: /templates[\\/](tauri|mutation-observer)\.js/,
|
||||
use: 'raw-loader'
|
||||
}
|
||||
]
|
||||
},
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "tauri-api"
|
||||
version = "0.4.2"
|
||||
version = "0.5.0"
|
||||
authors = ["Lucas Fernandes Gonçalves Nogueira <lucas@quasar.dev>", "Daniel Thompson-Yvetot <denjell@sfosc.org>", "Tensor Programming <tensordeveloper@gmail.com>"]
|
||||
license = "MIT"
|
||||
homepage = "https://tauri.studio"
|
||||
|
@ -11,6 +11,7 @@ exclude = ["test/fixture/**"]
|
|||
|
||||
[dependencies]
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_repr = "0.1"
|
||||
dirs = "2.0.2"
|
||||
ignore = "0.4.11"
|
||||
zip = "0.5.4"
|
||||
|
@ -21,7 +22,9 @@ either = "1.5.3"
|
|||
tar = "0.4"
|
||||
flate2 = "1"
|
||||
error-chain = "0.12"
|
||||
tauri-utils = {version = "0.4", path = "../tauri-utils"}
|
||||
rand = "0.7"
|
||||
nfd = "0.0.4"
|
||||
tauri-utils = {version = "0.5", path = "../tauri-utils"}
|
||||
|
||||
[dev-dependencies]
|
||||
quickcheck = "0.9.2"
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
use nfd::{DialogType, open_dialog};
|
||||
pub use nfd::Response;
|
||||
|
||||
fn open_dialog_internal(dialog_type: DialogType, filter: Option<String>, default_path: Option<String>) -> crate::Result<Response> {
|
||||
open_dialog(filter.as_deref(), default_path.as_deref(), dialog_type)
|
||||
.map_err(|err| crate::Error::with_chain(err, "open dialog failed"))
|
||||
.and_then(|response| {
|
||||
match response {
|
||||
Response::Cancel => Err(crate::Error::from("user cancelled")),
|
||||
_ => Ok(response)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// Open single select file dialog
|
||||
pub fn select(filter_list: Option<String>, default_path: Option<String>) -> crate::Result<Response> {
|
||||
open_dialog_internal(DialogType::SingleFile, filter_list, default_path)
|
||||
}
|
||||
|
||||
/// Open mulitple select file dialog
|
||||
pub fn select_multiple(filter_list: Option<String>, default_path: Option<String>) -> crate::Result<Response> {
|
||||
open_dialog_internal(DialogType::MultipleFiles, filter_list, default_path)
|
||||
}
|
||||
|
||||
/// Open save dialog
|
||||
pub fn save_file(filter_list: Option<String>, default_path: Option<String>) -> crate::Result<Response> {
|
||||
open_dialog_internal(DialogType::SaveFile, filter_list, default_path)
|
||||
}
|
||||
|
||||
/// Open pick folder dialog
|
||||
pub fn pick_folder(default_path: Option<String>) -> crate::Result<Response> {
|
||||
open_dialog_internal(DialogType::PickFolder, None, default_path)
|
||||
}
|
|
@ -44,7 +44,7 @@ pub fn walk_dir(path_copy: String) -> crate::Result<Vec<DiskEntry>> {
|
|||
|
||||
pub fn list_dir_contents(dir_path: String) -> crate::Result<Vec<DiskEntry>> {
|
||||
fs::read_dir(dir_path)
|
||||
.map_err(|err| crate::Error::with_chain(err, "read string failed"))
|
||||
.map_err(|err| crate::Error::with_chain(err, "read dir failed"))
|
||||
.and_then(|paths| {
|
||||
let mut dirs: Vec<DiskEntry> = vec![];
|
||||
for path in paths {
|
||||
|
|
|
@ -8,6 +8,9 @@ pub mod dir;
|
|||
pub mod file;
|
||||
pub mod rpc;
|
||||
pub mod version;
|
||||
pub mod tcp;
|
||||
pub mod dialog;
|
||||
pub mod path;
|
||||
|
||||
pub use tauri_utils::*;
|
||||
|
||||
|
@ -33,5 +36,9 @@ error_chain! {
|
|||
description("File function Error")
|
||||
display("File Error: {}", t)
|
||||
}
|
||||
Path(t: String) {
|
||||
description("Path function Error")
|
||||
display("Path Error: {}", t)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,163 @@
|
|||
use std::path::PathBuf;
|
||||
use serde_repr::{Serialize_repr, Deserialize_repr};
|
||||
|
||||
#[derive(Serialize_repr, Deserialize_repr, Clone, Debug)]
|
||||
#[repr(u16)]
|
||||
pub enum BaseDirectory {
|
||||
Audio = 1,
|
||||
Cache,
|
||||
Config,
|
||||
Data,
|
||||
LocalData,
|
||||
Desktop,
|
||||
Document,
|
||||
Download,
|
||||
Executable,
|
||||
Font,
|
||||
Home,
|
||||
Picture,
|
||||
Public,
|
||||
Runtime,
|
||||
Template,
|
||||
Video,
|
||||
Resource,
|
||||
App,
|
||||
}
|
||||
|
||||
pub fn resolve_path(path: String, dir: Option<BaseDirectory>) -> crate::Result<String> {
|
||||
if let Some(base_dir) = dir {
|
||||
let base_dir_path = match base_dir {
|
||||
BaseDirectory::Audio => audio_dir(),
|
||||
BaseDirectory::Cache => cache_dir(),
|
||||
BaseDirectory::Config => config_dir(),
|
||||
BaseDirectory::Data => data_dir(),
|
||||
BaseDirectory::LocalData => local_data_dir(),
|
||||
BaseDirectory::Desktop => desktop_dir(),
|
||||
BaseDirectory::Document => document_dir(),
|
||||
BaseDirectory::Download => download_dir(),
|
||||
BaseDirectory::Executable => executable_dir(),
|
||||
BaseDirectory::Font => font_dir(),
|
||||
BaseDirectory::Home => home_dir(),
|
||||
BaseDirectory::Picture => picture_dir(),
|
||||
BaseDirectory::Public => public_dir(),
|
||||
BaseDirectory::Runtime => runtime_dir(),
|
||||
BaseDirectory::Template => template_dir(),
|
||||
BaseDirectory::Video => video_dir(),
|
||||
BaseDirectory::Resource => resource_dir(),
|
||||
BaseDirectory::App => app_dir(),
|
||||
};
|
||||
if let Some(mut base_dir_path_value) = base_dir_path {
|
||||
base_dir_path_value.push(path);
|
||||
Ok(base_dir_path_value.to_string_lossy().to_string())
|
||||
} else {
|
||||
Err(crate::Error::from(crate::ErrorKind::Path("unable to determine base dir path".to_string())))
|
||||
}
|
||||
} else {
|
||||
Ok(path)
|
||||
}
|
||||
}
|
||||
|
||||
// Returns the path to the user's audio directory.
|
||||
pub fn audio_dir() -> Option<PathBuf> {
|
||||
dirs::audio_dir()
|
||||
}
|
||||
|
||||
// Returns the path to the user's cache directory.
|
||||
pub fn cache_dir() -> Option<PathBuf> {
|
||||
dirs::cache_dir()
|
||||
}
|
||||
|
||||
// Returns the path to the user's config directory.
|
||||
pub fn config_dir() -> Option<PathBuf> {
|
||||
dirs::config_dir()
|
||||
}
|
||||
|
||||
// Returns the path to the user's data directory.
|
||||
pub fn data_dir() -> Option<PathBuf> {
|
||||
dirs::data_dir()
|
||||
}
|
||||
|
||||
// Returns the path to the user's local data directory.
|
||||
pub fn local_data_dir() -> Option<PathBuf> {
|
||||
dirs::data_local_dir()
|
||||
}
|
||||
|
||||
// Returns the path to the user's desktop directory.
|
||||
pub fn desktop_dir() -> Option<PathBuf> {
|
||||
dirs::desktop_dir()
|
||||
}
|
||||
|
||||
// Returns the path to the user's document directory.
|
||||
pub fn document_dir() -> Option<PathBuf> {
|
||||
dirs::document_dir()
|
||||
}
|
||||
|
||||
// Returns the path to the user's download directory.
|
||||
pub fn download_dir() -> Option<PathBuf> {
|
||||
dirs::download_dir()
|
||||
}
|
||||
|
||||
// Returns the path to the user's executable directory.
|
||||
pub fn executable_dir() -> Option<PathBuf> {
|
||||
dirs::executable_dir()
|
||||
}
|
||||
|
||||
// Returns the path to the user's font directory.
|
||||
pub fn font_dir() -> Option<PathBuf> {
|
||||
dirs::font_dir()
|
||||
}
|
||||
|
||||
// Returns the path to the user's home directory.
|
||||
pub fn home_dir() -> Option<PathBuf> {
|
||||
dirs::home_dir()
|
||||
}
|
||||
|
||||
// Returns the path to the user's picture directory.
|
||||
pub fn picture_dir() -> Option<PathBuf> {
|
||||
dirs::picture_dir()
|
||||
}
|
||||
|
||||
// Returns the path to the user's public directory.
|
||||
pub fn public_dir() -> Option<PathBuf> {
|
||||
dirs::public_dir()
|
||||
}
|
||||
|
||||
// Returns the path to the user's runtime directory.
|
||||
pub fn runtime_dir() -> Option<PathBuf> {
|
||||
dirs::runtime_dir()
|
||||
}
|
||||
|
||||
// Returns the path to the user's template directory.
|
||||
pub fn template_dir() -> Option<PathBuf> {
|
||||
dirs::template_dir()
|
||||
}
|
||||
|
||||
// Returns the path to the user's video dir
|
||||
pub fn video_dir() -> Option<PathBuf> {
|
||||
dirs::video_dir()
|
||||
}
|
||||
|
||||
pub fn resource_dir() -> Option<PathBuf> {
|
||||
crate::platform::resource_dir().ok()
|
||||
}
|
||||
|
||||
fn app_name() -> crate::Result<String> {
|
||||
let exe = std::env::current_exe()?;
|
||||
let app_name = exe
|
||||
.file_name().expect("failed to get exe filename")
|
||||
.to_string_lossy();
|
||||
|
||||
Ok(app_name.to_string())
|
||||
}
|
||||
|
||||
pub fn app_dir() -> Option<PathBuf> {
|
||||
dirs::config_dir()
|
||||
.and_then(|mut dir| {
|
||||
if let Ok(app_name) = app_name() {
|
||||
dir.push(app_name);
|
||||
Some(dir)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
}
|
|
@ -17,8 +17,5 @@ pub fn get_available_port() -> Option<u16> {
|
|||
}
|
||||
|
||||
pub fn port_is_available(port: u16) -> bool {
|
||||
match TcpListener::bind(("127.0.0.1", port)) {
|
||||
Ok(_) => true,
|
||||
Err(_) => false,
|
||||
}
|
||||
TcpListener::bind(("127.0.0.1", port)).is_ok()
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "tauri-updater"
|
||||
version = "0.4.1"
|
||||
version = "0.4.2"
|
||||
authors = ["Lucas Fernandes Gonçalves Nogueira <lucas@quasar.dev>", "Daniel Thompson-Yvetot <denjell@sfosc.org>", "Tensor Programming <tensordeveloper@gmail.com>"]
|
||||
license = "MIT"
|
||||
homepage = "https://tauri.studio"
|
||||
|
@ -17,5 +17,5 @@ serde = "1.0"
|
|||
zip = "0.5.3"
|
||||
tempdir = "0.3"
|
||||
error-chain = "0.12.1"
|
||||
tauri-api = { version = "0.4", path = "../tauri-api" }
|
||||
tauri-utils = { version = "0.4", path = "../tauri-utils" }
|
||||
tauri-api = { version = "0.5", path = "../tauri-api" }
|
||||
tauri-utils = { version = "0.5", path = "../tauri-utils" }
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "tauri-utils"
|
||||
version = "0.4.1"
|
||||
version = "0.5.0"
|
||||
authors = ["Lucas Fernandes Gonçalves Nogueira <lucas@quasar.dev>", "Daniel Thompson-Yvetot <denjell@sfosc.org>", "Tensor Programming <tensordeveloper@gmail.com>"]
|
||||
license = "MIT"
|
||||
homepage = "https://tauri.studio"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "tauri"
|
||||
version = "0.4.3"
|
||||
version = "0.5.0"
|
||||
authors = ["Lucas Fernandes Gonçalves Nogueira <lucas@quasar.dev>", "Daniel Thompson-Yvetot <denjell@sfosc.org>", "Tensor Programming <tensordeveloper@gmail.com>"]
|
||||
license = "MIT"
|
||||
homepage = "https://tauri.studio"
|
||||
|
@ -12,25 +12,28 @@ exclude = ["test/fixture/**"]
|
|||
[dependencies]
|
||||
serde_json = "1.0"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
rand = "0.7"
|
||||
web-view = "0.6.0"
|
||||
webview-sys = "=0.5.0"
|
||||
web-view = "=0.6.2"
|
||||
tauri_includedir = "0.5.0"
|
||||
phf = "0.8.0"
|
||||
base64 = "0.11.0"
|
||||
base64 = "0.12.0"
|
||||
webbrowser = "0.5.2"
|
||||
lazy_static = "1.4.0"
|
||||
tiny_http = "0.6"
|
||||
threadpool = "1.7"
|
||||
uuid = { version = "0.8.1", features = ["v4"] }
|
||||
error-chain = "0.12.1"
|
||||
error-chain = "0.12.2"
|
||||
|
||||
tauri-api = { version = "0.4", path = "../tauri-api" }
|
||||
tauri-api = { version = "0.5", path = "../tauri-api" }
|
||||
|
||||
[build-dependencies]
|
||||
tauri_includedir_codegen = "0.5.2"
|
||||
|
||||
[dev-dependencies]
|
||||
proptest = "0.9.5"
|
||||
serde_json = "1.0"
|
||||
tauri = {path = ".", features = [ "all-api", "edge" ]}
|
||||
serde = { version = "1.0", features = [ "derive" ] }
|
||||
|
||||
[features]
|
||||
edge = ["web-view/edge"]
|
||||
|
@ -38,13 +41,27 @@ dev-server = []
|
|||
embedded-server = []
|
||||
no-server = []
|
||||
all-api = []
|
||||
readTextFile = []
|
||||
readBinaryFile = []
|
||||
writeFile = []
|
||||
listFiles = []
|
||||
listDirs = []
|
||||
setTitle = []
|
||||
read-text-file = []
|
||||
read-binary-file = []
|
||||
write-file = []
|
||||
read-dir = []
|
||||
copy-file = []
|
||||
create-dir = []
|
||||
remove-dir = []
|
||||
remove-file = []
|
||||
rename-file = []
|
||||
set-title = []
|
||||
execute = []
|
||||
open = []
|
||||
event = []
|
||||
updater = []
|
||||
open-dialog = []
|
||||
save-dialog = []
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
features = ["dev-server", "all-api"]
|
||||
|
||||
[[example]]
|
||||
name = "communication"
|
||||
path = "examples/communication/src-tauri/src/main.rs"
|
||||
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
document.getElementById('log').addEventListener('click', function () {
|
||||
window.tauri.invoke({
|
||||
cmd: 'logOperation',
|
||||
event: 'tauri-click',
|
||||
payload: 'this payload is optional because we used Option in Rust'
|
||||
})
|
||||
})
|
||||
|
||||
document.getElementById('request').addEventListener('click', function () {
|
||||
window.tauri.promisified({
|
||||
cmd: 'performRequest',
|
||||
endpoint: 'dummy endpoint arg',
|
||||
body: {
|
||||
id: 5,
|
||||
name: 'test'
|
||||
}
|
||||
}).then(registerResponse).catch(registerResponse)
|
||||
})
|
||||
|
||||
document.getElementById('event').addEventListener('click', function () {
|
||||
window.tauri.emit('js-event', 'this is the payload string')
|
||||
})
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
var defaultPathInput = document.getElementById('dialog-default-path')
|
||||
var filterInput = document.getElementById('dialog-filter')
|
||||
var multipleInput = document.getElementById('dialog-multiple')
|
||||
var directoryInput = document.getElementById('dialog-directory')
|
||||
|
||||
document.getElementById('open-dialog').addEventListener('click', function () {
|
||||
window.tauri.openDialog({
|
||||
defaultPath: defaultPathInput.value || null,
|
||||
filter: filterInput.value || null,
|
||||
multiple: multipleInput.checked,
|
||||
directory: directoryInput.checked
|
||||
}).then(registerResponse).catch(registerResponse)
|
||||
})
|
||||
|
||||
document.getElementById('save-dialog').addEventListener('click', function () {
|
||||
window.tauri.saveDialog({
|
||||
defaultPath: defaultPathInput.value || null,
|
||||
filter: filterInput.value || null
|
||||
}).then(registerResponse).catch(registerResponse)
|
||||
})
|
|
@ -0,0 +1,54 @@
|
|||
var dirSelect = document.getElementById('dir')
|
||||
function getDir () {
|
||||
return dirSelect.value ? parseInt(dir.value) : null
|
||||
}
|
||||
|
||||
function arrayBufferToBase64(buffer, callback) {
|
||||
var blob = new Blob([buffer], {
|
||||
type: 'application/octet-binary'
|
||||
})
|
||||
var reader = new FileReader()
|
||||
reader.onload = function (evt) {
|
||||
var dataurl = evt.target.result
|
||||
callback(dataurl.substr(dataurl.indexOf(',') + 1))
|
||||
}
|
||||
reader.readAsDataURL(blob)
|
||||
}
|
||||
|
||||
var pathInput = document.getElementById('path-to-read')
|
||||
|
||||
addClickEnterHandler(
|
||||
document.getElementById('read'),
|
||||
pathInput,
|
||||
function () {
|
||||
var pathToRead = pathInput.value
|
||||
var isFile = pathToRead.match(/\S+\.\S+$/g)
|
||||
var opts = { dir: getDir() }
|
||||
var promise = isFile ? window.tauri.readBinaryFile(pathToRead, opts) : window.tauri.readDir(pathToRead, opts)
|
||||
promise.then(function (response) {
|
||||
if (isFile) {
|
||||
if (pathToRead.includes('.png') || pathToRead.includes('.jpg')) {
|
||||
arrayBufferToBase64(new Uint8Array(response), function (base64) {
|
||||
var src = 'data:image/png;base64,' + base64
|
||||
registerResponse('<img src="' + src + '"></img>')
|
||||
})
|
||||
} else {
|
||||
var value = String.fromCharCode.apply(null, response)
|
||||
registerResponse('<textarea id="file-response" style="height: 400px"></textarea><button id="file-save">Save</button>')
|
||||
var fileInput = document.getElementById('file-response')
|
||||
fileInput.value = value
|
||||
document.getElementById('file-save').addEventListener('click', function () {
|
||||
window.tauri.writeFile({
|
||||
file: pathToRead,
|
||||
contents: fileInput.value
|
||||
}, {
|
||||
dir: getDir()
|
||||
}).catch(registerResponse)
|
||||
})
|
||||
}
|
||||
} else {
|
||||
registerResponse(response)
|
||||
}
|
||||
}).catch(registerResponse)
|
||||
}
|
||||
)
|
|
@ -0,0 +1,82 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<body>
|
||||
<div>
|
||||
<button id="log">Call Log API</button>
|
||||
<button id="request">Call Request (async) API</button>
|
||||
<button id="event">Send event to Rust</button>
|
||||
</div>
|
||||
|
||||
<div style="margin-top: 24px">
|
||||
<select id="dir">
|
||||
<option value="">None</option>
|
||||
</select>
|
||||
<input id="path-to-read" placeholder="Type the path to read...">
|
||||
<button id="read">Read</button>
|
||||
</div>
|
||||
|
||||
<div style="margin-top: 24px">
|
||||
<input id="url" value="https://tauri.studio">
|
||||
<button id="open-url">Open URL</button>
|
||||
</div>
|
||||
|
||||
<div style="margin-top: 24px">
|
||||
<input id="title" value="Awesome Tauri Example!">
|
||||
<button id="set-title">Set title</button>
|
||||
</div>
|
||||
|
||||
<div style="margin-top: 24px">
|
||||
<input id="dialog-default-path" placeholder="Default path">
|
||||
<input id="dialog-filter" placeholder="Extensions filter">
|
||||
<div>
|
||||
<input type="checkbox" id="dialog-multiple">
|
||||
<label>Multiple</label>
|
||||
</div>
|
||||
<div>
|
||||
<input type="checkbox" id="dialog-directory">
|
||||
<label>Directory</label>
|
||||
</div>
|
||||
|
||||
<button id="open-dialog">Open dialog</button>
|
||||
<button id="save-dialog">Open save dialog</button>
|
||||
</div>
|
||||
|
||||
<div id="response"></div>
|
||||
|
||||
<script>
|
||||
function registerResponse (response) {
|
||||
document.getElementById('response').innerHTML = typeof response === 'object'
|
||||
? JSON.stringify(response)
|
||||
: response
|
||||
}
|
||||
|
||||
function addClickEnterHandler (button, input, handler) {
|
||||
button.addEventListener('click', handler)
|
||||
input.addEventListener('keyup', function (e) {
|
||||
if (e.keyCode === 13) {
|
||||
handler()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
window.onTauriInit = function () {
|
||||
window.tauri.listen('rust-event', function (res) {
|
||||
document.getElementById('response').innerHTML = JSON.stringify(res)
|
||||
})
|
||||
|
||||
var dirSelect = document.getElementById('dir')
|
||||
for (var key in window.tauri.Dir) {
|
||||
var value = window.tauri.Dir[key]
|
||||
var opt = document.createElement("option")
|
||||
opt.value = value
|
||||
opt.innerHTML = key
|
||||
dirSelect.appendChild(opt)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<script src="communication.js"></script>
|
||||
<script src="fs.js"></script>
|
||||
<script src="window.js"></script>
|
||||
<script src="dialog.js"></script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,594 @@
|
|||
<!DOCTYPE html><html><head><meta http-equiv="Content-Security-Policy" content="default-src blob: data: filesystem: ws: http: https: 'unsafe-eval' 'unsafe-inline'"></head><body><script>/* eslint-disable */
|
||||
|
||||
/**
|
||||
* * THIS FILE IS GENERATED AUTOMATICALLY.
|
||||
* DO NOT EDIT.
|
||||
*
|
||||
* Please whitelist these API functions in tauri.conf.json
|
||||
*
|
||||
**/
|
||||
|
||||
/**
|
||||
* @module tauri
|
||||
* @description This API interface makes powerful interactions available
|
||||
* to be run on client side applications. They are opt-in features, and
|
||||
* must be enabled in tauri.conf.json
|
||||
*
|
||||
* Each binding MUST provide these interfaces in order to be compliant,
|
||||
* and also whitelist them based upon the developer's settings.
|
||||
*/
|
||||
|
||||
// polyfills
|
||||
if (!String.prototype.startsWith) {
|
||||
String.prototype.startsWith = function (searchString, position) {
|
||||
position = position || 0
|
||||
return this.substr(position, searchString.length) === searchString
|
||||
}
|
||||
}
|
||||
|
||||
// makes the window.external.invoke API available after window.location.href changes
|
||||
|
||||
switch (navigator.platform) {
|
||||
case "Macintosh":
|
||||
case "MacPPC":
|
||||
case "MacIntel":
|
||||
case "Mac68K":
|
||||
window.external = this
|
||||
invoke = function (x) {
|
||||
webkit.messageHandlers.invoke.postMessage(x);
|
||||
}
|
||||
break;
|
||||
case "Windows":
|
||||
case "WinCE":
|
||||
case "Win32":
|
||||
case "Win64":
|
||||
break;
|
||||
default:
|
||||
window.external = this
|
||||
invoke = function (x) {
|
||||
window.webkit.messageHandlers.external.postMessage(x);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
function s4() {
|
||||
return Math.floor((1 + Math.random()) * 0x10000)
|
||||
.toString(16)
|
||||
.substring(1)
|
||||
}
|
||||
|
||||
var uid = function () {
|
||||
return s4() + s4() + '-' + s4() + '-' + s4() + '-' +
|
||||
s4() + '-' + s4() + s4() + s4()
|
||||
}
|
||||
|
||||
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; }
|
||||
|
||||
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(source, true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(source).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
|
||||
|
||||
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
|
||||
|
||||
|
||||
function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
|
||||
|
||||
/**
|
||||
* @typedef {number} BaseDirectory
|
||||
*/
|
||||
/**
|
||||
* @enum {BaseDirectory}
|
||||
*/
|
||||
var Dir = {
|
||||
Audio: 1,
|
||||
Cache: 2,
|
||||
Config: 3,
|
||||
Data: 4,
|
||||
LocalData: 5,
|
||||
Desktop: 6,
|
||||
Document: 7,
|
||||
Download: 8,
|
||||
Executable: 9,
|
||||
Font: 10,
|
||||
Home: 11,
|
||||
Picture: 12,
|
||||
Public: 13,
|
||||
Runtime: 14,
|
||||
Template: 15,
|
||||
Video: 16,
|
||||
Resource: 17,
|
||||
App: 18
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @name return __whitelistWarning
|
||||
* @description Present a stylish warning to the developer that their API
|
||||
* call has not been whitelisted in tauri.conf.json
|
||||
* @param {String} func - function name to warn
|
||||
* @private
|
||||
*/
|
||||
var __whitelistWarning = function (func) {
|
||||
console.warn('%c[Tauri] Danger \ntauri.' + func + ' not whitelisted 💣\n%c\nAdd to tauri.conf.json: \n\ntauri: \n whitelist: { \n ' + func + ': true \n\nReference: https://github.com/tauri-apps/tauri/wiki' + func, 'background: red; color: white; font-weight: 800; padding: 2px; font-size:1.5em', ' ')
|
||||
return __reject()
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @name __reject
|
||||
* @description generates a promise used to deflect un-whitelisted tauri API calls
|
||||
* Its only purpose is to maintain thenable structure in client code without
|
||||
* breaking the application
|
||||
* * @type {Promise<any>}
|
||||
* @private
|
||||
*/
|
||||
|
||||
var __reject = function () {
|
||||
return new Promise(function (_, reject) {
|
||||
reject();
|
||||
});
|
||||
}
|
||||
|
||||
window.tauri = {
|
||||
Dir: Dir,
|
||||
|
||||
/**
|
||||
* @name invoke
|
||||
* @description Calls a Tauri Core feature, such as setTitle
|
||||
* @param {Object} args
|
||||
*/
|
||||
|
||||
invoke: function invoke(args) {
|
||||
window.external.invoke(JSON.stringify(args));
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* @name listen
|
||||
* @description Add an event listener to Tauri backend
|
||||
* @param {String} event
|
||||
* @param {Function} handler
|
||||
* @param {Boolean} once
|
||||
*/
|
||||
|
||||
listen: function listen(event, handler) {
|
||||
|
||||
var once = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
|
||||
this.invoke({
|
||||
cmd: 'listen',
|
||||
event: event,
|
||||
handler: window.tauri.transformCallback(handler, once),
|
||||
once: once
|
||||
});
|
||||
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* @name emit
|
||||
* @description Emits an evt to the Tauri back end
|
||||
* @param {String} evt
|
||||
* @param {Object} payload
|
||||
*/
|
||||
|
||||
emit: function emit(evt, payload) {
|
||||
|
||||
this.invoke({
|
||||
cmd: 'emit',
|
||||
event: evt,
|
||||
payload: payload
|
||||
});
|
||||
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* @name transformCallback
|
||||
* @description Registers a callback with a uid
|
||||
* @param {Function} callback
|
||||
* @param {Boolean} once
|
||||
* @returns {*}
|
||||
*/
|
||||
|
||||
transformCallback: function transformCallback(callback) {
|
||||
var once = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
|
||||
var identifier = uid();
|
||||
|
||||
window[identifier] = function (result) {
|
||||
if (once) {
|
||||
delete window[identifier];
|
||||
}
|
||||
|
||||
return callback && callback(result);
|
||||
};
|
||||
|
||||
return identifier;
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* @name promisified
|
||||
* @description Turns a request into a chainable promise
|
||||
* @param {Object} args
|
||||
* @returns {Promise<any>}
|
||||
*/
|
||||
|
||||
promisified: function promisified(args) {
|
||||
var _this = this;
|
||||
|
||||
return new Promise(function (resolve, reject) {
|
||||
_this.invoke(_objectSpread({
|
||||
callback: _this.transformCallback(resolve),
|
||||
error: _this.transformCallback(reject)
|
||||
}, args));
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* @name readTextFile
|
||||
* @description Accesses a non-binary file on the user's filesystem
|
||||
* and returns the content. Permissions based on the app's PID owner
|
||||
* @param {String} path
|
||||
* @param {Object} [options]
|
||||
* @param {BaseDirectory} [options.dir]
|
||||
* @returns {*|Promise<any>|Promise}
|
||||
*/
|
||||
|
||||
readTextFile: function readTextFile(path, options) {
|
||||
|
||||
return this.promisified({
|
||||
cmd: 'readTextFile',
|
||||
path: path,
|
||||
options: options
|
||||
});
|
||||
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* @name readBinaryFile
|
||||
* @description Accesses a binary file on the user's filesystem
|
||||
* and returns the content. Permissions based on the app's PID owner
|
||||
* @param {String} path
|
||||
* @param {Object} [options]
|
||||
* @param {BaseDirectory} [options.dir]
|
||||
* @returns {*|Promise<any>|Promise}
|
||||
*/
|
||||
|
||||
readBinaryFile: function readBinaryFile(path, options) {
|
||||
|
||||
return this.promisified({
|
||||
cmd: 'readBinaryFile',
|
||||
path: path,
|
||||
options: options
|
||||
});
|
||||
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* @name writeFile
|
||||
* @description Write a file to the Local Filesystem.
|
||||
* Permissions based on the app's PID owner
|
||||
* @param {Object} cfg
|
||||
* @param {String} cfg.file
|
||||
* @param {String|Binary} cfg.contents
|
||||
* @param {Object} [options]
|
||||
* @param {BaseDirectory} [options.dir]
|
||||
*/
|
||||
|
||||
writeFile: function writeFile(cfg, options) {
|
||||
|
||||
if (_typeof(cfg) === 'object') {
|
||||
Object.freeze(cfg);
|
||||
}
|
||||
return this.promisified({
|
||||
cmd: 'writeFile',
|
||||
file: cfg.file,
|
||||
contents: cfg.contents,
|
||||
options: options
|
||||
});
|
||||
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* @name readDir
|
||||
* @description Reads a directory
|
||||
* Permissions based on the app's PID owner
|
||||
* @param {String} path
|
||||
* @param {Object} [options]
|
||||
* @param {Boolean} [options.recursive]
|
||||
* @param {BaseDirectory} [options.dir]
|
||||
* @returns {*|Promise<any>|Promise}
|
||||
*/
|
||||
|
||||
readDir: function readDir(path, options) {
|
||||
|
||||
return this.promisified({
|
||||
cmd: 'readDir',
|
||||
path: path,
|
||||
options: options
|
||||
});
|
||||
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* @name createDir
|
||||
* @description Creates a directory
|
||||
* Permissions based on the app's PID owner
|
||||
* @param {String} path
|
||||
* @param {Object} [options]
|
||||
* @param {Boolean} [options.recursive]
|
||||
* @param {BaseDirectory} [options.dir]
|
||||
* @returns {*|Promise<any>|Promise}
|
||||
*/
|
||||
|
||||
createDir: function createDir(path, options) {
|
||||
|
||||
return this.promisified({
|
||||
cmd: 'createDir',
|
||||
path: path,
|
||||
options: options
|
||||
});
|
||||
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* @name removeDir
|
||||
* @description Removes a directory
|
||||
* Permissions based on the app's PID owner
|
||||
* @param {String} path
|
||||
* @param {Object} [options]
|
||||
* @param {Boolean} [options.recursive]
|
||||
* @param {BaseDirectory} [options.dir]
|
||||
* @returns {*|Promise<any>|Promise}
|
||||
*/
|
||||
|
||||
removeDir: function removeDir(path, options) {
|
||||
|
||||
return this.promisified({
|
||||
cmd: 'removeDir',
|
||||
path: path,
|
||||
options: options
|
||||
});
|
||||
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* @name copyFile
|
||||
* @description Copy file
|
||||
* Permissions based on the app's PID owner
|
||||
* @param {String} source
|
||||
* @param {String} destination
|
||||
* @param {Object} [options]
|
||||
* @param {BaseDirectory} [options.dir]
|
||||
* @returns {*|Promise<any>|Promise}
|
||||
*/
|
||||
|
||||
copyFile: function copyFile(source, destination, options) {
|
||||
|
||||
return this.promisified({
|
||||
cmd: 'copyFile',
|
||||
source: source,
|
||||
destination: destination,
|
||||
options: options
|
||||
});
|
||||
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* @name removeFile
|
||||
* @description Removes a file
|
||||
* Permissions based on the app's PID owner
|
||||
* @param {String} path
|
||||
* @param {Object} [options]
|
||||
* @param {BaseDirectory} [options.dir]
|
||||
* @returns {*|Promise<any>|Promise}
|
||||
*/
|
||||
|
||||
removeFile: function removeFile(path, options) {
|
||||
|
||||
return this.promisified({
|
||||
cmd: 'removeFile',
|
||||
path: path,
|
||||
options: options
|
||||
});
|
||||
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* @name renameFile
|
||||
* @description Renames a file
|
||||
* Permissions based on the app's PID owner
|
||||
* @param {String} path
|
||||
* @param {Object} [options]
|
||||
* @param {BaseDirectory} [options.dir]
|
||||
* @returns {*|Promise<any>|Promise}
|
||||
*/
|
||||
|
||||
renameFile: function renameFile(oldPath, newPath, options) {
|
||||
|
||||
return this.promisified({
|
||||
cmd: 'renameFile',
|
||||
old_path: oldPath,
|
||||
new_path: newPath,
|
||||
options: options
|
||||
});
|
||||
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* @name setTitle
|
||||
* @description Set the application's title
|
||||
* @param {String} title
|
||||
*/
|
||||
|
||||
setTitle: function setTitle(title) {
|
||||
|
||||
this.invoke({
|
||||
cmd: 'setTitle',
|
||||
title: title
|
||||
});
|
||||
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* @name open
|
||||
* @description Open an URI
|
||||
* @param {String} uri
|
||||
*/
|
||||
|
||||
open: function open(uri) {
|
||||
|
||||
this.invoke({
|
||||
cmd: 'open',
|
||||
uri: uri
|
||||
});
|
||||
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* @name execute
|
||||
* @description Execute a program with arguments.
|
||||
* Permissions based on the app's PID owner
|
||||
* @param {String} command
|
||||
* @param {String|Array} args
|
||||
* @returns {*|Promise<any>|Promise}
|
||||
*/
|
||||
|
||||
execute: function execute(command, args) {
|
||||
|
||||
|
||||
if (_typeof(args) === 'object') {
|
||||
Object.freeze(args);
|
||||
}
|
||||
|
||||
return this.promisified({
|
||||
cmd: 'execute',
|
||||
command: command,
|
||||
args: typeof args === 'string' ? [args] : args
|
||||
});
|
||||
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* @name openDialog
|
||||
* @description Open a file/directory selection dialog
|
||||
* @param {String} [options]
|
||||
* @param {String} [options.filter]
|
||||
* @param {String} [options.defaultPath]
|
||||
* @param {Boolean} [options.multiple=false]
|
||||
* @param {Boolean} [options.directory=false]
|
||||
* @returns {Promise<String|String[]>} promise resolving to the select path(s)
|
||||
*/
|
||||
|
||||
openDialog: function openDialog(options) {
|
||||
|
||||
var opts = options || {}
|
||||
if (_typeof(options) === 'object') {
|
||||
opts.default_path = opts.defaultPath
|
||||
Object.freeze(options);
|
||||
}
|
||||
return this.promisified({
|
||||
cmd: 'openDialog',
|
||||
options: opts
|
||||
});
|
||||
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* @name saveDialog
|
||||
* @description Open a file/directory save dialog
|
||||
* @param {String} [options]
|
||||
* @param {String} [options.filter]
|
||||
* @param {String} [options.defaultPath]
|
||||
* @returns {Promise<String>} promise resolving to the select path
|
||||
*/
|
||||
|
||||
saveDialog: function saveDialog(options) {
|
||||
|
||||
var opts = options || {}
|
||||
if (_typeof(options) === 'object') {
|
||||
opts.default_path = opts.defaultPath
|
||||
Object.freeze(options);
|
||||
}
|
||||
return this.promisified({
|
||||
cmd: 'saveDialog',
|
||||
options: opts
|
||||
});
|
||||
|
||||
},
|
||||
|
||||
loadAsset: function loadAsset(assetName, assetType) {
|
||||
return this.promisified({
|
||||
cmd: 'loadAsset',
|
||||
asset: assetName,
|
||||
asset_type: assetType || 'unknown'
|
||||
})
|
||||
}
|
||||
};
|
||||
|
||||
// init tauri API
|
||||
try {
|
||||
window.tauri.invoke({
|
||||
cmd: 'init'
|
||||
})
|
||||
} catch (e) {
|
||||
window.addEventListener('DOMContentLoaded', function () {
|
||||
window.tauri.invoke({
|
||||
cmd: 'init'
|
||||
})
|
||||
}, true)
|
||||
}
|
||||
|
||||
document.addEventListener('error', function (e) {
|
||||
var target = e.target
|
||||
while (target != null) {
|
||||
if (target.matches ? target.matches('img') : target.msMatchesSelector('img')) {
|
||||
window.tauri.loadAsset(target.src, 'image')
|
||||
.then(function (img) {
|
||||
target.src = img
|
||||
})
|
||||
break
|
||||
}
|
||||
target = target.parentElement
|
||||
}
|
||||
}, true)
|
||||
|
||||
// open <a href="..."> links with the Tauri API
|
||||
function __openLinks() {
|
||||
document.querySelector('body').addEventListener('click', function (e) {
|
||||
var target = e.target
|
||||
while (target != null) {
|
||||
if (target.matches ? target.matches('a') : target.msMatchesSelector('a')) {
|
||||
if (target.href && target.href.startsWith('http') && target.target === '_blank') {
|
||||
window.tauri.open(target.href)
|
||||
e.preventDefault()
|
||||
}
|
||||
break
|
||||
}
|
||||
target = target.parentElement
|
||||
}
|
||||
}, true)
|
||||
}
|
||||
|
||||
if (document.readyState === 'complete' || document.readyState === 'interactive') {
|
||||
__openLinks()
|
||||
} else {
|
||||
window.addEventListener('DOMContentLoaded', function () {
|
||||
__openLinks()
|
||||
}, true)
|
||||
}
|
||||
</script> <div> <button id="log">Call Log API</button> <button id="request">Call Request (async) API</button> <button id="event">Send event to Rust</button> </div> <div style="margin-top:24px"> <select id="dir"> <option value="">None</option> </select> <input id="path-to-read" placeholder="Type the path to read..."> <button id="read">Read</button> </div> <div style="margin-top:24px"> <input id="url" value="https://tauri.studio"> <button id="open-url">Open URL</button> </div> <div style="margin-top:24px"> <input id="title" value="Awesome Tauri Example!"> <button id="set-title">Set title</button> </div> <div style="margin-top:24px"> <input id="dialog-default-path" placeholder="Default path"> <input id="dialog-filter" placeholder="Extensions filter"> <div> <input type="checkbox" id="dialog-multiple"> <label>Multiple</label> </div> <div> <input type="checkbox" id="dialog-directory"> <label>Directory</label> </div> <button id="open-dialog">Open dialog</button> <button id="save-dialog">Open save dialog</button> </div> <div id="response"></div> <script>function registerResponse(e){document.getElementById("response").innerHTML="object"==typeof e?JSON.stringify(e):e}function addClickEnterHandler(e,n,t){e.addEventListener("click",t),n.addEventListener("keyup",function(e){13===e.keyCode&&t()})}window.onTauriInit=function(){window.tauri.listen("rust-event",function(e){document.getElementById("response").innerHTML=JSON.stringify(e)});var e=document.getElementById("dir");for(var n in window.tauri.Dir){var t=window.tauri.Dir[n],i=document.createElement("option");i.value=t,i.innerHTML=n,e.appendChild(i)}};</script> <script>document.getElementById("log").addEventListener("click",function(){window.tauri.invoke({cmd:"logOperation",event:"tauri-click",payload:"this payload is optional because we used Option in Rust"})}),document.getElementById("request").addEventListener("click",function(){window.tauri.promisified({cmd:"performRequest",endpoint:"dummy endpoint arg",body:{id:5,name:"test"}}).then(registerResponse).catch(registerResponse)}),document.getElementById("event").addEventListener("click",function(){window.tauri.emit("js-event","this is the payload string")});</script> <script>var dirSelect=document.getElementById("dir");function getDir(){return dirSelect.value?parseInt(dir.value):null}function arrayBufferToBase64(e,n){var t=new Blob([e],{type:"application/octet-binary"}),r=new FileReader;r.onload=function(e){var t=e.target.result;n(t.substr(t.indexOf(",")+1))},r.readAsDataURL(t)}var pathInput=document.getElementById("path-to-read");addClickEnterHandler(document.getElementById("read"),pathInput,function(){var r=pathInput.value,a=r.match(/\S+\.\S+$/g),e={dir:getDir()};(a?window.tauri.readBinaryFile(r,e):window.tauri.readDir(r,e)).then(function(e){if(a)if(r.includes(".png")||r.includes(".jpg"))arrayBufferToBase64(new Uint8Array(e),function(e){registerResponse('<img src="'+("data:image/png;base64,"+e)+'"></img>')});else{var t=String.fromCharCode.apply(null,e);registerResponse('<textarea id="file-response" style="height: 400px"></textarea><button id="file-save">Save</button>');var n=document.getElementById("file-response");n.value=t,document.getElementById("file-save").addEventListener("click",function(){window.tauri.writeFile({file:r,contents:n.value},{dir:getDir()}).catch(registerResponse)})}else registerResponse(e)}).catch(registerResponse)});</script> <script>var urlInput=document.getElementById("url");addClickEnterHandler(document.getElementById("open-url"),urlInput,function(){window.tauri.open(urlInput.value)});var titleInput=document.getElementById("title");addClickEnterHandler(document.getElementById("set-title"),titleInput,function(){window.tauri.setTitle(titleInput.value)});</script> <script>var defaultPathInput=document.getElementById("dialog-default-path"),filterInput=document.getElementById("dialog-filter"),multipleInput=document.getElementById("dialog-multiple"),directoryInput=document.getElementById("dialog-directory");document.getElementById("open-dialog").addEventListener("click",function(){window.tauri.openDialog({defaultPath:defaultPathInput.value||null,filter:filterInput.value||null,multiple:multipleInput.checked,directory:directoryInput.checked}).then(registerResponse).catch(registerResponse)}),document.getElementById("save-dialog").addEventListener("click",function(){window.tauri.saveDialog({defaultPath:defaultPathInput.value||null,filter:filterInput.value||null}).then(registerResponse).catch(registerResponse)});</script> </body></html>
|
|
@ -0,0 +1,19 @@
|
|||
var urlInput = document.getElementById('url')
|
||||
|
||||
addClickEnterHandler(
|
||||
document.getElementById('open-url'),
|
||||
urlInput,
|
||||
function () {
|
||||
window.tauri.open(urlInput.value)
|
||||
}
|
||||
)
|
||||
|
||||
var titleInput = document.getElementById('title')
|
||||
|
||||
addClickEnterHandler(
|
||||
document.getElementById('set-title'),
|
||||
titleInput,
|
||||
function () {
|
||||
window.tauri.setTitle(titleInput.value)
|
||||
}
|
||||
)
|
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"name": "communication-example",
|
||||
"version": "1.0.0",
|
||||
"description": "A Tauri example showcasing the JS-Rust communication",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"private": true
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
# Generated by Cargo
|
||||
# will have compiled files and executables
|
||||
/target/
|
||||
WixTools
|
||||
|
||||
# These are backup files generated by rustfmt
|
||||
**/*.rs.bk
|
||||
|
||||
tauri.js
|
||||
config.json
|
||||
bundle.json
|
|
@ -0,0 +1,39 @@
|
|||
workspace = { }
|
||||
|
||||
[package]
|
||||
name = "app"
|
||||
version = "0.1.0"
|
||||
description = "A Tauri App"
|
||||
authors = [ "you" ]
|
||||
license = ""
|
||||
repository = ""
|
||||
default-run = "app"
|
||||
edition = "2018"
|
||||
build = "src/build.rs"
|
||||
|
||||
[package.metadata.bundle]
|
||||
identifier = "com.tauri.dev"
|
||||
icon = [
|
||||
"icons/32x32.png",
|
||||
"icons/128x128.png",
|
||||
"icons/128x128@2x.png",
|
||||
"icons/icon.icns",
|
||||
"icons/icon.ico"
|
||||
]
|
||||
|
||||
[dependencies]
|
||||
serde_json = "1.0"
|
||||
serde = { version = "1.0", features = [ "derive" ] }
|
||||
tauri = { path = "../../..", features = [ "all-api", "edge" ] }
|
||||
|
||||
[target."cfg(windows)".build-dependencies]
|
||||
winres = "0.1"
|
||||
|
||||
[features]
|
||||
dev-server = [ "tauri/dev-server" ]
|
||||
embedded-server = [ "tauri/embedded-server" ]
|
||||
no-server = [ "tauri/no-server" ]
|
||||
|
||||
[[bin]]
|
||||
name = "app"
|
||||
path = "src/main.rs"
|
After Width: | Height: | Size: 16 KiB |
After Width: | Height: | Size: 37 KiB |
After Width: | Height: | Size: 2.3 KiB |
After Width: | Height: | Size: 12 KiB |
After Width: | Height: | Size: 18 KiB |