Some updates on NAppUpdate
After having several issues with their auto-update mechanism, 2 weeks ago the Hibernating Rhinos profilers were updated to use NAppUpdate. Once again it was proven to be a very flexible and robust library, and several updates were already pushed to hundreds (thousands?) of users without any problem.
Before the profilers could start using NAppUpdate I had to make some updates to the library, namely: catch and expose the last error thrown (if any); fix an issue with UAC popping for updates on Windows 7 and Vista; better support for promptly cancelling a download mid-way; and a few other fixes and updates. These fixes are already available on github, and probably invalidate the 0.1 release...
Implementing NAppUpdate required custom implementation of a FeedReader and a Task, and the whole process didn't take more than one hour to code (testing is another story...). The profiler's AutoUpdateFeedReader makes a simple check against a very simple one-liner feed with the profiler's current version, and the it's AutoUpdateTask downloads the latest build as a zip file from the server, extracts it to a temporary folder and when told to overwrites the old files with the new ones in a bulk.
The actual task looks something like this - note the logical separation into steps, which are executed sequentially:
[code lang="csharp"]
public bool Prepare(IUpdateSource source)
{
// Clear temp folder
if (Directory.Exists(updateDirectory))
{
try
{
Directory.Delete(updateDirectory, true);
}
catch {}
}
Directory.CreateDirectory(updateDirectory);
// Download the zip to a temp file that is deleted automatically when the app exits
string zipLocation = null;
try
{
if (!source.GetData(LatestVersionDownloadUrl, string.Empty, ref zipLocation))
return false;
}
catch (Exception ex)
{
Log.Error("Cannot get update package from source", ex);
throw new UpdateProcessFailedException("Couldn't get Data from source", ex);
}
if (string.IsNullOrEmpty(zipLocation))
return false;
// Unzip to temp folder; no need to delete the zip file as this will be done by the OS
return Extract(zipLocation);
}
public bool Execute()
{
// since all we do is a cold update, nothing other than backup needs to happen here
return true;
}
public IEnumerator<KeyValuePair<string, object>> GetColdUpdates()
{
if (filesList == null)
yield break;
foreach (var file in filesList)
{
yield return new KeyValuePair<string, object>(file, Path.Combine(updateDirectory, file));
Log.DebugFormat("Registering file {0} to be updated with {1}", file, Path.Combine(updateDirectory, file));
}
}
[/code]
Triggering the actual check for updates is a one-liner (after configuring the UpdateManager instance with a feed URL, a FeedReader and all that; the task is created and returned by the custom FeedReader):
[code lang="csharp"]
UpdateManager.Instance.updateManager.CheckForUpdateAsync(StartDownloadingUpdate);
// ...
private void StartDownloadingUpdate(int updates)
{
if (updates == 0) // no updates are available
return;
if (updates < 0) // an error has occurred
{
Log.ErrorFormat("Error while checking for updates: {0}", UpdateManager.Instance.LatestError);
return;
}
// If updates are found, start downloading them async
UpdateManager.Instance.PrepareUpdatesAsync(success =>
{
if (!success)
{
if (UpdateManager.Instance.LatestError != null)
{
Log.ErrorFormat("Error downloading updates: {0}", UpdateManager.Instance.LatestError);
}
return;
}
// Notify the user of the update, and call UpdateManager.Instance.ApplyUpdates() when ready
});
}
[/code]
It couldn't be simpler than that, and it just works...
This has triggered some interest in the project, and wheels are now in motion again and hopefully new features will be introduced soon, followed by a 0.2 release.
As always, you can grab the sources and file bugs here. Bugs and feature-requests can also be submitted to the mailing list.
Comments
Comments are now closed