瀏覽代碼

fix(tauri.js) `deps` cmd usage when `npm` is not installed, closes #1037 (#1053)

Lucas Fernandes Nogueira 4 年之前
父節點
當前提交
8da495f78c

+ 5 - 0
.changes/tauri-deps-yarn.md

@@ -0,0 +1,5 @@
+---
+"tauri.js": patch
+---
+
+Fixes `tauri deps` command usage when `npm` is not installed.

+ 0 - 5
.changes/updater-issue-without-npm

@@ -1,5 +0,0 @@
----
-"tauri.js": patch
----
-
-Fixes an issue with the dependency updater when NPM isn't installed.

+ 15 - 3
cli/tauri.js/src/api/dependency-manager/npm-packages.ts

@@ -11,6 +11,7 @@ import logger from '../../helpers/logger'
 import { resolve } from '../../helpers/app-paths'
 import inquirer from 'inquirer'
 import { existsSync } from 'fs'
+import { sync as crossSpawnSync } from 'cross-spawn'
 
 const log = logger('dependency:npm-packages')
 
@@ -21,19 +22,30 @@ async function manageDependencies(
   const installedDeps = []
   const updatedDeps = []
 
+  const npmChild = crossSpawnSync('npm', ['--version'])
+  const yarnChild = crossSpawnSync('yarn', ['--version'])
+  if (
+    (npmChild.status ?? npmChild.error) &&
+    (yarnChild.status ?? yarnChild.error)
+  ) {
+    throw new Error(
+      'must have `npm` or `yarn` installed to manage dependenices'
+    )
+  }
+
   if (existsSync(resolve.app('package.json'))) {
     for (const dependency of dependencies) {
       const currentVersion = await getNpmPackageVersion(dependency)
       if (currentVersion === null) {
         log(`Installing ${dependency}...`)
         if (managementType === ManagementType.Install) {
-          installNpmPackage(dependency)
+          await installNpmPackage(dependency)
         } else if (managementType === ManagementType.InstallDev) {
-          installNpmDevPackage(dependency)
+          await installNpmDevPackage(dependency)
         }
         installedDeps.push(dependency)
       } else if (managementType === ManagementType.Update) {
-        const latestVersion = getNpmLatestVersion(dependency)
+        const latestVersion = await getNpmLatestVersion(dependency)
         if (semverLt(currentVersion, latestVersion)) {
           // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-var-requires, @typescript-eslint/no-unsafe-member-access
           const inquired = await inquirer.prompt([

+ 53 - 32
cli/tauri.js/src/api/dependency-manager/util.ts

@@ -8,6 +8,18 @@ import semver from 'semver'
 
 const BASE_URL = 'https://docs.rs/crate/'
 
+async function useYarn(): Promise<boolean> {
+  const hasYarnLockfile = existsSync(appResolve.app('yarn.lock'))
+  if (hasYarnLockfile) {
+    return true
+  } else {
+    return await new Promise((resolve) => {
+      const child = crossSpawnSync('npm', ['--version'])
+      resolve(!!(child.status ?? child.error))
+    })
+  }
+}
+
 async function getCrateLatestVersion(crateName: string): Promise<string> {
   return await new Promise((resolve, reject) => {
     const url = `${BASE_URL}${crateName}`
@@ -22,51 +34,60 @@ async function getCrateLatestVersion(crateName: string): Promise<string> {
   })
 }
 
-function getNpmLatestVersion(packageName: string): string {
-  const usesYarn = existsSync(appResolve.app('yarn.lock'))
-  const cmd = usesYarn ? 'yarn' : 'npm'
-  const args = usesYarn
-    ? ['--silent', 'info', packageName, 'version']
-    : ['show', packageName, 'version']
-  const child = crossSpawnSync(cmd, args, {
-    cwd: appDir
-  })
-  return String(child.output[1]).replace('\n', '')
+async function getNpmLatestVersion(packageName: string): Promise<string> {
+  if (await useYarn()) {
+    const child = crossSpawnSync(
+      'yarn',
+      ['info', packageName, 'versions', '--json'],
+      {
+        cwd: appDir
+      }
+    )
+    const output = String(child.output[1])
+    const packageJson = JSON.parse(output) as { data: string[] }
+    return packageJson.data[packageJson.data.length - 1]
+  } else {
+    const child = crossSpawnSync('npm', ['show', packageName, 'version'], {
+      cwd: appDir
+    })
+    return String(child.output[1]).replace('\n', '')
+  }
 }
 
 async function getNpmPackageVersion(
   packageName: string
 ): Promise<string | null> {
-  const usesYarn = existsSync(appResolve.app('yarn.lock'))
-  const cmd = usesYarn ? 'yarn' : 'npm'
-  const args = usesYarn
-    ? ['--silent', 'list', packageName, 'version', '--depth', '0']
-    : ['list', packageName, 'version', '--depth', '0']
-  return await new Promise((resolve) => {
-    const child = crossSpawnSync(cmd, args, { cwd: appDir })
-    const output = String(child.output[1])
-    // eslint-disable-next-line security/detect-non-literal-regexp
-    const matches = new RegExp(packageName + '@(\\S+)', 'g').exec(output)
-    if (matches?.[1]) {
-      resolve(matches[1])
-    } else {
-      resolve(null)
-    }
-  })
+  const child = (await useYarn())
+    ? crossSpawnSync(
+        'yarn',
+        ['list', '--patern', packageName, '--depth', '0'],
+        {
+          cwd: appDir
+        }
+      )
+    : crossSpawnSync('npm', ['list', packageName, 'version', '--depth', '0'], {
+        cwd: appDir
+      })
+  const output = String(child.output[1])
+  // eslint-disable-next-line security/detect-non-literal-regexp
+  const matches = new RegExp(packageName + '@(\\S+)', 'g').exec(output)
+  if (matches?.[1]) {
+    return matches[1]
+  } else {
+    return null
+  }
 }
 
-function installNpmPackage(packageName: string): void {
-  const usesYarn = existsSync(appResolve.app('yarn.lock'))
-  if (usesYarn) {
+async function installNpmPackage(packageName: string): Promise<void> {
+  if (await useYarn()) {
     spawnSync('yarn', ['add', packageName], appDir)
   } else {
     spawnSync('npm', ['install', packageName], appDir)
   }
 }
 
-function installNpmDevPackage(packageName: string): void {
-  const usesYarn = existsSync(appResolve.app('yarn.lock'))
-  if (usesYarn) {
+async function installNpmDevPackage(packageName: string): Promise<void> {
+  if (await useYarn()) {
     spawnSync('yarn', ['add', packageName, '--dev'], appDir)
   } else {
     spawnSync('npm', ['install', packageName, '--save-dev'], appDir)

+ 1 - 1
cli/tauri.js/src/api/info.ts

@@ -265,7 +265,7 @@ module.exports = async () => {
   printVersion({
     key: '  tauri.js',
     version: packageJson.version,
-    targetVersion: getNpmLatestVersion('tauri')
+    targetVersion: await getNpmLatestVersion('tauri')
   })
 
   printInfo({ key: 'Rust environment', section: true })

+ 1 - 1
cli/tauri.js/yarn.lock

@@ -7732,7 +7732,7 @@ resolve@1.17.0, resolve@^1.10.0, resolve@^1.10.1, resolve@^1.13.1, resolve@^1.15
   dependencies:
     path-parse "^1.0.6"
 
-resolve@^1.19.0:
+resolve@^1.18.1, resolve@^1.19.0:
   version "1.19.0"
   resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.19.0.tgz#1af5bf630409734a067cae29318aac7fa29a267c"
   integrity sha512-rArEXAgsBG4UgRGcynxWIWKFvh/XZCcS8UJdHhwy91zwAvCZIbcs+vAbflgBnNjYMs/i/i+/Ux6IZhML1yPvxg==