-
Notifications
You must be signed in to change notification settings - Fork 8
/
index.js
107 lines (85 loc) · 3 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
'use strict';
const walkSync = require('walk-sync');
const FSTree = require('fs-tree-diff');
const mkdirp = require('mkdirp');
const fs = require('fs');
const debug = require('debug')('tree-sync');
module.exports = class TreeSync {
constructor(input, output, options = {}) {
this._input = input;
this._output = output;
this._options = options;
this._walkSyncOpts = {};
this._hasSynced = false;
this._lastInput = FSTree.fromEntries([]);
// Pass through whitelisted options to walk-sync.
if (this._options.globs) {
this._walkSyncOpts.globs = options.globs;
}
if (this._options.ignore) {
this._walkSyncOpts.ignore = options.ignore;
}
debug('initializing TreeSync: %s -> %s', this._input, this._output);
}
sync() {
mkdirp.sync(this._output);
mkdirp.sync(this._input);
debug('syncing %s -> %s', this._input, this._output);
const input = FSTree.fromEntries(walkSync.entries(this._input, this._walkSyncOpts));
const output = FSTree.fromEntries(walkSync.entries(this._output, this._walkSyncOpts));
debug('walked %s %dms and %s %dms', this._input, input.size, this._output, output.size);
const isFirstSync = !this._hasSynced;
let operations = output.calculatePatch(input).filter(operation => {
if (operation[0] === 'change') {
return isFirstSync;
} else {
return true;
}
});
const inputOperations = this._lastInput.calculatePatch(input).filter(operation => {
return operation[0] === 'change';
});
this._lastInput = input;
operations = operations.concat(inputOperations);
debug('calc operations %d', operations.length);
for (const patch of operations) {
const operation = patch[0];
const pathname = patch[1];
const entry = patch[2];
const inputFullPath = this._input + '/' + pathname;
const outputFullPath = this._output + '/' + pathname;
switch(operation) {
case 'create' :
case 'change' :
fs.writeFileSync(outputFullPath, fs.readFileSync(inputFullPath), { mode: entry.mode });
fs.utimesSync(outputFullPath, new Date(), entry.mtime / 1e3);
break;
case 'mkdir' :
try {
fs.mkdirSync(outputFullPath);
} catch(e) {
if (e && e.code === 'EEXIST') { /* do nothing */ }
else { throw e; }
}
break;
case 'unlink':
try {
fs.unlinkSync(outputFullPath);
} catch(e) {
if (e && e.code === 'ENOENT') { /* do nothing */ }
else { throw e; }
}
break;
case 'rmdir':
fs.rmdirSync(outputFullPath);
break;
default:
throw TypeError('Unknown operation:' + operation + ' on path: ' + pathname);
}
}
this._hasSynced = true;
debug('applied patches: %d', operations.length);
// Return only type and name; don't want downstream relying on entries.
return operations.map(op => op.slice(0,2));
}
};