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 | forceAllPattern: false,
|
9 | ctimes: 'metalsmith-changed-ctimes.json'
|
10 | };
|
11 |
|
12 | module.exports = function (opts) {
|
13 | opts = Object.assign({}, DEFAULTS, opts);
|
14 | debug(`options: ${JSON.stringify(opts)}`);
|
15 |
|
16 | |
17 |
|
18 |
|
19 | const notForced = function (filename) {
|
20 | const pattern = opts.forcePattern;
|
21 | return pattern === false || !mm.any(filename, pattern);
|
22 | };
|
23 |
|
24 | return function changed (files, metalsmith, done) {
|
25 |
|
26 | files[opts.ctimes] = createCtimes(files);
|
27 | if (metalsmith.clean() || opts.force ||
|
28 | contains(files, opts.forceAllPattern)) {
|
29 | debug('building all files');
|
30 | } else {
|
31 | const prevCtimes = readCtimes(metalsmith.destination(), opts.ctimes);
|
32 | const filenames = Object.keys(files).filter(notForced);
|
33 | for (let f of filenames) {
|
34 | if (!hasCtime(files[f])) {
|
35 | debug(`${f} does not have ctime`);
|
36 | continue;
|
37 | }
|
38 |
|
39 | if (prevCtimes[f] && files[f].stats.ctime.getTime() === prevCtimes[f]) {
|
40 | debug(`skipping ${f}`);
|
41 | delete files[f];
|
42 | }
|
43 | }
|
44 | }
|
45 | done();
|
46 | };
|
47 | };
|
48 |
|
49 | function hasCtime (file) {
|
50 | return file.stats && file.stats.ctime;
|
51 | }
|
52 |
|
53 |
|
54 |
|
55 |
|
56 |
|
57 |
|
58 |
|
59 | function createCtimes (files) {
|
60 | let ctimes = {};
|
61 | let filenames = Object.keys(files);
|
62 | for (let f of filenames) {
|
63 | if (!hasCtime(files[f])) {
|
64 | continue;
|
65 | }
|
66 | let ctime = files[f].stats.ctime.getTime();
|
67 | debug(`ctime ${f}: ${ctime}`);
|
68 | ctimes[f] = ctime;
|
69 | }
|
70 | return { contents: JSON.stringify(ctimes, null, 2) };
|
71 | }
|
72 |
|
73 |
|
74 |
|
75 |
|
76 |
|
77 |
|
78 |
|
79 |
|
80 | function readCtimes (folder, filename) {
|
81 | try {
|
82 | let content = fs.readFileSync(path.join(folder, filename), 'utf8');
|
83 | return JSON.parse(content);
|
84 | } catch (e) {
|
85 | return {};
|
86 | }
|
87 | }
|
88 |
|
89 |
|
90 |
|
91 |
|
92 | function contains (files, pattern) {
|
93 | return mm(Object.keys(files), pattern).length !== 0;
|
94 | }
|