Make the updater properly clean up after previous failed attempts to update, improve logging so that modules can be properly turned on and off for easier debugging, implement automated testing mode

This commit is contained in:
ben%bengoodger.com 2005-06-24 22:50:39 +00:00
Родитель 739f4f6901
Коммит efdb7c74c9
2 изменённых файлов: 102 добавлений и 47 удалений

Просмотреть файл

@ -43,6 +43,10 @@ const XMLNS_XUL = "http://www.mozilla.org/keymaster/gatekeeper/the
const PREF_UPDATE_MANUAL_URL = "app.update.url.manual";
const PREF_UPDATE_NAGTIMER_DL = "app.update.nagTimer.download";
const PREF_UPDATE_NAGTIMER_RESTART = "app.update.nagTimer.restart";
const PREF_APP_UPDATE_LOG_BRANCH = "app.update.log.";
const PREF_UPDATE_TEST_LOOP = "app.update.test.loop";
const UPDATE_TEST_LOOP_INTERVAL = 2000;
const URI_UPDATES_PROPERTIES = "chrome://mozapps/locale/update/updates.properties";
@ -55,15 +59,20 @@ const STATE_FAILED = "failed";
const SRCEVT_FOREGROUND = 1;
const SRCEVT_BACKGROUND = 2;
var gPref = null;
var gConsole = null;
var gPref = null;
var gLogEnabled = { };
/**
* Logs a string to the error console.
* @param string
* The string to write to the error console..
*/
function LOG(string) {
dump("*** " + string + "\n");
function LOG(module, string) {
if (module in gLogEnabled) {
dump("*** " + module + ":" + string + "\n");
gConsole.logStringMessage(string);
}
}
/**
@ -83,7 +92,7 @@ function getPref(func, preference, defaultValue) {
return gPref[func](preference);
}
catch (e) {
LOG("FAIL = " + e);
LOG("General", "Failed to get preference " + preference);
}
return defaultValue;
}
@ -139,7 +148,10 @@ var gUpdates = {
onLoad: function() {
gPref = Components.classes["@mozilla.org/preferences-service;1"]
.getService(Components.interfaces.nsIPrefBranch2);
gConsole = Components.classes["@mozilla.org/consoleservice;1"]
.getService(Components.interfaces.nsIConsoleService);
this._initLoggingPrefs();
this.strings = document.getElementById("updateStrings");
var brandStrings = document.getElementById("brandStrings");
this.brandName = brandStrings.getString("brandShortName");
@ -162,7 +174,26 @@ var gUpdates = {
// Advance to the Start page.
de.currentPage = this.startPage;
},
/**
*
*/
_initLoggingPrefs: function() {
try {
var ps = Components.classes["@mozilla.org/preferences-service;1"]
.getService(Components.interfaces.nsIPrefService);
var logBranch = ps.getBranch(PREF_APP_UPDATE_LOG_BRANCH);
var modules = logBranch.getChildList("", { value: 0 });
for (var i = 0; i < modules.length; ++i) {
if (logBranch.prefHasUserValue(modules[i]))
gLogEnabled[modules[i]] = logBranch.getBoolPref(modules[i]);
}
}
catch (e) {
}
},
/**
* Return the <wizardpage> object that should be displayed first.
*
@ -337,8 +368,9 @@ var gCheckingPage = {
.getService(Components.interfaces.nsIApplicationUpdateService);
gUpdates.update = aus.selectUpdate(updates, updates.length);
if (!gUpdates.update) {
LOG("Could not select an appropriate update, either because there were none," +
" or |selectUpdate| failed.");
LOG("UI:CheckingPage",
"Could not select an appropriate update, either because there " +
"were none, or |selectUpdate| failed.");
var checking = document.getElementById("checking");
checking.setAttribute("next", "noupdatesfound");
}
@ -349,7 +381,7 @@ var gCheckingPage = {
* See nsIUpdateCheckListener.idl
*/
onError: function() {
LOG("UpdateCheckListener: ERROR");
LOG("UI:CheckingPage", "UpdateCheckListener: ERROR");
},
/**
@ -728,7 +760,7 @@ var gDownloadingPage = {
}
if (!gUpdates.update) {
LOG("gDownloadingPage.onPageShow: no valid update to download?!");
LOG("UI:DownloadingPage.Progress", "no valid update to download?!");
return;
}
@ -859,7 +891,7 @@ var gDownloadingPage = {
}
if (downloadInBackground) {
// Cancel the download and start it again in the background.
LOG("gDownloadingPage.onWizardCancel: resuming download in background");
LOG("UI:DownloadingPage", "onWizardCancel: resuming download in background");
updates.pauseDownload();
updates.downloadUpdate(gUpdates.update, true);
}
@ -870,7 +902,7 @@ var gDownloadingPage = {
*/
onStartRequest: function(request, context) {
request.QueryInterface(nsIIncrementalDownload);
LOG("gDownloadingPage.onStartRequest: " + request.URI.spec);
LOG("UI:DownloadingPage", "onStartRequest: " + request.URI.spec);
this._statusFormatter = new DownloadStatusFormatter();
@ -882,7 +914,8 @@ var gDownloadingPage = {
*/
onProgress: function(request, context, progress, maxProgress) {
request.QueryInterface(nsIIncrementalDownload);
// LOG("gDownloadingPage.onProgress: " + request.URI.spec + ", " + progress + "/" + maxProgress);
LOG("UI:DownloadingPage.onProgress", request.URI.spec + ", " + progress +
"/" + maxProgress);
var p = gUpdates.update.selectedPatch;
p.QueryInterface(Components.interfaces.nsIWritablePropertyBag);
@ -903,7 +936,8 @@ var gDownloadingPage = {
*/
onStatus: function(request, context, status, statusText) {
request.QueryInterface(nsIIncrementalDownload);
LOG("gDownloadingPage.onStatus: " + request.URI.spec + " status = " + status + ", text = " + statusText);
LOG("UI:DownloadingPage", "onStatus: " + request.URI.spec + " status = " +
status + ", text = " + statusText);
},
/**
@ -911,7 +945,8 @@ var gDownloadingPage = {
*/
onStopRequest: function(request, context, status) {
request.QueryInterface(nsIIncrementalDownload);
LOG("gDownloadingPage.onStopRequest: " + request.URI.spec + ", status = " + status);
LOG("UI:DownloadingPage", "onStopRequest: " + request.URI.spec +
", status = " + status);
this._downloadThrobber.removeAttribute("state");
@ -932,12 +967,12 @@ var gDownloadingPage = {
}
break;
case NS_BINDING_ABORTED:
LOG("gDownloadingPage.onStopRequest: Pausing Download");
LOG("UI:DownloadingPage", "onStopRequest: Pausing Download");
// Return early, do not remove UI listener since the user may resume
// downloading again.
return;
case Components.results.NS_OK:
LOG("gDownloadingPage.onStopRequest: Patch Verification Succeeded");
LOG("UI:Downloader", "onStopRequest: Patch Verification Succeeded");
document.documentElement.advance();
break;
}
@ -1007,6 +1042,13 @@ var gFinishedPage = {
link.href = gUpdates.update.detailsURL;
this.onPageShow();
if (getPref("getBoolPref", PREF_UPDATE_TEST_LOOP, false)) {
window.restart = function () {
document.documentElement.getButton("finish").click();
}
setTimeout("restart();", UPDATE_TEST_LOOP_INTERVAL);
}
},
/**
@ -1015,7 +1057,7 @@ var gFinishedPage = {
*/
onWizardFinish: function() {
// Do the restart
LOG("gFinishedPage.onWizardFinish: Restarting Application...");
LOG("UI:FinishedPage" , "onWizardFinish: Restarting Application...");
// This process is *extremely* retarded. There should be some nice
// integrated system for determining whether or not windows are allowed

Просмотреть файл

@ -1365,7 +1365,7 @@ Downloader.prototype = {
_readStatusFile: function(dir) {
var statusFile = dir.clone();
statusFile.append(FILE_UPDATE_STATUS);
LOG("Downloader", statusFile.path);
LOG("Downloader", "Reading Status File: " + statusFile.path);
return readStringFromFile(statusFile);
},
@ -1444,11 +1444,12 @@ Downloader.prototype = {
// to select ourselves.
var selectedPatch = update.selectedPatch;
var state = this._readStatusFile(updateDir)
// If this is a patch that we know about, then select it. If it is a patch
// that we do not know about, then remove it and use our default logic.
var useComplete = false;
if (selectedPatch) {
var state = this._readStatusFile(updateDir)
LOG("Downloader", "found existing patch [state="+state+"]");
switch (state) {
case STATE_DOWNLOADING:
@ -1470,22 +1471,9 @@ Downloader.prototype = {
}
}
// The patch is no longer known to us, so we should assume that it is
// no longer valid. Remove all from the updateDir.
// XXX We may want to preserve an update.log file from a failed update.
// We expect this operation may fail since some files (e.g., updater.exe)
// may still be in use. That's ok.
try {
updateDir.remove(true);
} catch (e) {}
// Restore the updateDir since we may have deleted it.
updateDir = this._updatesDir;
selectedPatch = null;
}
LOG("Downloader", "USE COMPLETE = " + useComplete);
// If we were not able to discover an update from a previous download, we
// select the best patch from the given set.
var partialPatch = getPatchOfType("partial");
@ -1496,6 +1484,33 @@ Downloader.prototype = {
partialPatch.selected = false;
selectedPatch = getPatchOfType("complete");
}
// The patch is no longer known to us, so we should assume that it is
// no longer valid. Remove all from the updateDir.
// XXX We may want to preserve an update.log file from a failed update.
// We expect this operation may fail since some files
// (e.g., updater.exe) may still be in use. That's ok.
var e = updateDir.directoryEntries;
while (e.hasMoreElements()) {
var f = e.getNext().QueryInterface(Components.interfaces.nsIFile);
try {
f.remove(false);
}
catch (e) {
LOG("Downloader", "Failed to remove file: " + f.path);
}
}
try {
updateDir.remove(false);
} catch (e) {
LOG("Downloader", "Failed to remove update directory: " + updateDir.path +
" - This is almost always bad. Exception = " + e);
throw e;
}
// Restore the updateDir since we may have deleted it.
updateDir = this._updatesDir;
selectedPatch.selected = true;
update.isCompleteUpdate = useComplete;
@ -1531,7 +1546,6 @@ Downloader.prototype = {
// This function may return null, which indicates that there are no patches
// to download.
this._patch = this._selectPatch(update, updateDir);
LOG("Downloader", "PATCH = " + this._patch);
if (!this._patch) {
LOG("Downloader", "no patch to download");
return this._readStatusFile(updateDir);
@ -1557,7 +1571,6 @@ Downloader.prototype = {
this._request.init(uri, patchFile, DOWNLOAD_CHUNK_SIZE, interval);
this._request.start(this, null);
LOG("Downloader", "setting state = " + STATE_DOWNLOADING);
this._writeStatusFile(updateDir, STATE_DOWNLOADING);
this._patch.QueryInterface(Components.interfaces.nsIWritablePropertyBag);
this._patch.state = STATE_DOWNLOADING;
@ -1612,7 +1625,7 @@ Downloader.prototype = {
*/
onProgress: function(request, context, progress, maxProgress) {
request.QueryInterface(nsIIncrementalDownload);
// LOG("Downloader", "onProgress: " + request.URI.spec + ", " + progress + "/" + maxProgress);
LOG("Downloader.onProgress", "onProgress: " + request.URI.spec + ", " + progress + "/" + maxProgress);
var listenerCount = this._listeners.length;
for (var i = 0; i < listenerCount; ++i) {
@ -1643,9 +1656,9 @@ Downloader.prototype = {
request.QueryInterface(nsIIncrementalDownload);
LOG("Downloader", "onStopRequest: " + request.URI.spec + ", status = " + status);
var state;
var shouldShowPrompt = false;
if (Components.isSuccessCode(status)) {
var state;
if (this._verifyDownload()) {
state = STATE_PENDING;
@ -1667,16 +1680,6 @@ Downloader.prototype = {
.getService(Components.interfaces.nsIUpdateManager);
um.activeUpdate = null;
um.saveUpdates();
if (state == STATE_FAILED && !this._update.isCompleteUpdate) {
// If we were downloading a patch and the patch verification phase
// failed, log this and then commence downloading the complete update.
LOG("Downloader", "onStopRequest: Verification of patch failed, downloading complete update");
this._update.isCompleteUpdate = true;
this.downloadUpdate(this._update);
// This will reset the |.state| property on this._update if a new
// download initiates.
}
}
var listenerCount = this._listeners.length;
@ -1685,6 +1688,16 @@ Downloader.prototype = {
this._request = null;
if (state == STATE_FAILED && !this._update.isCompleteUpdate) {
// If we were downloading a patch and the patch verification phase
// failed, log this and then commence downloading the complete update.
LOG("Downloader", "onStopRequest: Verification of patch failed, downloading complete update");
this._update.isCompleteUpdate = true;
this.downloadUpdate(this._update);
// This will reset the |.state| property on this._update if a new
// download initiates.
}
// Do this after *everything* else, since it will likely cause the app
// to shut down.
if (shouldShowPrompt) {