cli: cleanup build (#190213)

- Remove the `prepare` script entirely
- Variables are now populated from the product.json during build. Most
  variables are mapped automatically, with some special handling in a
	few cases. `build.rs` is now much more self-contained.
- Look for the `product.overrides.json` for vscode developers instead of
  looking for a peer `vscode-distro` folder

Fixes #178691
This commit is contained in:
Connor Peet 2023-08-10 20:14:30 -07:00 committed by GitHub
parent 2e9459b34c
commit 52840e3ca5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
16 changed files with 233 additions and 428 deletions

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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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

View file

@ -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 = <T>(m: (productJson: any, quality: string) => T): Record<string, T> => {
const output: Record<string, T> = {};
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();
}

View file

@ -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 }}

View file

@ -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 }}

View file

@ -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 }}

View file

@ -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]

View file

@ -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");
output
}
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");
fn set_env_vars_from_map_keys(prefix: &str, map: impl IntoIterator<Item = (String, Value)>) {
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::<Vec<(String, String)>>(&output.stdout)
.expect("expected to deserialize output");
for (key, value) in vars {
println!("cargo:rustc-env={}={}", key, value);
}
fn read_json_from_path<T>(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<String, Value> = 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::<PackageJson>(&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> {

View file

@ -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,

View file

@ -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<HashMap<Quality, Vec<String>>> =
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<HashMap<Quality, String>> =
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<HashMap<Quality, String>> =
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<HashMap<Quality, String>> =
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<HashMap<Quality, String>> =
option_env!("VSCODE_CLI_SERVER_NAME_MAP").and_then(|s| serde_json::from_str(s).unwrap());
pub static ref SERVER_NAME_MAP: Option<HashMap<Quality, ServerQualityInfo>> =
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<Vec<String>> =
option_env!("VSCODE_CLI_WIN32_APP_IDS").map(|s| s.split(',').map(|s| s.to_string()).collect());
}

View file

@ -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<Self, Self::Error> {
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<Vec<PathBuf>> {
fn detect_installed_program(log: &log::Logger) -> io::Result<Vec<PathBuf>> {
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<V
line = line.trim();
match state {
State::LookingForName => {
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<V
}
#[cfg(windows)]
fn detect_installed_program(_log: &log::Logger, quality: Quality) -> io::Result<Vec<PathBuf>> {
use crate::constants::WIN32_APP_IDS;
fn detect_installed_program(_log: &log::Logger) -> io::Result<Vec<PathBuf>> {
use crate::constants::{APPLICATION_NAME, WIN32_APP_IDS};
use winreg::enums::{HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE};
use winreg::RegKey;
let mut output: Vec<PathBuf> = 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<Vec<PathBuf>> {
fn detect_installed_program(log: &log::Logger) -> io::Result<Vec<PathBuf>> {
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<V
}
};
let name = quality.get_application_name();
let current_exe = std::env::current_exe().expect("expected to read current exe");
let mut output = vec![];
for dir in path.split(':') {
let target: PathBuf = [dir, name].iter().collect();
let target: PathBuf = [dir, APPLICATION_NAME].iter().collect();
match std::fs::canonicalize(&target) {
Ok(m) if m == current_exe => 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()),
);
}

View file

@ -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();

View file

@ -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<Vec<String>> =
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(()),
}

View file

@ -1,7 +1,7 @@
{
"name": "code-oss-dev",
"version": "1.82.0",
"distro": "a94daa7ddfb25b11bd8f3376c01e30ff356d0a2b",
"distro": "32d09c1ac0a6f84901cd96b1f6f800f3f284fe36",
"author": {
"name": "Microsoft Corporation"
},