mirror of
https://github.com/meteor/meteor.git
synced 2026-05-02 03:01:46 -04:00
253 lines
7.5 KiB
JavaScript
253 lines
7.5 KiB
JavaScript
var fs = require("fs");
|
|
var https = require("https");
|
|
var os = require("os");
|
|
var path = require("path");
|
|
var spawn = require('child_process').spawn;
|
|
var url = require("url");
|
|
|
|
var ProgressBar = require('progress');
|
|
|
|
var updater = require(path.join(__dirname, "..", "lib", "updater.js"));
|
|
var files = require(path.join(__dirname, "..", "lib", "files.js"));
|
|
|
|
var _ = require('underscore');
|
|
|
|
// refuse to update if we're in a git checkout.
|
|
if (files.in_checkout()) {
|
|
console.log("Your Meteor installation is a git checkout. Update it " +
|
|
"manually with 'git pull'.");
|
|
process.exit(1);
|
|
}
|
|
|
|
// Immediately kick off manifest check.
|
|
updater.get_manifest(function (manifest) {
|
|
|
|
//// Examine manifest and see if we need to upgrade.
|
|
|
|
if (!manifest || !manifest.version || !manifest.urlbase) {
|
|
console.log("Failed to download manifest.");
|
|
return;
|
|
}
|
|
|
|
if (!updater.needs_upgrade(manifest)) {
|
|
if (manifest.version === updater.CURRENT_VERSION) {
|
|
console.log("Already at current version: " + manifest.version);
|
|
} else {
|
|
console.log("Not upgrading. Your version: " + updater.CURRENT_VERSION
|
|
+ ". New version: " + manifest.version + ".");
|
|
}
|
|
return;
|
|
}
|
|
|
|
console.log("New version available: " + manifest.version);
|
|
|
|
//// Setup post-upgrade function so we can call it later
|
|
var post_remove_directories = [];
|
|
var cleanup_temp_dirs = function () {
|
|
_.each(post_remove_directories, files.rm_recursive);
|
|
post_remove_directories = [];
|
|
};
|
|
|
|
var run_post_upgrade = function () {
|
|
cleanup_temp_dirs();
|
|
|
|
// Launch post-upgrade script
|
|
var nodejs_path = path.join(files.get_dev_bundle(), 'bin', 'node');
|
|
var postup_path = path.join(files.get_core_dir(), 'meteor', 'post-upgrade.js');
|
|
|
|
if (fs.existsSync(nodejs_path) && fs.existsSync(postup_path)) {
|
|
// setup environment.
|
|
var modules_path = path.join(files.get_dev_bundle(), 'lib', 'node_modules');
|
|
var env = _.extend({}, process.env);
|
|
env.NODE_PATH = modules_path;
|
|
|
|
// launch it.
|
|
var postup_proc = spawn(nodejs_path, [postup_path], {env: env});
|
|
postup_proc.stderr.setEncoding('utf8');
|
|
postup_proc.stderr.on('data', function (data) {
|
|
process.stderr.write(data);
|
|
});
|
|
postup_proc.stdout.setEncoding('utf8');
|
|
postup_proc.stdout.on('data', function (data) {
|
|
process.stdout.write(data);
|
|
});
|
|
} else {
|
|
// no postup. Still print a message, but one that is subtly
|
|
// different so developers can debug what is going on.
|
|
console.log("upgrade complete.");
|
|
}
|
|
};
|
|
|
|
var run_with_root = function (cmd, args) {
|
|
if (0 === process.getuid()) {
|
|
// already root. just spawn the command.
|
|
return spawn(cmd, args);
|
|
} else if (fs.existsSync("/bin/sudo") ||
|
|
fs.existsSync("/usr/bin/sudo")) {
|
|
// spawn a sudo
|
|
console.log("Since this system includes sudo, Meteor will request root privileges to");
|
|
console.log("install. You may be prompted for a password. If you prefer to not use");
|
|
console.log("sudo, please re-run this command as root.");
|
|
console.log("sudo", cmd, args.join(" "));
|
|
return spawn('sudo', [cmd].concat(args));
|
|
}
|
|
|
|
// no root, no sudo. fail
|
|
console.log("Meteor requires root privileges to install. Please re-run this command");
|
|
console.log("as root.");
|
|
process.exit(1);
|
|
return null; // unreached, but makes js2 mode happy.
|
|
};
|
|
|
|
|
|
//// Figure out what platform we're upgrading on (dpkg, rpm, tar)
|
|
|
|
var package_stamp_path = path.join(files.get_dev_bundle(), '.package_stamp');
|
|
var package_stamp;
|
|
try {
|
|
package_stamp = fs.readFileSync(package_stamp_path, 'utf8');
|
|
package_stamp = package_stamp.replace(/^\s+|\s+$/g, '');
|
|
} catch (err) {
|
|
// no package stamp, assume tarball.
|
|
package_stamp = 'tar';
|
|
}
|
|
|
|
var download_url; // url to download
|
|
var download_callback; // callback to call with path on disk of download.
|
|
|
|
var arch = os.arch();
|
|
var deb_arch;
|
|
var rpm_arch;
|
|
if ("ia32" == arch) {
|
|
deb_arch = "i386";
|
|
rpm_arch = "i386";
|
|
arch = "i686";
|
|
} else if ("x64" == arch) {
|
|
deb_arch = "amd64";
|
|
rpm_arch = "x86_64";
|
|
arch = "x86_64";
|
|
} else {
|
|
console.log("Unsupported architecture", arch);
|
|
return;
|
|
}
|
|
|
|
if ('deb' === package_stamp) {
|
|
download_url =
|
|
manifest.urlbase + "/meteor_" + manifest.deb_version +
|
|
"_" + deb_arch + ".deb";
|
|
|
|
download_callback = function (deb_path) {
|
|
var proc = run_with_root('dpkg', ['-i', deb_path]);
|
|
proc.on('exit', function (code, signal) {
|
|
if (code !== 0 || signal) {
|
|
console.log("failed to install deb");
|
|
return;
|
|
}
|
|
// success!
|
|
run_post_upgrade();
|
|
});
|
|
};
|
|
|
|
} else if ('rpm' === package_stamp) {
|
|
download_url =
|
|
manifest.urlbase + "/meteor-" + manifest.rpm_version +
|
|
"." + rpm_arch + ".rpm";
|
|
|
|
download_callback = function (rpm_path) {
|
|
var proc = run_with_root('rpm', ['-U', '--force', rpm_path]);
|
|
proc.on('exit', function (code, signal) {
|
|
if (code !== 0 || signal) {
|
|
console.log("Error: failed to install Meteor RPM package.");
|
|
return;
|
|
}
|
|
// success!
|
|
run_post_upgrade();
|
|
});
|
|
};
|
|
|
|
} else {
|
|
|
|
download_url =
|
|
manifest.urlbase + "/meteor-package-" + os.type() +
|
|
"-" + arch + "-" + manifest.version + ".tar.gz";
|
|
|
|
download_callback = function (tar_path) {
|
|
var base_dir = path.join(__dirname, "..", "..");
|
|
var tmp_dir = path.join(base_dir, "tmp");
|
|
// XXX error check!
|
|
try { fs.mkdirSync(tmp_dir, 0755); } catch (err) { }
|
|
|
|
// open pipe to tar
|
|
var tar_proc = spawn("tar", ["-C", tmp_dir, "-xzf", tar_path]);
|
|
|
|
tar_proc.stderr.setEncoding('utf8');
|
|
tar_proc.stderr.on('data', function (data) {
|
|
console.log(data);
|
|
});
|
|
|
|
tar_proc.on('exit', function (code, signal) {
|
|
if (code !== 0 || signal) {
|
|
console.log("Error: package download failed.");
|
|
return;
|
|
}
|
|
|
|
// untar complete. swap directories
|
|
var old_base_dir = base_dir + ".old";
|
|
if (fs.existsSync(old_base_dir))
|
|
files.rm_recursive(old_base_dir); // rm -rf !!
|
|
|
|
fs.renameSync(base_dir, old_base_dir);
|
|
fs.renameSync(path.join(old_base_dir, "tmp", "meteor"), base_dir);
|
|
|
|
// success!
|
|
run_post_upgrade();
|
|
});
|
|
|
|
};
|
|
}
|
|
|
|
//// Kick off download
|
|
|
|
var download_parsed = url.parse(download_url);
|
|
// XXX why is node's API for 'url' different from 'http'?
|
|
download_parsed.path = download_parsed.pathname;
|
|
|
|
var req = https.request(download_parsed, function(res) {
|
|
if (res.statusCode !== 200) {
|
|
console.log("Failed to download: " + download_url);
|
|
return;
|
|
}
|
|
var len = parseInt(res.headers['content-length'], 10);
|
|
|
|
var bar = new ProgressBar(' downloading [:bar] :percent', {
|
|
complete: '='
|
|
, incomplete: ' '
|
|
, width: 30
|
|
, total: len
|
|
});
|
|
|
|
// find / make directory paths
|
|
var tmp_dir = files.mkdtemp();
|
|
post_remove_directories.push(tmp_dir);
|
|
|
|
// open tempfile
|
|
var download_path = path.join(tmp_dir, path.basename(download_url));
|
|
var download_stream = fs.createWriteStream(download_path);
|
|
|
|
res.on('data', function (chunk) {
|
|
download_stream.write(chunk);
|
|
bar.tick(chunk.length);
|
|
});
|
|
|
|
res.on('end', function () {
|
|
download_stream.end();
|
|
console.log("... finished download");
|
|
download_callback(download_path);
|
|
// don't remove temp dir here, download_callback is probably still
|
|
// using it.
|
|
});
|
|
});
|
|
req.end();
|
|
|
|
});
|