| 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 |