diff --git a/build/azure-pipelines/cli/cli-compile-and-publish.yml b/build/azure-pipelines/cli/cli-compile-and-publish.yml index e635f51df8c..fb0c6c89d75 100644 --- a/build/azure-pipelines/cli/cli-compile-and-publish.yml +++ b/build/azure-pipelines/cli/cli-compile-and-publish.yml @@ -8,16 +8,10 @@ parameters: default: {} steps: - - script: cargo build --release --target ${{ parameters.VSCODE_CLI_TARGET }} --bin=code-tunnel + - script: cargo build --release --target ${{ parameters.VSCODE_CLI_TARGET }} --bin=code displayName: Compile ${{ parameters.VSCODE_CLI_TARGET }} workingDirectory: $(Build.SourcesDirectory)/cli env: - VSCODE_CLI_VERSION: $(VSCODE_CLI_VERSION) - VSCODE_CLI_REMOTE_LICENSE_TEXT: $(VSCODE_CLI_REMOTE_LICENSE_TEXT) - VSCODE_CLI_REMOTE_LICENSE_PROMPT: $(VSCODE_CLI_REMOTE_LICENSE_PROMPT) - VSCODE_CLI_ASSET_NAME: ${{ parameters.VSCODE_CLI_ARTIFACT }} - VSCODE_CLI_AI_KEY: $(VSCODE_CLI_AI_KEY) - VSCODE_CLI_AI_ENDPOINT: $(VSCODE_CLI_AI_ENDPOINT) ${{ each pair in parameters.VSCODE_CLI_ENV }}: ${{ pair.key }}: ${{ pair.value }} @@ -25,9 +19,9 @@ steps: - task: ArchiveFiles@2 inputs: ${{ if contains(parameters.VSCODE_CLI_TARGET, '-windows-') }}: - rootFolderOrFile: $(Build.SourcesDirectory)/cli/target/${{ parameters.VSCODE_CLI_TARGET }}/release/code-tunnel.exe + rootFolderOrFile: $(Build.SourcesDirectory)/cli/target/${{ parameters.VSCODE_CLI_TARGET }}/release/code.exe ${{ if contains(parameters.VSCODE_CLI_TARGET, '-darwin') }}: - rootFolderOrFile: $(Build.SourcesDirectory)/cli/target/${{ parameters.VSCODE_CLI_TARGET }}/release/code-tunnel + rootFolderOrFile: $(Build.SourcesDirectory)/cli/target/${{ parameters.VSCODE_CLI_TARGET }}/release/code includeRootFolder: false archiveType: zip archiveFile: $(Build.ArtifactStagingDirectory)/${{ parameters.VSCODE_CLI_ARTIFACT }}.zip @@ -39,7 +33,7 @@ steps: - ${{ else }}: - task: ArchiveFiles@2 inputs: - rootFolderOrFile: $(Build.SourcesDirectory)/cli/target/${{ parameters.VSCODE_CLI_TARGET }}/release/code-tunnel + rootFolderOrFile: $(Build.SourcesDirectory)/cli/target/${{ parameters.VSCODE_CLI_TARGET }}/release/code includeRootFolder: false archiveType: tar tarCompression: gz diff --git a/build/azure-pipelines/cli/cli-win32-sign.yml b/build/azure-pipelines/cli/cli-win32-sign.yml index 91e069617d8..26e303c2842 100644 --- a/build/azure-pipelines/cli/cli-win32-sign.yml +++ b/build/azure-pipelines/cli/cli-win32-sign.yml @@ -56,7 +56,7 @@ steps: - task: ArchiveFiles@2 inputs: - rootFolderOrFile: $(Build.ArtifactStagingDirectory)/sign/${{ target }}/code-tunnel.exe + rootFolderOrFile: $(Build.ArtifactStagingDirectory)/sign/${{ target }}/code.exe includeRootFolder: false archiveType: zip archiveFile: $(Build.ArtifactStagingDirectory)/$(ASSET_ID).zip diff --git a/build/azure-pipelines/cli/prepare.ts b/build/azure-pipelines/cli/prepare.ts index d30bce54b49..5a206717bfe 100644 --- a/build/azure-pipelines/cli/prepare.ts +++ b/build/azure-pipelines/cli/prepare.ts @@ -22,6 +22,7 @@ const setLauncherEnvironmentVars = () => { ['VSCODE_CLI_AI_KEY', product.aiConfig?.cliKey], ['VSCODE_CLI_AI_ENDPOINT', product.aiConfig?.cliEndpoint], ['VSCODE_CLI_VERSION', packageJson.version], + ['VSCODE_CLI_UPDATE_ENDPOINT', product.updateUrl], ['VSCODE_CLI_QUALIY', product.quality], ['VSCODE_CLI_COMMIT', commit], ]); diff --git a/build/azure-pipelines/darwin/product-build-darwin.yml b/build/azure-pipelines/darwin/product-build-darwin.yml index 7ccd0344d2c..e67854c1c9a 100644 --- a/build/azure-pipelines/darwin/product-build-darwin.yml +++ b/build/azure-pipelines/darwin/product-build-darwin.yml @@ -202,7 +202,8 @@ steps: - script: | set -e ARCHIVE_NAME=$(ls "$(Build.ArtifactStagingDirectory)/cli" | head -n 1) - unzip "$(Build.ArtifactStagingDirectory)/cli/$ARCHIVE_NAME" -d "$(APP_PATH)/Contents/Resources/app/bin" + unzip "$(Build.ArtifactStagingDirectory)/cli/$ARCHIVE_NAME" -d "$(Build.ArtifactStagingDirectory)/cli" + mv "$(Build.ArtifactStagingDirectory)/cli" "$(APP_PATH)/Contents/Resources/app/bin/code-tunnel" chmod +x "$(APP_PATH)/Contents/Resources/app/bin/code-tunnel" if [ "$(VSCODE_QUALITY)" != "stable" ]; then mv "$(APP_PATH)/Contents/Resources/app/bin/code-tunnel" "$(APP_PATH)/Contents/Resources/app/bin/code-tunnel-$(VSCODE_QUALITY)" diff --git a/build/azure-pipelines/linux/product-build-linux-client.yml b/build/azure-pipelines/linux/product-build-linux-client.yml index 9b22c4b26e6..705e15da79f 100644 --- a/build/azure-pipelines/linux/product-build-linux-client.yml +++ b/build/azure-pipelines/linux/product-build-linux-client.yml @@ -273,7 +273,8 @@ steps: - script: | set -e - tar -xzvf $(Build.ArtifactStagingDirectory)/cli/*.tar.gz -C $(agent.builddirectory)/VSCode-linux-$(VSCODE_ARCH)/bin + tar -xzvf $(Build.ArtifactStagingDirectory)/cli/*.tar.gz -C $(Build.ArtifactStagingDirectory)/cli + mv $(Build.ArtifactStagingDirectory)/cli/code $(agent.builddirectory)/VSCode-linux-$(VSCODE_ARCH)/bin/code-tunnel if [ "$(VSCODE_QUALITY)" != "stable" ]; then mv "$(agent.builddirectory)/VSCode-linux-$(VSCODE_ARCH)/bin/code-tunnel" "$(agent.builddirectory)/VSCode-linux-$(VSCODE_ARCH)/bin/code-tunnel-$(VSCODE_QUALITY)" fi diff --git a/build/azure-pipelines/product-build.yml b/build/azure-pipelines/product-build.yml index 8110d9aaea3..eba4edf81eb 100644 --- a/build/azure-pipelines/product-build.yml +++ b/build/azure-pipelines/product-build.yml @@ -233,6 +233,7 @@ stages: VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} VSCODE_BUILD_WIN32: ${{ parameters.VSCODE_BUILD_WIN32 }} VSCODE_BUILD_WIN32_ARM64: ${{ parameters.VSCODE_BUILD_WIN32_ARM64 }} + VSCODE_BUILD_WIN32_32BIT: ${{ parameters.VSCODE_BUILD_WIN32_32BIT }} - ${{ if and(eq(parameters.VSCODE_COMPILE_ONLY, false), eq(variables['VSCODE_BUILD_STAGE_WINDOWS'], true)) }}: - stage: Windows @@ -339,6 +340,7 @@ stages: parameters: VSCODE_BUILD_WIN32: ${{ parameters.VSCODE_BUILD_WIN32 }} VSCODE_BUILD_WIN32_ARM64: ${{ parameters.VSCODE_BUILD_WIN32_ARM64 }} + VSCODE_BUILD_WIN32_32BIT: ${{ parameters.VSCODE_BUILD_WIN32_32BIT }} - ${{ if and(eq(parameters.VSCODE_COMPILE_ONLY, false), eq(variables['VSCODE_BUILD_STAGE_LINUX'], true)) }}: - stage: LinuxServerDependencies diff --git a/build/azure-pipelines/win32/cli-build-win32.yml b/build/azure-pipelines/win32/cli-build-win32.yml index 2b77bccfd2a..78763d546fe 100644 --- a/build/azure-pipelines/win32/cli-build-win32.yml +++ b/build/azure-pipelines/win32/cli-build-win32.yml @@ -3,6 +3,8 @@ parameters: type: boolean - name: VSCODE_BUILD_WIN32_ARM64 type: boolean + - name: VSCODE_BUILD_WIN32_32BIT + type: boolean - name: VSCODE_QUALITY type: string - name: channel @@ -33,6 +35,8 @@ steps: - x86_64-pc-windows-msvc - ${{ if eq(parameters.VSCODE_BUILD_WIN32_ARM64, true) }}: - aarch64-pc-windows-msvc + - ${{ if eq(parameters.VSCODE_BUILD_WIN32_32BIT, true) }}: + - i686-pc-windows-msvc - template: ../vcpkg-install.yml parameters: @@ -41,6 +45,8 @@ steps: - x64-windows-static-md - ${{ if eq(parameters.VSCODE_BUILD_WIN32_ARM64, true) }}: - arm64-windows-static-md + - ${{ if eq(parameters.VSCODE_BUILD_WIN32_32BIT, true) }}: + - x86-windows-static-md vcpkgDir: $(Build.SourcesDirectory)/build/azure-pipelines/cli/vcpkg targetDirectory: $(Build.ArtifactStagingDirectory)/deps @@ -61,3 +67,12 @@ steps: VSCODE_CLI_ENV: OPENSSL_LIB_DIR: $(Build.ArtifactStagingDirectory)/deps/arm64-windows-static-md/lib OPENSSL_INCLUDE_DIR: $(Build.ArtifactStagingDirectory)/deps/arm64-windows-static-md/include + + - ${{ if eq(parameters.VSCODE_BUILD_WIN32_32BIT, true) }}: + - template: ../cli/cli-compile-and-publish.yml + parameters: + VSCODE_CLI_TARGET: i686-pc-windows-msvc + VSCODE_CLI_ARTIFACT: unsigned_vscode_cli_win32_ia32_cli + VSCODE_CLI_ENV: + OPENSSL_LIB_DIR: $(Build.ArtifactStagingDirectory)/deps/x86-windows-static-md/lib + OPENSSL_INCLUDE_DIR: $(Build.ArtifactStagingDirectory)/deps/x86-windows-static-md/include diff --git a/build/azure-pipelines/win32/product-build-win32-cli-sign.yml b/build/azure-pipelines/win32/product-build-win32-cli-sign.yml index 73526fbafcb..b3e7cf3764a 100644 --- a/build/azure-pipelines/win32/product-build-win32-cli-sign.yml +++ b/build/azure-pipelines/win32/product-build-win32-cli-sign.yml @@ -3,14 +3,9 @@ parameters: type: boolean - name: VSCODE_BUILD_WIN32_ARM64 type: boolean + - name: VSCODE_BUILD_WIN32_32BIT + type: boolean -variables: - - name: VSCODE_CLI_ARTIFACTS - value: - - ${{ if eq(parameters.VSCODE_BUILD_WIN32, true) }}: - - unsigned_vscode_cli_win32_x64_cli - - ${{ if eq(parameters.VSCODE_BUILD_WIN32_ARM64, true) }}: - - unsigned_vscode_cli_win32_arm64_cli steps: - task: NodeTool@0 displayName: "Use Node.js" @@ -30,3 +25,5 @@ steps: - unsigned_vscode_cli_win32_x64_cli - ${{ if eq(parameters.VSCODE_BUILD_WIN32_ARM64, true) }}: - unsigned_vscode_cli_win32_arm64_cli + - ${{ if eq(parameters.VSCODE_BUILD_WIN32_32BIT, true) }}: + - unsigned_vscode_cli_win32_ia32_cli diff --git a/build/azure-pipelines/win32/product-build-win32.yml b/build/azure-pipelines/win32/product-build-win32.yml index 0eb1ab16978..4bba63fed68 100644 --- a/build/azure-pipelines/win32/product-build-win32.yml +++ b/build/azure-pipelines/win32/product-build-win32.yml @@ -199,7 +199,8 @@ steps: . build/azure-pipelines/win32/exec.ps1 $ErrorActionPreference = "Stop" $ArtifactName = (gci -Path "$(Build.ArtifactStagingDirectory)/cli" | Select-Object -last 1).FullName - Expand-Archive -Path $ArtifactName -DestinationPath "$(agent.builddirectory)/VSCode-win32-$(VSCODE_ARCH)/bin" + Expand-Archive -Path $ArtifactName -DestinationPath "$(Build.ArtifactStagingDirectory)/cli" + Move-Item -Path "$(Build.ArtifactStagingDirectory)/cli/code.exe" -Destination "$(agent.builddirectory)/VSCode-win32-$(VSCODE_ARCH)/bin/code-tunnel.exe" if ("$(VSCODE_QUALITY)" -ne "stable") { diff --git a/cli/Cargo.toml b/cli/Cargo.toml index eca7ee53a6d..834253a3f94 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -8,9 +8,6 @@ default-run = "code" name = "cli" path = "src/lib.rs" -[[bin]] -name = "code-tunnel" - [[bin]] name = "code" diff --git a/cli/src/bin/code-tunnel/main.rs b/cli/src/bin/code-tunnel/main.rs deleted file mode 100644 index 4de8856f625..00000000000 --- a/cli/src/bin/code-tunnel/main.rs +++ /dev/null @@ -1,123 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -use clap::Parser; -use cli::{ - commands::{args, tunnels, CommandContext}, - constants, log as own_log, - state::LauncherPaths, -}; -use opentelemetry::sdk::trace::TracerProvider as SdkTracerProvider; -use opentelemetry::trace::TracerProvider; - -use log::{Level, Metadata, Record}; - -#[derive(Parser, Debug)] -#[clap( - long_about = None, - name = "Visual Studio Code Tunnels CLI", - version = match constants::VSCODE_CLI_VERSION { Some(v) => v, None => "dev" }, - )] -pub struct TunnelCli { - #[clap(flatten, next_help_heading = Some("GLOBAL OPTIONS"))] - pub global_options: args::GlobalOptions, - - #[clap(flatten, next_help_heading = Some("TUNNEL OPTIONS"))] - pub tunnel_options: args::TunnelArgs, -} - -/// Entrypoint for a standalone "code-tunnel" subcommand. This is a temporary -/// artifact until we're ready to do swap to the full "code" CLI, and most -/// code in here is duplicated from `src/bin/code/main.rs` -#[tokio::main] -async fn main() -> Result<(), std::convert::Infallible> { - let parsed = TunnelCli::parse(); - let context = CommandContext { - http: reqwest::Client::new(), - paths: LauncherPaths::new(&parsed.global_options.cli_data_dir).unwrap(), - log: own_log::Logger::new( - SdkTracerProvider::builder().build().tracer("codecli"), - if parsed.global_options.verbose { - own_log::Level::Trace - } else { - parsed.global_options.log.unwrap_or(own_log::Level::Info) - }, - ), - args: args::CliCore { - global_options: parsed.global_options, - subcommand: Some(args::Commands::Tunnel(parsed.tunnel_options.clone())), - ..Default::default() - }, - }; - - log::set_logger(Box::leak(Box::new(RustyLogger(context.log.clone())))) - .map(|()| log::set_max_level(log::LevelFilter::Debug)) - .expect("expected to make logger"); - - let result = match parsed.tunnel_options.subcommand { - Some(args::TunnelSubcommand::Prune) => tunnels::prune(context).await, - Some(args::TunnelSubcommand::Unregister) => tunnels::unregister(context).await, - Some(args::TunnelSubcommand::Rename(rename_args)) => { - tunnels::rename(context, rename_args).await - } - Some(args::TunnelSubcommand::User(user_command)) => { - tunnels::user(context, user_command).await - } - Some(args::TunnelSubcommand::Service(service_args)) => { - tunnels::service(context, service_args).await - } - None => tunnels::serve(context, parsed.tunnel_options.serve_args).await, - }; - - match result { - Err(e) => print_and_exit(e), - Ok(code) => std::process::exit(code), - } -} - -fn print_and_exit(err: E) -> ! -where - E: std::fmt::Display, -{ - own_log::emit(own_log::Level::Error, "", &format!("{}", err)); - std::process::exit(1); -} - -/// Logger that uses the common rust "log" crate and directs back to one of -/// our managed loggers. -struct RustyLogger(own_log::Logger); - -impl log::Log for RustyLogger { - fn enabled(&self, metadata: &Metadata) -> bool { - metadata.level() <= Level::Debug - } - - fn log(&self, record: &Record) { - if !self.enabled(record.metadata()) { - return; - } - - // exclude noisy log modules: - let src = match record.module_path() { - Some("russh::cipher") => return, - Some("russh::negotiation") => return, - Some(s) => s, - None => "", - }; - - self.0.emit( - match record.level() { - log::Level::Debug => own_log::Level::Debug, - log::Level::Error => own_log::Level::Error, - log::Level::Info => own_log::Level::Info, - log::Level::Trace => own_log::Level::Trace, - log::Level::Warn => own_log::Level::Warn, - }, - &format!("[{}] {}", src, record.args()), - ); - } - - fn flush(&self) {} -} diff --git a/cli/src/constants.rs b/cli/src/constants.rs index f89c34660a7..262ff676ab3 100644 --- a/cli/src/constants.rs +++ b/cli/src/constants.rs @@ -9,7 +9,6 @@ pub const CONTROL_PORT: u16 = 31545; pub const PROTOCOL_VERSION: u32 = 1; pub const VSCODE_CLI_VERSION: Option<&'static str> = option_env!("VSCODE_CLI_VERSION"); -pub const VSCODE_CLI_ASSET_NAME: Option<&'static str> = option_env!("VSCODE_CLI_ASSET_NAME"); pub const VSCODE_CLI_AI_KEY: Option<&'static str> = option_env!("VSCODE_CLI_AI_KEY"); pub const VSCODE_CLI_AI_ENDPOINT: Option<&'static str> = option_env!("VSCODE_CLI_AI_ENDPOINT"); pub const VSCODE_CLI_QUALITY: Option<&'static str> = option_env!("VSCODE_CLI_QUALITY"); diff --git a/cli/src/self_update.rs b/cli/src/self_update.rs index 103b505bfe1..14625c1f545 100644 --- a/cli/src/self_update.rs +++ b/cli/src/self_update.rs @@ -3,20 +3,17 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -use std::{ - fs::{rename, set_permissions}, - path::Path, -}; +use std::{fs, path::Path, process::Command}; use tempfile::tempdir; use crate::{ constants::{VSCODE_CLI_COMMIT, VSCODE_CLI_QUALITY}, options::Quality, - update_service::{Platform, Release, TargetKind, UpdateService}, + update_service::{unzip_downloaded_release, Platform, Release, TargetKind, UpdateService}, util::{ - errors::{wrap, AnyError, UpdatesNotConfigured}, + errors::{wrap, AnyError, CorruptDownload, UpdatesNotConfigured}, http, - io::ReportCopyProgress, + io::{ReportCopyProgress, SilentCopyProgress}, }, }; @@ -66,32 +63,80 @@ impl<'a> SelfUpdate<'a> { release: &Release, progress: impl ReportCopyProgress, ) -> Result<(), AnyError> { + // 1. Download the archive into a temporary directory + let tempdir = tempdir().map_err(|e| wrap(e, "Failed to create temp dir"))?; + let archive_path = tempdir.path().join("archive"); let stream = self.update_service.get_download_stream(release).await?; + http::download_into_file(&archive_path, progress, stream).await?; + + // 2. Unzip the archive and get the binary let target_path = std::env::current_exe().map_err(|e| wrap(e, "could not get current exe"))?; let staging_path = target_path.with_extension(".update"); + let archive_contents_path = tempdir.path().join("content"); + // unzipping the single binary is pretty small and fast--don't bother with passing progress + unzip_downloaded_release(&archive_path, &archive_contents_path, SilentCopyProgress())?; + copy_updated_cli_to_path(&archive_contents_path, &staging_path)?; - http::download_into_file(&staging_path, progress, stream).await?; - + // 3. Copy file metadata, make sure the new binary is executable\ copy_file_metadata(&target_path, &staging_path) .map_err(|e| wrap(e, "failed to set file permissions"))?; + validate_cli_is_good(&staging_path)?; - // Try to rename the old CLI to a tempdir, where it can get cleaned up by the + // Try to rename the old CLI to the tempdir, where it can get cleaned up by the // OS later. However, this can fail if the tempdir is on a different drive // than the installation dir. In this case just rename it to ".old". - let disposal_dir = tempdir().map_err(|e| wrap(e, "Failed to create disposal dir"))?; - if rename(&target_path, &disposal_dir.path().join("old-code-cli")).is_err() { - rename(&target_path, &target_path.with_extension(".old")) + if fs::rename(&target_path, &tempdir.path().join("old-code-cli")).is_err() { + fs::rename(&target_path, &target_path.with_extension(".old")) .map_err(|e| wrap(e, "failed to rename old CLI"))?; } - rename(&staging_path, &target_path) + fs::rename(&staging_path, &target_path) .map_err(|e| wrap(e, "failed to rename newly installed CLI"))?; Ok(()) } } +fn validate_cli_is_good(exe_path: &Path) -> Result<(), AnyError> { + let o = Command::new(exe_path) + .args(["--version"]) + .output() + .map_err(|e| CorruptDownload(format!("could not execute new binary, aborting: {}", e)))?; + + if !o.status.success() { + let msg = format!( + "could not execute new binary, aborting. Stdout:\r\n\r\n{}\r\n\r\nStderr:\r\n\r\n{}", + String::from_utf8_lossy(&o.stdout), + String::from_utf8_lossy(&o.stderr), + ); + + return Err(CorruptDownload(msg).into()); + } + + Ok(()) +} + +fn copy_updated_cli_to_path(unzipped_content: &Path, staging_path: &Path) -> Result<(), AnyError> { + let unzipped_files = fs::read_dir(unzipped_content) + .map_err(|e| wrap(e, "could not read update contents"))? + .collect::>(); + if unzipped_files.len() != 1 { + let msg = format!( + "expected exactly one file in update, got {}", + unzipped_files.len() + ); + return Err(CorruptDownload(msg).into()); + } + + let archive_file = unzipped_files[0] + .as_ref() + .map_err(|e| wrap(e, "error listing update files"))?; + fs::copy(&archive_file.path(), staging_path) + .map_err(|e| wrap(e, "error copying to staging file"))?; + Ok(()) +} + #[cfg(target_os = "windows")] fn copy_file_metadata(from: &Path, to: &Path) -> Result<(), std::io::Error> { let permissions = from.metadata()?.permissions(); @@ -105,7 +150,7 @@ fn copy_file_metadata(from: &Path, to: &Path) -> Result<(), std::io::Error> { use std::os::unix::fs::MetadataExt; let metadata = from.metadata()?; - set_permissions(&to, metadata.permissions())?; + fs::set_permissions(&to, metadata.permissions())?; // based on coreutils' chown https://github.com/uutils/coreutils/blob/72b4629916abe0852ad27286f4e307fbca546b6e/src/chown/chown.rs#L266-L281 let s = std::ffi::CString::new(to.as_os_str().as_bytes()).unwrap(); diff --git a/cli/src/update_service.rs b/cli/src/update_service.rs index 8bdf60138aa..3c1456ecc59 100644 --- a/cli/src/update_service.rs +++ b/cli/src/update_service.rs @@ -220,6 +220,7 @@ pub enum Platform { DarwinARM64, WindowsX64, WindowsX86, + WindowsARM64 } impl Platform { @@ -232,6 +233,7 @@ impl Platform { Platform::DarwinARM64 => Some("darwin-arm64".to_owned()), Platform::WindowsX64 => Some("win32-x64-archive".to_owned()), Platform::WindowsX86 => Some("win32-archive".to_owned()), + Platform::WindowsARM64 => Some("win32-arm64-archive".to_owned()), _ => None, } } @@ -246,6 +248,7 @@ impl Platform { Platform::DarwinARM64 => "server-darwin-arm64", Platform::WindowsX64 => "server-win32-x64", Platform::WindowsX86 => "server-win32", + Platform::WindowsARM64 => "server-win32-arm64", } .to_owned() } @@ -253,14 +256,15 @@ impl Platform { pub fn cli(&self) -> String { match self { Platform::LinuxAlpineARM64 => "cli-alpine-arm64", - Platform::LinuxAlpineX64 => "cli-linux-alpine", + Platform::LinuxAlpineX64 => "cli-alpine-x64", Platform::LinuxX64 => "cli-linux-x64", Platform::LinuxARM64 => "cli-linux-arm64", Platform::LinuxARM32 => "cli-linux-armhf", Platform::DarwinX64 => "cli-darwin-x64", Platform::DarwinARM64 => "cli-darwin-arm64", + Platform::WindowsARM64 => "cli-win32-arm64", Platform::WindowsX64 => "cli-win32-x64", - Platform::WindowsX86 => "cli-win32-x84", + Platform::WindowsX86 => "cli-win32", } .to_owned() } diff --git a/cli/src/util/errors.rs b/cli/src/util/errors.rs index b5308781259..31fba617b5e 100644 --- a/cli/src/util/errors.rs +++ b/cli/src/util/errors.rs @@ -362,6 +362,15 @@ impl std::fmt::Display for WindowsNeedsElevation { } } +#[derive(Debug)] +pub struct CorruptDownload(pub String); + +impl std::fmt::Display for CorruptDownload { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + write!(f, "Error updating the VS Code CLI: {}", self.0) + } +} + // Makes an "AnyError" enum that contains any of the given errors, in the form // `enum AnyError { FooError(FooError) }` (when given `makeAnyError!(FooError)`). // Useful to easily deal with application error types without making tons of "From" @@ -423,7 +432,8 @@ makeAnyError!( ServerHasClosed, ServiceAlreadyRegistered, WindowsNeedsElevation, - UpdatesNotConfigured + UpdatesNotConfigured, + CorruptDownload ); impl From for AnyError {