cloudron 4.15.3 → 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 +72 -14
- package/bin/cloudron-appstore +0 -18
- package/package.json +11 -11
- package/src/actions.js +134 -114
- package/src/appstore-actions.js +21 -34
- package/src/build-actions.js +1 -3
- package/src/completion.js +7 -7
- package/src/helper.js +0 -9
- package/src/templates/CloudronManifest.appstore.json.ejs +25 -0
- package/src/templates/Dockerfile.ejs +7 -1
- package/src/templates/start.sh.ejs +3 -0
- package/bin/cloudron-backup +0 -65
- package/bin/cloudron-env +0 -48
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
|
-
|
|
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
|
|
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
|
-
|
|
29
|
-
|
|
30
|
-
|
|
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'
|
|
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'
|
|
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')
|
|
@@ -122,6 +186,7 @@ program.command('inspect')
|
|
|
122
186
|
|
|
123
187
|
program.command('init')
|
|
124
188
|
.description('Creates a new CloudronManifest.json and Dockerfile')
|
|
189
|
+
.option('--appstore', 'Appstore template')
|
|
125
190
|
.action(actions.init);
|
|
126
191
|
|
|
127
192
|
program.command('install')
|
|
@@ -254,11 +319,4 @@ program.command('update')
|
|
|
254
319
|
}
|
|
255
320
|
|
|
256
321
|
program.parse(process.argv);
|
|
257
|
-
|
|
258
|
-
const knownCommand = program.commands.some(function (command) { return command._name === process.argv[2] || command._alias === process.argv[2]; });
|
|
259
|
-
if (!knownCommand) {
|
|
260
|
-
console.log('Unknown command: ' + process.argv[2] + '.\nTry ' + 'cloudron help');
|
|
261
|
-
process.exit(1);
|
|
262
|
-
}
|
|
263
322
|
})();
|
|
264
|
-
|
package/bin/cloudron-appstore
CHANGED
|
@@ -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": "
|
|
3
|
+
"version": "5.1.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"description": "Cloudron Commandline Tool",
|
|
6
6
|
"main": "main.js",
|
|
@@ -17,15 +17,15 @@
|
|
|
17
17
|
},
|
|
18
18
|
"author": "Cloudron Developers <support@cloudron.io>",
|
|
19
19
|
"dependencies": {
|
|
20
|
-
"async": "^3.2.
|
|
21
|
-
"cloudron-manifestformat": "^5.
|
|
22
|
-
"commander": "^
|
|
23
|
-
"debug": "^4.3.
|
|
20
|
+
"async": "^3.2.4",
|
|
21
|
+
"cloudron-manifestformat": "^5.17.0",
|
|
22
|
+
"commander": "^9.4.0",
|
|
23
|
+
"debug": "^4.3.4",
|
|
24
24
|
"delay": "^5.0.0",
|
|
25
25
|
"easy-table": "^1.2.0",
|
|
26
|
-
"ejs": "^3.1.
|
|
27
|
-
"eventsource": "^
|
|
28
|
-
"micromatch": "^4.0.
|
|
26
|
+
"ejs": "^3.1.8",
|
|
27
|
+
"eventsource": "^2.0.2",
|
|
28
|
+
"micromatch": "^4.0.5",
|
|
29
29
|
"once": "^1.4.0",
|
|
30
30
|
"open": "^8.4.0",
|
|
31
31
|
"progress": "^2.0.3",
|
|
@@ -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": "^
|
|
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.
|
|
38
|
+
"underscore": "^1.13.4"
|
|
39
39
|
},
|
|
40
40
|
"engines": {
|
|
41
41
|
"node": ">= 14.x.x"
|
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
"devDependencies": {
|
|
44
44
|
"expect.js": "^0.3.1",
|
|
45
45
|
"memorystream": "^0.3.1",
|
|
46
|
-
"mocha": "^
|
|
46
|
+
"mocha": "^10.0.0",
|
|
47
47
|
"rimraf": "^3.0.2"
|
|
48
48
|
}
|
|
49
49
|
}
|
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'),
|
|
@@ -14,7 +14,6 @@ const assert = require('assert'),
|
|
|
14
14
|
path = require('path'),
|
|
15
15
|
ProgressBar = require('progress'),
|
|
16
16
|
ProgressStream = require('progress-stream'),
|
|
17
|
-
querystring = require('querystring'),
|
|
18
17
|
readlineSync = require('readline-sync'),
|
|
19
18
|
safe = require('safetydance'),
|
|
20
19
|
spawn = require('child_process').spawn,
|
|
@@ -25,8 +24,6 @@ const assert = require('assert'),
|
|
|
25
24
|
zlib = require('zlib'),
|
|
26
25
|
_ = require('underscore');
|
|
27
26
|
|
|
28
|
-
const exit = helper.exit;
|
|
29
|
-
|
|
30
27
|
exports = module.exports = {
|
|
31
28
|
list,
|
|
32
29
|
login,
|
|
@@ -66,13 +63,13 @@ const NO_APP_FOUND_ERROR_STRING = 'Could not determine app. Use --app to specify
|
|
|
66
63
|
|
|
67
64
|
// options for the request module
|
|
68
65
|
function requestOptions(options) {
|
|
69
|
-
const adminFqdn = options.
|
|
66
|
+
const adminFqdn = options.server || config.apiEndpoint();
|
|
70
67
|
|
|
71
68
|
// ensure config can return the correct section
|
|
72
69
|
config.setActive(adminFqdn);
|
|
73
70
|
|
|
74
|
-
const token = options.
|
|
75
|
-
const rejectUnauthorized = !(options.
|
|
71
|
+
const token = options.token || config.token();
|
|
72
|
+
const rejectUnauthorized = !(options.allowSelfsigned || options.acceptSelfsigned || config.allowSelfsigned());
|
|
76
73
|
|
|
77
74
|
if (!adminFqdn && !token) return exit('Login with "cloudron login" first'); // a bit rough to put this here!
|
|
78
75
|
|
|
@@ -180,7 +177,7 @@ async function getApp(options) {
|
|
|
180
177
|
const app = options.app || null;
|
|
181
178
|
|
|
182
179
|
if (!app) { // determine based on repository name given during 'build'
|
|
183
|
-
const manifestFilePath =
|
|
180
|
+
const manifestFilePath = locateManifest();
|
|
184
181
|
|
|
185
182
|
if (!manifestFilePath) throw new Error(NO_APP_FOUND_ERROR_STRING);
|
|
186
183
|
|
|
@@ -369,7 +366,7 @@ async function authenticate(adminFqdn, username, password, options) {
|
|
|
369
366
|
return response.body.accessToken;
|
|
370
367
|
}
|
|
371
368
|
|
|
372
|
-
async function login(adminFqdn,
|
|
369
|
+
async function login(adminFqdn, localOptions, cmd) {
|
|
373
370
|
if (!adminFqdn) adminFqdn = readlineSync.question('Cloudron Domain (e.g. my.example.com): ', {});
|
|
374
371
|
if (!adminFqdn) return exit('');
|
|
375
372
|
|
|
@@ -378,7 +375,9 @@ async function login(adminFqdn, options) {
|
|
|
378
375
|
|
|
379
376
|
config.setActive(adminFqdn);
|
|
380
377
|
|
|
381
|
-
const
|
|
378
|
+
const options = cmd.optsWithGlobals();
|
|
379
|
+
|
|
380
|
+
const rejectUnauthorized = !(options.allowSelfsigned || options.acceptSelfsigned);
|
|
382
381
|
let token = config.token();
|
|
383
382
|
if (token) { // check if the token is not expired
|
|
384
383
|
const request = superagent.get(`https://${adminFqdn}/api/v1/profile?access_token=${token}`)
|
|
@@ -408,7 +407,7 @@ async function login(adminFqdn, options) {
|
|
|
408
407
|
config.setActive(adminFqdn);
|
|
409
408
|
config.setApiEndpoint(adminFqdn);
|
|
410
409
|
config.setToken(token);
|
|
411
|
-
config.setAllowSelfsigned(
|
|
410
|
+
config.setAllowSelfsigned(cmd.optsWithGlobals().allowSelfsigned || cmd.optsWithGlobals().acceptSelfsigned);
|
|
412
411
|
config.set('cloudrons.default', adminFqdn);
|
|
413
412
|
|
|
414
413
|
console.log('Login successful.');
|
|
@@ -421,7 +420,8 @@ function logout() {
|
|
|
421
420
|
console.log('Logged out.');
|
|
422
421
|
}
|
|
423
422
|
|
|
424
|
-
async function open(
|
|
423
|
+
async function open(localOptions, cmd) {
|
|
424
|
+
const options = cmd.optsWithGlobals();
|
|
425
425
|
const [error, app] = await safe(getApp(options));
|
|
426
426
|
if (error) return exit(error);
|
|
427
427
|
|
|
@@ -430,9 +430,8 @@ async function open(options) {
|
|
|
430
430
|
opn(`https://${app.fqdn}`);
|
|
431
431
|
}
|
|
432
432
|
|
|
433
|
-
async function list(
|
|
434
|
-
|
|
435
|
-
|
|
433
|
+
async function list(localOptions, cmd) {
|
|
434
|
+
const options = cmd.optsWithGlobals();
|
|
436
435
|
const [error, response] = await safe(createRequest('GET', '/api/v1/apps', options));
|
|
437
436
|
if (error) return exit(error);
|
|
438
437
|
if (response.statusCode !== 200) return exit(`Failed to list apps: ${requestError(response)}`);
|
|
@@ -533,7 +532,7 @@ async function getManifest(appstoreId) {
|
|
|
533
532
|
|
|
534
533
|
if (appstoreId) return await downloadManifest(appstoreId);
|
|
535
534
|
|
|
536
|
-
const manifestFilePath =
|
|
535
|
+
const manifestFilePath = locateManifest();
|
|
537
536
|
if (!manifestFilePath) throw new Error('No CloudronManifest.json found');
|
|
538
537
|
|
|
539
538
|
const result = manifestFormat.parseFile(manifestFilePath);
|
|
@@ -551,8 +550,8 @@ async function getManifest(appstoreId) {
|
|
|
551
550
|
return { manifest: result.manifest, manifestFilePath };
|
|
552
551
|
}
|
|
553
552
|
|
|
554
|
-
async function install(
|
|
555
|
-
|
|
553
|
+
async function install(localOptions, cmd) {
|
|
554
|
+
const options = cmd.optsWithGlobals();
|
|
556
555
|
|
|
557
556
|
try {
|
|
558
557
|
const result = await getManifest(options.appstoreId || '');
|
|
@@ -661,8 +660,8 @@ async function install(options) {
|
|
|
661
660
|
}
|
|
662
661
|
}
|
|
663
662
|
|
|
664
|
-
async function configure(
|
|
665
|
-
|
|
663
|
+
async function configure(localOptions, cmd) {
|
|
664
|
+
const options = cmd.optsWithGlobals();
|
|
666
665
|
|
|
667
666
|
try {
|
|
668
667
|
const app = await getApp(options);
|
|
@@ -741,8 +740,8 @@ async function configure(options) {
|
|
|
741
740
|
}
|
|
742
741
|
}
|
|
743
742
|
|
|
744
|
-
async function update(
|
|
745
|
-
|
|
743
|
+
async function update(localOptions, cmd) {
|
|
744
|
+
const options = cmd.optsWithGlobals();
|
|
746
745
|
|
|
747
746
|
try {
|
|
748
747
|
const app = await getApp(options);
|
|
@@ -798,15 +797,16 @@ async function update(options) {
|
|
|
798
797
|
}
|
|
799
798
|
}
|
|
800
799
|
|
|
801
|
-
async function debug(
|
|
800
|
+
async function debug(args, localOptions, cmd) {
|
|
802
801
|
try {
|
|
802
|
+
const options = cmd.optsWithGlobals();
|
|
803
803
|
const app = await getApp(options);
|
|
804
804
|
if (!app) return exit(NO_APP_FOUND_ERROR_STRING);
|
|
805
805
|
|
|
806
806
|
const data = {
|
|
807
807
|
debugMode: options.disable ? null : {
|
|
808
808
|
readonlyRootfs: options.readonly ? true : false,
|
|
809
|
-
cmd: parseDebugCommand(
|
|
809
|
+
cmd: parseDebugCommand(args.join(' ').trim())
|
|
810
810
|
}
|
|
811
811
|
};
|
|
812
812
|
|
|
@@ -835,8 +835,9 @@ async function debug(cmd, options) {
|
|
|
835
835
|
}
|
|
836
836
|
}
|
|
837
837
|
|
|
838
|
-
async function repair(
|
|
838
|
+
async function repair(localOptions, cmd) {
|
|
839
839
|
try {
|
|
840
|
+
const options = cmd.optsWithGlobals();
|
|
840
841
|
const app = await getApp(options);
|
|
841
842
|
if (!app) return exit(NO_APP_FOUND_ERROR_STRING);
|
|
842
843
|
|
|
@@ -863,10 +864,9 @@ async function repair(options) {
|
|
|
863
864
|
}
|
|
864
865
|
}
|
|
865
866
|
|
|
866
|
-
async function cancel(
|
|
867
|
-
helper.verifyArguments(arguments);
|
|
868
|
-
|
|
867
|
+
async function cancel(localOptions, cmd) {
|
|
869
868
|
try {
|
|
869
|
+
const options = cmd.optsWithGlobals();
|
|
870
870
|
const app = await getApp(options);
|
|
871
871
|
if (!app) return exit(NO_APP_FOUND_ERROR_STRING);
|
|
872
872
|
if (!app.taskId) return exit('No active task.');
|
|
@@ -877,10 +877,9 @@ async function cancel(options) {
|
|
|
877
877
|
}
|
|
878
878
|
}
|
|
879
879
|
|
|
880
|
-
async function uninstall(
|
|
881
|
-
helper.verifyArguments(arguments);
|
|
882
|
-
|
|
880
|
+
async function uninstall(localOptions, cmd) {
|
|
883
881
|
try {
|
|
882
|
+
const options = cmd.optsWithGlobals();
|
|
884
883
|
const app = await getApp(options);
|
|
885
884
|
if (!app) return exit(NO_APP_FOUND_ERROR_STRING);
|
|
886
885
|
|
|
@@ -919,9 +918,8 @@ function logPrinter(obj) {
|
|
|
919
918
|
console.log('%s - %s', ts, message);
|
|
920
919
|
}
|
|
921
920
|
|
|
922
|
-
async function logs(
|
|
923
|
-
|
|
924
|
-
|
|
921
|
+
async function logs(localOptions, cmd) {
|
|
922
|
+
const options = cmd.optsWithGlobals();
|
|
925
923
|
const { adminFqdn, token, rejectUnauthorized } = requestOptions(options);
|
|
926
924
|
const lines = options.lines || 500;
|
|
927
925
|
const tail = !!options.tail;
|
|
@@ -969,9 +967,8 @@ async function logs(options) {
|
|
|
969
967
|
}
|
|
970
968
|
}
|
|
971
969
|
|
|
972
|
-
async function status(
|
|
973
|
-
|
|
974
|
-
|
|
970
|
+
async function status(localOptions, cmd) {
|
|
971
|
+
const options = cmd.optsWithGlobals();
|
|
975
972
|
const [error, app] = await safe(getApp(options));
|
|
976
973
|
if (error) return exit(error);
|
|
977
974
|
if (!app) return exit(NO_APP_FOUND_ERROR_STRING);
|
|
@@ -987,10 +984,9 @@ async function status(options) {
|
|
|
987
984
|
console.log();
|
|
988
985
|
}
|
|
989
986
|
|
|
990
|
-
async function inspect(
|
|
991
|
-
helper.verifyArguments(arguments);
|
|
992
|
-
|
|
987
|
+
async function inspect(localOptions, cmd) {
|
|
993
988
|
try {
|
|
989
|
+
const options = cmd.optsWithGlobals();
|
|
994
990
|
const response = await createRequest('GET', '/api/v1/apps', options);
|
|
995
991
|
if (response.statusCode !== 200) return exit(`Failed to list apps: ${requestError(response)}`);
|
|
996
992
|
|
|
@@ -1003,7 +999,7 @@ async function inspect(options) {
|
|
|
1003
999
|
apps.push(response2.body);
|
|
1004
1000
|
}
|
|
1005
1001
|
|
|
1006
|
-
const { adminFqdn } = requestOptions(
|
|
1002
|
+
const { adminFqdn } = requestOptions(cmd.optsWithGlobals());
|
|
1007
1003
|
console.log(JSON.stringify({
|
|
1008
1004
|
apiEndpoint: adminFqdn,
|
|
1009
1005
|
appStoreOrigin: config.appStoreOrigin(),
|
|
@@ -1014,10 +1010,9 @@ async function inspect(options) {
|
|
|
1014
1010
|
}
|
|
1015
1011
|
}
|
|
1016
1012
|
|
|
1017
|
-
async function restart(
|
|
1018
|
-
helper.verifyArguments(arguments);
|
|
1019
|
-
|
|
1013
|
+
async function restart(localOptions, cmd) {
|
|
1020
1014
|
try {
|
|
1015
|
+
const options = cmd.optsWithGlobals();
|
|
1021
1016
|
const app = await getApp(options);
|
|
1022
1017
|
if (!app) return exit(NO_APP_FOUND_ERROR_STRING);
|
|
1023
1018
|
await restartApp(app, options);
|
|
@@ -1028,10 +1023,9 @@ async function restart(options) {
|
|
|
1028
1023
|
}
|
|
1029
1024
|
}
|
|
1030
1025
|
|
|
1031
|
-
async function start(
|
|
1032
|
-
helper.verifyArguments(arguments);
|
|
1033
|
-
|
|
1026
|
+
async function start(localOptions, cmd) {
|
|
1034
1027
|
try {
|
|
1028
|
+
const options = cmd.optsWithGlobals();
|
|
1035
1029
|
const app = await getApp(options);
|
|
1036
1030
|
if (!app) return exit(NO_APP_FOUND_ERROR_STRING);
|
|
1037
1031
|
await startApp(app, options);
|
|
@@ -1042,10 +1036,9 @@ async function start(options) {
|
|
|
1042
1036
|
}
|
|
1043
1037
|
}
|
|
1044
1038
|
|
|
1045
|
-
async function stop(
|
|
1046
|
-
helper.verifyArguments(arguments);
|
|
1047
|
-
|
|
1039
|
+
async function stop(localOptions, cmd) {
|
|
1048
1040
|
try {
|
|
1041
|
+
const options = cmd.optsWithGlobals();
|
|
1049
1042
|
const app = await getApp(options);
|
|
1050
1043
|
if (!app) return exit(NO_APP_FOUND_ERROR_STRING);
|
|
1051
1044
|
await stopApp(app, options);
|
|
@@ -1055,10 +1048,9 @@ async function stop(options) {
|
|
|
1055
1048
|
}
|
|
1056
1049
|
}
|
|
1057
1050
|
|
|
1058
|
-
async function backupCreate(
|
|
1059
|
-
helper.verifyArguments(arguments);
|
|
1060
|
-
|
|
1051
|
+
async function backupCreate(localOptions, cmd) {
|
|
1061
1052
|
try {
|
|
1053
|
+
const options = cmd.optsWithGlobals();
|
|
1062
1054
|
const app = await getApp(options);
|
|
1063
1055
|
if (!app) return exit(NO_APP_FOUND_ERROR_STRING);
|
|
1064
1056
|
|
|
@@ -1073,10 +1065,9 @@ async function backupCreate(options) {
|
|
|
1073
1065
|
}
|
|
1074
1066
|
}
|
|
1075
1067
|
|
|
1076
|
-
async function backupList(
|
|
1077
|
-
helper.verifyArguments(arguments);
|
|
1078
|
-
|
|
1068
|
+
async function backupList(localOptions, cmd) {
|
|
1079
1069
|
try {
|
|
1070
|
+
const options = cmd.optsWithGlobals();
|
|
1080
1071
|
const app = await getApp(options);
|
|
1081
1072
|
if (!app) return exit(NO_APP_FOUND_ERROR_STRING);
|
|
1082
1073
|
|
|
@@ -1122,10 +1113,9 @@ async function getLastBackup(app, options) {
|
|
|
1122
1113
|
return response.body.backups[0].id;
|
|
1123
1114
|
}
|
|
1124
1115
|
|
|
1125
|
-
async function restore(
|
|
1126
|
-
helper.verifyArguments(arguments);
|
|
1127
|
-
|
|
1116
|
+
async function restore(localOptions, cmd) {
|
|
1128
1117
|
try {
|
|
1118
|
+
const options = cmd.optsWithGlobals();
|
|
1129
1119
|
const app = await getApp(options);
|
|
1130
1120
|
if (!app) return exit(NO_APP_FOUND_ERROR_STRING);
|
|
1131
1121
|
|
|
@@ -1150,10 +1140,9 @@ async function restore(options) {
|
|
|
1150
1140
|
}
|
|
1151
1141
|
}
|
|
1152
1142
|
|
|
1153
|
-
async function importApp(
|
|
1154
|
-
helper.verifyArguments(arguments);
|
|
1155
|
-
|
|
1143
|
+
async function importApp(localOptions, cmd) {
|
|
1156
1144
|
try {
|
|
1145
|
+
const options = cmd.optsWithGlobals();
|
|
1157
1146
|
const app = await getApp(options);
|
|
1158
1147
|
if (!app) return exit(NO_APP_FOUND_ERROR_STRING);
|
|
1159
1148
|
|
|
@@ -1206,10 +1195,9 @@ async function importApp(options) {
|
|
|
1206
1195
|
}
|
|
1207
1196
|
}
|
|
1208
1197
|
|
|
1209
|
-
async function exportApp(
|
|
1210
|
-
helper.verifyArguments(arguments);
|
|
1211
|
-
|
|
1198
|
+
async function exportApp(localOptions, cmd) {
|
|
1212
1199
|
try {
|
|
1200
|
+
const options = cmd.optsWithGlobals();
|
|
1213
1201
|
const app = await getApp(options);
|
|
1214
1202
|
if (!app) return exit(NO_APP_FOUND_ERROR_STRING);
|
|
1215
1203
|
|
|
@@ -1228,10 +1216,9 @@ async function exportApp(options) {
|
|
|
1228
1216
|
}
|
|
1229
1217
|
}
|
|
1230
1218
|
|
|
1231
|
-
async function clone(
|
|
1232
|
-
helper.verifyArguments(arguments);
|
|
1233
|
-
|
|
1219
|
+
async function clone(localOptions, cmd) {
|
|
1234
1220
|
try {
|
|
1221
|
+
const options = cmd.optsWithGlobals();
|
|
1235
1222
|
const app = await getApp(options);
|
|
1236
1223
|
if (!app) return exit(NO_APP_FOUND_ERROR_STRING);
|
|
1237
1224
|
|
|
@@ -1290,11 +1277,12 @@ function demuxStream(stream, stdout, stderr) {
|
|
|
1290
1277
|
// echo "sauce" | cloudron exec -- bash -c "cat - > /app/data/sauce" - test with binary files. should disable tty
|
|
1291
1278
|
// cat ~/tmp/fantome.tar.gz | cloudron exec -- bash -c "tar xvf - -C /tmp" - must show an error
|
|
1292
1279
|
// cat ~/tmp/fantome.tar.gz | cloudron exec -- bash -c "tar zxf - -C /tmp" - must extrack ok
|
|
1293
|
-
async function exec(
|
|
1294
|
-
let stdin =
|
|
1295
|
-
let 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
|
|
1296
1283
|
|
|
1297
|
-
|
|
1284
|
+
const options = cmd.optsWithGlobals();
|
|
1285
|
+
let tty = !!options.tty;
|
|
1298
1286
|
|
|
1299
1287
|
const [error, app] = await safe(getApp(options));
|
|
1300
1288
|
if (error) return exit(error);
|
|
@@ -1302,26 +1290,37 @@ async function exec(cmd, options) {
|
|
|
1302
1290
|
|
|
1303
1291
|
if (app.installationState !== 'installed') exit('App is not yet running. Try again later.');
|
|
1304
1292
|
|
|
1305
|
-
if (
|
|
1306
|
-
|
|
1293
|
+
if (args.length === 0) {
|
|
1294
|
+
args = [ '/bin/bash' ];
|
|
1307
1295
|
tty = true; // override
|
|
1308
1296
|
}
|
|
1309
1297
|
|
|
1310
1298
|
if (tty && !stdin.isTTY) exit('stdin is not tty');
|
|
1311
1299
|
|
|
1312
|
-
const
|
|
1300
|
+
const request = createRequest('POST', `/api/v1/apps/${app.id}/exec`, options);
|
|
1301
|
+
const response = await request.send({ cmd: args, tty });
|
|
1302
|
+
if (response.statusCode !== 200) return exit(`Failed to create exec: ${requestError(response)}`);
|
|
1303
|
+
const execId = response.body.id;
|
|
1304
|
+
|
|
1305
|
+
async function exitWithCode() {
|
|
1306
|
+
const response2 = await createRequest('GET', `/api/v1/apps/${app.id}/exec/${execId}`, options);
|
|
1307
|
+
if (response2.statusCode !== 200) return exit(`Failed to get exec code: ${requestError(response2)}`);
|
|
1308
|
+
|
|
1309
|
+
process.exit(response2.body.exitCode);
|
|
1310
|
+
}
|
|
1311
|
+
|
|
1312
|
+
const { adminFqdn, token, rejectUnauthorized } = requestOptions(cmd.optsWithGlobals());
|
|
1313
1313
|
|
|
1314
|
-
const
|
|
1315
|
-
rows: stdout.rows,
|
|
1316
|
-
columns: stdout.columns,
|
|
1314
|
+
const searchParams = new URLSearchParams({
|
|
1315
|
+
rows: stdout.rows || 24,
|
|
1316
|
+
columns: stdout.columns || 80,
|
|
1317
1317
|
access_token: token,
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
};
|
|
1318
|
+
tty
|
|
1319
|
+
});
|
|
1321
1320
|
|
|
1322
1321
|
const req = https.request({
|
|
1323
1322
|
hostname: adminFqdn,
|
|
1324
|
-
path: `/api/v1/apps/${app.id}/exec
|
|
1323
|
+
path: `/api/v1/apps/${app.id}/exec/${execId}/start?${searchParams.toString()}`,
|
|
1325
1324
|
method: 'GET',
|
|
1326
1325
|
headers: {
|
|
1327
1326
|
'Connection': 'Upgrade',
|
|
@@ -1345,8 +1344,8 @@ async function exec(cmd, options) {
|
|
|
1345
1344
|
stdin.setRawMode(true);
|
|
1346
1345
|
stdin.pipe(socket, { end: false }); // the remote will close the connection
|
|
1347
1346
|
socket.pipe(stdout); // in tty mode, stdout/stderr is merged
|
|
1348
|
-
socket.on('end',
|
|
1349
|
-
} else {// create stdin process on demand
|
|
1347
|
+
socket.on('end', exitWithCode); // server closed the socket
|
|
1348
|
+
} else { // create stdin process on demand
|
|
1350
1349
|
if (typeof stdin === 'function') stdin = stdin();
|
|
1351
1350
|
|
|
1352
1351
|
stdin.on('data', function (d) {
|
|
@@ -1361,7 +1360,7 @@ async function exec(cmd, options) {
|
|
|
1361
1360
|
socket.write(buf);
|
|
1362
1361
|
});
|
|
1363
1362
|
|
|
1364
|
-
stdout.on('close',
|
|
1363
|
+
stdout.on('close', exitWithCode); // this is only emitted when stdout is a file and not the terminal
|
|
1365
1364
|
|
|
1366
1365
|
demuxStream(socket, stdout, process.stderr); // can get separate streams in non-tty mode
|
|
1367
1366
|
socket.on('end', function () { // server closed the socket
|
|
@@ -1371,7 +1370,7 @@ async function exec(cmd, options) {
|
|
|
1371
1370
|
socket.end();
|
|
1372
1371
|
|
|
1373
1372
|
// process._getActiveHandles(); process._getActiveRequests();
|
|
1374
|
-
if (stdout === process.stdout) setImmediate(
|
|
1373
|
+
if (stdout === process.stdout) setImmediate(exitWithCode); // otherwise, we rely on the 'close' event above
|
|
1375
1374
|
});
|
|
1376
1375
|
}
|
|
1377
1376
|
});
|
|
@@ -1380,30 +1379,30 @@ async function exec(cmd, options) {
|
|
|
1380
1379
|
req.end(); // this makes the request
|
|
1381
1380
|
}
|
|
1382
1381
|
|
|
1383
|
-
function push(localDir, remote,
|
|
1382
|
+
function push(localDir, remote, localOptions, cmd) {
|
|
1384
1383
|
// deal with paths prefixed with ~
|
|
1385
|
-
|
|
1386
|
-
|
|
1384
|
+
const local = localDir.replace(/^~(?=$|\/|\\)/, os.homedir());
|
|
1385
|
+
const stat = fs.existsSync(path.resolve(local)) ? fs.lstatSync(local) : null;
|
|
1387
1386
|
|
|
1388
1387
|
if (stat && stat.isDirectory()) {
|
|
1389
1388
|
// Create a functor for stdin. If no data event handlers are attached, and there are no stream.pipe() destinations, and the stream is
|
|
1390
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.
|
|
1391
|
-
|
|
1390
|
+
localOptions._stdin = function () {
|
|
1392
1391
|
var tarzip = spawn('tar', ['zcf', '-', '-C', path.dirname(local), path.basename(local)], { stdio: 'pipe' });
|
|
1393
1392
|
return tarzip.stdout;
|
|
1394
1393
|
};
|
|
1395
1394
|
|
|
1396
|
-
exec(['tar', 'zxvf', '-', '-C', remote],
|
|
1395
|
+
exec(['tar', 'zxvf', '-', '-C', remote], localOptions, cmd);
|
|
1397
1396
|
} else {
|
|
1398
1397
|
if (local === '-') {
|
|
1399
|
-
|
|
1398
|
+
localOptions._stdin = process.stdin;
|
|
1400
1399
|
} else if (stat) {
|
|
1401
|
-
|
|
1400
|
+
const progress = new ProgressStream({ length: stat.size, time: 1000 });
|
|
1402
1401
|
|
|
1403
|
-
|
|
1402
|
+
localOptions._stdin = progress;
|
|
1404
1403
|
fs.createReadStream(local).pipe(progress);
|
|
1405
1404
|
|
|
1406
|
-
|
|
1405
|
+
const bar = new ProgressBar('Uploading [:bar] :percent: :etas', {
|
|
1407
1406
|
complete: '=',
|
|
1408
1407
|
incomplete: ' ',
|
|
1409
1408
|
width: 100,
|
|
@@ -1415,48 +1414,52 @@ function push(localDir, remote, options) {
|
|
|
1415
1414
|
exit('local file ' + local + ' does not exist');
|
|
1416
1415
|
}
|
|
1417
1416
|
|
|
1418
|
-
|
|
1417
|
+
localOptions._stdin.on('error', function (error) { exit('Error pushing', error); });
|
|
1419
1418
|
|
|
1420
1419
|
if (remote.endsWith('/')) { // dir
|
|
1421
1420
|
remote = remote + '/' + path.basename(local); // do not use path.join as we want this to be a UNIX path
|
|
1422
1421
|
}
|
|
1423
1422
|
|
|
1424
|
-
exec(['bash', '-c', `cat - > "${remote}"`],
|
|
1423
|
+
exec(['bash', '-c', `cat - > "${remote}"`], localOptions, cmd);
|
|
1425
1424
|
}
|
|
1426
1425
|
}
|
|
1427
1426
|
|
|
1428
|
-
function pull(remote, local,
|
|
1427
|
+
function pull(remote, local, localOptions, cmd) {
|
|
1429
1428
|
if (remote.endsWith('/')) { // dir
|
|
1430
1429
|
var untar = tar.extract(local); // local directory is created if it doesn't exist!
|
|
1431
1430
|
var unzip = zlib.createGunzip();
|
|
1432
1431
|
|
|
1433
1432
|
unzip.pipe(untar);
|
|
1434
|
-
|
|
1433
|
+
localOptions._stdout = unzip;
|
|
1435
1434
|
|
|
1436
|
-
exec(['tar', 'zcf', '-', '-C', remote, '.'],
|
|
1435
|
+
exec(['tar', 'zcf', '-', '-C', remote, '.'], localOptions, cmd);
|
|
1437
1436
|
} else {
|
|
1438
1437
|
if (fs.existsSync(local) && fs.lstatSync(local).isDirectory()) {
|
|
1439
1438
|
local = path.join(local, path.basename(remote));
|
|
1440
|
-
|
|
1439
|
+
localOptions._stdout = fs.createWriteStream(local);
|
|
1441
1440
|
} else if (local === '-') {
|
|
1442
|
-
|
|
1441
|
+
localOptions._stdout = process.stdout;
|
|
1443
1442
|
} else {
|
|
1444
|
-
|
|
1443
|
+
localOptions._stdout = fs.createWriteStream(local);
|
|
1445
1444
|
}
|
|
1446
1445
|
|
|
1447
|
-
|
|
1446
|
+
localOptions._stdout.on('error', function (error) { exit('Error pulling', error); });
|
|
1448
1447
|
|
|
1449
|
-
exec(['cat', remote],
|
|
1448
|
+
exec(['cat', remote], localOptions, cmd);
|
|
1450
1449
|
}
|
|
1451
1450
|
}
|
|
1452
1451
|
|
|
1453
|
-
function init() {
|
|
1454
|
-
const
|
|
1452
|
+
function init(localOptions, cmd) {
|
|
1453
|
+
const options = cmd.optsWithGlobals();
|
|
1454
|
+
const manifestFilePath = locateManifest();
|
|
1455
1455
|
if (manifestFilePath && path.dirname(manifestFilePath) === process.cwd()) return exit('CloudronManifest.json already exists in current directory');
|
|
1456
1456
|
|
|
1457
|
-
const
|
|
1457
|
+
const manifestTemplateFilename = options.appstore ? 'CloudronManifest.appstore.json.ejs' : 'CloudronManifest.json.ejs';
|
|
1458
|
+
|
|
1459
|
+
const manifestTemplate = fs.readFileSync(path.join(__dirname, 'templates/', manifestTemplateFilename), 'utf8');
|
|
1458
1460
|
const dockerfileTemplate = fs.readFileSync(path.join(__dirname, 'templates/', 'Dockerfile.ejs'), 'utf8');
|
|
1459
1461
|
const dockerignoreTemplate = fs.readFileSync(path.join(__dirname, 'templates/', 'dockerignore.ejs'), 'utf8');
|
|
1462
|
+
const startShTemplate = fs.readFileSync(path.join(__dirname, 'templates/', 'start.sh.ejs'), 'utf8');
|
|
1460
1463
|
|
|
1461
1464
|
const data = {
|
|
1462
1465
|
version: '0.1.0',
|
|
@@ -1481,6 +1484,21 @@ function init() {
|
|
|
1481
1484
|
fs.writeFileSync('.dockerignore', dockerignore, 'utf8');
|
|
1482
1485
|
}
|
|
1483
1486
|
|
|
1487
|
+
if (fs.existsSync('start.sh')) {
|
|
1488
|
+
console.log('start.sh already exists, skipping');
|
|
1489
|
+
} else {
|
|
1490
|
+
const dockerignore = ejs.render(startShTemplate, {});
|
|
1491
|
+
fs.writeFileSync('start.sh', dockerignore, 'utf8');
|
|
1492
|
+
fs.chmodSync('start.sh', 0o0775);
|
|
1493
|
+
}
|
|
1494
|
+
|
|
1495
|
+
if (options.appstore) {
|
|
1496
|
+
if (!fs.existsSync('.gitignore')) fs.writeFileSync('.gitignore', 'node_modules/\n', 'utf8');
|
|
1497
|
+
if (!fs.existsSync('DESCRIPTION.md')) fs.writeFileSync('DESCRIPTION.md', '## About\n\nThis app changes everything\n\n', 'utf8');
|
|
1498
|
+
if (!fs.existsSync('POSTINSTALL.md')) fs.writeFileSync('POSTINSTALL.md', 'Post installation information\n\n', 'utf8');
|
|
1499
|
+
if (!fs.existsSync('CHANGELOG')) fs.writeFileSync('CHANGELOG', '[0.1.0]\n* Initial version\n\n', 'utf8');
|
|
1500
|
+
}
|
|
1501
|
+
|
|
1484
1502
|
console.log();
|
|
1485
1503
|
console.log('Now edit the CloudronManifest.json');
|
|
1486
1504
|
console.log();
|
|
@@ -1499,8 +1517,9 @@ async function setEnv(app, env, options) {
|
|
|
1499
1517
|
console.log('\n');
|
|
1500
1518
|
}
|
|
1501
1519
|
|
|
1502
|
-
async function envSet(envVars,
|
|
1520
|
+
async function envSet(envVars, localOptions, cmd) {
|
|
1503
1521
|
try {
|
|
1522
|
+
const options = cmd.optsWithGlobals();
|
|
1504
1523
|
const app = await getApp(options);
|
|
1505
1524
|
if (!app) return exit(NO_APP_FOUND_ERROR_STRING);
|
|
1506
1525
|
|
|
@@ -1520,8 +1539,9 @@ async function envSet(envVars, options) {
|
|
|
1520
1539
|
}
|
|
1521
1540
|
}
|
|
1522
1541
|
|
|
1523
|
-
async function envUnset(envNames,
|
|
1542
|
+
async function envUnset(envNames, localOptions, cmd) {
|
|
1524
1543
|
try {
|
|
1544
|
+
const options = cmd.optsWithGlobals();
|
|
1525
1545
|
const app = await getApp(options);
|
|
1526
1546
|
if (!app) return exit(NO_APP_FOUND_ERROR_STRING);
|
|
1527
1547
|
|
|
@@ -1537,10 +1557,9 @@ async function envUnset(envNames, options) {
|
|
|
1537
1557
|
}
|
|
1538
1558
|
}
|
|
1539
1559
|
|
|
1540
|
-
async function envList(
|
|
1541
|
-
helper.verifyArguments(arguments);
|
|
1542
|
-
|
|
1560
|
+
async function envList(localOptions, cmd) {
|
|
1543
1561
|
try {
|
|
1562
|
+
const options = cmd.optsWithGlobals();
|
|
1544
1563
|
const app = await getApp(options);
|
|
1545
1564
|
if (!app) return exit(NO_APP_FOUND_ERROR_STRING);
|
|
1546
1565
|
|
|
@@ -1566,8 +1585,9 @@ async function envList(options) {
|
|
|
1566
1585
|
}
|
|
1567
1586
|
}
|
|
1568
1587
|
|
|
1569
|
-
async function envGet(envName,
|
|
1588
|
+
async function envGet(envName, localOptions, cmd) {
|
|
1570
1589
|
try {
|
|
1590
|
+
const options = cmd.optsWithGlobals();
|
|
1571
1591
|
const app = await getApp(options);
|
|
1572
1592
|
if (!app) return exit(NO_APP_FOUND_ERROR_STRING);
|
|
1573
1593
|
|
package/src/appstore-actions.js
CHANGED
|
@@ -2,30 +2,29 @@
|
|
|
2
2
|
|
|
3
3
|
'use strict';
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
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
|
-
|
|
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
|
|
20
|
-
logout
|
|
21
|
-
info
|
|
22
|
-
listVersions
|
|
23
|
-
submit
|
|
24
|
-
upload
|
|
25
|
-
revoke
|
|
26
|
-
approve
|
|
27
|
-
unpublish
|
|
28
|
-
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 =
|
|
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 =
|
|
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 =
|
|
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() })
|
package/src/build-actions.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
exports = module.exports = {
|
|
4
|
-
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
|
-
|
|
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
|
-
|
|
12
|
-
for (
|
|
13
|
-
if (
|
|
14
|
-
if (
|
|
15
|
-
if (
|
|
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
|
-
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "",
|
|
3
|
+
"version": "<%- version %>",
|
|
4
|
+
"upstreamVersion": "",
|
|
5
|
+
"minBoxVersion": "7.1.0",
|
|
6
|
+
"title": "",
|
|
7
|
+
"author": "",
|
|
8
|
+
"description": "file://DESCRIPTION.md",
|
|
9
|
+
"tagline": "",
|
|
10
|
+
"website": "",
|
|
11
|
+
"contactEmail": "",
|
|
12
|
+
"icon": "file://logo.png",
|
|
13
|
+
"healthCheckPath": "/",
|
|
14
|
+
"mediaLinks": [],
|
|
15
|
+
"httpPort": <%- httpPort %>,
|
|
16
|
+
"tags": [],
|
|
17
|
+
"changelog": "file://CHANGELOG",
|
|
18
|
+
"postInstallMessage": "file://POSTINSTALL.md",
|
|
19
|
+
"documentationUrl": "",
|
|
20
|
+
"forumUrl": "",
|
|
21
|
+
"addons": {
|
|
22
|
+
"localstorage": {}
|
|
23
|
+
},
|
|
24
|
+
"manifestVersion": 2
|
|
25
|
+
}
|
package/bin/cloudron-backup
DELETED
|
@@ -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);
|