mirror of
https://github.com/meteor/meteor.git
synced 2026-05-02 03:01:46 -04:00
global meteor update
This commit is contained in:
246
lib/update.js
246
lib/update.js
@@ -7,248 +7,28 @@ 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 files = require('./files.js');
|
||||
var warehouse = require('./warehouse.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);
|
||||
}
|
||||
|
||||
// XXX update for engine
|
||||
var updateMeteor = function () {
|
||||
// Immediately kick off manifest check.
|
||||
// XXX error check
|
||||
var manifest = updater.getManifest();
|
||||
|
||||
//// 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.ENGINE_VERSION) {
|
||||
console.log("Already at current version: " + manifest.version);
|
||||
} else {
|
||||
console.log("Not upgrading. Your version: " + updater.ENGINE_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.getCurrentEngineDir(), '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.");
|
||||
// refuse to update if we're in a git checkout.
|
||||
if (!files.usesWarehouse()) {
|
||||
console.log("Your Meteor installation is a git checkout. Update it " +
|
||||
"manually with 'git pull'.");
|
||||
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";
|
||||
// XXX make errors look good
|
||||
var updated = warehouse.fetchLatestRelease();
|
||||
if (updated) {
|
||||
console.log("Updated Meteor to release " + warehouse.latestRelease());
|
||||
} else {
|
||||
console.log("Unsupported architecture", arch);
|
||||
return;
|
||||
console.log("Meteor release " + warehouse.latestRelease() +
|
||||
" is already the latest release.");
|
||||
}
|
||||
|
||||
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) { }
|
||||
|
||||
try {
|
||||
console.log('installing upgrade...');
|
||||
files.extractTarGz(fs.readFileSync(tar_path),
|
||||
tmp_dir);
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
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");
|
||||
// create a Fiber so that code in download_callback can use
|
||||
// sync calls having Futures.
|
||||
Fiber(function () {
|
||||
download_callback(download_path);
|
||||
// don't remove temp dir here, download_callback is probably still
|
||||
// using it.
|
||||
}).run();
|
||||
});
|
||||
});
|
||||
req.end();
|
||||
|
||||
// XXX update app
|
||||
};
|
||||
|
||||
@@ -69,13 +69,10 @@ var warehouse = module.exports = {
|
||||
var manifestPath = path.join(
|
||||
warehouse.getWarehouseDir(), 'releases', release + '.json');
|
||||
|
||||
if (fs.existsSync(manifestPath)) {
|
||||
// read from warehouse
|
||||
return JSON.parse(fs.readFileSync(manifestPath));
|
||||
} else {
|
||||
// grow warehouse with new manifest and packages
|
||||
return warehouse._populateWarehouseForRelease(release);
|
||||
}
|
||||
warehouse._populateWarehouseForRelease(release);
|
||||
|
||||
// read from warehouse
|
||||
return JSON.parse(fs.readFileSync(manifestPath));
|
||||
},
|
||||
|
||||
_latestReleaseSymlinkPath: function () {
|
||||
@@ -93,6 +90,7 @@ var warehouse = module.exports = {
|
||||
}
|
||||
},
|
||||
|
||||
// returns true if we updated the latest symlink
|
||||
// XXX make errors prettier
|
||||
fetchLatestRelease: function () {
|
||||
var manifest = updater.getManifest();
|
||||
@@ -104,12 +102,18 @@ var warehouse = module.exports = {
|
||||
}
|
||||
|
||||
warehouse._populateWarehouseForRelease(releaseName);
|
||||
|
||||
var storedLatestRelease = warehouse.latestRelease();
|
||||
if (storedLatestRelease && storedLatestRelease === releaseName)
|
||||
return false;
|
||||
|
||||
var latestReleaseSymlink = warehouse._latestReleaseSymlinkPath();
|
||||
var tmpSymlink = latestReleaseSymlink + ".tmp" + warehouse._randomToken();
|
||||
// You can't directly symlink over an existing symlink, but you can rename
|
||||
// over it.
|
||||
fs.symlinkSync(releaseName, tmpSymlink);
|
||||
fs.renameSync(tmpSymlink, latestReleaseSymlink);
|
||||
return true;
|
||||
},
|
||||
|
||||
packageExistsInWarehouse: function (name, version) {
|
||||
@@ -127,13 +131,15 @@ var warehouse = module.exports = {
|
||||
// fetches the manifest file for the given release version. also fetches
|
||||
// all of the missing versioned packages referenced from the release manifest
|
||||
// @param releaseVersion {String} eg "0.1"
|
||||
// @returns {Object} release manifest
|
||||
_populateWarehouseForRelease: function(releaseVersion) {
|
||||
var future = new Future;
|
||||
var releasesDir = path.join(warehouse.getWarehouseDir(), 'releases');
|
||||
files.mkdir_p(releasesDir, 0755);
|
||||
var releaseManifestPath = path.join(releasesDir, releaseVersion + '.json');
|
||||
|
||||
if (fs.existsSync(releaseManifestPath))
|
||||
return;
|
||||
|
||||
// get release manifest, but only write it after we're done
|
||||
// writing packages
|
||||
var releaseManifest;
|
||||
@@ -195,9 +201,6 @@ var warehouse = module.exports = {
|
||||
// now that we have written all packages, it's safe to write the
|
||||
// release manifest
|
||||
fs.writeFileSync(releaseManifestPath, JSON.stringify(releaseManifest));
|
||||
|
||||
// return manifest
|
||||
return releaseManifest;
|
||||
},
|
||||
|
||||
// @param packagesToPopulate {Object} eg {"less": "0.5.0"}
|
||||
|
||||
Reference in New Issue
Block a user