OLD | NEW |
| (Empty) |
1 /* | |
2 * Copyright (C) 2013 Google Inc. All rights reserved. | |
3 * | |
4 * Redistribution and use in source and binary forms, with or without | |
5 * modification, are permitted provided that the following conditions are | |
6 * met: | |
7 * | |
8 * * Redistributions of source code must retain the above copyright | |
9 * notice, this list of conditions and the following disclaimer. | |
10 * * Redistributions in binary form must reproduce the above | |
11 * copyright notice, this list of conditions and the following disclaimer | |
12 * in the documentation and/or other materials provided with the | |
13 * distribution. | |
14 * * Neither the name of Google Inc. nor the names of its | |
15 * contributors may be used to endorse or promote products derived from | |
16 * this software without specific prior written permission. | |
17 * | |
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
29 */ | |
30 | |
31 /** | |
32 * @constructor | |
33 * @param {!WebInspector.IsolatedFileSystemManager} manager | |
34 * @param {string} path | |
35 * @param {string} name | |
36 * @param {string} rootURL | |
37 */ | |
38 WebInspector.IsolatedFileSystem = function(manager, path, name, rootURL) | |
39 { | |
40 this._manager = manager; | |
41 this._path = path; | |
42 this._name = name; | |
43 this._rootURL = rootURL; | |
44 } | |
45 | |
46 /** | |
47 * @param {!FileError} error | |
48 * @return {string} | |
49 */ | |
50 WebInspector.IsolatedFileSystem.errorMessage = function(error) | |
51 { | |
52 return WebInspector.UIString("File system error: %s", error.message); | |
53 } | |
54 | |
55 /** | |
56 * @param {string} fileSystemPath | |
57 * @return {string} | |
58 */ | |
59 WebInspector.IsolatedFileSystem.normalizePath = function(fileSystemPath) | |
60 { | |
61 if (WebInspector.isWin()) | |
62 return fileSystemPath.replace(/\\/g, "/"); | |
63 return fileSystemPath; | |
64 } | |
65 | |
66 WebInspector.IsolatedFileSystem.prototype = { | |
67 /** | |
68 * @return {string} | |
69 */ | |
70 path: function() | |
71 { | |
72 return this._path; | |
73 }, | |
74 | |
75 /** | |
76 * @return {string} | |
77 */ | |
78 normalizedPath: function() | |
79 { | |
80 if (this._normalizedPath) | |
81 return this._normalizedPath; | |
82 this._normalizedPath = WebInspector.IsolatedFileSystem.normalizePath(thi
s._path); | |
83 return this._normalizedPath; | |
84 }, | |
85 | |
86 /** | |
87 * @return {string} | |
88 */ | |
89 name: function() | |
90 { | |
91 return this._name; | |
92 }, | |
93 | |
94 /** | |
95 * @return {string} | |
96 */ | |
97 rootURL: function() | |
98 { | |
99 return this._rootURL; | |
100 }, | |
101 | |
102 /** | |
103 * @param {function(?DOMFileSystem)} callback | |
104 */ | |
105 _requestFileSystem: function(callback) | |
106 { | |
107 this._manager.requestDOMFileSystem(this._path, callback); | |
108 }, | |
109 | |
110 /** | |
111 * @param {string} path | |
112 * @param {function(string)} fileCallback | |
113 * @param {function()=} finishedCallback | |
114 */ | |
115 requestFilesRecursive: function(path, fileCallback, finishedCallback) | |
116 { | |
117 var domFileSystem; | |
118 var pendingRequests = 0; | |
119 this._requestFileSystem(fileSystemLoaded.bind(this)); | |
120 /** | |
121 * @param {?DOMFileSystem} fs | |
122 * @this {WebInspector.IsolatedFileSystem} | |
123 */ | |
124 function fileSystemLoaded(fs) | |
125 { | |
126 domFileSystem = /** @type {!DOMFileSystem} */ (fs); | |
127 console.assert(domFileSystem); | |
128 ++pendingRequests; | |
129 this._requestEntries(domFileSystem, path, innerCallback.bind(this)); | |
130 } | |
131 | |
132 /** | |
133 * @param {!Array.<!FileEntry>} entries | |
134 * @this {WebInspector.IsolatedFileSystem} | |
135 */ | |
136 function innerCallback(entries) | |
137 { | |
138 for (var i = 0; i < entries.length; ++i) { | |
139 var entry = entries[i]; | |
140 if (!entry.isDirectory) { | |
141 if (this._manager.mapping().isFileExcluded(this._path, entry
.fullPath)) | |
142 continue; | |
143 fileCallback(entry.fullPath.substr(1)); | |
144 } | |
145 else { | |
146 if (this._manager.mapping().isFileExcluded(this._path, entry
.fullPath + "/")) | |
147 continue; | |
148 ++pendingRequests; | |
149 this._requestEntries(domFileSystem, entry.fullPath, innerCal
lback.bind(this)); | |
150 } | |
151 } | |
152 if (finishedCallback && (--pendingRequests === 0)) | |
153 finishedCallback(); | |
154 } | |
155 }, | |
156 | |
157 /** | |
158 * @param {string} path | |
159 * @param {?string} name | |
160 * @param {function(?string)} callback | |
161 */ | |
162 createFile: function(path, name, callback) | |
163 { | |
164 this._requestFileSystem(fileSystemLoaded.bind(this)); | |
165 var newFileIndex = 1; | |
166 if (!name) | |
167 name = "NewFile"; | |
168 var nameCandidate; | |
169 | |
170 /** | |
171 * @param {?DOMFileSystem} fs | |
172 * @this {WebInspector.IsolatedFileSystem} | |
173 */ | |
174 function fileSystemLoaded(fs) | |
175 { | |
176 var domFileSystem = /** @type {!DOMFileSystem} */ (fs); | |
177 console.assert(domFileSystem); | |
178 domFileSystem.root.getDirectory(path, null, dirEntryLoaded.bind(this
), errorHandler.bind(this)); | |
179 } | |
180 | |
181 /** | |
182 * @param {!DirectoryEntry} dirEntry | |
183 * @this {WebInspector.IsolatedFileSystem} | |
184 */ | |
185 function dirEntryLoaded(dirEntry) | |
186 { | |
187 var nameCandidate = name; | |
188 if (newFileIndex > 1) | |
189 nameCandidate += newFileIndex; | |
190 ++newFileIndex; | |
191 dirEntry.getFile(nameCandidate, { create: true, exclusive: true }, f
ileCreated, fileCreationError.bind(this)); | |
192 | |
193 function fileCreated(entry) | |
194 { | |
195 callback(entry.fullPath.substr(1)); | |
196 } | |
197 | |
198 /** | |
199 * @this {WebInspector.IsolatedFileSystem} | |
200 */ | |
201 function fileCreationError(error) | |
202 { | |
203 if (error.code === FileError.INVALID_MODIFICATION_ERR) { | |
204 dirEntryLoaded.call(this, dirEntry); | |
205 return; | |
206 } | |
207 | |
208 var errorMessage = WebInspector.IsolatedFileSystem.errorMessage(
error); | |
209 console.error(errorMessage + " when testing if file exists '" +
(this._path + "/" + path + "/" + nameCandidate) + "'"); | |
210 callback(null); | |
211 } | |
212 } | |
213 | |
214 /** | |
215 * @this {WebInspector.IsolatedFileSystem} | |
216 */ | |
217 function errorHandler(error) | |
218 { | |
219 var errorMessage = WebInspector.IsolatedFileSystem.errorMessage(erro
r); | |
220 var filePath = this._path + "/" + path; | |
221 if (nameCandidate) | |
222 filePath += "/" + nameCandidate; | |
223 console.error(errorMessage + " when getting content for file '" + (f
ilePath) + "'"); | |
224 callback(null); | |
225 } | |
226 }, | |
227 | |
228 /** | |
229 * @param {string} path | |
230 */ | |
231 deleteFile: function(path) | |
232 { | |
233 this._requestFileSystem(fileSystemLoaded.bind(this)); | |
234 | |
235 /** | |
236 * @param {?DOMFileSystem} fs | |
237 * @this {WebInspector.IsolatedFileSystem} | |
238 */ | |
239 function fileSystemLoaded(fs) | |
240 { | |
241 var domFileSystem = /** @type {!DOMFileSystem} */ (fs); | |
242 console.assert(domFileSystem); | |
243 domFileSystem.root.getFile(path, null, fileEntryLoaded.bind(this), e
rrorHandler.bind(this)); | |
244 } | |
245 | |
246 /** | |
247 * @param {!FileEntry} fileEntry | |
248 * @this {WebInspector.IsolatedFileSystem} | |
249 */ | |
250 function fileEntryLoaded(fileEntry) | |
251 { | |
252 fileEntry.remove(fileEntryRemoved, errorHandler.bind(this)); | |
253 } | |
254 | |
255 function fileEntryRemoved() | |
256 { | |
257 } | |
258 | |
259 /** | |
260 * @param {!FileError} error | |
261 * @this {WebInspector.IsolatedFileSystem} | |
262 */ | |
263 function errorHandler(error) | |
264 { | |
265 var errorMessage = WebInspector.IsolatedFileSystem.errorMessage(erro
r); | |
266 console.error(errorMessage + " when deleting file '" + (this._path +
"/" + path) + "'"); | |
267 } | |
268 }, | |
269 | |
270 /** | |
271 * @param {string} path | |
272 * @param {function(?Date, ?number)} callback | |
273 */ | |
274 requestMetadata: function(path, callback) | |
275 { | |
276 this._requestFileSystem(fileSystemLoaded); | |
277 | |
278 /** | |
279 * @param {?DOMFileSystem} fs | |
280 */ | |
281 function fileSystemLoaded(fs) | |
282 { | |
283 var domFileSystem = /** @type {!DOMFileSystem} */ (fs); | |
284 console.assert(domFileSystem); | |
285 domFileSystem.root.getFile(path, null, fileEntryLoaded, errorHandler
); | |
286 } | |
287 | |
288 /** | |
289 * @param {!FileEntry} entry | |
290 */ | |
291 function fileEntryLoaded(entry) | |
292 { | |
293 entry.getMetadata(successHandler, errorHandler); | |
294 } | |
295 | |
296 /** | |
297 * @param {!Metadata} metadata | |
298 */ | |
299 function successHandler(metadata) | |
300 { | |
301 callback(metadata.modificationTime, metadata.size); | |
302 } | |
303 | |
304 /** | |
305 * @param {!FileError} error | |
306 */ | |
307 function errorHandler(error) | |
308 { | |
309 callback(null, null); | |
310 } | |
311 }, | |
312 | |
313 /** | |
314 * @param {string} path | |
315 * @param {function(?string)} callback | |
316 */ | |
317 requestFileContent: function(path, callback) | |
318 { | |
319 this._requestFileSystem(fileSystemLoaded.bind(this)); | |
320 | |
321 /** | |
322 * @param {?DOMFileSystem} fs | |
323 * @this {WebInspector.IsolatedFileSystem} | |
324 */ | |
325 function fileSystemLoaded(fs) | |
326 { | |
327 var domFileSystem = /** @type {!DOMFileSystem} */ (fs); | |
328 console.assert(domFileSystem); | |
329 domFileSystem.root.getFile(path, null, fileEntryLoaded.bind(this), e
rrorHandler.bind(this)); | |
330 } | |
331 | |
332 /** | |
333 * @param {!FileEntry} entry | |
334 * @this {WebInspector.IsolatedFileSystem} | |
335 */ | |
336 function fileEntryLoaded(entry) | |
337 { | |
338 entry.file(fileLoaded, errorHandler.bind(this)); | |
339 } | |
340 | |
341 /** | |
342 * @param {!Blob} file | |
343 */ | |
344 function fileLoaded(file) | |
345 { | |
346 var reader = new FileReader(); | |
347 reader.onloadend = readerLoadEnd; | |
348 reader.readAsText(file); | |
349 } | |
350 | |
351 /** | |
352 * @this {!FileReader} | |
353 */ | |
354 function readerLoadEnd() | |
355 { | |
356 callback(/** @type {string} */ (this.result)); | |
357 } | |
358 | |
359 /** | |
360 * @this {WebInspector.IsolatedFileSystem} | |
361 */ | |
362 function errorHandler(error) | |
363 { | |
364 if (error.code === FileError.NOT_FOUND_ERR) { | |
365 callback(null); | |
366 return; | |
367 } | |
368 | |
369 var errorMessage = WebInspector.IsolatedFileSystem.errorMessage(erro
r); | |
370 console.error(errorMessage + " when getting content for file '" + (t
his._path + "/" + path) + "'"); | |
371 callback(null); | |
372 } | |
373 }, | |
374 | |
375 /** | |
376 * @param {string} path | |
377 * @param {string} content | |
378 * @param {function()} callback | |
379 */ | |
380 setFileContent: function(path, content, callback) | |
381 { | |
382 this._requestFileSystem(fileSystemLoaded.bind(this)); | |
383 WebInspector.userMetrics.FileSavedInWorkspace.record(); | |
384 | |
385 /** | |
386 * @param {?DOMFileSystem} fs | |
387 * @this {WebInspector.IsolatedFileSystem} | |
388 */ | |
389 function fileSystemLoaded(fs) | |
390 { | |
391 var domFileSystem = /** @type {!DOMFileSystem} */ (fs); | |
392 console.assert(domFileSystem); | |
393 domFileSystem.root.getFile(path, { create: true }, fileEntryLoaded.b
ind(this), errorHandler.bind(this)); | |
394 } | |
395 | |
396 /** | |
397 * @param {!FileEntry} entry | |
398 * @this {WebInspector.IsolatedFileSystem} | |
399 */ | |
400 function fileEntryLoaded(entry) | |
401 { | |
402 entry.createWriter(fileWriterCreated.bind(this), errorHandler.bind(t
his)); | |
403 } | |
404 | |
405 /** | |
406 * @param {!FileWriter} fileWriter | |
407 * @this {WebInspector.IsolatedFileSystem} | |
408 */ | |
409 function fileWriterCreated(fileWriter) | |
410 { | |
411 fileWriter.onerror = errorHandler.bind(this); | |
412 fileWriter.onwriteend = fileTruncated; | |
413 fileWriter.truncate(0); | |
414 | |
415 function fileTruncated() | |
416 { | |
417 fileWriter.onwriteend = writerEnd; | |
418 var blob = new Blob([content], { type: "text/plain" }); | |
419 fileWriter.write(blob); | |
420 } | |
421 } | |
422 | |
423 function writerEnd() | |
424 { | |
425 callback(); | |
426 } | |
427 | |
428 /** | |
429 * @this {WebInspector.IsolatedFileSystem} | |
430 */ | |
431 function errorHandler(error) | |
432 { | |
433 var errorMessage = WebInspector.IsolatedFileSystem.errorMessage(erro
r); | |
434 console.error(errorMessage + " when setting content for file '" + (t
his._path + "/" + path) + "'"); | |
435 callback(); | |
436 } | |
437 }, | |
438 | |
439 /** | |
440 * @param {string} path | |
441 * @param {string} newName | |
442 * @param {function(boolean, string=)} callback | |
443 */ | |
444 renameFile: function(path, newName, callback) | |
445 { | |
446 newName = newName ? newName.trim() : newName; | |
447 if (!newName || newName.indexOf("/") !== -1) { | |
448 callback(false); | |
449 return; | |
450 } | |
451 var fileEntry; | |
452 var dirEntry; | |
453 var newFileEntry; | |
454 this._requestFileSystem(fileSystemLoaded.bind(this)); | |
455 | |
456 /** | |
457 * @param {?DOMFileSystem} fs | |
458 * @this {WebInspector.IsolatedFileSystem} | |
459 */ | |
460 function fileSystemLoaded(fs) | |
461 { | |
462 var domFileSystem = /** @type {!DOMFileSystem} */ (fs); | |
463 console.assert(domFileSystem); | |
464 domFileSystem.root.getFile(path, null, fileEntryLoaded.bind(this), e
rrorHandler.bind(this)); | |
465 } | |
466 | |
467 /** | |
468 * @param {!FileEntry} entry | |
469 * @this {WebInspector.IsolatedFileSystem} | |
470 */ | |
471 function fileEntryLoaded(entry) | |
472 { | |
473 if (entry.name === newName) { | |
474 callback(false); | |
475 return; | |
476 } | |
477 | |
478 fileEntry = entry; | |
479 fileEntry.getParent(dirEntryLoaded.bind(this), errorHandler.bind(thi
s)); | |
480 } | |
481 | |
482 /** | |
483 * @param {!Entry} entry | |
484 * @this {WebInspector.IsolatedFileSystem} | |
485 */ | |
486 function dirEntryLoaded(entry) | |
487 { | |
488 dirEntry = entry; | |
489 dirEntry.getFile(newName, null, newFileEntryLoaded, newFileEntryLoad
ErrorHandler.bind(this)); | |
490 } | |
491 | |
492 /** | |
493 * @param {!FileEntry} entry | |
494 */ | |
495 function newFileEntryLoaded(entry) | |
496 { | |
497 callback(false); | |
498 } | |
499 | |
500 /** | |
501 * @this {WebInspector.IsolatedFileSystem} | |
502 */ | |
503 function newFileEntryLoadErrorHandler(error) | |
504 { | |
505 if (error.code !== FileError.NOT_FOUND_ERR) { | |
506 callback(false); | |
507 return; | |
508 } | |
509 fileEntry.moveTo(dirEntry, newName, fileRenamed, errorHandler.bind(t
his)); | |
510 } | |
511 | |
512 /** | |
513 * @param {!FileEntry} entry | |
514 */ | |
515 function fileRenamed(entry) | |
516 { | |
517 callback(true, entry.name); | |
518 } | |
519 | |
520 /** | |
521 * @this {WebInspector.IsolatedFileSystem} | |
522 */ | |
523 function errorHandler(error) | |
524 { | |
525 var errorMessage = WebInspector.IsolatedFileSystem.errorMessage(erro
r); | |
526 console.error(errorMessage + " when renaming file '" + (this._path +
"/" + path) + "' to '" + newName + "'"); | |
527 callback(false); | |
528 } | |
529 }, | |
530 | |
531 /** | |
532 * @param {!DirectoryEntry} dirEntry | |
533 * @param {function(!Array.<!FileEntry>)} callback | |
534 */ | |
535 _readDirectory: function(dirEntry, callback) | |
536 { | |
537 var dirReader = dirEntry.createReader(); | |
538 var entries = []; | |
539 | |
540 function innerCallback(results) | |
541 { | |
542 if (!results.length) | |
543 callback(entries.sort()); | |
544 else { | |
545 entries = entries.concat(toArray(results)); | |
546 dirReader.readEntries(innerCallback, errorHandler); | |
547 } | |
548 } | |
549 | |
550 function toArray(list) | |
551 { | |
552 return Array.prototype.slice.call(list || [], 0); | |
553 } | |
554 | |
555 dirReader.readEntries(innerCallback, errorHandler); | |
556 | |
557 function errorHandler(error) | |
558 { | |
559 var errorMessage = WebInspector.IsolatedFileSystem.errorMessage(erro
r); | |
560 console.error(errorMessage + " when reading directory '" + dirEntry.
fullPath + "'"); | |
561 callback([]); | |
562 } | |
563 }, | |
564 | |
565 /** | |
566 * @param {!DOMFileSystem} domFileSystem | |
567 * @param {string} path | |
568 * @param {function(!Array.<!FileEntry>)} callback | |
569 */ | |
570 _requestEntries: function(domFileSystem, path, callback) | |
571 { | |
572 domFileSystem.root.getDirectory(path, null, innerCallback.bind(this), er
rorHandler); | |
573 | |
574 /** | |
575 * @param {!DirectoryEntry} dirEntry | |
576 * @this {WebInspector.IsolatedFileSystem} | |
577 */ | |
578 function innerCallback(dirEntry) | |
579 { | |
580 this._readDirectory(dirEntry, callback) | |
581 } | |
582 | |
583 function errorHandler(error) | |
584 { | |
585 var errorMessage = WebInspector.IsolatedFileSystem.errorMessage(erro
r); | |
586 console.error(errorMessage + " when requesting entry '" + path + "'"
); | |
587 callback([]); | |
588 } | |
589 } | |
590 } | |
OLD | NEW |