@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 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 --format='%Y %n' .backups/* | sort -r`;
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@frakjs/frak",
3
- "version": "0.4.0",
3
+ "version": "0.5.0",
4
4
  "description": "A commandline deployment tool for syncing files to remote servers.",
5
5
  "main": "index.js",
6
6
  "engines": {
package/src/crypto.js CHANGED
@@ -1,5 +1,9 @@
1
1
  import crypto from 'node:crypto';
2
2
 
3
3
  export function sha256(text) {
4
+ if (typeof text === 'number') {
5
+ text = `${text}`;
6
+ }
7
+
4
8
  return crypto.createHash('sha256').update(text).digest('hex');
5
9
  }
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
- 'tarball=$(mktemp /tmp/frak-diff-tarball.XXXXXX);',
137
+ // Save the incoming tarball to /tmp
138
+ 'export tarball=$(mktemp /tmp/frak-diff-tarball.XXXXXX);',
118
139
  'cat > $tarball;',
119
- `cd ${config.root};`,
120
- diffs.join('; '),
121
- ';',
122
- 'rm $tarball',
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) {