[banshee] Windows: Auto-update functionality (bgo#641960)
- From: Gabriel Burt <gburt src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [banshee] Windows: Auto-update functionality (bgo#641960)
- Date: Tue, 22 Mar 2011 21:09:48 +0000 (UTC)
commit b0c18050a1e4e8c72d1af6eb790b1575146168c5
Author: Ján Sokoly <cruster gmail com>
Date: Mon Mar 14 23:34:43 2011 +0100
Windows: Auto-update functionality (bgo#641960)
Checks for update on startup, looking for a newer unstable release,
downloads it in background and launches the installer.
Signed-off-by: Gabriel Burt <gabriel burt gmail com>
.../Banshee.Windows/Banshee.Windows.csproj | 7 +-
.../Banshee.Windows/VersionUpdater.cs | 194 ++++++++++++++++++++
.../Banshee.Windows/WindowsService.cs | 28 +++
.../Resources/core-ui-actions-layout.xml | 1 +
4 files changed, 229 insertions(+), 1 deletions(-)
---
diff --git a/src/Backends/Banshee.Windows/Banshee.Windows.csproj b/src/Backends/Banshee.Windows/Banshee.Windows.csproj
index 2c6f9f1..5f3fd92 100644
--- a/src/Backends/Banshee.Windows/Banshee.Windows.csproj
+++ b/src/Backends/Banshee.Windows/Banshee.Windows.csproj
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
+<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="3.5">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
@@ -82,8 +82,13 @@
<Reference Include="System.Core">
</Reference>
<Reference Include="System.Windows.Forms" />
+ <Reference Include="System.Xml" />
+ <Reference Include="System.Xml.Linq">
+ <RequiredTargetFramework>3.5</RequiredTargetFramework>
+ </Reference>
</ItemGroup>
<ItemGroup>
+ <Compile Include="Banshee.Windows\VersionUpdater.cs" />
<Compile Include="Banshee.Windows\WindowsService.cs" />
<Compile Include="Banshee.Windows\ExtensionsForGtkAction.cs" />
<Compile Include="Banshee.Windows\GtkWindowThumbnailToolbarManager.cs" />
diff --git a/src/Backends/Banshee.Windows/Banshee.Windows/VersionUpdater.cs b/src/Backends/Banshee.Windows/Banshee.Windows/VersionUpdater.cs
new file mode 100644
index 0000000..2380335
--- /dev/null
+++ b/src/Backends/Banshee.Windows/Banshee.Windows/VersionUpdater.cs
@@ -0,0 +1,194 @@
+//
+// VersionUpdater.cs
+//
+// Authors:
+// Ján Sokoly <cruster gmail com>
+//
+// Copyright 2011 Ján Sokoly
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using System.Diagnostics;
+using System.IO;
+using System.Linq;
+using System.Xml.Linq;
+
+using Banshee.Gui;
+using Banshee.ServiceStack;
+
+using Gtk;
+using Hyena.Downloader;
+using Mono.Unix;
+
+namespace Banshee.Windows
+{
+ public class VersionUpdater : DownloadManager
+ {
+ private const string download_url = "http://download.banshee.fm/banshee/";
+ private const string doap_filename = "banshee.doap";
+ private string temp_doap_path = Path.GetTempPath () + doap_filename;
+ private string unstable_version;
+ private string temp_installer_path;
+ private bool verbose;
+ private DownloadManagerJob job;
+
+ public void CheckForUpdates (bool verbose)
+ {
+ this.verbose = verbose;
+
+ HttpFileDownloader downloader = new HttpFileDownloader ();
+ downloader.Uri = new Uri (download_url + doap_filename);
+ downloader.TempPathRoot = Path.GetTempPath ();
+ downloader.Finished += new Action<HttpDownloader> (DoapDownloader_Finished);
+ downloader.Start ();
+
+ temp_doap_path = downloader.LocalPath;
+ }
+
+ void DoapDownloader_Finished (HttpDownloader obj)
+ {
+ if (obj.State.FailureException != null) {
+ if (verbose) {
+ DisplayMessage (Catalog.GetString ("Can't check for updates"), Catalog.GetString ("We're currently not able to check if there's a new version available. Please try again later."), MessageType.Error);
+ }
+ }
+ else {
+ XDocument doap = XDocument.Load (temp_doap_path);
+ XNamespace nsDoap = XNamespace.Get ("http://usefulinc.com/ns/doap#");
+ unstable_version = (from p in doap.Descendants (nsDoap + "Version")
+ where p.Element (nsDoap + "branch").Value.StartsWith ("master")
+ select new { Revision = p.Element (nsDoap + "revision").Value }).First ().Revision;
+
+ // once we have the version information, the temporary local copy of doap may be deleted
+ File.Delete (temp_doap_path);
+
+ if (!String.IsNullOrEmpty (unstable_version) &&
+ Banshee.ServiceStack.Application.Version != "Unknown" &&
+ new Version (Banshee.ServiceStack.Application.Version) < new Version (unstable_version)) {
+ Gtk.Application.Invoke (delegate {
+ DisplayUpdateAvailableDialog ();
+ });
+ }
+ else {
+ if (verbose) {
+ DisplayMessage (Catalog.GetString ("No update available"), Catalog.GetString ("You already have the latest version of Banshee installed."), MessageType.Info);
+ }
+ }
+ }
+ }
+
+ public void DisplayUpdateAvailableDialog ()
+ {
+ bool update;
+ using (var message_dialog = new MessageDialog (ServiceManager.Get<GtkElementsService> ().PrimaryWindow, 0, MessageType.Question, ButtonsType.YesNo, String.Format (Catalog.GetString ("A new version of Banshee ({0}) is available.{1}Do you want to update?"), unstable_version, Environment.NewLine))) {
+ message_dialog.WindowPosition = WindowPosition.CenterOnParent;
+ message_dialog.Title = Catalog.GetString ("Banshee update available");
+ update = (message_dialog.Run () == (int)ResponseType.Yes);
+ message_dialog.Destroy ();
+ }
+
+ if (update) {
+ string downloadUrl = String.Format ("{0}unstable/{1}/Banshee-{1}.msi", download_url, unstable_version);
+
+ HttpFileDownloader downloader = new HttpFileDownloader ();
+ downloader.Uri = new Uri (downloadUrl);
+ downloader.TempPathRoot = Path.GetTempPath ();
+ downloader.FileExtension = "msi";
+ downloader.Progress += new Action<HttpDownloader> (InstallerDownloader_Progress);
+ downloader.Finished += new Action<HttpDownloader> (InstallerDownloader_Finished);
+ downloader.Start ();
+
+ temp_installer_path = downloader.LocalPath;
+
+ job = new DownloadManagerJob (this)
+ {
+ Title = Catalog.GetString (String.Format ("Downloading Banshee-{0}.msi", unstable_version)),
+ CanCancel = false
+ };
+
+ ServiceManager.Get<JobScheduler> ().Add (job);
+ }
+ }
+
+ void InstallerDownloader_Progress (HttpDownloader obj)
+ {
+ string downloaded = Math.Round (obj.State.TotalBytesRead / 1024d / 1024d, 1).ToString ("F1");
+ string todownload = Math.Round (obj.State.TotalBytesExpected / 1024d / 1024d, 1).ToString ();
+ string rate = Math.Round (obj.State.TransferRate / 1024d, 1).ToString ("F1");
+
+ job.Progress = obj.State.PercentComplete;
+ job.Status = String.Format ("{0} MB / {1} MB ({2} KB/s)", downloaded, todownload, rate);
+ }
+
+ void InstallerDownloader_Finished (HttpDownloader obj)
+ {
+ base.OnDownloaderFinished (obj);
+
+ if (obj.State.FailureException != null) {
+ DisplayMessage (Catalog.GetString ("Update download failed"), Catalog.GetString ("The download failed. Please try again later."), MessageType.Error);
+ }
+ else {
+ Gtk.Application.Invoke (delegate {
+ DisplayUpdateFinishedDownloadingDialog ();
+ });
+ }
+ }
+
+ private void DisplayUpdateFinishedDownloadingDialog ()
+ {
+ bool update;
+ using (var message_dialog = new MessageDialog (ServiceManager.Get<GtkElementsService> ().PrimaryWindow, 0, MessageType.Question, ButtonsType.YesNo, String.Format (Catalog.GetString ("The update finished downloading.{0}Do you want to shutdown Banshee and run the installer?"), Environment.NewLine))) {
+ message_dialog.WindowPosition = WindowPosition.CenterOnParent;
+ message_dialog.Title = Catalog.GetString ("Update finished downloading");
+ update = (message_dialog.Run () == (int)ResponseType.Yes);
+ message_dialog.Destroy ();
+ }
+
+ if (update) {
+ // run the downloaded installer and shutdown the running instance of Banshee
+ Process msiProcess = new Process ();
+ msiProcess.StartInfo.FileName = "msiexec";
+ msiProcess.StartInfo.Arguments = "/i " + temp_installer_path;
+ msiProcess.Start ();
+
+ Banshee.ServiceStack.Application.Shutdown ();
+ }
+ else {
+ // delete the downloaded installer as the user does not want to update now
+ File.Delete (temp_installer_path);
+ }
+ }
+
+ // helper which makes it possible to show Gtk's MessageDialog from a thread
+ private void DisplayMessage (string title, string message, MessageType type)
+ {
+ Gtk.Application.Invoke (delegate {
+ using (var message_dialog = new MessageDialog (ServiceManager.Get<GtkElementsService> ().PrimaryWindow, 0, type, ButtonsType.Ok, message)) {
+ message_dialog.WindowPosition = WindowPosition.CenterOnParent;
+ message_dialog.Title = title;
+ message_dialog.Run ();
+ message_dialog.Destroy ();
+ }
+ });
+ }
+ }
+}
diff --git a/src/Backends/Banshee.Windows/Banshee.Windows/WindowsService.cs b/src/Backends/Banshee.Windows/Banshee.Windows/WindowsService.cs
index ecc9684..f7604ff 100644
--- a/src/Backends/Banshee.Windows/Banshee.Windows/WindowsService.cs
+++ b/src/Backends/Banshee.Windows/Banshee.Windows/WindowsService.cs
@@ -36,6 +36,7 @@ using System.Text;
using Banshee.ServiceStack;
using Banshee.Gui;
+using Mono.Unix;
using Windows7Support;
namespace Banshee.Windows
@@ -45,6 +46,7 @@ namespace Banshee.Windows
bool disposed;
GtkElementsService elements_service;
InterfaceActionService interface_action_service;
+ VersionUpdater version_updater = new VersionUpdater ();
private IList<ThumbnailToolbarButton> buttons;
@@ -92,6 +94,7 @@ namespace Banshee.Windows
public void Initialize ()
{
// TODO check for updates and other cool stuff
+ version_updater.CheckForUpdates (false);
elements_service = ServiceManager.Get<GtkElementsService> ();
interface_action_service = ServiceManager.Get<InterfaceActionService> ();
@@ -99,6 +102,31 @@ namespace Banshee.Windows
if (!ServiceStart ()) {
ServiceManager.ServiceStarted += OnServiceStarted;
}
+
+ // add check for updates action
+ interface_action_service.GlobalActions.Add (new Gtk.ActionEntry[] {
+ new Gtk.ActionEntry ("CheckForUpdatesAction", null,
+ Catalog.GetString("Check for Updates"), null,
+ null, CheckForUpdatesEvent)
+ });
+
+ // merge check for updates menu item
+ interface_action_service.UIManager.AddUiFromString (@"
+ <ui>
+ <menubar name=""MainMenu"">
+ <menu name=""HelpMenu"" action=""HelpMenuAction"">
+ <placeholder name=""CheckForUpdatesPlaceholder"">
+ <menuitem name=""CheckForUpdates"" action=""CheckForUpdatesAction""/>
+ </placeholder>
+ </menu>
+ </menubar>
+ </ui>
+ ");
+ }
+
+ private void CheckForUpdatesEvent (object o, EventArgs args)
+ {
+ version_updater.CheckForUpdates (true);
}
#endregion
diff --git a/src/Core/Banshee.ThickClient/Resources/core-ui-actions-layout.xml b/src/Core/Banshee.ThickClient/Resources/core-ui-actions-layout.xml
index 547fe75..7908e13 100644
--- a/src/Core/Banshee.ThickClient/Resources/core-ui-actions-layout.xml
+++ b/src/Core/Banshee.ThickClient/Resources/core-ui-actions-layout.xml
@@ -121,6 +121,7 @@
<menuitem name="Wiki" action="WikiAction"/>
<menuitem name="WikiDeveloper" action="WikiDeveloperAction"/>
<separator/>
+ <placeholder name="CheckForUpdatesPlaceholder"/>
<menuitem name="VersionInformation" action="VersionInformationAction"/>
<menuitem name="About" action="AboutAction"/>
</menu>
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]