#!/usr/bin/env node /** * This code is closed source and Confidential and Proprietary to * Appcelerator, Inc. All Rights Reserved. This code MUST not be * modified, copied or otherwise redistributed without express * written permission of Appcelerator. This file is licensed as * part of the Appcelerator Platform and governed under the terms * of the Appcelerator license agreement. */ var chalk = require('chalk'), semver = require('semver'), pkg = require('../package'); // check Node.js version try { if (!semver.satisfies(process.version, pkg.engines.node)) { console.log(chalk.cyan('Appcelerator Command-Line Interface')); console.log('Copyright (c) 2014-' + (new Date().getFullYear()) + ', Appcelerator, Inc. All Rights Reserved.'); console.log(''); console.log(chalk.red('ERROR: appc requires Node.js ' + semver.validRange(pkg.engines.node))); console.log('Visit ' + chalk.cyan('http://nodejs.org/') + ' to download a newer version.'); console.log(''); process.exit(1); } } catch (e) {} var fs = require('fs'), path = require('path'), util = require('../lib/util'), error = require('../lib/error'), lib = require('../lib/index'), debug = require('debug')('appc:bin'), opts = util.parseOpts(), args = util.parseArgs(opts), installBin = util.getInstallBinary(opts), dirError; // backup our process.argv process.__argv = [].concat(process.argv); // set appc npm version process.env.NPM_APPC_VERSION = pkg.version; // set our npm cache directory to point to our own directory which we know is // writable and doesn't conflict with other npms installed by the user // we set this here so that all child processes will automatically pick them up var npmCacheDir = util.getNpmCacheDirectory(); if (fs.existsSync(npmCacheDir)) { dirError = util.checkDirectory(npmCacheDir,'npm'); } else { // make sure we write the directory util.ensureDir(npmCacheDir); dirError = util.checkDirectory(npmCacheDir,'npm'); } // check if we have an error and if so, fail if (dirError) { util.fail(dirError); } // if we get here, we're OK, set our environment. this means anything we now // do with npm should be in our user writable directory and not a different directory process.env.npm_config_cache = npmCacheDir; process.env.npm_config_prefix = npmCacheDir; // we need to make sure our install directory is writable at all times and if not, give // error up front var installDir = util.getInstallDir(); if (fs.existsSync(installDir)) { dirError = util.checkDirectory(installDir,'install'); } else { // make sure we write the directory util.ensureDir(installDir); dirError = util.checkDirectory(installDir,'install'); } // check if we have an error and if so, fail if (dirError) { util.fail(dirError); } // cleanup stale install tag var installTag = util.getInstallTag(); if (fs.existsSync(installTag)) { fs.unlinkSync(installTag); } // set an environment to the location of our install directory and bin directory process.env.APPC_INSTALL_DIR = installDir; process.env.APPC_INSTALL_BIN_DIR = installBin; debug('install bin is %o',installBin); process.env.APPC_CONFIG_PROXY = util.getProxyServer(); function after(err, installDir, version, installBin) { debug('after called with %o',arguments); if (opts.setup) { // save our version util.writeVersion(version); var appcli = util.getConfigFile(); // if we don't have this file, we need to prompt for login for first-run if (!fs.existsSync(appcli)) { var chalk = require('../vendor/chalk'); console.log(); console.log(chalk.yellow('Appcelerator login required. Please login now...')); console.log(chalk.yellow(chalk.dim('If you do not yet have an account, please visit '+chalk.underline('http://www.appcelerator.com/signup')))); console.log(); var args = program.argv.splice(2); // run our login process.argv[2] = 'login'; process.argv[3] = '--no-banner'; process.argv.length = 4; util.mergeOptsToArgs(progress.argv,opts); debug('calling lib run %s',installBin); lib.run(installBin); } else { // no need to re-run login. we're already setup process.exit(0); } } } // any of these subcommands will be passed var bundledSubcommands = /^(alloy|acs|cloud)$/; /** * support delegating to these bundled binaries in the case * they are not already installed as standalone binaries. * this is also a nice compromise for all the functionality we * aren't going to include directly in the appc CLI such that * we can still provide more advanced capabilities directly * through these underlying CLIs */ function subprocess(cmd, installBin) { var which = require('which'), spawn = require('child_process').spawn, pkg = path.join(installBin, '..','..'), version = path.basename(path.dirname(pkg)), argv = [], bin, env = process.env, argopts = { env: env, stdio:'inherit' }; // re-create args exactly as passed in but remove our subcommand var _args = process.argv.splice(2); for (var c=0;c<_args.length;c++) { var arg = _args[c]; if (arg!==cmd) { argv.push(arg); } } // set some special environment variables that can be used inside this scripts eventually if necessary env.APPC_VERSION = version; env.APPC_VERSION_DIR = pkg; env.APPC_SUBPROCESS = 1; // use our bundled version switch(cmd) { case 'alloy': { bin = path.resolve(path.join(pkg, 'node_modules','appc-cli-titanium','node_modules','alloy','bin','alloy')); break; } case 'cloud': case 'acs': { bin = path.resolve(path.join(pkg, 'node_modules','arrow','node_modules','acs','bin','acs')); cmd = 'acs'; break; } } if (!fs.existsSync(bin)) { error.failWithError('com.appcelerator.install.binary.missing',bin,pkg,version); } debug('calling spawn with %s, bin=%s, argv=%j, argopts=%j',process.execPath,bin,argv,argopts); // for windows, we need to actually run from node since these binaries aren't setup with cmd.exe var childArgs = (path.extname(bin).toLowerCase() === '.cmd') ? [bin, argv, argopts] : [process.execPath, [bin].concat(argv), argopts]; var child = spawn.apply(null, childArgs); child.on('error', function(err){ error.failWithError('com.appcelerator.install.binary.error',bin,err.message||String(err)); }); } function main() { var subcommand = args[0]; debug('main subcommand %s',subcommand); // see if this is a use command if (process.argv.length > 2) { if (subcommand==='use') { return lib.use(opts, function(err) { if (err) { if (err.name === 'AppCError') { err.failWithStackTrace(); } error.failWithError('com.appcelerator.install.download.server.response.error',err.message||String(err)); } // if we get here, we didn't find a version and we need to install it return lib.install(util.getInstallDir(), opts); }); } else { if (opts.version) { debug('main version found %s',opts.version); // if we aren't asking to print out the version but to use a specific version // we will set the version (remove the --version from args) and then run command // with this version if (opts.version!==true) { // set it explicitly by passing the version (otherwise will resolve to available) // if it doesn't explicitly find it, will return null and then install below installBin = util.getInstallBinary(opts,opts.version); debug('main explicitly set a version, installBin=%s',installBin); // delete --version so we don't add to pass through args var _args = []; for (var c=0;c