microsoft/vscode-react-native

Public

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

CodeCommitsIssuesPull requestsActionsInsightsSecurity
efbe1ba61ca71887b3fa9a2d1ae3afb9a78cb87e

Branches

Tags

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

Clone

HTTPS

Download ZIP

src/common/node/fileSystem.ts

227lines · 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 return Q.resolve(void 0);
40 });
41 }, (err: Error & { code?: string }): Q.Promise<any> => {
42 if (err && err.code === "ENOENT") {
43 return Q.nfcall(this.fs.writeFile, file, contents);
44 }
45 throw err;
46 });
47 }
48
49 /**
50 * Helper function to check if a file or directory exists
51 */
52 public existsSync(filename: string) {
53 try {
54 this.fs.statSync(filename);
55 return true;
56 } catch (error) {
57 return false;
58 }
59 }
60
61 /**
62 * Helper (asynchronous) function to check if a file or directory exists
63 */
64 public exists(filename: string): Q.Promise<boolean> {
65 return Q.nfcall(this.fs.stat, filename)
66 .then(function() {
67 return Q.resolve(true);
68 })
69 .catch(function(err) {
70 return Q.resolve(false);
71 });
72 }
73
74 /**
75 * Helper async function to read the contents of a directory
76 */
77 public readDir(directory: string): Q.Promise<string[]> {
78 return Q.nfcall<string[]>(this.fs.readdir, directory);
79 }
80
81 /**
82 * Helper (synchronous) function to create a directory recursively
83 */
84 public makeDirectoryRecursiveSync(dirPath: string): void {
85 let parentPath = path.dirname(dirPath);
86 if (!this.existsSync(parentPath)) {
87 this.makeDirectoryRecursiveSync(parentPath);
88 }
89
90 this.fs.mkdirSync(dirPath);
91 }
92
93 /**
94 * Helper function to asynchronously copy a file
95 */
96 public copyFile(from: string, to: string, encoding?: string): Q.Promise<void> {
97 let deferred: Q.Deferred<void> = Q.defer<void>();
98 let destFile: nodeFs.WriteStream = this.fs.createWriteStream(to, { encoding: encoding });
99 let srcFile: nodeFs.ReadStream = this.fs.createReadStream(from, { encoding: encoding });
100 destFile.on("finish", function(): void {
101 deferred.resolve(void 0);
102 });
103
104 destFile.on("error", function(e: Error): void {
105 deferred.reject(e);
106 });
107
108 srcFile.on("error", function(e: Error): void {
109 deferred.reject(e);
110 });
111
112 srcFile.pipe(destFile);
113 return deferred.promise;
114 }
115
116 public deleteFileIfExistsSync(filename: string) {
117 if (this.existsSync(filename)) {
118 this.fs.unlinkSync(filename);
119 }
120 }
121
122 public readFile(filename: string, encoding: string = "utf8"): Q.Promise<string> {
123 return Q.nfcall<string>(this.fs.readFile, filename, encoding);
124 }
125
126 public writeFile(filename: string, data: any): Q.Promise<void> {
127 return Q.nfcall<void>(this.fs.writeFile, filename, data);
128 }
129
130 public unlink(filename: string): Q.Promise<void> {
131 return Q.nfcall<void>(this.fs.unlink, filename);
132 }
133
134 public mkDir(p: string): Q.Promise<void> {
135 return Q.nfcall<void>(this.fs.mkdir, p);
136 }
137
138 public stat(fsPath: string): Q.Promise<nodeFs.Stats> {
139 return Q.nfcall<nodeFs.Stats>(this.fs.stat, fsPath);
140 }
141
142 public directoryExists(directoryPath: string): Q.Promise<boolean> {
143 return this.stat(directoryPath).then(stats => {
144 return stats.isDirectory();
145 }).catch(reason => {
146 return reason.code === "ENOENT"
147 ? false
148 : Q.reject<boolean>(reason);
149 });
150 }
151
152
153 /**
154 * Delete 'dirPath' if it's an empty folder. If not fail.
155 *
156 * @param {dirPath} path to the folder
157 * @returns {void} Nothing
158 */
159 public rmdir(dirPath: string): Q.Promise<void> {
160 return Q.nfcall<void>(this.fs.rmdir, dirPath);
161 }
162
163 /**
164 * Recursively copy 'source' to 'target' asynchronously
165 *
166 * @param {string} source Location to copy from
167 * @param {string} target Location to copy to
168 * @returns {Q.Promise} A promise which is fulfilled when the copy completes, and is rejected on error
169 */
170 public copyRecursive(source: string, target: string): Q.Promise<void> {
171 return Q.nfcall<nodeFs.Stats>(this.fs.stat, source).then(stats => {
172 if (stats.isDirectory()) {
173 return this.exists(target)
174 .then(exists => {
175 return exists ? void 0 : Q.nfcall<void>(this.fs.mkdir, target);
176 })
177 .then(() => {
178 return Q.nfcall<string[]>(this.fs.readdir, source);
179 })
180 .then(contents => {
181 Q.all(contents.map((childPath: string): Q.Promise<void> => {
182 return this.copyRecursive(path.join(source, childPath), path.join(target, childPath));
183 }));
184 });
185 } else {
186 return this.copyFile(source, target);
187 }
188 });
189 }
190
191 public removePathRecursivelyAsync(p: string): Q.Promise<void> {
192 return this.exists(p).then(exists => {
193 if (exists) {
194 return Q.nfcall<nodeFs.Stats>(this.fs.stat, p).then((stats: nodeFs.Stats) => {
195 if (stats.isDirectory()) {
196 return Q.nfcall<string[]>(this.fs.readdir, p).then((childPaths: string[]) => {
197 let result = Q<void>(void 0);
198 childPaths.forEach(childPath =>
199 result = result.then<void>(() => this.removePathRecursivelyAsync(path.join(p, childPath))));
200 return result;
201 }).then(() =>
202 Q.nfcall<void>(this.fs.rmdir, p));
203 } else {
204 /* file */
205 return Q.nfcall<void>(this.fs.unlink, p);
206 }
207 });
208 }
209 return Q.resolve(void 0);
210 });
211 }
212
213 public removePathRecursivelySync(p: string): void {
214 if (this.fs.existsSync(p)) {
215 let stats = this.fs.statSync(p);
216 if (stats.isDirectory()) {
217 let contents = this.fs.readdirSync(p);
218 contents.forEach(childPath =>
219 this.removePathRecursivelySync(path.join(p, childPath)));
220 this.fs.rmdirSync(p);
221 } else {
222 /* file */
223 this.fs.unlinkSync(p);
224 }
225 }
226 }
227}
228