Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(160)

Side by Side Diff: third_party/WebKit/Source/devtools/front_end/workspace/IsolatedFileSystem.js

Issue 2867783003: DevTools: move IsolatedFileSystem/IsolatedFileSystemManager into persistence/ (Closed)
Patch Set: fix order Created 3 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(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 * @unrestricted
33 */
34 Workspace.IsolatedFileSystem = class {
35 /**
36 * @param {!Workspace.IsolatedFileSystemManager} manager
37 * @param {string} path
38 * @param {string} embedderPath
39 * @param {!DOMFileSystem} domFileSystem
40 */
41 constructor(manager, path, embedderPath, domFileSystem) {
42 this._manager = manager;
43 this._path = path;
44 this._embedderPath = embedderPath;
45 this._domFileSystem = domFileSystem;
46 this._excludedFoldersSetting = Common.settings.createLocalSetting('workspace ExcludedFolders', {});
47 /** @type {!Set<string>} */
48 this._excludedFolders = new Set(this._excludedFoldersSetting.get()[path] || []);
49
50 /** @type {!Set<string>} */
51 this._initialFilePaths = new Set();
52 /** @type {!Set<string>} */
53 this._initialGitFolders = new Set();
54 }
55
56 /**
57 * @param {!Workspace.IsolatedFileSystemManager} manager
58 * @param {string} path
59 * @param {string} embedderPath
60 * @param {string} name
61 * @param {string} rootURL
62 * @return {!Promise<?Workspace.IsolatedFileSystem>}
63 */
64 static create(manager, path, embedderPath, name, rootURL) {
65 var domFileSystem = InspectorFrontendHost.isolatedFileSystem(name, rootURL);
66 if (!domFileSystem)
67 return Promise.resolve(/** @type {?Workspace.IsolatedFileSystem} */ (null) );
68
69 var fileSystem = new Workspace.IsolatedFileSystem(manager, path, embedderPat h, domFileSystem);
70 return fileSystem._initializeFilePaths()
71 .then(() => fileSystem)
72 .catchException(/** @type {?Workspace.IsolatedFileSystem} */ (null));
73 }
74
75 /**
76 * @param {!DOMError} error
77 * @return {string}
78 */
79 static errorMessage(error) {
80 return Common.UIString('File system error: %s', error.message);
81 }
82
83 /**
84 * @param {string} path
85 * @return {!Promise<?{modificationTime: !Date, size: number}>}
86 */
87 getMetadata(path) {
88 var fulfill;
89 var promise = new Promise(f => fulfill = f);
90 this._domFileSystem.root.getFile(path, undefined, fileEntryLoaded, errorHand ler);
91 return promise;
92
93 /**
94 * @param {!FileEntry} entry
95 */
96 function fileEntryLoaded(entry) {
97 entry.getMetadata(fulfill, errorHandler);
98 }
99
100 /**
101 * @param {!FileError} error
102 */
103 function errorHandler(error) {
104 var errorMessage = Workspace.IsolatedFileSystem.errorMessage(error);
105 console.error(errorMessage + ' when getting file metadata \'' + path);
106 fulfill(null);
107 }
108 }
109
110 /**
111 * @return {!Array<string>}
112 */
113 initialFilePaths() {
114 return this._initialFilePaths.valuesArray();
115 }
116
117 /**
118 * @return {!Array<string>}
119 */
120 initialGitFolders() {
121 return this._initialGitFolders.valuesArray();
122 }
123
124 /**
125 * @return {string}
126 */
127 path() {
128 return this._path;
129 }
130
131 /**
132 * @return {string}
133 */
134 embedderPath() {
135 return this._embedderPath;
136 }
137
138 /**
139 * @return {!Promise}
140 */
141 _initializeFilePaths() {
142 var fulfill;
143 var promise = new Promise(x => fulfill = x);
144 var pendingRequests = 1;
145 var boundInnerCallback = innerCallback.bind(this);
146 this._requestEntries('', boundInnerCallback);
147 return promise;
148
149 /**
150 * @param {!Array.<!FileEntry>} entries
151 * @this {Workspace.IsolatedFileSystem}
152 */
153 function innerCallback(entries) {
154 for (var i = 0; i < entries.length; ++i) {
155 var entry = entries[i];
156 if (!entry.isDirectory) {
157 if (this._isFileExcluded(entry.fullPath))
158 continue;
159 this._initialFilePaths.add(entry.fullPath.substr(1));
160 } else {
161 if (entry.fullPath.endsWith('/.git')) {
162 var lastSlash = entry.fullPath.lastIndexOf('/');
163 var parentFolder = entry.fullPath.substring(1, lastSlash);
164 this._initialGitFolders.add(parentFolder);
165 }
166 if (this._isFileExcluded(entry.fullPath + '/'))
167 continue;
168 ++pendingRequests;
169 this._requestEntries(entry.fullPath, boundInnerCallback);
170 }
171 }
172 if ((--pendingRequests === 0))
173 fulfill();
174 }
175 }
176
177 /**
178 * @param {string} path
179 * @param {?string} name
180 * @param {function(?string)} callback
181 */
182 createFile(path, name, callback) {
183 var newFileIndex = 1;
184 if (!name)
185 name = 'NewFile';
186 var nameCandidate;
187
188 this._domFileSystem.root.getDirectory(path, undefined, dirEntryLoaded.bind(t his), errorHandler.bind(this));
189
190 /**
191 * @param {!DirectoryEntry} dirEntry
192 * @this {Workspace.IsolatedFileSystem}
193 */
194 function dirEntryLoaded(dirEntry) {
195 var nameCandidate = name;
196 if (newFileIndex > 1)
197 nameCandidate += newFileIndex;
198 ++newFileIndex;
199 dirEntry.getFile(nameCandidate, {create: true, exclusive: true}, fileCreat ed, fileCreationError.bind(this));
200
201 function fileCreated(entry) {
202 callback(entry.fullPath.substr(1));
203 }
204
205 /**
206 * @this {Workspace.IsolatedFileSystem}
207 */
208 function fileCreationError(error) {
209 if (error.name === 'InvalidModificationError') {
210 dirEntryLoaded.call(this, dirEntry);
211 return;
212 }
213 var errorMessage = Workspace.IsolatedFileSystem.errorMessage(error);
214 console.error(
215 errorMessage + ' when testing if file exists \'' + (this._path + '/' + path + '/' + nameCandidate) + '\'');
216 callback(null);
217 }
218 }
219
220 /**
221 * @this {Workspace.IsolatedFileSystem}
222 */
223 function errorHandler(error) {
224 var errorMessage = Workspace.IsolatedFileSystem.errorMessage(error);
225 var filePath = this._path + '/' + path;
226 if (nameCandidate)
227 filePath += '/' + nameCandidate;
228 console.error(errorMessage + ' when getting content for file \'' + (filePa th) + '\'');
229 callback(null);
230 }
231 }
232
233 /**
234 * @param {string} path
235 */
236 deleteFile(path) {
237 this._domFileSystem.root.getFile(path, undefined, fileEntryLoaded.bind(this) , errorHandler.bind(this));
238
239 /**
240 * @param {!FileEntry} fileEntry
241 * @this {Workspace.IsolatedFileSystem}
242 */
243 function fileEntryLoaded(fileEntry) {
244 fileEntry.remove(fileEntryRemoved, errorHandler.bind(this));
245 }
246
247 function fileEntryRemoved() {
248 }
249
250 /**
251 * @param {!FileError} error
252 * @this {Workspace.IsolatedFileSystem}
253 * @suppress {checkTypes}
254 * TODO(jsbell): Update externs replacing FileError with DOMException. https ://crbug.com/496901
255 */
256 function errorHandler(error) {
257 var errorMessage = Workspace.IsolatedFileSystem.errorMessage(error);
258 console.error(errorMessage + ' when deleting file \'' + (this._path + '/' + path) + '\'');
259 }
260 }
261
262 /**
263 * @param {string} path
264 * @return {!Promise<?string>}
265 */
266 requestFileContentPromise(path) {
267 var fulfill;
268 var promise = new Promise(x => fulfill = x);
269 this.requestFileContent(path, fulfill);
270 return promise;
271 }
272
273 /**
274 * @param {string} path
275 * @param {function(?string)} callback
276 */
277 requestFileContent(path, callback) {
278 this._domFileSystem.root.getFile(path, undefined, fileEntryLoaded.bind(this) , errorHandler.bind(this));
279
280 /**
281 * @param {!FileEntry} entry
282 * @this {Workspace.IsolatedFileSystem}
283 */
284 function fileEntryLoaded(entry) {
285 entry.file(fileLoaded, errorHandler.bind(this));
286 }
287
288 /**
289 * @param {!Blob} file
290 */
291 function fileLoaded(file) {
292 var reader = new FileReader();
293 reader.onloadend = readerLoadEnd;
294 if (Workspace.IsolatedFileSystem.ImageExtensions.has(Common.ParsedURL.extr actExtension(path)))
295 reader.readAsDataURL(file);
296 else
297 reader.readAsText(file);
298 }
299
300 /**
301 * @this {!FileReader}
302 */
303 function readerLoadEnd() {
304 /** @type {?string} */
305 var string = null;
306 try {
307 string = /** @type {string} */ (this.result);
308 } catch (e) {
309 console.error('Can\'t read file: ' + path + ': ' + e);
310 }
311 callback(string);
312 }
313
314 /**
315 * @this {Workspace.IsolatedFileSystem}
316 */
317 function errorHandler(error) {
318 if (error.name === 'NotFoundError') {
319 callback(null);
320 return;
321 }
322
323 var errorMessage = Workspace.IsolatedFileSystem.errorMessage(error);
324 console.error(errorMessage + ' when getting content for file \'' + (this._ path + '/' + path) + '\'');
325 callback(null);
326 }
327 }
328
329 /**
330 * @param {string} path
331 * @param {string} content
332 * @param {function()} callback
333 */
334 setFileContent(path, content, callback) {
335 Host.userMetrics.actionTaken(Host.UserMetrics.Action.FileSavedInWorkspace);
336 this._domFileSystem.root.getFile(path, {create: true}, fileEntryLoaded.bind( this), errorHandler.bind(this));
337
338 /**
339 * @param {!FileEntry} entry
340 * @this {Workspace.IsolatedFileSystem}
341 */
342 function fileEntryLoaded(entry) {
343 entry.createWriter(fileWriterCreated.bind(this), errorHandler.bind(this));
344 }
345
346 /**
347 * @param {!FileWriter} fileWriter
348 * @this {Workspace.IsolatedFileSystem}
349 */
350 function fileWriterCreated(fileWriter) {
351 fileWriter.onerror = errorHandler.bind(this);
352 fileWriter.onwriteend = fileWritten;
353 var blob = new Blob([content], {type: 'text/plain'});
354 fileWriter.write(blob);
355
356 function fileWritten() {
357 fileWriter.onwriteend = callback;
358 fileWriter.truncate(blob.size);
359 }
360 }
361
362 /**
363 * @this {Workspace.IsolatedFileSystem}
364 */
365 function errorHandler(error) {
366 var errorMessage = Workspace.IsolatedFileSystem.errorMessage(error);
367 console.error(errorMessage + ' when setting content for file \'' + (this._ path + '/' + path) + '\'');
368 callback();
369 }
370 }
371
372 /**
373 * @param {string} path
374 * @param {string} newName
375 * @param {function(boolean, string=)} callback
376 */
377 renameFile(path, newName, callback) {
378 newName = newName ? newName.trim() : newName;
379 if (!newName || newName.indexOf('/') !== -1) {
380 callback(false);
381 return;
382 }
383 var fileEntry;
384 var dirEntry;
385
386 this._domFileSystem.root.getFile(path, undefined, fileEntryLoaded.bind(this) , errorHandler.bind(this));
387
388 /**
389 * @param {!FileEntry} entry
390 * @this {Workspace.IsolatedFileSystem}
391 */
392 function fileEntryLoaded(entry) {
393 if (entry.name === newName) {
394 callback(false);
395 return;
396 }
397
398 fileEntry = entry;
399 fileEntry.getParent(dirEntryLoaded.bind(this), errorHandler.bind(this));
400 }
401
402 /**
403 * @param {!Entry} entry
404 * @this {Workspace.IsolatedFileSystem}
405 */
406 function dirEntryLoaded(entry) {
407 dirEntry = entry;
408 dirEntry.getFile(newName, null, newFileEntryLoaded, newFileEntryLoadErrorH andler.bind(this));
409 }
410
411 /**
412 * @param {!FileEntry} entry
413 */
414 function newFileEntryLoaded(entry) {
415 callback(false);
416 }
417
418 /**
419 * @this {Workspace.IsolatedFileSystem}
420 */
421 function newFileEntryLoadErrorHandler(error) {
422 if (error.name !== 'NotFoundError') {
423 callback(false);
424 return;
425 }
426 fileEntry.moveTo(dirEntry, newName, fileRenamed, errorHandler.bind(this));
427 }
428
429 /**
430 * @param {!FileEntry} entry
431 */
432 function fileRenamed(entry) {
433 callback(true, entry.name);
434 }
435
436 /**
437 * @this {Workspace.IsolatedFileSystem}
438 */
439 function errorHandler(error) {
440 var errorMessage = Workspace.IsolatedFileSystem.errorMessage(error);
441 console.error(errorMessage + ' when renaming file \'' + (this._path + '/' + path) + '\' to \'' + newName + '\'');
442 callback(false);
443 }
444 }
445
446 /**
447 * @param {!DirectoryEntry} dirEntry
448 * @param {function(!Array.<!FileEntry>)} callback
449 */
450 _readDirectory(dirEntry, callback) {
451 var dirReader = dirEntry.createReader();
452 var entries = [];
453
454 function innerCallback(results) {
455 if (!results.length) {
456 callback(entries.sort());
457 } else {
458 entries = entries.concat(toArray(results));
459 dirReader.readEntries(innerCallback, errorHandler);
460 }
461 }
462
463 function toArray(list) {
464 return Array.prototype.slice.call(list || [], 0);
465 }
466
467 dirReader.readEntries(innerCallback, errorHandler);
468
469 function errorHandler(error) {
470 var errorMessage = Workspace.IsolatedFileSystem.errorMessage(error);
471 console.error(errorMessage + ' when reading directory \'' + dirEntry.fullP ath + '\'');
472 callback([]);
473 }
474 }
475
476 /**
477 * @param {string} path
478 * @param {function(!Array.<!FileEntry>)} callback
479 */
480 _requestEntries(path, callback) {
481 this._domFileSystem.root.getDirectory(path, undefined, innerCallback.bind(th is), errorHandler);
482
483 /**
484 * @param {!DirectoryEntry} dirEntry
485 * @this {Workspace.IsolatedFileSystem}
486 */
487 function innerCallback(dirEntry) {
488 this._readDirectory(dirEntry, callback);
489 }
490
491 function errorHandler(error) {
492 var errorMessage = Workspace.IsolatedFileSystem.errorMessage(error);
493 console.error(errorMessage + ' when requesting entry \'' + path + '\'');
494 callback([]);
495 }
496 }
497
498 _saveExcludedFolders() {
499 var settingValue = this._excludedFoldersSetting.get();
500 settingValue[this._path] = this._excludedFolders.valuesArray();
501 this._excludedFoldersSetting.set(settingValue);
502 }
503
504 /**
505 * @param {string} path
506 */
507 addExcludedFolder(path) {
508 this._excludedFolders.add(path);
509 this._saveExcludedFolders();
510 this._manager.dispatchEventToListeners(Workspace.IsolatedFileSystemManager.E vents.ExcludedFolderAdded, path);
511 }
512
513 /**
514 * @param {string} path
515 */
516 removeExcludedFolder(path) {
517 this._excludedFolders.delete(path);
518 this._saveExcludedFolders();
519 this._manager.dispatchEventToListeners(Workspace.IsolatedFileSystemManager.E vents.ExcludedFolderRemoved, path);
520 }
521
522 fileSystemRemoved() {
523 var settingValue = this._excludedFoldersSetting.get();
524 delete settingValue[this._path];
525 this._excludedFoldersSetting.set(settingValue);
526 }
527
528 /**
529 * @param {string} folderPath
530 * @return {boolean}
531 */
532 _isFileExcluded(folderPath) {
533 if (this._excludedFolders.has(folderPath))
534 return true;
535 var regex = this._manager.workspaceFolderExcludePatternSetting().asRegExp();
536 return !!(regex && regex.test(folderPath));
537 }
538
539 /**
540 * @return {!Set<string>}
541 */
542 excludedFolders() {
543 return this._excludedFolders;
544 }
545
546 /**
547 * @param {string} query
548 * @param {!Common.Progress} progress
549 * @param {function(!Array.<string>)} callback
550 */
551 searchInPath(query, progress, callback) {
552 var requestId = this._manager.registerCallback(innerCallback);
553 InspectorFrontendHost.searchInPath(requestId, this._embedderPath, query);
554
555 /**
556 * @param {!Array.<string>} files
557 */
558 function innerCallback(files) {
559 files = files.map(embedderPath => Common.ParsedURL.platformPathToURL(embed derPath));
560 progress.worked(1);
561 callback(files);
562 }
563 }
564
565 /**
566 * @param {!Common.Progress} progress
567 */
568 indexContent(progress) {
569 progress.setTotalWork(1);
570 var requestId = this._manager.registerProgress(progress);
571 InspectorFrontendHost.indexPath(requestId, this._embedderPath);
572 }
573 };
574
575 Workspace.IsolatedFileSystem.ImageExtensions =
576 new Set(['jpeg', 'jpg', 'svg', 'gif', 'webp', 'png', 'ico', 'tiff', 'tif', ' bmp']);
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698