Skip to content

Commit

Permalink
feat: show missing deps after template bootstrap (#367)
Browse files Browse the repository at this point in the history
  • Loading branch information
amrbashir authored Mar 13, 2023
1 parent 7bfdcaa commit 7b992e5
Show file tree
Hide file tree
Showing 13 changed files with 220 additions and 45 deletions.
6 changes: 6 additions & 0 deletions .changes/deps.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"create-tauri-app": "patch"
"create-tauri-app-js": "patch"
---

Show a table of missing dependencies with installation instructions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@ ignore = ["./src-tauri"]
address = "0.0.0.0"
port = 1420
open = false
ws_protocol = "ws"
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@ ignore = ["./src-tauri"]
address = "0.0.0.0"
port = 1420
open = false
ws_protocol = "ws"
1 change: 1 addition & 0 deletions packages/cli/fragments/fragment-yew/%(mobile)%Trunk.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@ ignore = ["./src-tauri"]
address = "0.0.0.0"
port = 1420
open = false
ws_protocol = "ws"
6 changes: 4 additions & 2 deletions packages/cli/node/create-tauri-app.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,12 @@ const binStem = path.parse(bin).name.toLowerCase();
// We want to make a helpful binary name for the underlying CLI helper, if we
// can successfully detect what command likely started the execution.
let binName;

if (bin === "@tauri-apps/cli") {
binName = "@tauri-apps/cli";
}
// Even if started by a package manager, the binary will be NodeJS.
// Some distribution still use "nodejs" as the binary name.
if (binStem.match(/(nodejs|node)([1-9]*)*$/g)) {
if (binStem.match(/(nodejs|node)-*([1-9]*)*$/g)) {
const managerStem = process.env.npm_execpath
? path.parse(process.env.npm_execpath).name.toLowerCase()
: null;
Expand Down
6 changes: 3 additions & 3 deletions packages/cli/src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,17 +62,17 @@ pub fn parse(argv: Vec<OsString>, bin_name: Option<String>) -> anyhow::Result<Ar
desc = env!("CARGO_PKG_DESCRIPTION"),
managers = PackageManager::ALL
.iter()
.map(|e| format!("{}{}{}", GREEN, e, RESET))
.map(|e| format!("{GREEN}{e}{RESET}"))
.collect::<Vec<_>>()
.join(", "),
fragments = Template::ALL
.iter()
.map(|e| format!("{}{}{}", GREEN, e, RESET))
.map(|e| format!("{GREEN}{e}{RESET}"))
.collect::<Vec<_>>()
.join(", "),
);

println!("{}", help);
println!("{help}");
std::process::exit(0);
}
if pargs.contains(["-v", "--version"]) {
Expand Down
17 changes: 17 additions & 0 deletions packages/cli/src/colors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT

#![allow(unused)]

pub const BLACK: &str = "\x1b[30m";
pub const RED: &str = "\x1b[31m";
pub const GREEN: &str = "\x1b[32m";
pub const YELLOW: &str = "\x1b[33m";
Expand All @@ -12,3 +15,17 @@ pub const BOLD: &str = "\x1b[1m";
pub const ITALIC: &str = "\x1b[3m";
pub const DIM: &str = "\x1b[2m";
pub const DIMRESET: &str = "\x1b[22m";

pub fn remove_colors(s: &str) -> String {
s.replace(BLACK, "")
.replace(RED, "")
.replace(GREEN, "")
.replace(YELLOW, "")
.replace(BLUE, "")
.replace(WHITE, "")
.replace(RESET, "")
.replace(BOLD, "")
.replace(ITALIC, "")
.replace(DIM, "")
.replace(DIMRESET, "")
}
154 changes: 154 additions & 0 deletions packages/cli/src/deps.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
use template::Template;

use crate::colors::*;
use crate::internal::template;
use crate::package_manager::PackageManager;
use std::process::Command;

fn is_rustc_installed() -> bool {
Command::new("rustc").arg("-V").output().is_ok()
}
fn is_cargo_installed() -> bool {
Command::new("cargo").arg("-V").output().is_ok()
}
fn is_node_installed() -> bool {
Command::new("node").arg("-v").output().is_ok()
}

fn is_trunk_installed() -> bool {
Command::new("trunk").arg("-V").output().is_ok()
}
fn is_tauri_cli_installed() -> bool {
Command::new("cargo")
.arg("tauri")
.arg("-V")
.output()
.map(|o| {
let s = String::from_utf8_lossy(&o.stderr);
!s.starts_with("error:")
})
.unwrap_or(false)
}
fn is_wasm32_installed() -> bool {
Command::new("rustup")
.args(["target", "list", "--installed"])
.output()
.map(|o| {
let s = String::from_utf8_lossy(&o.stdout);
s.contains("wasm32-unknown-unknown")
})
.unwrap_or(false)
}

pub fn print_missing_deps(pkg_manager: PackageManager, template: Template, alpha: bool) {
let rustc_installed = is_rustc_installed();
let cargo_installed = is_cargo_installed();
let deps: &[(&str, String, &dyn Fn() -> bool, bool)] = &[
(
"Rust",
format!("Visit {BLUE}{BOLD}https://www.rust-lang.org/learn/get-started#installing-rust{RESET}"),
&|| rustc_installed && cargo_installed,
rustc_installed || cargo_installed,
),
(
"rustc",
format!("Visit {BLUE}{BOLD}https://www.rust-lang.org/learn/get-started#installing-rust{RESET} to install Rust"),
&|| rustc_installed,
!rustc_installed && !cargo_installed,
),
(
"Cargo",
format!("Visit {BLUE}{BOLD}https://www.rust-lang.org/learn/get-started#installing-rust{RESET} to install Rust"),
&|| cargo_installed,
!rustc_installed && !cargo_installed,
),
(
"Tauri CLI",
if alpha {
format!("Run `{BLUE}{BOLD}cargo install tauri-cli --version 2.0.0-alpha.2{RESET}`")
} else {
format!("Run `{BLUE}{BOLD}cargo install tauri-cli{RESET}`")
},
&is_tauri_cli_installed,
pkg_manager.is_node() || !template.needs_tauri_cli(),
),
(
"Trunk",
if alpha {
format!("Run `{BLUE}{BOLD}cargo install trunk --git https://github.com/amrbashir/trunk{RESET}`")
} else {
format!("Visit {BLUE}{BOLD}https://trunkrs.dev/#install{RESET}")
},
&is_trunk_installed,
pkg_manager.is_node() || !template.needs_trunk(),
),
(
"wasm32 target",
format!("Run `{BLUE}{BOLD}rustup target add wasm32-unknown-unknown{RESET}`"),
&is_wasm32_installed,
pkg_manager.is_node() || !template.needs_wasm32_target(),
),
(
"Node.js",
format!("Visit {BLUE}{BOLD}https://nodejs.org/en/{RESET}"),
&is_node_installed,
!pkg_manager.is_node(),
),
];

let missing_deps: Vec<(String, String)> = deps
.iter()
.filter(|(_, _, exists, skip)| !skip && !exists())
.map(|(s, d, _, _)| (s.to_string(), d.clone()))
.collect();

let (largest_first_cell, largest_second_cell) =
missing_deps
.iter()
.fold((0, 0), |(mut prev_f, mut prev_s), (f, s)| {
let f_len = f.len();
if f_len > prev_f {
prev_f = f_len;
}

let s_len = remove_colors(s).len();
if s_len > prev_s {
prev_s = s_len;
}

(prev_f, prev_s)
});

if !missing_deps.is_empty() {
println!("\n\nYour system is {YELLOW}missing dependencies{RESET} (or they do not exist in {YELLOW}$PATH{RESET}):");
for (index, (name, instruction)) in missing_deps.iter().enumerate() {
if index == 0 {
println!(
"╭{}┬{}╮",
"─".repeat(largest_first_cell + 2),
"─".repeat(largest_second_cell + 2)
);
} else {
println!(
"├{}┼{}┤",
"─".repeat(largest_first_cell + 2),
"─".repeat(largest_second_cell + 2)
);
}
println!(
"│ {YELLOW}{name}{RESET}{} │ {instruction}{} │",
" ".repeat(largest_first_cell - name.len()),
" ".repeat(largest_second_cell - remove_colors(instruction).len()),
);
}
println!(
"╰{}┴{}╯",
"─".repeat(largest_first_cell + 2),
"─".repeat(largest_second_cell + 2),
);
println!();
println!("Make sure you have installed the prerequisites for your OS: {BLUE}{BOLD}https://tauri.app/v1/guides/getting-started/prerequisites{RESET}, then run:");
} else {
println!(" To get started run:")
}
}
23 changes: 11 additions & 12 deletions packages/cli/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,15 @@
use dialoguer::{Confirm, Input, Select};
use std::{ffi::OsString, fs, process::exit};

use crate::{category::Category, colors::*, package_manager::PackageManager, theme::ColorfulTheme};
use crate::{
category::Category, colors::*, deps::print_missing_deps, package_manager::PackageManager,
theme::ColorfulTheme,
};

mod category;
mod cli;
mod colors;
mod deps;
mod manifest;
mod package_manager;
mod template;
Expand Down Expand Up @@ -257,7 +261,7 @@ where
eprintln!(
"{BOLD}{RED}error{RESET}: the {GREEN}{}{RESET} template is not suppported for the {GREEN}{pkg_manager}{RESET} package manager\n possible templates for {GREEN}{pkg_manager}{RESET} are: [{}]",
template,
templates.iter().map(|e|format!("{GREEN}{}{RESET}", e, GREEN = GREEN, RESET = RESET)).collect::<Vec<_>>().join(", ")
templates.iter().map(|e|format!("{GREEN}{e}{RESET}")).collect::<Vec<_>>().join(", ")
);
exit(1);
}
Expand All @@ -276,27 +280,22 @@ where
template.render(&target_dir, pkg_manager, &package_name, alpha, mobile)?;

// Print post-render instructions

println!();
println!(
"{ITALIC}{DIM}Please follow{DIMRESET} {BLUE}https://tauri.app/v1/guides/getting-started/prerequisites{WHITE} {DIM}to install the needed prerequisites, if you haven't already.{DIMRESET}{RESET}",
);
if let Some(info) = template.post_init_info(pkg_manager, alpha) {
println!("{}", info);
}
println!();
println!("Done, now run:");
print!("Template created!");
print_missing_deps(pkg_manager, template, alpha);
if target_dir != cwd {
println!(
" cd {}",
if project_name.contains(' ') {
format!("\"{}\"", project_name)
format!("\"{project_name}\"")
} else {
project_name
}
);
}
if let Some(cmd) = pkg_manager.install_cmd() {
println!(" {}", cmd);
println!(" {cmd}");
}
if !mobile {
println!(" {} tauri dev", pkg_manager.run_cmd());
Expand Down
7 changes: 7 additions & 0 deletions packages/cli/src/package_manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,13 @@ impl PackageManager {
PackageManager::Npm => "npm run",
}
}

pub const fn is_node(&self) -> bool {
matches!(
self,
PackageManager::Pnpm | PackageManager::Yarn | PackageManager::Npm,
)
}
}

impl Display for PackageManager {
Expand Down
35 changes: 12 additions & 23 deletions packages/cli/src/template.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use std::{fmt::Display, fs, io::Write, path, str::FromStr};
use anyhow::Context;
use rust_embed::RustEmbed;

use crate::{colors::*, manifest::Manifest, package_manager::PackageManager};
use crate::{manifest::Manifest, package_manager::PackageManager};

#[derive(RustEmbed)]
#[folder = "$CARGO_MANIFEST_DIR/fragments"]
Expand Down Expand Up @@ -146,28 +146,17 @@ impl<'a> Template {
}
}

pub fn post_init_info(&self, pkg_manager: PackageManager, alpha: bool) -> Option<String> {
let tauri_cli_cmd = if alpha {
"cargo install tauri-cli --version 2.0.0-alpha.2"
} else {
"cargo install tauri-cli"
};

match self {
Template::Yew | Template::Leptos| Template::Sycamore => Some(
format!(
"{ITALIC}{DIM}You also need to install:\n 1. {DIMRESET}{YELLOW}tauri-cli{WHITE}{DIM} ({DIMRESET}{BLUE}{tauri_cli_cmd}{WHITE}{DIM})\n 2. {DIMRESET}{YELLOW}trunk{WHITE}{DIM} ({DIMRESET}{BLUE}https://trunkrs.dev/#install{WHITE}{DIM})\n 3. {DIMRESET}{YELLOW}wasm32{WHITE}{DIM} rust target ({DIMRESET}{BLUE}rustup target add wasm32-unknown-unknown{WHITE}{DIM}){DIMRESET}{RESET}",
tauri_cli_cmd = tauri_cli_cmd,
),
),
Template::Vanilla if pkg_manager == PackageManager::Cargo => Some(
format!(
"{ITALIC}{DIM}You also need to install{DIMRESET} {YELLOW}tauri-cli{WHITE} {DIM}({DIMRESET}{BLUE}{tauri_cli_cmd}{WHITE}{DIM})",
tauri_cli_cmd = tauri_cli_cmd,
),
),
_ => None,
}
pub const fn needs_trunk(&self) -> bool {
matches!(self, Template::Sycamore | Template::Yew | Template::Leptos)
}
pub const fn needs_tauri_cli(&self) -> bool {
matches!(
self,
Template::Sycamore | Template::Yew | Template::Leptos | Template::Vanilla
)
}
pub const fn needs_wasm32_target(&self) -> bool {
matches!(self, Template::Sycamore | Template::Yew | Template::Leptos)
}

pub fn render(
Expand Down
2 changes: 1 addition & 1 deletion packages/cli/src/theme.rs
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ impl Theme for ColorfulTheme {
Some(default) => write!(
f,
"{} {} ",
self.hint_style.apply_to(&format!("({})", default)),
self.hint_style.apply_to(&format!("({default})")),
&self.prompt_suffix
),
None => write!(f, "{} ", &self.prompt_suffix),
Expand Down
6 changes: 2 additions & 4 deletions renovate.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,8 @@
"extends": ["config:base", ":disableDependencyDashboard"],
"packageRules": [
{
"groupName": "templates dependencies",
"groupSlug": "templatesDeps",
"commitMessagePrefix": "chore(deps)",
"paths": [
"groupName": "fragments dependencies",
"matchPaths": [
"packages/cli/fragments/**/*package.json",
"packages/cli/fragments/**/*Cargo.toml"
],
Expand Down

0 comments on commit 7b992e5

Please sign in to comment.