From f10e84118baebec2bb2536d38987146fd5773c4c Mon Sep 17 00:00:00 2001 From: Martin Aeschlimann Date: Sun, 23 Oct 2022 19:12:23 +0200 Subject: [PATCH] ci: use tunnelApplicationName (#164257) fix location of tunnel command in CI and in code --- .../darwin/product-build-darwin.yml | 8 ++-- .../linux/product-build-linux-client.yml | 6 +-- .../win32/product-build-win32.yml | 10 ++--- cli/src/commands/args.rs | 4 ++ cli/src/commands/tunnels.rs | 4 +- cli/src/tunnels/legal.rs | 9 +++- src/vs/code/node/cli.ts | 2 +- .../environment/common/environment.ts | 3 ++ .../environment/common/environmentService.ts | 3 ++ .../electron-browser/remoteTunnelService.ts | 41 +++++++++++++++---- .../contrib/logs/common/logConstants.ts | 1 + .../contrib/logs/common/logs.contribution.ts | 1 + .../remoteTunnel.contribution.ts | 16 +++----- .../environment/browser/environmentService.ts | 3 ++ 14 files changed, 71 insertions(+), 40 deletions(-) diff --git a/build/azure-pipelines/darwin/product-build-darwin.yml b/build/azure-pipelines/darwin/product-build-darwin.yml index 6b75379a5d3..2c3c90f961f 100644 --- a/build/azure-pipelines/darwin/product-build-darwin.yml +++ b/build/azure-pipelines/darwin/product-build-darwin.yml @@ -203,11 +203,9 @@ steps: set -e ARCHIVE_NAME=$(ls "$(Build.ArtifactStagingDirectory)/cli" | head -n 1) unzip "$(Build.ArtifactStagingDirectory)/cli/$ARCHIVE_NAME" -d "$(Build.ArtifactStagingDirectory)/cli" - mv "$(Build.ArtifactStagingDirectory)/cli/code" "$(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)" - fi + CLI_APP_NAME=$(node -p "require(\"$(APP_PATH)/Contents/Resources/app/product.json\").tunnelApplicationName") + mv "$(Build.ArtifactStagingDirectory)/cli/code" "$(APP_PATH)/Contents/Resources/app/bin/$CLI_APP_NAME" + chmod +x "$(APP_PATH)/Contents/Resources/app/bin/$CLI_APP_NAME" displayName: Make CLI executable - ${{ if or(eq(parameters.VSCODE_RUN_UNIT_TESTS, true), eq(parameters.VSCODE_RUN_INTEGRATION_TESTS, true), eq(parameters.VSCODE_RUN_SMOKE_TESTS, true)) }}: diff --git a/build/azure-pipelines/linux/product-build-linux-client.yml b/build/azure-pipelines/linux/product-build-linux-client.yml index cc9d228280b..740a66b9dd9 100644 --- a/build/azure-pipelines/linux/product-build-linux-client.yml +++ b/build/azure-pipelines/linux/product-build-linux-client.yml @@ -282,10 +282,8 @@ steps: - script: | set -e 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 + CLI_APP_NAME=$(node -p "require(\"$(agent.builddirectory)/VSCode-linux-$(VSCODE_ARCH)/resources/app/product.json\").tunnelApplicationName") + mv $(Build.ArtifactStagingDirectory)/cli/code $(agent.builddirectory)/VSCode-linux-$(VSCODE_ARCH)/bin/$CLI_APP_NAME displayName: Make CLI executable - ${{ if or(eq(parameters.VSCODE_RUN_UNIT_TESTS, true), eq(parameters.VSCODE_RUN_INTEGRATION_TESTS, true), eq(parameters.VSCODE_RUN_SMOKE_TESTS, true)) }}: diff --git a/build/azure-pipelines/win32/product-build-win32.yml b/build/azure-pipelines/win32/product-build-win32.yml index 7b7f2f5cad8..9fad27e9fd7 100644 --- a/build/azure-pipelines/win32/product-build-win32.yml +++ b/build/azure-pipelines/win32/product-build-win32.yml @@ -219,13 +219,9 @@ steps: $ErrorActionPreference = "Stop" $ArtifactName = (gci -Path "$(Build.ArtifactStagingDirectory)/cli" | Select-Object -last 1).FullName 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") - { - Move-Item -Path "$(agent.builddirectory)/VSCode-win32-$(VSCODE_ARCH)/bin/code-tunnel.exe" -Destination "$(agent.builddirectory)/VSCode-win32-$(VSCODE_ARCH)/bin/code-tunnel-$(VSCODE_QUALITY).exe" - } - + $AppProductJson = Get-Content -Raw -Path "$(agent.builddirectory)\VSCode-win32-$(VSCODE_ARCH)\resources\app\product.json" | ConvertFrom-Json + $CliAppName = $AppProductJson.tunnelApplicationName + Move-Item -Path "$(Build.ArtifactStagingDirectory)/cli/code.exe" -Destination "$(agent.builddirectory)/VSCode-win32-$(VSCODE_ARCH)/bin/$CliAppName.exe" displayName: Move VS Code CLI - ${{ if eq(parameters.VSCODE_PUBLISH, true) }}: diff --git a/cli/src/commands/args.rs b/cli/src/commands/args.rs index f672fc5fc13..d2fdeaae822 100644 --- a/cli/src/commands/args.rs +++ b/cli/src/commands/args.rs @@ -554,6 +554,10 @@ pub struct TunnelServeArgs { /// Optional parent process id. If provided, the server will be stopped when the process of the given pid no longer exists #[clap(long, hide = true)] pub parent_process_id: Option, + + /// If set, the user accepts the server license terms and the server will be started without a user prompt. + #[clap(long)] + pub accept_server_license_terms: bool, } #[derive(Args, Debug, Clone)] diff --git a/cli/src/commands/tunnels.rs b/cli/src/commands/tunnels.rs index 3e332685a64..0dea7761d93 100644 --- a/cli/src/commands/tunnels.rs +++ b/cli/src/commands/tunnels.rs @@ -121,7 +121,7 @@ pub async fn service( .await?; // likewise for license consent - legal::require_consent(&ctx.paths)?; + legal::require_consent(&ctx.paths, false)?; let current_exe = std::env::current_exe().map_err(|e| wrap(e, "could not get current exe"))?; @@ -220,7 +220,7 @@ pub async fn serve(ctx: CommandContext, gateway_args: TunnelServeArgs) -> Result log, paths, args, .. } = ctx; - legal::require_consent(&paths)?; + legal::require_consent(&paths, gateway_args.accept_server_license_terms)?; let csa = (&args).into(); serve_with_csa(paths, log, gateway_args, csa, None).await diff --git a/cli/src/tunnels/legal.rs b/cli/src/tunnels/legal.rs index d675b10bdff..947fd07e4cd 100644 --- a/cli/src/tunnels/legal.rs +++ b/cli/src/tunnels/legal.rs @@ -15,12 +15,19 @@ struct PersistedConsent { pub consented: Option, } -pub fn require_consent(paths: &LauncherPaths) -> Result<(), AnyError> { +pub fn require_consent( + paths: &LauncherPaths, + accept_server_license_terms: bool, +) -> Result<(), AnyError> { match LICENSE_TEXT { Some(t) => println!("{}", t.replace("\\n", "\r\n")), None => return Ok(()), } + if accept_server_license_terms { + return Ok(()); + } + let prompt = match LICENSE_PROMPT { Some(p) => p, None => return Ok(()), diff --git a/src/vs/code/node/cli.ts b/src/vs/code/node/cli.ts index 9056d4f11c8..0207af243dc 100644 --- a/src/vs/code/node/cli.ts +++ b/src/vs/code/node/cli.ts @@ -61,7 +61,7 @@ export async function main(argv: string[]): Promise { } else { const tunnelCommand = join(dirname(process.execPath), 'bin', `${product.tunnelApplicationName}${isWindows ? '.exe' : ''}`); const tunnelArgs = argv.slice(3); - tunnelProcess = spawn(tunnelCommand, tunnelArgs); + tunnelProcess = spawn(tunnelCommand, ['tunnel', ...tunnelArgs]); } tunnelProcess.stdout.on('data', data => { console.log(data.toString()); diff --git a/src/vs/platform/environment/common/environment.ts b/src/vs/platform/environment/common/environment.ts index f41968d9b0e..2ec49007e19 100644 --- a/src/vs/platform/environment/common/environment.ts +++ b/src/vs/platform/environment/common/environment.ts @@ -69,6 +69,9 @@ export interface IEnvironmentService { editSessionId?: string; editSessionsLogResource: URI; + // remote tunnel + remoteTunnelLogResource: URI; + // --- extension development debugExtensionHost: IExtensionHostDebugParams; isExtensionDevelopment: boolean; diff --git a/src/vs/platform/environment/common/environmentService.ts b/src/vs/platform/environment/common/environmentService.ts index 17c18da90b4..cfbba68219b 100644 --- a/src/vs/platform/environment/common/environmentService.ts +++ b/src/vs/platform/environment/common/environmentService.ts @@ -85,6 +85,9 @@ export abstract class AbstractNativeEnvironmentService implements INativeEnviron @memoize get editSessionsLogResource(): URI { return URI.file(join(this.logsPath, 'editSessions.log')); } + @memoize + get remoteTunnelLogResource(): URI { return URI.file(join(this.logsPath, 'remoteTunnel.log')); } + @memoize get sync(): 'on' | 'off' | undefined { return this.args.sync; } diff --git a/src/vs/platform/remoteTunnel/electron-browser/remoteTunnelService.ts b/src/vs/platform/remoteTunnel/electron-browser/remoteTunnelService.ts index aca345c1cfd..785888f0615 100644 --- a/src/vs/platform/remoteTunnel/electron-browser/remoteTunnelService.ts +++ b/src/vs/platform/remoteTunnel/electron-browser/remoteTunnelService.ts @@ -13,13 +13,12 @@ import { URI } from 'vs/base/common/uri'; import { dirname, join } from 'vs/base/common/path'; import { ChildProcess, spawn } from 'child_process'; import { IProductService } from 'vs/platform/product/common/productService'; -import { isWindows } from 'vs/base/common/platform'; +import { isMacintosh, isWindows } from 'vs/base/common/platform'; import { CancelablePromise, createCancelablePromise, Delayer } from 'vs/base/common/async'; import { ISharedProcessLifecycleService } from 'vs/platform/lifecycle/electron-browser/sharedProcessLifecycleService'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { localize } from 'vs/nls'; - -import { hostname } from 'os'; +import { hostname, homedir } from 'os'; type RemoteTunnelEnablementClassification = { owner: 'aeschli'; @@ -56,6 +55,8 @@ export class RemoteTunnelService extends Disposable implements IRemoteTunnelServ private _tunnelStatus: TunnelStatus = TunnelStates.disconnected; private _startTunnelProcessDelayer: Delayer; + private _tunnelCommand: string | undefined; + constructor( @ITelemetryService private readonly telemetryService: ITelemetryService, @IProductService private readonly productService: IProductService, @@ -65,8 +66,7 @@ export class RemoteTunnelService extends Disposable implements IRemoteTunnelServ @IConfigurationService private readonly configurationService: IConfigurationService ) { super(); - const logFileUri = URI.file(join(dirname(environmentService.logsPath), 'remoteTunnel.log')); - this._logger = this._register(loggerService.createLogger(logFileUri, { name: 'remoteTunnel' })); + this._logger = this._register(loggerService.createLogger(environmentService.remoteTunnelLogResource, { name: 'remoteTunnel' })); this._startTunnelProcessDelayer = new Delayer(100); this._register(sharedProcessLifecycleService.onWillShutdown(e => { @@ -103,7 +103,25 @@ export class RemoteTunnelService extends Disposable implements IRemoteTunnelServ this._logger.error(e); } } + } + private getTunnelCommandLocation() { + if (!this._tunnelCommand) { + let binParentLocation; + if (isMacintosh) { + // appRoot = /Applications/Visual Studio Code - Insiders.app/Contents/Resources/app + // bin = /Applications/Visual Studio Code - Insiders.app/Contents/Resources/app/bin + binParentLocation = this.environmentService.appRoot; + } else { + // appRoot = C:\Users\\AppData\Local\Programs\Microsoft VS Code Insiders\resources\app + // bin = C:\Users\\AppData\Local\Programs\Microsoft VS Code Insiders\bin + // appRoot = /usr/share/code-insiders/resources/app + // bin = /usr/share/code-insiders/bin + binParentLocation = dirname(dirname(this.environmentService.appRoot)); + } + this._tunnelCommand = join(binParentLocation, 'bin', `${this.productService.tunnelApplicationName}${isWindows ? '.exe' : ''}`); + } + return this._tunnelCommand; } private async updateTunnelProcess(): Promise { @@ -130,7 +148,7 @@ export class RemoteTunnelService extends Disposable implements IRemoteTunnelServ this.setTunnelStatus(TunnelStates.disconnected); return; } - const args = ['--parent-process-id', String(process.pid)]; + const args = ['--parent-process-id', String(process.pid), '--accept-server-license-terms']; const hostName = this.getHostName(); if (hostName) { args.push('--name', hostName); @@ -183,13 +201,18 @@ export class RemoteTunnelService extends Disposable implements IRemoteTunnelServ tunnelProcess.kill(); } }); + this._logger.info(`${logLabel} appRoot ${this.environmentService.appRoot}`); + this._logger.info(`${logLabel} process.execPath ${process.execPath}`); + if (process.env['VSCODE_DEV']) { + onOutput('Compiling tunnel CLI from sources and run', false); this._logger.info(`${logLabel} Spawning: cargo run -- tunnel ${commandArgs.join(' ')}`); tunnelProcess = spawn('cargo', ['run', '--', 'tunnel', ...commandArgs], { cwd: join(this.environmentService.appRoot, 'cli') }); } else { - const tunnelCommand = join(dirname(process.execPath), 'bin', `${this.productService.tunnelApplicationName}${isWindows ? '.exe' : ''}`); - this._logger.info(`${logLabel} Spawning: ${tunnelCommand} ${commandArgs.join(' ')}`); - tunnelProcess = spawn(tunnelCommand, ['tunnel', ...commandArgs]); + onOutput('Running tunnel CLI', false); + const tunnelCommand = this.getTunnelCommandLocation(); + this._logger.info(`${logLabel} Spawning: ${tunnelCommand} tunnel ${commandArgs.join(' ')}`); + tunnelProcess = spawn(tunnelCommand, ['tunnel', ...commandArgs], { cwd: homedir() }); } tunnelProcess.stdout!.on('data', data => { diff --git a/src/vs/workbench/contrib/logs/common/logConstants.ts b/src/vs/workbench/contrib/logs/common/logConstants.ts index a9869d06fc7..49139de524d 100644 --- a/src/vs/workbench/contrib/logs/common/logConstants.ts +++ b/src/vs/workbench/contrib/logs/common/logConstants.ts @@ -10,6 +10,7 @@ export const telemetryLogChannelId = 'telemetryLog'; export const extensionTelemetryLogChannelId = 'extensionTelemetryLog'; export const userDataSyncLogChannelId = 'userDataSyncLog'; export const editSessionsLogChannelId = 'editSessionsSyncLog'; +export const remoteTunnelLogChannelId = 'remoteTunnelLog'; export const remoteServerLog = 'remoteServerLog'; export const remotePtyHostLog = 'remotePtyHostLog'; diff --git a/src/vs/workbench/contrib/logs/common/logs.contribution.ts b/src/vs/workbench/contrib/logs/common/logs.contribution.ts index ee34e86d564..e5348d71050 100644 --- a/src/vs/workbench/contrib/logs/common/logs.contribution.ts +++ b/src/vs/workbench/contrib/logs/common/logs.contribution.ts @@ -50,6 +50,7 @@ class LogOutputChannels extends Disposable implements IWorkbenchContribution { private registerCommonContributions(): void { this.registerLogChannel(Constants.userDataSyncLogChannelId, nls.localize('userDataSyncLog', "Settings Sync"), this.environmentService.userDataSyncLogResource); this.registerLogChannel(Constants.editSessionsLogChannelId, nls.localize('editSessionsLog', "Edit Sessions"), this.environmentService.editSessionsLogResource); + this.registerLogChannel(Constants.remoteTunnelLogChannelId, nls.localize('remoteTunnelLog', "Remote Tunnel"), this.environmentService.remoteTunnelLogResource); this.registerLogChannel(Constants.rendererLogChannelId, nls.localize('rendererLog', "Window"), this.environmentService.logFile); const registerTelemetryChannel = () => { diff --git a/src/vs/workbench/contrib/remoteTunnel/electron-sandbox/remoteTunnel.contribution.ts b/src/vs/workbench/contrib/remoteTunnel/electron-sandbox/remoteTunnel.contribution.ts index 9ede9481e33..ae5a2fc13be 100644 --- a/src/vs/workbench/contrib/remoteTunnel/electron-sandbox/remoteTunnel.contribution.ts +++ b/src/vs/workbench/contrib/remoteTunnel/electron-sandbox/remoteTunnel.contribution.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { Disposable, DisposableStore, toDisposable } from 'vs/base/common/lifecycle'; +import { Disposable, DisposableStore } from 'vs/base/common/lifecycle'; import { Action2, MenuId, registerAction2 } from 'vs/platform/actions/common/actions'; import { IProductService } from 'vs/platform/product/common/productService'; import { CONFIGURATION_KEY_HOST_NAME, CONFIGURATION_KEY_PREFIX, ConnectionInfo, IRemoteTunnelService } from 'vs/platform/remoteTunnel/common/remoteTunnel'; @@ -18,12 +18,10 @@ import { IDialogService } from 'vs/platform/dialogs/common/dialogs'; import { IStorageService, IStorageValueChangeEvent, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage'; import { ILogger, ILoggerService, ILogService } from 'vs/platform/log/common/log'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; -import { URI } from 'vs/base/common/uri'; -import { join } from 'vs/base/common/path'; import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; import { IStringDictionary } from 'vs/base/common/collections'; import { IQuickInputService, IQuickPickItem, IQuickPickSeparator, QuickPickItem } from 'vs/platform/quickinput/common/quickInput'; -import { IOutputService, registerLogChannel } from 'vs/workbench/services/output/common/output'; +import { IOutputService } from 'vs/workbench/services/output/common/output'; import { IFileService } from 'vs/platform/files/common/files'; import { IConfigurationRegistry, Extensions as ConfigurationExtensions, ConfigurationScope } from 'vs/platform/configuration/common/configurationRegistry'; import { IProgress, IProgressService, IProgressStep, ProgressLocation } from 'vs/platform/progress/common/progress'; @@ -34,6 +32,7 @@ import { IPreferencesService } from 'vs/workbench/services/preferences/common/pr import { IOpenerService } from 'vs/platform/opener/common/opener'; import { Action } from 'vs/base/common/actions'; import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService'; +import * as Constants from 'vs/workbench/contrib/logs/common/logConstants'; export const REMOTE_TUNNEL_CATEGORY: ILocalizedString = { original: 'Remote Tunnels', @@ -102,12 +101,7 @@ export class RemoteTunnelWorkbenchContribution extends Disposable implements IWo ) { super(); - const logPathURI = URI.file(join(environmentService.logsPath, 'remoteTunnel.log')); - - this.logger = this._register(loggerService.createLogger(logPathURI, { name: 'remoteTunnel' })); - - const promise = registerLogChannel('remoteTunnel', localize('remoteTunnel.outputTitle', "Remote Tunnel"), logPathURI, fileService, logService); - this._register(toDisposable(() => promise.cancel())); + this.logger = this._register(loggerService.createLogger(environmentService.remoteTunnelLogResource, { name: 'remoteTunnel' })); this.connectionStateContext = REMOTE_TUNNEL_CONNECTION_STATE.bindTo(this.contextKeyService); @@ -536,7 +530,7 @@ export class RemoteTunnelWorkbenchContribution extends Disposable implements IWo async run(accessor: ServicesAccessor) { const outputService = accessor.get(IOutputService); - outputService.showChannel('remoteTunnel'); + outputService.showChannel(Constants.remoteServerLog); } })); diff --git a/src/vs/workbench/services/environment/browser/environmentService.ts b/src/vs/workbench/services/environment/browser/environmentService.ts index 0f3e507ebb0..ef92b132b21 100644 --- a/src/vs/workbench/services/environment/browser/environmentService.ts +++ b/src/vs/workbench/services/environment/browser/environmentService.ts @@ -111,6 +111,9 @@ export class BrowserWorkbenchEnvironmentService implements IBrowserWorkbenchEnvi @memoize get editSessionsLogResource(): URI { return joinPath(this.logsHome, 'editSessions.log'); } + @memoize + get remoteTunnelLogResource(): URI { return joinPath(this.logsHome, 'remoteTunnel.log'); } + @memoize get sync(): 'on' | 'off' | undefined { return undefined; }