forked from DonJayamanne/pythonVSCode
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Expand file tree
/
Copy pathlogger.ts
More file actions
89 lines (79 loc) · 3.64 KB
/
logger.ts
File metadata and controls
89 lines (79 loc) · 3.64 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
'use strict';
import { inject, injectable } from 'inversify';
import { traceLog } from '../../logging';
import { IWorkspaceService } from '../application/types';
import { isCI, isTestExecution } from '../constants';
import { getOSType, getUserHomeDir, OSType } from '../utils/platform';
import { IProcessLogger, SpawnOptions } from './types';
import { escapeRegExp } from 'lodash';
import { replaceAll } from '../stringUtils';
import { identifyShellFromShellPath } from '../terminal/shellDetectors/baseShellDetector';
import '../../common/extensions';
@injectable()
export class ProcessLogger implements IProcessLogger {
constructor(@inject(IWorkspaceService) private readonly workspaceService: IWorkspaceService) {}
public logProcess(fileOrCommand: string, args?: string[], options?: SpawnOptions) {
if (!isTestExecution() && isCI && process.env.UITEST_DISABLE_PROCESS_LOGGING) {
// Added to disable logging of process execution commands during UI Tests.
// Used only during UI Tests (hence this setting need not be exposed as a valid setting).
return;
}
let command = args
? [fileOrCommand, ...args].map((e) => e.trimQuotes().toCommandArgumentForPythonExt()).join(' ')
: fileOrCommand;
const info = [`> ${this.getDisplayCommands(command)}`];
if (options?.cwd) {
const cwd: string = typeof options?.cwd === 'string' ? options?.cwd : options?.cwd?.toString();
info.push(`cwd: ${this.getDisplayCommands(cwd)}`);
}
if (typeof options?.shell === 'string') {
info.push(`shell: ${identifyShellFromShellPath(options?.shell)}`);
}
info.forEach((line) => {
traceLog(line);
});
}
private getDisplayCommands(command: string): string {
if (this.workspaceService.workspaceFolders && this.workspaceService.workspaceFolders.length === 1) {
command = replaceMatchesWithCharacter(command, this.workspaceService.workspaceFolders[0].uri.fsPath, '.');
}
const home = getUserHomeDir();
if (home) {
command = replaceMatchesWithCharacter(command, home, '~');
}
return command;
}
}
/**
* Finds case insensitive matches in the original string and replaces it with character provided.
*/
function replaceMatchesWithCharacter(original: string, match: string, character: string): string {
// Backslashes, plus signs, brackets and other characters have special meaning in regexes,
// we need to escape using an extra backlash so it's not considered special.
function getRegex(match: string) {
let pattern = escapeRegExp(match);
if (getOSType() === OSType.Windows) {
// Match both forward and backward slash versions of 'match' for Windows.
pattern = replaceAll(pattern, '\\\\', '(\\\\|/)');
}
let regex = new RegExp(pattern, 'ig');
return regex;
}
function isPrevioustoMatchRegexALetter(chunk: string, index: number) {
return chunk[index].match(/[a-z]/);
}
let chunked = original.split(' ');
for (let i = 0; i < chunked.length; i++) {
let regex = getRegex(match);
const regexResult = regex.exec(chunked[i]);
if (regexResult) {
const regexIndex = regexResult.index;
if (regexIndex > 0 && isPrevioustoMatchRegexALetter(chunked[i], regexIndex - 1))
regex = getRegex(match.substring(1));
chunked[i] = chunked[i].replace(regex, character);
}
}
return chunked.join(' ');
}