Skip to content

Commit b9c9e05

Browse files
Disentangle AboutPage from checking for updates (prepare for the later possibility of introducing AutoUpdate for MSI installs)
1 parent 4514e33 commit b9c9e05

6 files changed

+277
-163
lines changed

ILSpy/AboutPage.cs

+6-160
Original file line numberDiff line numberDiff line change
@@ -17,24 +17,20 @@
1717
// DEALINGS IN THE SOFTWARE.
1818

1919
using System;
20-
using System.ComponentModel;
2120
using System.IO;
22-
using System.Linq;
23-
using System.Net.Http;
2421
using System.Text.RegularExpressions;
25-
using System.Threading.Tasks;
2622
using System.Windows;
2723
using System.Windows.Controls;
2824
using System.Windows.Data;
2925
using System.Windows.Input;
3026
using System.Windows.Navigation;
31-
using System.Xml.Linq;
3227

3328
using ICSharpCode.AvalonEdit.Rendering;
3429
using ICSharpCode.Decompiler;
3530
using ICSharpCode.ILSpy.Properties;
3631
using ICSharpCode.ILSpy.TextView;
3732
using ICSharpCode.ILSpy.Themes;
33+
using ICSharpCode.ILSpy.Updates;
3834
using ICSharpCode.ILSpyX.Settings;
3935

4036
namespace ICSharpCode.ILSpy
@@ -50,11 +46,6 @@ public override void Execute(object parameter)
5046
);
5147
}
5248

53-
static readonly Uri UpdateUrl = new Uri("https://ilspy.net/updates.xml");
54-
const string band = "stable";
55-
56-
static AvailableVersionInfo latestAvailableVersion;
57-
5849
public static void Display(DecompilerTextView textView)
5950
{
6051
AvalonEditTextOutput output = new AvalonEditTextOutput() {
@@ -71,14 +62,14 @@ public static void Display(DecompilerTextView textView)
7162
StackPanel stackPanel = new StackPanel();
7263
stackPanel.HorizontalAlignment = HorizontalAlignment.Center;
7364
stackPanel.Orientation = Orientation.Horizontal;
74-
if (latestAvailableVersion == null)
65+
if (NotifyOfUpdatesStrategy.LatestAvailableVersion == null)
7566
{
7667
AddUpdateCheckButton(stackPanel, textView);
7768
}
7869
else
7970
{
8071
// we already retrieved the latest version sometime earlier
81-
ShowAvailableVersion(latestAvailableVersion, stackPanel);
72+
ShowAvailableVersion(NotifyOfUpdatesStrategy.LatestAvailableVersion, stackPanel);
8273
}
8374
CheckBox checkBox = new CheckBox();
8475
checkBox.Margin = new Thickness(4);
@@ -142,7 +133,7 @@ static void AddUpdateCheckButton(StackPanel stackPanel, DecompilerTextView textV
142133

143134
try
144135
{
145-
AvailableVersionInfo vInfo = await GetLatestVersionAsync();
136+
AvailableVersionInfo vInfo = await NotifyOfUpdatesStrategy.GetLatestVersionAsync();
146137
stackPanel.Children.Clear();
147138
ShowAvailableVersion(vInfo, stackPanel);
148139
}
@@ -155,11 +146,9 @@ static void AddUpdateCheckButton(StackPanel stackPanel, DecompilerTextView textV
155146
};
156147
}
157148

158-
static readonly Version currentVersion = new Version(DecompilerVersionInfo.Major + "." + DecompilerVersionInfo.Minor + "." + DecompilerVersionInfo.Build + "." + DecompilerVersionInfo.Revision);
159-
160149
static void ShowAvailableVersion(AvailableVersionInfo availableVersion, StackPanel stackPanel)
161150
{
162-
if (currentVersion == availableVersion.Version)
151+
if (AppUpdateService.CurrentVersion == availableVersion.Version)
163152
{
164153
stackPanel.Children.Add(
165154
new Image {
@@ -173,7 +162,7 @@ static void ShowAvailableVersion(AvailableVersionInfo availableVersion, StackPan
173162
VerticalAlignment = VerticalAlignment.Bottom
174163
});
175164
}
176-
else if (currentVersion < availableVersion.Version)
165+
else if (AppUpdateService.CurrentVersion < availableVersion.Version)
177166
{
178167
stackPanel.Children.Add(
179168
new TextBlock {
@@ -197,149 +186,6 @@ static void ShowAvailableVersion(AvailableVersionInfo availableVersion, StackPan
197186
stackPanel.Children.Add(new TextBlock { Text = Resources.UsingNightlyBuildNewerThanLatestRelease });
198187
}
199188
}
200-
201-
static async Task<AvailableVersionInfo> GetLatestVersionAsync()
202-
{
203-
var client = new HttpClient(new HttpClientHandler() {
204-
UseProxy = true,
205-
UseDefaultCredentials = true,
206-
});
207-
string data = await client.GetStringAsync(UpdateUrl);
208-
209-
XDocument doc = XDocument.Load(new StringReader(data));
210-
var bands = doc.Root.Elements("band");
211-
var currentBand = bands.FirstOrDefault(b => (string)b.Attribute("id") == band) ?? bands.First();
212-
Version version = new Version((string)currentBand.Element("latestVersion"));
213-
string url = (string)currentBand.Element("downloadUrl");
214-
if (!(url.StartsWith("http://", StringComparison.Ordinal) || url.StartsWith("https://", StringComparison.Ordinal)))
215-
url = null; // don't accept non-urls
216-
217-
latestAvailableVersion = new AvailableVersionInfo { Version = version, DownloadUrl = url };
218-
return latestAvailableVersion;
219-
}
220-
221-
sealed class AvailableVersionInfo
222-
{
223-
public Version Version;
224-
public string DownloadUrl;
225-
}
226-
227-
sealed class UpdateSettings : INotifyPropertyChanged
228-
{
229-
public UpdateSettings(ILSpySettings spySettings)
230-
{
231-
XElement s = spySettings["UpdateSettings"];
232-
this.automaticUpdateCheckEnabled = (bool?)s.Element("AutomaticUpdateCheckEnabled") ?? true;
233-
try
234-
{
235-
this.lastSuccessfulUpdateCheck = (DateTime?)s.Element("LastSuccessfulUpdateCheck");
236-
}
237-
catch (FormatException)
238-
{
239-
// avoid crashing on settings files invalid due to
240-
// https://github.com/icsharpcode/ILSpy/issues/closed/#issue/2
241-
}
242-
}
243-
244-
bool automaticUpdateCheckEnabled;
245-
246-
public bool AutomaticUpdateCheckEnabled {
247-
get { return automaticUpdateCheckEnabled; }
248-
set {
249-
if (automaticUpdateCheckEnabled != value)
250-
{
251-
automaticUpdateCheckEnabled = value;
252-
Save();
253-
OnPropertyChanged(nameof(AutomaticUpdateCheckEnabled));
254-
}
255-
}
256-
}
257-
258-
DateTime? lastSuccessfulUpdateCheck;
259-
260-
public DateTime? LastSuccessfulUpdateCheck {
261-
get { return lastSuccessfulUpdateCheck; }
262-
set {
263-
if (lastSuccessfulUpdateCheck != value)
264-
{
265-
lastSuccessfulUpdateCheck = value;
266-
Save();
267-
OnPropertyChanged(nameof(LastSuccessfulUpdateCheck));
268-
}
269-
}
270-
}
271-
272-
public void Save()
273-
{
274-
XElement updateSettings = new XElement("UpdateSettings");
275-
updateSettings.Add(new XElement("AutomaticUpdateCheckEnabled", automaticUpdateCheckEnabled));
276-
if (lastSuccessfulUpdateCheck != null)
277-
updateSettings.Add(new XElement("LastSuccessfulUpdateCheck", lastSuccessfulUpdateCheck));
278-
ILSpySettings.SaveSettings(updateSettings);
279-
}
280-
281-
public event PropertyChangedEventHandler PropertyChanged;
282-
283-
void OnPropertyChanged(string propertyName)
284-
{
285-
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
286-
}
287-
}
288-
289-
/// <summary>
290-
/// If automatic update checking is enabled, checks if there are any updates available.
291-
/// Returns the download URL if an update is available.
292-
/// Returns null if no update is available, or if no check was performed.
293-
/// </summary>
294-
public static async Task<string> CheckForUpdatesIfEnabledAsync(ILSpySettings spySettings)
295-
{
296-
UpdateSettings s = new UpdateSettings(spySettings);
297-
298-
// If we're in an MSIX package, updates work differently
299-
if (s.AutomaticUpdateCheckEnabled)
300-
{
301-
// perform update check if we never did one before;
302-
// or if the last check wasn't in the past 7 days
303-
if (s.LastSuccessfulUpdateCheck == null
304-
|| s.LastSuccessfulUpdateCheck < DateTime.UtcNow.AddDays(-7)
305-
|| s.LastSuccessfulUpdateCheck > DateTime.UtcNow)
306-
{
307-
return await CheckForUpdateInternal(s);
308-
}
309-
else
310-
{
311-
return null;
312-
}
313-
}
314-
else
315-
{
316-
return null;
317-
}
318-
}
319-
320-
public static Task<string> CheckForUpdatesAsync(ILSpySettings spySettings)
321-
{
322-
UpdateSettings s = new UpdateSettings(spySettings);
323-
return CheckForUpdateInternal(s);
324-
}
325-
326-
static async Task<string> CheckForUpdateInternal(UpdateSettings s)
327-
{
328-
try
329-
{
330-
var v = await GetLatestVersionAsync();
331-
s.LastSuccessfulUpdateCheck = DateTime.UtcNow;
332-
if (v.Version > currentVersion)
333-
return v.DownloadUrl;
334-
else
335-
return null;
336-
}
337-
catch (Exception)
338-
{
339-
// ignore errors getting the version info
340-
return null;
341-
}
342-
}
343189
}
344190

345191
/// <summary>

ILSpy/MainWindow.xaml.cs

+5-3
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@
5050
using ICSharpCode.ILSpy.TextView;
5151
using ICSharpCode.ILSpy.Themes;
5252
using ICSharpCode.ILSpy.TreeNodes;
53+
using ICSharpCode.ILSpy.Updates;
5354
using ICSharpCode.ILSpy.ViewModels;
5455
using ICSharpCode.ILSpyX;
5556
using ICSharpCode.ILSpyX.Settings;
@@ -954,13 +955,14 @@ public async Task ShowMessageIfUpdatesAvailableAsync(ILSpySettings spySettings,
954955
string downloadUrl;
955956
if (forceCheck)
956957
{
957-
downloadUrl = await AboutPage.CheckForUpdatesAsync(spySettings);
958+
downloadUrl = await NotifyOfUpdatesStrategy.CheckForUpdatesAsync(spySettings);
958959
}
959960
else
960961
{
961-
downloadUrl = await AboutPage.CheckForUpdatesIfEnabledAsync(spySettings);
962+
downloadUrl = await NotifyOfUpdatesStrategy.CheckForUpdatesIfEnabledAsync(spySettings);
962963
}
963964

965+
// The Update Panel is only available for NotifyOfUpdatesStrategy, AutoUpdate will have differing UI requirements
964966
AdjustUpdateUIAfterCheck(downloadUrl, forceCheck);
965967
}
966968

@@ -978,7 +980,7 @@ async void downloadOrCheckUpdateButtonClick(object sender, RoutedEventArgs e)
978980
else
979981
{
980982
updatePanel.Visibility = Visibility.Collapsed;
981-
string downloadUrl = await AboutPage.CheckForUpdatesAsync(ILSpySettings.Load());
983+
string downloadUrl = await NotifyOfUpdatesStrategy.CheckForUpdatesAsync(ILSpySettings.Load());
982984
AdjustUpdateUIAfterCheck(downloadUrl, true);
983985
}
984986
}

ILSpy/Updates/AppUpdateService.cs

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team
2+
//
3+
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
4+
// software and associated documentation files (the "Software"), to deal in the Software
5+
// without restriction, including without limitation the rights to use, copy, modify, merge,
6+
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
7+
// to whom the Software is furnished to do so, subject to the following conditions:
8+
//
9+
// The above copyright notice and this permission notice shall be included in all copies or
10+
// substantial portions of the Software.
11+
//
12+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
13+
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
14+
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
15+
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
16+
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
17+
// DEALINGS IN THE SOFTWARE.
18+
19+
using System;
20+
21+
namespace ICSharpCode.ILSpy.Updates
22+
{
23+
internal enum UpdateStrategy
24+
{
25+
NotifyOfUpdates,
26+
// AutoUpdate
27+
}
28+
29+
internal static class AppUpdateService
30+
{
31+
public static readonly UpdateStrategy updateStrategy = UpdateStrategy.NotifyOfUpdates;
32+
33+
public static readonly Version CurrentVersion = new Version(DecompilerVersionInfo.Major + "." + DecompilerVersionInfo.Minor + "." + DecompilerVersionInfo.Build + "." + DecompilerVersionInfo.Revision);
34+
}
35+
}

ILSpy/Updates/AvailableVersionInfo.cs

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team
2+
//
3+
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
4+
// software and associated documentation files (the "Software"), to deal in the Software
5+
// without restriction, including without limitation the rights to use, copy, modify, merge,
6+
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
7+
// to whom the Software is furnished to do so, subject to the following conditions:
8+
//
9+
// The above copyright notice and this permission notice shall be included in all copies or
10+
// substantial portions of the Software.
11+
//
12+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
13+
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
14+
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
15+
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
16+
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
17+
// DEALINGS IN THE SOFTWARE.
18+
19+
using System;
20+
21+
namespace ICSharpCode.ILSpy.Updates
22+
{
23+
sealed class AvailableVersionInfo
24+
{
25+
public Version Version;
26+
public string DownloadUrl;
27+
}
28+
}

0 commit comments

Comments
 (0)