diff --git a/packages/autoupdate/autoupdate_cordova.js b/packages/autoupdate/autoupdate_cordova.js index 2290c6d802..3cab024b6c 100644 --- a/packages/autoupdate/autoupdate_cordova.js +++ b/packages/autoupdate/autoupdate_cordova.js @@ -73,17 +73,21 @@ var restartServer = function (location) { }; var hasCalledReload = false; +var updating = false; +var localPathPrefix = null; + var onNewVersion = function () { var ft = new FileTransfer(); var urlPrefix = Meteor.absoluteUrl() + '__cordova'; - - var localPathPrefix = cordova.file.dataDirectory + 'meteor/'; HTTP.get(urlPrefix + '/manifest.json', function (err, res) { if (err || ! res.data) { log('Failed to download the manifest ' + (err && err.message) + ' ' + (res && res.content)); return; } + updating = true; + ensureLocalPathPrefix(); + var program = res.data; var manifest = _.clone(program.manifest); var version = program.version; @@ -113,8 +117,7 @@ var onNewVersion = function () { // success! downloaded all sources and saved the manifest // save the version string for atomicity - writeFile(localPathPrefix, 'version', version, - function (err) { + writeFile(localPathPrefix, 'version', version, function (err) { if (err) { log("Failed to write version: " + err); return; @@ -122,9 +125,7 @@ var onNewVersion = function () { // don't call reload twice! if (! hasCalledReload) { - // relative to 'bundle.app/www' - var location = - decodeURI(localPathPrefix + version).replace(/^file:\/\//, ''); + var location = uriToPath(localPathPrefix + version); restartServer(location); } }); @@ -214,5 +215,78 @@ Autoupdate._retrySubscription = function () { } }; +Meteor.startup(function () { + clearAutoupdateCache(autoupdateVersionCordova); +}); Meteor.startup(Autoupdate._retrySubscription); + +// A helper that removes old directories left from previous autoupdates +var clearAutoupdateCache = function (currentVersion) { + ensureLocalPathPrefix(); + // Try to clean up our cache directory, make sure to scan the directory + // *before* loading the actual app. This ordering will prevent race + // conditions when the app code tries to download a new version before + // the old-cache removal has scanned the cache folder. + listDirectory(localPathPrefix, {dirsOnly: true}, function (err, names) { + // Couldn't get the list of dirs or risking to get into a race with an + // on-going update to disk. + if (err || updating) { + return; + } + + _.each(names, function (name) { + // Skip the folder with the latest version + if (name === currentVersion) + return; + + // remove everything else, as we don't want to keep too much cache + // around on disk + removeDirectory(localPathPrefix + name + '/', function (err) { + if (err) { + log('Failed to remove an old cache folder ' + + name + ':' + err.message); + } else { + log('Successfully removed an old cache folder ' + name); + } + }); + }); + }); +}; + +// Cordova File plugin helpers +var listDirectory = function (url, options, cb) { + if (typeof options === 'function') + cb = options, options = {}; + + var fail = function (err) { cb(err); }; + window.resolveLocalFileSystemURL(url, function (entry) { + var reader = entry.createReader(); + reader.readEntries(function (entries) { + var names = []; + _.each(entries, function (entry) { + if (! options.dirsOnly || entry.isDirectory) + names.push(entry.name); + }); + cb(null, names); + }, fail); + }, fail); +}; + +var removeDirectory = function (url, cb) { + var fail = function (err) { + cb(err); + }; + window.resolveLocalFileSystemURL(url, function (entry) { + entry.removeRecursively(function () { cb(); }, fail); + }, fail); +}; + +var uriToPath = function (uri) { + return decodeURI(uri).replace(/^file:\/\//g, ''); +}; + +var ensureLocalPathPrefix = function () { + localPathPrefix = localPathPrefix || cordova.file.dataDirectory + 'meteor/'; +}; + diff --git a/tools/client/meteor_cordova_loader.js b/tools/client/meteor_cordova_loader.js index 346e68afbd..ad6a9c9e9c 100644 --- a/tools/client/meteor_cordova_loader.js +++ b/tools/client/meteor_cordova_loader.js @@ -11,6 +11,9 @@ var log = function (msg) { console.log(DEBUG_TAG + msg); }; + var uriToPath = function (uri) { + return decodeURI(uri).replace(/^file:\/\//g, ''); + }; var readFile = function (url, cb) { window.resolveLocalFileSystemURL(url, function (fileEntry) { var success = function (file) { @@ -32,21 +35,11 @@ }); }; - var each = function (array, f) { - for (var i = 0; i < array.length; i++) - f(array[i], i, array); - }; - - - var stripLeadingSlash = function (p) { - if (p.charAt(0) !== '/') - throw new Error("bad path: " + p); - return p.slice(1); - }; - var loadTries = 0; var loadFromLocation = function (location) { - var cordovaRoot = decodeURI(window.location.href).replace(/\/index.html$/, '/').replace(/^file:\/\/?/, ''); + var cordovaRoot = + uriToPath(window.location.href).replace(/\/index.html$/, '/'); + var httpd = cordova && cordova.plugins && cordova.plugins.CordovaUpdate; var retry = function () { @@ -85,41 +78,14 @@ log('No new versions saved to disk.'); } var location = cordova.file.applicationDirectory + 'www/application/'; - location = decodeURI(location).replace(/^file:\/\//g, ''); + location = uriToPath(location); loadFromLocation(location); }; - var listDirectory = function (url, options, cb) { - if (typeof options === 'function') - cb = options, options = {}; - - var fail = function (err) { cb(err); }; - window.resolveLocalFileSystemURL(url, function (entry) { - var reader = entry.createReader(); - reader.readEntries(function (entries) { - var names = []; - each(entries, function (entry) { - if (! options.dirsOnly || entry.isDirectory) - names.push(entry.name); - }); - cb(null, names); - }, fail); - }, fail); - }; - - var removeDirectory = function (url, cb) { - var fail = function (err) { - cb(err); - }; - window.resolveLocalFileSystemURL(url, function (entry) { - entry.removeRecursively(function () { cb(); }, fail); - }, fail); - }; - var loadVersion = function (version, localPathPrefix) { var versionPrefix = localPathPrefix + version + '/'; - var location = decodeURI(versionPrefix).replace(/^file:\/\//g, '') + var location = uriToPath(versionPrefix); loadFromLocation(location); }; @@ -131,31 +97,7 @@ return; } - // Try to clean up our cache directory, make sure to scan the directory - // *before* loading the actual app. This ordering will prevent race - // conditions when the app code tries to download a new version before - // the old-cache removal has scanned the cache folder. - listDirectory(localPathPrefix, {dirsOnly: true}, function (err, names) { - loadVersion(version, localPathPrefix); - - if (err) return; - each(names, function (name) { - // Skip the folder with the latest version - if (name === version) - return; - - // remove everything else, as we don't want to keep too much cache - // around on disk - removeDirectory(localPathPrefix + name + '/', function (err) { - if (err) { - log('Failed to remove an old cache folder ' - + name + ':' + err.message); - } else { - log('Successfully removed an old cache folder ' + name); - } - }); - }); - }); + loadVersion(version, localPathPrefix); }); }; diff --git a/tools/commands-cordova.js b/tools/commands-cordova.js index f7ccd02201..278d0237dc 100644 --- a/tools/commands-cordova.js +++ b/tools/commands-cordova.js @@ -1562,6 +1562,8 @@ _.extend(IOS.prototype, { okay = fix; } + if (!okay) return okay; + //Check if the full Xcode package is already installed: // // $ xcode-select -p @@ -1581,6 +1583,8 @@ _.extend(IOS.prototype, { } } + if (!okay) return okay; + _.each(['5.0', '5.0.1', '5.1', '6.0', '6.1'], function (version) { if (self.isSdkInstalled(version)) { log && Console.warn("An old version of the iPhone SDK is installed (" + version + "); you should"); @@ -1975,6 +1979,8 @@ _.extend(Android.prototype, { okay = fix; } + if (!okay) return okay; + // (hasAcceleration can also be undefined) var hasAcceleration = self.hasAcceleration(); if (hasAcceleration === false) { @@ -1986,6 +1992,8 @@ _.extend(Android.prototype, { log && Console.info(Console.success("HAXM is installed")); } + if (!okay) return okay; + if (self.hasAndroidBundle()) { log && Console.info(Console.success("Found Android bundle")); } else { @@ -1995,6 +2003,8 @@ _.extend(Android.prototype, { okay = fix; } + if (!okay) return okay; + if (self.hasTarget('19', 'default/x86')) { log && Console.info(Console.success("Found suitable Android API libraries")); } else { @@ -2004,6 +2014,8 @@ _.extend(Android.prototype, { okay = fix; } + if (!okay) return okay; + var avdName = self.getAvdName(); if (self.hasAvd(avdName)) { log && Console.info(Console.success("'" + avdName + "' android virtual device (AVD) found"));