From 06c0a50d833b1920b27bf5ca0e9b42d5203f8a94 Mon Sep 17 00:00:00 2001 From: nightwing Date: Sun, 2 Apr 2017 16:12:51 +0400 Subject: [PATCH] remove old code and add support for loading plugins from cdn --- bin/c9 | 6 +- configs/cli.js | 56 +- .../build_support/mini_require.js | 22 +- node_modules/architect/architect.js | 4 +- plugins/c9.cli.open/open.js | 9 +- plugins/c9.cli.publish/install.js | 577 ------------------ plugins/c9.cli.publish/list.js | 132 ---- plugins/c9.cli.publish/publish.git.sh | 23 - plugins/c9.cli.publish/publish.js | 437 ++----------- plugins/c9.cli.publish/publish_test.git.sh | 15 - plugins/c9.cli.publish/publish_test.js | 380 ------------ plugins/c9.cli/cli.js | 29 +- plugins/c9.ide.plugins/manager.js | 147 ++++- 13 files changed, 216 insertions(+), 1621 deletions(-) delete mode 100644 plugins/c9.cli.publish/install.js delete mode 100644 plugins/c9.cli.publish/list.js delete mode 100644 plugins/c9.cli.publish/publish.git.sh delete mode 100755 plugins/c9.cli.publish/publish_test.git.sh delete mode 100644 plugins/c9.cli.publish/publish_test.js diff --git a/bin/c9 b/bin/c9 index 9de38075..ce1d7cd1 100755 --- a/bin/c9 +++ b/bin/c9 @@ -1,11 +1,11 @@ #!/usr/bin/env node -// Architect -var architect = require("architect"); - // Add ability to load AMD modules require("amd-loader"); +// Architect +var architect = require("architect"); + architect.resolveConfig(require("../configs/cli.js")(), __dirname + "/../plugins", function (err, config) { diff --git a/configs/cli.js b/configs/cli.js index e68b4d21..98efe840 100644 --- a/configs/cli.js +++ b/configs/cli.js @@ -42,18 +42,6 @@ return [ }, { packagePath: "./c9.cli.publish/publish", - projectId: PID, - apiHost: APIHOST - }, - { - packagePath: "./c9.cli.publish/install", - projectId: PID, - apiHost: APIHOST - }, - { - packagePath: "./c9.cli.publish/list", - projectId: PID, - apiHost: APIHOST }, { packagePath: "./c9.ide.auth/auth", @@ -70,13 +58,11 @@ return [ }, { packagePath: "./c9.core/http-node" - // debug: !options.packed }, { packagePath: "./c9.cli.bridge/bridge-client", port: 17123 }, - // "./c9.cli.mount/mount", { packagePath: "./c9.cli.open/open", platform: process.platform @@ -89,35 +75,9 @@ return [ packagePath: "./c9.cli.open/restart", platform: process.platform }, - "./c9.automate/automate", - "./c9.ide.installer/commands/centos", - "./c9.ide.installer/commands/darwin", - "./c9.ide.installer/commands/bash", - "./c9.ide.installer/commands/npm", - "./c9.ide.installer/commands/npm-g", - "./c9.ide.installer/commands/pip", - "./c9.ide.installer/commands/gem", - "./c9.ide.installer/commands/zip", - "./c9.ide.installer/commands/symlink", - "./c9.ide.installer/commands/message", - { - packagePath: "./c9.ide.installer/commands/tar.gz", - bashBin: "bash" - }, - "./c9.ide.installer/commands/ubuntu", - "./c9.ide.installer/cli", - { - packagePath: "./c9.ide.installer/installer", - homeDir: process.env.HOME, - installSelfCheck: false, - installPath: process.env.HOME + "/.c9", - cli: true - }, - // "./c9.cli.sync/sync", - //"./c9.ide.keys/commands", { consumes: [], - provides: ["settings", "workspace", "cli_commands", "c9", "error_handler"], + provides: ["settings", "cli_commands", "c9", "error_handler"], setup: function(options, imports, register) { register(null, { // @todo share with ace min @@ -134,20 +94,6 @@ return [ error_handler: { log: function(){} }, - workspace: (function(){ - var ws = new EventEmitter(); - ws.connect = function(name, callback) { - callback(null, { - hostname: "54.242.22.91", - username: "ubuntu", - rootPath: "/home/ubuntu/newclient/", - setupSshConnection: function(callback) { - callback(); - } - }); - }; - return ws; - })(), cli_commands: (function(){ var cmds = new EventEmitter(); var commands = {}; diff --git a/node_modules/architect-build/build_support/mini_require.js b/node_modules/architect-build/build_support/mini_require.js index e25ccf6c..06a60e91 100644 --- a/node_modules/architect-build/build_support/mini_require.js +++ b/node_modules/architect-build/build_support/mini_require.js @@ -285,7 +285,7 @@ var config = require.config = function(cfg) { config.paths[p] = cfg.paths[p]; }); - if (cfg.useCache && global.caches && !/Firefox/i.test(navigator.userAgent)) { // Firefox promises throw too much recursion error + if (cfg.useCache && global.caches) { config.useCache = true; checkCache(); } @@ -304,32 +304,38 @@ require.resetConfig = function() { require.resetConfig(); define.undef = require.undef = function(module, recursive) { + module = normalizeName("", module); if (recursive) { var root = (module + "/").replace(/\/+$/, "/"); undefAll(root, define.errors); undefAll(root, define.loaded); undefAll(root, define.modules); + undefAll(root, define.loading); } - module = normalizeName("", module); - var path = require.toUrl(module, ".js"); + else { + undefOne(module, require.toUrl(module, ".js")); + } +}; + +function undefOne(module, path) { delete define.errors[module]; delete define.loaded[module]; - delete define.loading[module]; delete define.modules[module]; + delete define.loading[module]; delete define.fetchedUrls[path]; -}; +} function undefAll(module, hash) { Object.keys(hash).forEach(function(key) { var i = key.indexOf("!") + 1; if (key.lastIndexOf(module, 0) == 0) - require.undef(key); + undefOne(key, require.toUrl(key, ".js")); if (i) { var plugin = key.slice(0, i - 1); var resource = key.slice(i); if (resource.lastIndexOf(module, 0) == 0 || plugin.lastIndexOf(module, 0) == 0) { - require.undef(key); - require.undef(resource); + undefOne(key, require.toUrl(key, "")); + undefOne(resource, require.toUrl(resource, "")); } } }); diff --git a/node_modules/architect/architect.js b/node_modules/architect/architect.js index 37981a36..ef5b4edd 100644 --- a/node_modules/architect/architect.js +++ b/node_modules/architect/architect.js @@ -229,8 +229,8 @@ function checkCycles(config, lookup) { var unresolvedList = Object.keys(unresolved); var resolvedList = Object.keys(resolved); - var err = new Error("Could not resolve dependencies\n" - + (unresolvedList.length ? "Missing services: " + unresolvedList + var err = new Error("Could not resolve dependencies\n" + + (unresolvedList.length ? "Missing services: " + JSON.stringify(unresolved, null, 4) : "Config contains cyclic dependencies" // TODO print cycles )); err.unresolved = unresolvedList; diff --git a/plugins/c9.cli.open/open.js b/plugins/c9.cli.open/open.js index bf2168d0..c9209884 100755 --- a/plugins/c9.cli.open/open.js +++ b/plugins/c9.cli.open/open.js @@ -60,6 +60,7 @@ define(function(require, exports, module) { function open(paths, wait, callback) { try { paths = paths.map(function(path) { + path = String(path); var isDir = fs.existsSync(path) && fs.statSync(path).isDirectory(); path = PATH.resolve(path); if (path.substr(0, process.env.HOME.length) == process.env.HOME) @@ -71,9 +72,7 @@ define(function(require, exports, module) { }; }); } catch (e) { - var msg = e.message.split(",")[1].trim(); - console.error(msg.charAt(0).toUpperCase() + msg.substr(1)); - return; + return console.error(e); } var last; @@ -95,15 +94,11 @@ define(function(require, exports, module) { } } }); - // cwd = last || process.cwd(); - // else if (workspace == ".") - // cwd = process.cwd(); var message = { type: "open", workspace: "local", wait: wait, - // cwd : cwd, paths: paths }; diff --git a/plugins/c9.cli.publish/install.js b/plugins/c9.cli.publish/install.js deleted file mode 100644 index 3bfb4b79..00000000 --- a/plugins/c9.cli.publish/install.js +++ /dev/null @@ -1,577 +0,0 @@ -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] [[@] | . ]", - 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] ", // @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 - }); - } - -}); \ No newline at end of file diff --git a/plugins/c9.cli.publish/list.js b/plugins/c9.cli.publish/list.js deleted file mode 100644 index 908afaee..00000000 --- a/plugins/c9.cli.publish/list.js +++ /dev/null @@ -1,132 +0,0 @@ -define(function(require, exports, module) { - main.consumes = ["Plugin", "cli_commands", "api"]; - main.provides = ["cli.list"]; - return main; - - function main(options, imports, register) { - var Plugin = imports.Plugin; - var cmd = imports.cli_commands; - var api = imports.api; - - var BASICAUTH = process.env.C9_TEST_AUTH; - var verbose = false; - - var LIGHTBlUE = "\x1b[01;94m"; - var RESETCOLOR = "\x1b[0m"; - var PADDING = 2; - - // 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: "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, function(err) { - if (err) - console.error(err.message || err); - process.exit(err ? 1 : 0); - }); - } - }); - } - - /***** Methods *****/ - - function stringifyError(err) { - return (verbose ? JSON.stringify(err, 4, " ") : (typeof err == "string" ? err : err.message)); - } - - function pad(str, nr) { - return str + Array(Math.max(0, nr - str.length)).join(" "); - } - - 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); - } - // TODO if tty.isatty(process.stdout) use process.stdout.columns process.stdout.rows - // to give nicely wrapped output - if (asJson) { - console.log(JSON.stringify(list, 4, " ")); - return callback(null, list); - } - else { - var max = [0, 0, 0, 0]; - list.forEach(function(item) { - max[0] = Math.max(max[0], item.name.length); - max[1] = Math.max(max[1], Math.min(50, item.description.split(".")[0].length)); - max[2] = Math.max(max[2], item.name.length + 33); - max[3] = Math.max(max[3], (item.website || item.repository.url).length); - }); - list.forEach(function(item) { - console.log( - pad(item.name, max[0] + PADDING), - item.description.split(".")[0].replace(/[\r\n]/g, "")); - // pad(item.description.split(".")[0].replace(/[\r\n]/g, "-"), max[1] + PADDING)); - // LIGHTBlUE + pad("https://c9.io/packages/" + item.name, max[2] + PADDING) + RESETCOLOR, - // item.website || item.repository.url); // do not pad last item - }); - return callback(null, list); - } - }); - } - - /***** Lifecycle *****/ - - plugin.on("load", function() { - load(); - }); - plugin.on("enable", function() { - - }); - plugin.on("disable", function() { - - }); - plugin.on("unload", function() { - loaded = false; - verbose = false; - }); - - /***** Register and definfe API *****/ - - /** - * - **/ - plugin.freezePublicAPI({ - /** - * - */ - list: list - }); - - register(null, { - "cli.list": plugin - }); - } - -}); diff --git a/plugins/c9.cli.publish/publish.git.sh b/plugins/c9.cli.publish/publish.git.sh deleted file mode 100644 index bf32c8d7..00000000 --- a/plugins/c9.cli.publish/publish.git.sh +++ /dev/null @@ -1,23 +0,0 @@ -VERSION="$1" -PACKAGE_PATH="$2" -CWD="${PWD}" - -if [ ! -d .git ]; then - echo "$CWD is not a git repository" 1>&2 - exit 1 -fi - -if [ ! -f "$PACKAGE_PATH" ]; then - echo "Could not find package.json" 1>&2 - exit 1 -fi - -# Commit the package.json file -git add $PACKAGE_PATH -git commit -m "Publish version $VERSION" - -# Create a new Git tag for the version being published. -git tag $VERSION - -# Pushe the tag and current branch up to origin. -git push origin --tags \ No newline at end of file diff --git a/plugins/c9.cli.publish/publish.js b/plugins/c9.cli.publish/publish.js index 67c611a5..5043c490 100644 --- a/plugins/c9.cli.publish/publish.js +++ b/plugins/c9.cli.publish/publish.js @@ -11,7 +11,6 @@ define(function(require, exports, module) { var api = imports.api; var TEST_MODE = !!process.env.C9_TEST_MODE; - var SHELLSCRIPT = TEST_MODE ? "" : require("text!./publish.git.sh"); var TAR = "tar"; var APIHOST = options.apiHost; var BASICAUTH = process.env.C9_TEST_AUTH; @@ -32,9 +31,6 @@ define(function(require, exports, module) { 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"); var Path = require("path"); var basename = require("path").basename; var dirname = require("path").dirname; @@ -43,7 +39,6 @@ define(function(require, exports, module) { var verbose = false; var force = false; var dryRun = false; - var createTag = false; var compress = false; // Set up basic auth for api if needed @@ -59,81 +54,14 @@ define(function(require, exports, module) { if (loaded) return; loaded = true; - cmd.addCommand({ - name: "publish", - info: " Publishes a cloud9 package.", - usage: "[--verbose] [--force] [ | 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 - }, - "dry-run": { - "description": "Only build a test version", - "default": false, - "boolean": true - }, - "tag": { - "description": "Create git tag for published version", - "alias": "t", - "default": false, - "boolean": true - }, - "compress": { - "description": "Minify output with uglify.js", - "default": true, - "boolean": true - } - }, - check: function(argv) { - - }, - exec: function(argv) { - verbose = argv["verbose"]; - force = argv["force"]; - dryRun = argv["dry-run"]; - createTag = argv["tag"]; - - 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 if (!dryRun) { - console.log("Successfully published version", data.version); - process.exit(0); - } - }); - } - }); - cmd.addCommand({ name: "build", - info: " Builds development version of package to load in non-debug mode.", - usage: "[--devel]", + info: " Builds cloud9 package for loading from cdn.", + usage: "[--compress]", options: { - "devel": { - "description": "", - "alias": "d", - "default": false, - "boolean": true - }, "compress": { "description": "Minify output with uglify.js", + "alias": "c", "default": false, "boolean": true } @@ -142,116 +70,23 @@ define(function(require, exports, module) { compress = argv["compress"]; verbose = argv["verbose"]; force = argv["force"]; - 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); - - fs.writeFileSync(cwd + "/__installed__.js", code, "utf8"); - } - else { - dryRun = true; - publish({ local: true }, function(err, result) { - if (err) { - console.error(err); - if (!verbose) - console.error("\nTry running with --verbose flag for more information"); - process.exit(1); - } - console.log("Done!"); - }); - } - } - }); - - 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"]; - compress = argv["compress"]; - - unpublish( - function(err, data) { - if (err) { - console.error(err.message || err || "Terminated."); - process.exit(1); - } - else { - console.log("Successfully disabled package"); - process.exit(0); - } - }); + dryRun = true; + publish({ local: false }, function(err, result) { + if (err) { + console.error(err); + if (!verbose) + console.error("\nTry running with --verbose flag for more information"); + process.exit(1); + } + console.log("Done!"); + }); } }); } /***** 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 stringifyError(err) { - return (verbose ? JSON.stringify(err, 4, " ") : (typeof err == "string" ? err : err.message)); - } - + function addMissingValues(json) { - json.permissions = json.permissions || "world"; return json; } @@ -260,10 +95,6 @@ define(function(require, exports, module) { var cwd = process.cwd(); // Basic Validation - if (json.private) - return new Error("ERROR: Private flag in package.json prevents from publishing"); - if (!json.name) - return new Error("ERROR: Missing name property in package.json"); if (!json.name.match(/^[\w\._]+$/)) return new Error("ERROR: Package name can only contain Alphanumeric characters, periods and underscores"); if (basename(cwd) != json.name) { @@ -271,14 +102,6 @@ define(function(require, exports, module) { if (!force) return new Error("Use --force to ignore this warning."); } - if (!json.repository) - return new Error("ERROR: Missing repository property in package.json"); - if (!json.repository.url) - return new Error("ERROR: Missing repository.url property in package.json"); - if (!json.categories || json.categories.length == 0) - return new Error("ERROR: At least one category is required in package.json"); - if (!json.permissions || !json.permissions.match(/org|world/)) - return new Error("ERROR: Permissions must be 'org' or 'world'"); } function publish(options, callback) { @@ -297,11 +120,9 @@ define(function(require, exports, module) { return callback(new Error("ERROR: Could not parse package.json: ", e.message)); } - console.log("Permissions are: ", json.permissions); console.log("Data is: ", data); json = addMissingValues(json); - console.log("Permissions are: ", json.permissions); var validationError = validateConfig(json); if (validationError) return callback(validationError); @@ -310,16 +131,6 @@ define(function(require, exports, module) { if (description) console.warn("WARNING: Description property in package.json will be ignored. README.md will be used."); - // Validate README.md - if (fs.existsSync(join(cwd, "README.md"))) { - description = fs.readFileSync(join(cwd, "README.md"), "utf8") - .replace(/^\#.*\n*/, ""); - } else { - console.warn("WARNING: README.md is missing."); - if (!force) - return callback(new Error("Use --force to ignore these warnings.")); - } - // Validate plugins var plugins = {}; @@ -385,7 +196,7 @@ define(function(require, exports, module) { // Write the package.json file var indent = data.match(/{\n\r?^ {4}"/) ? 4 : 2; var newData = JSON.stringify(json, null, indent); - fs.writeFile(cwd + "/.c9/.build/package.json", newData, function() { + fs.writeFile(cwd + "/.build/package.json", newData, function() { if (dryRun) return next(); // if dry-run is passed only update path in .build fs.writeFile(packagePath, newData, function(err) { @@ -395,9 +206,6 @@ define(function(require, exports, module) { }); } - // Build the package - // @TODO add a .c9exclude file that excludes files - var zipFilePath; function build() { var base = dirname(cwd); var packageName = json.name; @@ -514,7 +322,7 @@ define(function(require, exports, module) { }); } - packedFiles.push(cwd + "/__installed__.js"); + packedFiles.push(cwd + "/package." + packageName + ".js"); if (json.installer) { var path = join(cwd, json.installer); @@ -592,16 +400,21 @@ define(function(require, exports, module) { additional.push(staticPlugin); packedConfig.push(staticPlugin.id); } - var path = "plugins/" + packageName + "/__installed__"; + var path = "plugins/" + packageName + "/package." + packageName; + + if (!json.c9) json.c9 = {}; + json.c9.plugins = packedConfig.map(function(p) { + var name = p.slice(p.lastIndexOf("/") + 1); + var options = json.plugins[name] || {}; + options.packagePath = p; + return options; + }); + json.name = packageName; + json.plugins = undefined; + additional.push({ id: path, - source: 'define("' + path + '", [],' + - JSON.stringify(packedConfig.map(function(p) { - var name = p.slice(p.lastIndexOf("/") + 1); - var options = json.plugins[name] || {}; - options.packagePath = p; - return options; - }), null, 4) + ');', + source: 'define("' + path + '", [], ' + JSON.stringify(json, null, 4) + ');', literal: true, order: -1 }); @@ -630,7 +443,7 @@ define(function(require, exports, module) { }, function(next) { if (options.local) - return fs.writeFile(cwd + "/__installed__.js", result.code, "utf8", callback); + return fs.writeFile(cwd + "/package." + packageName + ".js", result.code, "utf8", callback); next(); }, function(next) { @@ -638,17 +451,17 @@ define(function(require, exports, module) { args: ["-rf", ".c9/.build"], cwd: cwd }, function() { - mkdirP(cwd + "/.c9/.build"); - fs.writeFile(cwd + "/.c9/.build/__installed__.js", result.code, "utf8", next); + mkdirP(cwd + "/.build"); + fs.writeFile(cwd + "/.build/package." + packageName + ".js", result.code, "utf8", next); }); }, function(next) { var copy = require("architect-build/copy"); - var excludeRe = /^\.(gitignore|hgignore|git|c9|hg)$/; + var excludeRe = /^\.(\w*ignore|git|c9|hg|build)$/; var excludeMap = Object.create(null); - packedFiles.push(cwd + "/__installed__.js"); + packedFiles.push(cwd + "/package." + packageName + ".js"); packedFiles.forEach(function(p) { p = "/" + normalizePath(Path.relative(cwd, p)); excludeMap[p] = 1; @@ -657,7 +470,7 @@ define(function(require, exports, module) { if (json.installer) excludeMap["/" + normalizePath(Path.relative(cwd, json.installer))] = 0; - copy(cwd, cwd + "/.c9/.build", { + copy(cwd, cwd + "/.build", { exclude: function(name, parent) { if (excludeRe.test(name)) return true; @@ -669,182 +482,9 @@ define(function(require, exports, module) { }); next(); }, - updatePackageJSON, - function(next) { - zip(); - } + updatePackageJSON ]); - } - - function zip() { - zipFilePath = join(os.tmpDir(), json.name + "@" + json.version) + ".tar.gz"; - var tarArgs = ["-zcvf", normalizePath(zipFilePath)]; - var c9ignore = normalizePath(process.env.HOME + "/.c9/.c9ignore"); - fs.exists(c9ignore, function (exists) { - if (exists) { - tarArgs.push("--exclude-from=" + c9ignore); - } - tarArgs.push("."); - spawn(TAR, { - args: tarArgs, - cwd: cwd + "/.c9/.build" - }, function(err) { - if (err) - return callback(new Error("ERROR: Could not package directory")); - - console.log("Built package", json.name + "@" + json.version + - (dryRun ? " at " + zipFilePath : "")); - - if (dryRun) return callback(); - - 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: description, - owner_type: "user", // @TODO implement this when adding orgs - owner_id: parseInt(user.id), - permissions: json.permissions, - 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: 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 metadata of 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) { - // TODO better handle version exists error - if (res.statusCode == 412) - console.error("ERROR: most likely version " + json.version + " already exisits, try increasing version"); - if (res.statusCode != 200) - return callback(new Error("ERROR: Unknown Error:" + res.statusCode)); - - commitAndPush(); - }); - } - }); - } - - function commitAndPush() { - // Create Version Complete - if (!createTag) - callback(null, json); - - spawn("bash", { - args: ["-c", SHELLSCRIPT, "--", json.version, normalizePath(packagePath)] - }, function(err, p) { - if (err) return callback(err); - console.log("Created tag and updated package.json to version", json.version); - 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); }); } @@ -893,11 +533,6 @@ define(function(require, exports, module) { * */ publish: publish, - - /** - * - */ - unpublish: unpublish }); register(null, { diff --git a/plugins/c9.cli.publish/publish_test.git.sh b/plugins/c9.cli.publish/publish_test.git.sh deleted file mode 100755 index 3a624937..00000000 --- a/plugins/c9.cli.publish/publish_test.git.sh +++ /dev/null @@ -1,15 +0,0 @@ -set -e - -# Remove any pre-existing directory -rm -Rf /tmp/c9.ide.example -rm -Rf ~/.c9/plugins/c9.ide.example - -# Clone the test repo -git clone git@github.com:c9/c9.ide.example.git /tmp/c9.ide.example - -# Delete all the tags from remote and local -cd /tmp/c9.ide.example -git ls-remote --tags origin | awk '/^(.*)(\s+)(.*)$/ {print ":" $2}' | xargs git push origin -git tag -l | awk '/^(.*)$/ {print $1}' | xargs git tag -d - -echo "Done." \ No newline at end of file diff --git a/plugins/c9.cli.publish/publish_test.js b/plugins/c9.cli.publish/publish_test.js deleted file mode 100644 index c06a5548..00000000 --- a/plugins/c9.cli.publish/publish_test.js +++ /dev/null @@ -1,380 +0,0 @@ -/*global describe it before after beforeEach afterEach define*/ -"use strict"; -"use server"; -"use blacklist"; - -require("c9/inline-mocha")(module); - -if (typeof define === "undefined") { - require("amd-loader"); - require("../../test/setup_paths"); -} - -var fs = require("fs"); -var http = require('http'); -var baseTest = require('../c9.api/base_test'); -var child = require("child_process"); - -var expect = require("chai").expect; -var assert = require("assert"); -var sinon = require("sinon"); -var join = require("path").join; - -var HOST = "localhost:16565"; -var USERNAME = "fjakobs"; -var PASSWORD = "open"; -var BASE = "/tmp/c9.ide.example"; -var VERBOSE = false; -var PID = 123; - -describe("cli.publish", function() { - this.timeout(10000); - - var services; - - before(function(next) { - baseTest(function (err, s) { - // Services can be tested immediately by mocking API signatures params - (req, res, next) - or (user, params, callback) - services = s; - HOST = "localhost:" + s.apiPort; - next(err); - }); - }); - - describe("publish, unpublish and list", function(done) { - var packagePath = join(BASE, "package.json"); - var readmePath = join(BASE, "README.md"); - var packageJson, readmeMD; - - var json = { - "name": "c9.ide.example", - "latest": "1.0.0", - "owner": "https://api.$DOMAIN/user/2000", - "enabled": true, - "categories": [ - "example" - ], - "repository": { - "type": "git", - "url": "http://github.com/javruben/example.git" - }, - "longname": "c9.ide.example", - "website": "", - "description": "", - "star_count": 0, - "star_total": 0, - - "installs": 0, - "screenshots": [ - // TODO Screenshots are broken - // "example" - ] - }; - - before(function(done) { - // Create git repo that contains a plugin we'll use to test - var p = child.spawn(join(__dirname, "publish_test.git.sh")); - - 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("close", function(code) { - if (code) - return done(new Error("Git setup failed")); - - packageJson = fs.readFileSync(packagePath, "utf8"); - readmeMD = fs.readFileSync(readmePath, "utf8"); - - done(); - }); - }); - - it("should be fine if json.permissions is missing as it defaults to world", function(done) { - fs.writeFileSync(packagePath, packageJson.replace(/"permissions[\s\S]*?\],/, "")); - runCLI("publish", ["major"], function(err, stdout, stderr) { - assert(!err, err); - done(); - }); - }); - - it("should warn if the package.json is missing", function(done) { - fs.unlinkSync(packagePath); - runCLI("publish", ["major"], function(err, stdout, stderr) { - expect(stderr).to.match(/ERROR: Could not find package.json/); - done(); - }); - }); - it("should fail if the package.json cannot be parsed", function(done) { - fs.writeFileSync(packagePath, packageJson + "!@#!@#", "utf8"); - runCLI("publish", ["major"], function(err, stdout, stderr) { - expect(stderr).to.match(/ERROR: Could not parse package.json/); - done(); - }); - }); - it("should fail if the name in the package.json is missing", function(done) { - fs.writeFileSync(packagePath, packageJson.replace('"name": "c9.ide.example",', '')); - runCLI("publish", ["major"], function(err, stdout, stderr) { - expect(stderr).to.match(/ERROR: Missing name property in package.json/); - done(); - }); - }); - it("should fail if the name in the package.json contains invalid characters", function(done) { - fs.writeFileSync(packagePath, packageJson.replace('c9.ide.example', 'c9-ide-example')); - runCLI("publish", ["major"], function(err, stdout, stderr) { - expect(stderr).to.match(/ERROR: Package name can only contain/); - done(); - }); - }); - it("should fail if the name in the package.json is not equal to the directory", function(done) { - fs.writeFileSync(packagePath, packageJson.replace('"name": "c9.ide.example"', '"name": "wrongname"')); - runCLI("publish", ["major"], function(err, stdout, stderr) { - expect(stderr).to.match(/WARNING: The name property in package.json is not equal to the directory name/); - done(); - }); - }); - it("should fail if the repository in the package.json is missing", function(done) { - fs.writeFileSync(packagePath, packageJson.replace(/"repository[\s\S]*?\},/, "")); - runCLI("publish", ["major"], function(err, stdout, stderr) { - expect(stderr).to.match(/ERROR: Missing repository property in package.json/); - done(); - }); - }); - it("should fail if the category length is < 1 in the package.json is missing", function(done) { - fs.writeFileSync(packagePath, packageJson.replace(/"categories[\s\S]*?\],/, "")); - runCLI("publish", ["major"], function(err, stdout, stderr) { - expect(stderr).to.match(/ERROR: At least one category is required in package.json/); - done(); - }); - }); - it("should fail if json.permissions is not org or world", function(done) { - var parsedJson = JSON.parse(packageJson); - parsedJson.permissions = "notvalid"; - fs.writeFileSync(packagePath, JSON.stringify(parsedJson)); - runCLI("publish", ["major"], function(err, stdout, stderr) { - console.log("stdout: ", stdout); - expect(stderr).to.match(/ERROR: Permissions must be/); - done(); - }); - }); - it("should warn if a plugin is not listed in the package.json", function(done) { - fs.writeFileSync(packagePath, packageJson.replace('"example": {}', '')); - runCLI("publish", ["major"], function(err, stdout, stderr) { - expect(stderr).to.match(/WARNING: Plugin 'example.js' is not listed in package.json./); - done(); - }); - }); - it("should warn if the README.md is missing", function(done) { - fs.writeFileSync(packagePath, packageJson); - fs.unlink(readmePath); - runCLI("publish", ["major"], function(err, stdout, stderr) { - expect(stderr).to.match(/WARNING: README.md is missing./); - done(); - }); - }); - it("should publish when using force and increase the patch version", function(done) { - var strJson = packageJson.replace(/"version": "[\d\.]+"/, '"version": "0.0.0"'); - fs.writeFileSync(packagePath, strJson); - fs.writeFileSync(readmePath, readmeMD); - runCLI("publish", ["patch", "--force", "--tag"], function(err, stdout, stderr) { - assert(!err, err); - expect(stdout).to.match(/Successfully published version 0.0.1/); - - runCLI("list", ["--json"], function(err, stdout, stderr) { - assert(!err, err); - - json.latest = "0.0.1"; - - var list = JSON.parse(stdout); - if (!list.some(function(item) { - if (item.name == "c9.ide.example") { - expect(item).deep.equal(json); - return true; - } - })) throw new Error("Could not find plugin in list"); - - done(); - }); - }); - }); - it("should increase the minor version", function(done) { - fs.writeFileSync(readmePath, readmeMD); - runCLI("publish", ["minor"], function(err, stdout, stderr) { - assert(!err, err); - expect(stdout).to.match(/Successfully published version 0.1.0/); - - runCLI("list", ["--json"], function(err, stdout, stderr) { - assert(!err, err); - - json.latest = "0.1.0"; - - var list = JSON.parse(stdout); - if (!list.some(function(item) { - if (item.name == "c9.ide.example") { - expect(item).deep.equal(json); - return true; - } - })) throw new Error("Could not find plugin in list"); - - done(); - }); - }); - }); - it("should increase the major version", function(done) { - runCLI("publish", ["major"], function(err, stdout, stderr) { - assert(!err, err); - expect(stdout).to.match(/Successfully published version 1.0.0/); - - runCLI("list", ["--json"], function(err, stdout, stderr) { - assert(!err, err); - - json.latest = "1.0.0"; - - var list = JSON.parse(stdout); - if (!list.some(function(item) { - if (item.name == "c9.ide.example") { - expect(item).deep.equal(json); - return true; - } - })) throw new Error("Could not find plugin in list"); - - done(); - }); - }); - }); - it("should hide the package when it is unpublished", function(done) { - runCLI("unpublish", [], function(err, stdout, stderr) { - assert(!err, err); - expect(stdout).to.match(/Successfully disabled package/); - - runCLI("list", ["--json"], function(err, stdout, stderr) { - assert(!err, err); - expect(stdout).to.not.match(/c9\.ide\.example/); - done(); - }); - }); - }); - }); - - describe("install and remove (uninstall)", function() { - var pluginDir = join(process.env.HOME, ".c9/plugins/c9.ide.example"); - - // Lets make sure there is at least one package in the database - before(function(done) { - // Create git repo that contains a plugin we'll use to test - var p = child.spawn(join(__dirname, "publish_test.git.sh")); - - 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("close", function(code) { - if (code) - return done(new Error("Git setup failed")); - - runCLI("publish", ["10.0.0"], function(err, stdout, stderr) { - done(); - }); - }); - }); - - it("should install a package locally", function(done) { - runCLI("install", ["--local", "c9.ide.example"], function(err, stdout, stderr) { - expect(stdout).to.match(/Successfully installed c9.ide.example@10.0.0/); - expect(fs.existsSync(pluginDir)).ok; - done(); - }); - }); - it("should warn if a package is already installed", function(done) { - runCLI("install", ["--debug", "c9.ide.example"], function(err, stdout, stderr) { - expect(stderr).to.match(/WARNING: Directory not empty/); - done(); - }); - }); - it("should install a package in debug mode", function(done) { - runCLI("install", ["--force", "--debug", "c9.ide.example"], function(err, stdout, stderr) { - expect(stdout).to.match(/Successfully installed c9.ide.example/); - expect(fs.existsSync(join(pluginDir, "/.git"))).ok; - done(); - }); - }); - it("should install a package via the database", function(done) { - runCLI("install", ["c9.ide.example", "--force"], function(err, stdout, stderr) { - expect(stdout).to.match(/Successfully installed c9.ide.example/); - - // @TODO check if it's actually in the database - add list --own to cli - - done(); - }); - }); - // it("should install a package with a specific version via the database", function(done){ - // runCLI("install", ["c9.ide.example@1.0.0", "--force"], function(err, stdout, stderr){ - // console.log(stdout, stderr); - // expect(stdout).to.match(/Successfully installed c9.ide.example@1.0.0/); - - // // @TODO check if it's actually in the database - add list --own to cli - - // done(); - // }); - // }); - it("should remove a package locally", function(done) { - runCLI("remove", ["--local", "c9.ide.example"], function(err, stdout, stderr) { - expect(stdout).to.match(/Successfully removed c9.ide.example/); - expect(fs.existsSync(pluginDir)).not.ok; - done(); - }); - }); - it("should remove a from the database", function(done) { - runCLI("remove", ["c9.ide.example"], function(err, stdout, stderr) { - expect(stdout).to.match(/Successfully removed c9.ide.example/); - - // @TODO check if it's actually in the database - add list --own to cli - - done(); - }); - }); - }); -}); - -function runCLI(command, options, callback) { - var env = Object.create(process.env); - env["NODE_TLS_REJECT_UNAUTHORIZED"] = 0; - env["C9_APIHOST"] = HOST; - env["C9_PID"] = PID; - env["C9_TEST_AUTH"] = USERNAME + ":" + PASSWORD; - env["C9_TEST_MODE"] = 1; - - options.push("--verbose"); - var p = child.spawn(join(__dirname, "../../bin/c9"), [command].concat(options), { - cwd: BASE, - env: env - }); - - if (VERBOSE) - process.stdout.write("\n"); - - var stdout = ""; - p.stdout.on("data", function(c) { - c = c.toString("utf8"); - stdout += c; - if (VERBOSE) process.stdout.write(c); - }); - var stderr = ""; - p.stderr.on("data", function(c) { - c = c.toString("utf8"); - stderr += c; - if (VERBOSE) process.stderr.write(c); - }); - p.on("close", function(code) { - if (code) return callback(new Error(stderr), stdout, stderr); - callback(null, stdout, stderr); - }); -} \ No newline at end of file diff --git a/plugins/c9.cli/cli.js b/plugins/c9.cli/cli.js index 935775f0..a3656afd 100755 --- a/plugins/c9.cli/cli.js +++ b/plugins/c9.cli/cli.js @@ -1,5 +1,5 @@ define(function(require, exports, module) { - main.consumes = ["Plugin", "cli_commands", "workspace"]; + main.consumes = ["Plugin", "cli_commands"]; main.provides = ["cli"]; return main; @@ -10,8 +10,6 @@ define(function(require, exports, module) { var fs = require("fs"); var resolve = require("path").resolve; - var optimist; - /***** Initialization *****/ var plugin = new Plugin("Ajax.org", main.consumes); @@ -44,15 +42,20 @@ define(function(require, exports, module) { } } - optimist = require('optimist'); + var optimist = require('optimist'); - if (!module || !commands[module]) { + var def = commands[module]; + + if (!module || !def) { if (process.argv.indexOf("--version") != -1) { console.log(require("../../package.json").version); process.exit(0); } - argv = optimist + if (module && !def) + console.error(module + " is not a c9 command\n"); + + optimist .usage("The Cloud9 CLI.\nUsage: c9 [--verbose] []\n\n" + "The most commonly used c9 commands are:\n" + Object.keys(commands).map(function(name) { @@ -67,13 +70,10 @@ define(function(require, exports, module) { default: false } }) - .check(function() { - throw new Error("See 'c9 --help' for more information on a specific command."); - }) - .argv; + .showHelp(); + return; } - - var def = commands[module]; + def.options.help = { alias: "h", description: "Output help information" @@ -84,10 +84,7 @@ define(function(require, exports, module) { .options(def.options); if (argv.argv.help) - argv = argv.check(function() { - if (argv.help) - throw new Error("Help Requested"); - }); + return argv.showHelp(); if (def.check) argv = argv.check(def.check); argv = argv.argv; diff --git a/plugins/c9.ide.plugins/manager.js b/plugins/c9.ide.plugins/manager.js index afe471fd..12c5d44c 100644 --- a/plugins/c9.ide.plugins/manager.js +++ b/plugins/c9.ide.plugins/manager.js @@ -3,10 +3,10 @@ define(function(require, exports, module) { main.consumes = [ "PreferencePanel", "settings", "ui", "util", "Form", "ext", "c9", "dialog.alert", "dialog.confirm", "layout", "proc", "menus", "commands", - "dialog.error", "dialog.info", "tree.favorites", "fs", "tree", "plugin.debug", + "dialog.error", "dialog.info", "tree.favorites", "fs", "tree", "vfs", "plugin.debug", "preferences.experimental" ]; - main.provides = ["plugin.manager"]; + main.provides = ["plugin.manager", "pluginManager"]; return main; /* @@ -53,6 +53,8 @@ define(function(require, exports, module) { var proc = imports.proc; var util = imports.util; var qs = require("querystring"); + var apf = imports.apf; + var vfs = imports.vfs; var alert = imports["dialog.alert"].show; var confirm = imports["dialog.confirm"].show; var showError = imports["dialog.error"].show; @@ -67,6 +69,7 @@ define(function(require, exports, module) { var join = require("path").join; var basename = require("path").basename; var dirname = require("path").dirname; + var async = require("async"); var staticPrefix = options.staticPrefix; var architect; @@ -696,6 +699,140 @@ define(function(require, exports, module) { function getLastReloaded() { return qs.parse(document.location.search.substr(1)).reload; } + + var packages = {}; + function loadPackage(options, callback) { + if (Array.isArray(options)) + return async.map(options, loadPackage, callback || function() {}); + + if (typeof options == "string") { + if (/^https?:/.test(options)) { + options = { url: options }; + } else if (/^[~\/]/.test(options)) { + options = { path: options }; + } else if (/^[~\/]/.test(options)) { + options = { url: require.toUrl(options) }; + } + } + + if (!options.url && options.path) + options.url = vfs.vfsUrl(options.path); + + var parts = options.url.split("/"); + var root = parts.pop(); + options.url = parts.join("/"); + + if (!options.name) { + // try to find the name from file name + options.name = /^package\.(.*)\.js$|$/.exec(root)[1]; + // try folder name + if (!options.name || options.name == "json") + options.name = parts[parts.length - 1]; + // try parent folder name + if (/^(.?build|master)/.test(options.name)) + options.name = parts[parts.length - 2]; + // remove version from the name + options.name = options.name.replace(/@.*$/, ""); + } + if (!options.packageName) + options.packageName = root.replace(/\.js$/, ""); + + if (!options.rootDir) + options.rootDir = "plugins"; + + var name = options.name; + var id = options.rootDir + "/" + name; + var pathMappings = {}; + + pathMappings[id] = options.url; + requirejs.config({ paths: pathMappings }); + requirejs.undef(id + "/", true); + + if (/\.js$/.test(root)) { + require([options.url + "/" + root], function(json) { + json = json || require(id + "/" + options.packageName); + getPluginsFromPackage(json, callback); + }, function(err) { + addError("Error loading plugin", err); + }); + } + else if (options.path && /\.json$/.test(root)) { + fs.readFile(options.path, function(err, value) { + if (err) return addError("Error reading " + options.path, err); + try { + var json = JSON.parse(value); + } catch (e) { + return addError("Error parsing package.json", e); + } + json.fromVfs = true; + getPluginsFromPackage(json, callback); + }); + } + else if (options.url && /\.json$/.test(root)) { + require(["text!" + options.id + "/" + root], function(value) { + try { + var json = JSON.parse(value); + } catch (e) { + return addError("Error parsing package.json", e); + } + getPluginsFromPackage(json, callback); + }, function(err) { + addError("Error loading plugin", err); + }); + } + else { + callback && callback(new Error("Missing path and url")); + } + + function addError(message, err) { + if (!packages[name]) + packages[name] = {}; + packages[name].filePath = options.path; + packages[name].url = options.url; + packages[name].__error = new Error(message + "\n" + err.message); + + reloadModel(); + + callback && callback(err); + } + + function getPluginsFromPackage(json, callback) { + var plugins = []; + if (json.name != name) + name = json.name; + var unhandledPlugins = json.c9 && json.c9.plugins || json.plugins; + if (unhandledPlugins) { + Object.keys(unhandledPlugins).forEach(function(name) { + var plugin = unhandledPlugins[name]; + if (typeof plugin == "string") + plugin = { packagePath: plugin }; + if (!plugin.packagePath) + plugin.packagePath = id + "/" + name; + plugin.staticPrefix = options.url; + plugins.push(plugin); + }); + } + + packages[json.name] = json; + json.filePath = options.path; + json.url = options.url; + + if (!json.c9) + json.c9 = {}; + + json.c9.plugins = plugins; + json.enabled = true; + json.path = id; + + loadPlugins(plugins, callback); + } + } + + function loadPlugins(plugins, callback) { + architect.loadAdditionalPlugins(plugins, function(err) { + callback && callback && callback(err); + }); + } /***** Lifecycle *****/ @@ -754,6 +891,11 @@ define(function(require, exports, module) { */ createNewPlugin: createNewPlugin, + /** + * + */ + loadPackage: loadPackage, + /** * */ @@ -776,6 +918,7 @@ define(function(require, exports, module) { }); register(null, { + "pluginManager": plugin, "plugin.manager": plugin }); }