2015-02-10 19:41:24 +00:00
|
|
|
define(function(require, exports, module) {
|
|
|
|
main.consumes = ["Plugin", "cli_commands", "proc", "api", "auth"];
|
|
|
|
main.provides = ["cli.publish"];
|
|
|
|
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;
|
|
|
|
|
2015-02-19 16:03:55 +00:00
|
|
|
var TEST_MODE = !!process.env.C9_TEST_MODE;
|
|
|
|
var SHELLSCRIPT = TEST_MODE ? "" : require("text!./publish.git.sh").toString("utf8");
|
2015-02-10 19:41:24 +00:00
|
|
|
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 FormData = require("form-data");
|
|
|
|
var http = require(APIHOST.indexOf("localhost") > -1 ? "http" : "https");
|
2015-04-04 01:07:31 +00:00
|
|
|
var Path = require("path");
|
2015-02-10 19:41:24 +00:00
|
|
|
var basename = require("path").basename;
|
2015-03-29 23:15:52 +00:00
|
|
|
var dirname = require("path").dirname;
|
2015-04-04 01:07:31 +00:00
|
|
|
var async = require("async");
|
2015-02-10 19:41:24 +00:00
|
|
|
|
|
|
|
var verbose = false;
|
|
|
|
var force = false;
|
2015-04-04 01:07:31 +00:00
|
|
|
var dryRun = false;
|
2015-02-10 19:41:24 +00:00
|
|
|
|
|
|
|
// 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: "publish",
|
|
|
|
info: " Publishes a cloud9 package.",
|
|
|
|
usage: "[--verbose] [--force] [<newversion> | major | minor | patch | build]",
|
|
|
|
options: {
|
|
|
|
"verbose" : {
|
|
|
|
"description": "Output more information",
|
|
|
|
"alias": "v",
|
|
|
|
"default": false,
|
|
|
|
"boolean": true
|
|
|
|
},
|
|
|
|
"force" : {
|
|
|
|
"description": "Ignore warnings",
|
|
|
|
"alias": "f",
|
|
|
|
"default": false,
|
|
|
|
"boolean": true
|
2015-04-04 01:07:31 +00:00
|
|
|
},
|
|
|
|
"dry-run" : {
|
|
|
|
"description": "Only build a test version",
|
|
|
|
"default": false,
|
|
|
|
"boolean": true
|
2015-02-10 19:41:24 +00:00
|
|
|
}
|
|
|
|
},
|
|
|
|
check: function(argv) {
|
|
|
|
if (argv._.length < 2 && !argv["newversion"])
|
|
|
|
throw new Error("Missing version");
|
|
|
|
},
|
|
|
|
exec: function(argv) {
|
|
|
|
verbose = argv["verbose"];
|
|
|
|
force = argv["force"];
|
2015-04-04 01:07:31 +00:00
|
|
|
dryRun = argv["dry-run"];
|
2015-02-10 19:41:24 +00:00
|
|
|
|
|
|
|
publish(
|
|
|
|
argv._[1],
|
|
|
|
function(err, data){
|
|
|
|
if (err) {
|
|
|
|
if (err.message || typeof err == "string")
|
|
|
|
console.error(err.message || err);
|
|
|
|
|
|
|
|
if (!verbose)
|
|
|
|
console.error("\nTry running with --verbose flag for more information");
|
|
|
|
process.exit(1);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
console.log("Succesfully published version", data.version);
|
|
|
|
process.exit(0);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
cmd.addCommand({
|
|
|
|
name: "unpublish",
|
|
|
|
info: "Disables a cloud9 package.",
|
|
|
|
usage: "[--verbose]",
|
|
|
|
options: {
|
|
|
|
"verbose" : {
|
|
|
|
"description": "Output more information",
|
|
|
|
"alias": "v",
|
|
|
|
"default": false,
|
|
|
|
"boolean": true
|
|
|
|
}
|
|
|
|
},
|
|
|
|
check: function(argv) {},
|
|
|
|
exec: function(argv) {
|
|
|
|
verbose = argv["verbose"];
|
|
|
|
|
|
|
|
unpublish(
|
|
|
|
function(err, data){
|
|
|
|
if (err) {
|
|
|
|
console.error(err.message || err || "Terminated.");
|
|
|
|
process.exit(1);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
console.log("Succesfully disabled package");
|
|
|
|
process.exit(0);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
cmd.addCommand({
|
|
|
|
name: "install",
|
|
|
|
info: " Installs a cloud9 package.",
|
|
|
|
usage: "[--verbose] [--force] [--global] [--local] [--debug] <package>[@<version>]", // @TODO --global, --debug, --local
|
|
|
|
options: {
|
|
|
|
"local": {
|
|
|
|
description: "",
|
|
|
|
"default": false,
|
|
|
|
"boolean": true
|
|
|
|
},
|
|
|
|
"global": {
|
|
|
|
description: "",
|
|
|
|
"default": false,
|
|
|
|
"boolean": true
|
|
|
|
},
|
|
|
|
"debug": {
|
|
|
|
description: "",
|
|
|
|
"default": false,
|
|
|
|
"boolean": true
|
|
|
|
},
|
|
|
|
"package" : {
|
|
|
|
description: "",
|
|
|
|
"default": false
|
|
|
|
},
|
|
|
|
"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];
|
|
|
|
install(
|
|
|
|
name,
|
|
|
|
{
|
|
|
|
global: argv.global,
|
|
|
|
local: argv.local,
|
|
|
|
debug: argv.debug
|
|
|
|
},
|
|
|
|
function(err, data){
|
|
|
|
if (err) {
|
|
|
|
console.error(err.message || "Terminated.");
|
|
|
|
process.exit(1);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
console.log("Succesfully installed", name + (argv.debug ? "" : "@" + data.version));
|
|
|
|
process.exit(0);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
cmd.addCommand({
|
|
|
|
name: "remove",
|
|
|
|
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
|
|
|
|
},
|
|
|
|
"package" : {
|
|
|
|
description: ""
|
|
|
|
},
|
|
|
|
"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("Succesfully removed", name);
|
|
|
|
process.exit(0);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
cmd.addCommand({
|
|
|
|
name: "list",
|
|
|
|
info: " Lists all available packages.",
|
|
|
|
usage: "[--json]",
|
|
|
|
options: {
|
|
|
|
"json": {
|
|
|
|
description: "",
|
|
|
|
"default": false,
|
|
|
|
"boolean": true
|
|
|
|
},
|
|
|
|
},
|
|
|
|
check: function(argv) {},
|
|
|
|
exec: function(argv) {
|
|
|
|
verbose = argv["verbose"];
|
|
|
|
|
|
|
|
list(argv.json);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
/***** Methods *****/
|
|
|
|
|
|
|
|
function stringifyError(err){
|
|
|
|
return (verbose ? JSON.stringify(err, 4, " ") : (typeof err == "string" ? err : err.message));
|
|
|
|
}
|
|
|
|
|
|
|
|
function list(asJson, callback){
|
|
|
|
callback = callback || function(){};
|
|
|
|
api.packages.get("", function(err, list){
|
|
|
|
if (err) {
|
|
|
|
console.error("ERROR: Could not get list: ", stringifyError(err));
|
|
|
|
return callback(err);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (asJson) {
|
|
|
|
console.log(JSON.stringify(list, 4, " "));
|
|
|
|
return callback(null, list);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
list.forEach(function(item){
|
|
|
|
console.log(item.name, "https://c9.io/packages/" + item.name);
|
|
|
|
});
|
|
|
|
return callback(null, list);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
function publish(version, callback) {
|
|
|
|
var cwd = process.cwd();
|
|
|
|
var packagePath = cwd + "/package.json";
|
|
|
|
fs.readFile(packagePath, function(err, data){
|
|
|
|
if (err) return callback(new Error("ERROR: Could not find package.json in " + cwd));
|
|
|
|
|
|
|
|
var json;
|
|
|
|
try { json = JSON.parse(data); }
|
|
|
|
catch(e) {
|
|
|
|
return callback(new Error("ERROR: Could not parse package.json: ", e.message));
|
|
|
|
}
|
|
|
|
|
|
|
|
// Basic Validation
|
|
|
|
if (!json.name)
|
|
|
|
return callback(new Error("ERROR: Missing name property in package.json"));
|
|
|
|
if (basename(cwd) != json.name) {
|
|
|
|
console.warn("WARNING: The name property in package.json is not equal to the directory name, which is " + basename(cwd));
|
|
|
|
if (!force)
|
|
|
|
return callback(new Error("Use --force to ignore this warning."));
|
|
|
|
}
|
|
|
|
if (!json.description)
|
|
|
|
return callback(new Error("ERROR: Missing description property in package.json"));
|
|
|
|
if (!json.repository)
|
|
|
|
return callback(new Error("ERROR: Missing repository property in package.json"));
|
|
|
|
if (!json.categories || json.categories.length == 0)
|
|
|
|
return callback(new Error("ERROR: At least one category is required in package.json"));
|
|
|
|
|
|
|
|
// Validate README.md
|
|
|
|
if (!fs.existsSync(join(cwd, "README.md"))) {
|
|
|
|
console.warn("WARNING: README.md is missing.");
|
|
|
|
if (!force)
|
|
|
|
return callback(new Error("Use --force to ignore these warnings."));
|
|
|
|
}
|
|
|
|
|
|
|
|
// Validate plugins
|
|
|
|
var plugins = {};
|
2015-03-06 20:11:52 +00:00
|
|
|
fs.readdirSync(cwd).forEach(function(filename) {
|
2015-04-04 01:07:31 +00:00
|
|
|
if (/(__packed__|_test)\.js$/.test(filename) || !/\.js$/.test(filename)) return;
|
2015-03-06 20:11:52 +00:00
|
|
|
try {
|
|
|
|
var val = fs.readFileSync(cwd + "/" + filename);
|
|
|
|
} catch(e) {
|
|
|
|
if (e.code == "EISDIR") return;
|
|
|
|
throw e;
|
|
|
|
}
|
2015-02-10 19:41:24 +00:00
|
|
|
if (!/\(options,\s*imports,\s*register\)/.test(val)) return;
|
|
|
|
if (!/consumes\s*=/.test(val)) return;
|
|
|
|
if (!/provides\s*=/.test(val)) return;
|
|
|
|
plugins[filename] = {};
|
|
|
|
});
|
|
|
|
|
|
|
|
var warned, failed;
|
|
|
|
Object.keys(plugins).forEach(function(name){
|
|
|
|
if (!json.plugins[name.replace(/\.js$/, "")]) {
|
|
|
|
console.warn("WARNING: Plugin '" + name + "' is not listed in package.json.");
|
|
|
|
warned = true;
|
|
|
|
}
|
|
|
|
// @TODO temporarily disabled the requirement for tests while tests cannot actually run yet
|
|
|
|
// else if (!fs.existsSync(join(cwd, name.replace(/\.js$/, "_test.js")))) {
|
|
|
|
// console.warn("ERROR: Plugin '" + name + "' has no test associated with it.");
|
|
|
|
// failed = true;
|
|
|
|
// }
|
|
|
|
});
|
|
|
|
|
|
|
|
if (failed)
|
|
|
|
return callback(new Error());
|
|
|
|
|
|
|
|
if (warned && !force)
|
|
|
|
return callback(new Error("Use --force to ignore these warnings."));
|
|
|
|
|
|
|
|
var v = (json.version || "0.0.1").split(".");
|
|
|
|
|
|
|
|
// Update the version field in the package.json file
|
|
|
|
if (version == "major") {
|
|
|
|
v[0]++;
|
|
|
|
v[1] = 0;
|
|
|
|
v[2] = 0;
|
|
|
|
}
|
|
|
|
else if (version == "minor") {
|
|
|
|
v[1]++;
|
|
|
|
v[2] = 0;
|
|
|
|
}
|
|
|
|
else if (version == "patch" || version == "build") v[2]++;
|
|
|
|
else if (version.match(/^\d+\.\d+\.\d+$/))
|
|
|
|
v = version.split(".");
|
|
|
|
else
|
|
|
|
return callback(new Error("Invalid version. Semver required: " + version));
|
|
|
|
|
|
|
|
json.version = v.join(".");
|
|
|
|
|
|
|
|
// Write the package.json file
|
|
|
|
fs.writeFile(packagePath, JSON.stringify(json, 1, " "), function(err){
|
|
|
|
if (err) return callback(err);
|
|
|
|
|
2015-04-04 01:07:31 +00:00
|
|
|
if (dryRun) return build();
|
|
|
|
|
2015-02-10 19:41:24 +00:00
|
|
|
SHELLSCRIPT = SHELLSCRIPT
|
|
|
|
.replace(/\$1/, packagePath)
|
|
|
|
.replace(/\$2/, json.version);
|
|
|
|
|
|
|
|
proc.spawn("bash", {
|
|
|
|
args: ["-c", SHELLSCRIPT]
|
|
|
|
}, function(err, p){
|
|
|
|
if (err) return callback(err);
|
|
|
|
|
|
|
|
if (verbose) {
|
|
|
|
p.stdout.on("data", function(c){
|
|
|
|
process.stdout.write(c.toString("utf8"));
|
|
|
|
});
|
|
|
|
p.stderr.on("data", function(c){
|
|
|
|
process.stderr.write(c.toString("utf8"));
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
p.on("exit", function(code, stderr, stdout){
|
|
|
|
if (code !== 0)
|
|
|
|
return callback(new Error("ERROR: publish failed with exit code " + code));
|
|
|
|
|
|
|
|
console.log("Created tag and updated package.json to version", json.version);
|
|
|
|
|
|
|
|
build();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
// Build the package
|
|
|
|
// @TODO use a proper package tool
|
|
|
|
// @TODO add a .c9exclude file that excludes files
|
|
|
|
var zipFilePath;
|
|
|
|
function build(){
|
2015-03-29 23:15:52 +00:00
|
|
|
var base = dirname(cwd);
|
|
|
|
var packageName = json.name;
|
|
|
|
var config = Object.keys(plugins).map(function(p) {
|
|
|
|
return packageName + "/" + p;
|
|
|
|
});
|
|
|
|
var paths = {};
|
|
|
|
paths[packageName] = cwd;
|
|
|
|
|
|
|
|
var build = require("architect-build/build");
|
|
|
|
build(config, {
|
|
|
|
paths: paths,
|
|
|
|
enableBrowser: true,
|
|
|
|
includeConfig: false,
|
|
|
|
noArchitect: true,
|
2015-04-04 01:07:31 +00:00
|
|
|
compress: !dryRun,
|
2015-03-29 23:15:52 +00:00
|
|
|
obfuscate: true,
|
|
|
|
oneLine: true,
|
|
|
|
filter: [],
|
|
|
|
ignore: [],
|
|
|
|
withRequire: false,
|
|
|
|
stripLess: false,
|
|
|
|
basepath: base,
|
|
|
|
}, function(e, result) {
|
|
|
|
var packedFiles = result.sources.map(function(m) {
|
2015-04-04 01:07:31 +00:00
|
|
|
return m.file;
|
2015-03-29 23:15:52 +00:00
|
|
|
});
|
2015-04-04 01:07:31 +00:00
|
|
|
|
|
|
|
async.series([
|
|
|
|
function(next) {
|
2015-04-13 19:44:42 +00:00
|
|
|
fs.readdir(cwd, function(err, files) {
|
|
|
|
console.log(files)
|
|
|
|
if (err)
|
|
|
|
return next();
|
|
|
|
var extraCode = [];
|
|
|
|
function forEachFile(dir, f) {
|
|
|
|
try {
|
|
|
|
fs.readdirSync(dir).forEach(f);
|
|
|
|
} catch(e) {
|
|
|
|
console.log(e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (files.indexOf("builders") != -1) {
|
|
|
|
forEachFile(cwd + "/builders", function(p) {
|
|
|
|
console.log(p, "***");
|
|
|
|
extraCode.push()
|
|
|
|
|
|
|
|
});
|
|
|
|
}
|
|
|
|
if (files.indexOf("keymaps") != -1) {
|
|
|
|
forEachFile(cwd + "/keymaps", function(p) {
|
|
|
|
console.log(p, "***");
|
|
|
|
});
|
|
|
|
}
|
|
|
|
if (files.indexOf("modes") != -1) {
|
|
|
|
forEachFile(cwd + "/modes", function(p) {
|
|
|
|
console.log(p, "***");
|
|
|
|
});
|
|
|
|
}
|
|
|
|
if (files.indexOf("outline") != -1) {
|
|
|
|
forEachFile(cwd + "/outline", function(p) {
|
|
|
|
console.log(p, "***");
|
|
|
|
});
|
|
|
|
}
|
|
|
|
if (files.indexOf("runners") != -1) {
|
|
|
|
forEachFile(cwd + "/runners", function(p) {
|
|
|
|
console.log(p, "***");
|
|
|
|
});
|
|
|
|
}
|
|
|
|
if (files.indexOf("snippets") != -1) {
|
|
|
|
forEachFile(cwd + "/snippets", function(p) {
|
|
|
|
console.log(p, "***");
|
|
|
|
});
|
|
|
|
}
|
2015-04-04 01:07:31 +00:00
|
|
|
if (files.indexOf("themes") != -1) {
|
2015-04-13 19:44:42 +00:00
|
|
|
forEachFile(cwd + "/themes", function(p) {
|
|
|
|
console.log(p, "***");
|
|
|
|
});
|
|
|
|
}
|
|
|
|
if (files.indexOf("template") != -1) {
|
|
|
|
forEachFile(cwd + "/template", function(p) {
|
|
|
|
console.log(p, "***");
|
|
|
|
});
|
2015-04-04 01:07:31 +00:00
|
|
|
}
|
|
|
|
|
2015-04-13 19:44:42 +00:00
|
|
|
|
|
|
|
result.code += (function() {
|
|
|
|
extraCode
|
|
|
|
|
|
|
|
}).toString().replace(/^.*{|}$/g, "")
|
|
|
|
.replace("extraCode", extraCode);
|
|
|
|
|
|
|
|
next();
|
2015-04-04 01:07:31 +00:00
|
|
|
});
|
|
|
|
},
|
2015-04-13 19:44:42 +00:00
|
|
|
function(next) {
|
|
|
|
fs.writeFile("__packed__.js", result.code, "utf8", next);
|
|
|
|
},
|
2015-04-04 01:07:31 +00:00
|
|
|
function(next) {
|
|
|
|
packedFiles.push(cwd + "/themes");
|
|
|
|
zip(packedFiles);
|
|
|
|
}
|
|
|
|
]);
|
2015-03-29 23:15:52 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
function zip(ignore){
|
2015-04-04 01:07:31 +00:00
|
|
|
zipFilePath = join(os.tmpDir(), json.name + "@" + json.version) + ".tar.gz";
|
2015-02-10 19:41:24 +00:00
|
|
|
var tarArgs = ["-zcvf", zipFilePath, "."];
|
|
|
|
var c9ignore = process.env.HOME + "/.c9/.c9ignore";
|
2015-04-04 01:07:31 +00:00
|
|
|
if (process.platform == "win32") {
|
|
|
|
tarArgs[1]= zipFilePath.replace(/\\/g, "/").replace(/^(\w):/, "/$1");
|
|
|
|
c9ignore = c9ignore.replace(/\\/g, "/");
|
|
|
|
}
|
2015-02-10 19:41:24 +00:00
|
|
|
fs.exists(c9ignore, function (exists) {
|
|
|
|
if (exists) {
|
|
|
|
tarArgs.push("--exclude-from=" + c9ignore);
|
|
|
|
}
|
2015-04-04 01:07:31 +00:00
|
|
|
ignore.forEach(function(p) {
|
|
|
|
p = Path.relative(cwd, p);
|
|
|
|
if (!/^\.+\//.test(p)) {
|
|
|
|
tarArgs.push("--exclude=./" + p);
|
|
|
|
}
|
|
|
|
});
|
2015-04-13 19:44:42 +00:00
|
|
|
// console.log(tarArgs)
|
2015-04-04 01:07:31 +00:00
|
|
|
proc.spawn(TAR, {
|
|
|
|
args: tarArgs,
|
|
|
|
cwd: cwd
|
2015-02-10 19:41:24 +00:00
|
|
|
}, function(err, p){
|
|
|
|
if (err) return callback(err);
|
|
|
|
|
|
|
|
if (verbose) {
|
|
|
|
p.stdout.on("data", function(c){
|
|
|
|
process.stdout.write(c.toString("utf8"));
|
|
|
|
});
|
|
|
|
p.stderr.on("data", function(c){
|
|
|
|
process.stderr.write(c.toString("utf8"));
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
p.on("exit", function(code){
|
|
|
|
if (code !== 0)
|
|
|
|
return callback(new Error("ERROR: Could not package directory"));
|
|
|
|
|
|
|
|
console.log("Built package", json.name + "@" + json.version);
|
|
|
|
|
2015-04-04 01:07:31 +00:00
|
|
|
if (dryRun) return callback(1);
|
|
|
|
|
2015-02-10 19:41:24 +00:00
|
|
|
upload();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
// Update c9.io with the new version being published.
|
|
|
|
function upload(){
|
|
|
|
// Check if the plugin is already registered
|
|
|
|
if (verbose)
|
|
|
|
console.log("Uploading package " + json.name);
|
|
|
|
|
|
|
|
api.packages.get(json.name, function(err, pkg){
|
|
|
|
if (err) {} // Ignore error, if we don't get a response it means this package hasn't been published yet
|
|
|
|
|
|
|
|
if (!pkg || pkg.error) {
|
|
|
|
if (verbose)
|
|
|
|
console.log("Package not registered, creating new.");
|
|
|
|
|
|
|
|
// Registers the package name on c9.io if it is being published for the first time.
|
|
|
|
api.user.get("", function(err, user){
|
|
|
|
if (err) return callback(new Error("ERROR: Failed to get user details from API - " + stringifyError(err)));
|
|
|
|
|
|
|
|
api.packages.post("", {
|
|
|
|
contentType: "application/json",
|
|
|
|
body: {
|
|
|
|
name: json.name,
|
|
|
|
description: json.description,
|
|
|
|
owner_type: "user", // @TODO implement this when adding orgs
|
|
|
|
owner_id: parseInt(user.id),
|
|
|
|
permissions: json.permissions || "world",
|
|
|
|
categories: json.categories,
|
|
|
|
repository: json.repository,
|
|
|
|
longname: json.longname,
|
|
|
|
website: json.website,
|
|
|
|
screenshots: json.screenshots || [],
|
|
|
|
pricing: json.pricing || {}
|
|
|
|
}
|
|
|
|
}, function(err, pkg){
|
|
|
|
if (err)
|
|
|
|
return callback(new Error("ERROR: Failed to upload new package to API - "
|
|
|
|
+ stringifyError(err)));
|
|
|
|
|
|
|
|
next(pkg);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if (verbose)
|
|
|
|
console.log("Plugin already registered, updating.");
|
|
|
|
|
|
|
|
api.packages.put(json.name, {
|
|
|
|
contentType: "application/json",
|
|
|
|
body: {
|
|
|
|
permissions: json.permissions,
|
|
|
|
categories: json.categories,
|
|
|
|
repository: json.repository,
|
|
|
|
longname: json.longname,
|
|
|
|
website: json.website,
|
|
|
|
description: json.description,
|
|
|
|
screenshots: json.screenshots,
|
|
|
|
pricing: json.pricing,
|
|
|
|
enabled: true
|
|
|
|
}
|
|
|
|
}, function(err, pkg){
|
|
|
|
if (err)
|
|
|
|
return callback(new Error("ERROR: Failed to update existing package - "
|
|
|
|
+ stringifyError(err)));
|
|
|
|
if (verbose)
|
|
|
|
console.log("Successfully updated existing package");
|
|
|
|
|
|
|
|
next(pkg);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
function next(pkg){
|
|
|
|
// Create Version
|
|
|
|
if (verbose)
|
|
|
|
console.log("Sending new version ", json.version);
|
|
|
|
|
|
|
|
var form = new FormData();
|
|
|
|
form.append('version', json.version);
|
|
|
|
form.append('options', JSON.stringify(json.plugins));
|
|
|
|
form.append('package', fs.createReadStream(zipFilePath));
|
|
|
|
|
|
|
|
var path = "/packages/" + json.name
|
|
|
|
+ "/versions?access_token="
|
|
|
|
+ encodeURIComponent(auth.accessToken);
|
|
|
|
var host = APIHOST.split(":")[0]
|
|
|
|
var port = parseInt(APIHOST.split(":")[1]) || null;
|
|
|
|
|
|
|
|
var request = http.request({
|
|
|
|
agent: false,
|
|
|
|
method: "post",
|
|
|
|
host: host,
|
|
|
|
port: port,
|
|
|
|
path: path,
|
|
|
|
auth: BASICAUTH,
|
|
|
|
headers: form.getHeaders()
|
|
|
|
});
|
|
|
|
|
|
|
|
form.pipe(request);
|
|
|
|
|
|
|
|
request.on('response', function(res) {
|
|
|
|
if (res.statusCode != 200)
|
|
|
|
return callback(new Error("ERROR: Unknown Error:" + res.statusCode));
|
|
|
|
|
|
|
|
// Create Version Complete
|
|
|
|
callback(null, json);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
function unpublish(callback){
|
|
|
|
var packagePath = process.cwd() + "/package.json";
|
|
|
|
fs.readFile(packagePath, function(err, data){
|
|
|
|
if (err) return callback(err); // @TODO package.json not found
|
|
|
|
|
|
|
|
var json;
|
|
|
|
try { json = JSON.parse(data); }
|
|
|
|
catch(e) {
|
|
|
|
return callback(new Error("ERROR: Could not parse package.json: ", e.message));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!json.name)
|
|
|
|
return callback(new Error("ERROR: Missing name property in package.json"));
|
|
|
|
|
|
|
|
api.packages.put(json.name + "/disable", {}, callback);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
function install(packageName, options, callback){
|
|
|
|
// Call install url
|
|
|
|
var parts = packageName.split("@");
|
|
|
|
var name = parts[0];
|
|
|
|
var version = parts[1];
|
|
|
|
var repository;
|
|
|
|
|
|
|
|
if (!version || options.debug) {
|
|
|
|
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);
|
|
|
|
|
|
|
|
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) ;
|
|
|
|
if (exists) {
|
|
|
|
if (!force)
|
|
|
|
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)
|
|
|
|
return callback(new Error("No version found for this package"));
|
|
|
|
|
|
|
|
if (options.local) {
|
|
|
|
if (verbose)
|
|
|
|
console.log("Installing package locally");
|
|
|
|
|
|
|
|
prepareDirectory(function(err, packagePath){
|
|
|
|
if (err) return callback(err);
|
|
|
|
|
|
|
|
// 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:" + res.statusCode));
|
|
|
|
|
|
|
|
if (verbose)
|
|
|
|
console.log("Unpacking", gzPath, "to", packagePath);
|
|
|
|
|
|
|
|
// Untargz package
|
|
|
|
proc.spawn(TAR, {
|
|
|
|
args: ["-C", packagePath, "-zxvf", gzPath]
|
|
|
|
}, function(err, p){
|
|
|
|
if (err) return callback(err);
|
|
|
|
|
|
|
|
if (verbose) {
|
|
|
|
p.stdout.on("data", function(c){
|
|
|
|
process.stdout.write(c.toString("utf8"));
|
|
|
|
});
|
|
|
|
p.stderr.on("data", function(c){
|
|
|
|
process.stderr.write(c.toString("utf8"));
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
p.on("exit", function(code){
|
|
|
|
var err = code !== 0
|
|
|
|
? new Error("Failed to unpack package")
|
|
|
|
: null;
|
2015-04-01 14:51:46 +00:00
|
|
|
if (err) return callback(err);
|
2015-02-10 19:41:24 +00:00
|
|
|
|
2015-04-01 02:15:02 +00:00
|
|
|
proc.spawn(join(process.env.HOME, ".c9/node/bin/npm"), {
|
|
|
|
args: ["install"],
|
|
|
|
cwd: packagePath
|
|
|
|
}, function(err, p){
|
|
|
|
if (err) return callback(err);
|
|
|
|
|
|
|
|
if (verbose) {
|
|
|
|
p.stdout.on("data", function(c){
|
|
|
|
process.stdout.write(c.toString("utf8"));
|
|
|
|
});
|
|
|
|
p.stderr.on("data", function(c){
|
|
|
|
process.stderr.write(c.toString("utf8"));
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
p.on("exit", function(code){
|
|
|
|
// Done
|
|
|
|
callback(err, {
|
|
|
|
version: version
|
|
|
|
});
|
|
|
|
});
|
2015-02-10 19:41:24 +00:00
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
else if (options.debug) {
|
|
|
|
if (verbose)
|
|
|
|
console.log("Installing debug version of package");
|
|
|
|
|
|
|
|
prepareDirectory(function(err, packagePath){
|
|
|
|
if (err) return callback(err);
|
|
|
|
|
|
|
|
if (verbose)
|
|
|
|
console.log("Cloning repository: ", repository);
|
|
|
|
|
|
|
|
// Git clone repository
|
|
|
|
var scm = SCM[repository.type];
|
|
|
|
proc.spawn(scm.binary, {
|
|
|
|
args: [scm.clone, repository.url, packagePath]
|
|
|
|
}, function(err, p){
|
|
|
|
if (err) return callback(err);
|
|
|
|
|
|
|
|
if (verbose) {
|
|
|
|
p.stdout.on("data", function(c){
|
|
|
|
process.stdout.write(c.toString("utf8"));
|
|
|
|
});
|
|
|
|
p.stderr.on("data", function(c){
|
|
|
|
process.stderr.write(c.toString("utf8"));
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
p.on("exit", function(code){
|
|
|
|
var err = code !== 0
|
|
|
|
? new Error("Failed to clone package from repository. Do you have access?")
|
|
|
|
: null;
|
|
|
|
|
|
|
|
// Done
|
|
|
|
callback(err);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if (verbose)
|
|
|
|
console.log("Notifying c9.io that packages needs to be installed");
|
|
|
|
|
|
|
|
var endpoint = options.global ? api.user : api.project;
|
|
|
|
var url = "install/" + packageName + "/" + version;
|
|
|
|
|
|
|
|
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;
|
|
|
|
proc.spawn("rm", {
|
|
|
|
args: ["-rf", packagePath]
|
|
|
|
}, function(err, p){
|
|
|
|
if (err) return callback(err);
|
|
|
|
|
|
|
|
if (verbose) {
|
|
|
|
p.stdout.on("data", function(c){
|
|
|
|
process.stdout.write(c.toString("utf8"));
|
|
|
|
});
|
|
|
|
p.stderr.on("data", function(c){
|
|
|
|
process.stderr.write(c.toString("utf8"));
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
p.on("exit", function(code){
|
|
|
|
var err = code !== 0
|
|
|
|
? new Error("Failed to remove package.")
|
|
|
|
: null;
|
|
|
|
|
|
|
|
// if debug > see if should be installed and put back original
|
|
|
|
// @TODO
|
|
|
|
|
|
|
|
// Done
|
|
|
|
callback(err);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
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 + '/';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/***** 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 define API *****/
|
|
|
|
|
|
|
|
/**
|
|
|
|
*
|
|
|
|
**/
|
|
|
|
plugin.freezePublicAPI({
|
|
|
|
/**
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
publish: publish,
|
|
|
|
|
|
|
|
/**
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
unpublish: unpublish,
|
|
|
|
|
|
|
|
/**
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
install: install,
|
|
|
|
|
|
|
|
/**
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
uninstall: uninstall,
|
|
|
|
|
|
|
|
/**
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
list: list
|
|
|
|
});
|
|
|
|
|
|
|
|
register(null, {
|
|
|
|
"cli.publish": plugin
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
});
|