1 | const fs = require('fs');
|
2 | const path = require('path');
|
3 | const debug = require('debug')('metalsmith-changed');
|
4 | const mm = require('micromatch');
|
5 | const DEFAULTS = {
|
6 | force: false,
|
7 | forcePattern: false,
|
8 | ctimes: 'metalsmith-changed-ctimes.json'
|
9 | };
|
10 |
|
11 | module.exports = function (opts) {
|
12 | opts = Object.assign({}, DEFAULTS, opts);
|
13 | debug(`options: ${JSON.stringify(opts)}`);
|
14 |
|
15 | |
16 |
|
17 |
|
18 | const notForced = function (filename) {
|
19 | const pattern = opts.forcePattern;
|
20 | return pattern === false || !mm.isMatch(filename, pattern);
|
21 | };
|
22 |
|
23 | |
24 |
|
25 |
|
26 |
|
27 |
|
28 |
|
29 | function createCtimes (files, filename) {
|
30 |
|
31 | let ctimes = {};
|
32 | let filenames = Object.keys(files);
|
33 | for (let f of filenames) {
|
34 | if (!hasCtime(files[f])) {
|
35 | continue;
|
36 | }
|
37 | let ctime = files[f].stats.ctime.getTime();
|
38 | debug(`ctime ${f}: ${ctime}`);
|
39 | ctimes[f] = ctime;
|
40 | }
|
41 | fs.writeFileSync(filename, JSON.stringify(ctimes, null, 2));
|
42 | }
|
43 |
|
44 | return function changed (files, metalsmith, done) {
|
45 |
|
46 | createCtimes(files, path.join(metalsmith.source(), opts.ctimes));
|
47 | if (metalsmith.clean() || opts.force || !files[opts.ctimes]) {
|
48 | debug('building all files');
|
49 | } else {
|
50 | const prevCtimes = JSON.parse(files[opts.ctimes].contents.toString());
|
51 | const filenames = Object.keys(files).filter(notForced);
|
52 | for (let f of filenames) {
|
53 | if (!hasCtime(files[f])) {
|
54 | debug(`${f} does not have ctime`);
|
55 | continue;
|
56 | }
|
57 |
|
58 | if (prevCtimes[f] && files[f].stats.ctime.getTime() === prevCtimes[f]) {
|
59 | debug(`skipping ${f}`);
|
60 | delete files[f];
|
61 | }
|
62 | }
|
63 | }
|
64 |
|
65 | delete files[opts.ctimes];
|
66 | done();
|
67 | };
|
68 | };
|
69 |
|
70 | function hasCtime (file) {
|
71 | return file.stats && file.stats.ctime;
|
72 | }
|
73 |
|