mirror of
https://github.com/meteor/meteor.git
synced 2026-05-02 03:01:46 -04:00
This will be useful when we want to be smart with windows file paths later Also, all of the file calls are asynchronous with fibers now, which comes with many benefits. This is a combination of 23 commits. Original messages: Wrap a large number of fs calls inside files.* Convert a few more fs calls to files.* More moving fs.* to files Implement read/write streams and open/read/close Get rid of fs from auth.js Remove fs and unused imports from catalog-local and catalog-remote Remove unused imports from catalog.js Replace a whole lot of fs calls Fix error Migrate a lot more fs. calls to files. Add a temporary symlink method Convert old test to files.* Use files.pathX instead of path.x everywhere Replace path.x to files.pathX in tests Small fixes to files.js and one rename Make cleanup run in a fiber Make wrapping functions take function name in case we need it Add some timeouts and stuff to HCP tests wrapFsFunc also makes a sync version of the function Sometimes you just don't want to yield! Make sure JsImage readFromDisk doesn't yield Remove unused imports from npm test Change order of test now that some things don't yield Fix missing files import, and add a debug error printout
204 lines
7.0 KiB
JavaScript
204 lines
7.0 KiB
JavaScript
var _ = require('underscore');
|
|
var tropohouse = require('./tropohouse.js');
|
|
var release = require('./release.js');
|
|
var runLog = require('./run-log.js');
|
|
var catalog = require('./catalog.js');
|
|
var archinfo = require('./archinfo.js');
|
|
var isopack = require('./isopack.js');
|
|
var utils = require('./utils.js');
|
|
var buildmessage = require('./buildmessage.js');
|
|
var Console = require('./console.js').Console;
|
|
var auth = require('./auth.js');
|
|
var packageMapModule = require('./package-map.js');
|
|
var files = require("./files.js");
|
|
|
|
/**
|
|
* Check to see if an update is available. If so, download and install
|
|
* it before returning.
|
|
*
|
|
* options: showBanner
|
|
*/
|
|
var checkInProgress = false;
|
|
exports.tryToDownloadUpdate = function (options) {
|
|
options = options || {};
|
|
// Don't run more than one check simultaneously. It should be
|
|
// harmless but having two downloads happening simultaneously (and
|
|
// two sets of messages being printed) would be confusing.
|
|
if (checkInProgress)
|
|
return;
|
|
checkInProgress = true;
|
|
checkForUpdate(!!options.showBanner);
|
|
checkInProgress = false;
|
|
};
|
|
|
|
var firstCheck = true;
|
|
|
|
var checkForUpdate = function (showBanner) {
|
|
// While we're doing background stuff, try to revoke any old tokens in our
|
|
// session file.
|
|
auth.tryRevokeOldTokens({timeout: 15*1000});
|
|
|
|
if (firstCheck) {
|
|
// We want to avoid a potential race condition here, because we run an
|
|
// update almost immediately at run. We don't want to drop the resolver
|
|
// cache; that would be slow. "meteor run" itself should have run a refresh
|
|
// anyway. So, the first time, we just skip the remote catalog sync. But
|
|
// we do want to do the out-of-date release checks, so we can't just delay
|
|
// the first update cycle.
|
|
firstCheck = false;
|
|
} else {
|
|
try {
|
|
catalog.official.refresh();
|
|
} catch (err) {
|
|
Console.debug("Failed to refresh catalog, ignoring error", err);
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (!release.current.isProperRelease())
|
|
return;
|
|
|
|
updateMeteorToolSymlink();
|
|
|
|
maybeShowBanners();
|
|
};
|
|
|
|
var lastShowTimes = {};
|
|
|
|
var shouldShow = function (key, maxAge) {
|
|
var now = +(new Date);
|
|
|
|
if (maxAge === undefined) {
|
|
maxAge = 12 * 60 * 60 * 1000;
|
|
}
|
|
|
|
var lastShow = lastShowTimes[key];
|
|
if (lastShow !== undefined) {
|
|
var age = now - lastShow;
|
|
if (age < maxAge) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
lastShowTimes[key] = now;
|
|
return true;
|
|
};
|
|
|
|
var maybeShowBanners = function () {
|
|
var releaseData = release.current.getCatalogReleaseData();
|
|
|
|
var banner = releaseData.banner;
|
|
if (banner) {
|
|
var bannerDate =
|
|
banner.lastUpdated ? new Date(banner.lastUpdated) : new Date;
|
|
if (catalog.official.shouldShowBanner(release.current.name, bannerDate)) {
|
|
// This banner is new; print it!
|
|
runLog.log("");
|
|
runLog.log(banner.text);
|
|
runLog.log("");
|
|
catalog.official.setBannerShownDate(release.current.name, bannerDate);
|
|
return;
|
|
}
|
|
}
|
|
|
|
// We now consider printing some simpler banners, if this isn't the latest
|
|
// release. But if the user specified a release manually with --release, we
|
|
// don't bother: we only want to tell users about ways to update *their app*.
|
|
if (release.forced)
|
|
return;
|
|
|
|
// Didn't print a banner? Maybe we have a patch release to recommend.
|
|
var track = release.current.getReleaseTrack();
|
|
var patchReleaseVersion = releaseData.patchReleaseVersion;
|
|
if (patchReleaseVersion) {
|
|
var patchRelease = catalog.official.getReleaseVersion(
|
|
track, patchReleaseVersion);
|
|
if (patchRelease && patchRelease.recommended) {
|
|
var key = "patchrelease-" + track + "-" + patchReleaseVersion;
|
|
if (shouldShow(key)) {
|
|
runLog.log(
|
|
"=> A patch (" +
|
|
utils.displayRelease(track, patchReleaseVersion) +
|
|
") for your current release is available!");
|
|
runLog.log(" Update this project now with 'meteor update --patch'.");
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
|
|
// There's no patch (so no urgent exclamation!) but there may be something
|
|
// worth mentioning.
|
|
// XXX maybe run constraint solver to change the message depending on whether
|
|
// or not it will actually work?
|
|
var currentReleaseOrderKey = releaseData.orderKey || null;
|
|
var futureReleases = catalog.official.getSortedRecommendedReleaseVersions(
|
|
track, currentReleaseOrderKey);
|
|
if (futureReleases.length) {
|
|
var key = "futurerelease-" + track + "-" + futureReleases[0];
|
|
if (shouldShow(key)) {
|
|
runLog.log(
|
|
"=> " + utils.displayRelease(track, futureReleases[0]) +
|
|
" is available. Update this project with 'meteor update'.");
|
|
}
|
|
return;
|
|
}
|
|
};
|
|
|
|
// Update ~/.meteor/meteor to point to the tool binary from the tools of the
|
|
// latest recommended release on the default release track.
|
|
var updateMeteorToolSymlink = function () {
|
|
// Get the latest release version of METEOR. (*Always* of the default
|
|
// track, not of whatever we happen to be running: we always want the tool
|
|
// symlink to go to the default track.)
|
|
var latestReleaseVersion = catalog.official.getDefaultReleaseVersion();
|
|
// Maybe you're on some random track with nothing recommended. That's OK.
|
|
if (!latestReleaseVersion)
|
|
return;
|
|
|
|
var latestRelease = catalog.official.getReleaseVersion(
|
|
latestReleaseVersion.track, latestReleaseVersion.version);
|
|
if (!latestRelease)
|
|
throw Error("latest release doesn't exist?");
|
|
if (!latestRelease.tool)
|
|
throw Error("latest release doesn't have a tool?");
|
|
|
|
var latestReleaseToolParts = latestRelease.tool.split('@');
|
|
var latestReleaseToolPackage = latestReleaseToolParts[0];
|
|
var latestReleaseToolVersion = latestReleaseToolParts[1];
|
|
var relativeToolPath = tropohouse.default.packagePath(
|
|
latestReleaseToolPackage, latestReleaseToolVersion, true);
|
|
|
|
var localLatestReleaseLink = tropohouse.default.latestMeteorSymlink();
|
|
|
|
if (! utils.startsWith(localLatestReleaseLink, relativeToolPath + files.pathSep)) {
|
|
// The latest release from the catalog is not where the ~/.meteor/meteor
|
|
// symlink points to. Let's make sure we have that release on disk,
|
|
// and then update the symlink.
|
|
var packageMap =
|
|
packageMapModule.PackageMap.fromReleaseVersion(latestRelease);
|
|
var messages = buildmessage.capture(function () {
|
|
tropohouse.default.downloadPackagesMissingFromMap(packageMap);
|
|
});
|
|
if (messages.hasMessages()) {
|
|
// Ignore errors, because we are running in the background.
|
|
return;
|
|
}
|
|
|
|
var toolIsopack = new isopack.Isopack;
|
|
toolIsopack.initFromPath(
|
|
latestReleaseToolPackage,
|
|
tropohouse.default.packagePath(latestReleaseToolPackage,
|
|
latestReleaseToolVersion));
|
|
var toolRecord = _.findWhere(toolIsopack.toolsOnDisk,
|
|
{arch: archinfo.host()});
|
|
|
|
// XXX maybe we shouldn't throw from this background thing
|
|
// counter: this is super weird and should never ever happen.
|
|
if (!toolRecord)
|
|
throw Error("latest release has no tool?");
|
|
|
|
tropohouse.default.replaceLatestMeteorSymlink(
|
|
files.pathJoin(relativeToolPath, toolRecord.path, 'meteor'));
|
|
}
|
|
};
|