浏览代码

fix(cli): properly read info when using yarn 2+, closes #4106 (#4193)

Lucas Fernandes Nogueira 3 年之前
父节点
当前提交
cdfa625511
共有 4 个文件被更改,包括 93 次插入49 次删除
  1. 6 0
      .changes/fix-berry-info-cli.md
  2. 77 40
      tooling/cli/src/info.rs
  3. 1 8
      tooling/cli/src/init.rs
  4. 9 1
      tooling/cli/src/lib.rs

+ 6 - 0
.changes/fix-berry-info-cli.md

@@ -0,0 +1,6 @@
+---
+"cli.rs": patch
+"cli.js": patch
+---
+
+Properly fetch the NPM dependency information when using Yarn 2+.

+ 77 - 40
tooling/cli/src/info.rs

@@ -75,10 +75,12 @@ struct CargoManifest {
   dependencies: HashMap<String, CargoManifestDependency>,
 }
 
+#[derive(Debug, PartialEq, Eq)]
 enum PackageManager {
   Npm,
   Pnpm,
   Yarn,
+  Berry,
 }
 
 #[derive(Debug, Parser)]
@@ -165,6 +167,23 @@ fn npm_latest_version(pm: &PackageManager, name: &str) -> crate::Result<Option<S
         Ok(None)
       }
     }
+    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)
+      }
+    }
     PackageManager::Npm => {
       let mut cmd = cross_command("npm");
 
@@ -195,29 +214,46 @@ fn npm_package_version<P: AsRef<Path>>(
   name: &str,
   app_dir: P,
 ) -> crate::Result<Option<String>> {
-  let output = match pm {
-    PackageManager::Yarn => cross_command("yarn")
-      .args(&["list", "--pattern"])
-      .arg(name)
-      .args(&["--depth", "0"])
-      .current_dir(app_dir)
-      .output()?,
-    PackageManager::Npm => cross_command("npm")
-      .arg("list")
-      .arg(name)
-      .args(&["version", "--depth", "0"])
-      .current_dir(app_dir)
-      .output()?,
-    PackageManager::Pnpm => cross_command("pnpm")
-      .arg("list")
-      .arg(name)
-      .args(&["--parseable", "--depth", "0"])
-      .current_dir(app_dir)
-      .output()?,
+  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,
+    ),
   };
   if output.status.success() {
     let stdout = String::from_utf8_lossy(&output.stdout);
-    let regex = regex::Regex::new("@([\\da-zA-Z\\-\\.]+)").unwrap();
+    let regex = regex.unwrap_or_else(|| regex::Regex::new("@([\\da-zA-Z\\-\\.]+)").unwrap());
     Ok(
       regex
         .captures_iter(&stdout)
@@ -530,7 +566,7 @@ impl VersionBlock {
       let target_version = semver::Version::parse(self.target_version.as_str()).unwrap();
       if version < target_version {
         print!(
-          "({}, latest: {})",
+          " ({}, latest: {})",
           "outdated".red(),
           self.target_version.green()
         );
@@ -613,6 +649,10 @@ pub fn command(_options: Options) -> Result<()> {
     .unwrap_or_default();
   panic::set_hook(hook);
 
+  let yarn_version = get_version("yarn", &[])
+    .unwrap_or_default()
+    .unwrap_or_default();
+
   let metadata = version_metadata()?;
   VersionBlock::new(
     "Node.js",
@@ -640,13 +680,7 @@ pub fn command(_options: Options) -> Result<()> {
       .unwrap_or_default(),
   )
   .display();
-  VersionBlock::new(
-    "yarn",
-    get_version("yarn", &[])
-      .unwrap_or_default()
-      .unwrap_or_default(),
-  )
-  .display();
+  VersionBlock::new("yarn", &yarn_version).display();
   VersionBlock::new(
     "rustup",
     get_version("rustup", &[])
@@ -695,20 +729,23 @@ pub fn command(_options: Options) -> Result<()> {
 
   let mut package_manager = PackageManager::Npm;
   if let Some(app_dir) = &app_dir {
-    let file_names = read_dir(app_dir)
+    let app_dir_entries = 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)?;
+    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;
   }
+
   VersionBlock::new(
     format!("{} {}", "@tauri-apps/cli", "[NPM]".dimmed()),
     metadata.js_cli.version,
@@ -852,12 +889,12 @@ pub fn command(_options: Options) -> Result<()> {
   Ok(())
 }
 
-fn get_package_manager<T: AsRef<str>>(file_names: &[T]) -> crate::Result<PackageManager> {
+fn get_package_manager<T: AsRef<str>>(app_dir_entries: &[T]) -> crate::Result<PackageManager> {
   let mut use_npm = false;
   let mut use_pnpm = false;
   let mut use_yarn = false;
 
-  for name in file_names {
+  for name in app_dir_entries {
     if name.as_ref() == "package-lock.json" {
       use_npm = true;
     } else if name.as_ref() == "pnpm-lock.yaml" {

+ 1 - 8
tooling/cli/src/init.rs

@@ -25,7 +25,6 @@ use dialoguer::Input;
 use handlebars::{to_json, Handlebars};
 use include_dir::{include_dir, Dir};
 use log::warn;
-use serde::Deserialize;
 
 const TEMPLATE_DIR: Dir<'_> = include_dir!("templates/app");
 const TAURI_CONF_TEMPLATE: &str = include_str!("../templates/tauri.conf.json");
@@ -63,12 +62,6 @@ pub struct Options {
   dev_path: Option<String>,
 }
 
-#[derive(Deserialize)]
-struct PackageJson {
-  name: Option<String>,
-  product_name: Option<String>,
-}
-
 #[derive(Default)]
 struct InitDefaults {
   app_name: Option<String>,
@@ -82,7 +75,7 @@ impl Options {
 
     let init_defaults = if package_json_path.exists() {
       let package_json_text = read_to_string(package_json_path)?;
-      let package_json: PackageJson = serde_json::from_str(&package_json_text)?;
+      let package_json: crate::PackageJson = serde_json::from_str(&package_json_text)?;
       let (framework, _) = infer_framework(&package_json_text);
       InitDefaults {
         app_name: package_json.product_name.or(package_json.name),

+ 9 - 1
tooling/cli/src/lib.rs

@@ -17,17 +17,25 @@ use clap::{FromArgMatches, IntoApp, Parser, Subcommand};
 use env_logger::fmt::Color;
 use env_logger::Builder;
 use log::{debug, log_enabled, Level};
+use serde::Deserialize;
 use std::ffi::OsString;
 use std::io::Write;
 use std::process::{Command, Output};
 
-#[derive(serde::Deserialize)]
+#[derive(Deserialize)]
 pub struct VersionMetadata {
   tauri: String,
   #[serde(rename = "tauri-build")]
   tauri_build: String,
 }
 
+#[derive(Deserialize)]
+pub struct PackageJson {
+  name: Option<String>,
+  version: Option<String>,
+  product_name: Option<String>,
+}
+
 #[derive(Parser)]
 #[clap(
   author,