Skip to content

Commit

Permalink
fix(cli.rs): pnpm tauri info exits with error (fix #2509) (#2510)
Browse files Browse the repository at this point in the history
Co-authored-by: Lucas Nogueira <lucas@tauri.studio>
  • Loading branch information
linuxuser586 and lucasfernog authored Aug 24, 2021
1 parent 245d12f commit 2026134
Show file tree
Hide file tree
Showing 2 changed files with 259 additions and 74 deletions.
5 changes: 5 additions & 0 deletions .changes/tooling-fix-pnpm-info-error.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'cli.rs': patch
---

Fixes pnpm error when running `pnpm tauri info`.
328 changes: 254 additions & 74 deletions tooling/cli.rs/src/info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,12 @@ struct CargoManifest {
dependencies: HashMap<String, CargoManifestDependency>,
}

enum PackageManager {
Npm,
Pnpm,
Yarn,
}

#[derive(Default)]
pub struct Info;

Expand All @@ -86,96 +92,141 @@ fn crate_latest_version(name: &str) -> Option<String> {
}
}

fn npm_latest_version(use_yarn: bool, name: &str) -> crate::Result<Option<String>> {
fn npm_latest_version(pm: &PackageManager, name: &str) -> crate::Result<Option<String>> {
let mut cmd;
if use_yarn {
#[cfg(target_os = "windows")]
{
cmd = Command::new("cmd");
cmd.arg("/c").arg("yarn");
}
match pm {
PackageManager::Yarn => {
#[cfg(target_os = "windows")]
{
cmd = Command::new("cmd");
cmd.arg("/c").arg("yarn");
}

#[cfg(not(target_os = "windows"))]
{
cmd = Command::new("yarn")
}
#[cfg(not(target_os = "windows"))]
{
cmd = Command::new("yarn")
}

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)
}
} else {
#[cfg(target_os = "windows")]
{
cmd = Command::new("cmd");
cmd.arg("/c").arg("npm");
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)
}
}
PackageManager::Npm => {
#[cfg(target_os = "windows")]
{
cmd = Command::new("cmd");
cmd.arg("/c").arg("npm");
}

#[cfg(not(target_os = "windows"))]
{
cmd = Command::new("npm")
#[cfg(not(target_os = "windows"))]
{
cmd = Command::new("npm")
}

let output = cmd.arg("show").arg(name).arg("version").output()?;
if output.status.success() {
let stdout = String::from_utf8_lossy(&output.stdout);
Ok(Some(stdout.replace("\n", "")))
} else {
Ok(None)
}
}
PackageManager::Pnpm => {
#[cfg(target_os = "windows")]
{
cmd = Command::new("cmd");
cmd.arg("/c").arg("pnpm");
}

let output = cmd.arg("show").arg(name).arg("version").output()?;
if output.status.success() {
let stdout = String::from_utf8_lossy(&output.stdout);
Ok(Some(stdout.replace("\n", "")))
} else {
Ok(None)
#[cfg(not(target_os = "windows"))]
{
cmd = Command::new("pnpm")
}

let output = cmd.arg("info").arg(name).arg("version").output()?;
if output.status.success() {
let stdout = String::from_utf8_lossy(&output.stdout);
Ok(Some(stdout.replace("\n", "")))
} else {
Ok(None)
}
}
}
}

fn npm_package_version<P: AsRef<Path>>(
use_yarn: bool,
pm: &PackageManager,
name: &str,
app_dir: P,
) -> crate::Result<Option<String>> {
let mut cmd;
let output = if use_yarn {
#[cfg(target_os = "windows")]
{
cmd = Command::new("cmd");
cmd.arg("/c").arg("yarn");
}
let output = match pm {
PackageManager::Yarn => {
#[cfg(target_os = "windows")]
{
cmd = Command::new("cmd");
cmd.arg("/c").arg("yarn");
}

#[cfg(not(target_os = "windows"))]
{
cmd = Command::new("yarn")
}
#[cfg(not(target_os = "windows"))]
{
cmd = Command::new("yarn")
}

cmd
.args(&["list", "--pattern"])
.arg(name)
.args(&["--depth", "0"])
.current_dir(app_dir)
.output()?
} else {
#[cfg(target_os = "windows")]
{
cmd = Command::new("cmd");
cmd.arg("/c").arg("npm");
cmd
.args(&["list", "--pattern"])
.arg(name)
.args(&["--depth", "0"])
.current_dir(app_dir)
.output()?
}
PackageManager::Npm => {
#[cfg(target_os = "windows")]
{
cmd = Command::new("cmd");
cmd.arg("/c").arg("npm");
}

#[cfg(not(target_os = "windows"))]
{
cmd = Command::new("npm")
}

#[cfg(not(target_os = "windows"))]
{
cmd = Command::new("npm")
cmd
.arg("list")
.arg(name)
.args(&["version", "--depth", "0"])
.current_dir(app_dir)
.output()?
}
PackageManager::Pnpm => {
#[cfg(target_os = "windows")]
{
cmd = Command::new("cmd");
cmd.arg("/c").arg("pnpm");
}

#[cfg(not(target_os = "windows"))]
{
cmd = Command::new("pnpm")
}

cmd
.arg("list")
.arg(name)
.args(&["version", "--depth", "0"])
.current_dir(app_dir)
.output()?
cmd
.arg("list")
.arg(name)
.args(&["--parseable", "--depth", "0"])
.current_dir(app_dir)
.output()?
}
};
if output.status.success() {
let stdout = String::from_utf8_lossy(&output.stdout);
Expand Down Expand Up @@ -360,9 +411,22 @@ impl Info {
let app_dir = panic::catch_unwind(app_dir).map(Some).unwrap_or_default();
panic::set_hook(hook);

let use_yarn = app_dir
.map(|dir| dir.join("yarn.lock").exists())
.unwrap_or_default();
let mut package_manager = PackageManager::Npm;
if let Some(app_dir) = &app_dir {
let file_names = read_dir(app_dir)
.unwrap()
.filter(|e| {
e.as_ref()
.unwrap()
.metadata()
.unwrap()
.file_type()
.is_file()
})
.map(|e| e.unwrap().file_name().to_string_lossy().into_owned())
.collect::<Vec<String>>();
package_manager = get_package_manager(&file_names)?;
}

if let Some(node_version) = get_version("node", &[]).unwrap_or_default() {
InfoBlock::new("Node.js environment").section().display();
Expand All @@ -375,20 +439,21 @@ impl Info {
.display();

VersionBlock::new(" @tauri-apps/cli", metadata.js_cli.version)
.target_version(npm_latest_version(use_yarn, "@tauri-apps/cli").unwrap_or_default())
.target_version(npm_latest_version(&package_manager, "@tauri-apps/cli").unwrap_or_default())
.display();
if let Some(app_dir) = &app_dir {
VersionBlock::new(
" @tauri-apps/api",
npm_package_version(use_yarn, "@tauri-apps/api", app_dir).unwrap_or_default(),
npm_package_version(&package_manager, "@tauri-apps/api", app_dir).unwrap_or_default(),
)
.target_version(npm_latest_version(use_yarn, "@tauri-apps/api").unwrap_or_default())
.target_version(npm_latest_version(&package_manager, "@tauri-apps/api").unwrap_or_default())
.display();
}

InfoBlock::new("Global packages").section().display();

VersionBlock::new(" npm", get_version("npm", &[]).unwrap_or_default()).display();
VersionBlock::new(" pnpm", get_version("pnpm", &[]).unwrap_or_default()).display();
VersionBlock::new(" yarn", get_version("yarn", &[]).unwrap_or_default()).display();
}

Expand Down Expand Up @@ -576,3 +641,118 @@ impl Info {
Ok(())
}
}

fn get_package_manager<T: AsRef<str>>(file_names: &[T]) -> crate::Result<PackageManager> {
let mut use_npm = false;
let mut use_pnpm = false;
let mut use_yarn = false;

for name in file_names {
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!(
"only one package mangager should be used, but found {}\nplease remove unused package manager lock files",
found.join(" and ")
));
}

if use_npm {
Ok(PackageManager::Npm)
} else if use_pnpm {
Ok(PackageManager::Pnpm)
} else {
Ok(PackageManager::Yarn)
}
}

#[cfg(test)]
mod tests {
use crate::info::get_package_manager;

#[test]
fn no_package_manager_lock_file() -> crate::Result<()> {
let file_names = vec!["package.json"];
let pm = get_package_manager(&file_names);
match pm {
Ok(_) => Ok(()),
Err(m) => Err(m),
}
}

#[test]
fn package_managers_npm_and_yarn() -> crate::Result<()> {
let file_names = vec!["package.json", "package-lock.json", "yarn.lock"];
let pm = get_package_manager(&file_names);
match pm {
Ok(_) => panic!("expected error"),
Err(m) => assert_eq!(
m.to_string().as_str(),
"only one package mangager should be used, but found npm and yarn\nplease remove unused package manager lock files"
),
}
Ok(())
}

#[test]
fn package_managers_npm_and_pnpm() -> crate::Result<()> {
let file_names = vec!["package.json", "package-lock.json", "pnpm-lock.yaml"];
let pm = get_package_manager(&file_names);
match pm {
Ok(_) => panic!("expected error"),
Err(m) => assert_eq!(
m.to_string().as_str(),
"only one package mangager should be used, but found npm and pnpm\nplease remove unused package manager lock files"
),
}
Ok(())
}

#[test]
fn package_managers_pnpm_and_yarn() -> crate::Result<()> {
let file_names = vec!["package.json", "pnpm-lock.yaml", "yarn.lock"];
let pm = get_package_manager(&file_names);
match pm {
Ok(_) => panic!("expected error"),
Err(m) => assert_eq!(
m.to_string().as_str(),
"only one package mangager should be used, but found pnpm and yarn\nplease remove unused package manager lock files"
),
}
Ok(())
}

#[test]
fn package_managers_yarn() -> crate::Result<()> {
let file_names = vec!["package.json", "yarn.lock"];
let pm = get_package_manager(&file_names);
match pm {
Ok(_) => Ok(()),
Err(m) => Err(m),
}
}
}

0 comments on commit 2026134

Please sign in to comment.