Home | History | Annotate | Download | only in front_end
      1 /*
      2  * Copyright (C) 2012 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  * @extends {WebInspector.Object}
     34  */
     35 WebInspector.FileSystemMapping = function()
     36 {
     37     WebInspector.Object.call(this);
     38     this._fileSystemMappingSetting = WebInspector.settings.createSetting("fileSystemMapping", {});
     39     this._excludedFoldersSetting = WebInspector.settings.createSetting("workspaceExcludedFolders", {});
     40     var defaultCommonExcludedFolders = [
     41         "/\\.git/",
     42         "/\\.sass-cache/",
     43         "/\\.hg/",
     44         "/\\.idea/",
     45         "/\\.svn/",
     46         "/\\.cache/",
     47         "/\\.project/"
     48     ];
     49     var defaultWinExcludedFolders = [
     50         "/Thumbs.db$",
     51         "/ehthumbs.db$",
     52         "/Desktop.ini$",
     53         "/\\$RECYCLE.BIN/"
     54     ];
     55     var defaultMacExcludedFolders = [
     56         "/\\.DS_Store$",
     57         "/\\.Trashes$",
     58         "/\\.Spotlight-V100$",
     59         "/\\.AppleDouble$",
     60         "/\\.LSOverride$",
     61         "/Icon$",
     62         "/\\._.*$"
     63     ];
     64     var defaultLinuxExcludedFolders = [
     65         "/.*~$"
     66     ];
     67     var defaultExcludedFolders = defaultCommonExcludedFolders;
     68     if (WebInspector.isWin())
     69         defaultExcludedFolders = defaultExcludedFolders.concat(defaultWinExcludedFolders);
     70     else if (WebInspector.isMac())
     71         defaultExcludedFolders = defaultExcludedFolders.concat(defaultMacExcludedFolders);
     72     else
     73         defaultExcludedFolders = defaultExcludedFolders.concat(defaultLinuxExcludedFolders);
     74     var defaultExcludedFoldersPattern = defaultExcludedFolders.join("|");
     75     WebInspector.settings.workspaceFolderExcludePattern = WebInspector.settings.createSetting("workspaceFolderExcludePattern", defaultExcludedFoldersPattern);
     76     /** @type {!Object.<string, !Array.<!WebInspector.FileSystemMapping.Entry>>} */
     77     this._fileSystemMappings = {};
     78     /** @type {!Object.<string, !Array.<!WebInspector.FileSystemMapping.ExcludedFolderEntry>>} */
     79     this._excludedFolders = {};
     80     this._loadFromSettings();
     81 }
     82 
     83 WebInspector.FileSystemMapping.Events = {
     84     FileMappingAdded: "FileMappingAdded",
     85     FileMappingRemoved: "FileMappingRemoved",
     86     ExcludedFolderAdded: "ExcludedFolderAdded",
     87     ExcludedFolderRemoved: "ExcludedFolderRemoved"
     88 }
     89 
     90 
     91 WebInspector.FileSystemMapping.prototype = {
     92     _loadFromSettings: function()
     93     {
     94         var savedMapping = this._fileSystemMappingSetting.get();
     95         this._fileSystemMappings = {};
     96         for (var fileSystemPath in savedMapping) {
     97             var savedFileSystemMappings = savedMapping[fileSystemPath];
     98 
     99             this._fileSystemMappings[fileSystemPath] = [];
    100             var fileSystemMappings = this._fileSystemMappings[fileSystemPath];
    101 
    102             for (var i = 0; i < savedFileSystemMappings.length; ++i) {
    103                 var savedEntry = savedFileSystemMappings[i];
    104                 var entry = new WebInspector.FileSystemMapping.Entry(savedEntry.fileSystemPath, savedEntry.urlPrefix, savedEntry.pathPrefix);
    105                 fileSystemMappings.push(entry);
    106             }
    107         }
    108 
    109         var savedExcludedFolders = this._excludedFoldersSetting.get();
    110         this._excludedFolders = {};
    111         for (var fileSystemPath in savedExcludedFolders) {
    112             var savedExcludedFoldersForPath = savedExcludedFolders[fileSystemPath];
    113 
    114             this._excludedFolders[fileSystemPath] = [];
    115             var excludedFolders = this._excludedFolders[fileSystemPath];
    116 
    117             for (var i = 0; i < savedExcludedFoldersForPath.length; ++i) {
    118                 var savedEntry = savedExcludedFoldersForPath[i];
    119                 var entry = new WebInspector.FileSystemMapping.ExcludedFolderEntry(savedEntry.fileSystemPath, savedEntry.path);
    120                 excludedFolders.push(entry);
    121             }
    122         }
    123 
    124         var workspaceFolderExcludePattern = WebInspector.settings.workspaceFolderExcludePattern.get()
    125         try {
    126             var flags = WebInspector.isWin() ? "i" : "";
    127             this._workspaceFolderExcludeRegex = workspaceFolderExcludePattern ? new RegExp(workspaceFolderExcludePattern, flags) : null;
    128         } catch (e) {
    129         }
    130 
    131         this._rebuildIndexes();
    132     },
    133 
    134     _saveToSettings: function()
    135     {
    136         var savedMapping = this._fileSystemMappings;
    137         this._fileSystemMappingSetting.set(savedMapping);
    138 
    139         var savedExcludedFolders = this._excludedFolders;
    140         this._excludedFoldersSetting.set(savedExcludedFolders);
    141 
    142         this._rebuildIndexes();
    143     },
    144 
    145     _rebuildIndexes: function()
    146     {
    147         // We are building an index here to search for the longest url prefix match faster.
    148         this._mappingForURLPrefix = {};
    149         this._urlPrefixes = [];
    150         for (var fileSystemPath in this._fileSystemMappings) {
    151             var fileSystemMapping = this._fileSystemMappings[fileSystemPath];
    152             for (var i = 0; i < fileSystemMapping.length; ++i) {
    153                 var entry = fileSystemMapping[i];
    154                 this._mappingForURLPrefix[entry.urlPrefix] = entry;
    155                 this._urlPrefixes.push(entry.urlPrefix);
    156             }
    157         }
    158         this._urlPrefixes.sort();
    159     },
    160 
    161     /**
    162      * @param {string} fileSystemPath
    163      */
    164     addFileSystem: function(fileSystemPath)
    165     {
    166         if (this._fileSystemMappings[fileSystemPath])
    167             return;
    168 
    169         this._fileSystemMappings[fileSystemPath] = [];
    170         this._saveToSettings();
    171     },
    172 
    173     /**
    174      * @param {string} fileSystemPath
    175      */
    176     removeFileSystem: function(fileSystemPath)
    177     {
    178         if (!this._fileSystemMappings[fileSystemPath])
    179             return;
    180         delete this._fileSystemMappings[fileSystemPath];
    181         delete this._excludedFolders[fileSystemPath];
    182         this._saveToSettings();
    183     },
    184 
    185     /**
    186      * @param {string} fileSystemPath
    187      * @param {string} urlPrefix
    188      * @param {string} pathPrefix
    189      */
    190     addFileMapping: function(fileSystemPath, urlPrefix, pathPrefix)
    191     {
    192         var entry = new WebInspector.FileSystemMapping.Entry(fileSystemPath, urlPrefix, pathPrefix);
    193         this._fileSystemMappings[fileSystemPath].push(entry);
    194         this._saveToSettings();
    195         this.dispatchEventToListeners(WebInspector.FileSystemMapping.Events.FileMappingAdded, entry);
    196     },
    197 
    198     /**
    199      * @param {string} fileSystemPath
    200      * @param {string} urlPrefix
    201      * @param {string} pathPrefix
    202      */
    203     removeFileMapping: function(fileSystemPath, urlPrefix, pathPrefix)
    204     {
    205         var entry = this._mappingEntryForPathPrefix(fileSystemPath, pathPrefix);
    206         if (!entry)
    207             return;
    208         this._fileSystemMappings[fileSystemPath].remove(entry);
    209         this._saveToSettings();
    210         this.dispatchEventToListeners(WebInspector.FileSystemMapping.Events.FileMappingRemoved, entry);
    211     },
    212 
    213     /**
    214      * @param {string} fileSystemPath
    215      * @param {string} excludedFolderPath
    216      */
    217     addExcludedFolder: function(fileSystemPath, excludedFolderPath)
    218     {
    219         if (!this._excludedFolders[fileSystemPath])
    220             this._excludedFolders[fileSystemPath] = [];
    221         var entry = new WebInspector.FileSystemMapping.ExcludedFolderEntry(fileSystemPath, excludedFolderPath);
    222         this._excludedFolders[fileSystemPath].push(entry);
    223         this._saveToSettings();
    224         this.dispatchEventToListeners(WebInspector.FileSystemMapping.Events.ExcludedFolderAdded, entry);
    225     },
    226 
    227     /**
    228      * @param {string} fileSystemPath
    229      * @param {string} path
    230      */
    231     removeExcludedFolder: function(fileSystemPath, path)
    232     {
    233         var entry = this._excludedFolderEntryForPath(fileSystemPath, path);
    234         if (!entry)
    235             return;
    236         this._excludedFolders[fileSystemPath].remove(entry);
    237         this._saveToSettings();
    238         this.dispatchEventToListeners(WebInspector.FileSystemMapping.Events.ExcludedFolderRemoved, entry);
    239     },
    240 
    241     /**
    242      * @return {!Array.<string>}
    243      */
    244     fileSystemPaths: function()
    245     {
    246         return Object.keys(this._fileSystemMappings);
    247     },
    248 
    249     /**
    250      * @param {string} url
    251      * @return {?WebInspector.FileSystemMapping.Entry}
    252      */
    253     _mappingEntryForURL: function(url)
    254     {
    255         for (var i = this._urlPrefixes.length - 1; i >= 0; --i) {
    256             var urlPrefix = this._urlPrefixes[i];
    257             if (url.startsWith(urlPrefix))
    258                 return this._mappingForURLPrefix[urlPrefix];
    259         }
    260         return null;
    261     },
    262 
    263     /**
    264      * @param {string} fileSystemPath
    265      * @param {string} path
    266      * @return {?WebInspector.FileSystemMapping.ExcludedFolderEntry}
    267      */
    268     _excludedFolderEntryForPath: function(fileSystemPath, path)
    269     {
    270         var entries = this._excludedFolders[fileSystemPath];
    271         if (!entries)
    272             return null;
    273 
    274         for (var i = 0; i < entries.length; ++i) {
    275             if (entries[i].path === path)
    276                 return entries[i];
    277         }
    278         return null;
    279     },
    280 
    281     /**
    282      * @param {string} fileSystemPath
    283      * @param {string} filePath
    284      * @return {?WebInspector.FileSystemMapping.Entry}
    285      */
    286     _mappingEntryForPath: function(fileSystemPath, filePath)
    287     {
    288         var entries = this._fileSystemMappings[fileSystemPath];
    289         if (!entries)
    290             return null;
    291 
    292         var entry = null;
    293         for (var i = 0; i < entries.length; ++i) {
    294             var pathPrefix = entries[i].pathPrefix;
    295             // We are looking for the longest pathPrefix match.
    296             if (entry && entry.pathPrefix.length > pathPrefix.length)
    297                 continue;
    298             if (filePath.startsWith(pathPrefix.substr(1)))
    299                 entry = entries[i];
    300         }
    301         return entry;
    302     },
    303 
    304     /**
    305      * @param {string} fileSystemPath
    306      * @param {string} pathPrefix
    307      * @return {?WebInspector.FileSystemMapping.Entry}
    308      */
    309     _mappingEntryForPathPrefix: function(fileSystemPath, pathPrefix)
    310     {
    311         var entries = this._fileSystemMappings[fileSystemPath];
    312         for (var i = 0; i < entries.length; ++i) {
    313             if (pathPrefix === entries[i].pathPrefix)
    314                 return entries[i];
    315         }
    316         return null;
    317     },
    318 
    319     /**
    320      * @param {string} fileSystemPath
    321      * @param {string} folderPath
    322      * @return {boolean}
    323      */
    324     isFileExcluded: function(fileSystemPath, folderPath)
    325     {
    326         var excludedFolders = this._excludedFolders[fileSystemPath] || [];
    327         for (var i = 0; i < excludedFolders.length; ++i) {
    328             var entry = excludedFolders[i];
    329             if (entry.path === folderPath)
    330                 return true;
    331         }
    332         return this._workspaceFolderExcludeRegex && this._workspaceFolderExcludeRegex.test(folderPath);
    333     },
    334 
    335     /**
    336      * @param {string} fileSystemPath
    337      * @return {!Array.<!WebInspector.FileSystemMapping.ExcludedFolderEntry>}
    338      */
    339     excludedFolders: function(fileSystemPath)
    340     {
    341         var excludedFolders = this._excludedFolders[fileSystemPath];
    342         return excludedFolders ? excludedFolders.slice() : [];
    343     },
    344 
    345     /**
    346      * @param {string} fileSystemPath
    347      * @return {!Array.<!WebInspector.FileSystemMapping.Entry>}
    348      */
    349     mappingEntries: function(fileSystemPath)
    350     {
    351         return this._fileSystemMappings[fileSystemPath].slice();
    352     },
    353 
    354     /**
    355      * @param {string} url
    356      * @return {boolean}
    357      */
    358     hasMappingForURL: function(url)
    359     {
    360         return !!this._mappingEntryForURL(url);
    361     },
    362 
    363     /**
    364      * @param {string} url
    365      * @return {?{fileSystemPath: string, filePath: string}}
    366      */
    367     fileForURL: function(url)
    368     {
    369         var entry = this._mappingEntryForURL(url);
    370         if (!entry)
    371             return null;
    372         var file = {};
    373         file.fileSystemPath = entry.fileSystemPath;
    374         file.filePath = entry.pathPrefix.substr(1) + url.substr(entry.urlPrefix.length);
    375         return file;
    376     },
    377 
    378     /**
    379      * @param {string} fileSystemPath
    380      * @param {string} filePath
    381      * @return {string}
    382      */
    383     urlForPath: function(fileSystemPath, filePath)
    384     {
    385         var entry = this._mappingEntryForPath(fileSystemPath, filePath);
    386         if (!entry)
    387             return "";
    388         return entry.urlPrefix + filePath.substring(entry.pathPrefix.length - 1);
    389     },
    390 
    391     /**
    392      * @param {string} url
    393      */
    394     removeMappingForURL: function(url)
    395     {
    396         var entry = this._mappingEntryForURL(url);
    397         if (!entry)
    398             return;
    399         this._fileSystemMappings[entry.fileSystemPath].remove(entry);
    400         this._saveToSettings();
    401     },
    402 
    403     /**
    404      * @param {string} url
    405      * @param {string} fileSystemPath
    406      * @param {string} filePath
    407      */
    408     addMappingForResource: function(url, fileSystemPath, filePath)
    409     {
    410         var commonPathSuffixLength = 0;
    411         var normalizedFilePath = "/" + filePath;
    412         for (var i = 0; i < normalizedFilePath.length; ++i) {
    413             var filePathCharacter = normalizedFilePath[normalizedFilePath.length - 1 - i];
    414             var urlCharacter = url[url.length - 1 - i];
    415             if (filePathCharacter !== urlCharacter)
    416                 break;
    417             if (filePathCharacter === "/")
    418                 commonPathSuffixLength = i;
    419         }
    420         var pathPrefix = normalizedFilePath.substr(0, normalizedFilePath.length - commonPathSuffixLength);
    421         var urlPrefix = url.substr(0, url.length - commonPathSuffixLength);
    422         this.addFileMapping(fileSystemPath, urlPrefix, pathPrefix);
    423     },
    424 
    425     __proto__: WebInspector.Object.prototype
    426 }
    427 
    428 /**
    429  * @constructor
    430  * @param {string} fileSystemPath
    431  * @param {string} urlPrefix
    432  * @param {string} pathPrefix
    433  */
    434 WebInspector.FileSystemMapping.Entry = function(fileSystemPath, urlPrefix, pathPrefix)
    435 {
    436     this.fileSystemPath = fileSystemPath;
    437     this.urlPrefix = urlPrefix;
    438     this.pathPrefix = pathPrefix;
    439 }
    440 
    441 /**
    442  * @constructor
    443  * @param {string} fileSystemPath
    444  * @param {string} path
    445  */
    446 WebInspector.FileSystemMapping.ExcludedFolderEntry = function(fileSystemPath, path)
    447 {
    448     this.fileSystemPath = fileSystemPath;
    449     this.path = path;
    450 }
    451