/
fsUtils.ts
177 lines (154 loc) · 4.04 KB
/
fsUtils.ts
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
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
/*---------------------------------------------------------
* Copyright (C) Microsoft Corporation. All rights reserved.
*--------------------------------------------------------*/
import * as fs from 'fs';
import * as util from 'util';
import { FsPromises } from '../ioc-extras';
import Dap from '../dap/api';
export const fsModule = fs;
/**
* Returns whether the user can access the given file path.
*/
export async function canAccess({ access }: FsPromises, file: string | undefined | null) {
if (!file) {
return false;
}
try {
await access(file);
return true;
} catch (e) {
return false;
}
}
/**
* Returns whether the user can access the given file path.
*/
export async function existsInjected(
{ stat }: FsPromises,
file: string | undefined | null,
): Promise<fs.Stats | undefined> {
if (!file) {
return;
}
try {
return await stat(file);
} catch (e) {
return;
}
}
/**
* Returns the file path exists without derefencing symblinks.
*/
export async function existsWithoutDeref(
{ lstat }: FsPromises,
file: string | undefined | null,
): Promise<fs.Stats | undefined> {
if (!file) {
return;
}
try {
return await lstat(file);
} catch (e) {
return;
}
}
/**
* Moves the file from the source to destination.
*/
export async function moveFile(
{ copyFile, rename, unlink }: FsPromises,
src: string,
dest: string,
) {
try {
await rename(src, dest);
} catch {
await copyFile(src, dest);
await unlink(src);
}
}
export function stat(path: string): Promise<fs.Stats | undefined> {
return new Promise(cb => {
fs.stat(path, (err, stat) => {
return cb(err ? undefined : stat);
});
});
}
export function readdir(path: string): Promise<string[]> {
return new Promise(cb => {
fs.readdir(path, 'utf8', async (err, entries) => {
cb(err ? [] : entries);
});
});
}
export function readfile(path: string): Promise<string> {
return new Promise(cb => {
fs.readFile(path, 'utf8', async (err, content) => {
cb(err ? '' : content);
});
});
}
export const writeFile = util.promisify(fs.writeFile);
export function readFileRaw(path: string): Promise<Buffer> {
return fs.promises.readFile(path).catch(() => Buffer.alloc(0));
}
export interface IFsUtils {
exists(path: string): Promise<boolean>;
}
export class LocalFsUtils implements IFsUtils {
public constructor(private readonly fs: FsPromises) {}
public async exists(path: string): Promise<boolean> {
// Check if the file exists in the current directory.
try {
await this.fs.access(path, fs.constants.F_OK);
return true;
} catch {
return false;
}
}
}
export class RemoteFsThroughDapUtils implements IFsUtils {
public constructor(private readonly dap: Dap.Api) {}
public async exists(path: string): Promise<boolean> {
try {
// Custom request
const { doesExists } = await this.dap.remoteFileExistsRequest({
localFilePath: path,
});
return doesExists;
} catch {
return false;
}
}
}
/**
* Notes: remoteFilePrefix = '' // will do all fs operations thorugh DAP requests
* remoteFilePrefix = undefined // will do all operations thorugh Local Node.fs
*/
export class LocalAndRemoteFsUtils implements IFsUtils {
private constructor(
private readonly remoteFilePrefix: string,
private readonly localFsUtils: IFsUtils,
private readonly remoteFsUtils: IFsUtils,
) {}
public static create(
remoteFilePrefix: string | undefined,
fsPromises: FsPromises,
dap: Dap.Api,
): IFsUtils {
const localFsUtils = new LocalFsUtils(fsPromises);
if (remoteFilePrefix !== undefined) {
return new this(remoteFilePrefix, localFsUtils, new RemoteFsThroughDapUtils(dap));
} else {
return localFsUtils;
}
}
public async exists(path: string): Promise<boolean> {
return (this.shouldUseRemoteFileSystem(path) ? this.remoteFsUtils : this.localFsUtils).exists(
path,
);
}
public shouldUseRemoteFileSystem(path: string) {
return path.startsWith(this.remoteFilePrefix);
}
}