UNPKG

8.34 kBJavaScriptView Raw
1/**
2 * An asynchronous local file system API, based on a subset
3 * of the `narwhal/fs` API and the `narwhal/promise` API,
4 * such that the method names are the same but some return
5 * values are promises instead of fully resolved values.
6 * @module
7 */
8
9/*whatsupdoc*/
10
11var FS = require("fs"); // node
12var Q = require("qq");
13var IO = require("q-io");
14var COMMON = require("./common");
15var MOCK = require("./mock");
16var ROOT = require("./root");
17
18COMMON.update(exports, process.cwd);
19exports.Mock = MOCK.Fs;
20exports.mock = MOCK.mock;
21exports.Root = ROOT.Fs;
22
23/**
24 * @param {String} path
25 * @param {Object} options (flags, mode, bufferSize, charset, begin, end)
26 * @returns {Promise * Stream} a stream from the `q-io` module.
27 */
28exports.open = function (path, flags, charset, options) {
29 if (typeof flags == "object") {
30 options = flags;
31 flags = options.flags;
32 charset = options.charset;
33 }
34 options = options || {};
35 flags = flags || "r";
36 var nodeOptions = {
37 "flags": flags.replace(/b/g, "")
38 };
39 if ("bufferSize" in options) {
40 nodeOptions.bufferSize = options.bufferSize;
41 }
42 if ("mode" in options) {
43 nodeOptions.mode = options.mode;
44 }
45 if ("begin" in options) {
46 nodeOptions.start = options.begin;
47 nodeOptions.end = options.end - 1;
48 }
49 if (flags.indexOf("b") >= 0) {
50 if (charset) {
51 throw new Error("Can't open a binary file with a charset: " + charset);
52 }
53 }
54 if (flags.indexOf("w") >= 0) {
55 var stream = FS.createWriteStream(String(path), nodeOptions);
56 return IO.Writer(stream, charset);
57 } else {
58 var stream = FS.createReadStream(String(path), nodeOptions);
59 return IO.Reader(stream, charset);
60 }
61};
62
63exports.remove = function (path) {
64 path = String(path);
65 var done = Q.defer();
66 FS.unlink(path, function (error) {
67 if (error) {
68 error.message = "Can't remove " + JSON.stringify(path) + ": " + error.message;
69 done.reject(error);
70 } else {
71 done.resolve();
72 }
73 });
74 return done.promise;
75};
76
77exports.makeDirectory = function (path, mode) {
78 path = String(path);
79 var done = Q.defer();
80 mode = mode === undefined ? parseInt('755', 8) : mode;
81 FS.mkdir(path, mode, function (error) {
82 if (error) {
83 error.message = "Can't makeDirectory " + JSON.stringify(path) + " with mode " + mode + ": " + error.message;
84 done.reject(error);
85 } else {
86 done.resolve();
87 }
88 });
89 return done.promise;
90};
91
92exports.removeDirectory = function (path) {
93 path = String(path);
94 var done = Q.defer();
95 FS.rmdir(path, function (error) {
96 if (error) {
97 error.message = "Can't removeDirectory " + JSON.stringify(path) + ": " + error.message;
98 done.reject(error);
99 } else {
100 done.resolve();
101 }
102 });
103 return done.promise;
104};
105
106/**
107 */
108exports.list = function (path) {
109 path = String(path);
110 var result = Q.defer();
111 FS.readdir(path, function (error, list) {
112 if (error) {
113 error.message = "Can't list " + JSON.stringify(path) + ": " + error.message;
114 return result.reject(error);
115 } else {
116 result.resolve(list);
117 }
118 });
119 return Q.Lazy(Array, result.promise);
120};
121
122/**
123 * @param {String} path
124 * @returns {Promise * Stat}
125 */
126exports.stat = function (path) {
127 path = String(path);
128 var done = Q.defer();
129 try {
130 FS.stat(path, function (error, stat) {
131 if (error) {
132 error.message = "Can't stat " + JSON.stringify(path) + ": " + error;
133 done.reject(error);
134 } else {
135 done.resolve(new exports.Stats(stat));
136 }
137 });
138 } catch (error) {
139 done.reject(error);
140 }
141 return Q.Lazy(exports.Stats, done.promise);
142};
143
144exports.statLink = function (path) {
145 path = String(path);
146 var done = Q.defer();
147 try {
148 FS.lstat(path, function (error, stat) {
149 if (error) {
150 error.message = "Can't statLink " + JSON.stringify(path) + ": " + error.message;
151 done.reject(error);
152 } else {
153 done.resolve(stat);
154 }
155 });
156 } catch (error) {
157 done.reject(error);
158 }
159 return done.promise;
160};
161
162exports.statFd = function (fd) {
163 fd = Number(fd);
164 var done = Q.defer();
165 try {
166 FS.fstat(fd, function (error, stat) {
167 if (error) {
168 error.message = "Can't statFd file descriptor " + JSON.stringify(fd) + ": " + error.message;
169 done.reject(error);
170 } else {
171 done.resolve(stat);
172 }
173 });
174 } catch (error) {
175 done.reject(error);
176 }
177 return done.promise;
178};
179
180exports.link = function (source, target) {
181 source = String(source);
182 target = String(target);
183 var done = Q.defer();
184 try {
185 FS.link(source, target, function (error) {
186 if (error) {
187 error.message = "Can't link " + JSON.stringify(source) + " to " + JSON.stringify(target) + ": " + error.message;
188 done.reject(error);
189 } else {
190 done.resolve();
191 }
192 });
193 } catch (error) {
194 done.reject(error);
195 }
196 return done.promise;
197};
198
199exports.symbolicLink = function (target, relative) {
200 target = String(target);
201 relative = String(relative);
202 var done = Q.defer();
203 try {
204 FS.symlink(relative, target, function (error) {
205 if (error) {
206 error.message = "Can't create symbolicLink " + JSON.stringify(target) + " to relative location " + JSON.stringify(relative) + ": " + error.message;
207 done.reject(error);
208 } else {
209 done.resolve();
210 }
211 });
212 } catch (error) {
213 done.reject(error);
214 }
215 return done.promise;
216};
217
218exports.symbolicCopy = function (source, target) {
219 return Q.when(exports.relative(target, source), function (relative) {
220 return exports.symbolicLink(target, relative);
221 });
222};
223
224exports.chown = function (path, uid, gid) {
225 path = String(path);
226 var done = Q.defer();
227 try {
228 FS.chown(path, uid, gid, function (error) {
229 if (error) {
230 error.message = "Can't chown (change owner) of " + JSON.stringify(path) + " to user " + JSON.stringify(uid) + " and group " + JSON.stringify(gid) + ": " + error.message;
231 done.reject(error);
232 } else {
233 done.resolve();
234 }
235 });
236 } catch (error) {
237 done.reject(error);
238 }
239 return done.promise;
240};
241
242exports.chmod = function (path, mode) {
243 path = String(path);
244 mode = String(mode);
245 var done = Q.defer();
246 try {
247 FS.chmod(path, mode, function (error) {
248 if (error) {
249 error.message = "Can't chmod (change permissions mode) of " + JSON.stringify(path) + " to (octal number) " + mode.toString(8) + ": " + error.message;
250 done.reject(error);
251 } else {
252 done.resolve();
253 }
254 });
255 } catch (error) {
256 done.reject(error);
257 }
258 return done.promise;
259};
260
261exports.lastModified = function (path) {
262 var stat = exports.stat(path);
263 var mtime = Q.get(stat, 'mtime');
264 return Q.when(mtime, function (mtime) {
265 return Date.parse(mtime);
266 });
267};
268
269exports.canonical = function (path) {
270 var result = Q.defer();
271 FS.realpath(path, function (error, path) {
272 if (error) {
273 error.message = "Can't get canonical path of " + JSON.stringify(path) + " by way of C realpath: " + error.message;
274 result.reject(error);
275 } else {
276 result.resolve(path);
277 }
278 });
279 return result.promise;
280};
281
282exports.readLink = function (path) {
283 var result = Q.defer();
284 FS.readlink(path, function (error, path) {
285 if (error) {
286 error.message = "Can't get link from " + JSON.stringify(path) + " by way of C readlink: " + error.message;
287 result.reject(error);
288 } else {
289 result.resolve(path);
290 }
291 });
292 return result.promise;
293};
294