@frakjs/frak 0.4.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/frak.js +4 -1
- package/package.json +1 -1
- package/src/crypto.js +4 -0
- package/src/diff.js +45 -9
- package/src/humanize.js +2 -0
- package/src/rsync.js +1 -10
package/bin/frak.js
CHANGED
|
@@ -99,6 +99,8 @@ async function main(args) {
|
|
|
99
99
|
});
|
|
100
100
|
} catch (e) {
|
|
101
101
|
debug(e);
|
|
102
|
+
|
|
103
|
+
process.exit(e.status || 1);
|
|
102
104
|
}
|
|
103
105
|
} else if (command === 'diff') {
|
|
104
106
|
// Show the differences between local files and remote server
|
|
@@ -200,7 +202,7 @@ async function main(args) {
|
|
|
200
202
|
additions: `grep -e '^+' "$NAME"/*.patch | grep -v '^+++' | wc -l`,
|
|
201
203
|
deletions: `grep -e '^-' "$NAME"/*.patch | grep -v '^---' | wc -l`,
|
|
202
204
|
};
|
|
203
|
-
const ls = `stat
|
|
205
|
+
const ls = `stat -c '%Y %n' .backups/* | sort -r`;
|
|
204
206
|
|
|
205
207
|
const list = ssh.exec(
|
|
206
208
|
`${ls} | xargs -I {} sh -c 'TIMESTAMP=$(echo {} | cut -d" " -f1); NAME=$(echo {} | cut -d" " -f2-); echo $TIMESTAMP${delimeter}$NAME${delimeter}$(${grep.additions})${delimeter}$(${grep.deletions})'`,
|
|
@@ -232,6 +234,7 @@ async function main(args) {
|
|
|
232
234
|
.split(/\n/)
|
|
233
235
|
.forEach((backup) => {
|
|
234
236
|
const [timestamp, name, additions, deletions] = backup.split(delimeter);
|
|
237
|
+
debug(backup);
|
|
235
238
|
table.row([
|
|
236
239
|
name.replace(/^.backups\//, ''),
|
|
237
240
|
date.relative(timestamp * 1000),
|
package/package.json
CHANGED
package/src/crypto.js
CHANGED
package/src/diff.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { spawn } from 'node:child_process';
|
|
2
|
-
import { statSync } from 'node:fs';
|
|
2
|
+
import { existsSync, statSync, unlinkSync, writeFileSync } from 'node:fs';
|
|
3
3
|
import * as ansi from './ansi.js';
|
|
4
4
|
import * as cli from './cli.js';
|
|
5
|
+
import * as crypto from './crypto.js';
|
|
5
6
|
import config from './config.js';
|
|
6
7
|
import debug from './debug.js';
|
|
7
8
|
|
|
@@ -16,6 +17,8 @@ export default async function diff(dryRunOutput, options) {
|
|
|
16
17
|
const changes = dryRunOutput
|
|
17
18
|
.split(/\r?\n/)
|
|
18
19
|
.filter(Boolean)
|
|
20
|
+
.filter((line) => !/^created directory .*/.test(line))
|
|
21
|
+
.filter((line) => !/^cannot delete non-empty directory:.*/.test(line))
|
|
19
22
|
.map((line) => {
|
|
20
23
|
// Split line into action and file, preserving whitespace for filenames
|
|
21
24
|
const [action, ...parts] = line.split(/\s+/);
|
|
@@ -52,7 +55,7 @@ export default async function diff(dryRunOutput, options) {
|
|
|
52
55
|
return Promise.reject('Process canceled by user');
|
|
53
56
|
}
|
|
54
57
|
|
|
55
|
-
const files = changes.map(([, file]) => file);
|
|
58
|
+
const files = changes.map(([, file]) => file).filter((file) => existsSync(file));
|
|
56
59
|
|
|
57
60
|
const diffs = changes
|
|
58
61
|
.sort((a, b) => a[1].localeCompare(b[1]))
|
|
@@ -109,18 +112,47 @@ export default async function diff(dryRunOutput, options) {
|
|
|
109
112
|
if (diffs.length > 0) {
|
|
110
113
|
debug({ diffs, files });
|
|
111
114
|
|
|
115
|
+
const diffsScriptFilename = `.frak-diffs-${crypto.sha256(Date.now())}.sh`;
|
|
116
|
+
|
|
117
|
+
writeFileSync(`/tmp/${diffsScriptFilename}`, diffs.join(';'));
|
|
118
|
+
|
|
112
119
|
// Tarball the local files up to the server
|
|
113
|
-
const tar = spawn('tar', ['cz', ...files]);
|
|
120
|
+
const tar = spawn('tar', ['cz', ...files, `/tmp/${diffsScriptFilename}`]);
|
|
121
|
+
|
|
122
|
+
// Handle tar errors
|
|
123
|
+
tar.on('error', (error) => {
|
|
124
|
+
throw error;
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
// Cleanup the diffs script
|
|
128
|
+
tar.on('exit', () => {
|
|
129
|
+
unlinkSync(`/tmp/${diffsScriptFilename}`);
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
// Run ssh, it takes the tarball through stdin, and expands it inline to generate diffs.
|
|
133
|
+
// Don't forget, each command after the -- needs to end in a semicolon (;).
|
|
114
134
|
const ssh = spawn('ssh', [
|
|
115
135
|
config.server,
|
|
116
136
|
'--',
|
|
117
|
-
|
|
137
|
+
// Save the incoming tarball to /tmp
|
|
138
|
+
'export tarball=$(mktemp /tmp/frak-diff-tarball.XXXXXX);',
|
|
118
139
|
'cat > $tarball;',
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
';',
|
|
122
|
-
|
|
140
|
+
// Save the diffs script to the /tmp folder
|
|
141
|
+
`tar xzOf $tarball "tmp/${diffsScriptFilename}" > /tmp/${diffsScriptFilename};`,
|
|
142
|
+
process.env.DEBUG ? 'tar tf $tarball;' : '',
|
|
143
|
+
// Fixes missing root directory by jumping to an empty /tmp folder
|
|
144
|
+
`if [ -d "${config.root}" ] ; then cd "${config.root}"; else fakeroot=$(mktemp -d /tmp/frak-fake-root.XXXXXX); cd $fakeroot; fi ;`,
|
|
145
|
+
// Run the diffs script
|
|
146
|
+
`sh /tmp/${diffsScriptFilename};`,
|
|
147
|
+
// Clean up diffs script
|
|
148
|
+
`rm /tmp/${diffsScriptFilename};`,
|
|
149
|
+
// Clean up the tarball
|
|
150
|
+
'rm $tarball;',
|
|
151
|
+
// Clean up the fake root fix
|
|
152
|
+
'if [ -d "$fakeroot" ] ; then rmdir "$fakeroot" ; fi;',
|
|
123
153
|
]);
|
|
154
|
+
|
|
155
|
+
// Pipe the tar output to SSH
|
|
124
156
|
tar.stdout.pipe(ssh.stdin);
|
|
125
157
|
|
|
126
158
|
let less;
|
|
@@ -182,7 +214,7 @@ export default async function diff(dryRunOutput, options) {
|
|
|
182
214
|
});
|
|
183
215
|
} else {
|
|
184
216
|
/* node:coverage disable */
|
|
185
|
-
return await new Promise((resolve) => {
|
|
217
|
+
return await new Promise((resolve, reject) => {
|
|
186
218
|
let diff = '';
|
|
187
219
|
|
|
188
220
|
ssh.stdout.on('data', (data) => (diff += data));
|
|
@@ -192,6 +224,10 @@ export default async function diff(dryRunOutput, options) {
|
|
|
192
224
|
ssh.on('exit', () => {
|
|
193
225
|
resolve(diff);
|
|
194
226
|
});
|
|
227
|
+
|
|
228
|
+
ssh.on('error', (error) => {
|
|
229
|
+
reject(error);
|
|
230
|
+
});
|
|
195
231
|
});
|
|
196
232
|
/* node:coverage enable */
|
|
197
233
|
}
|
package/src/humanize.js
CHANGED
|
@@ -2,6 +2,8 @@ import * as ansi from './ansi.js';
|
|
|
2
2
|
|
|
3
3
|
export default function humanize(changes) {
|
|
4
4
|
return changes
|
|
5
|
+
.replace(/(^|\n)created directory .*\n/g, '$1')
|
|
6
|
+
.replace(/(^|\n)cannot delete non-empty directory: .*\n/g, '$1')
|
|
5
7
|
.replace(/cL\+\+\+\+\+\+\+\+\+/g, ansi.blue('New Link '))
|
|
6
8
|
.replace(/<f\+\+\+\+\+\+\+\+\+/g, ansi.green('New File '))
|
|
7
9
|
.replace(/>f\+\+\+\+\+\+\+\+\+/g, ansi.green('New File '))
|
package/src/rsync.js
CHANGED
|
@@ -14,16 +14,7 @@ export function filters() {
|
|
|
14
14
|
const { options } = parse(process.argv.slice(2));
|
|
15
15
|
const filters = [];
|
|
16
16
|
const includes = [];
|
|
17
|
-
const excludes = [
|
|
18
|
-
'.frak*',
|
|
19
|
-
'.git*',
|
|
20
|
-
'.svn*',
|
|
21
|
-
'.tags*',
|
|
22
|
-
'frak.config.js',
|
|
23
|
-
'Capfile',
|
|
24
|
-
'Gemfile*',
|
|
25
|
-
'Vagrantfile*',
|
|
26
|
-
];
|
|
17
|
+
const excludes = ['/.frak', '/.frakignore', '/.git/', '/.svn/', '/frak.config.js'];
|
|
27
18
|
|
|
28
19
|
// merge excludes via commandline
|
|
29
20
|
if (options.ignore) {
|