Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/monodevelop.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Hutchinson <mhutchinson@novell.com>2010-10-15 01:49:39 +0400
committerMichael Hutchinson <mhutchinson@novell.com>2010-10-15 01:52:09 +0400
commiteaf7716c477eb19145b823cb731df433619e9065 (patch)
treea1edfe0af7ab0e39e948fd3b89adac72fc409dbc /main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Updater
parentfd93b845081612cdbfa734fd7745cc372d5045dd (diff)
Move updater to MonoDevelop.Ide, make extensible
The Mac updater is now in MonoDevelop.Ide. Addins can register updateinfo files and platform services can provide an updater URL and environment flags.
Diffstat (limited to 'main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Updater')
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Updater/UpdateCommands.cs59
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Updater/UpdateDialog.cs205
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Updater/UpdateInfoExtensionNode.cs42
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Updater/UpdateResult.cs103
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Updater/UpdateService.cs244
5 files changed, 653 insertions, 0 deletions
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Updater/UpdateCommands.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Updater/UpdateCommands.cs
new file mode 100644
index 0000000000..ce6f48fa2b
--- /dev/null
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Updater/UpdateCommands.cs
@@ -0,0 +1,59 @@
+//
+// UpdateCommands.cs
+//
+// Author:
+// Michael Hutchinson <mhutchinson@novell.com>
+//
+// Copyright (c) 2010 Novell, Inc. (http://www.novell.com)
+//
+// 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 MonoDevelop.Components.Commands;
+
+namespace MonoDevelop.Ide.Updater
+{
+ public enum UpdateCommands
+ {
+ CheckForUpdates,
+ }
+
+ class CheckForUpdatesHandler : CommandHandler
+ {
+ protected override void Run ()
+ {
+ UpdateService.RunCheckDialog (false);
+ }
+
+ protected override void Update (CommandInfo info)
+ {
+ info.Visible = info.Enabled = UpdateService.CanUpdate;
+ }
+ }
+
+ class CheckForUpdatesOnStartUpHandler : CommandHandler
+ {
+ protected override void Run()
+ {
+ if (UpdateService.CanUpdate)
+ UpdateService.RunCheckDialog (true);
+ }
+ }
+}
+
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Updater/UpdateDialog.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Updater/UpdateDialog.cs
new file mode 100644
index 0000000000..c7b17a15f5
--- /dev/null
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Updater/UpdateDialog.cs
@@ -0,0 +1,205 @@
+//
+// UpdateDialog.cs
+//
+// Author:
+// Michael Hutchinson <mhutchinson@novell.com>
+//
+// Copyright (c) 2009 Novell, Inc. (http://www.novell.com)
+//
+// 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.Linq;
+using System.Collections.Generic;
+using System.Text;
+
+using Gtk;
+using MonoDevelop.Core;
+using MonoDevelop.Ide;
+
+namespace MonoDevelop.Ide.Updater
+{
+ partial class UpdateDialog : Gtk.Dialog
+ {
+ const int PAGE_MESSAGE = 0;
+ const int PAGE_UPDATES = 1;
+
+ List<UpdateResult> results = new List<UpdateResult> ();
+
+ public UpdateDialog ()
+ {
+ this.Build ();
+ notebook1.ShowTabs = false;
+
+ checkAutomaticallyCheck.Active = UpdateService.CheckAutomatically;
+ checkAutomaticallyCheck.Toggled += delegate {
+ UpdateService.CheckAutomatically = checkAutomaticallyCheck.Active;
+ };
+
+ updateLevelCombo.AppendText (GettextCatalog.GetString ("Stable")); // index = UpdateLevel.Stable
+ updateLevelCombo.AppendText (GettextCatalog.GetString ("Beta (unstable)")); // index = UpdateLevel.Beta
+ updateLevelCombo.AppendText (GettextCatalog.GetString ("Alpha (experimental)"));// index = UpdateLevel.Alpha
+
+ updateLevelCombo.Active = (int) UpdateService.UpdateLevel;
+
+ updateLevelCombo.Changed += delegate {
+ var level = (UpdateLevel) updateLevelCombo.Active;
+ UpdateService.UpdateLevel = level;
+
+ var cachedResult = results.Where (r => r.Level == level).FirstOrDefault ();
+
+ if (cachedResult != null && !cachedResult.HasError) {
+ LoadUpdates (cachedResult.Updates);
+ } else {
+ SetMessage (GettextCatalog.GetString ("Checking for updates..."));
+ UpdateService.QueryUpdateServer (UpdateService.DefaultUpdateInfos, level, delegate (UpdateResult result) {
+ Application.Invoke (delegate {
+ LoadResult (result);
+ });
+ });
+ }
+ };
+
+ SetMessage (GettextCatalog.GetString ("Checking for updates..."));
+ }
+
+ public void LoadResult (UpdateResult result)
+ {
+ bool replaced = false;
+ for (int i = 0; i < results.Count; i++) {
+ if (result.Level == results[i].Level) {
+ results[i] = result;
+ replaced = true;
+ break;
+ }
+ }
+ if (!replaced)
+ results.Add (result);
+
+ if (result.HasError) {
+ SetMessage (result.ErrorMessage);
+ } else {
+ LoadUpdates (result.Updates);
+ }
+ }
+
+ void SetMessage (string message)
+ {
+ notebook1.CurrentPage = PAGE_MESSAGE;
+ messageLabel.Text = message;
+ }
+
+ void LoadUpdates (List<Update> updates)
+ {
+ if (updates == null || updates.Count == 0) {
+ SetMessage (GettextCatalog.GetString ("No updates available"));
+ return;
+ }
+
+ foreach (var c in productBox.Children) {
+ productBox.Remove (c);
+ c.Destroy ();
+ }
+
+ productBox.Spacing = 0;
+
+ foreach (var update in updates) {
+ var updateBox = new VBox () { Spacing = 2 };
+ var labelBox = new HBox ();
+ updateBox.PackStart (labelBox, false, false, 0);
+
+ string warning = null;
+ switch (update.Level) {
+ case UpdateLevel.Alpha:
+ warning = GettextCatalog.GetString ("ALPHA");
+ break;
+ case UpdateLevel.Beta:
+ warning = GettextCatalog.GetString ("BETA");
+ break;
+ case UpdateLevel.Test:
+ warning = GettextCatalog.GetString ("TEST");
+ break;
+ }
+ if (warning != null)
+ warning = "<b><span color=\"#DD1111\">" + warning + "</span></b>";
+
+ var updateExpander = new Expander ("");
+ updateExpander.LabelWidget = new Label () {
+ Markup = string.Format ("<b>{0}</b>\n{1} ({2:yyyy-MM-dd}) {3}", update.Name, update.Version, update.Date,
+ warning ?? ""),
+ };
+ labelBox.PackStart (updateExpander, true, true, 0);
+
+ var downloadButton = new Button () {
+ Label = GettextCatalog.GetString ("Download")
+ };
+
+ //NOTE: grab the variable from the loop var so the closure captures it
+ var url = update.Url;
+ downloadButton.Clicked += delegate {
+ DesktopService.ShowUrl (url);
+ };
+ labelBox.PackStart (downloadButton, false, false, 0);
+
+ var sb = new StringBuilder ();
+ for (int i = 0; i < update.Releases.Count; i++) {
+ var release = update.Releases[i];
+ if (i > 0) {
+ if (i == 1) {
+ sb.AppendLine ();
+ sb.AppendLine ("This release also includes previous updates:");
+ }
+ sb.AppendLine ();
+ sb.AppendFormat ("{0} ({1:yyyy-MM-dd})\n", release.Version, release.Date);
+ sb.AppendLine ();
+ }
+ sb.Append (release.Notes.Trim ('\t', ' ', '\n', '\r'));
+ sb.AppendLine ();
+ }
+ var buffer = new TextBuffer (null);
+ buffer.Text = sb.ToString ();
+ var textView = new TextView (buffer);
+ textView.WrapMode = WrapMode.Word;
+ textView.Editable = false;
+ textView.LeftMargin = textView.RightMargin = 4;
+ updateBox.PackStart (textView, false, false, 0);
+
+ bool startsExpanded = false;
+ updateExpander.Expanded = startsExpanded;
+ updateExpander.Activated += delegate {
+ textView.Visible = updateExpander.Expanded;
+ };
+
+ updateBox.BorderWidth = 4;
+
+ productBox.PackStart (updateBox, false, false, 0);
+ updateBox.ShowAll ();
+ //this has to be set false after the ShowAll
+ textView.Visible = startsExpanded;
+
+
+ var sep = new HSeparator ();
+ productBox.PackStart (sep, false, false, 0);
+ sep.Show ();
+ }
+
+ notebook1.CurrentPage = PAGE_UPDATES;
+ }
+ }
+}
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Updater/UpdateInfoExtensionNode.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Updater/UpdateInfoExtensionNode.cs
new file mode 100644
index 0000000000..f03865ccf1
--- /dev/null
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Updater/UpdateInfoExtensionNode.cs
@@ -0,0 +1,42 @@
+//
+// UpdateInfoExtensionNode.cs
+//
+// Author:
+// Michael Hutchinson <mhutchinson@novell.com>
+//
+// Copyright (c) 2010 Novell, Inc.
+//
+// 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 Mono.Addins;
+
+namespace MonoDevelop.Ide.Updater
+{
+ class UpdateInfoExtensionNode : ExtensionNode
+ {
+ [NodeAttribute (Required=true)]
+ protected string file = null;
+
+ public string File {
+ get { return this.Addin.GetFilePath (file); }
+ }
+ }
+}
+
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Updater/UpdateResult.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Updater/UpdateResult.cs
new file mode 100644
index 0000000000..2b8d1fd89d
--- /dev/null
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Updater/UpdateResult.cs
@@ -0,0 +1,103 @@
+//
+// UpdateResult.cs
+//
+// Author:
+// Michael Hutchinson <mhutchinson@novell.com>
+//
+// Copyright (c) 2010 Novell, Inc. (http://www.novell.com)
+//
+// 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.Linq;
+using System.IO;
+using System.Text;
+using MonoDevelop.Core;
+using System.Net;
+using System.Collections.Generic;
+
+namespace MonoDevelop.Ide.Updater
+{
+ class Update
+ {
+ public string Name;
+ public string Url;
+ public string Version;
+ public DateTime Date;
+ public List<Release> Releases;
+ public UpdateLevel Level;
+ }
+
+ class Release
+ {
+ public string Version;
+ public DateTime Date;
+ public string Notes;
+ }
+
+ class UpdateInfo
+ {
+ UpdateInfo ()
+ {
+ }
+
+ public UpdateInfo (Guid appId, long versionId)
+ {
+ this.AppId = appId;
+ this.VersionId = versionId;
+ }
+
+ public readonly Guid AppId;
+ public readonly long VersionId;
+
+ public static UpdateInfo FromFile (string fileName)
+ {
+ using (var f = File.OpenText (fileName)) {
+ var s = f.ReadLine ();
+ var parts = s.Split (' ');
+ return new UpdateInfo (new Guid (parts[0]), long.Parse (parts[1]));
+ }
+ }
+ }
+
+ class UpdateResult
+ {
+ public UpdateResult (List<Update> updates, UpdateLevel level, string errorMessage, Exception errorDetail)
+ {
+ this.Updates = updates;
+ this.Level = level;
+ this.ErrorMessage = errorMessage;
+ this.ErrorDetail = errorDetail;
+ }
+
+ public List<Update> Updates { get; private set; }
+ public UpdateLevel Level { get; private set; }
+ public string ErrorMessage { get; private set; }
+ public Exception ErrorDetail { get; private set; }
+
+ public bool HasError {
+ get { return !string.IsNullOrEmpty (ErrorMessage); }
+ }
+
+ public bool HasUpdates {
+ get { return Updates != null && Updates.Count > 0; }
+ }
+ }
+}
+
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Updater/UpdateService.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Updater/UpdateService.cs
new file mode 100644
index 0000000000..6ab6382668
--- /dev/null
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Updater/UpdateService.cs
@@ -0,0 +1,244 @@
+//
+// MacUpdater.cs
+//
+// Author:
+// Michael Hutchinson <mhutchinson@novell.com>
+//
+// Copyright (c) 2009 Novell, Inc. (http://www.novell.com)
+//
+// 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.Collections.Generic;
+using System.IO;
+using System.Net;
+using System.Text;
+using System.Linq;
+using MonoDevelop.Core;
+using MonoDevelop.Ide;
+
+namespace MonoDevelop.Ide.Updater
+{
+ enum UpdateLevel
+ {
+ Stable = 0,
+ Beta = 1,
+ Alpha = 2,
+ Test = 3
+ }
+
+ static class UpdateService
+ {
+ const int formatVersion = 1;
+ const string updateAutoPropertyKey = "AppUpdater.CheckAutomatically";
+ const string updateLevelKey = "AppUpdate.UpdateLevel";
+
+ static UpdateInfo[] updateInfos;
+
+ static UpdateInfo[] LoadUpdateInfos ()
+ {
+ if (string.IsNullOrEmpty (DesktopService.GetUpdaterUrl ()))
+ return new UpdateInfo[0];
+
+ var list = new List<UpdateInfo> ();
+ foreach (var node in Mono.Addins.AddinManager.GetExtensionNodes ("/MonoDevelop/Ide/Updater")) {
+ var n = node as UpdateInfoExtensionNode;
+ if (n == null)
+ continue;
+ string file = n.File;
+ if (!File.Exists (file))
+ continue;
+
+ try {
+ list.Add (UpdateInfo.FromFile (file));
+ } catch (Exception ex) {
+ LoggingService.LogError ("Error reading update info file '" + file + "'", ex);
+ }
+ }
+ return list.ToArray ();
+ }
+
+ static UpdateService ()
+ {
+ updateInfos = LoadUpdateInfos ();
+ }
+
+ public static bool CanUpdate {
+ get { return DefaultUpdateInfos.Length > 0; }
+ }
+
+ public static UpdateInfo[] DefaultUpdateInfos {
+ get { return updateInfos; }
+ }
+
+ public static bool CheckAutomatically {
+ get {
+ return PropertyService.Get<bool> (updateAutoPropertyKey, true);
+ }
+ set {
+ PropertyService.Set (updateAutoPropertyKey, value);
+ }
+ }
+
+ public static UpdateLevel UpdateLevel {
+ get {
+ return PropertyService.Get<UpdateLevel> (updateLevelKey, UpdateLevel.Stable);
+ }
+ set {
+ PropertyService.Set (updateLevelKey, value);
+ }
+ }
+
+ public static void RunCheckDialog (bool automatic)
+ {
+ RunCheckDialog (DefaultUpdateInfos, automatic);
+ }
+
+ public static void RunCheckDialog (UpdateInfo[] updateInfos, bool automatic)
+ {
+ if (!CanUpdate || (automatic && !CheckAutomatically))
+ return;
+
+ if (!automatic) {
+ ShowUpdateDialog ();
+ QueryUpdateServer (updateInfos, UpdateLevel, delegate (UpdateResult result) {
+ ShowUpdateResult (result);
+ });
+ } else {
+ QueryUpdateServer (updateInfos, UpdateLevel, delegate (UpdateResult result) {
+ if (result.HasError || !result.HasUpdates)
+ return;
+ ShowUpdateDialog ();
+ ShowUpdateResult (result);
+ });
+ }
+ }
+
+ #region Singleton dialog management. Methods are threadsafe, field is not
+
+ static UpdateDialog visibleDialog;
+
+ static void ShowUpdateDialog ()
+ {
+ Gtk.Application.Invoke (delegate {
+ if (visibleDialog == null) {
+ visibleDialog = new UpdateDialog ();
+ MessageService.ShowCustomDialog (visibleDialog);
+ visibleDialog = null;
+ } else {
+ visibleDialog.GdkWindow.Focus (0);
+ }
+ });
+ }
+
+ static void ShowUpdateResult (UpdateResult result)
+ {
+ Gtk.Application.Invoke (delegate {
+ if (visibleDialog != null)
+ visibleDialog.LoadResult (result);
+ });
+ }
+
+ #endregion
+
+ public static void QueryUpdateServer (UpdateInfo[] updateInfos, UpdateLevel level, Action<UpdateResult> callback)
+ {
+ if (updateInfos == null || updateInfos.Length == 0) {
+ string error = GettextCatalog.GetString ("No updatable products detected");
+ callback (new UpdateResult (null, level, error, null));
+ return;
+ }
+
+ var query = new StringBuilder (DesktopService.GetUpdaterUrl ());
+ query.Append ("?v=");
+ query.Append (formatVersion);
+
+ foreach (var info in updateInfos)
+ query.AppendFormat ("&{0}={1}", info.AppId, info.VersionId);
+
+ if (!string.IsNullOrEmpty (Environment.GetEnvironmentVariable ("MONODEVELOP_UPDATER_TEST")))
+ level = UpdateLevel.Test;
+
+ if (level != UpdateLevel.Stable) {
+ query.Append ("&level=");
+ query.Append (level.ToString ().ToLower ());
+ }
+
+ bool hasEnv = false;
+ foreach (string flag in DesktopService.GetUpdaterEnvironmentFlags ()) {
+ if (!hasEnv) {
+ hasEnv = true;
+ query.Append ("&env=");
+ query.Append (flag);
+ } else {
+ query.Append (",");
+ query.Append (flag);
+ }
+ }
+
+ var requestUrl = query.ToString ();
+ var request = (HttpWebRequest) WebRequest.Create (requestUrl);
+
+ LoggingService.LogDebug ("Checking for updates: {0}", requestUrl);
+
+ //FIXME: use IfModifiedSince, with a cached value
+ //request.IfModifiedSince = somevalue;
+
+ request.BeginGetResponse (delegate (IAsyncResult ar) {
+ ReceivedResponse (request, ar, level, callback);
+ }, null);
+ }
+
+ static void ReceivedResponse (HttpWebRequest request, IAsyncResult ar, UpdateLevel level, Action<UpdateResult> callback)
+ {
+ List<Update> updates = null;
+ string error = null;
+ Exception errorDetail = null;
+
+ try {
+ using (var response = (HttpWebResponse) request.EndGetResponse (ar)) {
+ var encoding = Encoding.GetEncoding (response.CharacterSet);
+ using (var reader = new StreamReader (response.GetResponseStream(), encoding)) {
+ var doc = System.Xml.Linq.XDocument.Load (reader);
+ updates = (from x in doc.Root.Elements ("Application")
+ let first = x.Elements ("Update").First ()
+ select new Update () {
+ Name = x.Attribute ("name").Value,
+ Url = first.Attribute ("url").Value,
+ Version = first.Attribute ("version").Value,
+ Level = first.Attribute ("level") != null
+ ? (UpdateLevel)Enum.Parse (typeof(UpdateLevel), (string)first.Attribute ("level"))
+ : UpdateLevel.Stable,
+ Date = DateTime.Parse (first.Attribute ("date").Value),
+ Releases = x.Elements ("Update").Select (y => new Release () {
+ Version = y.Attribute ("version").Value,
+ Date = DateTime.Parse (y.Attribute ("date").Value),
+ Notes = y.Value
+ }).ToList ()
+ }).ToList ();
+ }
+ }
+ } catch (Exception ex) {
+ error = GettextCatalog.GetString ("Error retrieving update information");
+ errorDetail = ex;
+ }
+ callback (new UpdateResult (updates, level, error, errorDetail));
+ }
+ }
+}