microsoft/vscode-react-native

Public

mirrored fromhttps://github.com/microsoft/vscode-react-nativeAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
df4bce4041caa61af1460ef87f2380820508a455

Branches

Tags

  • No tags available.
0Branches0Tags
Go to file
Add file
Code

Clone

HTTPS

Download ZIP

src/common/node/fileSystem.ts

236lines · modecode

1// Copyright (c) Microsoft Corporation. All rights reserved.
2// Licensed under the MIT license. See LICENSE file in the project root for details.
3
4import * as nodeFs from "fs";
5import * as path from "path";
6import * as Q from "q";
7
8export class FileSystem {
9 private fs: typeof nodeFs;
10
11 constructor({ fs = nodeFs } = {}) {
12 this.fs = fs;
13 }
14
15 public ensureDirectory(dir: string): Q.Promise<void> {
16 return Q.nfcall(this.fs.stat, dir).then((stat: nodeFs.Stats): void => {
17 if (stat.isDirectory()) {
18 return;
19 }
20 throw new Error(`Expected ${dir} to be a directory`);
21 }, (err: Error & { code?: string }): Q.Promise<any> => {
22 if (err && err.code === "ENOENT") {
23 return Q.nfcall(this.fs.mkdir, dir);
24 }
25 throw err;
26 });
27 }
28
29 public ensureFileWithContents(file: string, contents: string): Q.Promise<void> {
30 return Q.nfcall(this.fs.stat, file).then((stat: nodeFs.Stats) => {
31 if (!stat.isFile()) {
32 throw new Error(`Expected ${file} to be a file`);
33 }
34
35 return this.readFile(file).then(existingContents => {
36 if (contents !== existingContents) {
37 return this.writeFile(file, contents);
38 }
39 });
40 }, (err: Error & { code?: string }): Q.Promise<any> => {
41 if (err && err.code === "ENOENT") {
42 return Q.nfcall(this.fs.writeFile, file, contents);
43 }
44 throw err;
45 });
46 }
47
48 /**
49 * Helper function to check if a file or directory exists
50 */
51 public existsSync(filename: string) {
52 try {
53 this.fs.statSync(filename);
54 return true;
55 } catch (error) {
56 return false;
57 }
58 }
59
60 /**
61 * Helper (asynchronous) function to check if a file or directory exists
62 */
63 public exists(filename: string): Q.Promise<boolean> {
64 return Q.nfcall(this.fs.stat, filename)
65 .then(function() {
66 return Q.resolve(true);
67 })
68 .catch(function(err) {
69 return Q.resolve(false);
70 });
71 }
72
73 /**
74 * Helper async function to read the contents of a directory
75 */
76 public readDir(directory: string): Q.Promise<string[]> {
77 return Q.nfcall<string[]>(this.fs.readdir, directory);
78 }
79
80 /**
81 * Helper (synchronous) function to create a directory recursively
82 */
83 public makeDirectoryRecursiveSync(dirPath: string): void {
84 let parentPath = path.dirname(dirPath);
85 if (!this.existsSync(parentPath)) {
86 this.makeDirectoryRecursiveSync(parentPath);
87 }
88
89 this.fs.mkdirSync(dirPath);
90 }
91
92 /**
93 * Helper function to asynchronously copy a file
94 */
95 public copyFile(from: string, to: string, encoding?: string): Q.Promise<void> {
96 let deferred: Q.Deferred<void> = Q.defer<void>();
97 let destFile: nodeFs.WriteStream = this.fs.createWriteStream(to, { encoding: encoding });
98 let srcFile: nodeFs.ReadStream = this.fs.createReadStream(from, { encoding: encoding });
99 destFile.on("finish", function(): void {
100 deferred.resolve(void 0);
101 });
102
103 destFile.on("error", function(e: Error): void {
104 deferred.reject(e);
105 });
106
107 srcFile.on("error", function(e: Error): void {
108 deferred.reject(e);
109 });
110
111 srcFile.pipe(destFile);
112 return deferred.promise;
113 }
114
115 public deleteFileIfExistsSync(filename: string) {
116 if (this.existsSync(filename)) {
117 this.fs.unlinkSync(filename);
118 }
119 }
120
121 public readFile(filename: string, encoding: string = "utf8"): Q.Promise<string> {
122 return Q.nfcall<string>(this.fs.readFile, filename, encoding);
123 }
124
125 public writeFile(filename: string, data: any): Q.Promise<void> {
126 return Q.nfcall<void>(this.fs.writeFile, filename, data);
127 }
128
129 public unlink(filename: string): Q.Promise<void> {
130 return Q.nfcall<void>(this.fs.unlink, filename);
131 }
132
133 public findFilesByExtension(folder: string, extension: string): Q.Promise<string[]> {
134 return Q.nfcall(this.fs.readdir, folder).then((files: string[]) => {
135 const extFiles = files.filter((file: string) => path.extname(file) === `.${extension}`);
136 if (extFiles.length === 0) {
137 throw new Error(`Unable to find any ${extension} files.`);
138 }
139 return extFiles;
140 });
141 }
142
143 public mkDir(p: string): Q.Promise<void> {
144 return Q.nfcall<void>(this.fs.mkdir, p);
145 }
146
147 public stat(path: string): Q.Promise<nodeFs.Stats> {
148 return Q.nfcall<nodeFs.Stats>(this.fs.stat, path);
149 }
150
151 public directoryExists(directoryPath: string): Q.Promise<boolean> {
152 return this.stat(directoryPath).then(stats => {
153 return stats.isDirectory();
154 }).catch(reason => {
155 return reason.code === "ENOENT"
156 ? false
157 : Q.reject<boolean>(reason);
158 });
159 }
160
161
162 /**
163 * Delete 'dirPath' if it's an empty folder. If not fail.
164 *
165 * @param {dirPath} path to the folder
166 * @returns {void} Nothing
167 */
168 public rmdir(dirPath: string): Q.Promise<void> {
169 return Q.nfcall<void>(this.fs.rmdir, dirPath);
170 }
171
172 /**
173 * Recursively copy 'source' to 'target' asynchronously
174 *
175 * @param {string} source Location to copy from
176 * @param {string} target Location to copy to
177 * @returns {Q.Promise} A promise which is fulfilled when the copy completes, and is rejected on error
178 */
179 public copyRecursive(source: string, target: string): Q.Promise<void> {
180 return Q.nfcall<nodeFs.Stats>(this.fs.stat, source).then(stats => {
181 if (stats.isDirectory()) {
182 return this.exists(target).then(exists => {
183 if (!exists) {
184 return Q.nfcall<void>(this.fs.mkdir, target);
185 }
186 })
187 .then(() => {
188 return Q.nfcall<string[]>(this.fs.readdir, source);
189 })
190 .then(contents => {
191 Q.all(contents.map((childPath: string): Q.Promise<void> => {
192 return this.copyRecursive(path.join(source, childPath), path.join(target, childPath));
193 }));
194 });
195 } else {
196 return this.copyFile(source, target);
197 }
198 });
199 }
200
201 public removePathRecursivelyAsync(p: string): Q.Promise<void> {
202 return this.exists(p).then(exists => {
203 if (exists) {
204 return Q.nfcall<nodeFs.Stats>(this.fs.stat, p).then((stats: nodeFs.Stats) => {
205 if (stats.isDirectory()) {
206 return Q.nfcall<string[]>(this.fs.readdir, p).then((childPaths: string[]) => {
207 let result = Q<void>(void 0);
208 childPaths.forEach(childPath =>
209 result = result.then<void>(() => this.removePathRecursivelyAsync(path.join(p, childPath))));
210 return result;
211 }).then(() =>
212 Q.nfcall<void>(this.fs.rmdir, p));
213 } else {
214 /* file */
215 return Q.nfcall<void>(this.fs.unlink, p);
216 }
217 });
218 }
219 });
220 }
221
222 public removePathRecursivelySync(p: string): void {
223 if (this.fs.existsSync(p)) {
224 let stats = this.fs.statSync(p);
225 if (stats.isDirectory()) {
226 let contents = this.fs.readdirSync(p);
227 contents.forEach(childPath =>
228 this.removePathRecursivelySync(path.join(p, childPath)));
229 this.fs.rmdirSync(p);
230 } else {
231 /* file */
232 this.fs.unlinkSync(p);
233 }
234 }
235 }
236}
237