2015-02-10 19:41:24 +00:00
|
|
|
define(function(require, exports, module) {
|
2015-04-27 17:07:49 +00:00
|
|
|
main.consumes = ["Plugin", "cli_commands", "proc", "api", "auth"];
|
2015-02-10 19:41:24 +00:00
|
|
|
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-04-24 23:24:10 +00:00
|
|
|
var createTag = 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-04-24 23:24:10 +00:00
|
|
|
},
|
|
|
|
"tag" : {
|
|
|
|
"description": "Create git tag for published version",
|
|
|
|
"alias": "t",
|
|
|
|
"default": false,
|
|
|
|
"boolean": true
|
2015-02-10 19:41:24 +00:00
|
|
|
}
|
|
|
|
},
|
|
|
|
check: function(argv) {
|
2015-04-24 23:24:10 +00:00
|
|
|
// if (argv._.length < 2 && !argv["newversion"] && !argv["dry-run"])
|
|
|
|
// throw new Error("Missing version");
|
2015-02-10 19:41:24 +00:00
|
|
|
},
|
|
|
|
exec: function(argv) {
|
|
|
|
verbose = argv["verbose"];
|
|
|
|
force = argv["force"];
|
2015-04-04 01:07:31 +00:00
|
|
|
dryRun = argv["dry-run"];
|
2015-04-24 23:24:10 +00:00
|
|
|
createTag = argv["tag"];
|
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);
|
|
|
|
}
|
2015-04-21 23:25:29 +00:00
|
|
|
else if (!dryRun) {
|
2015-02-10 19:41:24 +00:00
|
|
|
console.log("Succesfully published version", data.version);
|
|
|
|
process.exit(0);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2015-04-24 23:24:10 +00:00
|
|
|
cmd.addCommand({
|
2015-04-21 23:25:29 +00:00
|
|
|
name: "build",
|
2015-04-27 00:29:26 +00:00
|
|
|
info: " Builds development version of package to load in non-debug mode.",
|
2015-04-21 23:25:29 +00:00
|
|
|
usage: "[--devel]",
|
|
|
|
options: {
|
|
|
|
"devel" : {
|
|
|
|
"description": "",
|
|
|
|
"alias": "d",
|
|
|
|
"default": false,
|
|
|
|
"boolean": true
|
|
|
|
}
|
|
|
|
},
|
|
|
|
exec: function(argv) {
|
|
|
|
if (argv["devel"]) {
|
|
|
|
var code = function(argument) {
|
|
|
|
/* TODO explain */
|
|
|
|
define("plugins/PACKAGE_NAME/__installed__", [],[
|
|
|
|
"plugins/PACKAGE_NAME/__debug__"
|
|
|
|
]);
|
|
|
|
define("plugins/PACKAGE_NAME/__debug__",[], function(require, exports, module) {
|
|
|
|
main.consumes = ["plugin.debug"];
|
|
|
|
main.provides = [];
|
|
|
|
return main;
|
|
|
|
|
|
|
|
function main(options, imports, register) {
|
|
|
|
var debug = imports["plugin.debug"];
|
|
|
|
debug.loadPackage("PACKAGE_NAME");
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}.toString();
|
|
|
|
var cwd = process.cwd();
|
|
|
|
var packageName = basename(cwd);
|
|
|
|
var indent = code.match(/\n\r?(\s*)/)[1].length;
|
|
|
|
code = code
|
|
|
|
.replace(/\r/g, "")
|
|
|
|
.replace(new RegExp("^ {" + indent + "}", "gm"), "")
|
|
|
|
.replace(/^.*?{|}$/g, "")
|
|
|
|
.trim()
|
|
|
|
.replace(/PACKAGE_NAME/g, packageName);
|
|
|
|
|
2015-04-27 17:07:49 +00:00
|
|
|
fs.writeFileSync(cwd + "/__installed__.js", code, "utf8");
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
dryRun = true;
|
|
|
|
publish({local: true}, function(){});
|
2015-04-21 23:25:29 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2015-02-10 19:41:24 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
/***** Methods *****/
|
|
|
|
|
|
|
|
function stringifyError(err){
|
|
|
|
return (verbose ? JSON.stringify(err, 4, " ") : (typeof err == "string" ? err : err.message));
|
|
|
|
}
|
|
|
|
|
2015-04-21 23:25:29 +00:00
|
|
|
function publish(options, callback) {
|
|
|
|
if (typeof options != "object")
|
|
|
|
options = {version: options};
|
|
|
|
|
|
|
|
var version = options.version;
|
2015-02-10 19:41:24 +00:00
|
|
|
var cwd = process.cwd();
|
|
|
|
var packagePath = cwd + "/package.json";
|
2015-04-24 23:24:10 +00:00
|
|
|
fs.readFile(packagePath, "utf8", function(err, data){
|
2015-02-10 19:41:24 +00:00
|
|
|
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
|
2015-04-27 19:07:00 +00:00
|
|
|
if (json.private)
|
|
|
|
return callback(new Error("ERROR: Private flag in package.json prevents from publishing"));
|
2015-02-10 19:41:24 +00:00
|
|
|
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.repository)
|
|
|
|
return callback(new Error("ERROR: Missing repository property in package.json"));
|
2015-04-27 19:59:45 +00:00
|
|
|
if (!json.repository.url)
|
|
|
|
return callback(new Error("ERROR: Missing repository.url property in package.json"));
|
2015-02-10 19:41:24 +00:00
|
|
|
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."));
|
|
|
|
}
|
|
|
|
|
2015-04-27 19:12:12 +00:00
|
|
|
if (json.description)
|
2015-04-27 19:43:38 +00:00
|
|
|
console.warn("WARNING: Description property in package.json will be ignored. README.md will be used.");
|
2015-04-27 19:12:12 +00:00
|
|
|
|
2015-04-27 19:51:14 +00:00
|
|
|
var originalDesc = json.description;
|
2015-04-28 22:16:55 +00:00
|
|
|
json.description = fs.readFileSync(join(cwd, "README.md"), "utf8")
|
|
|
|
.replace(/^\#.*\n*/, "");
|
2015-04-27 17:07:49 +00:00
|
|
|
|
2015-02-10 19:41:24 +00:00
|
|
|
// Validate plugins
|
|
|
|
var plugins = {};
|
2015-03-06 20:11:52 +00:00
|
|
|
fs.readdirSync(cwd).forEach(function(filename) {
|
2015-04-15 23:30:14 +00:00
|
|
|
if (/(__\w*__|_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;
|
|
|
|
}
|
2015-04-21 01:48:05 +00:00
|
|
|
else if (!fs.existsSync(join(cwd, name.replace(/\.js$/, "_test.js")))) {
|
|
|
|
console.warn("ERROR: Plugin '" + name + "' has no test associated with it. There must be a file called '" + name + "_test.js' containing tests.");
|
|
|
|
failed = true;
|
|
|
|
}
|
2015-02-10 19:41:24 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
if (failed)
|
|
|
|
return callback(new Error());
|
|
|
|
|
2015-04-21 23:25:29 +00:00
|
|
|
if (warned && !force && !dryRun)
|
2015-02-10 19:41:24 +00:00
|
|
|
return callback(new Error("Use --force to ignore these warnings."));
|
|
|
|
|
2015-04-24 23:24:10 +00:00
|
|
|
if (version) {
|
2015-04-21 23:25:29 +00:00
|
|
|
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(".");
|
2015-02-10 19:41:24 +00:00
|
|
|
}
|
|
|
|
|
2015-04-26 18:18:40 +00:00
|
|
|
return build();
|
2015-02-10 19:41:24 +00:00
|
|
|
|
2015-04-26 18:18:40 +00:00
|
|
|
function updatePackageJSON(next) {
|
|
|
|
if (!version)
|
|
|
|
return next();
|
|
|
|
|
2015-04-27 19:51:14 +00:00
|
|
|
// Reset description
|
|
|
|
var pkgJson = Object.create(json);
|
|
|
|
pkgJson.description = originalDesc;
|
|
|
|
|
2015-04-26 18:18:40 +00:00
|
|
|
// Write the package.json file
|
|
|
|
var indent = data.match(/{\n\r?^ {4}"/) ? 4 : 2;
|
2015-04-27 19:51:14 +00:00
|
|
|
var newData = JSON.stringify(pkgJson, null, indent);
|
|
|
|
fs.writeFile(cwd + "/.c9/.build/pacage.json", newData, function(){
|
2015-04-26 18:18:40 +00:00
|
|
|
if (dryRun)
|
|
|
|
return next(); // if dry-run is passed only update path in .build
|
|
|
|
fs.writeFile(packagePath, newData, function(err){
|
|
|
|
if (err) return callback(err);
|
|
|
|
return next();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
2015-04-24 22:15:25 +00:00
|
|
|
|
2015-02-10 19:41:24 +00:00
|
|
|
// Build the package
|
|
|
|
// @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) {
|
2015-04-14 00:44:47 +00:00
|
|
|
return "plugins/" + packageName + "/" + p.replace(/\.js$/, "");
|
2015-03-29 23:15:52 +00:00
|
|
|
});
|
2015-04-14 00:44:47 +00:00
|
|
|
var result, packedFiles = [], staticPlugin;
|
2015-04-13 21:08:51 +00:00
|
|
|
async.series([
|
|
|
|
function(next) {
|
|
|
|
fs.readdir(cwd, function(err, files) {
|
|
|
|
if (err)
|
|
|
|
return next();
|
|
|
|
var extraCode = [];
|
|
|
|
function forEachFile(dir, f) {
|
|
|
|
try {
|
|
|
|
fs.readdirSync(dir).forEach(function(filename) {
|
|
|
|
var data = fs.readFileSync(dir + "/" + filename, "utf8");
|
|
|
|
f(filename, data);
|
2015-04-13 19:44:42 +00:00
|
|
|
});
|
2015-04-13 21:08:51 +00:00
|
|
|
} catch(e) {
|
|
|
|
console.error(e);
|
2015-04-13 19:44:42 +00:00
|
|
|
}
|
2015-04-13 21:08:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (files.indexOf("builders") != -1) {
|
|
|
|
forEachFile(cwd + "/builders", function(filename, data) {
|
2015-04-14 00:44:47 +00:00
|
|
|
packedFiles.push(cwd + "/builders/" + filename);
|
2015-04-13 21:08:51 +00:00
|
|
|
extraCode.push({
|
|
|
|
type: "builders",
|
|
|
|
filename: filename,
|
|
|
|
data: data
|
2015-04-13 19:44:42 +00:00
|
|
|
});
|
2015-04-13 21:08:51 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
if (files.indexOf("keymaps") != -1) {
|
|
|
|
forEachFile(cwd + "/keymaps", function(filename, data) {
|
2015-04-14 00:44:47 +00:00
|
|
|
packedFiles.push(cwd + "/keymaps/" + filename);
|
2015-04-13 21:08:51 +00:00
|
|
|
extraCode.push({
|
|
|
|
type: "keymaps",
|
|
|
|
filename: filename,
|
|
|
|
data: data
|
2015-04-13 19:44:42 +00:00
|
|
|
});
|
2015-04-13 21:08:51 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
if (files.indexOf("modes") != -1) {
|
|
|
|
forEachFile(cwd + "/modes", function(filename, data) {
|
|
|
|
if (/(?:_highlight_rules|_test|_worker|_fold|_behaviou?r).js$/.test(filename))
|
|
|
|
return;
|
|
|
|
var firstLine = data.split("\n", 1)[0];
|
|
|
|
extraCode.push({
|
|
|
|
type: "modes",
|
|
|
|
filename: filename,
|
|
|
|
data: firstLine
|
2015-04-13 19:44:42 +00:00
|
|
|
});
|
2015-04-13 21:08:51 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
if (files.indexOf("outline") != -1) {
|
|
|
|
forEachFile(cwd + "/outline", function(filename, data) {
|
2015-04-14 00:44:47 +00:00
|
|
|
packedFiles.push(cwd + "/outline/" + filename);
|
2015-04-13 21:08:51 +00:00
|
|
|
extraCode.push({
|
|
|
|
type: "outline",
|
|
|
|
filename: filename,
|
|
|
|
data: data
|
2015-04-13 19:44:42 +00:00
|
|
|
});
|
2015-04-13 21:08:51 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
if (files.indexOf("runners") != -1) {
|
|
|
|
forEachFile(cwd + "/runners", function(filename, data) {
|
2015-04-14 00:44:47 +00:00
|
|
|
packedFiles.push(cwd + "/runners/" + filename);
|
2015-04-13 21:08:51 +00:00
|
|
|
extraCode.push({
|
|
|
|
type: "runners",
|
|
|
|
filename: filename,
|
|
|
|
data: data
|
2015-04-13 19:44:42 +00:00
|
|
|
});
|
2015-04-13 21:08:51 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
if (files.indexOf("snippets") != -1) {
|
|
|
|
forEachFile(cwd + "/snippets", function(filename, data) {
|
2015-04-14 00:44:47 +00:00
|
|
|
packedFiles.push(cwd + "/snippets/" + filename);
|
2015-04-13 21:08:51 +00:00
|
|
|
extraCode.push({
|
|
|
|
type: "snippets",
|
|
|
|
filename: filename,
|
|
|
|
data: data
|
2015-04-13 19:44:42 +00:00
|
|
|
});
|
2015-04-13 21:08:51 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
if (files.indexOf("themes") != -1) {
|
|
|
|
forEachFile(cwd + "/themes", function(filename, data) {
|
2015-04-14 00:44:47 +00:00
|
|
|
packedFiles.push(cwd + "/themes/" + filename);
|
2015-04-13 21:08:51 +00:00
|
|
|
extraCode.push({
|
|
|
|
type: "themes",
|
|
|
|
filename: filename,
|
|
|
|
data: data
|
2015-04-13 19:44:42 +00:00
|
|
|
});
|
2015-04-13 21:08:51 +00:00
|
|
|
});
|
|
|
|
}
|
2015-04-14 00:44:47 +00:00
|
|
|
if (files.indexOf("templates") != -1) {
|
|
|
|
forEachFile(cwd + "/templates", function(filename, data) {
|
|
|
|
packedFiles.push(cwd + "/templates/" + filename);
|
2015-04-13 21:08:51 +00:00
|
|
|
extraCode.push({
|
2015-04-14 00:44:47 +00:00
|
|
|
type: "templates",
|
2015-04-13 21:08:51 +00:00
|
|
|
filename: filename,
|
|
|
|
data: data
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2015-04-21 23:25:29 +00:00
|
|
|
packedFiles.push(cwd + "/__installed__.js");
|
|
|
|
|
2015-04-15 22:18:02 +00:00
|
|
|
if (json.installer) {
|
2015-04-16 22:20:53 +00:00
|
|
|
var path = join(cwd, json.installer);
|
|
|
|
var installerCode = fs.readFileSync(path, "utf8");
|
|
|
|
|
|
|
|
var m = installerCode.match(/\.version\s*=\s*(\d+)/g);
|
|
|
|
|
|
|
|
var installerVersion = m && m[0];
|
|
|
|
if (!installerVersion)
|
|
|
|
return callback(new Error("ERROR: missing installer version in " + json.installer));
|
2015-04-15 22:18:02 +00:00
|
|
|
extraCode.push({
|
|
|
|
type: "installer",
|
2015-04-16 22:20:53 +00:00
|
|
|
filename: json.installer,
|
|
|
|
data: version
|
2015-04-15 22:18:02 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2015-04-13 21:08:51 +00:00
|
|
|
if (!extraCode.length)
|
|
|
|
return next();
|
2015-04-13 19:44:42 +00:00
|
|
|
|
2015-04-13 21:08:51 +00:00
|
|
|
var code = (function() {
|
2015-04-14 00:44:47 +00:00
|
|
|
define(function(require, exports, module) {
|
2015-04-13 21:08:51 +00:00
|
|
|
main.consumes = [
|
|
|
|
"Plugin", "plugin.debug"
|
|
|
|
];
|
|
|
|
main.provides = [];
|
|
|
|
return main;
|
|
|
|
function main(options, imports, register) {
|
|
|
|
var debug = imports["plugin.debug"];
|
2015-04-14 00:44:47 +00:00
|
|
|
var Plugin = imports.Plugin;
|
2015-04-13 21:08:51 +00:00
|
|
|
var plugin = new Plugin();
|
2015-04-16 22:20:53 +00:00
|
|
|
plugin.version = "VERSION";
|
|
|
|
plugin.on("load", function load() {
|
|
|
|
extraCode.forEach(function(x) {
|
2015-04-16 23:57:57 +00:00
|
|
|
debug.addStaticPlugin(x.type, "PACKAGE_NAME", x.filename, x.data, plugin);
|
2015-04-16 22:20:53 +00:00
|
|
|
});
|
2015-04-13 21:08:51 +00:00
|
|
|
});
|
|
|
|
|
2015-04-17 00:29:27 +00:00
|
|
|
plugin.load("PACKAGE_NAME.bundle");
|
2015-04-16 22:20:53 +00:00
|
|
|
|
2015-04-13 21:08:51 +00:00
|
|
|
register(null, {});
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}).toString();
|
|
|
|
|
|
|
|
var indent = code.match(/\n\r?(\s*)/)[1].length;
|
|
|
|
code = code
|
|
|
|
.replace(/\r/g, "")
|
|
|
|
.replace(new RegExp("^ {" + indent + "}", "gm"), "")
|
|
|
|
.replace(/^.*?{|}$/g, "")
|
2015-04-16 23:57:57 +00:00
|
|
|
.replace(/PACKAGE_NAME/g, packageName)
|
2015-04-16 22:20:53 +00:00
|
|
|
.replace(/VERSION/g, json.version)
|
2015-04-13 21:08:51 +00:00
|
|
|
.replace(/^(\s*)extraCode/gm, function(_, indent) {
|
|
|
|
return JSON.stringify(extraCode, null, 4)
|
|
|
|
.replace(/^/gm, indent);
|
|
|
|
});
|
|
|
|
|
|
|
|
staticPlugin = {
|
|
|
|
source: code,
|
2015-04-14 00:44:47 +00:00
|
|
|
id: "plugins/" + packageName + "/__static__",
|
2015-04-13 21:08:51 +00:00
|
|
|
path: ""
|
|
|
|
};
|
|
|
|
next();
|
|
|
|
});
|
|
|
|
},
|
|
|
|
|
|
|
|
function(next) {
|
|
|
|
var build = require("architect-build/build");
|
2015-04-14 00:44:47 +00:00
|
|
|
var paths = {};
|
|
|
|
paths["plugins/" + packageName] = cwd;
|
2015-04-14 19:03:54 +00:00
|
|
|
|
|
|
|
var additional = [];
|
2015-04-14 20:02:27 +00:00
|
|
|
var packedConfig = config.slice();
|
2015-04-14 19:03:54 +00:00
|
|
|
if (staticPlugin) {
|
|
|
|
additional.push(staticPlugin);
|
|
|
|
packedConfig.push(staticPlugin.id);
|
|
|
|
}
|
2015-04-15 23:30:14 +00:00
|
|
|
var path = "plugins/" + packageName + "/__installed__";
|
2015-04-14 19:03:54 +00:00
|
|
|
additional.push({
|
|
|
|
id: path,
|
|
|
|
source: 'define("' + path + '", [],' +
|
2015-04-15 17:14:44 +00:00
|
|
|
JSON.stringify(packedConfig, null, 4) + ');',
|
2015-04-14 19:03:54 +00:00
|
|
|
literal : true,
|
|
|
|
order: -1
|
|
|
|
});
|
|
|
|
|
2015-04-13 21:08:51 +00:00
|
|
|
build(config, {
|
2015-04-14 19:03:54 +00:00
|
|
|
additional: additional,
|
2015-04-13 21:08:51 +00:00
|
|
|
paths: paths,
|
|
|
|
enableBrowser: true,
|
|
|
|
includeConfig: false,
|
|
|
|
noArchitect: true,
|
|
|
|
compress: !dryRun,
|
|
|
|
obfuscate: true,
|
|
|
|
oneLine: true,
|
|
|
|
filter: [],
|
|
|
|
ignore: [],
|
|
|
|
withRequire: false,
|
|
|
|
stripLess: false,
|
|
|
|
basepath: base,
|
|
|
|
}, function(e, r) {
|
|
|
|
result = r;
|
2015-04-14 00:44:47 +00:00
|
|
|
result.sources.forEach(function(m) {
|
2015-04-14 19:03:54 +00:00
|
|
|
m.file && packedFiles.push(m.file);
|
2015-04-04 01:07:31 +00:00
|
|
|
});
|
2015-04-13 21:08:51 +00:00
|
|
|
next();
|
|
|
|
});
|
|
|
|
},
|
|
|
|
function(next) {
|
2015-04-24 21:59:55 +00:00
|
|
|
if (options.local)
|
|
|
|
fs.writeFile(cwd + "__installed__.js", result.code, "utf8", callback);
|
|
|
|
next();
|
2015-04-13 21:08:51 +00:00
|
|
|
},
|
|
|
|
function(next) {
|
2015-04-24 21:59:55 +00:00
|
|
|
proc.execFile("rm", {
|
2015-04-26 18:18:40 +00:00
|
|
|
args: ["-rf", ".c9/.build"],
|
2015-04-24 21:59:55 +00:00
|
|
|
cwd: cwd
|
|
|
|
}, function() {
|
2015-04-24 22:15:25 +00:00
|
|
|
mkdirP(cwd + "/.c9/.build");
|
|
|
|
fs.writeFile(cwd + "/.c9/.build/__installed__.js", result.code, "utf8", next);
|
2015-04-24 21:59:55 +00:00
|
|
|
});
|
|
|
|
},
|
|
|
|
function(next) {
|
|
|
|
var copy = require("architect-build/copy");
|
|
|
|
|
2015-04-26 18:18:40 +00:00
|
|
|
var excludeRe = /^\.(gitignore|hgignore|git|c9|hg)$/;
|
2015-04-24 21:59:55 +00:00
|
|
|
var excludeMap = Object.create(null);
|
|
|
|
|
|
|
|
packedFiles.push(cwd + "/__installed__.js");
|
|
|
|
packedFiles.forEach(function(p) {
|
|
|
|
p = "/" + normalizePath(Path.relative(cwd, p));
|
|
|
|
excludeMap[p] = 1;
|
|
|
|
});
|
2015-04-24 22:15:25 +00:00
|
|
|
copy(cwd, cwd + "/.c9/.build", {
|
2015-04-24 21:59:55 +00:00
|
|
|
exclude: function(name, parent) {
|
|
|
|
if (excludeRe.test(name))
|
|
|
|
return true;
|
|
|
|
var fullPath = parent.substr(cwd.length) + "/" + name;
|
|
|
|
if (excludeMap[fullPath])
|
|
|
|
return true;
|
|
|
|
return false;
|
|
|
|
}
|
2015-04-26 18:18:40 +00:00
|
|
|
});
|
|
|
|
next();
|
|
|
|
},
|
|
|
|
updatePackageJSON,
|
|
|
|
function(next) {
|
2015-04-24 21:59:55 +00:00
|
|
|
zip();
|
2015-04-13 21:08:51 +00:00
|
|
|
}
|
|
|
|
]);
|
|
|
|
|
2015-03-29 23:15:52 +00:00
|
|
|
}
|
|
|
|
|
2015-04-24 21:59:55 +00:00
|
|
|
function zip(){
|
2015-04-04 01:07:31 +00:00
|
|
|
zipFilePath = join(os.tmpDir(), json.name + "@" + json.version) + ".tar.gz";
|
2015-04-24 21:59:55 +00:00
|
|
|
var tarArgs = ["-zcvf", normalizePath(zipFilePath)];
|
2015-04-14 00:44:47 +00:00
|
|
|
var c9ignore = normalizePath(process.env.HOME + "/.c9/.c9ignore");
|
2015-02-10 19:41:24 +00:00
|
|
|
fs.exists(c9ignore, function (exists) {
|
|
|
|
if (exists) {
|
|
|
|
tarArgs.push("--exclude-from=" + c9ignore);
|
|
|
|
}
|
2015-04-24 21:59:55 +00:00
|
|
|
tarArgs.push(".");
|
2015-04-04 01:07:31 +00:00
|
|
|
proc.spawn(TAR, {
|
|
|
|
args: tarArgs,
|
2015-04-24 22:15:25 +00:00
|
|
|
cwd: cwd + "/.c9/.build"
|
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"));
|
|
|
|
|
2015-04-21 23:25:29 +00:00
|
|
|
console.log("Built package", json.name + "@" + json.version +
|
|
|
|
(dryRun ? " at " + zipFilePath : ""));
|
2015-02-10 19:41:24 +00:00
|
|
|
|
2015-04-21 23:25:29 +00:00
|
|
|
if (dryRun) return callback();
|
2015-04-04 01:07:31 +00:00
|
|
|
|
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)
|
2015-04-24 23:24:10 +00:00
|
|
|
console.log("Successfully updated metadata of existing package");
|
2015-02-10 19:41:24 +00:00
|
|
|
|
|
|
|
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) {
|
2015-04-24 23:24:10 +00:00
|
|
|
// TODO better handle version exists error
|
|
|
|
if (res.statusCode == 412 && !version)
|
|
|
|
console.error("ERROR: most likely version " + json.version + " already exisits, try increasing version");
|
2015-02-10 19:41:24 +00:00
|
|
|
if (res.statusCode != 200)
|
|
|
|
return callback(new Error("ERROR: Unknown Error:" + res.statusCode));
|
|
|
|
|
2015-04-24 23:24:10 +00:00
|
|
|
commitAndPush();
|
|
|
|
});
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
function commitAndPush() {
|
|
|
|
// Create Version Complete
|
|
|
|
if (!createTag)
|
|
|
|
callback(null, json);
|
|
|
|
|
|
|
|
proc.spawn("bash", {
|
|
|
|
args: ["-c", SHELLSCRIPT, "--", json.version, normalizePath(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"));
|
2015-02-10 19:41:24 +00:00
|
|
|
});
|
|
|
|
}
|
2015-04-24 23:24:10 +00:00
|
|
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
callback(null, json);
|
|
|
|
});
|
2015-02-10 19:41:24 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
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 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 + '/';
|
|
|
|
}
|
|
|
|
}
|
2015-04-21 23:25:29 +00:00
|
|
|
|
|
|
|
function normalizePath(p) {
|
|
|
|
if (process.platform == "win32")
|
|
|
|
p = p.replace(/\\/g, "/").replace(/^(\w):/, "/$1");
|
|
|
|
return p;
|
|
|
|
}
|
2015-02-10 19:41:24 +00:00
|
|
|
|
|
|
|
/***** Lifecycle *****/
|
|
|
|
|
|
|
|
plugin.on("load", function(){
|
|
|
|
load();
|
|
|
|
});
|
|
|
|
plugin.on("enable", function(){
|
|
|
|
|
|
|
|
});
|
|
|
|
plugin.on("disable", function(){
|
|
|
|
|
|
|
|
});
|
|
|
|
plugin.on("unload", function(){
|
|
|
|
loaded = false;
|
|
|
|
verbose = false;
|
|
|
|
force = false;
|
|
|
|
});
|
|
|
|
|
2015-04-26 18:18:40 +00:00
|
|
|
/***** Register and definfe API *****/
|
2015-02-10 19:41:24 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
*
|
|
|
|
**/
|
|
|
|
plugin.freezePublicAPI({
|
|
|
|
/**
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
publish: publish,
|
|
|
|
|
|
|
|
/**
|
|
|
|
*
|
|
|
|
*/
|
2015-04-27 17:07:49 +00:00
|
|
|
unpublish: unpublish
|
2015-02-10 19:41:24 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
register(null, {
|
|
|
|
"cli.publish": plugin
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
});
|