@frakjs/frak 0.2.0 → 0.3.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/.prettierrc ADDED
@@ -0,0 +1,8 @@
1
+ {
2
+ "tabSize": 4,
3
+ "singleQuote": true,
4
+ "semi": true,
5
+ "trailingComma": "es5",
6
+ "printWidth": 100,
7
+ "bracketSpacing": true
8
+ }
package/bin/frak.js CHANGED
@@ -20,15 +20,11 @@ import * as date from '../src/date.js';
20
20
  * @param {String} env
21
21
  */
22
22
  async function tryLoadConfig(env) {
23
- try {
24
- await loadConfig(env);
25
- } catch (e) {
23
+ return await loadConfig(env).catch((e) => {
26
24
  console.error(ansi.red(e.message));
27
25
 
28
26
  process.exit(1);
29
- }
30
-
31
- return;
27
+ });
32
28
  }
33
29
 
34
30
  /**
@@ -55,20 +51,22 @@ async function main(args) {
55
51
 
56
52
  debug('parsed:', { command, options });
57
53
 
58
- // Initialize Frak in the current directory
59
54
  if (command === 'init') {
55
+ // Initialize Frak in the current directory
60
56
  const configPath = path.join(process.cwd(), 'frak.config.js');
61
57
 
62
58
  if (!existsSync(configPath)) {
63
- writeFileSync(configPath, `export default ${JSON.stringify({ server: 'example.com', root: '/var/www/html' }, null, 4)}`);
59
+ writeFileSync(
60
+ configPath,
61
+ `export default ${JSON.stringify({ server: 'example.com', root: '/var/www/html' }, null, 4)}`
62
+ );
64
63
  console.info(ansi.green('Configuration file created: frak.config.js'));
65
64
  } else {
66
65
  console.error(ansi.red('Frak is already initialized in this directory.'));
67
66
  }
68
-
69
- // Start a console session, or run the provided command on
70
- // the remote server.
71
67
  } else if (command === 'console') {
68
+ // Start a console session, or run the provided command on
69
+ // the remote server.
72
70
  await tryLoadConfig(options.env);
73
71
 
74
72
  if (!config.server) {
@@ -77,14 +75,16 @@ async function main(args) {
77
75
  }
78
76
 
79
77
  try {
80
- const cmd = options.command ?? '\\$SHELL -l -i';
78
+ const cmd = options.command || '\\$SHELL -l -i';
81
79
 
82
- execSync(`ssh -t ${config.server} -- cd ${config.root} \\&\\& ${cmd}`, { stdio: 'inherit' });
80
+ execSync(`ssh -t ${config.server} -- cd ${config.root} \\&\\& ${cmd}`, {
81
+ stdio: 'inherit',
82
+ });
83
83
  } catch (e) {
84
- debug(e)
84
+ debug(e);
85
85
  }
86
- // Show the differences between local files and remote server
87
86
  } else if (command === 'diff') {
87
+ // Show the differences between local files and remote server
88
88
  await tryLoadConfig(options.env);
89
89
 
90
90
  try {
@@ -98,9 +98,8 @@ async function main(args) {
98
98
 
99
99
  console.error(e.message);
100
100
  }
101
-
102
- // Push or pull changes to remote server
103
101
  } else if (command === 'push' || command === 'pull') {
102
+ // Push or pull changes to remote server
104
103
  await tryLoadConfig(options.env);
105
104
 
106
105
  // Execute dry-run
@@ -115,7 +114,9 @@ async function main(args) {
115
114
  console.log('');
116
115
  }
117
116
 
118
- const proceed = await cli.agree(ansi.yellow('The above actions will be taken. Continue? (This cannot be undone): '));
117
+ const proceed = await cli.agree(
118
+ ansi.yellow('The above actions will be taken. Continue? (This cannot be undone): ')
119
+ );
119
120
 
120
121
  if (!proceed) {
121
122
  process.exit(1);
@@ -125,14 +126,13 @@ async function main(args) {
125
126
  let patch = '';
126
127
 
127
128
  if (command === 'push') {
128
- try {
129
- patch = await diff(output, { interactive: false });
130
- /* node:coverage disable */
131
- } catch (e) {
132
- console.error(e);
133
-
134
- process.exit(1);
135
- }
129
+ patch = await diff(output, { interactive: false })
130
+ /* node:coverage disable */
131
+ .catch((e) => {
132
+ console.error(e);
133
+
134
+ process.exit(1);
135
+ });
136
136
  /* node:coverage enable */
137
137
  }
138
138
 
@@ -145,7 +145,11 @@ async function main(args) {
145
145
  // Place patch file in backup dir
146
146
  if (command === 'push') {
147
147
  const hash = sha256(patch).slice(0, 7);
148
- const copy = spawn('ssh', [config.server, '--', `cat > '${config.root || '.'}/${backupPath}/${hash}.patch'`]);
148
+ const copy = spawn('ssh', [
149
+ config.server,
150
+ '--',
151
+ `cat > '${config.root || '.'}/${backupPath}/${hash}.patch'`,
152
+ ]);
149
153
 
150
154
  copy.stdout.on('data', (data) => debug('' + data));
151
155
  copy.stderr.on('data', (data) => debug('' + data));
@@ -158,13 +162,12 @@ async function main(args) {
158
162
 
159
163
  debug({ command: config.after });
160
164
 
161
- try {
162
- await ssh.exec(config.after, { server: config.server, root: config.root });
163
- /* node:coverage disable */
164
- } catch (e) {
165
- debug(e);
166
- }
167
- /* node:coverage enable */
165
+ await ssh
166
+ .exec(config.after, {
167
+ server: config.server,
168
+ root: config.root,
169
+ })
170
+ .catch(debug);
168
171
  }
169
172
 
170
173
  // TODO Webhook
@@ -179,13 +182,16 @@ async function main(args) {
179
182
  const grep = {
180
183
  additions: `grep -e '^+' "$NAME"/*.patch | grep -v '^+++' | wc -l`,
181
184
  deletions: `grep -e '^-' "$NAME"/*.patch | grep -v '^---' | wc -l`,
182
- }
185
+ };
183
186
  const ls = `stat --format='%Y %n' .backups/* | sort -r`;
184
187
 
185
- const list = ssh.exec(`${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})'`, { quiet: true, server: config.server, root: config.root });
188
+ const list = ssh.exec(
189
+ `${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})'`,
190
+ { quiet: true, server: config.server, root: config.root }
191
+ );
186
192
  let backups = '';
187
193
 
188
- list.stdout.on('data', data => backups += data);
194
+ list.stdout.on('data', (data) => (backups += data));
189
195
 
190
196
  await list;
191
197
 
@@ -201,17 +207,22 @@ async function main(args) {
201
207
  {
202
208
  header: 'Changes',
203
209
  width: 30,
204
- }
210
+ },
205
211
  ]);
206
212
 
207
- backups.trim().split(/\n/).forEach(backup => {
208
- const [ timestamp, name, additions, deletions ] = backup.split(delimeter);
209
- table.row([
210
- name.replace(/^.backups\//, ''),
211
- date.relative(timestamp * 1000),
212
- ansi.green(`${additions} addition${additions == 1 ? '' : 's'}`) + ', ' + ansi.red(`${deletions} deletion${deletions == 1 ? '' : 's'}`),
213
- ]);
214
- });
213
+ backups
214
+ .trim()
215
+ .split(/\n/)
216
+ .forEach((backup) => {
217
+ const [timestamp, name, additions, deletions] = backup.split(delimeter);
218
+ table.row([
219
+ name.replace(/^.backups\//, ''),
220
+ date.relative(timestamp * 1000),
221
+ ansi.green(`${additions} addition${additions == 1 ? '' : 's'}`) +
222
+ ', ' +
223
+ ansi.red(`${deletions} deletion${deletions == 1 ? '' : 's'}`),
224
+ ]);
225
+ });
215
226
 
216
227
  table.print();
217
228
  } else {
package/package.json CHANGED
@@ -1,15 +1,18 @@
1
1
  {
2
2
  "name": "@frakjs/frak",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "A commandline deployment tool for syncing files to remote servers.",
5
5
  "main": "index.js",
6
+ "engines": {
7
+ "node": ">=12"
8
+ },
6
9
  "bin": {
7
10
  "frak": "bin/frak.js"
8
11
  },
9
12
  "type": "module",
10
13
  "scripts": {
11
14
  "eslint": "eslint",
12
- "test": "node --test --experimental-test-coverage"
15
+ "test": "node --experimental-test-coverage tests/index.test.js"
13
16
  },
14
17
  "repository": {
15
18
  "type": "git",
@@ -32,6 +35,6 @@
32
35
  "globals": "^16.3.0"
33
36
  },
34
37
  "dependencies": {
35
- "yaml": "^2.8.1"
38
+ "yaml": "^1.10.0"
36
39
  }
37
40
  }
package/src/cli.js CHANGED
@@ -30,13 +30,13 @@ export function parse(args) {
30
30
  }
31
31
 
32
32
  export async function agree(string, { stdin = null, stdout = null } = {}) {
33
- stdout = stdout ?? process.stdout;
34
- stdin = stdin ?? process.stdin;
33
+ stdout = stdout || process.stdout;
34
+ stdin = stdin || process.stdin;
35
35
 
36
36
  stdout.write(string);
37
37
 
38
38
  const answer = await new Promise((resolve) => {
39
- stdin.on('data', data => resolve(data));
39
+ stdin.on('data', (data) => resolve(data));
40
40
  });
41
41
 
42
42
  return ['y', 'yes'].includes(`${answer}`.trim().toLowerCase());
@@ -56,8 +56,8 @@ export class Table {
56
56
  const { border, header } = this.columns.reduce(({ header, border }, column, i) => {
57
57
  const width = ansi.strip(column.header).length;
58
58
  const padding = Math.max(0, column.width - width - 2);
59
- const paddingString = (new Array(padding + 1)).join(' ');
60
- const borderString = (new Array(column.width + 1).join('-'));
59
+ const paddingString = new Array(padding + 1).join(' ');
60
+ const borderString = new Array(column.width + 1).join('-');
61
61
 
62
62
  return {
63
63
  border: `${border || ''}+${borderString}${i === this.columns.length - 1 ? '+' : ''}`,
@@ -69,17 +69,17 @@ export class Table {
69
69
  console.log(header);
70
70
  console.log(ansi.gray(border));
71
71
 
72
- this.rows.forEach(r => {
72
+ this.rows.forEach((r) => {
73
73
  const rowString = r.reduce((row, cell, i) => {
74
- const width = ansi.strip(cell).length
74
+ const width = ansi.strip(cell).length;
75
75
  const padding = Math.max(0, this.columns[i].width - width - 2);
76
- const paddingString = (new Array(padding + 1)).join(' ');
76
+ const paddingString = new Array(padding + 1).join(' ');
77
77
 
78
- return `${row || ''}${ansi.gray('|')} ${cell}${paddingString} ${i === r.length - 1 ? ansi.gray('|') : ''}`
78
+ return `${row || ''}${ansi.gray('|')} ${cell}${paddingString} ${i === r.length - 1 ? ansi.gray('|') : ''}`;
79
79
  }, '');
80
80
 
81
81
  console.log(rowString);
82
82
  console.log(ansi.gray(border));
83
- })
83
+ });
84
84
  }
85
85
  }
package/src/config.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import fs from 'node:fs';
2
2
  import path from 'node:path';
3
- import { parse } from 'yaml';
3
+ import * as yaml from 'yaml';
4
4
 
5
5
  // Cached config object. The config is stored in here so it can
6
6
  // be loaded once and imported across all modules.
@@ -43,18 +43,14 @@ export async function load(env = null) {
43
43
  if (path.basename(configPath) === 'frak.config.js') {
44
44
  Object.assign(config, (await import(configPath)).default);
45
45
  } else if (path.basename(configPath) === '.frak') {
46
- Object.assign(config, parse(fs.readFileSync(configPath).toString('utf-8')));
46
+ Object.assign(config, yaml.parse(fs.readFileSync(configPath).toString('utf-8')));
47
47
  }
48
48
 
49
49
  if (env in config) {
50
- Object.assign(config, {...config[env]});
50
+ Object.assign(config, { ...config[env] });
51
51
 
52
52
  delete config[env];
53
-
54
- return config;
55
- }
56
-
57
- if (env) {
53
+ } else if (env) {
58
54
  throw new Error(`Missing configuration for environment "${env}"!`);
59
55
  }
60
56
 
@@ -84,4 +80,3 @@ export function reset() {
84
80
  }
85
81
 
86
82
  export default config;
87
-
package/src/date.js CHANGED
@@ -29,28 +29,28 @@ export function relative(date) {
29
29
  value = 'just';
30
30
  unit = 'now';
31
31
  agoOrFromNow = '';
32
- // Less than a minute
33
32
  } else if (seconds < 60) {
33
+ // Less than a minute
34
34
  value = Math.floor(seconds);
35
35
  unit = plural('second', value);
36
- // Less than an hour
37
36
  } else if (seconds < 60 * 60) {
37
+ // Less than an hour
38
38
  value = Math.floor(seconds / 60);
39
39
  unit = plural('minute', value);
40
- // Less than a day
41
40
  } else if (seconds < 60 * 60 * 24) {
41
+ // Less than a day
42
42
  value = Math.floor(seconds / 60 / 60);
43
43
  unit = plural('hour', value);
44
- // Less than a week
45
44
  } else if (seconds < 60 * 60 * 24 * 7) {
45
+ // Less than a week
46
46
  value = Math.floor(seconds / 60 / 60 / 24);
47
47
  unit = plural('day', value);
48
- // Less than a month
49
48
  } else if (seconds < 60 * 60 * 24 * 30) {
49
+ // Less than a month
50
50
  value = Math.floor(seconds / 60 / 60 / 24 / 7);
51
51
  unit = plural('week', value);
52
- // Less than a year
53
52
  } else if (seconds < 60 * 60 * 24 * 365) {
53
+ // Less than a year
54
54
  value = Math.floor(seconds / 60 / 60 / 24 / 30);
55
55
  unit = plural('month', value);
56
56
  } else {
package/src/debug.js CHANGED
@@ -5,6 +5,6 @@ import * as ansi from '../src/ansi.js';
5
5
  */
6
6
  export default function debug() {
7
7
  if (process.env.DEBUG) {
8
- console.log.apply(console, [ ansi.bold(ansi.cyan('DEBUG:')), ...arguments ]);
8
+ console.log.apply(console, [ansi.bold(ansi.cyan('DEBUG:')), ...arguments]);
9
9
  }
10
10
  }
package/src/diff.js CHANGED
@@ -16,7 +16,7 @@ export default async function diff(dryRunOutput, options) {
16
16
  const changes = dryRunOutput
17
17
  .split(/\r?\n/)
18
18
  .filter(Boolean)
19
- .map(line => {
19
+ .map((line) => {
20
20
  // Split line into action and file, preserving whitespace for filenames
21
21
  const [action, ...parts] = line.split(/\s+/);
22
22
 
@@ -26,7 +26,7 @@ export default async function diff(dryRunOutput, options) {
26
26
  if (action.match(/^cL.+/)) {
27
27
  const index = parts.indexOf('->');
28
28
 
29
- debug({ parts })
29
+ debug({ parts });
30
30
 
31
31
  file = parts.slice(0, index).join(' ');
32
32
  target = parts.slice(index + 1).join(' ');
@@ -38,12 +38,14 @@ export default async function diff(dryRunOutput, options) {
38
38
  })
39
39
  .filter(([, file]) => file.slice(-1) !== '/');
40
40
 
41
- debug({ changes })
41
+ debug({ changes });
42
42
 
43
43
  let proceed = true;
44
44
 
45
45
  if (changes.length >= 50 && options.interactive) {
46
- proceed = await cli.agree(ansi.yellow(`${changes.length} file(s) will be compared. Continue? `))
46
+ proceed = await cli.agree(
47
+ ansi.yellow(`${changes.length} file(s) will be compared. Continue? `)
48
+ );
47
49
  }
48
50
 
49
51
  if (!proceed) {
@@ -52,53 +54,57 @@ export default async function diff(dryRunOutput, options) {
52
54
 
53
55
  const files = changes.map(([, file]) => file);
54
56
 
55
- const diffs = changes.sort((a, b) => a[1].localeCompare(b[1])).map(change => {
56
- const [action, file] = change;
57
+ const diffs = changes
58
+ .sort((a, b) => a[1].localeCompare(b[1]))
59
+ .map((change) => {
60
+ const [action, file] = change;
57
61
 
58
- // Escape double quotes in file
59
- const fileEscaped = file.replace(/"/g, '\\"');
62
+ // Escape double quotes in file
63
+ const fileEscaped = file.replace(/"/g, '\\"');
60
64
 
61
- const header = [
62
- file.match(/"/) ? `diff --git "a/${fileEscaped}" "b/${fileEscaped}"` : `diff --git a/${file} b/${file}`,
63
- ];
65
+ const header = [
66
+ file.match(/"/)
67
+ ? `diff --git "a/${fileEscaped}" "b/${fileEscaped}"`
68
+ : `diff --git a/${file} b/${file}`,
69
+ ];
64
70
 
65
- let diff = '';
71
+ let diff = '';
66
72
 
67
- if (action === '*deleting') {
68
- header.push('deleted file mode 100644');
69
- header.push('index 0000000..0000000');
73
+ if (action === '*deleting') {
74
+ header.push('deleted file mode 100644');
75
+ header.push('index 0000000..0000000');
70
76
 
71
- diff = `diff -Naurp --label="a/${fileEscaped}" --label=/dev/null "${fileEscaped}" /dev/null`;
72
- } else if (action.match(/^<f\++/)) {
73
- const { mode } = statSync(file);
77
+ diff = `diff -Naurp --label="a/${fileEscaped}" --label=/dev/null "${fileEscaped}" /dev/null`;
78
+ } else if (action.match(/^<f\++/)) {
79
+ const { mode } = statSync(file);
74
80
 
75
- header.push(`new file mode ${mode.toString(8)}`);
76
- header.push('index 0000000..0000000');
81
+ header.push(`new file mode ${mode.toString(8)}`);
82
+ header.push('index 0000000..0000000');
77
83
 
78
- diff = `diff -Naurp --label=/dev/null --label="b/${fileEscaped}" /dev/null <(tar xzOf $tarball "${fileEscaped}" || cat /dev/null)`;
79
- } else if (action.match(/^cL\++/)) {
80
- const target = change[2];
84
+ diff = `diff -Naurp --label=/dev/null --label="b/${fileEscaped}" /dev/null <(tar xzOf $tarball "${fileEscaped}" || cat /dev/null)`;
85
+ } else if (action.match(/^cL\++/)) {
86
+ const target = change[2];
81
87
 
82
- header.push('new file mode 120000');
83
- header.push('index 0000000..0000000');
88
+ header.push('new file mode 120000');
89
+ header.push('index 0000000..0000000');
84
90
 
85
- diff = `diff -Naurp --label=/dev/null --label="b/${fileEscaped}" /dev/null <(printf %s "${target}")`;
86
- } else if (action.match(/^cL.+/)) {
87
- const target = change[2];
91
+ diff = `diff -Naurp --label=/dev/null --label="b/${fileEscaped}" /dev/null <(printf %s "${target}")`;
92
+ } else if (action.match(/^cL.+/)) {
93
+ const target = change[2];
88
94
 
89
- header.push('index 0000000..0000000');
95
+ header.push('index 0000000..0000000');
90
96
 
91
- diff = `diff -Naurp --label="a/${fileEscaped}" --label="b/${fileEscaped}" <(printf %s "$(readlink "${fileEscaped}")") <(printf %s "${target}")`;
92
- } else {
93
- const { mode } = statSync(file);
97
+ diff = `diff -Naurp --label="a/${fileEscaped}" --label="b/${fileEscaped}" <(printf %s "$(readlink "${fileEscaped}")") <(printf %s "${target}")`;
98
+ } else {
99
+ const { mode } = statSync(file);
94
100
 
95
- header.push(`index 0000000..0000000 ${mode.toString(8)}`);
101
+ header.push(`index 0000000..0000000 ${mode.toString(8)}`);
96
102
 
97
- diff = `diff -Naurp --label="a/${fileEscaped}" --label="b/${fileEscaped}" "${fileEscaped}" <(tar xzOf $tarball "${fileEscaped}" || cat /dev/null)`;
98
- }
103
+ diff = `diff -Naurp --label="a/${fileEscaped}" --label="b/${fileEscaped}" "${fileEscaped}" <(tar xzOf $tarball "${fileEscaped}" || cat /dev/null)`;
104
+ }
99
105
 
100
- return `printf "%s\\n" '${header.join('\n')}'; ${diff}`;
101
- });
106
+ return `printf "%s\\n" '${header.join('\n')}'; ${diff}`;
107
+ });
102
108
 
103
109
  if (diffs.length > 0) {
104
110
  debug({ diffs, files });
@@ -111,9 +117,10 @@ export default async function diff(dryRunOutput, options) {
111
117
  'tarball=$(mktemp /tmp/frak-diff-tarball.XXXXXX);',
112
118
  'cat > $tarball;',
113
119
  `cd ${config.root};`,
114
- diffs.join('; '), ';',
120
+ diffs.join('; '),
121
+ ';',
115
122
  'rm $tarball',
116
- ])
123
+ ]);
117
124
  tar.stdout.pipe(ssh.stdin);
118
125
 
119
126
  let less;
@@ -125,22 +132,35 @@ export default async function diff(dryRunOutput, options) {
125
132
  if (options.interactive && options.colorize) {
126
133
  const colorize = spawn('sed', [
127
134
  // headers
128
- '-e', `s/^\\(diff --git .*\\)/${ansi.bold('\\1')}/`,
129
- '-e', `s/^\\(index .*\\)/${ansi.bold('\\1')}/`,
130
- '-e', `s/^\\(new file mode .*\\)/${ansi.bold('\\1')}/`,
131
- '-e', `s/^\\(deleted file mode .*\\)/${ansi.bold('\\1')}/`,
132
- '-e', `s/^\\(--- .*\\)/${ansi.bold('\\1')}/`,
133
- '-e', `s/^\\(+++ .*\\)/${ansi.bold('\\1')}/`,
135
+ '-e',
136
+ `s/^\\(diff --git .*\\)/${ansi.bold('\\1')}/`,
137
+ '-e',
138
+ `s/^\\(index .*\\)/${ansi.bold('\\1')}/`,
139
+ '-e',
140
+ `s/^\\(new file mode .*\\)/${ansi.bold('\\1')}/`,
141
+ '-e',
142
+ `s/^\\(deleted file mode .*\\)/${ansi.bold('\\1')}/`,
143
+ '-e',
144
+ `s/^\\(--- .*\\)/${ansi.bold('\\1')}/`,
145
+ '-e',
146
+ `s/^\\(+++ .*\\)/${ansi.bold('\\1')}/`,
134
147
  // additions
135
- '-e', `s/^\\(+[^+].*\\)/${ansi.green('\\1')}/`,
136
- '-e', `s/^\\(+\\)$/${ansi.green('\\1')}/`,
148
+ '-e',
149
+ `s/^\\(+[^+].*\\)/${ansi.green('\\1')}/`,
150
+ '-e',
151
+ `s/^\\(+\\)$/${ansi.green('\\1')}/`,
137
152
  // deletions
138
- '-e', `s/^\\(-[^-].*\\)/${ansi.red('\\1')}/`,
139
- '-e', `s/^\\(-\\)$/${ansi.red('\\1')}/`,
153
+ '-e',
154
+ `s/^\\(-[^-].*\\)/${ansi.red('\\1')}/`,
155
+ '-e',
156
+ `s/^\\(-\\)$/${ansi.red('\\1')}/`,
140
157
  // markers
141
- '-e', `s/^\\(@@ -[0-9][0-9]*,[0-9][0-9]* +[0-9][0-9]*,[0-9][0-9]* .*@@\\)/${ansi.blue('\\1')}/`,
142
- '-e', `s/^\\(@@ -[0-9][0-9]*,[0-9][0-9]* +[0-9][0-9]* .*@@\\)/${ansi.blue('\\1')}/`,
143
- '-e', `s/^\\(@@ -[0-9][0-9]* +[0-9][0-9]*,[0-9][0-9]* .*@@\\)/${ansi.blue('\\1')}/`,
158
+ '-e',
159
+ `s/^\\(@@ -[0-9][0-9]*,[0-9][0-9]* +[0-9][0-9]*,[0-9][0-9]* .*@@\\)/${ansi.blue('\\1')}/`,
160
+ '-e',
161
+ `s/^\\(@@ -[0-9][0-9]*,[0-9][0-9]* +[0-9][0-9]* .*@@\\)/${ansi.blue('\\1')}/`,
162
+ '-e',
163
+ `s/^\\(@@ -[0-9][0-9]* +[0-9][0-9]*,[0-9][0-9]* .*@@\\)/${ansi.blue('\\1')}/`,
144
164
  ]);
145
165
  ssh.stdout.pipe(colorize.stdin);
146
166
  colorize.stdout.pipe(less.stdin);
@@ -153,19 +173,19 @@ export default async function diff(dryRunOutput, options) {
153
173
  less.on('exit', (code) => {
154
174
  if (code === 0) {
155
175
  resolve();
156
- /* node:coverage disable */
157
176
  } else {
177
+ /* node :coverage disable */
158
178
  reject(`exited with code ${code}`);
179
+ /* node:coverage enable */
159
180
  }
160
- /* node:coverage enable */
161
181
  });
162
182
  });
163
- /* node:coverage disable */
164
183
  } else {
184
+ /* node:coverage disable */
165
185
  return await new Promise((resolve) => {
166
186
  let diff = '';
167
187
 
168
- ssh.stdout.on('data', (data) => diff += data);
188
+ ssh.stdout.on('data', (data) => (diff += data));
169
189
 
170
190
  ssh.stderr.pipe(process.stderr);
171
191
 
@@ -173,8 +193,8 @@ export default async function diff(dryRunOutput, options) {
173
193
  resolve(diff);
174
194
  });
175
195
  });
196
+ /* node:coverage enable */
176
197
  }
177
- /* node:coverage enable */
178
198
  } else if (options.interactive) {
179
199
  console.log(ansi.yellow('No changes detected.'));
180
200
  }
package/src/rsync.js CHANGED
@@ -32,23 +32,24 @@ export function filters() {
32
32
 
33
33
  // merge path
34
34
  if (options.path) {
35
- const paths = options.path.split(/((?<!\\) )+/)
36
- .map(p => p.replace(/\\ /g, ' '))
37
- .map(p => path.resolve(p))
38
- .map(p => p) // TODO glob // paths.map! { |p| p[/[*?]/] ? Dir.glob(p) : p }
35
+ const paths = options.path
36
+ .split(/((?<!\\) )+/)
37
+ .map((p) => p.replace(/\\ /g, ' '))
38
+ .map((p) => path.resolve(p))
39
+ .map((p) => p) // TODO glob // paths.map! { |p| p[/[*?]/] ? Dir.glob(p) : p }
39
40
  .flat(Infinity)
40
41
  // make paths relative to .frak file
41
- .map(p => p.replace(path.dirname(locateConfig()), ''));
42
+ .map((p) => p.replace(path.dirname(locateConfig()), ''));
42
43
 
43
44
  // include all parent directories to fix recursive rsync from excluding all
44
- paths.forEach(p => {
45
+ paths.forEach((p) => {
45
46
  includes.push(p);
46
47
 
47
48
  while (path.dirname(p) !== '/') {
48
49
  excludes.push(`${path.dirname(p)}/*`);
49
50
 
50
51
  p = path.dirname(p);
51
- includes.push(p)
52
+ includes.push(p);
52
53
  }
53
54
  });
54
55
 
@@ -60,8 +61,8 @@ export function filters() {
60
61
  filters.push('.e .frakignore');
61
62
  }
62
63
 
63
- includes.forEach(include => filters.push(`+ ${include}`));
64
- excludes.forEach(include => filters.push(`- ${include}`));
64
+ includes.forEach((include) => filters.push(`+ ${include}`));
65
+ excludes.forEach((include) => filters.push(`- ${include}`));
65
66
 
66
67
  return filters;
67
68
  }
@@ -90,35 +91,45 @@ export function exec(...options) {
90
91
  }
91
92
 
92
93
  let backup = [];
93
- let backupName = 'name' in commandOptions
94
- ? `${commandOptions.name}_${(new Date()).toISOString()}`
95
- : (new Date()).toISOString();
94
+ let backupName =
95
+ 'name' in commandOptions
96
+ ? `${commandOptions.name}_${new Date().toISOString()}`
97
+ : new Date().toISOString();
96
98
 
97
99
  // Figure out backup options
98
- backup = [
99
- '--exclude=.backups/',
100
- ];
100
+ backup = ['--exclude=.backups/'];
101
101
 
102
102
  // Keep the same backup path for all rsync commands
103
103
  if (backupPath === null) {
104
- backupPath = `.backups/${backupName}`
104
+ backupPath = `.backups/${backupName}`;
105
105
  }
106
106
 
107
107
  // This should only happen on push
108
108
  if (command === 'push') {
109
- backup = [...backup, '--backup', `--backup-dir='${backupPath}'`]
109
+ backup = [...backup, '--backup', `--backup-dir=${backupPath}`];
110
110
  }
111
111
 
112
112
  const args = [
113
113
  'rsync',
114
114
  [
115
- '--archive', '--no-group', '--no-owner', '--no-perms', '--no-times', '--human-readable',
116
- '--compress', '--checksum', '--itemize-changes', '--recursive', '--delete',
115
+ '--archive',
116
+ '--no-group',
117
+ '--no-owner',
118
+ '--no-perms',
119
+ '--no-times',
120
+ '--human-readable',
121
+ '--compress',
122
+ '--checksum',
123
+ '--itemize-changes',
124
+ '--recursive',
125
+ '--delete',
126
+ process.env.DEBUG ? '--rsh=ssh' : '--rsh=ssh -q',
117
127
  `--rsync-path=${config['rsync_path'] ? config['rsync_path'] : 'rsync'}`,
118
128
  '--filter=. -',
119
129
  ...backup,
120
130
  ...options,
121
- source, destination,
131
+ source,
132
+ destination,
122
133
  ],
123
134
  ];
124
135
 
@@ -126,17 +137,21 @@ export function exec(...options) {
126
137
  debug(args.flat().join(' '));
127
138
  debug('filters:', filters());
128
139
 
129
- let output = '';
140
+ let output = '',
141
+ stderr = '';
130
142
 
131
143
  const rsync = spawn.apply(null, args);
132
144
 
133
- const echo = spawn('echo', [ filters().join('\n') ]);
145
+ const echo = spawn('echo', [filters().join('\n')]);
134
146
 
135
147
  echo.stdout.pipe(rsync.stdin);
136
148
 
137
149
  rsync.stdout.on('data', (data) => {
138
150
  output += `${data}`;
139
151
  });
152
+ rsync.stderr.on('data', (data) => {
153
+ stderr += `${data}`;
154
+ });
140
155
 
141
156
  /* node:coverage disable */
142
157
  rsync.stderr.on('data', (data) => {
@@ -151,11 +166,11 @@ export function exec(...options) {
151
166
  output,
152
167
  backupPath,
153
168
  });
154
- /* node:coverage disable */
155
169
  } else {
156
- reject(`rsync exited with code ${code}`);
170
+ /* node:coverage disable */
171
+ reject(`rsync exited with code ${code}: ${stderr}`);
172
+ /* node:coverage enable */
157
173
  }
158
- /* node:coverage enable */
159
174
  });
160
175
  });
161
176
  }
package/src/ssh.js CHANGED
@@ -6,7 +6,7 @@ export function exec(command, options = {}) {
6
6
 
7
7
  const cmd = `cd ${options.root || '.'}; sh`;
8
8
 
9
- const ssh = spawn('ssh', [ options.server, '--', cmd ]);
9
+ const ssh = spawn('ssh', [options.server, '--', cmd]);
10
10
 
11
11
  // const echo = spawn('echo', [ command ]);
12
12
 
@@ -31,11 +31,11 @@ export function exec(command, options = {}) {
31
31
  ssh.on('exit', (code) => {
32
32
  if (code === 0) {
33
33
  resolve();
34
- /* node:coverage disable */
35
34
  } else {
35
+ /* node:coverage disable */
36
36
  reject(`exited with code ${code}`);
37
+ /* node:coverage enable */
37
38
  }
38
- /* node:coverage enable */
39
39
  });
40
40
  });
41
41