download-binary.ts 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. import { promisify } from 'util'
  2. import stream from 'stream'
  3. import fs from 'fs'
  4. import { CargoManifest } from '../types/cargo'
  5. import path from 'path'
  6. import { bootstrap } from 'global-agent'
  7. import { fileURLToPath } from 'url'
  8. import { createRequire } from 'module'
  9. // Webpack reads the file at build-time, so this becomes a static var
  10. // @ts-expect-error
  11. import manifest from '../../../cli.rs/Cargo.toml'
  12. const tauriCliManifest = manifest as CargoManifest
  13. const currentDirName = path.dirname(fileURLToPath(import.meta.url))
  14. const require = createRequire(import.meta.url)
  15. /* eslint-disable @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-var-requires */
  16. const got = require('got')
  17. /* eslint-enable @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-var-requires */
  18. // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
  19. const pipeline = promisify(stream.pipeline)
  20. const downloads: { [url: string]: boolean } = {}
  21. async function downloadBinaryRelease(
  22. tag: string,
  23. asset: string,
  24. outPath: string
  25. ): Promise<void> {
  26. const url = `https://github.com/tauri-apps/binary-releases/releases/download/${tag}/${asset}`
  27. const removeDownloadedCliIfNeeded = (): void => {
  28. try {
  29. if (!(url in downloads)) {
  30. // eslint-disable-next-line security/detect-non-literal-fs-filename
  31. fs.unlinkSync(outPath)
  32. }
  33. } finally {
  34. process.exit()
  35. }
  36. }
  37. // on exit, we remove the `tauri-cli` file if the download didn't complete
  38. process.on('exit', removeDownloadedCliIfNeeded)
  39. process.on('SIGINT', removeDownloadedCliIfNeeded)
  40. process.on('SIGTERM', removeDownloadedCliIfNeeded)
  41. process.on('SIGHUP', removeDownloadedCliIfNeeded)
  42. process.on('SIGBREAK', removeDownloadedCliIfNeeded)
  43. bootstrap({
  44. environmentVariableNamespace: ''
  45. })
  46. // TODO: Check hash of download
  47. // eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access, security/detect-non-literal-fs-filename
  48. await pipeline(got.stream(url), fs.createWriteStream(outPath)).catch(
  49. (e: unknown) => {
  50. try {
  51. // eslint-disable-next-line security/detect-non-literal-fs-filename
  52. fs.unlinkSync(outPath)
  53. } catch {}
  54. throw e
  55. }
  56. )
  57. // eslint-disable-next-line security/detect-object-injection
  58. downloads[url] = true
  59. // eslint-disable-next-line security/detect-non-literal-fs-filename
  60. fs.chmodSync(outPath, 0o700)
  61. console.log('Download Complete')
  62. }
  63. async function downloadCli(): Promise<void> {
  64. const version = tauriCliManifest.package.version
  65. let platform: string = process.platform
  66. if (platform === 'win32') {
  67. platform = 'windows'
  68. } else if (platform === 'linux') {
  69. platform = 'linux'
  70. } else if (platform === 'darwin') {
  71. platform = 'macos'
  72. } else {
  73. throw Error('Unsupported platform')
  74. }
  75. const extension = platform === 'windows' ? '.exe' : ''
  76. const outPath = path.join(currentDirName, `../../bin/tauri-cli${extension}`)
  77. console.log('Downloading Rust CLI...')
  78. await downloadBinaryRelease(
  79. `tauri-cli-v${version}`,
  80. `tauri-cli_${platform}${extension}`,
  81. outPath
  82. )
  83. }
  84. async function downloadRustup(): Promise<void> {
  85. const assetName =
  86. process.platform === 'win32' ? 'rustup-init.exe' : 'rustup-init.sh'
  87. console.log('Downloading Rustup...')
  88. return await downloadBinaryRelease(
  89. 'rustup',
  90. assetName,
  91. path.join(currentDirName, `../../bin/${assetName}`)
  92. )
  93. }
  94. export { downloadCli, downloadRustup }