source: Dev/trunk/src/client/util/build/discover.js @ 532

Last change on this file since 532 was 483, checked in by hendrikvanantwerpen, 11 years ago

Added Dojo 1.9.3 release.

File size: 8.9 KB
Line 
1define([
2        "./buildControl",
3        "./fileUtils",
4        "./fs"
5], function(bc, fileUtils, fs){
6        // find all files as given by files, dirs, trees, and packages
7        var
8                dirsProcessed =
9                        // a set of the directory names that have been inspected
10                        {},
11
12                treesDirsFiles = ["trees", "dirs", "files"],
13
14                srcDirs = {},
15
16                destDirs = {},
17
18                getFilepath = fileUtils.getFilepath,
19                catPath = fileUtils.catPath,
20                compactPath = fileUtils.compactPath,
21
22                start = function(resource, tagResource){
23                        if(!resource.tag){
24                                resource.tag = {};
25                        }
26                        if(tagResource){
27                                tagResource(resource);
28                        }
29                        bc.start(resource);
30                        srcDirs[getFilepath(resource.src)] = 1;
31                        destDirs[getFilepath(resource.dest)] = 1;
32                },
33
34                getResourceTagFunction = function(resourceTags){
35                        //resource tags is a map from tag to a function or a regular expression
36                        var getFilterFunction = function(item){
37                                        return typeof item=="function" ?
38                                                item :
39                                                function(filename){
40                                                        return item.test(filename);
41                                                };
42                                },
43                                tag = {},
44                                gotOne  = false;
45                        for(var p in resourceTags){
46                                tag[p] = getFilterFunction(resourceTags[p]);
47                                gotOne  = true;
48                        }
49                        if(!gotOne){
50                                return 0;
51                        }
52                        return function(resource){
53                                for(var p in tag){
54                                        if(tag[p](resource.src, resource.mid, resource)){
55                                                resource.tag[p] = 1;
56                                        }
57                                }
58                        };
59                },
60
61                neverExclude = function(){
62                        return 0;
63                },
64
65                getExcludes = function(excludes){
66                        // excludes is falsy, a function, or a regulare expression
67                        if(!excludes){
68                                return neverExclude;
69                        }else if(typeof excludes=="function"){
70                                return excludes;
71                        }else{
72                                return function(filename){
73                                        return excludes.test(filename);
74                                };
75                        }
76                },
77
78                readSingleDir = function(srcBase, destBase, current, excludes, advise, traverse){
79                        // Read a directory and advise of each child contained therein if the child is
80                        // not excluded.
81                        //
82                        // If traverse is truthy, then traverse the directory tree. When traversing,
83                        // current gives the current position in the traversal relative to srcBase.
84                        // The first call when traversing (or only call when not traversing) must
85                        // have current set to falsy.
86                        //
87                        // Notice that only the complete child path relative to srcBase is submitted
88                        // to excludes. This simplifies constructing exclude functions since srcBase
89                        // will never be part of the input to those functions.
90
91                        var dir = srcBase + (current ? "/" + current : ""),
92                                fullPrefix = dir + "/",
93                                currentPrefix = current ? current + "/" : "",
94                                subdirs = [];
95
96                        // inspect each directory once per build
97                        if(dirsProcessed[dir]){
98                                return;
99                        }
100                        dirsProcessed[dir] = 1;
101
102                        fs.readdirSync(dir).forEach(function(filename){
103                                var current = currentPrefix + filename;
104                                if(!excludes || !excludes(current)){
105                                        var fullFilename = fullPrefix + filename,
106                                                stats = fs.statSync(fullFilename);
107                                        if(stats.isDirectory()){
108                                                subdirs.push(current);
109                                        }else{
110                                                advise(fullFilename, destBase + "/" + current);
111                                        }
112                                }
113                        });
114                        if(traverse && subdirs.length){
115                                subdirs.forEach(function(current){
116                                        readSingleDir(srcBase, destBase, current, excludes, advise, 1);
117                                });
118                        }
119                },
120
121                readFile = function(item, advise){
122                        advise(item[0], item[1]);
123                },
124
125                srcPathExists = function(srcPath){
126                        if(!fileUtils.dirExists(srcPath)){
127                                bc.log("missingDirDuringDiscovery", ["directory", srcPath]);
128                                return 0;
129                        }
130                        return 1;
131                },
132
133                readDir = function(item, advise){
134                        if(srcPathExists(item[0])){
135                                readSingleDir(item[0], item[1], 0, getExcludes(item[2]), advise, 0, 0);
136                        }
137                },
138
139                readTree = function(item, advise){
140                        if(srcPathExists(item[0])){
141                                readSingleDir(item[0], item[1], 0, getExcludes(item[2]), advise, 1);
142                        }
143                },
144
145                discover = {
146                        files:readFile,
147                        dirs:readDir,
148                        trees:readTree
149                },
150
151                processPackage = function(pack, destPack){
152                        // treeItem is the package location tree; it may give explicit exclude instructions
153                        var treeItem;
154                        for(var trees = pack.trees || [], i = 0; i<trees.length; i++){
155                                if(trees[i][0]==pack.location){
156                                        treeItem = trees[i];
157                                        break;
158                                }
159                        }
160                        if(!treeItem){
161                                // create a tree item; don't traverse into hidden, backup, etc. files (e.g., .svn, .git, etc.)
162                                treeItem = [pack.location, destPack.location, /(\/\.)|(^\.)|(~$)/];
163                        }
164
165                        var filenames = [];
166                        readTree(treeItem, function(filename){ filenames.push(filename); });
167
168                        // next, sift filenames to find AMD modules
169                        var
170                                maybeAmdModules = {},
171                                notModules = {},
172                                locationPathLength = pack.location.length + 1,
173                                packName = pack.name,
174                                prefix = packName ? packName + "/" : "",
175                                mainModuleInfo = packName && bc.getSrcModuleInfo(packName),
176                                mainModuleFilename = packName && mainModuleInfo.url;
177                        filenames.forEach(function(filename){
178                                // strip the package location path and the .js suffix(iff any) to get the mid
179                                var
180                                        maybeModule = /\.js$/.test(filename),
181                                        mid = prefix + filename.substring(locationPathLength, maybeModule ? filename.length-3 : filename.length),
182                                        moduleInfo = maybeModule && bc.getSrcModuleInfo(mid);
183                                if(!maybeModule){
184                                        notModules[mid] = [filename, mid];
185                                }else if(filename==mainModuleFilename){
186                                        maybeAmdModules[packName] = mainModuleInfo;
187                                }else{
188                                        // notice that this may result in mapping the module to a different location
189                                        maybeAmdModules[mid] = moduleInfo;
190                                }
191                        });
192
193                        // add modules as per explicit pack.modules vector; this is a way to add modules that map strangely
194                        // (for example "myPackage/foo" maps to the file "myPackage/bar"); recall, packageInfo.modules has two forms:
195                        //
196                        //       modules:{
197                        //               "foo":1,
198                        //               "foo":"path/to/foo/filename.js"
199                        //       }
200                        for(var mid in pack.modules){
201                                var
202                                        fullMid = prefix + mid,
203                                        moduleInfo = bc.getSrcModuleInfo(fullMid);
204                                if(typeof pack.modules[mid]=="string"){
205                                        moduleInfo.url = pack.modules[mid];
206                                }
207                                maybeAmdModules[fullMid] = moduleInfo;
208                                delete notModules[fullMid];
209                        };
210
211                        var tagResource = getResourceTagFunction(pack.resourceTags);
212
213                        // start all the package modules; each property holds a module info object
214                        for(var p in maybeAmdModules){
215                                moduleInfo = maybeAmdModules[p];
216                                var resource = {
217                                        src:moduleInfo.url,
218                                        dest:bc.getDestModuleInfo(moduleInfo.mid).url,
219                                        pid:moduleInfo.pid,
220                                        mid:moduleInfo.mid,
221                                        pack:pack,
222                                        deps:[]
223                                };
224                                start(resource, tagResource);
225                        }
226
227                        // start all the "notModules"
228                        var prefixLength = prefix.length;
229                        for(p in notModules){
230                                resource = {
231                                        src:notModules[p][0],
232                                        // not really an AMD mid, but the filename with installation-dependent prefix stripped
233                                        // this makes tagging easier
234                                        mid:notModules[p][1],
235                                        dest:catPath(destPack.location, p.substring(prefixLength))
236                                };
237                                start(resource, tagResource);
238                        }
239
240                        // finish by processing all the trees, dirs, and files explicitly specified for the package
241                        for(i = 0; i<treesDirsFiles.length; i++){
242                                var set = treesDirsFiles[i];
243                                if(pack[set]){
244                                        pack[set].forEach(function(item){
245                                                discover[set](item, function(src, dest){
246                                                        start({src:src, dest:dest}, tagResource);
247                                                });
248                                        });
249                                }
250                        }
251                },
252
253                discoverPackages = function(){
254                        // discover all the package modules; discover the default package last since it may overlap
255                        // into other packages and we want modules in those other packages to be discovered as members
256                        // of those other packages; not as a module in the default package
257                        for(var p in bc.packages){
258                                processPackage(bc.packages[p], bc.destPackages[p]);
259                        }
260                };
261
262        return function(){
263                ///
264                // build/discover
265
266                bc.waiting++; // matches *1*
267
268                // start the synthetic report resource
269                start({
270                        tag:{report:1},
271                        src:"*report",
272                        dest:"*report",
273                        reports:[]
274                });
275
276                discoverPackages();
277
278                // discover all trees, dirs, and files
279                var tagResource = getResourceTagFunction(bc.resourceTags);
280                for(var i = 0; i<treesDirsFiles.length; i++){
281                        var set = treesDirsFiles[i];
282                        bc[set].forEach(function(item){
283                                discover[set](item, function(src, dest){
284                                        start({src:src, dest:dest}, tagResource);
285                                });
286                        });
287                }
288
289                // advise all modules that are to be written as a layer
290                // advise the loader of boot layers
291                for(var mid in bc.layers){
292                        var
293                                layer = bc.layers[mid],
294                                moduleInfo = bc.getSrcModuleInfo(mid),
295                                resource = bc.resources[moduleInfo.url];
296                        if(!resource){
297                                // this is a synthetic layer (just a set of real modules aggregated but doesn't exist in the source)
298                                resource = {
299                                        tag:{synthetic:1, amd:1},
300                                        src:moduleInfo.url,
301                                        dest:bc.getDestModuleInfo(moduleInfo.mid).url,
302                                        pid:moduleInfo.pid,
303                                        mid:moduleInfo.mid,
304                                        pack:moduleInfo.pack,
305                                        deps:[],
306                                        text:"define([], 1);" + bc.newline,
307                                        getText:function(){
308                                                return this.text;
309                                        },
310                                        encoding:"utf8"
311                                };
312                                start(resource);
313                        }
314                        resource.layer = layer;
315                        if(layer.boot){
316                                if(bc.loader){
317                                        bc.loader.boots.push(resource);
318                                }else{
319                                        bc.log("inputNoLoaderForBoot", ["boot layer", mid]);
320                                }
321                        }
322                }
323
324                bc.passGate(); // matches *1*
325        };
326});
Note: See TracBrowser for help on using the repository browser.