Skip to content

Commit

Permalink
Merge pull request #142 from Squirrel/msdelta
Browse files Browse the repository at this point in the history
Switch to MSDelta for binary diff/patch
  • Loading branch information
anaisbetts committed Dec 2, 2014
2 parents ce48c58 + cbcffd7 commit 4d2ceb3
Show file tree
Hide file tree
Showing 21 changed files with 100 additions and 1,015 deletions.
922 changes: 0 additions & 922 deletions src/Squirrel/BinaryPatchUtility.cs

This file was deleted.

21 changes: 10 additions & 11 deletions src/Squirrel/DeltaPackage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using System.Text.RegularExpressions;
using ICSharpCode.SharpZipLib.Zip;
using Splat;
using DeltaCompressionDotNet.MsDelta;

namespace Squirrel
{
Expand Down Expand Up @@ -102,6 +103,7 @@ public ReleasePackage ApplyDeltaPackage(ReleasePackage basePackage, ReleasePacka
// Apply all of the .diff files
deltaPathRelativePaths
.Where(x => x.StartsWith("lib", StringComparison.InvariantCultureIgnoreCase))
.Where(x => !x.EndsWith(".shasum", StringComparison.InvariantCultureIgnoreCase))
.ForEach(file => {
pathsVisited.Add(Regex.Replace(file, @".diff$", "").ToLowerInvariant());
applyDiffToFile(deltaPath, file, workingPath);
Expand Down Expand Up @@ -164,13 +166,12 @@ void createDeltaForSingleFile(FileInfo targetFile, DirectoryInfo workingDirector
}

this.Log().Info("Delta patching {0} => {1}", baseFileListing[relativePath], targetFile.FullName);
using (var of = File.Create(targetFile.FullName + ".diff")) {
BinaryPatchUtility.Create(oldData, newData, of);
var msDelta = new MsDeltaCompression();
msDelta.CreateDelta(baseFileListing[relativePath], targetFile.FullName, targetFile.FullName + ".diff");

var rl = ReleaseEntry.GenerateFromFile(new MemoryStream(newData), targetFile.Name + ".shasum");
File.WriteAllText(targetFile.FullName + ".shasum", rl.EntryAsString, Encoding.UTF8);
targetFile.Delete();
}
var rl = ReleaseEntry.GenerateFromFile(new MemoryStream(newData), targetFile.Name + ".shasum");
File.WriteAllText(targetFile.FullName + ".shasum", rl.EntryAsString, Encoding.UTF8);
targetFile.Delete();
}


Expand All @@ -188,11 +189,9 @@ void applyDiffToFile(string deltaPath, string relativeFilePath, string workingDi
}

if (relativeFilePath.EndsWith(".diff", StringComparison.InvariantCultureIgnoreCase)) {
using (var of = File.OpenWrite(tempTargetFile))
using (var inf = File.OpenRead(finalTarget)) {
this.Log().Info("Applying Diff to {0}", relativeFilePath);
BinaryPatchUtility.Apply(inf, () => File.OpenRead(inputFile), of);
}
this.Log().Info("Applying Diff to {0}", relativeFilePath);
var msDelta = new MsDeltaCompression();
msDelta.ApplyDelta(inputFile, finalTarget, tempTargetFile);

try {
verifyPatchedFile(relativeFilePath, inputFile, tempTargetFile);
Expand Down
2 changes: 1 addition & 1 deletion src/Squirrel/ReleaseEntry.cs
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ public static void WriteReleaseFile(IEnumerable<ReleaseEntry> releaseEntries, st
Contract.Requires(releaseEntries != null && releaseEntries.Any());
Contract.Requires(!String.IsNullOrEmpty(path));

using (var f = File.OpenWrite(path)) {
using (var f = File.Open(path, FileMode.Create, FileAccess.Write, FileShare.None)) {
WriteReleaseFile(releaseEntries, f);
}
}
Expand Down
7 changes: 6 additions & 1 deletion src/Squirrel/Squirrel.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,12 @@
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<ItemGroup>
<Reference Include="DeltaCompressionDotNet">
<HintPath>..\..\packages\DeltaCompressionDotNet.1.0.0\lib\net45\DeltaCompressionDotNet.dll</HintPath>
</Reference>
<Reference Include="DeltaCompressionDotNet.MsDelta">
<HintPath>..\..\packages\DeltaCompressionDotNet.1.0.0\lib\net45\DeltaCompressionDotNet.MsDelta.dll</HintPath>
</Reference>
<Reference Include="ICSharpCode.SharpZipLib">
<HintPath>..\..\ext\ICSharpCode.SharpZipLib.dll</HintPath>
</Reference>
Expand Down Expand Up @@ -79,7 +85,6 @@
<Compile Include="..\SolutionAssemblyInfo.cs">
<Link>Properties\SolutionAssemblyInfo.cs</Link>
</Compile>
<Compile Include="BinaryPatchUtility.cs" />
<Compile Include="ContentType.cs" />
<Compile Include="DeltaPackage.cs" />
<Compile Include="EnumerableExtensions.cs" />
Expand Down
79 changes: 47 additions & 32 deletions src/Squirrel/UpdateManager.ApplyReleases.cs
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,10 @@ await this.ErrorIfThrows(() => invokePostInstall(newVersion, attemptingFullInsta
progress(75);

try {
await cleanDeadVersions(newVersion);
var currentVersion = updateInfo.CurrentlyInstalledVersion != null ?
updateInfo.CurrentlyInstalledVersion.Version : null;

await cleanDeadVersions(currentVersion, newVersion);
} catch (Exception ex) {
this.Log().WarnException("Failed to clean dead versions, continuing anyways", ex);
}
Expand Down Expand Up @@ -204,10 +207,8 @@ async Task<string> installPackageToAppDir(UpdateInfo updateInfo, ReleaseEntry re

var newCurrentVersion = updateInfo.FutureReleaseEntry.Version;

// Perform post-install; clean up the previous version by asking it
// which shortcuts to install, and nuking them. Then, run the app's
// post install and set up shortcuts.
this.ErrorIfThrows(() => runPostInstallAndCleanup(newCurrentVersion, updateInfo.IsBootstrapping));
this.Log().Info("runPostInstallAndCleanup: starting fixPinnedExecutables");
this.ErrorIfThrows(() => fixPinnedExecutables(newCurrentVersion));

return target.FullName;
}
Expand All @@ -230,14 +231,6 @@ void copyFileToLocation(FileSystemInfo target, IPackageFile x)
}, "Failed to write file: " + target.FullName);
}

void runPostInstallAndCleanup(Version newCurrentVersion, bool isBootstrapping)
{
fixPinnedExecutables(newCurrentVersion);

this.Log().Info("runPostInstallAndCleanup: finished fixPinnedExecutables");
cleanUpOldVersions(newCurrentVersion);
}

static bool pathIsInFrameworkProfile(IPackageFile packageFile, FrameworkVersion appFrameworkVersion)
{
if (!packageFile.Path.StartsWith("lib", StringComparison.InvariantCultureIgnoreCase)) {
Expand Down Expand Up @@ -292,15 +285,18 @@ async Task<ReleaseEntry> createFullPackagesFromDeltas(IEnumerable<ReleaseEntry>
return await createFullPackagesFromDeltas(releasesToApply.Skip(1), entry);
}

void cleanUpOldVersions(Version newCurrentVersion)
void cleanUpOldVersions(Version currentlyExecutingVersion, Version newCurrentVersion)
{
var directory = new DirectoryInfo(rootAppDirectory);
if (!directory.Exists) {
this.Log().Warn("cleanUpOldVersions: the directory '{0}' does not exist", rootAppDirectory);
return;
}

foreach (var v in getOldReleases(newCurrentVersion)) {
foreach (var v in getReleases()) {
var version = v.Name.ToVersion();
if (version == currentlyExecutingVersion || version == newCurrentVersion) continue;

Utility.DeleteDirectoryAtNextReboot(v.FullName);
}
}
Expand Down Expand Up @@ -455,7 +451,7 @@ void updateLink(ShellLink shortcut, string[] oldAppDirectories, string newAppPat
// directory are "dead" (i.e. already uninstalled, but not deleted), and
// we blow them away. This is to make sure that we don't attempt to run
// an uninstaller on an already-uninstalled version.
async Task cleanDeadVersions(Version currentVersion)
async Task cleanDeadVersions(Version originalVersion, Version currentVersion, bool forceUninstall = false)
{
if (currentVersion == null) return;

Expand All @@ -464,6 +460,12 @@ async Task cleanDeadVersions(Version currentVersion)

this.Log().Info("cleanDeadVersions: for version {0}", currentVersion);

string originalVersionFolder = null;
if (originalVersion != null) {
originalVersionFolder = getDirectoryForRelease(originalVersion).Name;
this.Log().Info("cleanDeadVersions: exclude folder {0}", originalVersionFolder);
}

string currentVersionFolder = null;
if (currentVersion != null) {
currentVersionFolder = getDirectoryForRelease(currentVersion).Name;
Expand All @@ -476,25 +478,45 @@ async Task cleanDeadVersions(Version currentVersion)
// come from here.
var toCleanup = di.GetDirectories()
.Where(x => x.Name.ToLowerInvariant().Contains("app-"))
.Where(x => x.Name != currentVersionFolder);
.Where(x => x.Name != currentVersionFolder && x.Name != originalVersionFolder);

await toCleanup.ForEachAsync(async x => {
var squirrelApps = SquirrelAwareExecutableDetector.GetAllSquirrelAwareApps(x.FullName);
var args = String.Format("--squirrel-obsolete {0}", x.Name.Replace("app-", ""));
if (forceUninstall == false) {
await toCleanup.ForEachAsync(async x => {
var squirrelApps = SquirrelAwareExecutableDetector.GetAllSquirrelAwareApps(x.FullName);
var args = String.Format("--squirrel-obsolete {0}", x.Name.Replace("app-", ""));
if (squirrelApps.Count > 0) {
// For each app, run the install command in-order and wait
await squirrelApps.ForEachAsync(exe => Utility.InvokeProcessAsync(exe, args), 1 /* at a time */);
}
});
if (squirrelApps.Count > 0) {
// For each app, run the install command in-order and wait
await squirrelApps.ForEachAsync(exe => Utility.InvokeProcessAsync(exe, args), 1 /* at a time */);
}
});
}

// Finally, clean up the app-X.Y.Z directories
await toCleanup.ForEachAsync(async x => {
try {
await Utility.DeleteDirectoryWithFallbackToNextReboot(x.FullName);
} catch (UnauthorizedAccessException ex) {
this.Log().WarnException("Couldn't delete directory: " + x.FullName, ex);
}
});

// Clean up the packages directory too
var releasesFile = Utility.LocalReleaseFileForAppDir(rootAppDirectory);
var entries = ReleaseEntry.ParseReleaseFile(File.ReadAllText(releasesFile, Encoding.UTF8));
var pkgDir = Utility.PackageDirectoryForAppDir(rootAppDirectory);
var releaseEntry = default(ReleaseEntry);

foreach (var entry in entries) {
if (entry.Version == currentVersion) {
releaseEntry = ReleaseEntry.GenerateFromFile(Path.Combine(pkgDir, entry.Filename));
continue;
}

File.Delete(Path.Combine(pkgDir, entry.Filename));
}

ReleaseEntry.WriteReleaseFile(new[] { releaseEntry }, releasesFile);
}

internal async Task<List<ReleaseEntry>> updateLocalReleasesFile()
Expand All @@ -512,13 +534,6 @@ IEnumerable<DirectoryInfo> getReleases()
.Where(x => x.Name.StartsWith("app-", StringComparison.InvariantCultureIgnoreCase));
}

IEnumerable<DirectoryInfo> getOldReleases(Version version)
{
return getReleases()
.Where(x => x.Name.ToVersion() < version)
.ToArray();
}

DirectoryInfo getDirectoryForRelease(Version releaseVersion)
{
return new DirectoryInfo(Path.Combine(rootAppDirectory, "app-" + releaseVersion));
Expand Down
1 change: 1 addition & 0 deletions src/Squirrel/packages.config
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="DeltaCompressionDotNet" version="1.0.0" targetFramework="net45" />
<package id="Microsoft.Web.Xdt" version="2.1.1" targetFramework="net45" />
<package id="Mono.Cecil" version="0.9.5.4" targetFramework="net45" />
<package id="NuGet.Core" version="2.8.2" targetFramework="net45" />
Expand Down
11 changes: 10 additions & 1 deletion src/Update/Update.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,15 @@
<StartupObject />
</PropertyGroup>
<ItemGroup>
<Reference Include="DeltaCompressionDotNet">
<HintPath>..\..\packages\DeltaCompressionDotNet.1.0.0\lib\net45\DeltaCompressionDotNet.dll</HintPath>
</Reference>
<Reference Include="DeltaCompressionDotNet.MsDelta">
<HintPath>..\..\packages\DeltaCompressionDotNet.1.0.0\lib\net45\DeltaCompressionDotNet.MsDelta.dll</HintPath>
</Reference>
<Reference Include="DeltaCompressionDotNet.PatchApi">
<HintPath>..\..\packages\DeltaCompressionDotNet.1.0.0\lib\net45\DeltaCompressionDotNet.PatchApi.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Web.XmlTransform">
<HintPath>..\..\packages\Microsoft.Web.Xdt.2.1.1\lib\net40\Microsoft.Web.XmlTransform.dll</HintPath>
</Reference>
Expand Down Expand Up @@ -110,7 +119,7 @@
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PostBuildEvent>cd "$(TargetDir)"
"$(SolutionDir)packages\ILRepack.1.25.0\tools\ILRepack.exe" /internalize /out:$(TargetFileName).tmp $(TargetFileName) WpfAnimatedGif.dll ICSharpCode.SharpZipLib.dll Microsoft.Web.XmlTransform.dll Mono.Cecil.dll NuGet.Core.dll Splat.dll Squirrel.dll
"$(SolutionDir)packages\ILRepack.1.25.0\tools\ILRepack.exe" /internalize /out:$(TargetFileName).tmp $(TargetFileName) WpfAnimatedGif.dll ICSharpCode.SharpZipLib.dll Microsoft.Web.XmlTransform.dll Mono.Cecil.dll NuGet.Core.dll Splat.dll DeltaCompressionDotNet.dll DeltaCompressionDotNet.MsDelta.dll Squirrel.dll
del "$(TargetFileName)"
ren "$(TargetFileName).tmp" "$(TargetFileName)"</PostBuildEvent>
</PropertyGroup>
Expand Down
1 change: 1 addition & 0 deletions src/Update/packages.config
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="DeltaCompressionDotNet" version="1.0.0" targetFramework="net45" />
<package id="Microsoft.Web.Xdt" version="2.1.1" targetFramework="net45" />
<package id="Mono.Cecil" version="0.9.5.4" targetFramework="net45" />
<package id="Mono.Options" version="1.1" targetFramework="net45" />
Expand Down
2 changes: 0 additions & 2 deletions test/ApplyReleasesTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,6 @@ public async Task ApplyReleasesWithOneReleaseFile()
var filesToFind = new[] {
new {Name = "NLog.dll", Version = new Version("2.0.0.0")},
new {Name = "NSync.Core.dll", Version = new Version("1.1.0.0")},
new {Name = Path.Combine("sub", "Ionic.Zip.dll"), Version = new Version("1.9.1.8")},
};

filesToFind.ForEach(x => {
Expand Down Expand Up @@ -403,7 +402,6 @@ public async Task ApplyReleasesWithDeltaReleases()
var filesToFind = new[] {
new {Name = "NLog.dll", Version = new Version("2.0.0.0")},
new {Name = "NSync.Core.dll", Version = new Version("1.1.0.0")},
new {Name = Path.Combine("sub", "Ionic.Zip.dll"), Version = new Version("1.9.1.8")},
};

filesToFind.ForEach(x => {
Expand Down
14 changes: 7 additions & 7 deletions test/DeltaPackageTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,16 +31,16 @@ public void ApplyDeltaPackageSmokeTest()
result.Version.ShouldEqual(expected.Version);

this.Log().Info("Expected file list:");
expected.GetFiles().Select(x => x.Path).OrderBy(x => x).ForEach(x => this.Log().Info(x));
var expectedList = expected.GetFiles().Select(x => x.Path).OrderBy(x => x).ToList();
expectedList.ForEach(x => this.Log().Info(x));

this.Log().Info("Actual file list:");
result.GetFiles().Select(x => x.Path).OrderBy(x => x).ForEach(x => this.Log().Info(x));
var actualList = result.GetFiles().Select(x => x.Path).OrderBy(x => x).ToList();
actualList.ForEach(x => this.Log().Info(x));

Enumerable.Zip(
expected.GetFiles().Select(x => x.Path).OrderBy(x => x),
result.GetFiles().Select(x => x.Path).OrderBy(x => x),
(e, a) => e == a
).All(x => x).ShouldBeTrue();
Enumerable.Zip(expectedList, actualList, (e, a) => e == a)
.All(x => x != false)
.ShouldBeTrue();
} finally {
if (File.Exists(outFile)) {
File.Delete(outFile);
Expand Down
29 changes: 0 additions & 29 deletions test/DiffTests.cs

This file was deleted.

3 changes: 2 additions & 1 deletion test/Properties/AssemblyInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,5 @@
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("f781bbe0-d19d-41aa-a78b-c689b1943094")]

[assembly: CollectionBehavior(MaxParallelThreads=1, DisableTestParallelization=true)]
[assembly: CollectionBehavior(MaxParallelThreads=1, DisableTestParallelization=true)]
[assembly: AssemblyMetadata("SquirrelAwareVersion", "1")]
Loading

0 comments on commit 4d2ceb3

Please sign in to comment.