cloudron 5.0.1 → 5.1.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/cloudron CHANGED
@@ -3,10 +3,11 @@
3
3
  'use strict';
4
4
 
5
5
  const actions = require('../src/actions.js'),
6
+ backupTools = require('../src/backup-tools.js'),
6
7
  buildActions = require('../src/build-actions.js'),
7
8
  completion = require('../src/completion.js'),
8
9
  config = require('../src/config.js'),
9
- program = require('commander'),
10
+ Command = require('commander').Command,
10
11
  safe = require('safetydance'),
11
12
  semver = require('semver'),
12
13
  superagent = require('superagent'),
@@ -16,30 +17,72 @@ const version = require('../package.json').version;
16
17
 
17
18
  // ensure node version
18
19
  if (!semver.satisfies(process.version, require('../package.json').engines.node)) {
19
- console.error('Your nodejs version is not compatible. Please installe nodejs', require('../package.json').engines.node);
20
+ console.error('Your nodejs version is not compatible. Please install nodejs', require('../package.json').engines.node);
20
21
  process.exit(1);
21
22
  }
22
23
 
24
+ const program = new Command();
25
+
23
26
  function collectArgs(value, collected) {
24
27
  collected.push(value);
25
28
  return collected;
26
29
  }
27
30
 
28
- // TODO when updating to commander v8 we require https://github.com/tj/commander.js/pull/1670
29
- program.version(version)
30
- .option('--server <server>', 'Cloudron domain')
31
+ program.version(version);
32
+
33
+ // global options
34
+ program.option('--server <server>', 'Cloudron domain')
31
35
  .option('--token <token>', 'Cloudron token')
32
36
  .option('--allow-selfsigned', 'Accept self signed SSL certificate')
33
37
  .option('--accept-selfsigned', 'Accept self signed SSL certificate');
34
38
 
39
+ // this is a separate binary since global options are not applicable
35
40
  program.command('appstore', 'Cloudron appstore commands');
36
41
 
37
- program.command('backup', 'App backup commands');
42
+ const backupCommand = program.command('backup')
43
+ .description('App backup commands');
44
+
45
+ backupCommand.command('create')
46
+ .description('Create new app backup')
47
+ .option('--app <id>', 'App id')
48
+ .action(actions.backupCreate);
49
+
50
+ backupCommand.command('list')
51
+ .description('List all backups for specified app')
52
+ .option('--raw', 'Print raw json output')
53
+ .option('--app <id>', 'App id')
54
+ .action(actions.backupList);
55
+
56
+ backupCommand.command('decrypt <file>')
57
+ .description('Decrypt an encrypted file')
58
+ .option('--password <password>', 'password')
59
+ .action(backupTools.decrypt);
60
+
61
+ backupCommand.command('decrypt-dir <indir> <outdir>')
62
+ .description('Decrypt an encrypted directory')
63
+ .option('--password <password>', 'password')
64
+ .action(backupTools.decryptDir);
65
+
66
+ backupCommand.command('decrypt-filename <path>')
67
+ .description('Encrypt a file name')
68
+ .option('--password <password>', 'password')
69
+ .action(backupTools.decryptFilename);
70
+
71
+ backupCommand.command('encrypt <input>')
72
+ .description('Encrypt a file')
73
+ .option('--password <password>', 'password')
74
+ .action(backupTools.encrypt);
75
+
76
+ backupCommand.command('encrypt-filename <path>')
77
+ .description('Encrypt a file name')
78
+ .option('--password <password>', 'password')
79
+ .action(backupTools.encryptFilename);
38
80
 
39
81
  program.command('completion')
40
82
  .description('Shows completion for your shell')
41
83
  .action(completion);
42
84
 
85
+ // should probably move to separate binary since globals don't apply
43
86
  program.command('build')
44
87
  .description('Build an app')
45
88
  .option('--build-arg <namevalue>', 'Build arg passed to docker. Can be used multiple times', collectArgs, [])
@@ -83,7 +126,28 @@ program.command('debug [cmd...]')
83
126
  .option('--limit-memory', 'Enforces app memory limit. Default is to not limit memory in debug mode.')
84
127
  .action(actions.debug);
85
128
 
86
- program.command('env', 'App environment commands');
129
+ const envCommand = program.command('env')
130
+ .description('App environment commands');
131
+
132
+ envCommand.command('get <name>')
133
+ .description('Get environment variables')
134
+ .option('--app <id>', 'App id')
135
+ .action(actions.envGet);
136
+
137
+ envCommand.command('list')
138
+ .description('List environment variables')
139
+ .option('--app <id>', 'App id')
140
+ .action(actions.envList);
141
+
142
+ envCommand.command('set <KEY=value...>')
143
+ .description('Set environment variables')
144
+ .option('--app <id>', 'App id')
145
+ .action(actions.envSet);
146
+
147
+ envCommand.command('unset <KEY...>')
148
+ .description('Unset environment variables')
149
+ .option('--app <id>', 'App id')
150
+ .action(actions.envUnset);
87
151
 
88
152
  program.command('exec [cmd...]')
89
153
  .description('Exec a command in an application')
@@ -255,11 +319,4 @@ program.command('update')
255
319
  }
256
320
 
257
321
  program.parse(process.argv);
258
-
259
- const knownCommand = program.commands.some(function (command) { return command._name === process.argv[2] || command._alias === process.argv[2]; });
260
- if (!knownCommand) {
261
- console.log('Unknown command: ' + process.argv[2] + '.\nTry ' + 'cloudron help');
262
- process.exit(1);
263
- }
264
322
  })();
265
-
@@ -59,22 +59,4 @@ program.command('versions')
59
59
  .option('--raw', 'Dump versions as json')
60
60
  .action(appstoreActions.listVersions);
61
61
 
62
- if (!process.argv.slice(2).length) {
63
- program.outputHelp();
64
- } else { // https://github.com/tj/commander.js/issues/338
65
- // deal first with global flags!
66
- program.parse(process.argv);
67
-
68
- if (process.argv[2] === 'help') {
69
- return program.outputHelp();
70
- }
71
-
72
- var knownCommand = program.commands.some(function (command) { return command._name === process.argv[2] || command._alias === process.argv[2]; });
73
- if (!knownCommand) {
74
- console.log('Unknown command: ' + process.argv[2] + '.\nTry ' + 'cloudron appstore help');
75
- process.exit(1);
76
- }
77
- return;
78
- }
79
-
80
62
  program.parse(process.argv);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cloudron",
3
- "version": "5.0.1",
3
+ "version": "5.1.0",
4
4
  "license": "MIT",
5
5
  "description": "Cloudron Commandline Tool",
6
6
  "main": "main.js",
@@ -17,9 +17,9 @@
17
17
  },
18
18
  "author": "Cloudron Developers <support@cloudron.io>",
19
19
  "dependencies": {
20
- "async": "^3.2.3",
21
- "cloudron-manifestformat": "^5.15.2",
22
- "commander": "^6.1.0",
20
+ "async": "^3.2.4",
21
+ "cloudron-manifestformat": "^5.17.0",
22
+ "commander": "^9.4.0",
23
23
  "debug": "^4.3.4",
24
24
  "delay": "^5.0.0",
25
25
  "easy-table": "^1.2.0",
@@ -33,9 +33,9 @@
33
33
  "readline-sync": "^1.4.10",
34
34
  "safetydance": "^2.2.0",
35
35
  "split": "^1.0.1",
36
- "superagent": "^7.1.3",
36
+ "superagent": "^8.0.0",
37
37
  "tar-fs": "https://registry.npmjs.org/tar-fs/-/tar-fs-1.12.0.tgz",
38
- "underscore": "^1.13.3"
38
+ "underscore": "^1.13.4"
39
39
  },
40
40
  "engines": {
41
41
  "node": ">= 14.x.x"
package/src/actions.js CHANGED
@@ -4,9 +4,9 @@ const assert = require('assert'),
4
4
  config = require('./config.js'),
5
5
  delay = require('delay'),
6
6
  ejs = require('ejs'),
7
+ { exit, locateManifest } = require('./helper.js'),
7
8
  EventSource = require('eventsource'),
8
9
  fs = require('fs'),
9
- helper = require('./helper.js'),
10
10
  https = require('https'),
11
11
  manifestFormat = require('cloudron-manifestformat'),
12
12
  opn = require('open'),
@@ -24,8 +24,6 @@ const assert = require('assert'),
24
24
  zlib = require('zlib'),
25
25
  _ = require('underscore');
26
26
 
27
- const exit = helper.exit;
28
-
29
27
  exports = module.exports = {
30
28
  list,
31
29
  login,
@@ -65,13 +63,13 @@ const NO_APP_FOUND_ERROR_STRING = 'Could not determine app. Use --app to specify
65
63
 
66
64
  // options for the request module
67
65
  function requestOptions(options) {
68
- const adminFqdn = options.parent.server || config.apiEndpoint();
66
+ const adminFqdn = options.server || config.apiEndpoint();
69
67
 
70
68
  // ensure config can return the correct section
71
69
  config.setActive(adminFqdn);
72
70
 
73
- const token = options.parent.token || config.token();
74
- const rejectUnauthorized = !(options.parent.allowSelfsigned || options.parent.acceptSelfsigned || config.allowSelfsigned());
71
+ const token = options.token || config.token();
72
+ const rejectUnauthorized = !(options.allowSelfsigned || options.acceptSelfsigned || config.allowSelfsigned());
75
73
 
76
74
  if (!adminFqdn && !token) return exit('Login with "cloudron login" first'); // a bit rough to put this here!
77
75
 
@@ -179,7 +177,7 @@ async function getApp(options) {
179
177
  const app = options.app || null;
180
178
 
181
179
  if (!app) { // determine based on repository name given during 'build'
182
- const manifestFilePath = helper.locateManifest();
180
+ const manifestFilePath = locateManifest();
183
181
 
184
182
  if (!manifestFilePath) throw new Error(NO_APP_FOUND_ERROR_STRING);
185
183
 
@@ -368,7 +366,7 @@ async function authenticate(adminFqdn, username, password, options) {
368
366
  return response.body.accessToken;
369
367
  }
370
368
 
371
- async function login(adminFqdn, options) {
369
+ async function login(adminFqdn, localOptions, cmd) {
372
370
  if (!adminFqdn) adminFqdn = readlineSync.question('Cloudron Domain (e.g. my.example.com): ', {});
373
371
  if (!adminFqdn) return exit('');
374
372
 
@@ -377,7 +375,9 @@ async function login(adminFqdn, options) {
377
375
 
378
376
  config.setActive(adminFqdn);
379
377
 
380
- const rejectUnauthorized = !(options.parent.allowSelfsigned || options.parent.acceptSelfsigned);
378
+ const options = cmd.optsWithGlobals();
379
+
380
+ const rejectUnauthorized = !(options.allowSelfsigned || options.acceptSelfsigned);
381
381
  let token = config.token();
382
382
  if (token) { // check if the token is not expired
383
383
  const request = superagent.get(`https://${adminFqdn}/api/v1/profile?access_token=${token}`)
@@ -407,7 +407,7 @@ async function login(adminFqdn, options) {
407
407
  config.setActive(adminFqdn);
408
408
  config.setApiEndpoint(adminFqdn);
409
409
  config.setToken(token);
410
- config.setAllowSelfsigned(options.parent.allowSelfsigned || options.parent.acceptSelfsigned);
410
+ config.setAllowSelfsigned(cmd.optsWithGlobals().allowSelfsigned || cmd.optsWithGlobals().acceptSelfsigned);
411
411
  config.set('cloudrons.default', adminFqdn);
412
412
 
413
413
  console.log('Login successful.');
@@ -420,7 +420,8 @@ function logout() {
420
420
  console.log('Logged out.');
421
421
  }
422
422
 
423
- async function open(options) {
423
+ async function open(localOptions, cmd) {
424
+ const options = cmd.optsWithGlobals();
424
425
  const [error, app] = await safe(getApp(options));
425
426
  if (error) return exit(error);
426
427
 
@@ -429,9 +430,8 @@ async function open(options) {
429
430
  opn(`https://${app.fqdn}`);
430
431
  }
431
432
 
432
- async function list(options) {
433
- helper.verifyArguments(arguments);
434
-
433
+ async function list(localOptions, cmd) {
434
+ const options = cmd.optsWithGlobals();
435
435
  const [error, response] = await safe(createRequest('GET', '/api/v1/apps', options));
436
436
  if (error) return exit(error);
437
437
  if (response.statusCode !== 200) return exit(`Failed to list apps: ${requestError(response)}`);
@@ -532,7 +532,7 @@ async function getManifest(appstoreId) {
532
532
 
533
533
  if (appstoreId) return await downloadManifest(appstoreId);
534
534
 
535
- const manifestFilePath = helper.locateManifest();
535
+ const manifestFilePath = locateManifest();
536
536
  if (!manifestFilePath) throw new Error('No CloudronManifest.json found');
537
537
 
538
538
  const result = manifestFormat.parseFile(manifestFilePath);
@@ -550,8 +550,8 @@ async function getManifest(appstoreId) {
550
550
  return { manifest: result.manifest, manifestFilePath };
551
551
  }
552
552
 
553
- async function install(options) {
554
- helper.verifyArguments(arguments);
553
+ async function install(localOptions, cmd) {
554
+ const options = cmd.optsWithGlobals();
555
555
 
556
556
  try {
557
557
  const result = await getManifest(options.appstoreId || '');
@@ -660,8 +660,8 @@ async function install(options) {
660
660
  }
661
661
  }
662
662
 
663
- async function configure(options) {
664
- helper.verifyArguments(arguments);
663
+ async function configure(localOptions, cmd) {
664
+ const options = cmd.optsWithGlobals();
665
665
 
666
666
  try {
667
667
  const app = await getApp(options);
@@ -740,8 +740,8 @@ async function configure(options) {
740
740
  }
741
741
  }
742
742
 
743
- async function update(options) {
744
- helper.verifyArguments(arguments);
743
+ async function update(localOptions, cmd) {
744
+ const options = cmd.optsWithGlobals();
745
745
 
746
746
  try {
747
747
  const app = await getApp(options);
@@ -797,15 +797,16 @@ async function update(options) {
797
797
  }
798
798
  }
799
799
 
800
- async function debug(cmd, options) {
800
+ async function debug(args, localOptions, cmd) {
801
801
  try {
802
+ const options = cmd.optsWithGlobals();
802
803
  const app = await getApp(options);
803
804
  if (!app) return exit(NO_APP_FOUND_ERROR_STRING);
804
805
 
805
806
  const data = {
806
807
  debugMode: options.disable ? null : {
807
808
  readonlyRootfs: options.readonly ? true : false,
808
- cmd: parseDebugCommand(cmd.join(' ').trim())
809
+ cmd: parseDebugCommand(args.join(' ').trim())
809
810
  }
810
811
  };
811
812
 
@@ -834,8 +835,9 @@ async function debug(cmd, options) {
834
835
  }
835
836
  }
836
837
 
837
- async function repair(options) {
838
+ async function repair(localOptions, cmd) {
838
839
  try {
840
+ const options = cmd.optsWithGlobals();
839
841
  const app = await getApp(options);
840
842
  if (!app) return exit(NO_APP_FOUND_ERROR_STRING);
841
843
 
@@ -862,10 +864,9 @@ async function repair(options) {
862
864
  }
863
865
  }
864
866
 
865
- async function cancel(options) {
866
- helper.verifyArguments(arguments);
867
-
867
+ async function cancel(localOptions, cmd) {
868
868
  try {
869
+ const options = cmd.optsWithGlobals();
869
870
  const app = await getApp(options);
870
871
  if (!app) return exit(NO_APP_FOUND_ERROR_STRING);
871
872
  if (!app.taskId) return exit('No active task.');
@@ -876,10 +877,9 @@ async function cancel(options) {
876
877
  }
877
878
  }
878
879
 
879
- async function uninstall(options) {
880
- helper.verifyArguments(arguments);
881
-
880
+ async function uninstall(localOptions, cmd) {
882
881
  try {
882
+ const options = cmd.optsWithGlobals();
883
883
  const app = await getApp(options);
884
884
  if (!app) return exit(NO_APP_FOUND_ERROR_STRING);
885
885
 
@@ -918,9 +918,8 @@ function logPrinter(obj) {
918
918
  console.log('%s - %s', ts, message);
919
919
  }
920
920
 
921
- async function logs(options) {
922
- helper.verifyArguments(arguments);
923
-
921
+ async function logs(localOptions, cmd) {
922
+ const options = cmd.optsWithGlobals();
924
923
  const { adminFqdn, token, rejectUnauthorized } = requestOptions(options);
925
924
  const lines = options.lines || 500;
926
925
  const tail = !!options.tail;
@@ -968,9 +967,8 @@ async function logs(options) {
968
967
  }
969
968
  }
970
969
 
971
- async function status(options) {
972
- helper.verifyArguments(arguments);
973
-
970
+ async function status(localOptions, cmd) {
971
+ const options = cmd.optsWithGlobals();
974
972
  const [error, app] = await safe(getApp(options));
975
973
  if (error) return exit(error);
976
974
  if (!app) return exit(NO_APP_FOUND_ERROR_STRING);
@@ -986,10 +984,9 @@ async function status(options) {
986
984
  console.log();
987
985
  }
988
986
 
989
- async function inspect(options) {
990
- helper.verifyArguments(arguments);
991
-
987
+ async function inspect(localOptions, cmd) {
992
988
  try {
989
+ const options = cmd.optsWithGlobals();
993
990
  const response = await createRequest('GET', '/api/v1/apps', options);
994
991
  if (response.statusCode !== 200) return exit(`Failed to list apps: ${requestError(response)}`);
995
992
 
@@ -1002,7 +999,7 @@ async function inspect(options) {
1002
999
  apps.push(response2.body);
1003
1000
  }
1004
1001
 
1005
- const { adminFqdn } = requestOptions(options);
1002
+ const { adminFqdn } = requestOptions(cmd.optsWithGlobals());
1006
1003
  console.log(JSON.stringify({
1007
1004
  apiEndpoint: adminFqdn,
1008
1005
  appStoreOrigin: config.appStoreOrigin(),
@@ -1013,10 +1010,9 @@ async function inspect(options) {
1013
1010
  }
1014
1011
  }
1015
1012
 
1016
- async function restart(options) {
1017
- helper.verifyArguments(arguments);
1018
-
1013
+ async function restart(localOptions, cmd) {
1019
1014
  try {
1015
+ const options = cmd.optsWithGlobals();
1020
1016
  const app = await getApp(options);
1021
1017
  if (!app) return exit(NO_APP_FOUND_ERROR_STRING);
1022
1018
  await restartApp(app, options);
@@ -1027,10 +1023,9 @@ async function restart(options) {
1027
1023
  }
1028
1024
  }
1029
1025
 
1030
- async function start(options) {
1031
- helper.verifyArguments(arguments);
1032
-
1026
+ async function start(localOptions, cmd) {
1033
1027
  try {
1028
+ const options = cmd.optsWithGlobals();
1034
1029
  const app = await getApp(options);
1035
1030
  if (!app) return exit(NO_APP_FOUND_ERROR_STRING);
1036
1031
  await startApp(app, options);
@@ -1041,10 +1036,9 @@ async function start(options) {
1041
1036
  }
1042
1037
  }
1043
1038
 
1044
- async function stop(options) {
1045
- helper.verifyArguments(arguments);
1046
-
1039
+ async function stop(localOptions, cmd) {
1047
1040
  try {
1041
+ const options = cmd.optsWithGlobals();
1048
1042
  const app = await getApp(options);
1049
1043
  if (!app) return exit(NO_APP_FOUND_ERROR_STRING);
1050
1044
  await stopApp(app, options);
@@ -1054,10 +1048,9 @@ async function stop(options) {
1054
1048
  }
1055
1049
  }
1056
1050
 
1057
- async function backupCreate(options) {
1058
- helper.verifyArguments(arguments);
1059
-
1051
+ async function backupCreate(localOptions, cmd) {
1060
1052
  try {
1053
+ const options = cmd.optsWithGlobals();
1061
1054
  const app = await getApp(options);
1062
1055
  if (!app) return exit(NO_APP_FOUND_ERROR_STRING);
1063
1056
 
@@ -1072,10 +1065,9 @@ async function backupCreate(options) {
1072
1065
  }
1073
1066
  }
1074
1067
 
1075
- async function backupList(options) {
1076
- helper.verifyArguments(arguments);
1077
-
1068
+ async function backupList(localOptions, cmd) {
1078
1069
  try {
1070
+ const options = cmd.optsWithGlobals();
1079
1071
  const app = await getApp(options);
1080
1072
  if (!app) return exit(NO_APP_FOUND_ERROR_STRING);
1081
1073
 
@@ -1121,10 +1113,9 @@ async function getLastBackup(app, options) {
1121
1113
  return response.body.backups[0].id;
1122
1114
  }
1123
1115
 
1124
- async function restore(options) {
1125
- helper.verifyArguments(arguments);
1126
-
1116
+ async function restore(localOptions, cmd) {
1127
1117
  try {
1118
+ const options = cmd.optsWithGlobals();
1128
1119
  const app = await getApp(options);
1129
1120
  if (!app) return exit(NO_APP_FOUND_ERROR_STRING);
1130
1121
 
@@ -1149,10 +1140,9 @@ async function restore(options) {
1149
1140
  }
1150
1141
  }
1151
1142
 
1152
- async function importApp(options) {
1153
- helper.verifyArguments(arguments);
1154
-
1143
+ async function importApp(localOptions, cmd) {
1155
1144
  try {
1145
+ const options = cmd.optsWithGlobals();
1156
1146
  const app = await getApp(options);
1157
1147
  if (!app) return exit(NO_APP_FOUND_ERROR_STRING);
1158
1148
 
@@ -1205,10 +1195,9 @@ async function importApp(options) {
1205
1195
  }
1206
1196
  }
1207
1197
 
1208
- async function exportApp(options) {
1209
- helper.verifyArguments(arguments);
1210
-
1198
+ async function exportApp(localOptions, cmd) {
1211
1199
  try {
1200
+ const options = cmd.optsWithGlobals();
1212
1201
  const app = await getApp(options);
1213
1202
  if (!app) return exit(NO_APP_FOUND_ERROR_STRING);
1214
1203
 
@@ -1227,10 +1216,9 @@ async function exportApp(options) {
1227
1216
  }
1228
1217
  }
1229
1218
 
1230
- async function clone(options) {
1231
- helper.verifyArguments(arguments);
1232
-
1219
+ async function clone(localOptions, cmd) {
1233
1220
  try {
1221
+ const options = cmd.optsWithGlobals();
1234
1222
  const app = await getApp(options);
1235
1223
  if (!app) return exit(NO_APP_FOUND_ERROR_STRING);
1236
1224
 
@@ -1289,11 +1277,12 @@ function demuxStream(stream, stdout, stderr) {
1289
1277
  // echo "sauce" | cloudron exec -- bash -c "cat - > /app/data/sauce" - test with binary files. should disable tty
1290
1278
  // cat ~/tmp/fantome.tar.gz | cloudron exec -- bash -c "tar xvf - -C /tmp" - must show an error
1291
1279
  // cat ~/tmp/fantome.tar.gz | cloudron exec -- bash -c "tar zxf - -C /tmp" - must extrack ok
1292
- async function exec(cmd, options) {
1293
- let stdin = options._stdin || process.stdin; // hack for 'push', 'pull' to reuse this function
1294
- let stdout = options._stdout || process.stdout;
1280
+ async function exec(args, localOptions, cmd) {
1281
+ let stdin = localOptions._stdin || process.stdin; // hack for 'push', 'pull' to reuse this function
1282
+ let stdout = localOptions._stdout || process.stdout; // hack for 'push', 'pull' to reuse this function
1295
1283
 
1296
- let tty = !!options.const;
1284
+ const options = cmd.optsWithGlobals();
1285
+ let tty = !!options.tty;
1297
1286
 
1298
1287
  const [error, app] = await safe(getApp(options));
1299
1288
  if (error) return exit(error);
@@ -1301,15 +1290,15 @@ async function exec(cmd, options) {
1301
1290
 
1302
1291
  if (app.installationState !== 'installed') exit('App is not yet running. Try again later.');
1303
1292
 
1304
- if (cmd.length === 0) {
1305
- cmd = [ '/bin/bash' ];
1293
+ if (args.length === 0) {
1294
+ args = [ '/bin/bash' ];
1306
1295
  tty = true; // override
1307
1296
  }
1308
1297
 
1309
1298
  if (tty && !stdin.isTTY) exit('stdin is not tty');
1310
1299
 
1311
1300
  const request = createRequest('POST', `/api/v1/apps/${app.id}/exec`, options);
1312
- const response = await request.send({ cmd, tty });
1301
+ const response = await request.send({ cmd: args, tty });
1313
1302
  if (response.statusCode !== 200) return exit(`Failed to create exec: ${requestError(response)}`);
1314
1303
  const execId = response.body.id;
1315
1304
 
@@ -1320,7 +1309,7 @@ async function exec(cmd, options) {
1320
1309
  process.exit(response2.body.exitCode);
1321
1310
  }
1322
1311
 
1323
- const { adminFqdn, token, rejectUnauthorized } = requestOptions(options);
1312
+ const { adminFqdn, token, rejectUnauthorized } = requestOptions(cmd.optsWithGlobals());
1324
1313
 
1325
1314
  const searchParams = new URLSearchParams({
1326
1315
  rows: stdout.rows || 24,
@@ -1390,30 +1379,30 @@ async function exec(cmd, options) {
1390
1379
  req.end(); // this makes the request
1391
1380
  }
1392
1381
 
1393
- function push(localDir, remote, options) {
1382
+ function push(localDir, remote, localOptions, cmd) {
1394
1383
  // deal with paths prefixed with ~
1395
- var local = localDir.replace(/^~(?=$|\/|\\)/, os.homedir());
1396
- var stat = fs.existsSync(path.resolve(local)) ? fs.lstatSync(local) : null;
1384
+ const local = localDir.replace(/^~(?=$|\/|\\)/, os.homedir());
1385
+ const stat = fs.existsSync(path.resolve(local)) ? fs.lstatSync(local) : null;
1397
1386
 
1398
1387
  if (stat && stat.isDirectory()) {
1399
1388
  // Create a functor for stdin. If no data event handlers are attached, and there are no stream.pipe() destinations, and the stream is
1400
1389
  // switched into flowing mode, then data will be lost. So, we have to start the tarzip only when exec is ready to attach event handlers.
1401
- options._stdin = function () {
1390
+ localOptions._stdin = function () {
1402
1391
  var tarzip = spawn('tar', ['zcf', '-', '-C', path.dirname(local), path.basename(local)], { stdio: 'pipe' });
1403
1392
  return tarzip.stdout;
1404
1393
  };
1405
1394
 
1406
- exec(['tar', 'zxvf', '-', '-C', remote], options);
1395
+ exec(['tar', 'zxvf', '-', '-C', remote], localOptions, cmd);
1407
1396
  } else {
1408
1397
  if (local === '-') {
1409
- options._stdin = process.stdin;
1398
+ localOptions._stdin = process.stdin;
1410
1399
  } else if (stat) {
1411
- var progress = new ProgressStream({ length: stat.size, time: 1000 });
1400
+ const progress = new ProgressStream({ length: stat.size, time: 1000 });
1412
1401
 
1413
- options._stdin = progress;
1402
+ localOptions._stdin = progress;
1414
1403
  fs.createReadStream(local).pipe(progress);
1415
1404
 
1416
- var bar = new ProgressBar('Uploading [:bar] :percent: :etas', {
1405
+ const bar = new ProgressBar('Uploading [:bar] :percent: :etas', {
1417
1406
  complete: '=',
1418
1407
  incomplete: ' ',
1419
1408
  width: 100,
@@ -1425,43 +1414,44 @@ function push(localDir, remote, options) {
1425
1414
  exit('local file ' + local + ' does not exist');
1426
1415
  }
1427
1416
 
1428
- options._stdin.on('error', function (error) { exit('Error pushing', error); });
1417
+ localOptions._stdin.on('error', function (error) { exit('Error pushing', error); });
1429
1418
 
1430
1419
  if (remote.endsWith('/')) { // dir
1431
1420
  remote = remote + '/' + path.basename(local); // do not use path.join as we want this to be a UNIX path
1432
1421
  }
1433
1422
 
1434
- exec(['bash', '-c', `cat - > "${remote}"`], options);
1423
+ exec(['bash', '-c', `cat - > "${remote}"`], localOptions, cmd);
1435
1424
  }
1436
1425
  }
1437
1426
 
1438
- function pull(remote, local, options) {
1427
+ function pull(remote, local, localOptions, cmd) {
1439
1428
  if (remote.endsWith('/')) { // dir
1440
1429
  var untar = tar.extract(local); // local directory is created if it doesn't exist!
1441
1430
  var unzip = zlib.createGunzip();
1442
1431
 
1443
1432
  unzip.pipe(untar);
1444
- options._stdout = unzip;
1433
+ localOptions._stdout = unzip;
1445
1434
 
1446
- exec(['tar', 'zcf', '-', '-C', remote, '.'], options);
1435
+ exec(['tar', 'zcf', '-', '-C', remote, '.'], localOptions, cmd);
1447
1436
  } else {
1448
1437
  if (fs.existsSync(local) && fs.lstatSync(local).isDirectory()) {
1449
1438
  local = path.join(local, path.basename(remote));
1450
- options._stdout = fs.createWriteStream(local);
1439
+ localOptions._stdout = fs.createWriteStream(local);
1451
1440
  } else if (local === '-') {
1452
- options._stdout = process.stdout;
1441
+ localOptions._stdout = process.stdout;
1453
1442
  } else {
1454
- options._stdout = fs.createWriteStream(local);
1443
+ localOptions._stdout = fs.createWriteStream(local);
1455
1444
  }
1456
1445
 
1457
- options._stdout.on('error', function (error) { exit('Error pulling', error); });
1446
+ localOptions._stdout.on('error', function (error) { exit('Error pulling', error); });
1458
1447
 
1459
- exec(['cat', remote], options);
1448
+ exec(['cat', remote], localOptions, cmd);
1460
1449
  }
1461
1450
  }
1462
1451
 
1463
- function init(options) {
1464
- const manifestFilePath = helper.locateManifest();
1452
+ function init(localOptions, cmd) {
1453
+ const options = cmd.optsWithGlobals();
1454
+ const manifestFilePath = locateManifest();
1465
1455
  if (manifestFilePath && path.dirname(manifestFilePath) === process.cwd()) return exit('CloudronManifest.json already exists in current directory');
1466
1456
 
1467
1457
  const manifestTemplateFilename = options.appstore ? 'CloudronManifest.appstore.json.ejs' : 'CloudronManifest.json.ejs';
@@ -1527,8 +1517,9 @@ async function setEnv(app, env, options) {
1527
1517
  console.log('\n');
1528
1518
  }
1529
1519
 
1530
- async function envSet(envVars, options) {
1520
+ async function envSet(envVars, localOptions, cmd) {
1531
1521
  try {
1522
+ const options = cmd.optsWithGlobals();
1532
1523
  const app = await getApp(options);
1533
1524
  if (!app) return exit(NO_APP_FOUND_ERROR_STRING);
1534
1525
 
@@ -1548,8 +1539,9 @@ async function envSet(envVars, options) {
1548
1539
  }
1549
1540
  }
1550
1541
 
1551
- async function envUnset(envNames, options) {
1542
+ async function envUnset(envNames, localOptions, cmd) {
1552
1543
  try {
1544
+ const options = cmd.optsWithGlobals();
1553
1545
  const app = await getApp(options);
1554
1546
  if (!app) return exit(NO_APP_FOUND_ERROR_STRING);
1555
1547
 
@@ -1565,10 +1557,9 @@ async function envUnset(envNames, options) {
1565
1557
  }
1566
1558
  }
1567
1559
 
1568
- async function envList(options) {
1569
- helper.verifyArguments(arguments);
1570
-
1560
+ async function envList(localOptions, cmd) {
1571
1561
  try {
1562
+ const options = cmd.optsWithGlobals();
1572
1563
  const app = await getApp(options);
1573
1564
  if (!app) return exit(NO_APP_FOUND_ERROR_STRING);
1574
1565
 
@@ -1594,8 +1585,9 @@ async function envList(options) {
1594
1585
  }
1595
1586
  }
1596
1587
 
1597
- async function envGet(envName, options) {
1588
+ async function envGet(envName, localOptions, cmd) {
1598
1589
  try {
1590
+ const options = cmd.optsWithGlobals();
1599
1591
  const app = await getApp(options);
1600
1592
  if (!app) return exit(NO_APP_FOUND_ERROR_STRING);
1601
1593
 
@@ -2,30 +2,29 @@
2
2
 
3
3
  'use strict';
4
4
 
5
- var superagent = require('superagent'),
6
- util = require('util'),
7
- path = require('path'),
8
- assert = require('assert'),
5
+ const assert = require('assert'),
6
+ config = require('./config.js'),
9
7
  fs = require('fs'),
8
+ { exit, locateManifest } = require('./helper.js'),
9
+ manifestFormat = require('cloudron-manifestformat'),
10
+ path = require('path'),
11
+ readlineSync = require('readline-sync'),
10
12
  safe = require('safetydance'),
13
+ superagent = require('superagent'),
11
14
  Table = require('easy-table'),
12
- readlineSync = require('readline-sync'),
13
- config = require('./config.js'),
14
- helper = require('./helper.js'),
15
- exit = helper.exit,
16
- manifestFormat = require('cloudron-manifestformat');
15
+ util = require('util');
17
16
 
18
17
  exports = module.exports = {
19
- login: login,
20
- logout: logout,
21
- info: info,
22
- listVersions: listVersions,
23
- submit: submit,
24
- upload: upload,
25
- revoke: revoke,
26
- approve: approve,
27
- unpublish: unpublish,
28
- listPublishedApps: listPublishedApps
18
+ login,
19
+ logout,
20
+ info,
21
+ listVersions,
22
+ submit,
23
+ upload,
24
+ revoke,
25
+ approve,
26
+ unpublish,
27
+ listPublishedApps
29
28
  };
30
29
 
31
30
  const NO_MANIFEST_FOUND_ERROR_STRING = 'No CloudronManifest.json found';
@@ -42,7 +41,7 @@ function getAppstoreId(appstoreId, callback) {
42
41
  return callback(null, parts[0], parts[1]);
43
42
  }
44
43
 
45
- var manifestFilePath = helper.locateManifest();
44
+ var manifestFilePath = locateManifest();
46
45
 
47
46
  if (!manifestFilePath) return callback('No CloudronManifest.json found');
48
47
 
@@ -136,8 +135,6 @@ function info(options) {
136
135
  }
137
136
 
138
137
  function listVersions(options) {
139
- helper.verifyArguments(arguments);
140
-
141
138
  getAppstoreId(options.appstoreId, function (error, id) {
142
139
  if (error) exit(error);
143
140
 
@@ -428,10 +425,8 @@ function submitAppForReview(manifest, callback) {
428
425
  }
429
426
 
430
427
  function upload(options) {
431
- helper.verifyArguments(arguments);
432
-
433
428
  // try to find the manifest of this project
434
- var manifestFilePath = helper.locateManifest();
429
+ var manifestFilePath = locateManifest();
435
430
  if (!manifestFilePath) return exit(NO_MANIFEST_FOUND_ERROR_STRING);
436
431
 
437
432
  var result = manifestFormat.parseFile(manifestFilePath);
@@ -467,10 +462,8 @@ function upload(options) {
467
462
  }
468
463
 
469
464
  function submit() {
470
- helper.verifyArguments(arguments);
471
-
472
465
  // try to find the manifest of this project
473
- var manifestFilePath = helper.locateManifest();
466
+ var manifestFilePath = locateManifest();
474
467
  if (!manifestFilePath) return exit(NO_MANIFEST_FOUND_ERROR_STRING);
475
468
 
476
469
  var result = manifestFormat.parseFile(manifestFilePath);
@@ -482,8 +475,6 @@ function submit() {
482
475
  }
483
476
 
484
477
  function unpublish(options) {
485
- helper.verifyArguments(arguments);
486
-
487
478
  getAppstoreId(options.appstoreId, function (error, id, version) {
488
479
  if (error) exit(error);
489
480
 
@@ -499,8 +490,6 @@ function unpublish(options) {
499
490
  }
500
491
 
501
492
  function revoke(options) {
502
- helper.verifyArguments(arguments);
503
-
504
493
  getAppstoreId(options.appstoreId, function (error, id, version) {
505
494
  if (error) return exit(error);
506
495
 
@@ -525,8 +514,6 @@ function approve(options) {
525
514
 
526
515
  // TODO currently no pagination, only needed once we have users with more than 100 apps
527
516
  function listPublishedApps(options) {
528
- helper.verifyArguments(arguments);
529
-
530
517
  superagentEnd(function () {
531
518
  return superagent.get(createUrl('/api/v1/developers/apps?per_page=100'))
532
519
  .query({ accessToken: config.appStoreToken() })
@@ -1,7 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  exports = module.exports = {
4
- build: build
4
+ build
5
5
  };
6
6
 
7
7
  const assert = require('assert'),
@@ -292,8 +292,6 @@ function buildRemote(manifest, sourceDir, appConfig, options) {
292
292
  }
293
293
 
294
294
  function build(options) {
295
- helper.verifyArguments(arguments);
296
-
297
295
  // try to find the manifest of this project
298
296
  const manifestFilePath = helper.locateManifest();
299
297
  if (!manifestFilePath) return exit('No CloudronManifest.json found');
package/src/completion.js CHANGED
@@ -2,17 +2,17 @@
2
2
 
3
3
  'use strict';
4
4
 
5
- var helper = require('./helper.js'),
5
+ const helper = require('./helper.js'),
6
6
  util = require('util');
7
7
 
8
- exports = module.exports = function (options) {
8
+ exports = module.exports = function (options, cmd) {
9
9
  var completion = '';
10
10
 
11
- var commands = [];
12
- for (var command in options.parent.commands) {
13
- if (options.parent.commands[command]._name === '*' || options.parent.commands[command]._name === 'completion') continue;
14
- if (options.parent.commands[command]._name) commands.push(options.parent.commands[command]._name);
15
- if (options.parent.commands[command]._alias) commands.push(options.parent.commands[command]._alias);
11
+ const commands = [];
12
+ for (const command of cmd.parent.commands) {
13
+ if (command._name === '*' || command._name === 'completion') continue;
14
+ if (command._name) commands.push(command._name);
15
+ if (command._alias) commands.push(command._alias);
16
16
  }
17
17
  commands.sort();
18
18
 
package/src/helper.js CHANGED
@@ -10,7 +10,6 @@ exports = module.exports = {
10
10
  exit,
11
11
 
12
12
  locateManifest,
13
- verifyArguments
14
13
  };
15
14
 
16
15
  function exit(error) {
@@ -35,11 +34,3 @@ function locateManifest() {
35
34
 
36
35
  return null;
37
36
  }
38
-
39
- function verifyArguments(args) {
40
- if (args.length > 1) {
41
- console.log('Too many arguments');
42
- args[0].parent.help(); // extra args won't have parent() field
43
- process.exit(1);
44
- }
45
- }
@@ -1,4 +1,5 @@
1
1
  {
2
+ "id": "",
2
3
  "version": "<%- version %>",
3
4
  "upstreamVersion": "",
4
5
  "minBoxVersion": "7.1.0",
@@ -1,65 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- 'use strict';
4
-
5
- const program = require('commander'),
6
- actions = require('../src/actions.js'),
7
- backupTools = require('../src/backup-tools.js');
8
-
9
- program.version(require('../package.json').version);
10
-
11
- program.command('create')
12
- .description('Create new app backup')
13
- .option('--app <id>', 'App id')
14
- .action(actions.backupCreate);
15
-
16
- program.command('list')
17
- .description('List all backups for specified app')
18
- .option('--raw', 'Print raw json output')
19
- .option('--app <id>', 'App id')
20
- .action(actions.backupList);
21
-
22
- program.command('decrypt <file>')
23
- .description('Decrypt an encrypted file')
24
- .option('--password <password>', 'password')
25
- .action(backupTools.decrypt);
26
-
27
- program.command('decrypt-dir <indir> <outdir>')
28
- .description('Decrypt an encrypted directory')
29
- .option('--password <password>', 'password')
30
- .action(backupTools.decryptDir);
31
-
32
- program.command('decrypt-filename <path>')
33
- .description('Encrypt a file name')
34
- .option('--password <password>', 'password')
35
- .action(backupTools.decryptFilename);
36
-
37
- program.command('encrypt <input>')
38
- .description('Encrypt a file')
39
- .option('--password <password>', 'password')
40
- .action(backupTools.encrypt);
41
-
42
- program.command('encrypt-filename <path>')
43
- .description('Encrypt a file name')
44
- .option('--password <password>', 'password')
45
- .action(backupTools.encryptFilename);
46
-
47
- if (!process.argv.slice(2).length) {
48
- program.outputHelp();
49
- } else { // https://github.com/tj/commander.js/issues/338
50
- // deal first with global flags!
51
- program.parse(process.argv);
52
-
53
- if (process.argv[2] === 'help') {
54
- return program.outputHelp();
55
- }
56
-
57
- var knownCommand = program.commands.some(function (command) { return command._name === process.argv[2] || command._alias === process.argv[2]; });
58
- if (!knownCommand) {
59
- console.log('Unknown command: ' + process.argv[2] + '.\nTry ' + 'cloudron backup help');
60
- process.exit(1);
61
- }
62
- return;
63
- }
64
-
65
- program.parse(process.argv);
package/bin/cloudron-env DELETED
@@ -1,48 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- 'use strict';
4
-
5
- const program = require('commander'),
6
- actions = require('../src/actions.js');
7
-
8
- program.version(require('../package.json').version);
9
-
10
- program.command('get <name>')
11
- .description('Get environment variables')
12
- .option('--app <id>', 'App id')
13
- .action(actions.envGet);
14
-
15
- program.command('list')
16
- .description('List environment variables')
17
- .option('--app <id>', 'App id')
18
- .action(actions.envList);
19
-
20
- program.command('set <KEY=value...>')
21
- .description('Set environment variables')
22
- .option('--app <id>', 'App id')
23
- .action(actions.envSet);
24
-
25
- program.command('unset <KEY...>')
26
- .description('Unset environment variables')
27
- .option('--app <id>', 'App id')
28
- .action(actions.envUnset);
29
-
30
- if (!process.argv.slice(2).length) {
31
- program.outputHelp();
32
- } else { // https://github.com/tj/commander.js/issues/338
33
- // deal first with global flags!
34
- program.parse(process.argv);
35
-
36
- if (process.argv[2] === 'help') {
37
- return program.outputHelp();
38
- }
39
-
40
- var knownCommand = program.commands.some(function (command) { return command._name === process.argv[2] || command._alias === process.argv[2]; });
41
- if (!knownCommand) {
42
- console.log('Unknown command: ' + process.argv[2] + '.\nTry ' + 'cloudron env help');
43
- process.exit(1);
44
- }
45
- return;
46
- }
47
-
48
- program.parse(process.argv);