mirror of
https://github.com/tauri-apps/tauri.git
synced 2024-12-01 03:02:28 +03:00
feat(cli.js): package managers interface, add pnpm support (#1743)
Co-authored-by: Lucas Nogueira <lucas@tauri.studio>
This commit is contained in:
parent
bb8dafbe1e
commit
908b703246
5
.changes/pnpm-support.md
Normal file
5
.changes/pnpm-support.md
Normal file
@ -0,0 +1,5 @@
|
||||
---
|
||||
"cli.js": patch
|
||||
---
|
||||
|
||||
Adds `pnpm` support.
|
@ -0,0 +1,4 @@
|
||||
export * from './yarn-manager'
|
||||
export * from './npm-manager'
|
||||
export * from './pnpm-manager'
|
||||
export * from './types'
|
@ -0,0 +1,48 @@
|
||||
import { IManager } from './types'
|
||||
import { sync as crossSpawnSync } from 'cross-spawn'
|
||||
import { spawnSync } from '../../../helpers/spawn'
|
||||
import { appDir } from '../../../helpers/app-paths'
|
||||
|
||||
export class NpmManager implements IManager {
|
||||
type = 'npm'
|
||||
|
||||
installPackage(packageName: string): void {
|
||||
spawnSync('npm', ['install', packageName], appDir)
|
||||
}
|
||||
|
||||
installDevPackage(packageName: string): void {
|
||||
spawnSync('npm', ['install', packageName, '--save-dev'], appDir)
|
||||
}
|
||||
|
||||
updatePackage(packageName: string): void {
|
||||
spawnSync('npm', ['install', `${packageName}@latest`], appDir)
|
||||
}
|
||||
|
||||
getPackageVersion(packageName: string): string | null {
|
||||
const child = 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
|
||||
}
|
||||
}
|
||||
|
||||
getLatestVersion(packageName: string): string {
|
||||
const child = crossSpawnSync('npm', ['show', packageName, 'version'], {
|
||||
cwd: appDir
|
||||
})
|
||||
|
||||
return String(child.output[1]).replace('\n', '')
|
||||
}
|
||||
}
|
@ -0,0 +1,48 @@
|
||||
import { IManager } from './types'
|
||||
import { sync as crossSpawnSync } from 'cross-spawn'
|
||||
import { spawnSync } from '../../../helpers/spawn'
|
||||
import { appDir } from '../../../helpers/app-paths'
|
||||
|
||||
export class PnpmManager implements IManager {
|
||||
type = 'pnpm'
|
||||
|
||||
installPackage(packageName: string): void {
|
||||
spawnSync('pnpm', ['add', packageName], appDir)
|
||||
}
|
||||
|
||||
installDevPackage(packageName: string): void {
|
||||
spawnSync('pnpm', ['add', packageName, '--save-dev'], appDir)
|
||||
}
|
||||
|
||||
updatePackage(packageName: string): void {
|
||||
spawnSync('pnpm', ['add', `${packageName}@latest`], appDir)
|
||||
}
|
||||
|
||||
getPackageVersion(packageName: string): string | null {
|
||||
const child = crossSpawnSync(
|
||||
'pnpm',
|
||||
['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
|
||||
}
|
||||
}
|
||||
|
||||
getLatestVersion(packageName: string): string {
|
||||
const child = crossSpawnSync('pnpm', ['info', packageName, 'version'], {
|
||||
cwd: appDir
|
||||
})
|
||||
|
||||
return String(child.output[1]).replace('\n', '')
|
||||
}
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
export interface IManager {
|
||||
type: string
|
||||
installPackage: (packageName: string) => void
|
||||
installDevPackage: (packageName: string) => void
|
||||
updatePackage: (packageName: string) => void
|
||||
getPackageVersion: (packageName: string) => string | null
|
||||
getLatestVersion: (packageName: string) => string
|
||||
}
|
@ -0,0 +1,48 @@
|
||||
import { IManager } from './types'
|
||||
import { sync as crossSpawnSync } from 'cross-spawn'
|
||||
import { spawnSync } from '../../../helpers/spawn'
|
||||
import { appDir } from '../../../helpers/app-paths'
|
||||
|
||||
export class YarnManager implements IManager {
|
||||
type = 'yarn'
|
||||
|
||||
installPackage(packageName: string): void {
|
||||
spawnSync('yarn', ['add', packageName], appDir)
|
||||
}
|
||||
|
||||
installDevPackage(packageName: string): void {
|
||||
spawnSync('yarn', ['add', packageName, '--dev'], appDir)
|
||||
}
|
||||
|
||||
updatePackage(packageName: string): void {
|
||||
spawnSync('yarn', ['upgrade', packageName, '--latest'], appDir)
|
||||
}
|
||||
|
||||
getPackageVersion(packageName: string): string | null {
|
||||
const child = crossSpawnSync(
|
||||
'yarn',
|
||||
['list', '--pattern', packageName, '--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
|
||||
}
|
||||
}
|
||||
|
||||
getLatestVersion(packageName: string): string {
|
||||
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]
|
||||
}
|
||||
}
|
@ -2,7 +2,7 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
import { ManagementType, Result } from './types'
|
||||
import { Answer, ManagementType, Result } from './types'
|
||||
import {
|
||||
getNpmLatestVersion,
|
||||
getNpmPackageVersion,
|
||||
@ -10,7 +10,7 @@ import {
|
||||
installNpmDevPackage,
|
||||
updateNpmPackage,
|
||||
semverLt,
|
||||
useYarn
|
||||
getManager
|
||||
} from './util'
|
||||
import logger from '../../helpers/logger'
|
||||
import { resolve } from '../../helpers/app-paths'
|
||||
@ -29,37 +29,42 @@ async function manageDependencies(
|
||||
|
||||
const npmChild = crossSpawnSync('npm', ['--version'])
|
||||
const yarnChild = crossSpawnSync('yarn', ['--version'])
|
||||
const pnpmChild = crossSpawnSync('pnpm', ['--version'])
|
||||
if (
|
||||
(npmChild.status ?? npmChild.error) &&
|
||||
(yarnChild.status ?? yarnChild.error)
|
||||
(yarnChild.status ?? yarnChild.error) &&
|
||||
(pnpmChild.status ?? pnpmChild.error)
|
||||
) {
|
||||
throw new Error(
|
||||
'must have `npm` or `yarn` installed to manage dependenices'
|
||||
'must have installed one of the following package managers `npm`, `yarn`, `pnpm` to manage dependenices'
|
||||
)
|
||||
}
|
||||
|
||||
if (existsSync(resolve.app('package.json'))) {
|
||||
for (const dependency of dependencies) {
|
||||
const currentVersion = getNpmPackageVersion(dependency)
|
||||
const packageManager = getManager().type.toUpperCase()
|
||||
|
||||
if (currentVersion === null) {
|
||||
log(`Installing ${dependency}...`)
|
||||
if (
|
||||
managementType === ManagementType.Install ||
|
||||
managementType === ManagementType.InstallDev
|
||||
) {
|
||||
const packageManager = useYarn() ? 'YARN' : 'NPM'
|
||||
const inquired = (await inquirer.prompt([
|
||||
const prefix =
|
||||
managementType === ManagementType.InstallDev
|
||||
? ' as dev-dependency'
|
||||
: ''
|
||||
|
||||
const inquired = await inquirer.prompt<Answer>([
|
||||
{
|
||||
type: 'confirm',
|
||||
name: 'answer',
|
||||
message: `[${packageManager}]: "Do you want to install ${dependency} ${
|
||||
managementType === ManagementType.InstallDev
|
||||
? 'as dev-dependency'
|
||||
: ''
|
||||
}?"`,
|
||||
message: `[${packageManager}]: "Do you want to install ${dependency}${prefix}?"`,
|
||||
default: false
|
||||
}
|
||||
])) as { answer: boolean }
|
||||
])
|
||||
|
||||
if (inquired.answer) {
|
||||
if (managementType === ManagementType.Install) {
|
||||
installNpmPackage(dependency)
|
||||
@ -71,15 +76,17 @@ async function manageDependencies(
|
||||
}
|
||||
} else if (managementType === ManagementType.Update) {
|
||||
const latestVersion = getNpmLatestVersion(dependency)
|
||||
|
||||
if (semverLt(currentVersion, latestVersion)) {
|
||||
const inquired = (await inquirer.prompt([
|
||||
const inquired = await inquirer.prompt<Answer>([
|
||||
{
|
||||
type: 'confirm',
|
||||
name: 'answer',
|
||||
message: `[NPM]: "${dependency}" latest version is ${latestVersion}. Do you want to update?`,
|
||||
message: `[${packageManager}]: "${dependency}" latest version is ${latestVersion}. Do you want to update?`,
|
||||
default: false
|
||||
}
|
||||
])) as { answer: boolean }
|
||||
])
|
||||
|
||||
if (inquired.answer) {
|
||||
log(`Updating ${dependency}...`)
|
||||
updateNpmPackage(dependency)
|
||||
|
@ -9,3 +9,7 @@ export enum ManagementType {
|
||||
}
|
||||
|
||||
export type Result = Map<ManagementType, string[]>
|
||||
|
||||
export interface Answer {
|
||||
answer: boolean
|
||||
}
|
||||
|
@ -2,16 +2,21 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
import { spawnSync } from '../../helpers/spawn'
|
||||
import { sync as crossSpawnSync } from 'cross-spawn'
|
||||
import { appDir, resolve as appResolve } from '../../helpers/app-paths'
|
||||
import { resolve as appResolve } from '../../helpers/app-paths'
|
||||
import { existsSync } from 'fs'
|
||||
import semver from 'semver'
|
||||
import { IManager, NpmManager, YarnManager, PnpmManager } from './managers'
|
||||
|
||||
const useYarn = (): boolean =>
|
||||
process.env.npm_execpath
|
||||
? process.env.npm_execpath.includes('yarn')
|
||||
: existsSync(appResolve.app('yarn.lock'))
|
||||
const getManager = (): IManager => {
|
||||
if (existsSync(appResolve.app('yarn.lock'))) {
|
||||
return new YarnManager()
|
||||
} else if (existsSync(appResolve.app('pnpm-lock.yaml'))) {
|
||||
return new PnpmManager()
|
||||
} else {
|
||||
return new NpmManager()
|
||||
}
|
||||
}
|
||||
|
||||
function getCrateLatestVersion(crateName: string): string | null {
|
||||
const child = crossSpawnSync('cargo', ['search', crateName, '--limit', '1'])
|
||||
@ -26,69 +31,23 @@ function getCrateLatestVersion(crateName: string): string | null {
|
||||
}
|
||||
|
||||
function getNpmLatestVersion(packageName: string): string {
|
||||
if (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', '')
|
||||
}
|
||||
return getManager().getLatestVersion(packageName)
|
||||
}
|
||||
|
||||
function getNpmPackageVersion(packageName: string): string | null {
|
||||
const child = useYarn()
|
||||
? crossSpawnSync(
|
||||
'yarn',
|
||||
['list', '--pattern', 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
|
||||
}
|
||||
return getManager().getPackageVersion(packageName)
|
||||
}
|
||||
|
||||
function installNpmPackage(packageName: string): void {
|
||||
if (useYarn()) {
|
||||
spawnSync('yarn', ['add', packageName], appDir)
|
||||
} else {
|
||||
spawnSync('npm', ['install', packageName], appDir)
|
||||
}
|
||||
return getManager().installPackage(packageName)
|
||||
}
|
||||
|
||||
function installNpmDevPackage(packageName: string): void {
|
||||
if (useYarn()) {
|
||||
spawnSync('yarn', ['add', packageName, '--dev'], appDir)
|
||||
} else {
|
||||
spawnSync('npm', ['install', packageName, '--save-dev'], appDir)
|
||||
}
|
||||
return getManager().installDevPackage(packageName)
|
||||
}
|
||||
|
||||
function updateNpmPackage(packageName: string): void {
|
||||
if (useYarn()) {
|
||||
spawnSync('yarn', ['upgrade', packageName, '--latest'], appDir)
|
||||
} else {
|
||||
spawnSync('npm', ['install', `${packageName}@latest`], appDir)
|
||||
}
|
||||
return getManager().updatePackage(packageName)
|
||||
}
|
||||
|
||||
function padVersion(version: string): string {
|
||||
@ -105,7 +64,7 @@ function semverLt(first: string, second: string): boolean {
|
||||
}
|
||||
|
||||
export {
|
||||
useYarn,
|
||||
getManager,
|
||||
getCrateLatestVersion,
|
||||
getNpmLatestVersion,
|
||||
getNpmPackageVersion,
|
||||
|
Loading…
Reference in New Issue
Block a user