Merge pull request #15 from mrxiaozhuox/master
Add `tools` install & manage support
This commit is contained in:
15 files changed
+423
-30
No files matched your search
+7
-2
@@ -9,10 +9,12 @@ license = "MIT/Apache-2.0"
|
|||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
|
||||||
# cli core
|
# cli core
|
||||||
clap = { version = "3.0.14", features = ["derive"] }
|
clap = { version = "3.0.14", features = ["derive"] }
|
||||||
thiserror = "1.0.30"
|
thiserror = "1.0.30"
|
||||||
wasm-bindgen-cli-support = "0.2.79"
|
wasm-bindgen-cli-support = "0.2.79"
|
||||||
|
|
||||||
# features
|
# features
|
||||||
log = "0.4.14"
|
log = "0.4.14"
|
||||||
fern = { version = "0.6.0", features = ["colored"] }
|
fern = { version = "0.6.0", features = ["colored"] }
|
||||||
@@ -37,10 +39,13 @@ hyper = "0.14.17"
|
|||||||
axum = { version = "0.4.5", features = ["ws", "headers"] }
|
axum = { version = "0.4.5", features = ["ws", "headers"] }
|
||||||
tower-http = { version = "0.2.2", features = ["fs", "trace"] }
|
tower-http = { version = "0.2.2", features = ["fs", "trace"] }
|
||||||
headers = "0.3.7"
|
headers = "0.3.7"
|
||||||
|
# tools download
|
||||||
|
dirs = "4.0.0"
|
||||||
|
reqwest = { version = "0.11", features = ["rustls-tls", "stream", "trust-dns"] }
|
||||||
|
flate2 = "1.0.22"
|
||||||
|
tar = "0.4.38"
|
||||||
tower = "0.4.12"
|
tower = "0.4.12"
|
||||||
|
|
||||||
# hyper = { version = "0.14.11", features = ["full"] }
|
|
||||||
|
|
||||||
[[bin]]
|
[[bin]]
|
||||||
path = "src/main.rs"
|
path = "src/main.rs"
|
||||||
name = "dioxus"
|
name = "dioxus"
|
||||||
+45
@@ -0,0 +1,45 @@
|
|||||||
|
[application]
|
||||||
|
|
||||||
|
# dioxus project name
|
||||||
|
name = "dioxus-cli"
|
||||||
|
|
||||||
|
# default platfrom
|
||||||
|
# you can also use `dioxus serve/build --platform XXX` to use other platform
|
||||||
|
# value: web | desktop
|
||||||
|
default_platform = "desktop"
|
||||||
|
|
||||||
|
# Web `build` & `serve` dist path
|
||||||
|
out_dir = "dist"
|
||||||
|
|
||||||
|
# resource (static) file folder
|
||||||
|
asset_dir = "public"
|
||||||
|
|
||||||
|
[web.app]
|
||||||
|
|
||||||
|
# HTML title tag content
|
||||||
|
title = "dioxus | ⛺"
|
||||||
|
|
||||||
|
[web.watcher]
|
||||||
|
|
||||||
|
watch_path = ["src"]
|
||||||
|
|
||||||
|
# include `assets` in web platform
|
||||||
|
[web.resource]
|
||||||
|
|
||||||
|
# CSS style file
|
||||||
|
style = []
|
||||||
|
|
||||||
|
# Javascript code file
|
||||||
|
script = []
|
||||||
|
|
||||||
|
[web.resource.dev]
|
||||||
|
|
||||||
|
# Javascript code file
|
||||||
|
# serve: [dev-server] only
|
||||||
|
script = []
|
||||||
|
|
||||||
|
[application.tools]
|
||||||
|
|
||||||
|
# use binaryen.wasm-opt for output Wasm file
|
||||||
|
# binaryen just will trigger in `web` platform
|
||||||
|
binaryen = { wasm_opt = true }
|
||||||
@@ -1,3 +1,6 @@
|
|||||||
|
// Dioxus-CLI
|
||||||
|
// https://github.com/DioxusLabs/cli
|
||||||
|
|
||||||
(function () {
|
(function () {
|
||||||
var protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
|
var protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
|
||||||
var url = protocol + '//' + window.location.host + '/_dioxus/ws';
|
var url = protocol + '//' + window.location.host + '/_dioxus/ws';
|
||||||
@@ -15,7 +18,6 @@
|
|||||||
var ws = new WebSocket(url);
|
var ws = new WebSocket(url);
|
||||||
ws.onmessage = (ev) => {
|
ws.onmessage = (ev) => {
|
||||||
if (ev.data == "reload") {
|
if (ev.data == "reload") {
|
||||||
// alert("reload!!!");
|
|
||||||
window.location.reload();
|
window.location.reload();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ name = "{{project-name}}"
|
|||||||
# default platfrom
|
# default platfrom
|
||||||
# you can also use `dioxus serve/build --platform XXX` to use other platform
|
# you can also use `dioxus serve/build --platform XXX` to use other platform
|
||||||
# value: web | desktop
|
# value: web | desktop
|
||||||
default_platform = "web"
|
default_platform = "{{default-platform}}"
|
||||||
|
|
||||||
# Web `build` & `serve` dist path
|
# Web `build` & `serve` dist path
|
||||||
out_dir = "dist"
|
out_dir = "dist"
|
||||||
@@ -36,4 +36,10 @@ script = []
|
|||||||
|
|
||||||
# Javascript code file
|
# Javascript code file
|
||||||
# serve: [dev-server] only
|
# serve: [dev-server] only
|
||||||
script = []
|
script = []
|
||||||
|
|
||||||
|
[application.tools]
|
||||||
|
|
||||||
|
# use binaryen.wasm-opt for output Wasm file
|
||||||
|
# binaryen just will trigger in `web` platform
|
||||||
|
binaryen = { wasm_opt = [".PROJECT_OUT"] }
|
||||||
@@ -1,14 +1,11 @@
|
|||||||
<html>
|
<html>
|
||||||
|
|
||||||
<head>
|
<head>
|
||||||
<title>{app_title}</title>
|
<title>{app_title}</title>
|
||||||
<meta content="text/html;charset=utf-8" http-equiv="Content-Type" />
|
<meta content="text/html;charset=utf-8" http-equiv="Content-Type" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
{style_include}
|
{style_include}
|
||||||
|
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<div id="main"></div>
|
<div id="main"></div>
|
||||||
<!-- Note the usage of `type=module` here as this is an ES6 module -->
|
<!-- Note the usage of `type=module` here as this is an ES6 module -->
|
||||||
@@ -22,5 +19,4 @@
|
|||||||
</script>
|
</script>
|
||||||
{script_include}
|
{script_include}
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
+50
-2
@@ -4,7 +4,8 @@ use crate::{
|
|||||||
DioxusConfig,
|
DioxusConfig,
|
||||||
};
|
};
|
||||||
use std::{
|
use std::{
|
||||||
fs::{copy, create_dir_all, remove_dir_all},
|
fs::{copy, create_dir_all, remove_dir_all, File},
|
||||||
|
io::Read,
|
||||||
panic,
|
panic,
|
||||||
path::PathBuf,
|
path::PathBuf,
|
||||||
process::Command,
|
process::Command,
|
||||||
@@ -95,8 +96,43 @@ pub fn build(config: &CrateConfig) -> Result<()> {
|
|||||||
});
|
});
|
||||||
if bindgen_result.is_err() {
|
if bindgen_result.is_err() {
|
||||||
log::error!("Bindgen build failed! \nThis is probably due to the Bindgen version, dioxus-cli using `0.2.79` Bindgen crate.");
|
log::error!("Bindgen build failed! \nThis is probably due to the Bindgen version, dioxus-cli using `0.2.79` Bindgen crate.");
|
||||||
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// check binaryen:wasm-opt tool
|
||||||
|
let dioxus_tools = dioxus_config.application.tools.clone().unwrap_or_default();
|
||||||
|
if dioxus_tools.contains_key("binaryen") {
|
||||||
|
let info = dioxus_tools.get("binaryen").unwrap();
|
||||||
|
let binaryen = crate::tools::Tool::Binaryen;
|
||||||
|
|
||||||
|
if binaryen.is_installed() {
|
||||||
|
if let Some(sub) = info.as_table() {
|
||||||
|
if sub.contains_key("wasm_opt")
|
||||||
|
&& sub.get("wasm_opt").unwrap().as_bool().unwrap_or(false)
|
||||||
|
{
|
||||||
|
let target_file = out_dir
|
||||||
|
.join("assets")
|
||||||
|
.join("dioxus")
|
||||||
|
.join(format!("{}_bg.wasm", dioxus_config.application.name));
|
||||||
|
if target_file.is_file() {
|
||||||
|
binaryen.call(
|
||||||
|
"wasm-opt",
|
||||||
|
vec![
|
||||||
|
target_file.to_str().unwrap(),
|
||||||
|
"-o",
|
||||||
|
target_file.to_str().unwrap(),
|
||||||
|
],
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log::warn!(
|
||||||
|
"Binaryen tool not found, you can use `dioxus tool add binaryen` to install it."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// this code will copy all public file to the output dir
|
// this code will copy all public file to the output dir
|
||||||
let copy_options = fs_extra::dir::CopyOptions {
|
let copy_options = fs_extra::dir::CopyOptions {
|
||||||
overwrite: true,
|
overwrite: true,
|
||||||
@@ -237,7 +273,19 @@ pub fn build_desktop(config: &CrateConfig, is_serve: bool) -> Result<()> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn gen_page(config: &DioxusConfig, serve: bool) -> String {
|
pub fn gen_page(config: &DioxusConfig, serve: bool) -> String {
|
||||||
let mut html = String::from(include_str!("./assets/index.html"));
|
let crate_root = crate::cargo::crate_root().unwrap();
|
||||||
|
let custom_html_file = crate_root.join("index.html");
|
||||||
|
let mut html = if custom_html_file.is_file() {
|
||||||
|
let mut buf = String::new();
|
||||||
|
let mut file = File::open(custom_html_file).unwrap();
|
||||||
|
if file.read_to_string(&mut buf).is_ok() {
|
||||||
|
buf
|
||||||
|
} else {
|
||||||
|
String::from(include_str!("./assets/index.html"))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
String::from(include_str!("./assets/index.html"))
|
||||||
|
};
|
||||||
|
|
||||||
let resouces = config.web.resource.clone();
|
let resouces = config.web.resource.clone();
|
||||||
|
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ impl Build {
|
|||||||
pub fn build(self) -> Result<()> {
|
pub fn build(self) -> Result<()> {
|
||||||
let mut crate_config = crate::CrateConfig::new()?;
|
let mut crate_config = crate::CrateConfig::new()?;
|
||||||
|
|
||||||
|
|
||||||
// change the release state.
|
// change the release state.
|
||||||
crate_config.with_release(self.build.release);
|
crate_config.with_release(self.build.release);
|
||||||
|
|
||||||
|
|||||||
+25
-2
@@ -13,14 +13,26 @@ pub enum Config {
|
|||||||
#[clap(long)]
|
#[clap(long)]
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
force: bool,
|
force: bool,
|
||||||
|
|
||||||
|
/// Project default platform
|
||||||
|
#[clap(long, default_value = "web")]
|
||||||
|
platform: String,
|
||||||
},
|
},
|
||||||
|
/// Format print Dioxus config.
|
||||||
|
FormatPrint {},
|
||||||
|
/// Create a custom html file.
|
||||||
|
CustomHtml {}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Config {
|
impl Config {
|
||||||
pub fn config(self) -> Result<()> {
|
pub fn config(self) -> Result<()> {
|
||||||
let crate_root = crate::cargo::crate_root()?;
|
let crate_root = crate::cargo::crate_root()?;
|
||||||
match self {
|
match self {
|
||||||
Config::Init { name, force } => {
|
Config::Init {
|
||||||
|
name,
|
||||||
|
force,
|
||||||
|
platform,
|
||||||
|
} => {
|
||||||
let conf_path = crate_root.join("Dioxus.toml");
|
let conf_path = crate_root.join("Dioxus.toml");
|
||||||
if conf_path.is_file() && !force {
|
if conf_path.is_file() && !force {
|
||||||
log::warn!(
|
log::warn!(
|
||||||
@@ -30,10 +42,21 @@ impl Config {
|
|||||||
}
|
}
|
||||||
let mut file = File::create(conf_path)?;
|
let mut file = File::create(conf_path)?;
|
||||||
let content = String::from(include_str!("../../assets/dioxus.toml"))
|
let content = String::from(include_str!("../../assets/dioxus.toml"))
|
||||||
.replace("{{project-name}}", &name);
|
.replace("{{project-name}}", &name)
|
||||||
|
.replace("{{default-platform}}", &platform);
|
||||||
file.write_all(content.as_bytes())?;
|
file.write_all(content.as_bytes())?;
|
||||||
log::info!("🚩 Init config file completed.");
|
log::info!("🚩 Init config file completed.");
|
||||||
}
|
}
|
||||||
|
Config::FormatPrint {} => {
|
||||||
|
println!("{:#?}", crate::CrateConfig::new()?.dioxus_config);
|
||||||
|
}
|
||||||
|
Config::CustomHtml {} => {
|
||||||
|
let html_path = crate_root.join("index.html");
|
||||||
|
let mut file = File::create(html_path)?;
|
||||||
|
let content = include_str!("../../assets/index.html");
|
||||||
|
file.write_all(content.as_bytes())?;
|
||||||
|
log::info!("🚩 Create custom html file done.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ pub mod config;
|
|||||||
pub mod create;
|
pub mod create;
|
||||||
pub mod serve;
|
pub mod serve;
|
||||||
pub mod translate;
|
pub mod translate;
|
||||||
|
pub mod tool;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
cfg::{ConfigOptsBuild, ConfigOptsServe},
|
cfg::{ConfigOptsBuild, ConfigOptsServe},
|
||||||
@@ -55,4 +56,7 @@ pub enum Commands {
|
|||||||
/// Dioxus config file controls.
|
/// Dioxus config file controls.
|
||||||
#[clap(subcommand)]
|
#[clap(subcommand)]
|
||||||
Config(config::Config),
|
Config(config::Config),
|
||||||
|
/// Install & Manage tools for Dioxus-cli.
|
||||||
|
#[clap(subcommand)]
|
||||||
|
Tool(tool::Tool),
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
use crate::tools;
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
/// Build the Rust WASM app and all of its assets.
|
||||||
|
#[derive(Clone, Debug, Deserialize, Subcommand)]
|
||||||
|
#[clap(name = "tool")]
|
||||||
|
pub enum Tool {
|
||||||
|
/// Return all dioxus-cli support tools.
|
||||||
|
List {},
|
||||||
|
/// Get default app install path.
|
||||||
|
AppPath {},
|
||||||
|
/// Install a new tool.
|
||||||
|
Add {
|
||||||
|
name: String
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Tool {
|
||||||
|
pub async fn tool(self) -> Result<()> {
|
||||||
|
match self {
|
||||||
|
Tool::List {} => {
|
||||||
|
for item in tools::tool_list() {
|
||||||
|
if tools::Tool::from_str(item).unwrap().is_installed() {
|
||||||
|
println!("{item} [installed]");
|
||||||
|
} else {
|
||||||
|
println!("{item}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Tool::AppPath {} => {
|
||||||
|
println!("{}", tools::tools_path().to_str().unwrap());
|
||||||
|
}
|
||||||
|
Tool::Add { name } => {
|
||||||
|
let tool_list = tools::tool_list();
|
||||||
|
|
||||||
|
if !tool_list.contains(&name.as_str()) {
|
||||||
|
log::error!("Tool {name} not found.");
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
let target_tool = tools::Tool::from_str(&name).unwrap();
|
||||||
|
|
||||||
|
if target_tool.is_installed() {
|
||||||
|
log::warn!("Tool {name} is installed.");
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
log::info!("Start to download tool package...");
|
||||||
|
if let Err(e) = target_tool.download_package().await {
|
||||||
|
log::error!("Tool download failed: {e}");
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
log::info!("Start to install tool package...");
|
||||||
|
if let Err(e) = target_tool.install_package().await {
|
||||||
|
log::error!("Tool install failed: {e}");
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
log::info!("Tool {name} install successfully!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
+3
-1
@@ -1,6 +1,6 @@
|
|||||||
use crate::error::Result;
|
use crate::error::Result;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::{fs::File, io::Read, path::PathBuf};
|
use std::{fs::File, io::Read, path::PathBuf, collections::HashMap};
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct DioxusConfig {
|
pub struct DioxusConfig {
|
||||||
@@ -34,6 +34,7 @@ impl Default for DioxusConfig {
|
|||||||
default_platform: "web".to_string(),
|
default_platform: "web".to_string(),
|
||||||
out_dir: Some(PathBuf::from("dist")),
|
out_dir: Some(PathBuf::from("dist")),
|
||||||
asset_dir: Some(PathBuf::from("public")),
|
asset_dir: Some(PathBuf::from("public")),
|
||||||
|
tools: None,
|
||||||
sub_package: None,
|
sub_package: None,
|
||||||
},
|
},
|
||||||
web: WebConfig {
|
web: WebConfig {
|
||||||
@@ -65,6 +66,7 @@ pub struct ApplicationConfig {
|
|||||||
pub default_platform: String,
|
pub default_platform: String,
|
||||||
pub out_dir: Option<PathBuf>,
|
pub out_dir: Option<PathBuf>,
|
||||||
pub asset_dir: Option<PathBuf>,
|
pub asset_dir: Option<PathBuf>,
|
||||||
|
pub tools: Option<HashMap<String, toml::Value>>,
|
||||||
pub sub_package: Option<String>,
|
pub sub_package: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
pub mod builder;
|
pub mod builder;
|
||||||
pub mod server;
|
pub mod server;
|
||||||
|
pub mod tools;
|
||||||
|
|
||||||
pub use builder::*;
|
pub use builder::*;
|
||||||
|
|
||||||
pub mod cargo;
|
pub mod cargo;
|
||||||
|
|||||||
@@ -42,6 +42,12 @@ async fn main() -> Result<()> {
|
|||||||
log::error!("config error: {}", e);
|
log::error!("config error: {}", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Commands::Tool(opts) => {
|
||||||
|
if let Err(e) = opts.tool().await {
|
||||||
|
log::error!("tool error: {}", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|||||||
+16
-16
@@ -35,23 +35,23 @@ pub async fn startup(config: CrateConfig) -> Result<()> {
|
|||||||
// file watcher: check file change
|
// file watcher: check file change
|
||||||
let watcher_conf = config.clone();
|
let watcher_conf = config.clone();
|
||||||
let mut watcher = RecommendedWatcher::new(move |_: notify::Result<notify::Event>| {
|
let mut watcher = RecommendedWatcher::new(move |_: notify::Result<notify::Event>| {
|
||||||
if chrono::Local::now().timestamp() > last_update_time
|
if chrono::Local::now().timestamp() > last_update_time {
|
||||||
&& builder::build(&watcher_conf).is_ok()
|
log::info!("Start to rebuild project...");
|
||||||
{
|
if builder::build(&watcher_conf).is_ok() {
|
||||||
// change the websocket reload state to true;
|
// change the websocket reload state to true;
|
||||||
// the page will auto-reload.
|
// the page will auto-reload.
|
||||||
if watcher_conf
|
if watcher_conf
|
||||||
.dioxus_config
|
.dioxus_config
|
||||||
.web
|
.web
|
||||||
.watcher
|
.watcher
|
||||||
.reload_html
|
.reload_html
|
||||||
.unwrap_or(false)
|
.unwrap_or(false)
|
||||||
{
|
{
|
||||||
let _ = Serve::regen_dev_page(&watcher_conf);
|
let _ = Serve::regen_dev_page(&watcher_conf);
|
||||||
|
}
|
||||||
|
let _ = reload_tx.send("reload".into());
|
||||||
|
last_update_time = chrono::Local::now().timestamp();
|
||||||
}
|
}
|
||||||
println!("watcher send reload");
|
|
||||||
reload_tx.send("reload".into()).unwrap();
|
|
||||||
last_update_time = chrono::Local::now().timestamp();
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|||||||
+187
@@ -0,0 +1,187 @@
|
|||||||
|
use std::{
|
||||||
|
fs::{create_dir_all, File},
|
||||||
|
path::PathBuf,
|
||||||
|
process::Command,
|
||||||
|
};
|
||||||
|
|
||||||
|
use anyhow::Context;
|
||||||
|
use flate2::read::GzDecoder;
|
||||||
|
use futures::StreamExt;
|
||||||
|
use tar::Archive;
|
||||||
|
use tokio::io::AsyncWriteExt;
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
|
pub enum Tool {
|
||||||
|
Binaryen,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn tool_list() -> Vec<&'static str> {
|
||||||
|
vec!["binaryen"]
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn app_path() -> PathBuf {
|
||||||
|
let data_local = dirs::data_local_dir().unwrap();
|
||||||
|
let dioxus_dir = data_local.join("dioxus");
|
||||||
|
if !dioxus_dir.is_dir() {
|
||||||
|
create_dir_all(&dioxus_dir).unwrap();
|
||||||
|
}
|
||||||
|
dioxus_dir
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn temp_path() -> PathBuf {
|
||||||
|
let app_path = app_path();
|
||||||
|
let temp_path = app_path.join("temp");
|
||||||
|
if !temp_path.is_dir() {
|
||||||
|
create_dir_all(&temp_path).unwrap();
|
||||||
|
}
|
||||||
|
temp_path
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn tools_path() -> PathBuf {
|
||||||
|
let app_path = app_path();
|
||||||
|
let temp_path = app_path.join("tools");
|
||||||
|
if !temp_path.is_dir() {
|
||||||
|
create_dir_all(&temp_path).unwrap();
|
||||||
|
}
|
||||||
|
temp_path
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::should_implement_trait)]
|
||||||
|
impl Tool {
|
||||||
|
/// from str to tool enum
|
||||||
|
pub fn from_str(name: &str) -> Option<Self> {
|
||||||
|
match name {
|
||||||
|
"binaryen" => Some(Self::Binaryen),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// get current tool name str
|
||||||
|
pub fn name(&self) -> &str {
|
||||||
|
match self {
|
||||||
|
Self::Binaryen => "binaryen",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// get tool bin dir path
|
||||||
|
pub fn bin_path(&self) -> &str {
|
||||||
|
match self {
|
||||||
|
Self::Binaryen => "bin",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// get target platform
|
||||||
|
pub fn target_platform(&self) -> &str {
|
||||||
|
match self {
|
||||||
|
Self::Binaryen => {
|
||||||
|
if cfg!(target_os = "windows") {
|
||||||
|
"windows"
|
||||||
|
} else if cfg!(target_os = "macos") {
|
||||||
|
"macos"
|
||||||
|
} else if cfg!(target_os = "linux") {
|
||||||
|
"linux"
|
||||||
|
} else {
|
||||||
|
panic!("unsupported platformm");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// get tool package download url
|
||||||
|
pub fn download_url(&self) -> String {
|
||||||
|
match self {
|
||||||
|
Self::Binaryen => {
|
||||||
|
format!(
|
||||||
|
"https://github.com/WebAssembly/binaryen/releases/download/version_105/binaryen-version_105-x86_64-{target}.tar.gz",
|
||||||
|
target = self.target_platform()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// get package extension name
|
||||||
|
pub fn extension(&self) -> &str {
|
||||||
|
match self {
|
||||||
|
Self::Binaryen => "tar.gz",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// check tool state
|
||||||
|
pub fn is_installed(&self) -> bool {
|
||||||
|
tools_path().join(self.name()).is_dir()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// get download temp path
|
||||||
|
pub fn temp_out_path(&self) -> PathBuf {
|
||||||
|
temp_path().join(format!("{}-tool.tmp", self.name()))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// start to download package
|
||||||
|
pub async fn download_package(&self) -> anyhow::Result<PathBuf> {
|
||||||
|
let download_url = self.download_url();
|
||||||
|
let temp_out = self.temp_out_path();
|
||||||
|
let mut file = tokio::fs::File::create(&temp_out)
|
||||||
|
.await
|
||||||
|
.context("failed creating temporary output file")?;
|
||||||
|
|
||||||
|
let resp = reqwest::get(download_url).await.unwrap();
|
||||||
|
|
||||||
|
let mut res_bytes = resp.bytes_stream();
|
||||||
|
while let Some(chunk_res) = res_bytes.next().await {
|
||||||
|
let chunk = chunk_res.context("error reading chunk from download")?;
|
||||||
|
let _ = file.write(chunk.as_ref()).await;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(temp_out)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// start to install package
|
||||||
|
pub async fn install_package(&self) -> anyhow::Result<()> {
|
||||||
|
let temp_path = self.temp_out_path();
|
||||||
|
let tool_path = tools_path();
|
||||||
|
|
||||||
|
let dir_name = if self == &Tool::Binaryen {
|
||||||
|
"binaryen-version_105"
|
||||||
|
} else {
|
||||||
|
""
|
||||||
|
};
|
||||||
|
|
||||||
|
if self.extension() == "tar.gz" {
|
||||||
|
let tar_gz = File::open(temp_path)?;
|
||||||
|
let tar = GzDecoder::new(tar_gz);
|
||||||
|
let mut archive = Archive::new(tar);
|
||||||
|
archive.unpack(&tool_path)?;
|
||||||
|
// println!("{:?} -> {:?}", tool_path.join(dir_name), tool_path.join(self.name()));
|
||||||
|
std::fs::rename(tool_path.join(dir_name), tool_path.join(self.name()))?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn call(&self, command: &str, args: Vec<&str>) -> anyhow::Result<Vec<u8>> {
|
||||||
|
let bin_path = tools_path().join(self.name()).join(self.bin_path());
|
||||||
|
|
||||||
|
let command_file = match self {
|
||||||
|
Tool::Binaryen => {
|
||||||
|
if cfg!(target_os = "windows") {
|
||||||
|
format!("{}.exe", command)
|
||||||
|
} else {
|
||||||
|
command.to_string()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if !bin_path.join(&command_file).is_file() {
|
||||||
|
return Err(anyhow::anyhow!("Command file not found."));
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut command = Command::new(bin_path.join(&command_file).to_str().unwrap());
|
||||||
|
|
||||||
|
let output = command
|
||||||
|
.args(&args[..])
|
||||||
|
.stdout(std::process::Stdio::inherit())
|
||||||
|
.stderr(std::process::Stdio::inherit())
|
||||||
|
.output()?;
|
||||||
|
Ok(output.stdout)
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in new issue
Block a user