-
Notifications
You must be signed in to change notification settings - Fork 44
Expand file tree
/
Copy pathInstallManager.cs
More file actions
175 lines (146 loc) · 7.64 KB
/
InstallManager.cs
File metadata and controls
175 lines (146 loc) · 7.64 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
using System;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using System.IO;
using System.Linq;
using System.Reactive;
using System.Reactive.Linq;
using System.Reactive.Subjects;
using System.Reactive.Threading.Tasks;
using System.Threading.Tasks;
using NuGet;
using ReactiveUIMicro;
using Squirrel.Client.Extensions;
using Squirrel.Core;
namespace Squirrel.Client
{
public interface IInstallManager : IEnableLogger
{
IObservable<List<string>> ExecuteInstall(string currentAssemblyDir, IPackage bundledPackageMetadata, IObserver<int> progress = null);
IObservable<Unit> ExecuteUninstall(Version version);
}
public class InstallManager : IInstallManager
{
public ReleaseEntry BundledRelease { get; protected set; }
public string TargetRootDirectory { get; protected set; }
readonly IRxUIFullLogger log;
public InstallManager(ReleaseEntry bundledRelease, string targetRootDirectory = null)
{
BundledRelease = bundledRelease;
TargetRootDirectory = targetRootDirectory;
log = LogManager.GetLogger<InstallManager>();
}
public IObservable<List<string>> ExecuteInstall(string currentAssemblyDir, IPackage bundledPackageMetadata, IObserver<int> progress = null)
{
progress = progress ?? new Subject<int>();
// NB: This bit of code is a bit clever. The binaries that WiX
// has installed *itself* meets the qualifications for being a
// Squirrel update directory (a RELEASES file and the corresponding
// NuGet packages).
//
// So, in order to reuse some code and not write the same things
// twice we're going to "Eigenupdate" from our own directory;
// UpdateManager will operate in bootstrap mode and create a
// local directory for us.
//
// Then, we create a *new* UpdateManager whose target is the normal
// update URL - we can then apply delta updates against the bundled
// NuGet package to get up to vCurrent. The reason we go through
// this rigamarole is so that developers don't have to rebuild the
// installer as often (never, technically).
var updateUsingDeltas =
executeInstall(currentAssemblyDir, bundledPackageMetadata, progress: progress)
.ToObservable()
.ObserveOn(RxApp.DeferredScheduler)
.Catch<List<string>, Exception>(ex => {
log.WarnException("Updating using deltas has failed", ex);
return executeInstall(currentAssemblyDir, bundledPackageMetadata, true, progress)
.ToObservable();
});
return updateUsingDeltas;
}
async Task<List<string>> executeInstall(
string currentAssemblyDir,
IPackage bundledPackageMetadata,
bool ignoreDeltaUpdates = false,
IObserver<int> progress = null)
{
var fxVersion = bundledPackageMetadata.DetectFrameworkVersion();
var eigenCheckProgress = new Subject<int>();
var eigenCopyFileProgress = new Subject<int>();
var eigenApplyProgress = new Subject<int>();
var realCheckProgress = new Subject<int>();
var realCopyFileProgress = new Subject<int>();
var realApplyProgress = new Subject<int>();
List<string> ret = null;
using (var eigenUpdater = new UpdateManager(
currentAssemblyDir,
bundledPackageMetadata.Id,
fxVersion,
TargetRootDirectory)) {
// The real update takes longer than the eigenupdate because we're
// downloading from the Internet instead of doing everything
// locally, so give it more weight
Observable.Concat(
Observable.Concat(eigenCheckProgress, eigenCopyFileProgress, eigenCopyFileProgress)
.Select(x => (x/3.0)*0.33),
Observable.Concat(realCheckProgress, realCopyFileProgress, realApplyProgress)
.Select(x => (x/3.0)*0.67))
.Select(x => (int) x)
.Subscribe(progress);
var updateInfo = await eigenUpdater.CheckForUpdate(ignoreDeltaUpdates, eigenCheckProgress);
log.Info("The checking of releases completed - and there was much rejoicing");
if (!updateInfo.ReleasesToApply.Any()) {
var rootDirectory = TargetRootDirectory ?? Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
var version = updateInfo.CurrentlyInstalledVersion;
var releaseFolder = String.Format("app-{0}", version.Version);
var absoluteFolder = Path.Combine(rootDirectory, version.PackageName, releaseFolder);
if (!Directory.Exists(absoluteFolder)) {
log.Warn("executeInstall: the directory {0} doesn't exist - cannot find the current app?!!?");
} else {
return Directory.GetFiles(absoluteFolder, "*.exe", SearchOption.TopDirectoryOnly)
.ToList();
}
}
foreach (var u in updateInfo.ReleasesToApply) {
log.Info("HEY! We should be applying update {0}", u.Filename);
}
await eigenUpdater.DownloadReleases(updateInfo.ReleasesToApply, eigenCopyFileProgress);
log.Info("The downloading of releases completed - and there was much rejoicing");
ret = await eigenUpdater.ApplyReleases(updateInfo, eigenApplyProgress);
log.Info("The applying of releases completed - and there was much rejoicing");
}
var updateUrl = bundledPackageMetadata.ProjectUrl != null ? bundledPackageMetadata.ProjectUrl.ToString() : null;
updateUrl = null; //XXX REMOVE ME
if (updateUrl == null) {
realCheckProgress.OnNext(100); realCheckProgress.OnCompleted();
realCopyFileProgress.OnNext(100); realCopyFileProgress.OnCompleted();
realApplyProgress.OnNext(100); realApplyProgress.OnCompleted();
return ret;
}
using(var realUpdater = new UpdateManager(
updateUrl,
bundledPackageMetadata.Id,
fxVersion,
TargetRootDirectory)) {
try {
var updateInfo = await realUpdater.CheckForUpdate(progress: realCheckProgress);
await realUpdater.DownloadReleases(updateInfo.ReleasesToApply, realCopyFileProgress);
await realUpdater.ApplyReleases(updateInfo, realApplyProgress);
} catch (Exception ex) {
log.ErrorException("Failed to update to latest remote version", ex);
return new List<string>();
}
}
return ret;
}
public IObservable<Unit> ExecuteUninstall(Version version = null)
{
var updateManager = new UpdateManager("http://lol", BundledRelease.PackageName, FrameworkVersion.Net40, TargetRootDirectory);
return updateManager.FullUninstall(version)
.ObserveOn(RxApp.DeferredScheduler)
.Log(this, "Full uninstall")
.Finally(updateManager.Dispose);
}
}
}