Home | History | Annotate | Download | only in workspace
      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.createRegExpSetting("workspaceFolderExcludePattern", defaultExcludedFoldersPattern, WebInspector.isWin() ? "i" : "");
     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         this._rebuildIndexes();
    125     },
    126 
    127     _saveToSettings: function()
    128     {
    129         var savedMapping = this._fileSystemMappings;
    130         this._fileSystemMappingSetting.set(savedMapping);
    131 
    132         var savedExcludedFolders = this._excludedFolders;
    133         this._excludedFoldersSetting.set(savedExcludedFolders);
    134 
    135         this._rebuildIndexes();
    136     },
    137 
    138     _rebuildIndexes: function()
    139     {
    140         // We are building an index here to search for the longest url prefix match faster.
    141         this._mappingForURLPrefix = {};
    142         this._urlPrefixes = [];
    143         for (var fileSystemPath in this._fileSystemMappings) {
    144             var fileSystemMapping = this._fileSystemMappings[fileSystemPath];
    145             for (var i = 0; i < fileSystemMapping.length; ++i) {
    146                 var entry = fileSystemMapping[i];
    147                 this._mappingForURLPrefix[entry.urlPrefix] = entry;
    148                 this._urlPrefixes.push(entry.urlPrefix);
    149             }
    150         }
    151         this._urlPrefixes.sort();
    152     },
    153 
    154     /**
    155      * @param {string} fileSystemPath
    156      */
    157     addFileSystem: function(fileSystemPath)
    158     {
    159         if (this._fileSystemMappings[fileSystemPath])
    160             return;
    161 
    162         this._fileSystemMappings[fileSystemPath] = [];
    163         this._saveToSettings();
    164     },
    165 
    166     /**
    167      * @param {string} fileSystemPath
    168      */
    169     removeFileSystem: function(fileSystemPath)
    170     {
    171         if (!this._fileSystemMappings[fileSystemPath])
    172             return;
    173         delete this._fileSystemMappings[fileSystemPath];
    174         delete this._excludedFolders[fileSystemPath];
    175         this._saveToSettings();
    176     },
    177 
    178     /**
    179      * @param {string} fileSystemPath
    180      * @param {string} urlPrefix
    181      * @param {string} pathPrefix
    182      */
    183     addFileMapping: function(fileSystemPath, urlPrefix, pathPrefix)
    184     {
    185         var entry = new WebInspector.FileSystemMapping.Entry(fileSystemPath, urlPrefix, pathPrefix);
    186         this._fileSystemMappings[fileSystemPath].push(entry);
    187         this._saveToSettings();
    188         this.dispatchEventToListeners(WebInspector.FileSystemMapping.Events.FileMappingAdded, entry);
    189     },
    190 
    191     /**
    192      * @param {string} fileSystemPath
    193      * @param {string} urlPrefix
    194      * @param {string} pathPrefix
    195      */
    196     removeFileMapping: function(fileSystemPath, urlPrefix, pathPrefix)
    197     {
    198         var entry = this._mappingEntryForPathPrefix(fileSystemPath, pathPrefix);
    199         if (!entry)
    200             return;
    201         this._fileSystemMappings[fileSystemPath].remove(entry);
    202         this._saveToSettings();
    203         this.dispatchEventToListeners(WebInspector.FileSystemMapping.Events.FileMappingRemoved, entry);
    204     },
    205 
    206     /**
    207      * @param {string} fileSystemPath
    208      * @param {string} excludedFolderPath
    209      */
    210     addExcludedFolder: function(fileSystemPath, excludedFolderPath)
    211     {
    212         if (!this._excludedFolders[fileSystemPath])
    213             this._excludedFolders[fileSystemPath] = [];
    214         var entry = new WebInspector.FileSystemMapping.ExcludedFolderEntry(fileSystemPath, excludedFolderPath);
    215         this._excludedFolders[fileSystemPath].push(entry);
    216         this._saveToSettings();
    217         this.dispatchEventToListeners(WebInspector.FileSystemMapping.Events.ExcludedFolderAdded, entry);
    218     },
    219 
    220     /**
    221      * @param {string} fileSystemPath
    222      * @param {string} path
    223      */
    224     removeExcludedFolder: function(fileSystemPath, path)
    225     {
    226         var entry = this._excludedFolderEntryForPath(fileSystemPath, path);
    227         if (!entry)
    228             return;
    229         this._excludedFolders[fileSystemPath].remove(entry);
    230         this._saveToSettings();
    231         this.dispatchEventToListeners(WebInspector.FileSystemMapping.Events.ExcludedFolderRemoved, entry);
    232     },
    233 
    234     /**
    235      * @return {!Array.<string>}
    236      */
    237     fileSystemPaths: function()
    238     {
    239         return Object.keys(this._fileSystemMappings);
    240     },
    241 
    242     /**
    243      * @param {string} url
    244      * @return {?WebInspector.FileSystemMapping.Entry}
    245      */
    246     _mappingEntryForURL: function(url)
    247     {
    248         for (var i = this._urlPrefixes.length - 1; i >= 0; --i) {
    249             var urlPrefix = this._urlPrefixes[i];
    250             if (url.startsWith(urlPrefix))
    251                 return this._mappingForURLPrefix[urlPrefix];
    252         }
    253         return null;
    254     },
    255 
    256     /**
    257      * @param {string} fileSystemPath
    258      * @param {string} path
    259      * @return {?WebInspector.FileSystemMapping.ExcludedFolderEntry}
    260      */
    261     _excludedFolderEntryForPath: function(fileSystemPath, path)
    262     {
    263         var entries = this._excludedFolders[fileSystemPath];
    264         if (!entries)
    265             return null;
    266 
    267         for (var i = 0; i < entries.length; ++i) {
    268             if (entries[i].path === path)
    269                 return entries[i];
    270         }
    271         return null;
    272     },
    273 
    274     /**
    275      * @param {string} fileSystemPath
    276      * @param {string} filePath
    277      * @return {?WebInspector.FileSystemMapping.Entry}
    278      */
    279     _mappingEntryForPath: function(fileSystemPath, filePath)
    280     {
    281         var entries = this._fileSystemMappings[fileSystemPath];
    282         if (!entries)
    283             return null;
    284 
    285         var entry = null;
    286         for (var i = 0; i < entries.length; ++i) {
    287             var pathPrefix = entries[i].pathPrefix;
    288             // We are looking for the longest pathPrefix match.
    289             if (entry && entry.pathPrefix.length > pathPrefix.length)
    290                 continue;
    291             if (filePath.startsWith(pathPrefix.substr(1)))
    292                 entry = entries[i];
    293         }
    294         return entry;
    295     },
    296 
    297     /**
    298      * @param {string} fileSystemPath
    299      * @param {string} pathPrefix
    300      * @return {?WebInspector.FileSystemMapping.Entry}
    301      */
    302     _mappingEntryForPathPrefix: function(fileSystemPath, pathPrefix)
    303     {
    304         var entries = this._fileSystemMappings[fileSystemPath];
    305         for (var i = 0; i < entries.length; ++i) {
    306             if (pathPrefix === entries[i].pathPrefix)
    307                 return entries[i];
    308         }
    309         return null;
    310     },
    311 
    312     /**
    313      * @param {string} fileSystemPath
    314      * @param {string} folderPath
    315      * @return {boolean}
    316      */
    317     isFileExcluded: function(fileSystemPath, folderPath)
    318     {
    319         var excludedFolders = this._excludedFolders[fileSystemPath] || [];
    320         for (var i = 0; i < excludedFolders.length; ++i) {
    321             var entry = excludedFolders[i];
    322             if (entry.path === folderPath)
    323                 return true;
    324         }
    325         var regex = WebInspector.settings.workspaceFolderExcludePattern.asRegExp();
    326         return regex && regex.test(folderPath);
    327     },
    328 
    329     /**
    330      * @param {string} fileSystemPath
    331      * @return {!Array.<!WebInspector.FileSystemMapping.ExcludedFolderEntry>}
    332      */
    333     excludedFolders: function(fileSystemPath)
    334     {
    335         var excludedFolders = this._excludedFolders[fileSystemPath];
    336         return excludedFolders ? excludedFolders.slice() : [];
    337     },
    338 
    339     /**
    340      * @param {string} fileSystemPath
    341      * @return {!Array.<!WebInspector.FileSystemMapping.Entry>}
    342      */
    343     mappingEntries: function(fileSystemPath)
    344     {
    345         return this._fileSystemMappings[fileSystemPath].slice();
    346     },
    347 
    348     /**
    349      * @param {string} url
    350      * @return {boolean}
    351      */
    352     hasMappingForURL: function(url)
    353     {
    354         return !!this._mappingEntryForURL(url);
    355     },
    356 
    357     /**
    358      * @param {string} url
    359      * @return {?{fileSystemPath: string, filePath: string}}
    360      */
    361     fileForURL: function(url)
    362     {
    363         var entry = this._mappingEntryForURL(url);
    364         if (!entry)
    365             return null;
    366         var file = {};
    367         file.fileSystemPath = entry.fileSystemPath;
    368         file.filePath = entry.pathPrefix.substr(1) + url.substr(entry.urlPrefix.length);
    369         return file;
    370     },
    371 
    372     /**
    373      * @param {string} fileSystemPath
    374      * @param {string} filePath
    375      * @return {string}
    376      */
    377     urlForPath: function(fileSystemPath, filePath)
    378     {
    379         var entry = this._mappingEntryForPath(fileSystemPath, filePath);
    380         if (!entry)
    381             return "";
    382         return entry.urlPrefix + filePath.substring(entry.pathPrefix.length - 1);
    383     },
    384 
    385     /**
    386      * @param {string} url
    387      */
    388     removeMappingForURL: function(url)
    389     {
    390         var entry = this._mappingEntryForURL(url);
    391         if (!entry)
    392             return;
    393         this._fileSystemMappings[entry.fileSystemPath].remove(entry);
    394         this._saveToSettings();
    395     },
    396 
    397     /**
    398      * @param {string} url
    399      * @param {string} fileSystemPath
    400      * @param {string} filePath
    401      */
    402     addMappingForResource: function(url, fileSystemPath, filePath)
    403     {
    404         var commonPathSuffixLength = 0;
    405         var normalizedFilePath = "/" + filePath;
    406         for (var i = 0; i < normalizedFilePath.length; ++i) {
    407             var filePathCharacter = normalizedFilePath[normalizedFilePath.length - 1 - i];
    408             var urlCharacter = url[url.length - 1 - i];
    409             if (filePathCharacter !== urlCharacter)
    410                 break;
    411             if (filePathCharacter === "/")
    412                 commonPathSuffixLength = i;
    413         }
    414         var pathPrefix = normalizedFilePath.substr(0, normalizedFilePath.length - commonPathSuffixLength);
    415         var urlPrefix = url.substr(0, url.length - commonPathSuffixLength);
    416         this.addFileMapping(fileSystemPath, urlPrefix, pathPrefix);
    417     },
    418 
    419     __proto__: WebInspector.Object.prototype
    420 }
    421 
    422 /**
    423  * @constructor
    424  * @param {string} fileSystemPath
    425  * @param {string} urlPrefix
    426  * @param {string} pathPrefix
    427  */
    428 WebInspector.FileSystemMapping.Entry = function(fileSystemPath, urlPrefix, pathPrefix)
    429 {
    430     this.fileSystemPath = fileSystemPath;
    431     this.urlPrefix = urlPrefix;
    432     this.pathPrefix = pathPrefix;
    433 }
    434 
    435 /**
    436  * @constructor
    437  * @param {string} fileSystemPath
    438  * @param {string} path
    439  */
    440 WebInspector.FileSystemMapping.ExcludedFolderEntry = function(fileSystemPath, path)
    441 {
    442     this.fileSystemPath = fileSystemPath;
    443     this.path = path;
    444 }
    445