1 | 'use strict';
|
2 |
|
3 | var exit = process.exit.bind(process);
|
4 |
|
5 | var fs = require('fs'),
|
6 | path = require('path'),
|
7 | util = require('gulp-util'),
|
8 | debug = require('gulp-debug'),
|
9 | watch = require('gulp-watch'),
|
10 | filter = require('gulp-filter'),
|
11 | sequence = require('gulp-sequence');
|
12 |
|
13 | var getData = require('./utils/data');
|
14 |
|
15 | var mainBowerFiles = require('main-bower-files');
|
16 |
|
17 | var errorHandler = function(e) {
|
18 | util.log(util.colors.red(e.message || e.toString()));
|
19 | this.emit('end');
|
20 | };
|
21 |
|
22 | function expandVariables(obj, data) {
|
23 | if (typeof obj === 'string') {
|
24 | return obj.replace(/\$\{(\w+)\}/g, function(match, key) {
|
25 | return data[key] || match;
|
26 | });
|
27 | }
|
28 |
|
29 | if (typeof obj === 'object') {
|
30 | for (var key in obj) {
|
31 | obj[key] = expandVariables(obj[key], data);
|
32 | }
|
33 | }
|
34 |
|
35 | return obj;
|
36 | }
|
37 |
|
38 | function to_array(obj) {
|
39 | return Array.isArray(obj) ? obj : (obj ? [obj] : []);
|
40 | }
|
41 |
|
42 | function is_file(fullpath) {
|
43 | return fs.existsSync(fullpath) && fs.statSync(fullpath).isFile();
|
44 | }
|
45 |
|
46 | function is_dir(fullpath) {
|
47 | return fs.existsSync(fullpath) && fs.statSync(fullpath).isDirectory();
|
48 | }
|
49 |
|
50 | function hook(chain, set) {
|
51 | if (set) {
|
52 | (Array.isArray(set) ? set : [set])
|
53 | .forEach(function(task) {
|
54 | chain = task(chain, errorHandler)
|
55 | .on('error', errorHandler);
|
56 | });
|
57 | }
|
58 |
|
59 | return chain;
|
60 | }
|
61 |
|
62 | module.exports = function(options) {
|
63 | options = options || {};
|
64 |
|
65 | var gulp = options.gulp;
|
66 |
|
67 | if (!gulp) {
|
68 | util.log(util.colors.red('Missing the main `gulp` instance to work'));
|
69 | exit(1);
|
70 | }
|
71 |
|
72 | var base = typeof util.env.base === 'string' ? util.env.base : 'default',
|
73 | base_dir = path.join(process.cwd(), 'src', options.cwd || '', (util.env.base || options.base) !== false ? base : '');
|
74 |
|
75 | if (!is_dir(base_dir)) {
|
76 | util.log(util.colors.red('The specified base directory `' + base + '` is missing'));
|
77 | exit(1);
|
78 | }
|
79 |
|
80 | var isBuild = options.build || util.env.build,
|
81 | sources = options.files || {},
|
82 | params = options.params || {};
|
83 |
|
84 | params.base = base;
|
85 | options.build = !!isBuild;
|
86 |
|
87 | if (options.bundle === true) {
|
88 | options.bundle = {
|
89 | compact: true
|
90 | };
|
91 | }
|
92 |
|
93 | if (typeof options.bundle === 'object') {
|
94 | options.bundle.compact = options.bundle.compact !== false;
|
95 | }
|
96 |
|
97 | var _errorHandler = errorHandler;
|
98 |
|
99 | errorHandler = function(e) {
|
100 | _errorHandler.call(this, e);
|
101 |
|
102 | if (isBuild) {
|
103 | exit(1);
|
104 | }
|
105 | };
|
106 |
|
107 | sources.filter = sources.filter || [];
|
108 | sources.vendor = sources.vendor || '';
|
109 | sources.bower = sources.bower || '';
|
110 | sources.env = sources.env || '';
|
111 | sources.dest = sources.dest || '';
|
112 | sources.views = sources.views || {};
|
113 | sources.fonts = sources.fonts || {};
|
114 | sources.styles = sources.styles || {};
|
115 | sources.images = sources.images || {};
|
116 | sources.sprites = sources.sprites || {};
|
117 | sources.scripts = sources.scripts || {};
|
118 |
|
119 | var env_file = path.join(base_dir, sources.env || 'env.yml');
|
120 |
|
121 | options.paths = expandVariables({
|
122 | fonts: {
|
123 | on: path.join(base_dir, sources.fonts.src || 'fonts', '**/*.{ttf,otf,eot,woff,woff2,svg}'),
|
124 | cwd: path.join(base_dir, sources.fonts.src || 'fonts'),
|
125 | dest: sources.fonts.dest || 'fonts',
|
126 | glob: '**/*.{ttf,otf,eot,woff,woff2,svg}'
|
127 | },
|
128 | images: {
|
129 | on: path.join(base_dir, sources.images.src || 'images', '**/*.{jpg,jpeg,png,svg}'),
|
130 | cwd: path.join(base_dir, sources.images.src || 'images'),
|
131 | dest: sources.images.dest || 'img',
|
132 | glob: '**/*.{jpg,jpeg,png,svg}'
|
133 | },
|
134 | sprites: {
|
135 | on: path.join(base_dir, sources.sprites.src || 'sprites', '**/*.png'),
|
136 | cwd: path.join(base_dir, sources.sprites.src || 'sprites'),
|
137 | dest: sources.sprites.dest || 'img',
|
138 | glob: '**/*.png'
|
139 | },
|
140 | styles: {
|
141 | on: [
|
142 | path.join(path.dirname(env_file), '_site/**/*.{variables,overrides}'),
|
143 | path.join(base_dir, sources.styles.src || 'styles', '**/*.less'),
|
144 | env_file
|
145 | ],
|
146 | cwd: path.join(base_dir, sources.styles.src || 'styles'),
|
147 | dest: sources.styles.dest || 'css',
|
148 | glob: '**/' + (options.bundle ? 'index' : '*') + '.less',
|
149 | filter: sources.styles.filter || []
|
150 | },
|
151 | scripts: {
|
152 | on: path.join(base_dir, sources.scripts.src || 'scripts', '**/*.{coffee,litcoffee}'),
|
153 | cwd: path.join(base_dir, sources.scripts.src || 'scripts'),
|
154 | dest: sources.scripts.dest || 'js',
|
155 | glob: '**/*.{coffee,litcoffee}',
|
156 | filter: sources.scripts.filter || []
|
157 | },
|
158 | views: {
|
159 | on: [
|
160 | path.join(base_dir, sources.views.src || 'views', '**/*.*'),
|
161 | path.join(path.dirname(env_file), 'data/**/*.yml'),
|
162 | path.join(process.cwd(), 'data/**/*.yml')
|
163 | ],
|
164 | ext: sources.views.ext || '.html',
|
165 | cwd: path.join(base_dir, sources.views.src || 'views'),
|
166 | dest: sources.views.dest || '',
|
167 | glob: '**/*.jade',
|
168 | filter: sources.views.filter || []
|
169 | },
|
170 | data: {
|
171 | src: [
|
172 | path.join(path.dirname(env_file), 'data'),
|
173 | path.join(process.cwd(), 'data')
|
174 | ],
|
175 | glob: '**/*.yml'
|
176 | },
|
177 | vendor: sources.vendor || 'vendor',
|
178 | bower: path.join(process.cwd(), sources.bower || ''),
|
179 | dest: path.join(process.cwd(), sources.dest || 'generated'),
|
180 | env: env_file
|
181 | }, params);
|
182 |
|
183 | options.env = util.env;
|
184 |
|
185 | var copyTask = require('./tasks/copy');
|
186 |
|
187 | var rainbow = {
|
188 | clean: require('./tasks/clean')(options),
|
189 | fonts: copyTask(options, 'fonts'),
|
190 | images: copyTask(options, 'images'),
|
191 | sprites: require('./tasks/sprites')(options),
|
192 | scripts: require('./tasks/scripts')(options),
|
193 | install: require('./tasks/install')(options),
|
194 | server: require('./tasks/server')(options),
|
195 | styles: require('./tasks/styles')(options),
|
196 | vendor: require('./tasks/vendor')(options),
|
197 | views: require('./tasks/views')(options)
|
198 | };
|
199 |
|
200 | var main = [],
|
201 | tasks = [];
|
202 |
|
203 | if (isBuild || options.env.clean === true) {
|
204 | tasks.push('clean');
|
205 | }
|
206 |
|
207 | if (is_file(path.join(options.paths.bower, 'bower.json'))) {
|
208 | Array.prototype.push.call(tasks, 'install', 'vendor');
|
209 | }
|
210 |
|
211 | ['fonts', 'images', 'sprites', 'styles', 'scripts', 'views']
|
212 | .forEach(function(task) {
|
213 | if (is_dir(options.paths[task].cwd)) {
|
214 | tasks.push(task);
|
215 | }
|
216 | });
|
217 |
|
218 | if (options.server === true && !isBuild) {
|
219 | tasks.push('server');
|
220 | }
|
221 |
|
222 | tasks
|
223 | .forEach(function(task) {
|
224 | var files = options.paths[task],
|
225 | callback = rainbow[task];
|
226 |
|
227 | if (to_array(sources.skip).indexOf(task) > -1) {
|
228 | return;
|
229 | }
|
230 |
|
231 | var prefix = options.prefix ? options.prefix + ':' : 'rainbow:';
|
232 |
|
233 | if (callback) {
|
234 | main.push(prefix + task);
|
235 |
|
236 | if (typeof callback === 'function') {
|
237 | gulp.task(prefix + task, callback);
|
238 | } else {
|
239 | gulp.task(prefix + task, function() {
|
240 | var chain = gulp.src(callback.src);
|
241 |
|
242 | chain = chain
|
243 | .pipe(filter(['**', '!**/_*', '!**/_*/**']
|
244 | .concat(to_array(sources.filter))
|
245 | .concat(to_array(files.filter))));
|
246 |
|
247 | if (typeof callback.check === 'function' && (options.env.check !== false)) {
|
248 | chain = hook(chain, callback.check);
|
249 | }
|
250 |
|
251 | chain = hook(chain, sources[task].before);
|
252 |
|
253 | if (typeof callback.pipe === 'function') {
|
254 | chain = hook(chain, callback.pipe);
|
255 | }
|
256 |
|
257 | return hook(chain, sources[task].after)
|
258 | .pipe(gulp.dest(callback.dest))
|
259 | .pipe(debug({ title: prefix + task }));
|
260 | });
|
261 | }
|
262 |
|
263 | if (files && files.on && !isBuild) {
|
264 | watch(files.on, function() {
|
265 | gulp.start(prefix + task);
|
266 | });
|
267 | }
|
268 | } else {
|
269 | util.log(util.colors.red('Unknown rainbow-task `' + task + '`'));
|
270 | exit(1);
|
271 | }
|
272 | });
|
273 |
|
274 | if (options.before) {
|
275 | Array.prototype.unshift.apply(main, to_array(options.before));
|
276 | }
|
277 |
|
278 | if (options.after) {
|
279 | Array.prototype.push.apply(main, to_array(options.after));
|
280 | }
|
281 |
|
282 | if (options.prefix) {
|
283 | return sequence.use(gulp).apply(null, main);
|
284 | }
|
285 |
|
286 | gulp.task('rainbow', sequence.use(gulp).apply(null, main));
|
287 | };
|
288 |
|
289 | module.exports.bowerFiles = function(from) {
|
290 | var bower_dir = path.resolve(from, 'bower_components');
|
291 |
|
292 | return mainBowerFiles({
|
293 | paths: {
|
294 | bowerDirectory: path.relative(process.cwd(), bower_dir),
|
295 | bowerJson: path.join(from, 'bower.json')
|
296 | }
|
297 | });
|
298 | };
|
299 |
|
300 | module.exports.server = function(root) {
|
301 | return require('./tasks/server')({
|
302 | paths: { dest: root },
|
303 | env: util.env
|
304 | });
|
305 | };
|
306 |
|
307 | module.exports.data = getData;
|