c9-core/plugins/c9.ide.local/update.js

298 wiersze
10 KiB
JavaScript

/*global nativeRequire*/
define(function(require, exports, module) {
main.consumes = [
"c9", "Plugin", "fs", "util", "proc", "dialog.alert", "dialog.confirm",
"http", "layout"
];
main.provides = ["local.update"];
return main;
function main(options, imports, register) {
var c9 = imports.c9;
var Plugin = imports.Plugin;
var showConfirm = imports["dialog.confirm"].show;
var showAlert = imports["dialog.alert"].show;
var fs = imports.fs;
var proc = imports.proc;
var http = imports.http;
var nodeBin = Array.isArray(options.nodeBin)
? options.nodeBin[0]
: options.nodeBin || "node";
var layout = imports.layout;
var join = require("path").join;
var dirname = require("path").dirname;
var basename = require("path").basename;
var windowManager = window.server.windowManager;
/***** Initialization *****/
var plugin = new Plugin("Ajax.org", main.consumes);
// var emit = plugin.getEmitter();
var HOST = options.host || "localhost";
var PORT = options.port || "8888";
var PROTOCOL = options.protocol || "https";
var BASH = options.bashBin || "bash";
var installPath = options.installPath.replace(/^~/, c9.home);
var loaded = false;
function load() {
if (loaded) return false;
loaded = true;
setTimeout(function() {
// At startup check for updates
checkForUpdates();
// Then check for updates once every 15 minutes
setInterval(checkForUpdates, 60 * 15 * 1000);
}, 5 * 1000);
}
/***** Methods *****/
function checkForUpdates() {
if (!windowManager.isPrimaryWindow(window))
return;
var url = PROTOCOL + "://" + HOST + ":" + PORT + "/update";
http.request(url, {}, function(err, date, res) {
isNewer(date, function(err, newer) {
if (err) return;
if (newer)
downloadLatest(date);
});
});
}
function isNewer(date, callback) {
fs.readFile(options.path + "/version", function(err, currentDate) {
if (!currentDate) currentDate = 0;
var newer = parseInt(currentDate, 10) < parseInt(date, 10);
callback(null, newer);
});
}
function downloadLatest(date) {
if (!c9.has(c9.NETWORK))
return;
var updateDir = join(installPath, "updates");
var updateFile = join(updateDir, date);
console.log('updateFile: ' + updateFile);
// check if already downloaded
fs.exists(updateFile, function(exists) {
var url = PROTOCOL + "://" + HOST + ":" + PORT + "/update/"
+ c9.platform + "/" + date;
if (exists) {
return decompress(date, updateFile);
}
var cmdDlUpdate = "(curl " + url + ".sig -o '" + updateFile + ".sig' --post301 --post302 --create-dirs &&"
+ "curl " + url + " -o '" + updateFile + "' --post301 --post302 --create-dirs) || "
+ "(wget " + url + ".sig -P '" + updateDir + "' && "
+ "wget " + url + " -P '" + updateDir + "')";
console.log("cmdDlUpdate: " + cmdDlUpdate);
proc.execFile("bash", {
args: [
"-c",
cmdDlUpdate
],
}, function(err, stdout, stderr) {
if (err) {
showAlert(
"Unable to download update",
"Got errors while attempting to download update to Cloud9",
"I tried to download using curl and wget. See the browser's log for more info. "
+ "Contact support@c9.io to help your resolve this issue."
);
console.error(err.message, stderr);
return;
}
decompress(date, updateFile);
});
});
}
function decompress(date, target) {
fs.rmdir(installPath + "/updates/app.nw", { recursive: true }, function() {
proc.execFile("tar", {
args: ["-zxf", basename(target)],
cwd: dirname(target)
}, function(err, stdout, stderr) {
if (err) {
fs.unlink(target, function() {});
return;
}
// fs.writeFile(installPath + "/updates/app.nw/version", date, function(){
update(date);
// });
});
return false;
});
}
function flagUpdate(date) {
if (typeof document === "undefined")
return;
layout.flagUpdate(function() {
showUpdatePopup(date);
});
}
function showUpdatePopup(date) {
showConfirm("Cloud9 needs to be updated",
"Update Available",
"There is an update available of Cloud9. ",
function() {
restart();
},
function() {
// Do nothing
},
{
yes: "Update",
no: "Not now",
});
}
//@TODO needs to be platform specific
function getC9Path() {
return options.path + "/bin/c9";
}
function update(date) {
// Use the update script from the new package
var script = join(getC9Path(), "../../scripts/checkforupdates.sh");
var path = options.path;
var appRoot, appPath;
var updateRoot = installPath;
if (c9.platform == "linux") {
// @todo
return alert("Unsupported Platform");
}
else if (c9.platform == "win32") {
var toCygwinPath = function(winPath) {
return winPath.replace(/(\w):/, "/$1").replace(/\\/g, "/");
};
// script = toCygwinPath(script);
path = toCygwinPath(path);
updateRoot = toCygwinPath(updateRoot);
appPath = path;
appRoot = path.substr(0, path.lastIndexOf("/"));
}
else if (c9.platform == "darwin") {
// Set a default path during development
if (path.indexOf("Contents/Resources") == -1)
path = "/Applications/Cloud9.app/Contents/Resources/app.nw";
appPath = path;
appRoot = path.substr(0, path.lastIndexOf("/"));
}
fs.readFile(script, "utf8", function(e, scriptContent) {
// replace $R1 - $R5 in the bash script by
var url = PROTOCOL + "://" + HOST + ":" + PORT + "/nw/" + c9.platform + "/";
var args = [script, appRoot, appPath, updateRoot, date, nodeBin, url];
scriptContent = scriptContent.replace(/\$R(\d)/g, function(_, i) {
return args[i];
});
proc.spawn(BASH, {
args: ["-c", scriptContent]
}, function(err, child) {
if (err) return console.error(err);
child.stdout.on("data", function(chunk) {
console.log(chunk);
});
child.stderr.on("data", function(chunk) {
console.log(chunk);
});
child.on("exit", function(code) {
if (code !== 0) {
console.log("Update Failed.");
// @todo cleanup
}
else {
// restart();
flagUpdate(date);
}
});
});
});
}
function restart() {
// nativeRequire('nw.gui').Window.get().reloadIgnoringCache();
// todo this doesn't work
proc.spawn(getC9Path(), {
args: ["restart"],
detached: true
}, function(err, process) {
if (err) return;
// required so the parent can exit
process.unref();
});
}
/***** Lifecycle *****/
plugin.on("load", function() {
load();
});
plugin.on("enable", function() {
});
plugin.on("disable", function() {
});
plugin.on("unload", function() {
loaded = false;
});
/***** Register and define API *****/
/**
* Draws the file tree
* @event afterfilesave Fires after a file is saved
* @param {Object} e
* node {XMLNode} description
* oldpath {String} description
**/
plugin.freezePublicAPI({
/**
*
*/
checkForUpdates: checkForUpdates,
/**
*
*/
restart: restart,
/**
* @ignore
*/
update: update
});
register(null, {
"local.update": plugin
});
}
});