kopia lustrzana https://github.com/c9/core
577 wiersze
21 KiB
JavaScript
577 wiersze
21 KiB
JavaScript
define(function(require, exports, module) {
|
|
main.consumes = [
|
|
"Plugin", "cli_commands", "proc", "api", "auth", "installer",
|
|
"installer.cli"
|
|
];
|
|
main.provides = ["cli.install"];
|
|
return main;
|
|
|
|
function main(options, imports, register) {
|
|
var Plugin = imports.Plugin;
|
|
var cmd = imports.cli_commands;
|
|
var proc = imports.proc;
|
|
var auth = imports.auth;
|
|
var api = imports.api;
|
|
var installer = imports.installer;
|
|
var installerCLI = imports["installer.cli"];
|
|
|
|
var dirname = require("path").dirname;
|
|
|
|
var TEST_MODE = !!process.env.C9_TEST_MODE;
|
|
var TAR = "tar";
|
|
var APIHOST = options.apiHost;
|
|
var BASICAUTH = process.env.C9_TEST_AUTH;
|
|
var SCM = {
|
|
"git": {
|
|
binary: "git",
|
|
clone: "clone"
|
|
},
|
|
"mercurial": {
|
|
binary: "hg",
|
|
clone: "clone"
|
|
},
|
|
"hg": {
|
|
binary: "hg",
|
|
clone: "clone"
|
|
}
|
|
};
|
|
|
|
var fs = require("fs");
|
|
var join = require("path").join;
|
|
var os = require("os");
|
|
var http = require(APIHOST.indexOf("localhost") > -1 ? "http" : "https");
|
|
|
|
var verbose = false;
|
|
var force = false;
|
|
|
|
// Set up basic auth for api if needed
|
|
if (BASICAUTH) api.basicAuth = BASICAUTH;
|
|
|
|
/***** Initialization *****/
|
|
|
|
var plugin = new Plugin("Ajax.org", main.consumes);
|
|
// var emit = plugin.getEmitter();
|
|
|
|
var loaded;
|
|
function load(){
|
|
if (loaded) return;
|
|
loaded = true;
|
|
|
|
cmd.addCommand({
|
|
name: "install",
|
|
info: " Installs a cloud9 package.",
|
|
usage: "[--verbose] [--force] [--global] [--local] [--debug] [<package>[@<version>] | . ]",
|
|
options: {
|
|
"local": {
|
|
description: "",
|
|
"default": false,
|
|
"boolean": true
|
|
},
|
|
"global": {
|
|
description: "",
|
|
"default": false,
|
|
"boolean": true
|
|
},
|
|
"debug": {
|
|
description: "",
|
|
"default": false,
|
|
"boolean": true
|
|
},
|
|
"verbose" : {
|
|
"description": "Output more information",
|
|
"alias": "v",
|
|
"default": false,
|
|
"boolean": true
|
|
},
|
|
"force" : {
|
|
"description": "Ignore warnings",
|
|
"alias": "f",
|
|
"default": false,
|
|
"boolean": true
|
|
}
|
|
},
|
|
check: function(argv) {
|
|
if (argv._.length < 2 && !argv["package"])
|
|
throw new Error("package");
|
|
},
|
|
exec: function(argv) {
|
|
verbose = argv["verbose"];
|
|
force = argv["force"];
|
|
|
|
if (argv.accessToken)
|
|
auth.accessToken = argv.accessToken;
|
|
|
|
if (!argv.local && !argv.debug) {
|
|
if (!process.env.C9_PID) {
|
|
console.warn("It looks like you are not running on c9.io. Will default to local installation of the package");
|
|
argv.local = true;
|
|
}
|
|
}
|
|
|
|
var name = argv._[1];
|
|
|
|
var test = name == ".";
|
|
if (test)
|
|
name = require("path").basename(process.cwd());
|
|
|
|
install(
|
|
name,
|
|
{
|
|
global: argv.global,
|
|
local: argv.local,
|
|
debug: argv.debug,
|
|
test: test
|
|
},
|
|
function(err, data){
|
|
if (err) {
|
|
console.error(err.message || "Terminated.");
|
|
process.exit(1);
|
|
}
|
|
else {
|
|
console.log("Successfully installed", name + (argv.debug ? "" : "@" + data.version));
|
|
process.exit(0);
|
|
}
|
|
});
|
|
}
|
|
});
|
|
|
|
cmd.addCommand({
|
|
name: "remove",
|
|
alias: "uninstall",
|
|
info: " Removes a cloud9 package.",
|
|
usage: "[--verbose] [--global] [--local] <package>", // @TODO --global
|
|
options: {
|
|
"local": {
|
|
description: "",
|
|
"default": false,
|
|
"boolean": true
|
|
},
|
|
"global": {
|
|
description: "",
|
|
"default": false,
|
|
"boolean": true
|
|
},
|
|
"verbose" : {
|
|
"description": "Output more information",
|
|
"alias": "v",
|
|
"default": false,
|
|
"boolean": true
|
|
}
|
|
},
|
|
check: function(argv) {
|
|
if (argv._.length < 2 && !argv["package"])
|
|
throw new Error("package");
|
|
},
|
|
exec: function(argv) {
|
|
verbose = argv["verbose"];
|
|
|
|
if (argv.accessToken)
|
|
auth.accessToken = argv.accessToken;
|
|
|
|
var name = argv._[1];
|
|
uninstall(
|
|
name,
|
|
{
|
|
global: argv.global,
|
|
local: argv.local
|
|
},
|
|
function(err, data){
|
|
if (err) {
|
|
console.error(err.message || "Terminated.");
|
|
process.exit(1);
|
|
}
|
|
else {
|
|
console.log("Successfully removed", name);
|
|
process.exit(0);
|
|
}
|
|
});
|
|
}
|
|
});
|
|
}
|
|
|
|
/***** Methods *****/
|
|
|
|
function spawn(command, options, callback) {
|
|
if (options.stdio == null) {
|
|
// if verbose, echo stdout
|
|
// always echo stderr
|
|
options.stdio = [
|
|
"pipe",
|
|
verbose ? process.stdout : "ignore",
|
|
process.stderr
|
|
];
|
|
}
|
|
|
|
proc.spawn(command, options, function(err, child) {
|
|
if (err) return callback(err);
|
|
|
|
child.on("exit", function(code) {
|
|
if (code !== 0) {
|
|
var error = new Error("Command failed: " + command);
|
|
error.code = code;
|
|
return callback(error);
|
|
}
|
|
|
|
callback();
|
|
});
|
|
});
|
|
}
|
|
|
|
function install(packageName, options, callback){
|
|
// Call install url
|
|
var parts = packageName.split("@");
|
|
var name = parts[0];
|
|
var version = parts[1];
|
|
var repository;
|
|
|
|
if (!options.test) {
|
|
if (verbose)
|
|
console.log("Retrieving package info");
|
|
|
|
api.packages.get(name, function (err, info) {
|
|
if (err) return callback(err);
|
|
|
|
if (verbose)
|
|
console.log("Found:", info);
|
|
|
|
if (!version)
|
|
version = info.latest;
|
|
|
|
repository = info.repository;
|
|
|
|
installPackage();
|
|
});
|
|
}
|
|
else {
|
|
installPackage();
|
|
}
|
|
|
|
function prepareDirectory(callback){
|
|
// Create package dir
|
|
var packagePath = process.env.HOME + "/.c9/plugins/" + name;
|
|
var exists = fs.existsSync(packagePath);
|
|
|
|
// Ignore when testing and in the same dir
|
|
if (options.test && process.cwd() == packagePath)
|
|
exists = false;
|
|
|
|
if (exists) {
|
|
if (!force && !options.test)
|
|
return callback(new Error("WARNING: Directory not empty: " + packagePath
|
|
+ ". Use --force to overwrite."));
|
|
|
|
proc.execFile("rm", {
|
|
args: ["-Rf", packagePath]
|
|
}, function(){
|
|
mkdirP(packagePath);
|
|
callback(null, packagePath);
|
|
});
|
|
}
|
|
else {
|
|
mkdirP(packagePath);
|
|
callback(null, packagePath);
|
|
}
|
|
}
|
|
|
|
function installPackage(){
|
|
if (!version && !options.test)
|
|
return callback(new Error("No version found for this package"));
|
|
|
|
if (options.local) {
|
|
installLocal();
|
|
}
|
|
else if (options.debug) {
|
|
installDebug();
|
|
}
|
|
else {
|
|
installFull();
|
|
}
|
|
}
|
|
|
|
function installLocal(){
|
|
if (verbose)
|
|
console.log("Installing package locally");
|
|
|
|
prepareDirectory(function(err, packagePath){
|
|
if (err) return callback(err);
|
|
var npmBin = [
|
|
join(process.env.HOME, process.platform == "win32"? ".c9/npm.cmd" : ".c9/node/bin/npm"),
|
|
"/mnt/shared/sbin/npm"
|
|
];
|
|
function installNPM(){
|
|
spawn(npmBin[0], {
|
|
args: ["install"],
|
|
cwd: packagePath
|
|
}, function(err) {
|
|
if (err && err.code == 127) {
|
|
npmBin.shift();
|
|
if (npmBin.length)
|
|
return installNPM();
|
|
}
|
|
|
|
if (err) return callback(err);
|
|
callback(null, { version: version });
|
|
});
|
|
}
|
|
|
|
if (options.test) {
|
|
try {
|
|
var json = JSON.parse(fs.readFileSync(join(process.cwd(), "package.json")));
|
|
if (json.private)
|
|
return callback(new Error("ERROR: Private flag in package.json prevents from installing"));
|
|
}
|
|
catch(e) {
|
|
return callback(new Error("ERROR: Invalid package: " + e.message));
|
|
}
|
|
|
|
if (process.cwd() == packagePath)
|
|
installNPM();
|
|
else {
|
|
proc.execFile("cp", {
|
|
args: ["-R", process.cwd(), dirname(packagePath)]
|
|
}, function(err){
|
|
if (err) return callback(err);
|
|
|
|
installNPM();
|
|
});
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
// Download package
|
|
var gzPath = join(os.tmpDir(), name + "@" + version + ".tar.gz");
|
|
var file = fs.createWriteStream(gzPath);
|
|
|
|
var path = "/packages/" + name + "/versions/" + version
|
|
+ "/download?access_token="
|
|
+ encodeURIComponent(auth.accessToken);
|
|
var host = APIHOST.split(":")[0];
|
|
var port = parseInt(APIHOST.split(":")[1]) || null;
|
|
|
|
var request = http.get({
|
|
agent: false,
|
|
method: "get",
|
|
host: host,
|
|
port: port,
|
|
auth: BASICAUTH,
|
|
path: path
|
|
}, function(response){
|
|
response.pipe(file);
|
|
});
|
|
|
|
if (verbose)
|
|
console.log("Downloading package to", gzPath);
|
|
|
|
request.on('response', function(res) {
|
|
if (res.statusCode != 200)
|
|
return callback(new Error("Unknown Error getting "
|
|
+ host + (port ? ":" + port : "")
|
|
+ path + ":" + res.statusCode));
|
|
});
|
|
|
|
file.on('finish', function() {
|
|
if (verbose)
|
|
console.log("Unpacking", gzPath, "to", packagePath);
|
|
|
|
// Untargz package
|
|
spawn(TAR, {
|
|
args: [
|
|
(verbose ? "-v" : ""),
|
|
"-C", normalizePath(packagePath),
|
|
"-zxf", normalizePath(gzPath)
|
|
]
|
|
}, function(err) {
|
|
if (err) {
|
|
var error = new Error("Failed to unpack package");
|
|
error.code = err.code;
|
|
return callback(error);
|
|
}
|
|
|
|
installNPM();
|
|
});
|
|
});
|
|
});
|
|
}
|
|
|
|
function installDebug(){
|
|
if (verbose)
|
|
console.log("Installing debug version of package");
|
|
|
|
if (options.test)
|
|
return callback(new Error("Test is not supported for debug installations"));
|
|
|
|
prepareDirectory(function(err, packagePath){
|
|
if (err) return callback(err);
|
|
|
|
if (verbose)
|
|
console.log("Cloning repository: ", repository);
|
|
|
|
// Git clone repository
|
|
var scm = SCM[repository.type];
|
|
spawn(scm.binary, {
|
|
args: [scm.clone, repository.url, packagePath]
|
|
}, function(err) {
|
|
if (err) {
|
|
var error = new Error("Failed to clone package from repository. Do you have access?");
|
|
error.code = err.code;
|
|
return callback(error);
|
|
}
|
|
|
|
callback();
|
|
});
|
|
});
|
|
}
|
|
|
|
function installFull(){
|
|
// Install Locally
|
|
options.local = true;
|
|
install(name + "@" + version, options, function(err){
|
|
if (err) return callback(err);
|
|
|
|
var path = process.env.HOME + "/.c9/plugins/" + name;
|
|
fs.readFile(path + "/package.json", "utf8", function(err, data){
|
|
if (err) return callback(new Error("Package.json not found in " + path));
|
|
|
|
var installPath;
|
|
try { installPath = JSON.parse(data).installer; }
|
|
catch(e){
|
|
return callback(new Error("Could not parse package.json in " + path));
|
|
}
|
|
|
|
if (installPath) {
|
|
installerCLI.verbose = verbose;
|
|
installer.createSession(name, version || "", require(path + "/" + installPath), function(err){
|
|
if (err) return callback(new Error("Error Installing Package " + name + "@" + version));
|
|
installToDatabase();
|
|
}, force || options.test);
|
|
}
|
|
else
|
|
installToDatabase();
|
|
});
|
|
|
|
|
|
function installToDatabase(){
|
|
if (options.test)
|
|
return callback(null, { version: "test" });
|
|
|
|
if (verbose)
|
|
console.log("Notifying c9.io that package is installed");
|
|
|
|
var endpoint = options.global ? api.user : api.project;
|
|
var url = "install/" + name + "/" + version + "?mode=silent";
|
|
|
|
endpoint.post(url, function(err, info){
|
|
callback(err, info);
|
|
});
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
function uninstall(packageName, options, callback){
|
|
// Call uninstall url
|
|
var parts = packageName.split("@");
|
|
var name = parts[0];
|
|
var version = parts[1];
|
|
|
|
if (!version) {
|
|
api.packages.get(name, function (err, info) {
|
|
if (err) return callback(err);
|
|
version = info.latest;
|
|
|
|
uninstallPackage();
|
|
});
|
|
}
|
|
else {
|
|
uninstallPackage();
|
|
}
|
|
|
|
function uninstallPackage(){
|
|
if (options.local || options.debug) {
|
|
// rm -Rf
|
|
var packagePath = process.env.HOME + "/.c9/plugins/" + name;
|
|
spawn("rm", {
|
|
args: ["-rf", packagePath]
|
|
}, function(err) {
|
|
if (err) {
|
|
var error = new Error("Failed to remove package.");
|
|
error.code = err.code;
|
|
return callback(error);
|
|
}
|
|
|
|
// if debug > see if should be installed and put back original
|
|
// @TODO
|
|
|
|
callback();
|
|
});
|
|
}
|
|
else {
|
|
var endpoint = options.global ? api.user : api.project;
|
|
var url = "uninstall/" + packageName;
|
|
|
|
endpoint.post(url, function(err, info){
|
|
callback(err, info);
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
function mkdirP(path){
|
|
var dirs = path.split('/');
|
|
var prevDir = dirs.splice(0,1) + "/";
|
|
while (dirs.length > 0) {
|
|
var curDir = prevDir + dirs.splice(0,1);
|
|
if (! fs.existsSync(curDir) ) {
|
|
fs.mkdirSync(curDir);
|
|
}
|
|
prevDir = curDir + '/';
|
|
}
|
|
}
|
|
|
|
function normalizePath(p) {
|
|
if (process.platform == "win32")
|
|
p = p.replace(/\\/g, "/").replace(/^(\w):/, "/$1");
|
|
return p;
|
|
}
|
|
|
|
/***** Lifecycle *****/
|
|
|
|
plugin.on("load", function(){
|
|
load();
|
|
});
|
|
plugin.on("enable", function(){
|
|
|
|
});
|
|
plugin.on("disable", function(){
|
|
|
|
});
|
|
plugin.on("unload", function(){
|
|
loaded = false;
|
|
verbose = false;
|
|
force = false;
|
|
});
|
|
|
|
/***** Register and definfe API *****/
|
|
|
|
/**
|
|
*
|
|
**/
|
|
plugin.freezePublicAPI({
|
|
/**
|
|
*
|
|
*/
|
|
install: install,
|
|
|
|
/**
|
|
*
|
|
*/
|
|
uninstall: uninstall
|
|
});
|
|
|
|
register(null, {
|
|
"cli.install": plugin
|
|
});
|
|
}
|
|
|
|
}); |