#!/usr/bin/env node 'use strict'; require('supererror'); require('colors'); let actions = require('../src/actions.js'), buildActions = require('../src/build-actions.js'), completion = require('../src/completion.js'), config = require('../src/config.js'), program = require('commander'), semver = require('semver'), util = require('util'); var version = require('../package.json').version; // ensure node version if (!semver.satisfies(process.version, require('../package.json').engines.node)) { console.error('Your nodejs version is not compatible. Please installe nodejs', require('../package.json').engines.node); process.exit(1); } // completion is useful in shell configs, so don't block here if (process.argv[2] !== 'completion') { if (Date.now() - (config.get('lastCliUpdateCheck') || 0) > 24*60*60*1000) { // check if cli tool is up-to-date var res = require('superagent-sync').get('https://registry.npmjs.org/cloudron').retry(0).end(); if (res.statusCode === 200 && res.body['dist-tags'].latest !== version) { var updateCommand = 'npm install -g cloudron@' + res.body['dist-tags'].latest; process.stderr.write(util.format('A new version of Cloudron CLI is available. Please update with: %s\n'.yellow.bold, updateCommand.white)); } config.set('lastCliUpdateCheck', Date.now()); } } function collectArgs(value, collected) { collected.push(value); return collected; } program.version(version) .option('--server ', 'Cloudron domain') .option('--token ', 'Cloudron token') .option('--allow-selfsigned', 'Accept self signed SSL certificate') .option('--accept-selfsigned', 'Accept self signed SSL certificate'); program.command('appstore', 'Cloudron appstore commands'); program.command('backup', 'App backup commands'); program.command('completion') .description('Shows completion for your shell') .action(completion); program.command('build') .description('Build an app') .option('--set-repository [repository url]', 'Change the repository') .option('--set-build-service', 'Set build service app URL') .option('--local', 'Build docker images locally') .option('--no-cache', 'Do not use cache') .option('--raw', 'Raw output build log') .option('--build-arg ', 'Build arg passed to docker. Can be used multiple times', collectArgs, []) .action(buildActions.build); program.command('cancel') .description('Cancels any active or pending app task') .option('--app ', 'App id or location') .action(actions.cancel); program.command('clone') .description('Clone an existing app to a new location') .option('--app ', 'App id or location') .option('--backup ', 'Backup id or "latest"') .option('--location ', 'Subdomain or full domain') .action(actions.clone); program.command('configure') .description('Change location of an app') .option('--app ', 'App id or location') .option('--no-wait', 'Wait for healthcheck to succeed [false]', false) .option('-p, --port-bindings [PORT=port,...]', 'Query port bindings') .option('-l, --location ', 'Location') .action(actions.configure); program.command('createOAuthAppCredentials') .option('--redirect-uri [uri]', 'Redirect Uri', 'http://localhost:4000') .option('--scope [scopes]', 'Scopes (comma separated)', 'apps,appstore,clients,cloudron,domains,mail,profile,settings,subscription,users') .option('--shell', 'Print shell friendly output') .description('Create oauth app credentials for local development') .action(actions.createOAuthAppCredentials); program.command('debug [cmd...]') .description('Put app in debug mode and run [cmd] as entrypoint. If cmd is "default" the main app entrypoint is run.') .option('--app ', 'App id or location') .option('--disable', 'Disable debug mode.') .option('--readonly', 'Mount filesystem readonly. Default is read/write in debug mode.') .option('--limit-memory', 'Enforces app memory limit. Default is to not limit memory in debug mode.') .action(actions.debug); program.command('env', 'App environment commands'); program.command('exec [cmd...]') .description('Exec a command in an application') .option('-t,--tty', 'Allocate tty') .option('--app ', 'App id or location') .action(actions.exec) .on('--help', function() { console.log(' Examples:'); console.log(); console.log(' $ cloudron exec --app myapp # run an interactive shell'); console.log(' $ cloudron exec --app myapp ls # run command'); console.log(' $ cloudron exec --app myapp -- ls -l # use -- to indicate end of options'); console.log(); }); program.command('import') .description('Import app from an external backup') .option('--app ', 'App id or location') .option('--backup-id ', 'Backup id') .option('--backup-format ', 'Backup format (default: tgz)') .option('--backup-config ', 'Backup config in JSON format') .option('--backup-path ', 'Absolute path to a backup on the filesystem') .option('--backup-key ', 'Encryption key') .option('--in-place', 'Re-import from current app directory without downloading any backup', false) .action(actions.importApp); program.command('inspect') .description('Inspect a Cloudron returning raw JSON') .action(actions.inspect); program.command('init') .description('Creates a new CloudronManifest.json and Dockerfile') .action(actions.init); program.command('install') .description('Install or update app') .option('--app ', 'App id or location. OBSOLETE: Use "update" instead.') .option('--image ', 'Docker image') .option('--no-wait', 'Wait for healthcheck to succeed [false]', false) .option('-p, --port-bindings [PORT=port,...]', 'Query port bindings') .option('-l, --location ', 'Subdomain or full domain') .option('--appstore-id ', 'Use app from the store') .option('--no-sso', 'Disable Cloudron SSO [false]', false) .option('--debug [cmd]', 'Enable debug mode') .option('--readonly', 'Mount filesystem readonly. Default is read/write in debug mode.') .action(actions.install); program.command('list') .description('List installed applications') .action(actions.list); program.command('login [cloudron]') .description('Login to cloudron') .action(actions.login); program.command('logout') .description('Logout from cloudron') .action(actions.logout); program.command('logs') .description('Application logs') .option('-f, --tail', 'Follow') .option('-l, --lines ', 'Number of lines to show (default: 500)') .option('--app ', 'App id or location') .action(actions.logs); program.command('open') .description('Open the app in the Browser') .option('--app ', 'App id or location') .action(actions.open); program.command('pull ') .description('pull remote file/dir. Use trailing slash to indicate remote directory.') .option('--app ', 'App id or location') .action(actions.pull); program.command('push ') .description('push a single local file or directory to a remote directory') .option('--app ', 'App id or location') .action(actions.push) .on('--help', function() { console.log(); console.log(' Examples:'); console.log(); console.log(' $ cloudron push --app myapp file.txt /app/data/file.txt # pushes file.txt'); console.log(' $ cloudron push --app myapp file.txt /app/data/ # pushes file.txt. trailing slash is important'); console.log(' $ cloudron push --app myapp dir /app/data # pushes dir/* as /app/data/dir/*'); console.log(' $ cloudron push --app myapp dir/. /app/data # pushes dir/* as /app/data/*'); console.log(' $ cloudron push --app myapp dir/subdir /app/data # pushes dir/subdir/* as /app/data/subdir/*'); console.log(' $ cloudron push --app myapp . /app/data # pushes .* as /app/data/*'); console.log(); }); program.command('repair') .description('Repair an installed application (re-configure)') .option('--app ', 'App id or location') .option('--image ', 'Docker image') .option('--no-wait', 'Wait for healthcheck to succeed [false]', false) .action(actions.repair); program.command('restore') .description('Restore app from known backup') .option('--app ', 'App id or location') .option('--backup ', 'Backup id') .option('--no-wait', 'Wait for healthcheck to succeed [false]', false) .action(actions.restore); program.command('restart') .description('Restart an installed application') .option('--app ', 'App id or location') .option('--no-wait', 'Wait for healthcheck to succeed [false]', false) .action(actions.restart); program.command('start') .description('Start an installed application') .option('--app ', 'App id or location') .option('--no-wait', 'Wait for healthcheck to succeed [false]', false) .action(actions.start); program.command('stop') .description('Stop an installed application') .option('--app ', 'App id or location') .action(actions.stop); program.command('status') .description('Application info') .option('--app ', 'App id or location') .action(actions.status); program.command('uninstall') .description('Uninstall app from cloudron') .option('--app ', 'App id or location') .action(actions.uninstall); program.command('update') .description('Update app') .option('--app ', 'App id or location') .option('--image ', 'Docker image') .option('--no-backup', 'Skip backup [false]', false) .option('--no-wait', 'Wait for healthcheck to succeed [false]', false) .option('--no-force', 'Match appstore id and backup the app before updating', true) .action(actions.update); // deal first with global flags! program.parse(process.argv); var knownCommand = program.commands.some(function (command) { return command._name === process.argv[2] || command._alias === process.argv[2]; }); if (!knownCommand) { console.log('Unknown command: ' + process.argv[2].bold + '.\nTry ' + 'cloudron help'.yellow); process.exit(1); }