cargo-crates.ts 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  1. import { spawnSync } from './../../helpers/spawn'
  2. import { CargoManifest, CargoManifestDependency, CargoLock } from './../../types/cargo'
  3. import { ManagementType, Result } from './types'
  4. import { getCrateLatestVersion, semverLt } from './util'
  5. import logger from '../../helpers/logger'
  6. import { resolve as appResolve, tauriDir } from '../../helpers/app-paths'
  7. import { readFileSync, writeFileSync, existsSync } from 'fs'
  8. import toml from '@tauri-apps/toml'
  9. import inquirer from 'inquirer'
  10. const log = logger('dependency:crates')
  11. const dependencies = ['tauri']
  12. function readToml<T>(tomlPath: string): T | null {
  13. if (existsSync(tomlPath)) {
  14. const manifest = readFileSync(tomlPath).toString()
  15. return toml.parse(manifest) as any as T
  16. }
  17. return null
  18. }
  19. function dependencyDefinition(version: string): CargoManifestDependency {
  20. return { version: version.substring(0, version.lastIndexOf('.')) }
  21. }
  22. async function manageDependencies(managementType: ManagementType): Promise<Result> {
  23. const installedDeps = []
  24. const updatedDeps = []
  25. const result: Result = new Map<ManagementType, string[]>()
  26. const manifest = readToml<CargoManifest>(appResolve.tauri('Cargo.toml'))
  27. if (manifest === null) {
  28. log('Cargo.toml not found. Skipping crates check...')
  29. return result
  30. }
  31. const lockPath = appResolve.tauri('Cargo.lock')
  32. if (!existsSync(lockPath)) {
  33. spawnSync('cargo', ['generate-lockfile'], tauriDir)
  34. }
  35. const lock = readToml<CargoLock>(lockPath)
  36. for (const dependency of dependencies) {
  37. const lockPackages = lock ? lock.package.filter(pkg => pkg.name === dependency) : []
  38. // eslint-disable-next-line security/detect-object-injection
  39. const manifestDep = manifest.dependencies[dependency]
  40. const currentVersion = lockPackages.length === 1
  41. ? lockPackages[0].version
  42. : (typeof manifestDep === 'string' ? manifestDep : manifestDep?.version)
  43. if (currentVersion === undefined) {
  44. log(`Installing ${dependency}...`)
  45. const latestVersion = await getCrateLatestVersion(dependency)
  46. // eslint-disable-next-line security/detect-object-injection
  47. manifest.dependencies[dependency] = dependencyDefinition(latestVersion)
  48. installedDeps.push(dependency)
  49. } else if (managementType === ManagementType.Update) {
  50. const latestVersion = await getCrateLatestVersion(dependency)
  51. if (semverLt(currentVersion, latestVersion)) {
  52. const inquired = await inquirer.prompt([{
  53. type: 'confirm',
  54. name: 'answer',
  55. message: `[CRATES] "${dependency}" latest version is ${latestVersion}. Do you want to update?`,
  56. default: false
  57. }])
  58. if (inquired.answer) {
  59. log(`Updating ${dependency}...`)
  60. // eslint-disable-next-line security/detect-object-injection
  61. manifest.dependencies[dependency] = dependencyDefinition(latestVersion)
  62. updatedDeps.push(dependency)
  63. }
  64. } else {
  65. log(`"${dependency}" is up to date`)
  66. }
  67. } else {
  68. log(`"${dependency}" is already installed`)
  69. }
  70. }
  71. if (installedDeps.length || updatedDeps.length) {
  72. writeFileSync(appResolve.tauri('Cargo.toml'), toml.stringify(manifest as any))
  73. }
  74. if (updatedDeps.length) {
  75. if (!existsSync(appResolve.tauri('Cargo.lock'))) {
  76. spawnSync('cargo', ['generate-lockfile'], tauriDir)
  77. }
  78. spawnSync('cargo', ['update', ...updatedDeps.reduce<string[]>((initialValue, dep) => [...initialValue, '-p', dep], [])], tauriDir)
  79. }
  80. result.set(ManagementType.Install, installedDeps)
  81. result.set(ManagementType.Update, updatedDeps)
  82. return result
  83. }
  84. async function install(): Promise<Result> {
  85. return await manageDependencies(ManagementType.Install)
  86. }
  87. async function update(): Promise<Result> {
  88. return await manageDependencies(ManagementType.Update)
  89. }
  90. export {
  91. install,
  92. update
  93. }