1 | var
|
2 | when = require('when'),
|
3 | fs = require('final-fs'),
|
4 | _ = require('underscore'),
|
5 | parseOptions = require('./parse_options'),
|
6 | pathjs = require('path'),
|
7 | join = require('path').join,
|
8 | debugBase = require('debug'),
|
9 | debug = debugBase('loaddir:directory'),
|
10 | Directory
|
11 | ;
|
12 |
|
13 | Directory = function(options) {
|
14 | var self = this;
|
15 |
|
16 | this.options = options;
|
17 | this.children = [];
|
18 |
|
19 | debug('Directory'.yellow, 'constructor'.blue, self.path);
|
20 |
|
21 |
|
22 | self._watchHandler = _.debounce( _.bind(self._watchHandler, self), 500);
|
23 |
|
24 | options.watchedPaths = options.watchedPaths || [];
|
25 | options.watchers = options.watchers || [];
|
26 |
|
27 | parseOptions.call(this);
|
28 |
|
29 |
|
30 | _.each([ 'top', 'white_list'], function(key) {
|
31 | self[key] = options[key]
|
32 | delete options[key]
|
33 | });
|
34 |
|
35 |
|
36 | this.relativePath = this.relativePath == null ?
|
37 | '' : join(this.relativePath, this.baseName);
|
38 |
|
39 | when().then(function(){
|
40 | if (self.destination)
|
41 | return ensureDirectory(self.destination);
|
42 | });
|
43 |
|
44 | return this;
|
45 |
|
46 | };
|
47 |
|
48 | Directory.prototype.load = function() {
|
49 | var
|
50 | self = this,
|
51 | opts = self.options;
|
52 |
|
53 | debug('Directory'.yellow, '.load'.blue, this.path.green)
|
54 |
|
55 | return fs.readdir(self.path)
|
56 | .then(function(results) {
|
57 | if (self.watch == true || (self.watch !== false && self.watch !== 'files'))
|
58 | self._watch();
|
59 | return when.map(results, _.bind(self.iterate, self));
|
60 | })
|
61 | .otherwise(function(er) {
|
62 | debug('Directory'.yellow, 'not found'.red, er);
|
63 |
|
64 | if (this.watcher) {
|
65 | if (_.contains(self.watchers, self.watcher))
|
66 | self.watchers.splice(_.indexOf(self.watchers, self.watcher), 1)
|
67 |
|
68 | self.watcher.close();
|
69 | }
|
70 |
|
71 | if (self.asObject)
|
72 | delete opts.parent.output[self.baseName];
|
73 | else
|
74 | delete opts.output[self.path];
|
75 |
|
76 | });
|
77 |
|
78 | };
|
79 |
|
80 |
|
81 | Directory.prototype.iterate = function(fileName){
|
82 |
|
83 | var self = this;
|
84 | debug('Directory'.yellow, 'iterate'.blue, fileName.green);
|
85 |
|
86 |
|
87 | var
|
88 | Class,
|
89 | path, baseName, options;
|
90 |
|
91 | path = join(this.path, fileName);
|
92 | baseName = pathjs.basename(fileName, pathjs.extname(fileName));
|
93 |
|
94 | if ( self.exclude(baseName, path) ) return;
|
95 |
|
96 | var black_list = self.buildBlackList(fileName),
|
97 | options = _.extend( _.clone(self.options), {
|
98 | path: path,
|
99 | fileName: fileName,
|
100 | parent: self,
|
101 | black_list: black_list,
|
102 | destination: self.destination,
|
103 | relativePath: self.relativePath,
|
104 | baseName: baseName,
|
105 | existingManifest: self.options.existingManifest && self.options.existingManifest[path],
|
106 | });
|
107 |
|
108 | File = require('./file');
|
109 |
|
110 | return fs.lstat( path )
|
111 | .then(function(stats) {
|
112 |
|
113 | if (stats.isDirectory()) {
|
114 | if (self.asObject)
|
115 |
|
116 | self.output[baseName] = options.output = {};
|
117 | else
|
118 |
|
119 | options.output = self.output;
|
120 |
|
121 | Class = Directory;
|
122 | } else {
|
123 | Class = require('./file');
|
124 | };
|
125 |
|
126 | var child = new Class(options);
|
127 | child.stats = stats;
|
128 |
|
129 | self.children.push(child);
|
130 |
|
131 | return child.load();
|
132 | });
|
133 |
|
134 | };
|
135 |
|
136 | Directory.prototype.buildBlackList = function(fileName) {
|
137 |
|
138 | var self = this;
|
139 | var output = [];
|
140 |
|
141 | _.each(self.black_list, function(path) {
|
142 | var parts = path.split('/')
|
143 | if (parts[0] == fileName && parts.slice(1).length)
|
144 | output.push(parts.slice(1).join('/'));
|
145 | });
|
146 |
|
147 | return output
|
148 |
|
149 |
|
150 | };
|
151 |
|
152 |
|
153 | Directory.prototype.exclude = function(fileName, path) {
|
154 |
|
155 | var self = this;
|
156 | if (!self.asObject && self.output[path] || self.asObject && self.output[fileName])
|
157 | debug(' Directory exclude. Already exists on output '.red,
|
158 | !self.asObject && self.output[path],
|
159 | self.asObject && self.output[fileName],
|
160 | fileName, path);
|
161 |
|
162 |
|
163 | return (!self.asObject && self.output[path]) || (self.asObject && self.output[fileName]) ||
|
164 |
|
165 |
|
166 | (self.white_list && !_.include(self.white_list, fileName)) ||
|
167 | (_.any(self.black_list, function(bl, key) {
|
168 |
|
169 | if (bl == fileName) {
|
170 | delete self.black_list[key]
|
171 | return true;
|
172 | } else
|
173 | return bl == '*';
|
174 | }) ) ||
|
175 |
|
176 |
|
177 | (fileName.charAt(0) == '.');
|
178 |
|
179 | };
|
180 |
|
181 | Directory.prototype._watch = function(){
|
182 |
|
183 | var self = this;
|
184 | if (self.watcher || _.include(self.watchedPaths, self.path))
|
185 | return
|
186 |
|
187 | debug('Directory'.yellow, 'start_watching'.blue, self.path.green)
|
188 |
|
189 | self.watchedPaths.push(self.path);
|
190 | self.watcher = fs.watch(self.path, _.bind(self._watchHandler, self))
|
191 |
|
192 | };
|
193 |
|
194 | Directory.prototype._watchHandler = function(){
|
195 |
|
196 | debugBase('loaddir:watch')('Directory'.yellow, '_watchHandler'.blue, this.options.path.green);
|
197 |
|
198 | if (this.watchHandler)
|
199 | this.watchHandler();
|
200 | else
|
201 | this.load();
|
202 |
|
203 | };
|
204 |
|
205 | Directory.prototype.buildManifest = function(manifest){
|
206 |
|
207 | var self = this;
|
208 |
|
209 | var manifest = manifest || {};
|
210 |
|
211 | _.each(self.children, function(child) {
|
212 |
|
213 | manifest[child.path] = (function(){
|
214 | if (child instanceof Directory)
|
215 | return {
|
216 | isDir: true,
|
217 | children: child.buildManifest(),
|
218 | }
|
219 | else
|
220 |
|
221 | return {
|
222 | isFile: true,
|
223 | mtime: child.stats.mtime,
|
224 | fileData: child.fileData,
|
225 | fileContents: child.fileContents,
|
226 | };
|
227 | })();
|
228 | });
|
229 |
|
230 | return manifest;
|
231 | };
|
232 |
|
233 | function ensureDirectory(path) {
|
234 |
|
235 | return fs.exists(path).then(function(exists) {
|
236 | if (!exists) return fs.mkdir(path);
|
237 | });
|
238 | };
|
239 |
|
240 | module.exports = Directory;
|