forked from microsoft/vscode-python
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathexternalDependencies.ts
More file actions
162 lines (141 loc) · 5.65 KB
/
externalDependencies.ts
File metadata and controls
162 lines (141 loc) · 5.65 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
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
import * as fsapi from 'fs-extra';
import * as path from 'path';
import * as vscode from 'vscode';
import { ExecutionResult, SpawnOptions } from '../../common/process/types';
import { IExperimentService, IDisposable } from '../../common/types';
import { chain, iterable } from '../../common/utils/async';
import { normalizeFilename } from '../../common/utils/filesystem';
import { getOSType, OSType } from '../../common/utils/platform';
import { IServiceContainer } from '../../ioc/types';
import { plainExec, shellExec } from '../../common/process/rawProcessApis';
import { BufferDecoder } from '../../common/process/decoder';
let internalServiceContainer: IServiceContainer;
export function initializeExternalDependencies(serviceContainer: IServiceContainer): void {
internalServiceContainer = serviceContainer;
}
// processes
/**
* Specialized version of the more generic shellExecute function to use only in
* cases where we don't need to pass custom environment variables read from env
* files or execution options.
*/
export async function shellExecute(
command: string,
timeout: number,
disposables?: Set<IDisposable>,
): Promise<ExecutionResult<string>> {
return shellExec(command, { timeout }, undefined, disposables);
}
/**
* Specialized version of the more generic exec function to use only in
* cases where we don't need to pass custom environment variables read from
* env files.
*/
export async function exec(
file: string,
args: string[],
options: SpawnOptions = {},
disposables?: Set<IDisposable>,
): Promise<ExecutionResult<string>> {
return plainExec(file, args, options, new BufferDecoder(), undefined, disposables);
}
// filesystem
export function pathExists(absPath: string): Promise<boolean> {
return fsapi.pathExists(absPath);
}
export function readFile(filePath: string): Promise<string> {
return fsapi.readFile(filePath, 'utf-8');
}
/**
* Returns true if given file path exists within the given parent directory, false otherwise.
* @param filePath File path to check for
* @param parentPath The potential parent path to check for
*/
export function isParentPath(filePath: string, parentPath: string): boolean {
return normCasePath(filePath).startsWith(normCasePath(parentPath));
}
export async function isDirectory(filename: string): Promise<boolean> {
const stat = await fsapi.lstat(filename);
return stat.isDirectory();
}
export function normalizePath(filename: string): string {
return normalizeFilename(filename);
}
export function normCasePath(filePath: string): string {
return getOSType() === OSType.Windows ? path.normalize(filePath).toUpperCase() : path.normalize(filePath);
}
export function arePathsSame(path1: string, path2: string): boolean {
return normCasePath(path1) === normCasePath(path2);
}
export async function getFileInfo(filePath: string): Promise<{ ctime: number; mtime: number }> {
try {
const data = await fsapi.lstat(filePath);
return {
ctime: data.ctime.valueOf(),
mtime: data.mtime.valueOf(),
};
} catch (ex) {
// This can fail on some cases, such as, `reparse points` on windows. So, return the
// time as -1. Which we treat as not set in the extension.
return { ctime: -1, mtime: -1 };
}
}
export async function resolveSymbolicLink(absPath: string): Promise<string> {
const stats = await fsapi.lstat(absPath);
if (stats.isSymbolicLink()) {
const link = await fsapi.readlink(absPath);
return resolveSymbolicLink(link);
}
return absPath;
}
/**
* Returns full path to sub directories of a given directory.
* @param root
* @param resolveSymlinks
*/
export async function* getSubDirs(root: string, resolveSymlinks: boolean): AsyncIterableIterator<string> {
const dirContents = await fsapi.promises.readdir(root, { withFileTypes: true });
const generators = dirContents.map((item) => {
async function* generator() {
const fullPath = path.join(root, item.name);
if (item.isDirectory()) {
yield fullPath;
} else if (resolveSymlinks && item.isSymbolicLink()) {
// The current FS item is a symlink. It can potentially be a file
// or a directory. Resolve it first and then check if it is a directory.
const resolvedPath = await resolveSymbolicLink(fullPath);
const resolvedPathStat = await fsapi.lstat(resolvedPath);
if (resolvedPathStat.isDirectory()) {
yield resolvedPath;
}
}
}
return generator();
});
yield* iterable(chain(generators));
}
/**
* Returns the value for setting `python.<name>`.
* @param name The name of the setting.
*/
export function getPythonSetting<T>(name: string): T | undefined {
return vscode.workspace.getConfiguration('python').get(name);
}
/**
* Registers the listener to be called when a particular setting changes.
* @param name The name of the setting.
* @param callback The listener function to be called when the setting changes.
*/
export function onDidChangePythonSetting(name: string, callback: () => void): IDisposable {
return vscode.workspace.onDidChangeConfiguration((event: vscode.ConfigurationChangeEvent) => {
if (event.affectsConfiguration(`python.${name}`)) {
callback();
}
});
}
export function inExperiment(experiment: string): Promise<boolean> {
const experimentService = internalServiceContainer.get<IExperimentService>(IExperimentService);
return experimentService.inExperiment(experiment);
}