Просмотр исходного кода

refactor(cli.js): download rustup binary (#1711)

Lucas Fernandes Nogueira 4 лет назад
Родитель
Сommit
862e33a0f6

+ 5 - 0
.changes/cli.js-rustup.md

@@ -0,0 +1,5 @@
+---
+"cli.js": patch
+---
+
+Download `rustup` script on runtime instead of shipping it.

+ 3 - 1
tooling/cli.js/.gitignore

@@ -2,9 +2,11 @@
 /dist
 target/
 
-# Prebuilt rust CLI
+# Downloaded binaries
 bin/tauri-cli
 bin/tauri-cli.exe
+bin/rustup-init.sh
+bin/rustup-init.exe
 
 # Logs
 logs

+ 0 - 1
tooling/cli.js/scripts/is-admin.ps1

@@ -1 +0,0 @@
-[bool](([System.Security.Principal.WindowsIdentity]::GetCurrent()).groups -match "S-1-5-32-544");

BIN
tooling/cli.js/scripts/rustup-init.exe


+ 0 - 557
tooling/cli.js/scripts/rustup-init.sh

@@ -1,557 +0,0 @@
-#!/bin/sh
-# Copyright 2019-2021 Tauri Programme within The Commons Conservancy
-# SPDX-License-Identifier: Apache-2.0
-# SPDX-License-Identifier: MIT
-
-# shellcheck shell=dash
-
-# This is just a little script that can be downloaded from the internet to
-# install rustup. It just does platform detection, downloads the installer
-# and runs it.
-
-# It runs on Unix shells like {a,ba,da,k,z}sh. It uses the common `local`
-# extension. Note: Most shells limit `local` to 1 var per line, contra bash.
-
-set -u
-
-# If RUSTUP_UPDATE_ROOT is unset or empty, default it.
-RUSTUP_UPDATE_ROOT="${RUSTUP_UPDATE_ROOT:-https://static.rust-lang.org/rustup}"
-
-#XXX: If you change anything here, please make the same changes in setup_mode.rs
-usage() {
-    cat 1>&2 <<EOF
-rustup-init 1.22.1 (76644d669 2020-07-08)
-The installer for rustup
-
-USAGE:
-    rustup-init [FLAGS] [OPTIONS]
-
-FLAGS:
-    -v, --verbose           Enable verbose output
-    -q, --quiet             Disable progress output
-    -y                      Disable confirmation prompt.
-        --no-modify-path    Don't configure the PATH environment variable
-    -h, --help              Prints help information
-    -V, --version           Prints version information
-
-OPTIONS:
-        --default-host <default-host>              Choose a default host triple
-        --default-toolchain <default-toolchain>    Choose a default toolchain to install
-        --default-toolchain none                   Do not install any toolchains
-        --profile [minimal|default|complete]       Choose a profile
-    -c, --component <components>...                Component name to also install
-    -t, --target <targets>...                      Target name to also install
-EOF
-}
-
-main() {
-    downloader --check
-    need_cmd uname
-    need_cmd mktemp
-    need_cmd chmod
-    need_cmd mkdir
-    need_cmd rm
-    need_cmd rmdir
-
-    get_architecture || return 1
-    local _arch="$RETVAL"
-    assert_nz "$_arch" "arch"
-
-    local _ext=""
-    case "$_arch" in
-        *windows*)
-            _ext=".exe"
-            ;;
-    esac
-
-    local _url="${RUSTUP_UPDATE_ROOT}/dist/${_arch}/rustup-init${_ext}"
-
-    local _dir
-    _dir="$(mktemp -d 2>/dev/null || ensure mktemp -d -t rustup)"
-    local _file="${_dir}/rustup-init${_ext}"
-
-    local _ansi_escapes_are_valid=false
-    if [ -t 2 ]; then
-        if [ "${TERM+set}" = 'set' ]; then
-            case "$TERM" in
-                xterm*|rxvt*|urxvt*|linux*|vt*)
-                    _ansi_escapes_are_valid=true
-                ;;
-            esac
-        fi
-    fi
-
-    # check if we have to use /dev/tty to prompt the user
-    local need_tty=yes
-    for arg in "$@"; do
-        case "$arg" in
-            -h|--help)
-                usage
-                exit 0
-                ;;
-            -y)
-                # user wants to skip the prompt -- we don't need /dev/tty
-                need_tty=no
-                ;;
-            *)
-                ;;
-        esac
-    done
-
-    if $_ansi_escapes_are_valid; then
-        printf "\33[1minfo:\33[0m downloading installer\n" 1>&2
-    else
-        printf '%s\n' 'info: downloading installer' 1>&2
-    fi
-
-    ensure mkdir -p "$_dir"
-    ensure downloader "$_url" "$_file" "$_arch"
-    ensure chmod u+x "$_file"
-    if [ ! -x "$_file" ]; then
-        printf '%s\n' "Cannot execute $_file (likely because of mounting /tmp as noexec)." 1>&2
-        printf '%s\n' "Please copy the file to a location where you can execute binaries and run ./rustup-init${_ext}." 1>&2
-        exit 1
-    fi
-
-    if [ "$need_tty" = "yes" ]; then
-        # The installer is going to want to ask for confirmation by
-        # reading stdin.  This script was piped into `sh` though and
-        # doesn't have stdin to pass to its children. Instead we're going
-        # to explicitly connect /dev/tty to the installer's stdin.
-        if [ ! -t 1 ]; then
-            err "Unable to run interactively. Run with -y to accept defaults, --help for additional options"
-        fi
-
-        ignore "$_file" "$@" < /dev/tty
-    else
-        ignore "$_file" "$@"
-    fi
-
-    local _retval=$?
-
-    ignore rm "$_file"
-    ignore rmdir "$_dir"
-
-    return "$_retval"
-}
-
-get_bitness() {
-    need_cmd head
-    # Architecture detection without dependencies beyond coreutils.
-    # ELF files start out "\x7fELF", and the following byte is
-    #   0x01 for 32-bit and
-    #   0x02 for 64-bit.
-    # The printf builtin on some shells like dash only supports octal
-    # escape sequences, so we use those.
-    local _current_exe_head
-    _current_exe_head=$(head -c 5 /proc/self/exe )
-    if [ "$_current_exe_head" = "$(printf '\177ELF\001')" ]; then
-        echo 32
-    elif [ "$_current_exe_head" = "$(printf '\177ELF\002')" ]; then
-        echo 64
-    else
-        err "unknown platform bitness"
-    fi
-}
-
-get_endianness() {
-    local cputype=$1
-    local suffix_eb=$2
-    local suffix_el=$3
-
-    # detect endianness without od/hexdump, like get_bitness() does.
-    need_cmd head
-    need_cmd tail
-
-    local _current_exe_endianness
-    _current_exe_endianness="$(head -c 6 /proc/self/exe | tail -c 1)"
-    if [ "$_current_exe_endianness" = "$(printf '\001')" ]; then
-        echo "${cputype}${suffix_el}"
-    elif [ "$_current_exe_endianness" = "$(printf '\002')" ]; then
-        echo "${cputype}${suffix_eb}"
-    else
-        err "unknown platform endianness"
-    fi
-}
-
-get_architecture() {
-    local _ostype _cputype _bitness _arch _clibtype
-    _ostype="$(uname -s)"
-    _cputype="$(uname -m)"
-    _clibtype="gnu"
-
-    if [ "$_ostype" = Linux ]; then
-        if [ "$(uname -o)" = Android ]; then
-            _ostype=Android
-        fi
-        if ldd --version 2>&1 | grep -q 'musl'; then
-            _clibtype="musl"
-        fi
-    fi
-
-    if [ "$_ostype" = Darwin ] && [ "$_cputype" = i386 ]; then
-        # Darwin `uname -m` lies
-        if sysctl hw.optional.x86_64 | grep -q ': 1'; then
-            _cputype=x86_64
-        fi
-    fi
-
-    case "$_ostype" in
-
-        Android)
-            _ostype=linux-android
-            ;;
-
-        Linux)
-            _ostype=unknown-linux-$_clibtype
-            _bitness=$(get_bitness)
-            ;;
-
-        FreeBSD)
-            _ostype=unknown-freebsd
-            ;;
-
-        NetBSD)
-            _ostype=unknown-netbsd
-            ;;
-
-        DragonFly)
-            _ostype=unknown-dragonfly
-            ;;
-
-        Darwin)
-            _ostype=apple-darwin
-            ;;
-
-        MINGW* | MSYS* | CYGWIN*)
-            _ostype=pc-windows-gnu
-            ;;
-
-        *)
-            err "unrecognized OS type: $_ostype"
-            ;;
-
-    esac
-
-    case "$_cputype" in
-
-        i386 | i486 | i686 | i786 | x86)
-            _cputype=i686
-            ;;
-
-        xscale | arm)
-            _cputype=arm
-            if [ "$_ostype" = "linux-android" ]; then
-                _ostype=linux-androideabi
-            fi
-            ;;
-
-        armv6l)
-            _cputype=arm
-            if [ "$_ostype" = "linux-android" ]; then
-                _ostype=linux-androideabi
-            else
-                _ostype="${_ostype}eabihf"
-            fi
-            ;;
-
-        armv7l | armv8l)
-            _cputype=armv7
-            if [ "$_ostype" = "linux-android" ]; then
-                _ostype=linux-androideabi
-            else
-                _ostype="${_ostype}eabihf"
-            fi
-            ;;
-
-        aarch64)
-            _cputype=aarch64
-            ;;
-
-        x86_64 | x86-64 | x64 | amd64)
-            _cputype=x86_64
-            ;;
-
-        mips)
-            _cputype=$(get_endianness mips '' el)
-            ;;
-
-        mips64)
-            if [ "$_bitness" -eq 64 ]; then
-                # only n64 ABI is supported for now
-                _ostype="${_ostype}abi64"
-                _cputype=$(get_endianness mips64 '' el)
-            fi
-            ;;
-
-        ppc)
-            _cputype=powerpc
-            ;;
-
-        ppc64)
-            _cputype=powerpc64
-            ;;
-
-        ppc64le)
-            _cputype=powerpc64le
-            ;;
-
-        s390x)
-            _cputype=s390x
-            ;;
-        riscv64)
-            _cputype=riscv64gc
-            ;;
-        *)
-            err "unknown CPU type: $_cputype"
-
-    esac
-
-    # Detect 64-bit linux with 32-bit userland
-    if [ "${_ostype}" = unknown-linux-gnu ] && [ "${_bitness}" -eq 32 ]; then
-        case $_cputype in
-            x86_64)
-                _cputype=i686
-                ;;
-            mips64)
-                _cputype=$(get_endianness mips '' el)
-                ;;
-            powerpc64)
-                _cputype=powerpc
-                ;;
-            aarch64)
-                _cputype=armv7
-                if [ "$_ostype" = "linux-android" ]; then
-                    _ostype=linux-androideabi
-                else
-                    _ostype="${_ostype}eabihf"
-                fi
-                ;;
-            riscv64gc)
-                err "riscv64 with 32-bit userland unsupported"
-                ;;
-        esac
-    fi
-
-    # Detect armv7 but without the CPU features Rust needs in that build,
-    # and fall back to arm.
-    # See https://github.com/rust-lang/rustup.rs/issues/587.
-    if [ "$_ostype" = "unknown-linux-gnueabihf" ] && [ "$_cputype" = armv7 ]; then
-        if ensure grep '^Features' /proc/cpuinfo | grep -q -v neon; then
-            # At least one processor does not have NEON.
-            _cputype=arm
-        fi
-    fi
-
-    _arch="${_cputype}-${_ostype}"
-
-    RETVAL="$_arch"
-}
-
-say() {
-    printf 'rustup: %s\n' "$1"
-}
-
-err() {
-    say "$1" >&2
-    exit 1
-}
-
-need_cmd() {
-    if ! check_cmd "$1"; then
-        err "need '$1' (command not found)"
-    fi
-}
-
-check_cmd() {
-    command -v "$1" > /dev/null 2>&1
-}
-
-assert_nz() {
-    if [ -z "$1" ]; then err "assert_nz $2"; fi
-}
-
-# Run a command that should never fail. If the command fails execution
-# will immediately terminate with an error showing the failing
-# command.
-ensure() {
-    if ! "$@"; then err "command failed: $*"; fi
-}
-
-# This is just for indicating that commands' results are being
-# intentionally ignored. Usually, because it's being executed
-# as part of error handling.
-ignore() {
-    "$@"
-}
-
-# This wraps curl or wget. Try curl first, if not installed,
-# use wget instead.
-downloader() {
-    local _dld
-    local _ciphersuites
-    if check_cmd curl; then
-        _dld=curl
-    elif check_cmd wget; then
-        _dld=wget
-    else
-        _dld='curl or wget' # to be used in error message of need_cmd
-    fi
-
-    if [ "$1" = --check ]; then
-        need_cmd "$_dld"
-    elif [ "$_dld" = curl ]; then
-        get_ciphersuites_for_curl
-        _ciphersuites="$RETVAL"
-        if [ -n "$_ciphersuites" ]; then
-            curl --proto '=https' --tlsv1.2 --ciphers "$_ciphersuites" --silent --show-error --fail --location "$1" --output "$2"
-        else
-            echo "Warning: Not enforcing strong cipher suites for TLS, this is potentially less secure"
-            if ! check_help_for "$3" curl --proto --tlsv1.2; then
-                echo "Warning: Not enforcing TLS v1.2, this is potentially less secure"
-                curl --silent --show-error --fail --location "$1" --output "$2"
-            else
-                curl --proto '=https' --tlsv1.2 --silent --show-error --fail --location "$1" --output "$2"
-            fi
-        fi
-    elif [ "$_dld" = wget ]; then
-        get_ciphersuites_for_wget
-        _ciphersuites="$RETVAL"
-        if [ -n "$_ciphersuites" ]; then
-            wget --https-only --secure-protocol=TLSv1_2 --ciphers "$_ciphersuites" "$1" -O "$2"
-        else
-            echo "Warning: Not enforcing strong cipher suites for TLS, this is potentially less secure"
-            if ! check_help_for "$3" wget --https-only --secure-protocol; then
-                echo "Warning: Not enforcing TLS v1.2, this is potentially less secure"
-                wget "$1" -O "$2"
-            else
-                wget --https-only --secure-protocol=TLSv1_2 "$1" -O "$2"
-            fi
-        fi
-    else
-        err "Unknown downloader"   # should not reach here
-    fi
-}
-
-check_help_for() {
-    local _arch
-    local _cmd
-    local _arg
-    _arch="$1"
-    shift
-    _cmd="$1"
-    shift
-
-    case "$_arch" in
-
-        # If we're running on OS-X, older than 10.13, then we always
-        # fail to find these options to force fallback
-        *darwin*)
-        if check_cmd sw_vers; then
-            if [ "$(sw_vers -productVersion | cut -d. -f2)" -lt 13 ]; then
-                # Older than 10.13
-                echo "Warning: Detected OS X platform older than 10.13"
-                return 1
-            fi
-        fi
-        ;;
-
-    esac
-
-    for _arg in "$@"; do
-        if ! "$_cmd" --help | grep -q -- "$_arg"; then
-            return 1
-        fi
-    done
-
-    true # not strictly needed
-}
-
-# Return cipher suite string specified by user, otherwise return strong TLS 1.2-1.3 cipher suites
-# if support by local tools is detected. Detection currently supports these curl backends: 
-# GnuTLS and OpenSSL (possibly also LibreSSL and BoringSSL). Return value can be empty.
-get_ciphersuites_for_curl() {
-    if [ -n "${RUSTUP_TLS_CIPHERSUITES-}" ]; then
-        # user specified custom cipher suites, assume they know what they're doing
-        RETVAL="$RUSTUP_TLS_CIPHERSUITES"
-        return
-    fi
-
-    local _openssl_syntax="no"
-    local _gnutls_syntax="no"
-    local _backend_supported="yes"
-    if curl -V | grep -q ' OpenSSL/'; then
-        _openssl_syntax="yes"
-    elif curl -V | grep -iq ' LibreSSL/'; then
-        _openssl_syntax="yes"
-    elif curl -V | grep -iq ' BoringSSL/'; then
-        _openssl_syntax="yes"
-    elif curl -V | grep -iq ' GnuTLS/'; then
-        _gnutls_syntax="yes"
-    else
-        _backend_supported="no"
-    fi
-
-    local _args_supported="no"
-    if [ "$_backend_supported" = "yes" ]; then
-        # "unspecified" is for arch, allows for possibility old OS using macports, homebrew, etc.
-        if check_help_for "notspecified" "curl" "--tlsv1.2" "--ciphers" "--proto"; then
-            _args_supported="yes"
-        fi
-    fi
-
-    local _cs=""
-    if [ "$_args_supported" = "yes" ]; then
-        if [ "$_openssl_syntax" = "yes" ]; then
-            _cs=$(get_strong_ciphersuites_for "openssl")
-        elif [ "$_gnutls_syntax" = "yes" ]; then
-            _cs=$(get_strong_ciphersuites_for "gnutls")
-        fi
-    fi
-
-    RETVAL="$_cs"
-}
-
-# Return cipher suite string specified by user, otherwise return strong TLS 1.2-1.3 cipher suites
-# if support by local tools is detected. Detection currently supports these wget backends: 
-# GnuTLS and OpenSSL (possibly also LibreSSL and BoringSSL). Return value can be empty.
-get_ciphersuites_for_wget() {
-    if [ -n "${RUSTUP_TLS_CIPHERSUITES-}" ]; then
-        # user specified custom cipher suites, assume they know what they're doing
-        RETVAL="$RUSTUP_TLS_CIPHERSUITES"
-        return
-    fi
-
-    local _cs=""
-    if wget -V | grep -q '\-DHAVE_LIBSSL'; then
-        # "unspecified" is for arch, allows for possibility old OS using macports, homebrew, etc.
-        if check_help_for "notspecified" "wget" "TLSv1_2" "--ciphers" "--https-only" "--secure-protocol"; then
-            _cs=$(get_strong_ciphersuites_for "openssl")
-        fi
-    elif wget -V | grep -q '\-DHAVE_LIBGNUTLS'; then
-        # "unspecified" is for arch, allows for possibility old OS using macports, homebrew, etc.
-        if check_help_for "notspecified" "wget" "TLSv1_2" "--ciphers" "--https-only" "--secure-protocol"; then
-            _cs=$(get_strong_ciphersuites_for "gnutls")
-        fi
-    fi
-
-    RETVAL="$_cs"
-}
-
-# Return strong TLS 1.2-1.3 cipher suites in OpenSSL or GnuTLS syntax. TLS 1.2 
-# excludes non-ECDHE and non-AEAD cipher suites. DHE is excluded due to bad 
-# DH params often found on servers (see RFC 7919). Sequence matches or is
-# similar to Firefox 68 ESR with weak cipher suites disabled via about:config.  
-# $1 must be openssl or gnutls.
-get_strong_ciphersuites_for() {
-    if [ "$1" = "openssl" ]; then
-        # OpenSSL is forgiving of unknown values, no problems with TLS 1.3 values on versions that don't support it yet.
-        echo "TLS_AES_128_GCM_SHA256:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_256_GCM_SHA384:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384"
-    elif [ "$1" = "gnutls" ]; then
-        # GnuTLS isn't forgiving of unknown values, so this may require a GnuTLS version that supports TLS 1.3 even if wget doesn't.
-        # Begin with SECURE128 (and higher) then remove/add to build cipher suites. Produces same 9 cipher suites as OpenSSL but in slightly different order.
-        echo "SECURE128:-VERS-SSL3.0:-VERS-TLS1.0:-VERS-TLS1.1:-VERS-DTLS-ALL:-CIPHER-ALL:-MAC-ALL:-KX-ALL:+AEAD:+ECDHE-ECDSA:+ECDHE-RSA:+AES-128-GCM:+CHACHA20-POLY1305:+AES-256-GCM"
-    fi 
-}
-
-main "$@" || exit 1

+ 2 - 2
tooling/cli.js/src/api/dependency-manager/index.ts

@@ -12,13 +12,13 @@ const log = logger('dependency:manager')
 module.exports = {
   async installDependencies() {
     log('Installing missing dependencies...')
-    rust.install()
+    await rust.install()
     await cargoCrates.install()
     await npmPackages.install()
   },
   async updateDependencies() {
     log('Updating dependencies...')
-    rust.update()
+    await rust.update()
     await cargoCrates.update()
     await npmPackages.update()
   }

+ 19 - 18
tooling/cli.js/src/api/dependency-manager/rust.ts

@@ -5,8 +5,9 @@
 import { ManagementType } from './types'
 import { spawnSync } from '../../helpers/spawn'
 import getScriptVersion from '../../helpers/get-script-version'
+import { downloadRustup } from '../../helpers/download-binary'
 import logger from '../../helpers/logger'
-import { createWriteStream, unlinkSync } from 'fs'
+import { createWriteStream, unlinkSync, existsSync } from 'fs'
 import { resolve } from 'path'
 import { platform } from 'os'
 import https from 'https'
@@ -32,25 +33,25 @@ async function download(url: string, dest: string): Promise<void> {
   })
 }
 
-function installRustup(): void {
+async function installRustup(): Promise<void> {
+  const assetName =
+    platform() === 'win32' ? 'rustup-init.exe' : 'rustup-init.sh'
+  const rustupPath = resolve(__dirname, `../../bin/${assetName}`)
+  if (!existsSync(rustupPath)) {
+    await downloadRustup()
+  }
   if (platform() === 'win32') {
-    return spawnSync(
-      'powershell',
-      [resolve(__dirname, '../../scripts/rustup-init.exe')],
-      process.cwd()
-    )
+    return spawnSync('powershell', [rustupPath], process.cwd())
   }
-  return spawnSync(
-    '/bin/sh',
-    [resolve(__dirname, '../../scripts/rustup-init.sh')],
-    process.cwd()
-  )
+  return spawnSync('/bin/sh', [rustupPath], process.cwd())
 }
 
-function manageDependencies(managementType: ManagementType): void {
+async function manageDependencies(
+  managementType: ManagementType
+): Promise<void> {
   if (getScriptVersion('rustup') === null) {
     log('Installing rustup...')
-    installRustup()
+    await installRustup()
   }
 
   if (managementType === ManagementType.Update) {
@@ -58,12 +59,12 @@ function manageDependencies(managementType: ManagementType): void {
   }
 }
 
-function install(): void {
-  return manageDependencies(ManagementType.Install)
+async function install(): Promise<void> {
+  return await manageDependencies(ManagementType.Install)
 }
 
-function update(): void {
-  return manageDependencies(ManagementType.Update)
+async function update(): Promise<void> {
+  return await manageDependencies(ManagementType.Update)
 }
 
 export { install, update }

+ 44 - 20
tooling/cli.js/src/helpers/download-cli.ts → tooling/cli.js/src/helpers/download-binary.ts

@@ -10,28 +10,18 @@ const pipeline = promisify(stream.pipeline)
 // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-var-requires, @typescript-eslint/no-unsafe-member-access
 const tauriCliManifest = require('../../../cli.rs/Cargo.toml') as CargoManifest
 
-let downloadedCli = false
+const downloads: { [url: string]: boolean } = {}
 
-const downloadCli = async (): Promise<void> => {
-  const version = tauriCliManifest.package.version
-  let platform: string = process.platform
-  if (platform === 'win32') {
-    platform = 'windows'
-  } else if (platform === 'linux') {
-    platform = 'linux'
-  } else if (platform === 'darwin') {
-    platform = 'macos'
-  } else {
-    throw Error('Unsupported platform')
-  }
-  const exe = platform === 'windows' ? '.exe' : ''
-  const url = `https://github.com/tauri-apps/binary-releases/releases/download/tauri-cli-v${version}/tauri-cli_${platform}${exe}`
-  const outPath = path.join(__dirname, `../../bin/tauri-cli${exe}`)
+async function downloadBinaryRelease(
+  tag: string,
+  asset: string,
+  outPath: string
+): Promise<void> {
+  const url = `https://github.com/tauri-apps/binary-releases/releases/download/${tag}/${asset}`
 
-  console.log('Downloading Tauri CLI')
   const removeDownloadedCliIfNeeded = (): void => {
     try {
-      if (!downloadedCli) {
+      if (!(url in downloads)) {
         // eslint-disable-next-line security/detect-non-literal-fs-filename
         fs.unlinkSync(outPath)
       }
@@ -53,10 +43,44 @@ const downloadCli = async (): Promise<void> => {
     removeDownloadedCliIfNeeded()
     throw e
   })
-  downloadedCli = true
+  // eslint-disable-next-line security/detect-object-injection
+  downloads[url] = true
   // eslint-disable-next-line security/detect-non-literal-fs-filename
   fs.chmodSync(outPath, 0o700)
   console.log('Download Complete')
 }
 
-export { downloadCli }
+async function downloadCli(): Promise<void> {
+  const version = tauriCliManifest.package.version
+  let platform: string = process.platform
+  if (platform === 'win32') {
+    platform = 'windows'
+  } else if (platform === 'linux') {
+    platform = 'linux'
+  } else if (platform === 'darwin') {
+    platform = 'macos'
+  } else {
+    throw Error('Unsupported platform')
+  }
+  const extension = platform === 'windows' ? '.exe' : ''
+  const outPath = path.join(__dirname, `../../bin/tauri-cli${extension}`)
+  console.log('Downloading Rust CLI...')
+  await downloadBinaryRelease(
+    `tauri-cli-v${version}`,
+    `tauri-cli_${platform}${extension}`,
+    outPath
+  )
+}
+
+async function downloadRustup(): Promise<void> {
+  const assetName =
+    process.platform === 'win32' ? 'rustup-init.exe' : 'rustup-init.sh'
+  console.log('Downloading Rustup...')
+  return await downloadBinaryRelease(
+    'rustup',
+    assetName,
+    path.join(__dirname, `../../bin/${assetName}`)
+  )
+}
+
+export { downloadCli, downloadRustup }

+ 1 - 1
tooling/cli.js/src/helpers/rust-cli.ts

@@ -6,7 +6,7 @@ import { existsSync } from 'fs'
 import { resolve, join } from 'path'
 import { spawnSync, spawn } from './spawn'
 import { CargoManifest } from '../types/cargo'
-import { downloadCli } from './download-cli'
+import { downloadCli } from './download-binary'
 
 const currentTauriCliVersion = (): string => {
   // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-var-requires, @typescript-eslint/no-unsafe-member-access

+ 1 - 1
tooling/cli.js/webpack.config.js

@@ -8,7 +8,7 @@ module.exports = {
     'api/dependency-manager': './src/api/dependency-manager/index.ts',
     'helpers/spawn': './src/helpers/spawn.ts',
     'helpers/rust-cli': './src/helpers/rust-cli.ts',
-    'helpers/download-cli': './src/helpers/download-cli.ts'
+    'helpers/download-binary': './src/helpers/download-binary.ts'
   },
   mode: process.env.NODE_ENV || 'development',
   devtool: 'source-map',