kopia lustrzana https://github.com/c9/core
Merge pull request +8790 from c9/fix-plugin-loader
Update and load plugins from managed directorypull/137/head
commit
2cdd900c3e
|
@ -16,6 +16,9 @@ define(function(require, exports, module) {
|
||||||
|
|
||||||
var dirname = require("path").dirname;
|
var dirname = require("path").dirname;
|
||||||
var join = require("path").join;
|
var join = require("path").join;
|
||||||
|
var async = require("async");
|
||||||
|
var _ = require("lodash");
|
||||||
|
|
||||||
var architect;
|
var architect;
|
||||||
|
|
||||||
/***** Initialization *****/
|
/***** Initialization *****/
|
||||||
|
@ -23,18 +26,15 @@ define(function(require, exports, module) {
|
||||||
var plugin = new Plugin("Ajax.org", main.consumes);
|
var plugin = new Plugin("Ajax.org", main.consumes);
|
||||||
// var emit = plugin.getEmitter();
|
// var emit = plugin.getEmitter();
|
||||||
|
|
||||||
var ENABLED = c9.location.indexOf("plugins=0") == -1;
|
var ENABLED = (c9.location.indexOf("plugins=0") === -1);
|
||||||
var HASSDK = c9.location.indexOf("sdk=0") === -1;
|
var HASSDK = (c9.location.indexOf("sdk=0") === -1);
|
||||||
|
|
||||||
var plugins = options.plugins;
|
var plugins = options.plugins;
|
||||||
var loadFromDisk = options.loadFromDisk
|
var loadFromDisk = options.loadFromDisk
|
||||||
|
|
||||||
var names = [];
|
var names = [];
|
||||||
|
|
||||||
var loaded = false;
|
|
||||||
function load() {
|
function load() {
|
||||||
if (loaded) return false;
|
|
||||||
loaded = true;
|
|
||||||
|
|
||||||
if (!HASSDK) return;
|
if (!HASSDK) return;
|
||||||
if (!ENABLED) return;
|
if (!ENABLED) return;
|
||||||
|
|
||||||
|
@ -42,96 +42,263 @@ define(function(require, exports, module) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/***** Methods *****/
|
/***** Methods *****/
|
||||||
|
|
||||||
function loadPlugins(config){
|
/**
|
||||||
|
* List all packages on disk by scanning `~/.c9` and resolve the
|
||||||
|
* detected packages by order of override priority:
|
||||||
|
*
|
||||||
|
* - Developer plugins in `~/.c9/dev/plugins` have the highest
|
||||||
|
* priority to allow local development of new functionality without
|
||||||
|
* the risk of having your changes overwritten by any update
|
||||||
|
* mechanism.
|
||||||
|
*
|
||||||
|
* - Managed plugins in `~/.c9/managed/plugins` are pre-installed and
|
||||||
|
* updated by the Cloud9 system and have a higher priority that
|
||||||
|
* possibly outdated or unknown packages installed by the user.
|
||||||
|
*
|
||||||
|
* - User-installed in `~/.c9/plugins` plugins installed plugins are
|
||||||
|
* the default priority have the lowest priority.
|
||||||
|
*
|
||||||
|
* @param {Function} callback
|
||||||
|
* @param {Error=} callback.err
|
||||||
|
*/
|
||||||
|
function listAllPackages(callback) {
|
||||||
|
async.parallel({
|
||||||
|
"plugins" : async.apply(listPackages, "~/.c9/plugins"),
|
||||||
|
"managed" : async.apply(listPackages, "~/.c9/managed/plugins"),
|
||||||
|
"dev" : async.apply(listPackages, "~/.c9/dev/plugins"),
|
||||||
|
}, function(err, packages) {
|
||||||
|
if (err && err.code === "EDISCONNECT") {
|
||||||
|
c9.once("connect", function() {
|
||||||
|
loadPluginsFromDisk(callback);
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (err) return callback(err);
|
||||||
|
|
||||||
|
var resolved = {};
|
||||||
|
|
||||||
|
// default: ~/.c9/plugins
|
||||||
|
packages.plugins.forEach(function(config) {
|
||||||
|
if (!config) return;
|
||||||
|
resolved[config.name] = config;
|
||||||
|
});
|
||||||
|
|
||||||
|
// high: ~/.c9/managed/plugins
|
||||||
|
packages.managed.forEach(function(config) {
|
||||||
|
if (!config) return;
|
||||||
|
resolved[config.name] = config;
|
||||||
|
});
|
||||||
|
|
||||||
|
// higher: ~/.c9/dev/plugins
|
||||||
|
packages.dev.forEach(function(config) {
|
||||||
|
if (!config) return;
|
||||||
|
resolved[config.name] = config;
|
||||||
|
});
|
||||||
|
|
||||||
|
callback(null, _.values(resolved));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List packages in the given directory
|
||||||
|
*
|
||||||
|
* @param {String} dirPath Path to the directory to scan
|
||||||
|
*
|
||||||
|
* @param {Function} callback
|
||||||
|
* @param {Error=} callback.err
|
||||||
|
* @param {Object[]} callback.packages
|
||||||
|
*/
|
||||||
|
function listPackages(dirPath, callback) {
|
||||||
|
fs.readdir(dirPath, function(err, stats) {
|
||||||
|
if (err && err.code === "ENOENT")
|
||||||
|
return callback(null, []);
|
||||||
|
|
||||||
|
if (err)
|
||||||
|
return callback(err);
|
||||||
|
|
||||||
|
async.map(stats, function(stat, done) {
|
||||||
|
// check for folder or symlink with folder target
|
||||||
|
|
||||||
|
if (stat.mime !== "inode/directory"
|
||||||
|
&& (stat.mime === "inode/symlink" && stat.linkStat.mime !== "inode/directory")
|
||||||
|
) {
|
||||||
|
return done();
|
||||||
|
}
|
||||||
|
|
||||||
|
// check folers not prefixed with [._]
|
||||||
|
|
||||||
|
if (stat.name[0] === "." || stat.name[0] === "_") {
|
||||||
|
return done();
|
||||||
|
}
|
||||||
|
|
||||||
|
// check and load package.json
|
||||||
|
|
||||||
|
var config = {
|
||||||
|
name: stat.name,
|
||||||
|
path: absolutePath([ dirPath, stat.name ].join("/")),
|
||||||
|
packagePath: [ "plugins", stat.name ].join("/"),
|
||||||
|
staticPrefix: stat.href.replace(/\/$/, ""),
|
||||||
|
};
|
||||||
|
|
||||||
|
loadPackageMetadata(config, function(err, metadata) {
|
||||||
|
if (err) return done(err);
|
||||||
|
config.metadata = metadata;
|
||||||
|
done(null, config);
|
||||||
|
});
|
||||||
|
}, callback);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load a the `package.json` metadata of the given package
|
||||||
|
*
|
||||||
|
* @param {Object} config The package configuration
|
||||||
|
*
|
||||||
|
* @param {Function} callback
|
||||||
|
* @param {Error=} callback.err
|
||||||
|
* @param {Object} callback.metadata
|
||||||
|
*/
|
||||||
|
function loadPackageMetadata(config, callback) {
|
||||||
|
var paths = {};
|
||||||
|
paths[config.packagePath] = config.staticPrefix;
|
||||||
|
|
||||||
|
requirejs.config({ paths: paths });
|
||||||
|
requirejs.undef([config.packagePath, "package.json"].join("/"));
|
||||||
|
|
||||||
|
require([("text!" + [config.packagePath, "package.json" ].join("/"))], function(metadataStr) {
|
||||||
|
var metadata;
|
||||||
|
|
||||||
|
try {
|
||||||
|
metadata = JSON.parse(metadataStr);
|
||||||
|
} catch (e) {
|
||||||
|
return callback(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
callback(null, metadata);
|
||||||
|
}, function(err) {
|
||||||
|
callback(err);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load a the `__installed__.js` definition of the given package
|
||||||
|
*
|
||||||
|
* @param {Object} config The package configuration
|
||||||
|
*
|
||||||
|
* @param {Function} callback
|
||||||
|
* @param {Error=} callback.err
|
||||||
|
* @param {Array<String|Object>} callback.installed
|
||||||
|
*/
|
||||||
|
function loadPackageInstalledJs(config, callback) {
|
||||||
|
var paths = {};
|
||||||
|
paths[config.packagePath] = config.staticPrefix;
|
||||||
|
|
||||||
|
requirejs.config({ paths: paths });
|
||||||
|
requirejs.undef([config.packagePath, "__installed__.js"].join("/"));
|
||||||
|
|
||||||
|
require([[config.packagePath, "__installed__" ].join("/")], function(installed) {
|
||||||
|
callback(null, installed);
|
||||||
|
}, function(err) {
|
||||||
|
callback(err);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load the given package by checking its `__installed__.js` file or
|
||||||
|
* its `package.json#plugins`, then call `Architect#loadAdditionalPlugins()`.
|
||||||
|
*
|
||||||
|
* @param {Object} config The package configuration
|
||||||
|
*
|
||||||
|
* @param {Function} callback
|
||||||
|
* @param {Error=} callback.err
|
||||||
|
*/
|
||||||
|
function loadPackage(config, callback) {
|
||||||
|
loadPackageInstalledJs(config, function(err, installed) {
|
||||||
|
var plugins;
|
||||||
|
|
||||||
|
if (err) {
|
||||||
|
plugins = _.map(config.metadata.plugins, function(value, key) {
|
||||||
|
return [ "plugins", config.name, key ].join("/");
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
plugins = installed;
|
||||||
|
}
|
||||||
|
|
||||||
|
var architectConfig = installed.map(function(plugin) {
|
||||||
|
if (typeof plugin == "string")
|
||||||
|
plugin = { packagePath: plugin };
|
||||||
|
|
||||||
|
plugin.staticPrefix = config.staticPrefix;
|
||||||
|
|
||||||
|
plugin.packageName = config.name;
|
||||||
|
plugin.packageMetadata = config.metadata;
|
||||||
|
plugin.packageDir = config.path;
|
||||||
|
|
||||||
|
plugin.apiKey = null; // FIXME
|
||||||
|
|
||||||
|
return plugin;
|
||||||
|
});
|
||||||
|
|
||||||
|
architect.loadAdditionalPlugins(architectConfig, function(err) {
|
||||||
|
callback(err);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadPlugins(loaderConfig){
|
||||||
if (!vfs.connected) {
|
if (!vfs.connected) {
|
||||||
vfs.once("connect", loadPlugins.bind(this, config));
|
vfs.once("connect", loadPlugins.bind(this, loaderConfig));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var wait = 0;
|
listAllPackages(function(err, resolved) {
|
||||||
var host = vfs.baseUrl + "/";
|
if (!loadFromDisk) {
|
||||||
var base = join(String(c9.projectId), "plugins", auth.accessToken);
|
// filter packages by config instead of loading
|
||||||
var install = [];
|
// everything from disk
|
||||||
|
|
||||||
if (loadFromDisk) {
|
resolved = resolved.filter(function(config) {
|
||||||
fs.readdir("~/.c9/plugins", function handle(err, files){
|
var extraConfig = _.find(loaderConfig, { packagePath: config.packagePath });
|
||||||
if (err) {
|
|
||||||
if (err.code == "EDISCONNECT") {
|
if (!extraConfig) {
|
||||||
c9.once("connect", function(){
|
console.warn("[c9.ide.loader] Not loading package "
|
||||||
fs.readdir("~/.c9/plugins", handle);
|
+ config.path + " because it is not installed, "
|
||||||
});
|
+ "according to the database");
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
console.error(err);
|
|
||||||
return;
|
config.apiKey = extraConfig.apiKey;
|
||||||
}
|
|
||||||
|
return true;
|
||||||
files.forEach(function(f) {
|
|
||||||
if (!/^[_.]/.test(f.name)) {
|
|
||||||
fs.exists("~/.c9/plugins/" + f.name + "/__installed__.js", function(exists) {
|
|
||||||
if (exists) loadOne({packageName: f.name}, false);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
var packages = {};
|
|
||||||
config.forEach(function(options){
|
|
||||||
var name = options.packagePath.replace(/^plugins\/([^\/]*?)\/.*$/, "$1");
|
|
||||||
if (!packages[name]) {
|
|
||||||
packages[name] = {
|
|
||||||
packageName: name,
|
|
||||||
apiKey: options.apiKey
|
|
||||||
};
|
|
||||||
}
|
|
||||||
names.push(name);
|
|
||||||
});
|
|
||||||
|
|
||||||
Object.keys(packages).forEach(function(key) {
|
|
||||||
loadOne(packages[key], false);
|
|
||||||
});
|
|
||||||
|
|
||||||
function loadOne(packageConfig, forceInstall) {
|
|
||||||
wait++;
|
|
||||||
|
|
||||||
var packageName = packageConfig.packageName;
|
|
||||||
var root = "plugins/" + packageName;
|
|
||||||
var paths = {};
|
|
||||||
paths[root] = host + base + "/" + packageName;
|
|
||||||
requirejs.config({paths: paths});
|
|
||||||
requirejs.undef(root + "/__installed__.js");
|
|
||||||
require([root + "/__installed__"], function(plugins) {
|
|
||||||
var config = plugins.map(function(p) {
|
|
||||||
if (typeof p == "string")
|
|
||||||
p = { packagePath: p };
|
|
||||||
p.staticPrefix = paths[root];
|
|
||||||
return p;
|
|
||||||
});
|
|
||||||
|
|
||||||
architect.loadAdditionalPlugins(config, function(err){
|
|
||||||
if (err) console.error(err);
|
|
||||||
});
|
|
||||||
|
|
||||||
done();
|
|
||||||
}, function(err) {
|
|
||||||
if (err && forceInstall) {
|
|
||||||
install.push(packageName);
|
|
||||||
}
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function done(){
|
|
||||||
if (!--wait) return;
|
|
||||||
if (install.length) {
|
|
||||||
installer.installPlugins(install, function(err){
|
|
||||||
if (err) console.error(err);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
loaderConfig.forEach(function(extraConfig) {
|
||||||
|
// warn about missing packages which are supposed to be installed
|
||||||
|
|
||||||
|
if (!_.find(resolved, { packagePath: extraConfig.packagePath })) {
|
||||||
|
console.warn("[c9.ide.loader] Package "
|
||||||
|
+ extraConfig.packagePath + " should be installed, according "
|
||||||
|
+ "to the database, but was not found on the filesystem. "
|
||||||
|
+ "Try reinstalling it.");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
names = _.pluck(resolved, "name");
|
||||||
|
|
||||||
|
async.each(resolved, loadPackage, function(err) {
|
||||||
|
if (err) console.error(err);
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function absolutePath(fromPath) {
|
||||||
|
var toPath = fromPath.replace(/^~/, c9.home);
|
||||||
|
return toPath;
|
||||||
|
}
|
||||||
|
|
||||||
/***** Lifecycle *****/
|
/***** Lifecycle *****/
|
||||||
|
|
||||||
plugin.on("load", function() {
|
plugin.on("load", function() {
|
||||||
|
|
|
@ -23,7 +23,6 @@ define(function(require, exports, module) {
|
||||||
/***** Initialization *****/
|
/***** Initialization *****/
|
||||||
|
|
||||||
var npmBin = options.npmBin || "/home/ubuntu/.nvm/nvm-exec";
|
var npmBin = options.npmBin || "/home/ubuntu/.nvm/nvm-exec";
|
||||||
var pluginsPath = options.pluginsPath || "/home/ubuntu/.c9/plugins";
|
|
||||||
var managedPath = options.managedPath || "/home/ubuntu/.c9/managed";
|
var managedPath = options.managedPath || "/home/ubuntu/.c9/managed";
|
||||||
|
|
||||||
var managedNpmPath = [managedPath, "npm"].join("/");
|
var managedNpmPath = [managedPath, "npm"].join("/");
|
||||||
|
@ -45,7 +44,7 @@ define(function(require, exports, module) {
|
||||||
|
|
||||||
// TODO: DRY error handling
|
// TODO: DRY error handling
|
||||||
|
|
||||||
fsMkdirs([ managedPath, managedEtcPath, managedModulesPath, pluginsPath ], function(err) {
|
fsMkdirs([ managedPath, managedEtcPath, managedModulesPath, managedPluginsPath ], function(err) {
|
||||||
if (err) {
|
if (err) {
|
||||||
console.error("[plugin.updater.npm]", err);
|
console.error("[plugin.updater.npm]", err);
|
||||||
showErrorDialog(err);
|
showErrorDialog(err);
|
||||||
|
@ -269,16 +268,16 @@ define(function(require, exports, module) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes symbolic links from the `~/.c9/plugins` folder.
|
* Removes symbolic links from the `~/.c9/managed/plugins` folder.
|
||||||
*/
|
*/
|
||||||
function fsRmLinks(callback) {
|
function fsRmLinks(callback) {
|
||||||
debug("find", { args: [ pluginsPath, "-maxdepth", "1", "-type", "l", "-exec", "rm", "{}", ";" ] });
|
debug("find", { args: [ managedPluginsPath, "-maxdepth", "1", "-type", "l", "-exec", "rm", "{}", ";" ] });
|
||||||
|
|
||||||
// find . -maxdepth 1 -type l -exec rm {} \;
|
// find . -maxdepth 1 -type l -exec rm {} \;
|
||||||
|
|
||||||
proc.execFile("find", {
|
proc.execFile("find", {
|
||||||
args: [
|
args: [
|
||||||
pluginsPath,
|
managedPluginsPath,
|
||||||
"-maxdepth", "1",
|
"-maxdepth", "1",
|
||||||
"-type", "l",
|
"-type", "l",
|
||||||
"-exec", "rm", "{}", ";"
|
"-exec", "rm", "{}", ";"
|
||||||
|
@ -296,13 +295,13 @@ define(function(require, exports, module) {
|
||||||
* @param {String} pkgPath Path to the source package folder
|
* @param {String} pkgPath Path to the source package folder
|
||||||
*/
|
*/
|
||||||
function fsLink(pkgPath, callback) {
|
function fsLink(pkgPath, callback) {
|
||||||
debug("ls", { args: [ "-s", "-f", pkgPath, [ pluginsPath, "." ].join("/") ]});
|
debug("ls", { args: [ "-s", "-f", pkgPath, [ managedPluginsPath, "." ].join("/") ]});
|
||||||
|
|
||||||
proc.execFile("ln", {
|
proc.execFile("ln", {
|
||||||
args: [
|
args: [
|
||||||
"-s", "-f",
|
"-s", "-f",
|
||||||
pkgPath,
|
pkgPath,
|
||||||
[ pluginsPath, "." ].join("/"),
|
[ managedPluginsPath, "." ].join("/"),
|
||||||
],
|
],
|
||||||
}, function(err, stdout, stderr) {
|
}, function(err, stdout, stderr) {
|
||||||
debug([err, stdout, stderr]);
|
debug([err, stdout, stderr]);
|
||||||
|
@ -324,7 +323,7 @@ define(function(require, exports, module) {
|
||||||
args: [
|
args: [
|
||||||
"-rf", basename,
|
"-rf", basename,
|
||||||
],
|
],
|
||||||
cwd: pluginsPath,
|
cwd: managedPluginsPath,
|
||||||
}, function(err, stdout, stderr) {
|
}, function(err, stdout, stderr) {
|
||||||
debug([err, stdout, stderr]);
|
debug([err, stdout, stderr]);
|
||||||
|
|
||||||
|
|
Ładowanie…
Reference in New Issue