diff --git a/build/azure-pipelines/alpine/cli-build-alpine.yml b/build/azure-pipelines/alpine/cli-build-alpine.yml index 1417bd16c407d..3fb6234cbcf67 100644 --- a/build/azure-pipelines/alpine/cli-build-alpine.yml +++ b/build/azure-pipelines/alpine/cli-build-alpine.yml @@ -14,8 +14,6 @@ steps: versionSpec: "18.x" - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: - - template: ../distro/download-distro.yml - # Install yarn as the ARM64 build agent is using vanilla Ubuntu - ${{ if eq(parameters.VSCODE_BUILD_ALPINE_ARM64, true) }}: - task: Npm@1 @@ -30,8 +28,7 @@ steps: workingDirectory: build displayName: Install pipeline build - - script: node .build/distro/cli-patches/index.js - displayName: Apply distro patches + - template: ../cli/cli-apply-patches.yml - task: Npm@1 displayName: Download openssl prebuilt @@ -56,13 +53,6 @@ steps: sudo ln -s "/usr/bin/g++" "/usr/bin/musl-g++" || echo "link exists" displayName: Install musl build dependencies - - script: node build/azure-pipelines/cli/prepare.js - displayName: Prepare CLI build - env: - VSCODE_CLI_PREPARE_ROOT: $(Build.SourcesDirectory)/.build/distro - VSCODE_QUALITY: ${{ parameters.VSCODE_QUALITY }} - GITHUB_TOKEN: "$(github-distro-mixin-password)" - - template: ../cli/install-rust-posix.yml parameters: targets: @@ -76,6 +66,7 @@ steps: parameters: VSCODE_CLI_TARGET: aarch64-unknown-linux-musl VSCODE_CLI_ARTIFACT: vscode_cli_alpine_arm64_cli + VSCODE_QUALITY: ${{ parameters.VSCODE_QUALITY }} VSCODE_CLI_ENV: CXX_aarch64-unknown-linux-musl: musl-g++ CC_aarch64-unknown-linux-musl: musl-gcc @@ -88,6 +79,7 @@ steps: parameters: VSCODE_CLI_TARGET: x86_64-unknown-linux-musl VSCODE_CLI_ARTIFACT: vscode_cli_alpine_x64_cli + VSCODE_QUALITY: ${{ parameters.VSCODE_QUALITY }} VSCODE_CLI_ENV: CXX_aarch64-unknown-linux-musl: musl-g++ CC_aarch64-unknown-linux-musl: musl-gcc diff --git a/build/azure-pipelines/cli/cli-apply-patches.yml b/build/azure-pipelines/cli/cli-apply-patches.yml index 35b429375c02d..b96aa4ef7dd94 100644 --- a/build/azure-pipelines/cli/cli-apply-patches.yml +++ b/build/azure-pipelines/cli/cli-apply-patches.yml @@ -1,5 +1,8 @@ steps: - template: ../distro/download-distro.yml + - script: node build/azure-pipelines/distro/mixin-quality + displayName: Mixin distro quality + - script: node .build/distro/cli-patches/index.js displayName: Apply distro patches diff --git a/build/azure-pipelines/cli/cli-compile-and-publish.yml b/build/azure-pipelines/cli/cli-compile-and-publish.yml index a6468ad3ae966..e4ef4af5481af 100644 --- a/build/azure-pipelines/cli/cli-compile-and-publish.yml +++ b/build/azure-pipelines/cli/cli-compile-and-publish.yml @@ -1,4 +1,6 @@ parameters: + - name: VSCODE_QUALITY + type: string - name: VSCODE_CLI_TARGET type: string - name: VSCODE_CLI_ARTIFACT @@ -11,6 +13,13 @@ parameters: default: false steps: + - ${{ if eq(parameters.VSCODE_QUALITY, 'oss') }}: + - pwsh: Write-Host "##vso[task.setvariable variable=VSCODE_CLI_PRODUCT_JSON]$(Build.SourcesDirectory)/product.json" + displayName: Set product.json path + - ${{ else }}: + - pwsh: Write-Host "##vso[task.setvariable variable=VSCODE_CLI_PRODUCT_JSON]$(Build.SourcesDirectory)/.build/distro/mixin/${{ parameters.VSCODE_QUALITY }}/product.json" + displayName: Set product.json path + - ${{ if parameters.VSCODE_CHECK_ONLY }}: - script: rustup component add clippy && cargo clippy --target ${{ parameters.VSCODE_CLI_TARGET }} --bin=code displayName: Lint ${{ parameters.VSCODE_CLI_TARGET }} @@ -26,6 +35,7 @@ steps: workingDirectory: $(Build.SourcesDirectory)/cli env: CARGO_NET_GIT_FETCH_WITH_CLI: true + VSCODE_CLI_COMMIT: $(Build.SourceVersion) ${{ each pair in parameters.VSCODE_CLI_ENV }}: ${{ pair.key }}: ${{ pair.value }} @@ -33,6 +43,11 @@ steps: - powershell: | . build/azure-pipelines/win32/exec.ps1 $ErrorActionPreference = "Stop" + $AppProductJson = Get-Content -Raw -Path "$env:VSCODE_CLI_PRODUCT_JSON" | ConvertFrom-Json + $env:VSCODE_CLI_APPLICATION_NAME = $AppProductJson.applicationName + + Write-Host "##vso[task.setvariable variable=VSCODE_CLI_APPLICATION_NAME]$env:VSCODE_CLI_APPLICATION_NAME" + Move-Item -Path $(Build.SourcesDirectory)/cli/target/${{ parameters.VSCODE_CLI_TARGET }}/release/code.exe -Destination "$(Build.ArtifactStagingDirectory)/${env:VSCODE_CLI_APPLICATION_NAME}.exe" - task: ArchiveFiles@2 @@ -49,7 +64,10 @@ steps: - ${{ else }}: - script: | set -e - mv $(Build.SourcesDirectory)/cli/target/${{ parameters.VSCODE_CLI_TARGET }}/release/code $(Build.ArtifactStagingDirectory)/$(VSCODE_CLI_APPLICATION_NAME) + VSCODE_CLI_APPLICATION_NAME=$(node -p "require(\"$VSCODE_CLI_PRODUCT_JSON\").applicationName") + echo "##vso[task.setvariable variable=VSCODE_CLI_APPLICATION_NAME]$VSCODE_CLI_APPLICATION_NAME" + + mv $(Build.SourcesDirectory)/cli/target/${{ parameters.VSCODE_CLI_TARGET }}/release/code $(Build.ArtifactStagingDirectory)/$VSCODE_CLI_APPLICATION_NAME - ${{ if contains(parameters.VSCODE_CLI_TARGET, '-darwin') }}: - task: ArchiveFiles@2 diff --git a/build/azure-pipelines/cli/prepare.js b/build/azure-pipelines/cli/prepare.js deleted file mode 100644 index bd11bc6a0a4c1..0000000000000 --- a/build/azure-pipelines/cli/prepare.js +++ /dev/null @@ -1,93 +0,0 @@ -"use strict"; -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ -Object.defineProperty(exports, "__esModule", { value: true }); -const getVersion_1 = require("../../lib/getVersion"); -const fs = require("fs"); -const path = require("path"); -const packageJson = require("../../../package.json"); -const root = process.env.VSCODE_CLI_PREPARE_ROOT || path.dirname(path.dirname(path.dirname(__dirname))); -const readJSON = (path) => JSON.parse(fs.readFileSync(path, 'utf8')); -let productJsonPath; -const isOSS = process.env.VSCODE_QUALITY === 'oss' || !process.env.VSCODE_QUALITY; -if (isOSS) { - productJsonPath = path.join(root, 'product.json'); -} -else { - productJsonPath = path.join(root, 'mixin', process.env.VSCODE_QUALITY, 'product.json'); -} -console.error('Loading product.json from', productJsonPath); -const product = readJSON(productJsonPath); -const allProductsAndQualities = isOSS ? [product] : fs.readdirSync(path.join(root, 'mixin')) - .map(quality => ({ quality, json: readJSON(path.join(root, 'mixin', quality, 'product.json')) })); -const commit = (0, getVersion_1.getVersion)(root); -const makeQualityMap = (m) => { - const output = {}; - for (const { quality, json } of allProductsAndQualities) { - output[quality] = m(json, quality); - } - return output; -}; -/** - * Sets build environment variables for the CLI for current contextual info. - */ -const setLauncherEnvironmentVars = () => { - const vars = new Map([ - ['VSCODE_CLI_ALREADY_PREPARED', 'true'], - ['VSCODE_CLI_REMOTE_LICENSE_TEXT', product.serverLicense?.join('\\n')], - ['VSCODE_CLI_REMOTE_LICENSE_PROMPT', product.serverLicensePrompt], - ['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_QUALITY', product.quality], - ['VSCODE_CLI_NAME_SHORT', product.nameShort], - ['VSCODE_CLI_NAME_LONG', product.nameLong], - ['VSCODE_CLI_QUALITYLESS_PRODUCT_NAME', product.nameLong.replace(/ - [a-z]+$/i, '')], - ['VSCODE_CLI_DOCUMENTATION_URL', product.documentationUrl], - ['VSCODE_CLI_APPLICATION_NAME', product.applicationName], - ['VSCODE_CLI_EDITOR_WEB_URL', product.tunnelApplicationConfig?.editorWebUrl], - ['VSCODE_CLI_TUNNEL_SERVICE_MUTEX', product.win32TunnelServiceMutex], - ['VSCODE_CLI_TUNNEL_CLI_MUTEX', product.win32TunnelMutex], - ['VSCODE_CLI_COMMIT', commit], - ['VSCODE_CLI_DEFAULT_PARENT_DATA_DIR', product.dataFolderName], - [ - 'VSCODE_CLI_WIN32_APP_IDS', - !isOSS && JSON.stringify(makeQualityMap(json => Object.entries(json) - .filter(([key]) => /^win32.*AppId$/.test(key)) - .map(([, value]) => String(value).replace(/[{}]/g, '')))), - ], - [ - 'VSCODE_CLI_NAME_LONG_MAP', - !isOSS && JSON.stringify(makeQualityMap(json => json.nameLong)), - ], - [ - 'VSCODE_CLI_APPLICATION_NAME_MAP', - !isOSS && JSON.stringify(makeQualityMap(json => json.applicationName)), - ], - [ - 'VSCODE_CLI_SERVER_NAME_MAP', - !isOSS && JSON.stringify(makeQualityMap(json => json.serverApplicationName)), - ], - [ - 'VSCODE_CLI_QUALITY_DOWNLOAD_URIS', - !isOSS && JSON.stringify(makeQualityMap(json => json.downloadUrl)), - ], - ]); - if (process.env.VSCODE_CLI_PREPARE_OUTPUT === 'json') { - console.log(JSON.stringify([...vars].filter(([, v]) => !!v))); - } - else { - for (const [key, value] of vars) { - if (value) { - console.log(`##vso[task.setvariable variable=${key}]${value}`); - } - } - } -}; -if (require.main === module) { - setLauncherEnvironmentVars(); -} -//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicHJlcGFyZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbInByZXBhcmUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBOzs7Z0dBR2dHOztBQUVoRyxxREFBa0Q7QUFDbEQseUJBQXlCO0FBQ3pCLDZCQUE2QjtBQUM3QixxREFBcUQ7QUFFckQsTUFBTSxJQUFJLEdBQUcsT0FBTyxDQUFDLEdBQUcsQ0FBQyx1QkFBdUIsSUFBSSxJQUFJLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFDLENBQUM7QUFDeEcsTUFBTSxRQUFRLEdBQUcsQ0FBQyxJQUFZLEVBQUUsRUFBRSxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDLFlBQVksQ0FBQyxJQUFJLEVBQUUsTUFBTSxDQUFDLENBQUMsQ0FBQztBQUU3RSxJQUFJLGVBQXVCLENBQUM7QUFDNUIsTUFBTSxLQUFLLEdBQUcsT0FBTyxDQUFDLEdBQUcsQ0FBQyxjQUFjLEtBQUssS0FBSyxJQUFJLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxjQUFjLENBQUM7QUFDbEYsSUFBSSxLQUFLLEVBQUU7SUFDVixlQUFlLEdBQUcsSUFBSSxDQUFDLElBQUksQ0FBQyxJQUFJLEVBQUUsY0FBYyxDQUFDLENBQUM7Q0FDbEQ7S0FBTTtJQUNOLGVBQWUsR0FBRyxJQUFJLENBQUMsSUFBSSxDQUFDLElBQUksRUFBRSxPQUFPLEVBQUUsT0FBTyxDQUFDLEdBQUcsQ0FBQyxjQUFlLEVBQUUsY0FBYyxDQUFDLENBQUM7Q0FDeEY7QUFFRCxPQUFPLENBQUMsS0FBSyxDQUFDLDJCQUEyQixFQUFFLGVBQWUsQ0FBQyxDQUFDO0FBQzVELE1BQU0sT0FBTyxHQUFHLFFBQVEsQ0FBQyxlQUFlLENBQUMsQ0FBQztBQUMxQyxNQUFNLHVCQUF1QixHQUFHLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFD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 \ No newline at end of file diff --git a/build/azure-pipelines/cli/prepare.ts b/build/azure-pipelines/cli/prepare.ts deleted file mode 100644 index 7157dae3ecd7c..0000000000000 --- a/build/azure-pipelines/cli/prepare.ts +++ /dev/null @@ -1,99 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import { getVersion } from '../../lib/getVersion'; -import * as fs from 'fs'; -import * as path from 'path'; -import * as packageJson from '../../../package.json'; - -const root = process.env.VSCODE_CLI_PREPARE_ROOT || path.dirname(path.dirname(path.dirname(__dirname))); -const readJSON = (path: string) => JSON.parse(fs.readFileSync(path, 'utf8')); - -let productJsonPath: string; -const isOSS = process.env.VSCODE_QUALITY === 'oss' || !process.env.VSCODE_QUALITY; -if (isOSS) { - productJsonPath = path.join(root, 'product.json'); -} else { - productJsonPath = path.join(root, 'mixin', process.env.VSCODE_QUALITY!, 'product.json'); -} - -console.error('Loading product.json from', productJsonPath); -const product = readJSON(productJsonPath); -const allProductsAndQualities = isOSS ? [product] : fs.readdirSync(path.join(root, 'mixin')) - .map(quality => ({ quality, json: readJSON(path.join(root, 'mixin', quality, 'product.json')) })); -const commit = getVersion(root); - -const makeQualityMap = (m: (productJson: any, quality: string) => T): Record => { - const output: Record = {}; - for (const { quality, json } of allProductsAndQualities) { - output[quality] = m(json, quality); - } - return output; -}; - -/** - * Sets build environment variables for the CLI for current contextual info. - */ -const setLauncherEnvironmentVars = () => { - const vars = new Map([ - ['VSCODE_CLI_ALREADY_PREPARED', 'true'], - ['VSCODE_CLI_REMOTE_LICENSE_TEXT', product.serverLicense?.join('\\n')], - ['VSCODE_CLI_REMOTE_LICENSE_PROMPT', product.serverLicensePrompt], - ['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_QUALITY', product.quality], - ['VSCODE_CLI_NAME_SHORT', product.nameShort], - ['VSCODE_CLI_NAME_LONG', product.nameLong], - ['VSCODE_CLI_QUALITYLESS_PRODUCT_NAME', product.nameLong.replace(/ - [a-z]+$/i, '')], - ['VSCODE_CLI_DOCUMENTATION_URL', product.documentationUrl], - ['VSCODE_CLI_APPLICATION_NAME', product.applicationName], - ['VSCODE_CLI_EDITOR_WEB_URL', product.tunnelApplicationConfig?.editorWebUrl], - ['VSCODE_CLI_TUNNEL_SERVICE_MUTEX', product.win32TunnelServiceMutex], - ['VSCODE_CLI_TUNNEL_CLI_MUTEX', product.win32TunnelMutex], - ['VSCODE_CLI_COMMIT', commit], - ['VSCODE_CLI_DEFAULT_PARENT_DATA_DIR', product.dataFolderName], - [ - 'VSCODE_CLI_WIN32_APP_IDS', - !isOSS && JSON.stringify( - makeQualityMap(json => Object.entries(json) - .filter(([key]) => /^win32.*AppId$/.test(key)) - .map(([, value]) => String(value).replace(/[{}]/g, ''))), - ), - ], - [ - 'VSCODE_CLI_NAME_LONG_MAP', - !isOSS && JSON.stringify(makeQualityMap(json => json.nameLong)), - ], - [ - 'VSCODE_CLI_APPLICATION_NAME_MAP', - !isOSS && JSON.stringify(makeQualityMap(json => json.applicationName)), - ], - [ - 'VSCODE_CLI_SERVER_NAME_MAP', - !isOSS && JSON.stringify(makeQualityMap(json => json.serverApplicationName)), - ], - [ - 'VSCODE_CLI_QUALITY_DOWNLOAD_URIS', - !isOSS && JSON.stringify(makeQualityMap(json => json.downloadUrl)), - ], - ]); - - if (process.env.VSCODE_CLI_PREPARE_OUTPUT === 'json') { - console.log(JSON.stringify([...vars].filter(([, v]) => !!v))); - } else { - for (const [key, value] of vars) { - if (value) { - console.log(`##vso[task.setvariable variable=${key}]${value}`); - } - } - } - -}; - -if (require.main === module) { - setLauncherEnvironmentVars(); -} diff --git a/build/azure-pipelines/darwin/cli-build-darwin.yml b/build/azure-pipelines/darwin/cli-build-darwin.yml index 3597c62142aa8..ae8f0e846521b 100644 --- a/build/azure-pipelines/darwin/cli-build-darwin.yml +++ b/build/azure-pipelines/darwin/cli-build-darwin.yml @@ -34,13 +34,6 @@ steps: tar -xvzf $(Build.ArtifactStagingDirectory)/vscode-internal-openssl-prebuilt-0.0.8.tgz --strip-components=1 --directory=$(Build.ArtifactStagingDirectory)/openssl displayName: Extract openssl prebuilt - - script: node build/azure-pipelines/cli/prepare.js - displayName: Prepare CLI build - env: - VSCODE_CLI_PREPARE_ROOT: $(Build.SourcesDirectory)/.build/distro - VSCODE_QUALITY: ${{ parameters.VSCODE_QUALITY }} - GITHUB_TOKEN: "$(github-distro-mixin-password)" - - template: ../cli/install-rust-posix.yml parameters: targets: @@ -52,6 +45,7 @@ steps: - ${{ if eq(parameters.VSCODE_BUILD_MACOS, true) }}: - template: ../cli/cli-compile-and-publish.yml parameters: + VSCODE_QUALITY: ${{ parameters.VSCODE_QUALITY }} VSCODE_CLI_TARGET: x86_64-apple-darwin VSCODE_CLI_ARTIFACT: unsigned_vscode_cli_darwin_x64_cli VSCODE_CHECK_ONLY: ${{ parameters.VSCODE_CHECK_ONLY }} @@ -62,6 +56,7 @@ steps: - ${{ if eq(parameters.VSCODE_BUILD_MACOS_ARM64, true) }}: - template: ../cli/cli-compile-and-publish.yml parameters: + VSCODE_QUALITY: ${{ parameters.VSCODE_QUALITY }} VSCODE_CLI_TARGET: aarch64-apple-darwin VSCODE_CLI_ARTIFACT: unsigned_vscode_cli_darwin_arm64_cli VSCODE_CHECK_ONLY: ${{ parameters.VSCODE_CHECK_ONLY }} diff --git a/build/azure-pipelines/linux/cli-build-linux.yml b/build/azure-pipelines/linux/cli-build-linux.yml index 1fecc7b636066..b77b78aa1a873 100644 --- a/build/azure-pipelines/linux/cli-build-linux.yml +++ b/build/azure-pipelines/linux/cli-build-linux.yml @@ -45,13 +45,6 @@ steps: - bash: sudo apt-get install -yq gcc-aarch64-linux-gnu g++-aarch64-linux-gnu binutils-aarch64-linux-gnu displayName: Install arm64 toolchains - - script: node build/azure-pipelines/cli/prepare.js - displayName: Prepare CLI build - env: - VSCODE_CLI_PREPARE_ROOT: $(Build.SourcesDirectory)/.build/distro - VSCODE_QUALITY: ${{ parameters.VSCODE_QUALITY }} - GITHUB_TOKEN: "$(github-distro-mixin-password)" - - template: ../cli/install-rust-posix.yml parameters: targets: @@ -65,6 +58,7 @@ steps: - ${{ if eq(parameters.VSCODE_BUILD_LINUX_ARM64, true) }}: - template: ../cli/cli-compile-and-publish.yml parameters: + VSCODE_QUALITY: ${{ parameters.VSCODE_QUALITY }} VSCODE_CLI_TARGET: aarch64-unknown-linux-gnu VSCODE_CLI_ARTIFACT: vscode_cli_linux_arm64_cli VSCODE_CHECK_ONLY: ${{ parameters.VSCODE_CHECK_ONLY }} @@ -76,6 +70,7 @@ steps: - ${{ if eq(parameters.VSCODE_BUILD_LINUX, true) }}: - template: ../cli/cli-compile-and-publish.yml parameters: + VSCODE_QUALITY: ${{ parameters.VSCODE_QUALITY }} VSCODE_CLI_TARGET: x86_64-unknown-linux-gnu VSCODE_CLI_ARTIFACT: vscode_cli_linux_x64_cli VSCODE_CHECK_ONLY: ${{ parameters.VSCODE_CHECK_ONLY }} @@ -86,6 +81,7 @@ steps: - ${{ if eq(parameters.VSCODE_BUILD_LINUX_ARMHF, true) }}: - template: ../cli/cli-compile-and-publish.yml parameters: + VSCODE_QUALITY: ${{ parameters.VSCODE_QUALITY }} VSCODE_CLI_TARGET: armv7-unknown-linux-gnueabihf VSCODE_CLI_ARTIFACT: vscode_cli_linux_armhf_cli VSCODE_CHECK_ONLY: ${{ parameters.VSCODE_CHECK_ONLY }} diff --git a/build/azure-pipelines/win32/cli-build-win32.yml b/build/azure-pipelines/win32/cli-build-win32.yml index 0413ecd9eb283..6eb5ac41f5c49 100644 --- a/build/azure-pipelines/win32/cli-build-win32.yml +++ b/build/azure-pipelines/win32/cli-build-win32.yml @@ -36,13 +36,6 @@ steps: tar -xvzf $(Build.ArtifactStagingDirectory)/vscode-internal-openssl-prebuilt-0.0.8.tgz --strip-components=1 --directory=$(Build.ArtifactStagingDirectory)/openssl displayName: Extract openssl prebuilt - - powershell: node build/azure-pipelines/cli/prepare.js - displayName: Prepare CLI build - env: - VSCODE_CLI_PREPARE_ROOT: $(Build.SourcesDirectory)/.build/distro - VSCODE_QUALITY: ${{ parameters.VSCODE_QUALITY }} - GITHUB_TOKEN: "$(github-distro-mixin-password)" - - template: ../cli/install-rust-win32.yml parameters: targets: @@ -56,6 +49,7 @@ steps: - ${{ if eq(parameters.VSCODE_BUILD_WIN32, true) }}: - template: ../cli/cli-compile-and-publish.yml parameters: + VSCODE_QUALITY: ${{ parameters.VSCODE_QUALITY }} VSCODE_CLI_TARGET: x86_64-pc-windows-msvc VSCODE_CLI_ARTIFACT: unsigned_vscode_cli_win32_x64_cli VSCODE_CHECK_ONLY: ${{ parameters.VSCODE_CHECK_ONLY }} @@ -67,6 +61,7 @@ steps: - ${{ if eq(parameters.VSCODE_BUILD_WIN32_ARM64, true) }}: - template: ../cli/cli-compile-and-publish.yml parameters: + VSCODE_QUALITY: ${{ parameters.VSCODE_QUALITY }} VSCODE_CLI_TARGET: aarch64-pc-windows-msvc VSCODE_CLI_ARTIFACT: unsigned_vscode_cli_win32_arm64_cli VSCODE_CHECK_ONLY: ${{ parameters.VSCODE_CHECK_ONLY }} @@ -78,6 +73,7 @@ steps: - ${{ if eq(parameters.VSCODE_BUILD_WIN32_32BIT, true) }}: - template: ../cli/cli-compile-and-publish.yml parameters: + VSCODE_QUALITY: ${{ parameters.VSCODE_QUALITY }} VSCODE_CLI_TARGET: i686-pc-windows-msvc VSCODE_CLI_ARTIFACT: unsigned_vscode_cli_win32_ia32_cli VSCODE_CHECK_ONLY: ${{ parameters.VSCODE_CHECK_ONLY }} diff --git a/cli/Cargo.toml b/cli/Cargo.toml index 8aad5fea7b83f..a25bee1f2cea1 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -56,7 +56,7 @@ bytes = "1.4.0" tar = "0.4.38" [build-dependencies] -serde = "1.0.163" +serde = { version="1.0.163", features = ["derive"] } serde_json = "1.0.96" [target.'cfg(windows)'.dependencies] diff --git a/cli/build.rs b/cli/build.rs index 41e289774e94f..16078e34044bd 100644 --- a/cli/build.rs +++ b/cli/build.rs @@ -6,53 +6,146 @@ const FILE_HEADER: &str = "/*---------------------------------------------------------------------------------------------\n * Copyright (c) Microsoft Corporation. All rights reserved.\n * Licensed under the MIT License. See License.txt in the project root for license information.\n *--------------------------------------------------------------------------------------------*/"; use std::{ + collections::HashMap, env, fs, io, - path::PathBuf, - process::{self, Command}, + path::{Path, PathBuf}, + process::{self}, str::FromStr, }; +use serde::{de::DeserializeOwned, Deserialize}; +use serde_json::Value; + fn main() { let files = enumerate_source_files().expect("expected to enumerate files"); ensure_file_headers(&files).expect("expected to ensure file headers"); apply_build_environment_variables(); } -fn apply_build_environment_variables() { - // only do this for local, debug builds - if env::var("PROFILE").unwrap() != "debug" || env::var("VSCODE_CLI_ALREADY_PREPARED").is_ok() { - return; +fn camel_case_to_constant_case(key: &str) -> String { + let mut output = String::new(); + let mut prev_upper = false; + for c in key.chars() { + if c.is_uppercase() { + if prev_upper { + output.push(c.to_ascii_lowercase()); + } else { + output.push('_'); + output.push(c.to_ascii_uppercase()); + } + prev_upper = true; + } else if c.is_lowercase() { + output.push(c.to_ascii_uppercase()); + prev_upper = false; + } else { + output.push(c); + prev_upper = false; + } } - let pkg_dir = env::var("CARGO_MANIFEST_DIR").unwrap(); - let mut cmd = Command::new(env::var("NODE_PATH").unwrap_or_else(|_| "node".to_string())); - cmd.arg("../build/azure-pipelines/cli/prepare.js"); - cmd.current_dir(&pkg_dir); - cmd.env("VSCODE_CLI_PREPARE_OUTPUT", "json"); - - let mut distro_location = PathBuf::from_str(&pkg_dir).unwrap(); - distro_location.pop(); // vscode dir - distro_location.pop(); // parent dir - distro_location.push("vscode-distro"); // distro dir, perhaps? - if distro_location.exists() { - cmd.env("VSCODE_CLI_PREPARE_ROOT", distro_location); - cmd.env("VSCODE_QUALITY", "insider"); + output +} + +fn set_env_vars_from_map_keys(prefix: &str, map: impl IntoIterator) { + let mut win32_app_ids = vec![]; + + for (key, value) in map { + //#region special handling + let value = match key.as_str() { + "tunnelServerQualities" | "serverLicense" => { + Value::String(serde_json::to_string(&value).unwrap()) + } + "nameLong" => { + if let Value::String(s) = &value { + let idx = s.find(" - "); + println!( + "cargo:rustc-env=VSCODE_CLI_QUALITYLESS_PRODUCT_NAME={}", + idx.map(|i| &s[..i]).unwrap_or(s) + ); + } + + value + } + "tunnelApplicationConfig" => { + if let Value::Object(v) = value { + set_env_vars_from_map_keys(&format!("{}_{}", prefix, "TUNNEL"), v); + } + continue; + } + _ => value, + }; + if key.contains("win32") && key.contains("AppId") { + if let Value::String(s) = value { + win32_app_ids.push(s); + continue; + } + } + //#endregion + + if let Value::String(s) = value { + println!( + "cargo:rustc-env={}_{}={}", + prefix, + camel_case_to_constant_case(&key), + s + ); + } } - let output = cmd.output().expect("expected to run prepare script"); - if !output.status.success() { - eprint!( - "error running prepare script: {}", - String::from_utf8_lossy(&output.stderr) + if !win32_app_ids.is_empty() { + println!( + "cargo:rustc-env=VSCODE_CLI_WIN32_APP_IDS={}", + win32_app_ids.join(",") ); - process::exit(output.status.code().unwrap_or(1)); } +} - let vars = serde_json::from_slice::>(&output.stdout) - .expect("expected to deserialize output"); - for (key, value) in vars { - println!("cargo:rustc-env={}={}", key, value); - } +fn read_json_from_path(path: &Path) -> T +where + T: DeserializeOwned, +{ + let mut file = fs::File::open(path).expect("failed to open file"); + serde_json::from_reader(&mut file).expect("failed to deserialize JSON") +} + +fn apply_build_from_product_json(path: &Path) { + let json: HashMap = read_json_from_path(path); + set_env_vars_from_map_keys("VSCODE_CLI", json); +} + +#[derive(Deserialize)] +struct PackageJson { + pub version: String, +} + +fn apply_build_environment_variables() { + let repo_dir = env::current_dir().unwrap().join(".."); + let package_json = read_json_from_path::(&repo_dir.join("package.json")); + println!( + "cargo:rustc-env=VSCODE_CLI_VERSION={}", + package_json.version + ); + + match env::var("VSCODE_CLI_PRODUCT_JSON") { + Ok(v) => { + let path = if cfg!(windows) { + PathBuf::from_str(&v.replace('/', "\\")).unwrap() + } else { + PathBuf::from_str(&v).unwrap() + }; + println!("cargo:warning=loading product.json from <{:?}>", path); + apply_build_from_product_json(&path); + } + + Err(_) => { + apply_build_from_product_json(&repo_dir.join("product.json")); + + let overrides = repo_dir.join("product.overrides.json"); + if overrides.exists() { + apply_build_from_product_json(&overrides); + } + } + }; } fn ensure_file_headers(files: &[PathBuf]) -> Result<(), io::Error> { diff --git a/cli/src/commands/args.rs b/cli/src/commands/args.rs index 0051f72f3957d..9caee09ed64b2 100644 --- a/cli/src/commands/args.rs +++ b/cli/src/commands/args.rs @@ -304,7 +304,7 @@ pub enum VersionSubcommand { #[derive(Args, Debug, Clone)] pub struct UseVersionArgs { /// The version of the editor you want to use. Can be "stable", "insiders", - /// a version number, or an absolute path to an existing install. + /// or an absolute path to an existing install. #[clap(value_name = "stable | insiders | x.y.z | path")] pub name: String, diff --git a/cli/src/constants.rs b/cli/src/constants.rs index 19ae4c82600c2..6f604e8876ee6 100644 --- a/cli/src/constants.rs +++ b/cli/src/constants.rs @@ -3,6 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +use serde::Deserialize; use std::{collections::HashMap, io::IsTerminal}; use const_format::concatcp; @@ -32,17 +33,16 @@ pub const VSCODE_CLI_AI_ENDPOINT: Option<&'static str> = option_env!("VSCODE_CLI pub const VSCODE_CLI_QUALITY: Option<&'static str> = option_env!("VSCODE_CLI_QUALITY"); pub const DOCUMENTATION_URL: Option<&'static str> = option_env!("VSCODE_CLI_DOCUMENTATION_URL"); pub const VSCODE_CLI_COMMIT: Option<&'static str> = option_env!("VSCODE_CLI_COMMIT"); -pub const VSCODE_CLI_UPDATE_ENDPOINT: Option<&'static str> = - option_env!("VSCODE_CLI_UPDATE_ENDPOINT"); +pub const VSCODE_CLI_UPDATE_ENDPOINT: Option<&'static str> = option_env!("VSCODE_CLI_UPDATE_URL"); /// Windows lock name for the running tunnel service. Used by the setup script /// to detect a tunnel process. See #179265. pub const TUNNEL_SERVICE_LOCK_NAME: Option<&'static str> = - option_env!("VSCODE_CLI_TUNNEL_SERVICE_MUTEX"); + option_env!("VSCODE_CLI_WIN32_TUNNEL_SERVICE_MUTEX"); /// Windows lock name for the running tunnel without a service. Used by the setup /// script to detect a tunnel process. See #179265. -pub const TUNNEL_CLI_LOCK_NAME: Option<&'static str> = option_env!("VSCODE_CLI_TUNNEL_CLI_MUTEX"); +pub const TUNNEL_CLI_LOCK_NAME: Option<&'static str> = option_env!("VSCODE_CLI_WIN32_TUNNEL_MUTEX"); pub const TUNNEL_SERVICE_USER_AGENT_ENV_VAR: &str = "TUNNEL_SERVICE_USER_AGENT"; @@ -68,16 +68,24 @@ pub const QUALITYLESS_PRODUCT_NAME: &str = match option_env!("VSCODE_CLI_QUALITY /// Name of the application without quality information. pub const QUALITYLESS_SERVER_NAME: &str = concatcp!(QUALITYLESS_PRODUCT_NAME, " Server"); +pub const QUALITY: &str = match VSCODE_CLI_QUALITY { + Some(q) => q, + _ => "oss", +}; + /// Web URL the editor is hosted at. For VS Code, this is vscode.dev. -pub const EDITOR_WEB_URL: Option<&'static str> = option_env!("VSCODE_CLI_EDITOR_WEB_URL"); +pub const EDITOR_WEB_URL: Option<&'static str> = option_env!("VSCODE_CLI_TUNNEL_EDITOR_WEB_URL"); /// Name shown in places where we need to tell a user what a process is, e.g. in sleep inhibition. pub const TUNNEL_ACTIVITY_NAME: &str = concatcp!(PRODUCT_NAME_LONG, " Tunnel"); +/// Download URL of the desktop product. +pub const PRODUCT_DOWNLOAD_URL: Option<&'static str> = option_env!("VSCODE_CLI_DOWNLOAD_URL"); + const NONINTERACTIVE_VAR: &str = "VSCODE_CLI_NONINTERACTIVE"; /// Default data CLI data directory. -pub const DEFAULT_DATA_PARENT_DIR: &str = match option_env!("VSCODE_CLI_DEFAULT_PARENT_DATA_DIR") { +pub const DEFAULT_DATA_PARENT_DIR: &str = match option_env!("VSCODE_CLI_DATA_FOLDER_NAME") { Some(n) => n, None => ".vscode-oss", }; @@ -91,6 +99,12 @@ pub fn get_default_user_agent() -> String { const NO_COLOR_ENV: &str = "NO_COLOR"; +#[derive(Deserialize, Debug)] +#[serde(rename_all = "camelCase")] +pub struct ServerQualityInfo { + pub server_application_name: String, +} + lazy_static! { pub static ref TUNNEL_SERVICE_USER_AGENT: String = match std::env::var(TUNNEL_SERVICE_USER_AGENT_ENV_VAR) { @@ -98,25 +112,9 @@ lazy_static! { _ => get_default_user_agent(), }; - /// Map of quality names to arrays of app IDs used for them, for example, `{"stable":["ABC123"]}` - pub static ref WIN32_APP_IDS: Option>> = - option_env!("VSCODE_CLI_WIN32_APP_IDS").and_then(|s| serde_json::from_str(s).unwrap()); - - /// Map of quality names to desktop download URIs - pub static ref QUALITY_DOWNLOAD_URIS: Option> = - option_env!("VSCODE_CLI_QUALITY_DOWNLOAD_URIS").and_then(|s| serde_json::from_str(s).unwrap()); - - /// Map of qualities to the long name of the app in that quality - pub static ref PRODUCT_NAME_LONG_MAP: Option> = - option_env!("VSCODE_CLI_NAME_LONG_MAP").and_then(|s| serde_json::from_str(s).unwrap()); - - /// Map of qualities to the application name - pub static ref APPLICATION_NAME_MAP: Option> = - option_env!("VSCODE_CLI_APPLICATION_NAME_MAP").and_then(|s| serde_json::from_str(s).unwrap()); - /// Map of qualities to the server name - pub static ref SERVER_NAME_MAP: Option> = - option_env!("VSCODE_CLI_SERVER_NAME_MAP").and_then(|s| serde_json::from_str(s).unwrap()); + pub static ref SERVER_NAME_MAP: Option> = + option_env!("VSCODE_CLI_TUNNEL_SERVER_QUALITIES").and_then(|s| serde_json::from_str(s).unwrap()); /// Whether i/o interactions are allowed in the current CLI. pub static ref IS_A_TTY: bool = std::io::stdin().is_terminal(); @@ -126,4 +124,8 @@ lazy_static! { /// Whether i/o interactions are allowed in the current CLI. pub static ref IS_INTERACTIVE_CLI: bool = *IS_A_TTY && std::env::var(NONINTERACTIVE_VAR).is_err(); + + /// Map of quality names to arrays of app IDs used for them, for example, `{"stable":["ABC123"]}` + pub static ref WIN32_APP_IDS: Option> = + option_env!("VSCODE_CLI_WIN32_APP_IDS").map(|s| s.split(',').map(|s| s.to_string()).collect()); } diff --git a/cli/src/desktop/version_manager.rs b/cli/src/desktop/version_manager.rs index e08b42aa98201..bb0f1011ab67c 100644 --- a/cli/src/desktop/version_manager.rs +++ b/cli/src/desktop/version_manager.rs @@ -14,9 +14,8 @@ use regex::Regex; use serde::{Deserialize, Serialize}; use crate::{ - constants::{QUALITYLESS_PRODUCT_NAME, QUALITY_DOWNLOAD_URIS}, + constants::{PRODUCT_DOWNLOAD_URL, QUALITY, QUALITYLESS_PRODUCT_NAME}, log, - options::{self, Quality}, state::{LauncherPaths, PersistedState}, update_service::Platform, util::errors::{AnyError, InvalidRequestedVersion}, @@ -26,34 +25,23 @@ use crate::{ #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)] #[serde(tag = "t", content = "c")] pub enum RequestedVersion { - Quality(options::Quality), - Version { - version: String, - quality: options::Quality, - }, - Commit { - commit: String, - quality: options::Quality, - }, + Default, + Commit(String), Path(String), } lazy_static! { - static ref SEMVER_RE: Regex = Regex::new(r"^\d+\.\d+\.\d+(-insider)?$").unwrap(); - static ref COMMIT_RE: Regex = Regex::new(r"^[a-z]+/[a-e0-f]{40}$").unwrap(); + static ref COMMIT_RE: Regex = Regex::new(r"^[a-e0-f]{40}$").unwrap(); } impl RequestedVersion { pub fn get_command(&self) -> String { match self { - RequestedVersion::Quality(quality) => { - format!("code version use {}", quality.get_machine_name()) + RequestedVersion::Default => { + format!("code version use {}", QUALITY) } - RequestedVersion::Version { version, .. } => { - format!("code version use {}", version) - } - RequestedVersion::Commit { commit, quality } => { - format!("code version use {}/{}", quality.get_machine_name(), commit) + RequestedVersion::Commit(commit) => { + format!("code version use {}/{}", QUALITY, commit) } RequestedVersion::Path(path) => { format!("code version use {}", path) @@ -65,12 +53,11 @@ impl RequestedVersion { impl std::fmt::Display for RequestedVersion { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { - RequestedVersion::Quality(quality) => write!(f, "{}", quality.get_capitalized_name()), - RequestedVersion::Version { version, .. } => { - write!(f, "{}", version) + RequestedVersion::Default => { + write!(f, "{}", QUALITY) } - RequestedVersion::Commit { commit, quality } => { - write!(f, "{}/{}", quality, commit) + RequestedVersion::Commit(commit) => { + write!(f, "{}/{}", QUALITY, commit) } RequestedVersion::Path(path) => write!(f, "{}", path), } @@ -81,19 +68,8 @@ impl TryFrom<&str> for RequestedVersion { type Error = InvalidRequestedVersion; fn try_from(s: &str) -> Result { - if let Ok(quality) = options::Quality::try_from(s) { - return Ok(RequestedVersion::Quality(quality)); - } - - if SEMVER_RE.is_match(s) { - return Ok(RequestedVersion::Version { - quality: if s.ends_with("-insider") { - options::Quality::Insiders - } else { - options::Quality::Stable - }, - version: s.to_string(), - }); + if s == QUALITY { + return Ok(RequestedVersion::Default); } if Path::is_absolute(&PathBuf::from(s)) { @@ -101,13 +77,7 @@ impl TryFrom<&str> for RequestedVersion { } if COMMIT_RE.is_match(s) { - let idx = s.find('/').expect("expected a /"); - if let Ok(quality) = options::Quality::try_from(&s[0..idx]) { - return Ok(RequestedVersion::Commit { - commit: s[idx + 1..].to_string(), - quality, - }); - } + return Ok(RequestedVersion::Commit(s.to_string())); } Err(InvalidRequestedVersion()) @@ -206,7 +176,7 @@ impl CodeVersionManager { .versions .get(stored.current) .map(|(v, _)| v.clone()) - .unwrap_or(RequestedVersion::Quality(options::Quality::Stable)) + .unwrap_or(RequestedVersion::Default) } /// Tries to get the entrypoint for the version, if one can be found. @@ -221,7 +191,7 @@ impl CodeVersionManager { // For simple quality requests, see if that's installed already on the system let candidates = match &version { - RequestedVersion::Quality(q) => match detect_installed_program(&self.log, *q) { + RequestedVersion::Default => match detect_installed_program(&self.log) { Ok(p) => p, Err(e) => { warning!(self.log, "error looking up installed applications: {}", e); @@ -254,8 +224,8 @@ pub fn prompt_to_install(version: &RequestedVersion) { QUALITYLESS_PRODUCT_NAME, version ); - if let RequestedVersion::Quality(quality) = version { - if let Some(uri) = QUALITY_DOWNLOAD_URIS.as_ref().and_then(|m| m.get(quality)) { + if let RequestedVersion::Default = version { + if let Some(uri) = PRODUCT_DOWNLOAD_URL { // todo: on some platforms, we may be able to help automate installation. For example, // we can unzip the app ourselves on macOS and on windows we can download and spawn the GUI installer #[cfg(target_os = "linux")] @@ -272,11 +242,12 @@ pub fn prompt_to_install(version: &RequestedVersion) { } #[cfg(target_os = "macos")] -fn detect_installed_program(log: &log::Logger, quality: Quality) -> io::Result> { +fn detect_installed_program(log: &log::Logger) -> io::Result> { + use crate::constants::PRODUCT_NAME_LONG; + // easy, fast detection for where apps are usually installed let mut probable = PathBuf::from("/Applications"); - let app_name = quality.get_long_name(); - probable.push(format!("{}.app", app_name)); + probable.push(format!("{}.app", PRODUCT_NAME_LONG)); if probable.exists() { probable.extend(["Contents/Resources", "app", "bin", "code"]); return Ok(vec![probable]); @@ -316,7 +287,7 @@ fn detect_installed_program(log: &log::Logger, quality: Quality) -> io::Result { - if line.starts_with(app_name) && line.ends_with(':') { + if line.starts_with(PRODUCT_NAME_LONG) && line.ends_with(':') { state = State::LookingForLocation; } } @@ -341,13 +312,13 @@ fn detect_installed_program(log: &log::Logger, quality: Quality) -> io::Result io::Result> { - use crate::constants::WIN32_APP_IDS; +fn detect_installed_program(_log: &log::Logger) -> io::Result> { + use crate::constants::{APPLICATION_NAME, WIN32_APP_IDS}; use winreg::enums::{HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE}; use winreg::RegKey; let mut output: Vec = vec![]; - let app_ids = match WIN32_APP_IDS.as_ref().and_then(|m| m.get(&quality)) { + let app_ids = match WIN32_APP_IDS.as_ref() { Some(ids) => ids, None => return Ok(output), }; @@ -381,7 +352,7 @@ fn detect_installed_program(_log: &log::Logger, quality: Quality) -> io::Result< [ location.as_str(), "bin", - &format!("{}.cmd", quality.get_application_name()), + &format!("{}.cmd", APPLICATION_NAME), ] .iter() .collect(), @@ -397,7 +368,9 @@ fn detect_installed_program(_log: &log::Logger, quality: Quality) -> io::Result< // Looks for the given binary name in the PATH, returning all candidate matches. // Based on https://github.dev/microsoft/vscode-js-debug/blob/7594d05518df6700df51771895fcad0ddc7f92f9/src/common/pathUtils.ts#L15 #[cfg(target_os = "linux")] -fn detect_installed_program(log: &log::Logger, quality: Quality) -> io::Result> { +fn detect_installed_program(log: &log::Logger) -> io::Result> { + use crate::constants::APPLICATION_NAME; + let path = match std::env::var("PATH") { Ok(p) => p, Err(e) => { @@ -406,11 +379,10 @@ fn detect_installed_program(log: &log::Logger, quality: Quality) -> io::Result continue, Ok(_) => {} @@ -471,97 +443,40 @@ mod tests { fn test_detect_installed_program() { // developers can run this test and debug output manually; VS Code will not // be installed in CI, so the test only makes sure it doesn't error out - let result = detect_installed_program(&log::Logger::test(), Quality::Insiders); + let result = detect_installed_program(&log::Logger::test()); println!("result: {:?}", result); assert!(result.is_ok()); } - #[test] - fn test_requested_version_parses() { - assert_eq!( - RequestedVersion::try_from("1.2.3").unwrap(), - RequestedVersion::Version { - quality: options::Quality::Stable, - version: "1.2.3".to_string(), - } - ); - - assert_eq!( - RequestedVersion::try_from("1.2.3-insider").unwrap(), - RequestedVersion::Version { - quality: options::Quality::Insiders, - version: "1.2.3-insider".to_string(), - } - ); - - assert_eq!( - RequestedVersion::try_from("stable").unwrap(), - RequestedVersion::Quality(options::Quality::Stable) - ); - - assert_eq!( - RequestedVersion::try_from("insiders").unwrap(), - RequestedVersion::Quality(options::Quality::Insiders) - ); - - assert_eq!( - RequestedVersion::try_from("insiders/92fd228156aafeb326b23f6604028d342152313b") - .unwrap(), - RequestedVersion::Commit { - commit: "92fd228156aafeb326b23f6604028d342152313b".to_string(), - quality: options::Quality::Insiders - } - ); - - assert_eq!( - RequestedVersion::try_from("stable/92fd228156aafeb326b23f6604028d342152313b").unwrap(), - RequestedVersion::Commit { - commit: "92fd228156aafeb326b23f6604028d342152313b".to_string(), - quality: options::Quality::Stable - } - ); - - let exe = std::env::current_exe() - .expect("expected to get exe") - .to_string_lossy() - .to_string(); - assert_eq!( - RequestedVersion::try_from(exe.as_str()).unwrap(), - RequestedVersion::Path(exe), - ); - } - #[tokio::test] async fn test_set_preferred_version() { let dir = make_multiple_vscode_install(); let lp = LauncherPaths::new_without_replacements(dir.path().to_owned()); let vm1 = CodeVersionManager::new(log::Logger::test(), &lp, Platform::LinuxARM64); - assert_eq!( - vm1.get_preferred_version(), - RequestedVersion::Quality(options::Quality::Stable) - ); + assert_eq!(vm1.get_preferred_version(), RequestedVersion::Default); vm1.set_preferred_version( - RequestedVersion::Quality(options::Quality::Exploration), + RequestedVersion::Commit("foobar".to_string()), dir.path().join("desktop/stable"), ) .await .expect("expected to store"); vm1.set_preferred_version( - RequestedVersion::Quality(options::Quality::Insiders), + RequestedVersion::Commit("foobar2".to_string()), dir.path().join("desktop/stable"), ) .await .expect("expected to store"); + assert_eq!( vm1.get_preferred_version(), - RequestedVersion::Quality(options::Quality::Insiders) + RequestedVersion::Commit("foobar2".to_string()), ); let vm2 = CodeVersionManager::new(log::Logger::test(), &lp, Platform::LinuxARM64); assert_eq!( vm2.get_preferred_version(), - RequestedVersion::Quality(options::Quality::Insiders) + RequestedVersion::Commit("foobar2".to_string()), ); } diff --git a/cli/src/options.rs b/cli/src/options.rs index 9423a6da92ecd..e37a718a49a44 100644 --- a/cli/src/options.rs +++ b/cli/src/options.rs @@ -7,7 +7,7 @@ use std::fmt; use serde::{Deserialize, Serialize}; -use crate::constants::{APPLICATION_NAME_MAP, PRODUCT_NAME_LONG_MAP, SERVER_NAME_MAP}; +use crate::constants::SERVER_NAME_MAP; #[derive(clap::ValueEnum, Copy, Clone, Debug, Hash, PartialEq, Eq, Serialize, Deserialize)] pub enum Quality { @@ -38,30 +38,12 @@ impl Quality { } } - /// Product long name - pub fn get_long_name(&self) -> &'static str { - PRODUCT_NAME_LONG_MAP - .as_ref() - .and_then(|m| m.get(self)) - .map(|s| s.as_str()) - .unwrap_or("Code - OSS") - } - - /// Product application name - pub fn get_application_name(&self) -> &'static str { - APPLICATION_NAME_MAP - .as_ref() - .and_then(|m| m.get(self)) - .map(|s| s.as_str()) - .unwrap_or("code") - } - /// Server application name pub fn server_entrypoint(&self) -> String { let mut server_name = SERVER_NAME_MAP .as_ref() .and_then(|m| m.get(self)) - .map(|s| s.as_str()) + .map(|s| s.server_application_name.as_str()) .unwrap_or("code-server-oss") .to_string(); diff --git a/cli/src/tunnels/legal.rs b/cli/src/tunnels/legal.rs index 84b72bf8e695f..676ccb7da55bf 100644 --- a/cli/src/tunnels/legal.rs +++ b/cli/src/tunnels/legal.rs @@ -6,9 +6,14 @@ use crate::constants::{IS_INTERACTIVE_CLI, PRODUCT_NAME_LONG}; use crate::state::{LauncherPaths, PersistedState}; use crate::util::errors::{AnyError, MissingLegalConsent}; use crate::util::input::prompt_yn; +use lazy_static::lazy_static; use serde::{Deserialize, Serialize}; -const LICENSE_TEXT: Option<&'static str> = option_env!("VSCODE_CLI_REMOTE_LICENSE_TEXT"); +lazy_static! { + static ref LICENSE_TEXT: Option> = + option_env!("VSCODE_CLI_SERVER_LICENSE").and_then(|s| serde_json::from_str(s).unwrap()); +} + const LICENSE_PROMPT: Option<&'static str> = option_env!("VSCODE_CLI_REMOTE_LICENSE_PROMPT"); #[derive(Clone, Default, Serialize, Deserialize)] @@ -20,8 +25,8 @@ pub fn require_consent( paths: &LauncherPaths, accept_server_license_terms: bool, ) -> Result<(), AnyError> { - match LICENSE_TEXT { - Some(t) => println!("{}", t.replace("\\n", "\r\n")), + match &*LICENSE_TEXT { + Some(t) => println!("{}", t.join("\r\n")), None => return Ok(()), } diff --git a/package.json b/package.json index b6f40a6fd9d17..2a1e2af40ea43 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "code-oss-dev", "version": "1.82.0", - "distro": "a94daa7ddfb25b11bd8f3376c01e30ff356d0a2b", + "distro": "32d09c1ac0a6f84901cd96b1f6f800f3f284fe36", "author": { "name": "Microsoft Corporation" },