Skip to content

Commit

Permalink
Merge pull request #120419 from microsoft/tyriar/profile_test
Browse files Browse the repository at this point in the history
Improve terminal profiles tests
  • Loading branch information
Tyriar authored Apr 3, 2021
2 parents 96eaf9d + 8be3c73 commit 94c9ea4
Show file tree
Hide file tree
Showing 4 changed files with 226 additions and 129 deletions.
4 changes: 2 additions & 2 deletions src/vs/platform/terminal/node/terminalEnvironment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import * as os from 'os';
import * as path from 'vs/base/common/path';
import * as process from 'vs/base/common/process';
import { exists } from 'vs/base/node/pfs';
import * as pfs from 'vs/base/node/pfs';
import { isString } from 'vs/base/common/types';
import { getCaseInsensitive } from 'vs/base/common/objects';
import { IProcessEnvironment, isWindows } from 'vs/base/common/platform';
Expand All @@ -20,7 +20,7 @@ export function getWindowsBuildNumber(): number {
return buildNumber;
}

export async function findExecutable(command: string, cwd?: string, paths?: string[], env: IProcessEnvironment = process.env as IProcessEnvironment): Promise<string | undefined> {
export async function findExecutable(command: string, cwd?: string, paths?: string[], env: IProcessEnvironment = process.env as IProcessEnvironment, exists: (path: string) => Promise<boolean> = pfs.exists): Promise<string | undefined> {
// If we have an absolute path then we take it.
if (path.isAbsolute(command)) {
return await exists(command) ? command : undefined;
Expand Down
2 changes: 1 addition & 1 deletion src/vs/workbench/api/node/extHostTerminalService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ export class ExtHostTerminalService extends BaseExtHostTerminalService {

public async $getAvailableProfiles(configuredProfilesOnly: boolean): Promise<ITerminalProfile[]> {
const config = await (await this._extHostConfiguration.getConfigProvider()).getConfiguration().get('terminal.integrated');
return detectAvailableProfiles(configuredProfilesOnly, this._logService, config as ITerminalConfiguration, await this._variableResolverPromise, this._lastActiveWorkspace);
return detectAvailableProfiles(configuredProfilesOnly, undefined, this._logService, config as ITerminalConfiguration, await this._variableResolverPromise, this._lastActiveWorkspace);
}

public async $getDefaultShellAndArgs(useAutomationShell: boolean): Promise<IShellAndArgsDto> {
Expand Down
42 changes: 26 additions & 16 deletions src/vs/workbench/contrib/terminal/node/terminalProfiles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,18 @@ import * as pfs from 'vs/base/node/pfs';

let profileSources: Map<string, IPotentialTerminalProfile> | undefined;

export function detectAvailableProfiles(configuredProfilesOnly: boolean, logService?: ILogService, config?: ITerminalConfiguration, variableResolver?: ExtHostVariableResolverService, workspaceFolder?: IWorkspaceFolder, statProvider?: IStatProvider, testPaths?: string[]): Promise<ITerminalProfile[]> {
return platform.isWindows ? detectAvailableWindowsProfiles(configuredProfilesOnly, statProvider, logService, config?.useWslProfiles, config?.profiles.windows, variableResolver, workspaceFolder) : detectAvailableUnixProfiles(statProvider, logService, configuredProfilesOnly, platform.isMacintosh ? config?.profiles.osx : config?.profiles.linux, testPaths, variableResolver, workspaceFolder);
export function detectAvailableProfiles(configuredProfilesOnly: boolean, fsProvider?: IFsProvider, logService?: ILogService, config?: ITerminalConfiguration, variableResolver?: ExtHostVariableResolverService, workspaceFolder?: IWorkspaceFolder, testPaths?: string[]): Promise<ITerminalProfile[]> {
fsProvider = fsProvider || {
existsFile: pfs.SymlinkSupport.existsFile,
readFile: fs.promises.readFile
};
if (platform.isWindows) {
return detectAvailableWindowsProfiles(configuredProfilesOnly, fsProvider, logService, config?.useWslProfiles, config?.profiles.windows, variableResolver, workspaceFolder);
}
return detectAvailableUnixProfiles(fsProvider, logService, configuredProfilesOnly, platform.isMacintosh ? config?.profiles.osx : config?.profiles.linux, testPaths, variableResolver, workspaceFolder);
}

async function detectAvailableWindowsProfiles(configuredProfilesOnly: boolean, statProvider?: IStatProvider, logService?: ILogService, useWslProfiles?: boolean, configProfiles?: { [key: string]: ITerminalProfileObject }, variableResolver?: ExtHostVariableResolverService, workspaceFolder?: IWorkspaceFolder): Promise<ITerminalProfile[]> {
async function detectAvailableWindowsProfiles(configuredProfilesOnly: boolean, fsProvider: IFsProvider, logService?: ILogService, useWslProfiles?: boolean, configProfiles?: { [key: string]: ITerminalProfileObject }, variableResolver?: ExtHostVariableResolverService, workspaceFolder?: IWorkspaceFolder): Promise<ITerminalProfile[]> {
// Determine the correct System32 path. We want to point to Sysnative
// when the 32-bit version of VS Code is running on a 64-bit machine.
// The reason for this is because PowerShell's important PSReadline
Expand Down Expand Up @@ -61,7 +68,7 @@ async function detectAvailableWindowsProfiles(configuredProfilesOnly: boolean, s

applyConfigProfilesToMap(configProfiles, detectedProfiles);

const resultProfiles: ITerminalProfile[] = await transformToTerminalProfiles(detectedProfiles.entries(), logService, statProvider, variableResolver, workspaceFolder);
const resultProfiles: ITerminalProfile[] = await transformToTerminalProfiles(detectedProfiles.entries(), fsProvider, logService, variableResolver, workspaceFolder);

if (!configuredProfilesOnly || (configuredProfilesOnly && useWslProfiles)) {
try {
Expand All @@ -77,7 +84,7 @@ async function detectAvailableWindowsProfiles(configuredProfilesOnly: boolean, s
return resultProfiles;
}

async function transformToTerminalProfiles(entries: IterableIterator<[string, ITerminalProfileObject]>, logService?: ILogService, statProvider?: IStatProvider, variableResolver?: ExtHostVariableResolverService, workspaceFolder?: IWorkspaceFolder): Promise<ITerminalProfile[]> {
async function transformToTerminalProfiles(entries: IterableIterator<[string, ITerminalProfileObject]>, fsProvider: IFsProvider, logService?: ILogService, variableResolver?: ExtHostVariableResolverService, workspaceFolder?: IWorkspaceFolder): Promise<ITerminalProfile[]> {
const resultProfiles: ITerminalProfile[] = [];
for (const [profileName, profile] of entries) {
if (profile === null) { continue; }
Expand All @@ -102,7 +109,8 @@ async function transformToTerminalProfiles(entries: IterableIterator<[string, IT
for (let i = 0; i < paths.length; i++) {
paths[i] = variableResolver?.resolve(workspaceFolder, paths[i]) || paths[i];
}
const validatedProfile = await validateProfilePaths(profileName, paths, statProvider, args, profile.overrideName, profile.isAutoDetected, logService);
const validatedProfile = await validateProfilePaths(profileName, paths, fsProvider, args, profile.overrideName, profile.isAutoDetected, logService);
console.log('validated', validatedProfile?.profileName + ' ' + validatedProfile?.path);
if (validatedProfile) {
validatedProfile.isAutoDetected = profile.isAutoDetected;
resultProfiles.push(validatedProfile);
Expand Down Expand Up @@ -201,12 +209,13 @@ async function getWslProfiles(wslPath: string, useWslProfiles?: boolean): Promis
return [];
}

async function detectAvailableUnixProfiles(statProvider?: IStatProvider, logService?: ILogService, configuredProfilesOnly?: boolean, configProfiles?: { [key: string]: ITerminalProfileObject }, testPaths?: string[], variableResolver?: ExtHostVariableResolverService, workspaceFolder?: IWorkspaceFolder): Promise<ITerminalProfile[]> {
async function detectAvailableUnixProfiles(fsProvider: IFsProvider, logService?: ILogService, configuredProfilesOnly?: boolean, configProfiles?: { [key: string]: ITerminalProfileObject }, testPaths?: string[], variableResolver?: ExtHostVariableResolverService, workspaceFolder?: IWorkspaceFolder): Promise<ITerminalProfile[]> {
const detectedProfiles: Map<string, ITerminalProfileObject> = new Map();

// Add non-quick launch profiles
if (!configuredProfilesOnly) {
const contents = await fs.promises.readFile('/etc/shells', 'utf8');
const contents = await fsProvider.readFile('/etc/shells', 'utf8');
console.log('contents:' + contents);
const profiles = testPaths || contents.split('\n').filter(e => e.trim().indexOf('#') !== 0 && e.trim().length > 0);
const counts: Map<string, number> = new Map();
for (const profile of profiles) {
Expand All @@ -223,7 +232,7 @@ async function detectAvailableUnixProfiles(statProvider?: IStatProvider, logServ

applyConfigProfilesToMap(configProfiles, detectedProfiles);

return await transformToTerminalProfiles(detectedProfiles.entries(), logService, statProvider, variableResolver, workspaceFolder);
return await transformToTerminalProfiles(detectedProfiles.entries(), fsProvider, logService, variableResolver, workspaceFolder);
}

function applyConfigProfilesToMap(configProfiles: { [key: string]: ITerminalProfileObject } | undefined, profilesMap: Map<string, ITerminalProfileObject>) {
Expand All @@ -239,13 +248,13 @@ function applyConfigProfilesToMap(configProfiles: { [key: string]: ITerminalProf
}
}

async function validateProfilePaths(profileName: string, potentialPaths: string[], statProvider?: IStatProvider, args?: string[] | string, overrideName?: boolean, isAutoDetected?: boolean, logService?: ILogService): Promise<ITerminalProfile | undefined> {
async function validateProfilePaths(profileName: string, potentialPaths: string[], fsProvider: IFsProvider, args?: string[] | string, overrideName?: boolean, isAutoDetected?: boolean, logService?: ILogService): Promise<ITerminalProfile | undefined> {
if (potentialPaths.length === 0) {
return Promise.resolve(undefined);
}
const path = potentialPaths.shift()!;
if (path === '') {
return validateProfilePaths(profileName, potentialPaths, statProvider, args, overrideName, isAutoDetected);
return validateProfilePaths(profileName, potentialPaths, fsProvider, args, overrideName, isAutoDetected);
}

const profile = { profileName, path, args, overrideName, isAutoDetected };
Expand All @@ -254,23 +263,24 @@ async function validateProfilePaths(profileName: string, potentialPaths: string[
if (basename(path) === path) {
// The executable isn't an absolute path, try find it on the PATH
const envPaths: string[] | undefined = process.env.PATH ? process.env.PATH.split(delimiter) : undefined;
const executable = await findExecutable(path, undefined, envPaths);
const executable = await findExecutable(path, undefined, envPaths, undefined, fsProvider.existsFile);
if (!executable) {
return validateProfilePaths(profileName, potentialPaths, statProvider, args);
return validateProfilePaths(profileName, potentialPaths, fsProvider, args);
}
return profile;
}

const result = statProvider ? await statProvider.existsFile(path) : await pfs.SymlinkSupport.existsFile(normalize(path));
const result = await fsProvider.existsFile(normalize(path));
if (result) {
return profile;
}

return validateProfilePaths(profileName, potentialPaths, statProvider, args, overrideName, isAutoDetected);
return validateProfilePaths(profileName, potentialPaths, fsProvider, args, overrideName, isAutoDetected);
}

export interface IStatProvider {
export interface IFsProvider {
existsFile(path: string): Promise<boolean>,
readFile(path: string, options: { encoding: BufferEncoding, flag?: string | number } | BufferEncoding): Promise<string>;
}

interface IPotentialTerminalProfile {
Expand Down
Loading

0 comments on commit 94c9ea4

Please sign in to comment.