2021-04-11 01:09:09 +03:00
|
|
|
|
// Copyright 2019-2021 Tauri Programme within The Commons Conservancy
|
|
|
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
|
|
2021-03-26 04:19:32 +03:00
|
|
|
|
use crate::helpers::{
|
2022-02-13 23:47:21 +03:00
|
|
|
|
config::get as get_config, framework::infer_from_package_json as infer_framework,
|
2021-03-26 04:19:32 +03:00
|
|
|
|
};
|
2021-12-09 18:21:33 +03:00
|
|
|
|
use crate::Result;
|
|
|
|
|
use clap::Parser;
|
2022-03-08 22:35:19 +03:00
|
|
|
|
use colored::Colorize;
|
2021-03-26 04:19:32 +03:00
|
|
|
|
use serde::Deserialize;
|
|
|
|
|
|
|
|
|
|
use std::{
|
|
|
|
|
collections::HashMap,
|
|
|
|
|
fs::{read_dir, read_to_string},
|
|
|
|
|
panic,
|
|
|
|
|
path::{Path, PathBuf},
|
|
|
|
|
process::Command,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
#[derive(Deserialize)]
|
|
|
|
|
struct YarnVersionInfo {
|
|
|
|
|
data: Vec<String>,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Clone, Deserialize)]
|
|
|
|
|
struct CargoLockPackage {
|
|
|
|
|
name: String,
|
|
|
|
|
version: String,
|
2022-02-05 03:00:55 +03:00
|
|
|
|
source: Option<String>,
|
2021-03-26 04:19:32 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Deserialize)]
|
|
|
|
|
struct CargoLock {
|
|
|
|
|
package: Vec<CargoLockPackage>,
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-14 19:37:29 +03:00
|
|
|
|
#[derive(Deserialize)]
|
|
|
|
|
struct JsCliVersionMetadata {
|
|
|
|
|
version: String,
|
|
|
|
|
node: String,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Deserialize)]
|
2021-04-15 08:48:38 +03:00
|
|
|
|
#[serde(rename_all = "camelCase")]
|
2021-04-14 19:37:29 +03:00
|
|
|
|
struct VersionMetadata {
|
2021-04-17 01:52:20 +03:00
|
|
|
|
#[serde(rename = "cli.js")]
|
2021-04-14 19:37:29 +03:00
|
|
|
|
js_cli: JsCliVersionMetadata,
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-26 04:19:32 +03:00
|
|
|
|
#[derive(Clone, Deserialize)]
|
|
|
|
|
struct CargoManifestDependencyPackage {
|
|
|
|
|
version: Option<String>,
|
2022-02-05 03:00:55 +03:00
|
|
|
|
git: Option<String>,
|
|
|
|
|
branch: Option<String>,
|
|
|
|
|
rev: Option<String>,
|
2021-03-26 04:19:32 +03:00
|
|
|
|
path: Option<PathBuf>,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Clone, Deserialize)]
|
|
|
|
|
#[serde(untagged)]
|
|
|
|
|
enum CargoManifestDependency {
|
|
|
|
|
Version(String),
|
|
|
|
|
Package(CargoManifestDependencyPackage),
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Deserialize)]
|
|
|
|
|
struct CargoManifestPackage {
|
|
|
|
|
version: String,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Deserialize)]
|
|
|
|
|
struct CargoManifest {
|
|
|
|
|
package: CargoManifestPackage,
|
|
|
|
|
dependencies: HashMap<String, CargoManifestDependency>,
|
|
|
|
|
}
|
|
|
|
|
|
2022-05-23 15:37:31 +03:00
|
|
|
|
#[derive(Debug, PartialEq, Eq)]
|
2021-08-24 19:01:16 +03:00
|
|
|
|
enum PackageManager {
|
|
|
|
|
Npm,
|
|
|
|
|
Pnpm,
|
|
|
|
|
Yarn,
|
2022-05-23 15:37:31 +03:00
|
|
|
|
Berry,
|
2021-08-24 19:01:16 +03:00
|
|
|
|
}
|
|
|
|
|
|
2021-12-09 18:21:33 +03:00
|
|
|
|
#[derive(Debug, Parser)]
|
|
|
|
|
#[clap(about = "Shows information about Tauri dependencies and project configuration")]
|
|
|
|
|
pub struct Options;
|
2021-01-30 18:15:47 +03:00
|
|
|
|
|
2022-04-25 17:31:25 +03:00
|
|
|
|
fn version_metadata() -> Result<VersionMetadata> {
|
|
|
|
|
serde_json::from_str::<VersionMetadata>(include_str!("../metadata.json")).map_err(Into::into)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[cfg(not(debug_assertions))]
|
|
|
|
|
pub(crate) fn cli_current_version() -> Result<String> {
|
|
|
|
|
version_metadata().map(|meta| meta.js_cli.version)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[cfg(not(debug_assertions))]
|
|
|
|
|
pub(crate) fn cli_upstream_version() -> Result<String> {
|
|
|
|
|
let upstream_metadata = match ureq::get(
|
|
|
|
|
"https://raw.githubusercontent.com/tauri-apps/tauri/dev/tooling/cli/metadata.json",
|
|
|
|
|
)
|
2022-04-29 19:44:31 +03:00
|
|
|
|
.timeout(std::time::Duration::from_secs(3))
|
2022-04-25 17:31:25 +03:00
|
|
|
|
.call()
|
|
|
|
|
{
|
|
|
|
|
Ok(r) => r,
|
|
|
|
|
Err(ureq::Error::Status(code, _response)) => {
|
|
|
|
|
let message = format!("Unable to find updates at the moment. Code: {}", code);
|
|
|
|
|
return Err(anyhow::Error::msg(message));
|
|
|
|
|
}
|
|
|
|
|
Err(ureq::Error::Transport(transport)) => {
|
|
|
|
|
let message = format!(
|
|
|
|
|
"Unable to find updates at the moment. Error: {:?}",
|
|
|
|
|
transport.kind()
|
|
|
|
|
);
|
|
|
|
|
return Err(anyhow::Error::msg(message));
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
upstream_metadata
|
|
|
|
|
.into_string()
|
|
|
|
|
.and_then(|meta_str| Ok(serde_json::from_str::<VersionMetadata>(&meta_str)))
|
|
|
|
|
.and_then(|json| Ok(json.unwrap().js_cli.version))
|
|
|
|
|
.map_err(|e| anyhow::Error::new(e))
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-26 04:19:32 +03:00
|
|
|
|
fn crate_latest_version(name: &str) -> Option<String> {
|
|
|
|
|
let url = format!("https://docs.rs/crate/{}/", name);
|
|
|
|
|
match ureq::get(&url).call() {
|
|
|
|
|
Ok(response) => match (response.status(), response.header("location")) {
|
|
|
|
|
(302, Some(location)) => Some(location.replace(&url, "")),
|
|
|
|
|
_ => None,
|
|
|
|
|
},
|
|
|
|
|
Err(_) => None,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-02-06 15:52:39 +03:00
|
|
|
|
#[allow(clippy::let_and_return)]
|
2022-02-06 02:17:39 +03:00
|
|
|
|
fn cross_command(bin: &str) -> Command {
|
|
|
|
|
#[cfg(target_os = "windows")]
|
2022-02-06 16:52:01 +03:00
|
|
|
|
let cmd = {
|
|
|
|
|
let mut cmd = Command::new("cmd");
|
|
|
|
|
cmd.arg("/c").arg(bin);
|
|
|
|
|
cmd
|
|
|
|
|
};
|
2022-02-06 02:17:39 +03:00
|
|
|
|
#[cfg(not(target_os = "windows"))]
|
2022-02-06 15:52:39 +03:00
|
|
|
|
let cmd = Command::new(bin);
|
2022-02-06 02:17:39 +03:00
|
|
|
|
cmd
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn npm_latest_version(pm: &PackageManager, name: &str) -> crate::Result<Option<String>> {
|
2021-08-24 19:01:16 +03:00
|
|
|
|
match pm {
|
|
|
|
|
PackageManager::Yarn => {
|
2022-02-06 02:17:39 +03:00
|
|
|
|
let mut cmd = cross_command("yarn");
|
2021-04-17 01:52:20 +03:00
|
|
|
|
|
2021-08-24 19:01:16 +03:00
|
|
|
|
let output = cmd
|
|
|
|
|
.arg("info")
|
|
|
|
|
.arg(name)
|
|
|
|
|
.args(&["version", "--json"])
|
|
|
|
|
.output()?;
|
|
|
|
|
if output.status.success() {
|
|
|
|
|
let stdout = String::from_utf8_lossy(&output.stdout);
|
|
|
|
|
let info: YarnVersionInfo = serde_json::from_str(&stdout)?;
|
|
|
|
|
Ok(Some(info.data.last().unwrap().to_string()))
|
|
|
|
|
} else {
|
|
|
|
|
Ok(None)
|
|
|
|
|
}
|
2021-04-17 01:52:20 +03:00
|
|
|
|
}
|
2022-05-23 15:37:31 +03:00
|
|
|
|
PackageManager::Berry => {
|
|
|
|
|
let mut cmd = cross_command("yarn");
|
|
|
|
|
|
|
|
|
|
let output = cmd
|
|
|
|
|
.arg("npm")
|
|
|
|
|
.arg("info")
|
|
|
|
|
.arg(name)
|
|
|
|
|
.args(["--fields", "version", "--json"])
|
|
|
|
|
.output()?;
|
|
|
|
|
if output.status.success() {
|
|
|
|
|
let info: crate::PackageJson =
|
|
|
|
|
serde_json::from_reader(std::io::Cursor::new(output.stdout)).unwrap();
|
|
|
|
|
Ok(info.version)
|
|
|
|
|
} else {
|
|
|
|
|
Ok(None)
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-08-24 19:01:16 +03:00
|
|
|
|
PackageManager::Npm => {
|
2022-02-06 02:17:39 +03:00
|
|
|
|
let mut cmd = cross_command("npm");
|
2021-08-24 19:01:16 +03:00
|
|
|
|
|
|
|
|
|
let output = cmd.arg("show").arg(name).arg("version").output()?;
|
|
|
|
|
if output.status.success() {
|
|
|
|
|
let stdout = String::from_utf8_lossy(&output.stdout);
|
2021-12-09 05:47:43 +03:00
|
|
|
|
Ok(Some(stdout.replace('\n', "")))
|
2021-08-24 19:01:16 +03:00
|
|
|
|
} else {
|
|
|
|
|
Ok(None)
|
|
|
|
|
}
|
2021-04-17 01:52:20 +03:00
|
|
|
|
}
|
2021-08-24 19:01:16 +03:00
|
|
|
|
PackageManager::Pnpm => {
|
2022-02-06 02:17:39 +03:00
|
|
|
|
let mut cmd = cross_command("pnpm");
|
2021-08-24 19:01:16 +03:00
|
|
|
|
|
|
|
|
|
let output = cmd.arg("info").arg(name).arg("version").output()?;
|
|
|
|
|
if output.status.success() {
|
|
|
|
|
let stdout = String::from_utf8_lossy(&output.stdout);
|
2021-12-09 05:47:43 +03:00
|
|
|
|
Ok(Some(stdout.replace('\n', "")))
|
2021-08-24 19:01:16 +03:00
|
|
|
|
} else {
|
|
|
|
|
Ok(None)
|
|
|
|
|
}
|
2021-03-26 04:19:32 +03:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn npm_package_version<P: AsRef<Path>>(
|
2021-08-24 19:01:16 +03:00
|
|
|
|
pm: &PackageManager,
|
2021-03-26 04:19:32 +03:00
|
|
|
|
name: &str,
|
|
|
|
|
app_dir: P,
|
|
|
|
|
) -> crate::Result<Option<String>> {
|
2022-05-23 15:37:31 +03:00
|
|
|
|
let (output, regex) = match pm {
|
|
|
|
|
PackageManager::Yarn => (
|
|
|
|
|
cross_command("yarn")
|
|
|
|
|
.args(&["list", "--pattern"])
|
|
|
|
|
.arg(name)
|
|
|
|
|
.args(&["--depth", "0"])
|
|
|
|
|
.current_dir(app_dir)
|
|
|
|
|
.output()?,
|
|
|
|
|
None,
|
|
|
|
|
),
|
|
|
|
|
PackageManager::Berry => (
|
|
|
|
|
cross_command("yarn")
|
|
|
|
|
.arg("info")
|
|
|
|
|
.arg(name)
|
|
|
|
|
.current_dir(app_dir)
|
|
|
|
|
.output()?,
|
|
|
|
|
Some(regex::Regex::new("Version: ([\\da-zA-Z\\-\\.]+)").unwrap()),
|
|
|
|
|
),
|
|
|
|
|
PackageManager::Npm => (
|
|
|
|
|
cross_command("npm")
|
|
|
|
|
.arg("list")
|
|
|
|
|
.arg(name)
|
|
|
|
|
.args(&["version", "--depth", "0"])
|
|
|
|
|
.current_dir(app_dir)
|
|
|
|
|
.output()?,
|
|
|
|
|
None,
|
|
|
|
|
),
|
|
|
|
|
PackageManager::Pnpm => (
|
|
|
|
|
cross_command("pnpm")
|
|
|
|
|
.arg("list")
|
|
|
|
|
.arg(name)
|
|
|
|
|
.args(&["--parseable", "--depth", "0"])
|
|
|
|
|
.current_dir(app_dir)
|
|
|
|
|
.output()?,
|
|
|
|
|
None,
|
|
|
|
|
),
|
2021-03-26 04:19:32 +03:00
|
|
|
|
};
|
|
|
|
|
if output.status.success() {
|
|
|
|
|
let stdout = String::from_utf8_lossy(&output.stdout);
|
2022-05-23 15:37:31 +03:00
|
|
|
|
let regex = regex.unwrap_or_else(|| regex::Regex::new("@([\\da-zA-Z\\-\\.]+)").unwrap());
|
2021-03-26 04:19:32 +03:00
|
|
|
|
Ok(
|
|
|
|
|
regex
|
|
|
|
|
.captures_iter(&stdout)
|
|
|
|
|
.last()
|
|
|
|
|
.and_then(|cap| cap.get(1).map(|v| v.as_str().to_string())),
|
|
|
|
|
)
|
|
|
|
|
} else {
|
|
|
|
|
Ok(None)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn get_version(command: &str, args: &[&str]) -> crate::Result<Option<String>> {
|
2022-02-06 02:17:39 +03:00
|
|
|
|
let output = cross_command(command)
|
|
|
|
|
.args(args)
|
|
|
|
|
.arg("--version")
|
|
|
|
|
.output()?;
|
2021-03-26 04:19:32 +03:00
|
|
|
|
let version = if output.status.success() {
|
2021-06-05 15:23:09 +03:00
|
|
|
|
Some(
|
|
|
|
|
String::from_utf8_lossy(&output.stdout)
|
2021-12-09 05:47:43 +03:00
|
|
|
|
.replace('\n', "")
|
|
|
|
|
.replace('\r', ""),
|
2021-06-05 15:23:09 +03:00
|
|
|
|
)
|
2021-03-26 04:19:32 +03:00
|
|
|
|
} else {
|
|
|
|
|
None
|
|
|
|
|
};
|
|
|
|
|
Ok(version)
|
|
|
|
|
}
|
|
|
|
|
|
2021-05-04 07:26:56 +03:00
|
|
|
|
#[cfg(windows)]
|
|
|
|
|
fn webview2_version() -> crate::Result<Option<String>> {
|
2021-12-29 01:28:21 +03:00
|
|
|
|
// check 64bit machine-wide installation
|
2021-05-04 07:26:56 +03:00
|
|
|
|
let output = Command::new("powershell")
|
2021-12-09 18:21:33 +03:00
|
|
|
|
.args(&["-NoProfile", "-Command"])
|
|
|
|
|
.arg("Get-ItemProperty -Path 'HKLM:\\SOFTWARE\\WOW6432Node\\Microsoft\\EdgeUpdate\\Clients\\{F3017226-FE2A-4295-8BDF-00C3A9A7E4C5}' | ForEach-Object {$_.pv}")
|
|
|
|
|
.output()?;
|
2021-12-29 01:28:21 +03:00
|
|
|
|
if output.status.success() {
|
|
|
|
|
return Ok(Some(
|
|
|
|
|
String::from_utf8_lossy(&output.stdout).replace('\n', ""),
|
|
|
|
|
));
|
|
|
|
|
}
|
|
|
|
|
// check 32bit machine-wide installation
|
|
|
|
|
let output = Command::new("powershell")
|
2021-12-09 18:21:33 +03:00
|
|
|
|
.args(&["-NoProfile", "-Command"])
|
|
|
|
|
.arg("Get-ItemProperty -Path 'HKLM:\\SOFTWARE\\Microsoft\\EdgeUpdate\\Clients\\{F3017226-FE2A-4295-8BDF-00C3A9A7E4C5}' | ForEach-Object {$_.pv}")
|
|
|
|
|
.output()?;
|
2021-12-29 01:28:21 +03:00
|
|
|
|
if output.status.success() {
|
|
|
|
|
return Ok(Some(
|
|
|
|
|
String::from_utf8_lossy(&output.stdout).replace('\n', ""),
|
|
|
|
|
));
|
|
|
|
|
}
|
|
|
|
|
// check user-wide installation
|
|
|
|
|
let output = Command::new("powershell")
|
|
|
|
|
.args(&["-NoProfile", "-Command"])
|
|
|
|
|
.arg("Get-ItemProperty -Path 'HKCU:\\SOFTWARE\\Microsoft\\EdgeUpdate\\Clients\\{F3017226-FE2A-4295-8BDF-00C3A9A7E4C5}' | ForEach-Object {$_.pv}")
|
|
|
|
|
.output()?;
|
|
|
|
|
if output.status.success() {
|
|
|
|
|
return Ok(Some(
|
|
|
|
|
String::from_utf8_lossy(&output.stdout).replace('\n', ""),
|
|
|
|
|
));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Ok(None)
|
2021-05-04 07:26:56 +03:00
|
|
|
|
}
|
|
|
|
|
|
2021-09-21 16:24:48 +03:00
|
|
|
|
#[cfg(windows)]
|
2022-02-06 02:17:39 +03:00
|
|
|
|
#[derive(Deserialize, Debug)]
|
|
|
|
|
#[serde(rename_all = "camelCase")]
|
|
|
|
|
struct VsInstanceInfo {
|
|
|
|
|
display_name: String,
|
2021-09-21 16:24:48 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[cfg(windows)]
|
2022-04-03 17:26:57 +03:00
|
|
|
|
const VSWHERE: &[u8] = include_bytes!("../scripts/vswhere.exe");
|
2021-09-21 16:24:48 +03:00
|
|
|
|
|
2022-02-06 02:17:39 +03:00
|
|
|
|
#[cfg(windows)]
|
|
|
|
|
fn build_tools_version() -> crate::Result<Option<Vec<String>>> {
|
|
|
|
|
let mut vswhere = std::env::temp_dir();
|
|
|
|
|
vswhere.push("vswhere.exe");
|
2021-09-21 16:24:48 +03:00
|
|
|
|
|
2022-02-06 02:17:39 +03:00
|
|
|
|
if !vswhere.exists() {
|
2022-04-03 17:26:57 +03:00
|
|
|
|
if let Ok(mut file) = std::fs::File::create(&vswhere) {
|
2022-02-06 02:17:39 +03:00
|
|
|
|
use std::io::Write;
|
|
|
|
|
let _ = file.write_all(VSWHERE);
|
2021-09-21 16:24:48 +03:00
|
|
|
|
}
|
2022-02-06 02:17:39 +03:00
|
|
|
|
}
|
|
|
|
|
let output = cross_command(vswhere.to_str().unwrap())
|
|
|
|
|
.args(&[
|
|
|
|
|
"-prerelease",
|
|
|
|
|
"-products",
|
|
|
|
|
"*",
|
|
|
|
|
"-requiresAny",
|
|
|
|
|
"-requires",
|
|
|
|
|
"Microsoft.VisualStudio.Workload.NativeDesktop",
|
|
|
|
|
"-requires",
|
|
|
|
|
"Microsoft.VisualStudio.Workload.VCTools",
|
|
|
|
|
"-format",
|
|
|
|
|
"json",
|
|
|
|
|
])
|
|
|
|
|
.output()?;
|
|
|
|
|
Ok(if output.status.success() {
|
|
|
|
|
let stdout = String::from_utf8_lossy(&output.stdout);
|
|
|
|
|
let instances: Vec<VsInstanceInfo> = serde_json::from_str(&stdout)?;
|
|
|
|
|
Some(
|
|
|
|
|
instances
|
|
|
|
|
.iter()
|
|
|
|
|
.map(|i| i.display_name.clone())
|
|
|
|
|
.collect::<Vec<String>>(),
|
|
|
|
|
)
|
2021-09-21 16:24:48 +03:00
|
|
|
|
} else {
|
|
|
|
|
None
|
2022-02-06 02:17:39 +03:00
|
|
|
|
})
|
2021-09-21 16:24:48 +03:00
|
|
|
|
}
|
|
|
|
|
|
2022-02-06 02:17:39 +03:00
|
|
|
|
fn active_rust_toolchain() -> crate::Result<Option<String>> {
|
|
|
|
|
let output = cross_command("rustup")
|
|
|
|
|
.args(["show", "active-toolchain"])
|
|
|
|
|
.output()?;
|
2021-12-09 07:28:26 +03:00
|
|
|
|
let toolchain = if output.status.success() {
|
|
|
|
|
Some(
|
|
|
|
|
String::from_utf8_lossy(&output.stdout)
|
2021-12-09 18:21:33 +03:00
|
|
|
|
.replace('\n', "")
|
2022-02-06 02:17:39 +03:00
|
|
|
|
.replace('\r', "")
|
|
|
|
|
.split('(')
|
|
|
|
|
.collect::<Vec<&str>>()[0]
|
|
|
|
|
.into(),
|
2021-12-09 07:28:26 +03:00
|
|
|
|
)
|
|
|
|
|
} else {
|
|
|
|
|
None
|
|
|
|
|
};
|
|
|
|
|
Ok(toolchain)
|
|
|
|
|
}
|
|
|
|
|
|
2022-02-13 23:47:21 +03:00
|
|
|
|
fn crate_version(
|
|
|
|
|
tauri_dir: &Path,
|
|
|
|
|
manifest: Option<&CargoManifest>,
|
|
|
|
|
lock: Option<&CargoLock>,
|
|
|
|
|
name: &str,
|
|
|
|
|
) -> (String, Option<String>) {
|
|
|
|
|
let crate_lock_packages: Vec<CargoLockPackage> = lock
|
|
|
|
|
.as_ref()
|
|
|
|
|
.map(|lock| {
|
|
|
|
|
lock
|
|
|
|
|
.package
|
|
|
|
|
.iter()
|
|
|
|
|
.filter(|p| p.name == name)
|
|
|
|
|
.cloned()
|
|
|
|
|
.collect()
|
|
|
|
|
})
|
|
|
|
|
.unwrap_or_default();
|
|
|
|
|
let (crate_version_string, found_crate_versions) =
|
|
|
|
|
match (&manifest, &lock, crate_lock_packages.len()) {
|
|
|
|
|
(Some(_manifest), Some(_lock), 1) => {
|
|
|
|
|
let crate_lock_package = crate_lock_packages.first().unwrap();
|
|
|
|
|
let version_string = if let Some(s) = &crate_lock_package.source {
|
|
|
|
|
if s.starts_with("git") {
|
|
|
|
|
format!("{} ({})", s, crate_lock_package.version)
|
|
|
|
|
} else {
|
|
|
|
|
crate_lock_package.version.clone()
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
crate_lock_package.version.clone()
|
|
|
|
|
};
|
|
|
|
|
(version_string, vec![crate_lock_package.version.clone()])
|
|
|
|
|
}
|
|
|
|
|
(None, Some(_lock), 1) => {
|
|
|
|
|
let crate_lock_package = crate_lock_packages.first().unwrap();
|
|
|
|
|
let version_string = if let Some(s) = &crate_lock_package.source {
|
|
|
|
|
if s.starts_with("git") {
|
|
|
|
|
format!("{} ({})", s, crate_lock_package.version)
|
|
|
|
|
} else {
|
|
|
|
|
crate_lock_package.version.clone()
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
crate_lock_package.version.clone()
|
|
|
|
|
};
|
|
|
|
|
(
|
|
|
|
|
format!("{} (no manifest)", version_string),
|
|
|
|
|
vec![crate_lock_package.version.clone()],
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
_ => {
|
|
|
|
|
let mut found_crate_versions = Vec::new();
|
|
|
|
|
let mut is_git = false;
|
|
|
|
|
let manifest_version = match manifest.and_then(|m| m.dependencies.get(name).cloned()) {
|
|
|
|
|
Some(tauri) => match tauri {
|
|
|
|
|
CargoManifestDependency::Version(v) => {
|
|
|
|
|
found_crate_versions.push(v.clone());
|
|
|
|
|
v
|
|
|
|
|
}
|
|
|
|
|
CargoManifestDependency::Package(p) => {
|
|
|
|
|
if let Some(v) = p.version {
|
|
|
|
|
found_crate_versions.push(v.clone());
|
|
|
|
|
v
|
|
|
|
|
} else if let Some(p) = p.path {
|
|
|
|
|
let manifest_path = tauri_dir.join(&p).join("Cargo.toml");
|
|
|
|
|
let v = match read_to_string(&manifest_path)
|
|
|
|
|
.map_err(|_| ())
|
|
|
|
|
.and_then(|m| toml::from_str::<CargoManifest>(&m).map_err(|_| ()))
|
|
|
|
|
{
|
|
|
|
|
Ok(manifest) => manifest.package.version,
|
|
|
|
|
Err(_) => "unknown version".to_string(),
|
|
|
|
|
};
|
|
|
|
|
format!("path:{:?} [{}]", p, v)
|
|
|
|
|
} else if let Some(g) = p.git {
|
|
|
|
|
is_git = true;
|
|
|
|
|
let mut v = format!("git:{}", g);
|
|
|
|
|
if let Some(branch) = p.branch {
|
|
|
|
|
v.push_str(&format!("&branch={}", branch));
|
|
|
|
|
} else if let Some(rev) = p.rev {
|
|
|
|
|
v.push_str(&format!("#{}", rev));
|
|
|
|
|
}
|
|
|
|
|
v
|
|
|
|
|
} else {
|
|
|
|
|
"unknown manifest".to_string()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
None => "no manifest".to_string(),
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
let lock_version = match (lock, crate_lock_packages.is_empty()) {
|
|
|
|
|
(Some(_lock), true) => crate_lock_packages
|
|
|
|
|
.iter()
|
|
|
|
|
.map(|p| p.version.clone())
|
|
|
|
|
.collect::<Vec<String>>()
|
|
|
|
|
.join(", "),
|
|
|
|
|
(Some(_lock), false) => "unknown lockfile".to_string(),
|
|
|
|
|
_ => "no lockfile".to_string(),
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
(
|
|
|
|
|
format!(
|
|
|
|
|
"{} {}({})",
|
|
|
|
|
manifest_version,
|
|
|
|
|
if is_git { "(git manifest)" } else { "" },
|
|
|
|
|
lock_version
|
|
|
|
|
),
|
|
|
|
|
found_crate_versions,
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
let crate_version = found_crate_versions
|
|
|
|
|
.into_iter()
|
|
|
|
|
.map(|v| semver::Version::parse(&v).unwrap())
|
|
|
|
|
.max();
|
|
|
|
|
let suffix = match (crate_version, crate_latest_version(name)) {
|
|
|
|
|
(Some(version), Some(target_version)) => {
|
|
|
|
|
let target_version = semver::Version::parse(&target_version).unwrap();
|
|
|
|
|
if version < target_version {
|
|
|
|
|
Some(format!(" (outdated, latest: {})", target_version))
|
|
|
|
|
} else {
|
|
|
|
|
None
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
_ => None,
|
|
|
|
|
};
|
|
|
|
|
(crate_version_string, suffix)
|
|
|
|
|
}
|
|
|
|
|
|
2022-03-08 22:35:19 +03:00
|
|
|
|
fn indent(spaces: usize) {
|
2022-04-02 02:59:56 +03:00
|
|
|
|
print!("{}", " ".repeat(spaces));
|
2022-03-08 22:35:19 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct Section(&'static str);
|
|
|
|
|
impl Section {
|
|
|
|
|
fn display(&self) {
|
|
|
|
|
println!();
|
|
|
|
|
println!("{}", self.0.yellow().bold());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct VersionBlock {
|
|
|
|
|
name: String,
|
|
|
|
|
version: String,
|
|
|
|
|
target_version: String,
|
|
|
|
|
indentation: usize,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl VersionBlock {
|
|
|
|
|
fn new(name: impl Into<String>, version: impl Into<String>) -> Self {
|
|
|
|
|
Self {
|
|
|
|
|
name: name.into(),
|
|
|
|
|
version: version.into(),
|
|
|
|
|
target_version: "".into(),
|
|
|
|
|
indentation: 2,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn target_version(mut self, version: impl Into<String>) -> Self {
|
|
|
|
|
self.target_version = version.into();
|
|
|
|
|
self
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn display(&self) {
|
|
|
|
|
indent(self.indentation);
|
|
|
|
|
print!("{} ", "›".cyan());
|
|
|
|
|
print!("{}", self.name.bold());
|
|
|
|
|
print!(": ");
|
|
|
|
|
print!(
|
|
|
|
|
"{}",
|
|
|
|
|
if self.version.is_empty() {
|
|
|
|
|
"Not installed!".red().to_string()
|
|
|
|
|
} else {
|
|
|
|
|
self.version.clone()
|
|
|
|
|
}
|
|
|
|
|
);
|
2022-04-29 19:29:31 +03:00
|
|
|
|
if !(self.version.is_empty() || self.target_version.is_empty()) {
|
2022-04-02 02:59:56 +03:00
|
|
|
|
let version = semver::Version::parse(self.version.as_str()).unwrap();
|
|
|
|
|
let target_version = semver::Version::parse(self.target_version.as_str()).unwrap();
|
|
|
|
|
if version < target_version {
|
|
|
|
|
print!(
|
2022-05-23 15:37:31 +03:00
|
|
|
|
" ({}, latest: {})",
|
2022-04-02 02:59:56 +03:00
|
|
|
|
"outdated".red(),
|
|
|
|
|
self.target_version.green()
|
|
|
|
|
);
|
|
|
|
|
}
|
2022-03-08 22:35:19 +03:00
|
|
|
|
}
|
|
|
|
|
println!();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct InfoBlock {
|
|
|
|
|
key: String,
|
|
|
|
|
value: String,
|
|
|
|
|
indentation: usize,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl InfoBlock {
|
|
|
|
|
fn new(key: impl Into<String>, val: impl Into<String>) -> Self {
|
|
|
|
|
Self {
|
|
|
|
|
key: key.into(),
|
|
|
|
|
value: val.into(),
|
|
|
|
|
indentation: 2,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn display(&self) {
|
|
|
|
|
indent(self.indentation);
|
|
|
|
|
print!("{} ", "›".cyan());
|
|
|
|
|
print!("{}", self.key.bold());
|
|
|
|
|
print!(": ");
|
|
|
|
|
print!("{}", self.value.clone());
|
|
|
|
|
println!();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-09 18:21:33 +03:00
|
|
|
|
pub fn command(_options: Options) -> Result<()> {
|
2022-03-08 22:35:19 +03:00
|
|
|
|
Section("Environment").display();
|
|
|
|
|
|
2021-12-09 18:21:33 +03:00
|
|
|
|
let os_info = os_info::get();
|
2022-03-08 22:35:19 +03:00
|
|
|
|
VersionBlock::new(
|
|
|
|
|
"OS",
|
|
|
|
|
format!(
|
|
|
|
|
"{} {} {:?}",
|
2021-12-09 18:21:33 +03:00
|
|
|
|
os_info.os_type(),
|
|
|
|
|
os_info.version(),
|
|
|
|
|
os_info.bitness()
|
2022-03-08 22:35:19 +03:00
|
|
|
|
),
|
|
|
|
|
)
|
2021-12-09 18:21:33 +03:00
|
|
|
|
.display();
|
|
|
|
|
|
|
|
|
|
#[cfg(windows)]
|
2022-03-08 22:35:19 +03:00
|
|
|
|
VersionBlock::new(
|
|
|
|
|
"Webview2",
|
|
|
|
|
webview2_version().unwrap_or_default().unwrap_or_default(),
|
|
|
|
|
)
|
|
|
|
|
.display();
|
2022-02-06 02:17:39 +03:00
|
|
|
|
|
2021-12-09 18:21:33 +03:00
|
|
|
|
#[cfg(windows)]
|
2022-02-06 02:17:39 +03:00
|
|
|
|
{
|
|
|
|
|
let build_tools = build_tools_version()
|
|
|
|
|
.unwrap_or_default()
|
|
|
|
|
.unwrap_or_default();
|
|
|
|
|
|
|
|
|
|
if build_tools.is_empty() {
|
2022-03-08 22:35:19 +03:00
|
|
|
|
InfoBlock::new("MSVC", "").display();
|
2022-02-06 02:17:39 +03:00
|
|
|
|
} else {
|
2022-03-08 22:35:19 +03:00
|
|
|
|
InfoBlock::new("MSVC", "").display();
|
2022-02-06 02:17:39 +03:00
|
|
|
|
for i in build_tools {
|
2022-03-08 22:35:19 +03:00
|
|
|
|
indent(6);
|
|
|
|
|
println!("{}", format!("{} {}", "-".cyan(), i));
|
2022-02-06 02:17:39 +03:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-12-09 18:21:33 +03:00
|
|
|
|
|
|
|
|
|
let hook = panic::take_hook();
|
|
|
|
|
panic::set_hook(Box::new(|_info| {
|
|
|
|
|
// do nothing
|
|
|
|
|
}));
|
2022-02-13 23:47:21 +03:00
|
|
|
|
let app_dir = panic::catch_unwind(crate::helpers::app_paths::app_dir)
|
|
|
|
|
.map(Some)
|
|
|
|
|
.unwrap_or_default();
|
2021-12-09 18:21:33 +03:00
|
|
|
|
panic::set_hook(hook);
|
|
|
|
|
|
2022-05-23 15:37:31 +03:00
|
|
|
|
let yarn_version = get_version("yarn", &[])
|
|
|
|
|
.unwrap_or_default()
|
|
|
|
|
.unwrap_or_default();
|
|
|
|
|
|
2022-04-25 17:31:25 +03:00
|
|
|
|
let metadata = version_metadata()?;
|
2022-03-08 22:35:19 +03:00
|
|
|
|
VersionBlock::new(
|
|
|
|
|
"Node.js",
|
|
|
|
|
get_version("node", &[])
|
|
|
|
|
.unwrap_or_default()
|
|
|
|
|
.unwrap_or_default()
|
|
|
|
|
.chars()
|
|
|
|
|
.skip(1)
|
|
|
|
|
.collect::<String>(),
|
|
|
|
|
)
|
|
|
|
|
.target_version(metadata.js_cli.node.replace(">= ", ""))
|
|
|
|
|
.display();
|
|
|
|
|
|
|
|
|
|
VersionBlock::new(
|
|
|
|
|
"npm",
|
|
|
|
|
get_version("npm", &[])
|
|
|
|
|
.unwrap_or_default()
|
|
|
|
|
.unwrap_or_default(),
|
|
|
|
|
)
|
|
|
|
|
.display();
|
|
|
|
|
VersionBlock::new(
|
|
|
|
|
"pnpm",
|
|
|
|
|
get_version("pnpm", &[])
|
|
|
|
|
.unwrap_or_default()
|
|
|
|
|
.unwrap_or_default(),
|
|
|
|
|
)
|
|
|
|
|
.display();
|
2022-05-23 15:37:31 +03:00
|
|
|
|
VersionBlock::new("yarn", &yarn_version).display();
|
2022-03-08 22:35:19 +03:00
|
|
|
|
VersionBlock::new(
|
|
|
|
|
"rustup",
|
|
|
|
|
get_version("rustup", &[])
|
|
|
|
|
.unwrap_or_default()
|
|
|
|
|
.map(|v| {
|
|
|
|
|
let mut s = v.split(' ');
|
|
|
|
|
s.next();
|
|
|
|
|
s.next().unwrap().to_string()
|
|
|
|
|
})
|
|
|
|
|
.unwrap_or_default(),
|
|
|
|
|
)
|
|
|
|
|
.display();
|
|
|
|
|
VersionBlock::new(
|
|
|
|
|
"rustc",
|
|
|
|
|
get_version("rustc", &[])
|
|
|
|
|
.unwrap_or_default()
|
|
|
|
|
.map(|v| {
|
|
|
|
|
let mut s = v.split(' ');
|
|
|
|
|
s.next();
|
|
|
|
|
s.next().unwrap().to_string()
|
|
|
|
|
})
|
|
|
|
|
.unwrap_or_default(),
|
|
|
|
|
)
|
|
|
|
|
.display();
|
|
|
|
|
VersionBlock::new(
|
|
|
|
|
"cargo",
|
|
|
|
|
get_version("cargo", &[])
|
|
|
|
|
.unwrap_or_default()
|
|
|
|
|
.map(|v| {
|
|
|
|
|
let mut s = v.split(' ');
|
|
|
|
|
s.next();
|
|
|
|
|
s.next().unwrap().to_string()
|
|
|
|
|
})
|
|
|
|
|
.unwrap_or_default(),
|
|
|
|
|
)
|
|
|
|
|
.display();
|
|
|
|
|
InfoBlock::new(
|
|
|
|
|
"Rust toolchain",
|
|
|
|
|
active_rust_toolchain()
|
|
|
|
|
.unwrap_or_default()
|
|
|
|
|
.unwrap_or_default(),
|
|
|
|
|
)
|
|
|
|
|
.display();
|
|
|
|
|
|
|
|
|
|
Section("Packages").display();
|
|
|
|
|
|
2021-12-09 18:21:33 +03:00
|
|
|
|
let mut package_manager = PackageManager::Npm;
|
|
|
|
|
if let Some(app_dir) = &app_dir {
|
2022-05-23 15:37:31 +03:00
|
|
|
|
let app_dir_entries = read_dir(app_dir)
|
2021-12-09 18:21:33 +03:00
|
|
|
|
.unwrap()
|
|
|
|
|
.map(|e| e.unwrap().file_name().to_string_lossy().into_owned())
|
|
|
|
|
.collect::<Vec<String>>();
|
2022-05-23 15:37:31 +03:00
|
|
|
|
package_manager = get_package_manager(&app_dir_entries)?;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if package_manager == PackageManager::Yarn
|
|
|
|
|
&& yarn_version
|
|
|
|
|
.chars()
|
|
|
|
|
.next()
|
|
|
|
|
.map(|c| c > '1')
|
|
|
|
|
.unwrap_or_default()
|
|
|
|
|
{
|
|
|
|
|
package_manager = PackageManager::Berry;
|
2021-01-30 18:15:47 +03:00
|
|
|
|
}
|
2022-05-23 15:37:31 +03:00
|
|
|
|
|
2021-12-09 18:21:33 +03:00
|
|
|
|
VersionBlock::new(
|
2022-03-08 22:35:19 +03:00
|
|
|
|
format!("{} {}", "@tauri-apps/cli", "[NPM]".dimmed()),
|
|
|
|
|
metadata.js_cli.version,
|
2021-12-09 18:21:33 +03:00
|
|
|
|
)
|
2022-03-08 22:35:19 +03:00
|
|
|
|
.target_version(
|
|
|
|
|
npm_latest_version(&package_manager, "@tauri-apps/cli")
|
|
|
|
|
.unwrap_or_default()
|
|
|
|
|
.unwrap_or_default(),
|
2021-12-09 18:21:33 +03:00
|
|
|
|
)
|
|
|
|
|
.display();
|
2022-03-08 22:35:19 +03:00
|
|
|
|
if let Some(app_dir) = &app_dir {
|
|
|
|
|
VersionBlock::new(
|
|
|
|
|
format!("{} {}", "@tauri-apps/api", "[NPM]".dimmed()),
|
|
|
|
|
npm_package_version(&package_manager, "@tauri-apps/api", app_dir)
|
|
|
|
|
.unwrap_or_default()
|
|
|
|
|
.unwrap_or_default(),
|
|
|
|
|
)
|
|
|
|
|
.target_version(
|
|
|
|
|
npm_latest_version(&package_manager, "@tauri-apps/api")
|
|
|
|
|
.unwrap_or_default()
|
|
|
|
|
.unwrap_or_default(),
|
|
|
|
|
)
|
|
|
|
|
.display();
|
2021-12-09 18:21:33 +03:00
|
|
|
|
}
|
2021-03-26 04:19:32 +03:00
|
|
|
|
|
2022-02-13 23:47:21 +03:00
|
|
|
|
let hook = panic::take_hook();
|
|
|
|
|
panic::set_hook(Box::new(|_info| {
|
|
|
|
|
// do nothing
|
|
|
|
|
}));
|
|
|
|
|
let tauri_dir = panic::catch_unwind(crate::helpers::app_paths::tauri_dir)
|
|
|
|
|
.map(Some)
|
2021-12-09 18:21:33 +03:00
|
|
|
|
.unwrap_or_default();
|
2022-02-13 23:47:21 +03:00
|
|
|
|
panic::set_hook(hook);
|
|
|
|
|
|
|
|
|
|
if tauri_dir.is_some() || app_dir.is_some() {
|
2022-03-08 22:35:19 +03:00
|
|
|
|
if let Some(tauri_dir) = tauri_dir.clone() {
|
2022-02-13 23:47:21 +03:00
|
|
|
|
let manifest: Option<CargoManifest> =
|
|
|
|
|
if let Ok(manifest_contents) = read_to_string(tauri_dir.join("Cargo.toml")) {
|
|
|
|
|
toml::from_str(&manifest_contents).ok()
|
2022-02-05 03:00:55 +03:00
|
|
|
|
} else {
|
2022-02-13 23:47:21 +03:00
|
|
|
|
None
|
2022-02-05 03:00:55 +03:00
|
|
|
|
};
|
2022-02-13 23:47:21 +03:00
|
|
|
|
let lock: Option<CargoLock> =
|
|
|
|
|
if let Ok(lock_contents) = read_to_string(tauri_dir.join("Cargo.lock")) {
|
|
|
|
|
toml::from_str(&lock_contents).ok()
|
2022-02-05 03:00:55 +03:00
|
|
|
|
} else {
|
2022-02-13 23:47:21 +03:00
|
|
|
|
None
|
2021-03-26 04:19:32 +03:00
|
|
|
|
};
|
2021-12-09 18:21:33 +03:00
|
|
|
|
|
2022-02-13 23:47:21 +03:00
|
|
|
|
for (dep, label) in [
|
2022-03-08 22:35:19 +03:00
|
|
|
|
("tauri", format!("{} {}", "tauri", "[RUST]".dimmed())),
|
|
|
|
|
(
|
|
|
|
|
"tauri-build",
|
|
|
|
|
format!("{} {}", "tauri-build", "[RUST]".dimmed()),
|
|
|
|
|
),
|
|
|
|
|
("tao", format!("{} {}", "tao", "[RUST]".dimmed())),
|
|
|
|
|
("wry", format!("{} {}", "wry", "[RUST]".dimmed())),
|
2022-02-13 23:47:21 +03:00
|
|
|
|
] {
|
|
|
|
|
let (version_string, version_suffix) =
|
|
|
|
|
crate_version(&tauri_dir, manifest.as_ref(), lock.as_ref(), dep);
|
2022-03-08 22:35:19 +03:00
|
|
|
|
VersionBlock::new(
|
|
|
|
|
label,
|
|
|
|
|
format!(
|
|
|
|
|
"{},{}",
|
|
|
|
|
version_string,
|
|
|
|
|
version_suffix.unwrap_or_else(|| "".into())
|
|
|
|
|
),
|
|
|
|
|
)
|
|
|
|
|
.display();
|
2021-03-26 04:19:32 +03:00
|
|
|
|
}
|
2022-03-08 22:35:19 +03:00
|
|
|
|
}
|
|
|
|
|
}
|
2021-12-09 18:21:33 +03:00
|
|
|
|
|
2022-03-08 22:35:19 +03:00
|
|
|
|
if tauri_dir.is_some() || app_dir.is_some() {
|
|
|
|
|
Section("App").display();
|
|
|
|
|
if tauri_dir.is_some() {
|
2022-02-13 23:47:21 +03:00
|
|
|
|
if let Ok(config) = get_config(None) {
|
|
|
|
|
let config_guard = config.lock().unwrap();
|
|
|
|
|
let config = config_guard.as_ref().unwrap();
|
2022-03-08 22:35:19 +03:00
|
|
|
|
InfoBlock::new(
|
|
|
|
|
"build-type",
|
|
|
|
|
if config.tauri.bundle.active {
|
2022-02-13 23:47:21 +03:00
|
|
|
|
"bundle".to_string()
|
|
|
|
|
} else {
|
|
|
|
|
"build".to_string()
|
2022-03-08 22:35:19 +03:00
|
|
|
|
},
|
|
|
|
|
)
|
|
|
|
|
.display();
|
|
|
|
|
InfoBlock::new(
|
|
|
|
|
"CSP",
|
|
|
|
|
config
|
|
|
|
|
.tauri
|
|
|
|
|
.security
|
|
|
|
|
.csp
|
|
|
|
|
.clone()
|
|
|
|
|
.map(|c| c.to_string())
|
|
|
|
|
.unwrap_or_else(|| "unset".to_string()),
|
|
|
|
|
)
|
|
|
|
|
.display();
|
|
|
|
|
InfoBlock::new("distDir", config.build.dist_dir.to_string()).display();
|
|
|
|
|
InfoBlock::new("devPath", config.build.dev_path.to_string()).display();
|
2021-05-03 03:51:35 +03:00
|
|
|
|
}
|
2021-03-26 04:19:32 +03:00
|
|
|
|
}
|
|
|
|
|
|
2022-02-13 23:47:21 +03:00
|
|
|
|
if let Some(app_dir) = app_dir {
|
|
|
|
|
if let Ok(package_json) = read_to_string(app_dir.join("package.json")) {
|
|
|
|
|
let (framework, bundler) = infer_framework(&package_json);
|
|
|
|
|
if let Some(framework) = framework {
|
2022-03-08 22:35:19 +03:00
|
|
|
|
InfoBlock::new("framework", framework.to_string()).display();
|
2022-02-13 23:47:21 +03:00
|
|
|
|
}
|
|
|
|
|
if let Some(bundler) = bundler {
|
2022-03-08 22:35:19 +03:00
|
|
|
|
InfoBlock::new("bundler", bundler.to_string()).display();
|
2022-02-13 23:47:21 +03:00
|
|
|
|
}
|
2021-12-09 18:21:33 +03:00
|
|
|
|
} else {
|
2022-02-13 23:47:21 +03:00
|
|
|
|
println!("package.json not found");
|
2021-12-09 18:21:33 +03:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-03-08 22:35:19 +03:00
|
|
|
|
if let Some(app_dir) = app_dir {
|
|
|
|
|
Section("App directory structure").display();
|
|
|
|
|
let dirs = read_dir(app_dir)?
|
|
|
|
|
.filter(|p| p.is_ok() && p.as_ref().unwrap().path().is_dir())
|
|
|
|
|
.collect::<Vec<Result<std::fs::DirEntry, _>>>();
|
|
|
|
|
let dirs_len = dirs.len();
|
|
|
|
|
for (i, entry) in dirs.into_iter().enumerate() {
|
|
|
|
|
let entry = entry?;
|
|
|
|
|
let prefix = if i + 1 == dirs_len {
|
|
|
|
|
"└─".cyan()
|
|
|
|
|
} else {
|
|
|
|
|
"├─".cyan()
|
|
|
|
|
};
|
|
|
|
|
println!(
|
|
|
|
|
" {} {}",
|
|
|
|
|
prefix,
|
|
|
|
|
entry.path().file_name().unwrap().to_string_lossy()
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-09 18:21:33 +03:00
|
|
|
|
Ok(())
|
2021-01-30 18:15:47 +03:00
|
|
|
|
}
|
2021-08-24 19:01:16 +03:00
|
|
|
|
|
2022-05-23 15:37:31 +03:00
|
|
|
|
fn get_package_manager<T: AsRef<str>>(app_dir_entries: &[T]) -> crate::Result<PackageManager> {
|
2021-08-24 19:01:16 +03:00
|
|
|
|
let mut use_npm = false;
|
|
|
|
|
let mut use_pnpm = false;
|
|
|
|
|
let mut use_yarn = false;
|
|
|
|
|
|
2022-05-23 15:37:31 +03:00
|
|
|
|
for name in app_dir_entries {
|
2021-08-24 19:01:16 +03:00
|
|
|
|
if name.as_ref() == "package-lock.json" {
|
|
|
|
|
use_npm = true;
|
|
|
|
|
} else if name.as_ref() == "pnpm-lock.yaml" {
|
|
|
|
|
use_pnpm = true;
|
|
|
|
|
} else if name.as_ref() == "yarn.lock" {
|
|
|
|
|
use_yarn = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if !use_npm && !use_pnpm && !use_yarn {
|
|
|
|
|
println!("WARNING: no lock files found, defaulting to npm");
|
|
|
|
|
return Ok(PackageManager::Npm);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let mut found = Vec::new();
|
|
|
|
|
|
|
|
|
|
if use_npm {
|
|
|
|
|
found.push("npm");
|
|
|
|
|
}
|
|
|
|
|
if use_pnpm {
|
|
|
|
|
found.push("pnpm");
|
|
|
|
|
}
|
|
|
|
|
if use_yarn {
|
|
|
|
|
found.push("yarn");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if found.len() > 1 {
|
|
|
|
|
return Err(anyhow::anyhow!(
|
2021-12-09 18:21:33 +03:00
|
|
|
|
"only one package mangager should be used, but found {}\nplease remove unused package manager lock files",
|
|
|
|
|
found.join(" and ")
|
|
|
|
|
));
|
2021-08-24 19:01:16 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if use_npm {
|
|
|
|
|
Ok(PackageManager::Npm)
|
|
|
|
|
} else if use_pnpm {
|
|
|
|
|
Ok(PackageManager::Pnpm)
|
|
|
|
|
} else {
|
|
|
|
|
Ok(PackageManager::Yarn)
|
|
|
|
|
}
|
|
|
|
|
}
|