public void ApplyDeltaPackageSmokeTest() { var basePackage = new ReleasePackage(IntegrationTestHelper.GetPath("fixtures", "Squirrel.Core.1.0.0.0-full.nupkg")); var deltaPackage = new ReleasePackage(IntegrationTestHelper.GetPath("fixtures", "Squirrel.Core.1.1.0.0-delta.nupkg")); var expectedPackageFile = IntegrationTestHelper.GetPath("fixtures", "Squirrel.Core.1.1.0.0-full.nupkg"); var outFile = Path.GetTempFileName() + ".nupkg"; try { var deltaBuilder = new DeltaPackageBuilder(); deltaBuilder.ApplyDeltaPackage(basePackage, deltaPackage, outFile); var result = new ZipPackage(outFile); var expected = new ZipPackage(expectedPackageFile); result.Id.ShouldEqual(expected.Id); result.Version.ShouldEqual(expected.Version); this.Log().Info("Expected file list:"); 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:"); var actualList = result.GetFiles().Select(x => x.Path).OrderBy(x => x).ToList(); actualList.ForEach(x => this.Log().Info(x)); Enumerable.Zip(expectedList, actualList, (e, a) => e == a) .All(x => x != false) .ShouldBeTrue(); } finally { if (File.Exists(outFile)) { File.Delete(outFile); } } }
public void ReleasePackageIntegrationTest() { var inputPackage = IntegrationTestHelper.GetPath("fixtures", "Squirrel.Tests.0.1.0-pre.nupkg"); var outputPackage = Path.GetTempFileName() + ".nupkg"; var sourceDir = IntegrationTestHelper.GetPath("fixtures", "packages"); var fixture = new ReleasePackage(inputPackage); (new DirectoryInfo(sourceDir)).Exists.ShouldBeTrue(); try { fixture.CreateReleasePackage(outputPackage, sourceDir); this.Log().Info("Resulting package is at {0}", outputPackage); var pkg = new ZipPackage(outputPackage); int refs = pkg.FrameworkAssemblies.Count(); this.Log().Info("Found {0} refs", refs); refs.ShouldEqual(0); this.Log().Info("Files in release package:"); List<IPackageFile> files = pkg.GetFiles().ToList(); files.ForEach(x => this.Log().Info(x.Path)); List<string> nonDesktopPaths = new[] {"sl", "winrt", "netcore", "win8", "windows8", "MonoAndroid", "MonoTouch", "MonoMac", "wp", } .Select(x => @"lib\" + x) .ToList(); files.Any(x => nonDesktopPaths.Any(y => x.Path.ToLowerInvariant().Contains(y.ToLowerInvariant()))).ShouldBeFalse(); files.Any(x => x.Path.ToLowerInvariant().EndsWith(@".xml")).ShouldBeFalse(); } finally { File.Delete(outputPackage); } }
async Task <ReleaseEntry> createFullPackagesFromDeltas(IEnumerable <ReleaseEntry> releasesToApply, ReleaseEntry currentVersion) { Contract.Requires(releasesToApply != null); // If there are no remote releases at all, bail if (!releasesToApply.Any()) { return(null); } // If there are no deltas in our list, we're already done if (releasesToApply.All(x => !x.IsDelta)) { return(releasesToApply.MaxBy(x => x.Version).FirstOrDefault()); } if (!releasesToApply.All(x => x.IsDelta)) { throw new Exception("Cannot apply combinations of delta and full packages"); } // Smash together our base full package and the nearest delta var ret = await Task.Run(() => { var basePkg = new ReleasePackage(Path.Combine(rootAppDirectory, "packages", currentVersion.Filename)); var deltaPkg = releasesToApply.Select(x => new ReleasePackage(Path.Combine(rootAppDirectory, "packages", x.Filename))); var deltaBuilder = new DeltaPackageBuilder(Directory.GetParent(this.rootAppDirectory).FullName); return(deltaBuilder.ApplyDeltaPackage(basePkg, deltaPkg, Regex.Replace(deltaPkg.Last().InputPackageFile, @"-delta.nupkg$", ".nupkg", RegexOptions.IgnoreCase | RegexOptions.CultureInvariant))); }); return(ReleaseEntry.GenerateFromFile(ret.InputPackageFile)); }
public ReleasePackage CreateDeltaPackage(ReleasePackage basePackage, ReleasePackage newPackage, string outputFile) { Contract.Requires(basePackage != null); Contract.Requires(!String.IsNullOrEmpty(outputFile) && !File.Exists(outputFile)); if (basePackage.Version > newPackage.Version) { var message = String.Format( "You cannot create a delta package based on version {0} as it is a later version than {1}", basePackage.Version, newPackage.Version); throw new InvalidOperationException(message); } if (basePackage.ReleasePackageFile == null) { throw new ArgumentException("The base package's release file is null", "basePackage"); } if (!File.Exists(basePackage.ReleasePackageFile)) { throw new FileNotFoundException("The base package release does not exist", basePackage.ReleasePackageFile); } if (!File.Exists(newPackage.ReleasePackageFile)) { throw new FileNotFoundException("The new package release does not exist", newPackage.ReleasePackageFile); } string baseTempPath = null; string tempPath = null; using (Utility.WithTempDirectory(out baseTempPath, null)) using (Utility.WithTempDirectory(out tempPath, null)) { var baseTempInfo = new DirectoryInfo(baseTempPath); var tempInfo = new DirectoryInfo(tempPath); this.Log().Info("Extracting {0} and {1} into {2}", basePackage.ReleasePackageFile, newPackage.ReleasePackageFile, tempPath); var fz = new FastZip(); fz.ExtractZip(basePackage.ReleasePackageFile, baseTempInfo.FullName, null); fz.ExtractZip(newPackage.ReleasePackageFile, tempInfo.FullName, null); // Collect a list of relative paths under 'lib' and map them // to their full name. We'll use this later to determine in // the new version of the package whether the file exists or // not. var baseLibFiles = baseTempInfo.GetAllFilesRecursively() .Where(x => x.FullName.ToLowerInvariant().Contains("lib" + Path.DirectorySeparatorChar)) .ToDictionary(k => k.FullName.Replace(baseTempInfo.FullName, ""), v => v.FullName); var newLibDir = tempInfo.GetDirectories().First(x => x.Name.ToLowerInvariant() == "lib"); foreach (var libFile in newLibDir.GetAllFilesRecursively()) { createDeltaForSingleFile(libFile, tempInfo, baseLibFiles); } ReleasePackage.addDeltaFilesToContentTypes(tempInfo.FullName); fz.CreateZip(outputFile, tempInfo.FullName, true, null); } return new ReleasePackage(outputFile); }
public void ApplyDeltaPackageToWorkingDirectory(string workingPath, ReleasePackage deltaPackage) { Contract.Requires(deltaPackage != null); string deltaPath; var opts = new ExtractionOptions() { ExtractFullPath = true, Overwrite = true, PreserveFileTime = true }; using (Utility.WithTempDirectory(out deltaPath, localAppDirectory)) { using (var za = ZipArchive.Open(deltaPackage.InputPackageFile)) using (var reader = za.ExtractAllEntries()) { reader.WriteAllToDirectory(deltaPath, opts); var pathsVisited = new List <string>(); var deltaPathRelativePaths = new DirectoryInfo(deltaPath).GetAllFilesRecursively() .Select(x => x.FullName.Replace(deltaPath + Path.DirectorySeparatorChar, "")) .ToArray(); // Apply all of the .diff files deltaPathRelativePaths .Where(x => x.StartsWith("lib", StringComparison.InvariantCultureIgnoreCase)) .Where(x => !x.EndsWith(".shasum", StringComparison.InvariantCultureIgnoreCase)) .Where(x => !x.EndsWith(".diff", StringComparison.InvariantCultureIgnoreCase) || !deltaPathRelativePaths.Contains(x.Replace(".diff", ".bsdiff"))) .ForEach(file => { pathsVisited.Add(Regex.Replace(file, @"\.(bs)?diff$", "").ToLowerInvariant()); applyDiffToFile(deltaPath, file, workingPath); }); // Delete all of the files that were in the old package but // not in the new one. new DirectoryInfo(workingPath).GetAllFilesRecursively() .Select(x => x.FullName.Replace(workingPath + Path.DirectorySeparatorChar, "").ToLowerInvariant()) .Where(x => x.StartsWith("lib", StringComparison.InvariantCultureIgnoreCase) && !pathsVisited.Contains(x)) .ForEach(x => { this.Log().Info("{0} was in old package but not in new one, deleting", x); File.Delete(Path.Combine(workingPath, x)); }); // Update all the files that aren't in 'lib' with the delta // package's versions (i.e. the nuspec file, etc etc). deltaPathRelativePaths .Where(x => !x.StartsWith("lib", StringComparison.InvariantCultureIgnoreCase)) .ForEach(x => { this.Log().Info("Updating metadata file: {0}", x); File.Copy(Path.Combine(deltaPath, x), Path.Combine(workingPath, x), true); }); } } }
async Task <ReleaseEntry> createFullPackagesFromDeltas(IEnumerable <ReleaseEntry> releasesToApply, ReleaseEntry currentVersion, ApplyReleasesProgress progress) { Contract.Requires(releasesToApply != null); progress = progress ?? new ApplyReleasesProgress(releasesToApply.Count(), x => { }); // If there are no remote releases at all, bail if (!releasesToApply.Any()) { return(null); } // If there are no deltas in our list, we're already done if (releasesToApply.All(x => !x.IsDelta)) { return(releasesToApply.MaxBy(x => x.Version).FirstOrDefault()); } if (!releasesToApply.All(x => x.IsDelta)) { throw new Exception("Cannot apply combinations of delta and full packages"); } // Progress calculation is "complex" here. We need to known how many releases, and then give each release a similar amount of // progress. For example, when applying 5 releases: // // release 1: 00 => 20 // release 2: 20 => 40 // release 3: 40 => 60 // release 4: 60 => 80 // release 5: 80 => 100 // // Smash together our base full package and the nearest delta var ret = await Task.Run(() => { var basePkg = new ReleasePackage(Path.Combine(rootAppDirectory, "packages", currentVersion.Filename)); var deltaPkg = new ReleasePackage(Path.Combine(rootAppDirectory, "packages", releasesToApply.First().Filename)); var deltaBuilder = new DeltaPackageBuilder(Directory.GetParent(this.rootAppDirectory).FullName); return(deltaBuilder.ApplyDeltaPackage(basePkg, deltaPkg, Regex.Replace(deltaPkg.InputPackageFile, @"-delta.nupkg$", ".nupkg", RegexOptions.IgnoreCase | RegexOptions.CultureInvariant), x => progress.ReportReleaseProgress(x))); }); progress.FinishRelease(); if (releasesToApply.Count() == 1) { return(ReleaseEntry.GenerateFromFile(ret.InputPackageFile)); } var fi = new FileInfo(ret.InputPackageFile); var entry = ReleaseEntry.GenerateFromFile(fi.OpenRead(), fi.Name); // Recursively combine the rest of them return(await createFullPackagesFromDeltas(releasesToApply.Skip(1), entry, progress)); }
public ReleasePackage ApplyDeltaPackage(ReleasePackage basePackage, ReleasePackage deltaPackage, string outputFile) { Contract.Requires(deltaPackage != null); Contract.Requires(!String.IsNullOrEmpty(outputFile) && !File.Exists(outputFile)); string workingPath; string deltaPath; using (Utility.WithTempDirectory(out deltaPath)) using (Utility.WithTempDirectory(out workingPath)) using (var deltaZip = new ZipFile(deltaPackage.InputPackageFile)) using (var baseZip = new ZipFile(basePackage.InputPackageFile)) { deltaZip.ExtractAll(deltaPath); baseZip.ExtractAll(workingPath); var pathsVisited = new List <string>(); var deltaPathRelativePaths = new DirectoryInfo(deltaPath).GetAllFilesRecursively() .Select(x => x.FullName.Replace(deltaPath + Path.DirectorySeparatorChar, "")) .ToArray(); // Apply all of the .diff files deltaPathRelativePaths .Where(x => x.StartsWith("lib", StringComparison.InvariantCultureIgnoreCase)) .ForEach(file => { pathsVisited.Add(Regex.Replace(file, @".diff$", "").ToLowerInvariant()); applyDiffToFile(deltaPath, file, workingPath); }); // Delete all of the files that were in the old package but // not in the new one. new DirectoryInfo(workingPath).GetAllFilesRecursively() .Select(x => x.FullName.Replace(workingPath + Path.DirectorySeparatorChar, "").ToLowerInvariant()) .Where(x => x.StartsWith("lib", StringComparison.InvariantCultureIgnoreCase) && !pathsVisited.Contains(x)) .ForEach(x => { this.Log().Info("{0} was in old package but not in new one, deleting", x); File.Delete(Path.Combine(workingPath, x)); }); // Update all the files that aren't in 'lib' with the delta // package's versions (i.e. the nuspec file, etc etc). deltaPathRelativePaths .Where(x => !x.StartsWith("lib", StringComparison.InvariantCultureIgnoreCase)) .ForEach(x => { this.Log().Info("Updating metadata file: {0}", x); File.Copy(Path.Combine(deltaPath, x), Path.Combine(workingPath, x), true); }); using (var zf = new ZipFile(outputFile)) { this.Log().Info("Repacking into full package: {0}", outputFile); zf.AddDirectory(workingPath); zf.Save(); } } return(new ReleasePackage(outputFile)); }
public void FindDependentPackagesForDummyPackage() { var inputPackage = IntegrationTestHelper.GetPath("fixtures", "Squirrel.Tests.0.1.0-pre.nupkg"); var fixture = new ReleasePackage(inputPackage); var sourceDir = IntegrationTestHelper.GetPath("fixtures", "packages"); (new DirectoryInfo(sourceDir)).Exists.ShouldBeTrue(); IEnumerable<IPackage> results = fixture.findAllDependentPackages(default(IPackage), (IPackageRepository)new LocalPackageRepository(sourceDir), default(HashSet<string>), default(FrameworkName)); results.Count().ShouldBeGreaterThan(0); }
public void WhenCurrentReleaseMatchesLastReleaseReturnNull() { var package = new ReleasePackage("Espera-1.7.6-beta.nupkg"); var releaseEntries = new[] { ReleaseEntry.ParseReleaseEntry(MockReleaseEntry("Espera-1.7.6-beta.nupkg")) }; Assert.Null(ReleaseEntry.GetPreviousRelease( releaseEntries, package, @"C:\temp\somefolder")); }
public ReleasePackage ApplyDeltaPackage(ReleasePackage basePackage, ReleasePackage deltaPackage, string outputFile) { Contract.Requires(deltaPackage != null); Contract.Requires(!String.IsNullOrEmpty(outputFile) && !File.Exists(outputFile)); string workingPath; string deltaPath; using (Utility.WithTempDirectory(out deltaPath)) using (Utility.WithTempDirectory(out workingPath)) { var fz = new FastZip(); fz.ExtractZip(deltaPackage.InputPackageFile, deltaPath, null); fz.ExtractZip(basePackage.InputPackageFile, workingPath, null); var pathsVisited = new List<string>(); var deltaPathRelativePaths = new DirectoryInfo(deltaPath).GetAllFilesRecursively() .Select(x => x.FullName.Replace(deltaPath + Path.DirectorySeparatorChar, "")) .ToArray(); // 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); }); // Delete all of the files that were in the old package but // not in the new one. new DirectoryInfo(workingPath).GetAllFilesRecursively() .Select(x => x.FullName.Replace(workingPath + Path.DirectorySeparatorChar, "").ToLowerInvariant()) .Where(x => x.StartsWith("lib", StringComparison.InvariantCultureIgnoreCase) && !pathsVisited.Contains(x)) .ForEach(x => { this.Log().Info("{0} was in old package but not in new one, deleting", x); File.Delete(Path.Combine(workingPath, x)); }); // Update all the files that aren't in 'lib' with the delta // package's versions (i.e. the nuspec file, etc etc). deltaPathRelativePaths .Where(x => !x.StartsWith("lib", StringComparison.InvariantCultureIgnoreCase)) .ForEach(x => { this.Log().Info("Updating metadata file: {0}", x); File.Copy(Path.Combine(deltaPath, x), Path.Combine(workingPath, x), true); }); this.Log().Info("Repacking into full package: {0}", outputFile); fz.CreateZip(outputFile, workingPath, true, null); } return new ReleasePackage(outputFile); }
async Task <ReleaseEntry> createFullPackagesFromDeltas(IEnumerable <ReleaseEntry> releasesToApply, ReleaseEntry currentVersion, Action <int> progress = null, int done = 0) { Contract.Requires(releasesToApply != null); progress = progress ?? (_ => { }); // If there are no remote releases at all, bail if (!releasesToApply.Any()) { return(null); } var startProgress = (done) * 100 / (done + releasesToApply.Count()); var endProgress = (done + 1) * 100 / (done + releasesToApply.Count()); // If there are no deltas in our list, we're already done if (releasesToApply.All(x => !x.IsDelta)) { return(releasesToApply.MaxBy(x => x.Version).FirstOrDefault()); } if (!releasesToApply.All(x => x.IsDelta)) { throw new Exception("Cannot apply combinations of delta and full packages"); } // Smash together our base full package and the nearest delta var ret = await Task.Run(() => { var basePkg = new ReleasePackage(Path.Combine(rootAppDirectory, "packages", currentVersion.Filename)); var deltaPkg = new ReleasePackage(Path.Combine(rootAppDirectory, "packages", releasesToApply.First().Filename)); var deltaBuilder = new DeltaPackageBuilder(Directory.GetParent(this.rootAppDirectory).FullName); return(deltaBuilder.ApplyDeltaPackage(basePkg, deltaPkg, Regex.Replace(deltaPkg.InputPackageFile, @"-delta.nupkg$", ".nupkg", RegexOptions.IgnoreCase | RegexOptions.CultureInvariant), x => progress(startProgress + (endProgress - startProgress) * x / 100))); }); if (releasesToApply.Count() == 1) { return(ReleaseEntry.GenerateFromFile(ret.InputPackageFile)); } var fi = new FileInfo(ret.InputPackageFile); var entry = ReleaseEntry.GenerateFromFile(fi.OpenRead(), fi.Name); progress(endProgress); // Recursively combine the rest of them return(await createFullPackagesFromDeltas(releasesToApply.Skip(1), entry, progress, done + 1)); }
Task <string> installPackageToAppDir(UpdateInfo updateInfo, ReleaseEntry release) { return(Task.Run(async() => { var target = getDirectoryForRelease(release.Version); // NB: This might happen if we got killed partially through applying the release if (target.Exists) { this.Log().Warn("Found partially applied release folder, killing it: " + target.FullName); await Utility.DeleteDirectory(target.FullName); } target.Create(); this.Log().Info("Writing files to app directory: {0}", target.FullName); ReleasePackage.ExtractZipDecoded(Path.Combine(updateInfo.PackageDirectory, release.Filename), target.FullName, @"lib"); // Move all of the files out of the lib/ dirs in the NuGet package // into our target App directory. // // NB: We sort this list in order to guarantee that if a Net20 // and a Net40 version of a DLL get shipped, we always end up // with the 4.0 version. var libDir = target.GetDirectories().First(x => x.Name.Equals("lib", StringComparison.OrdinalIgnoreCase)); var toMove = libDir.GetDirectories().OrderBy(x => x.Name); toMove.ForEach(ld => { ld.GetDirectories() .ForEachAsync(subdir => subdir.MoveTo(subdir.FullName.Replace(ld.FullName, target.FullName))) .Wait(); ld.GetFiles() .ForEachAsync(file => { var tgt = Path.Combine(target.FullName, file.Name); this.Log().Info("Moving file {0} to {1}", file.FullName, tgt); if (File.Exists(tgt)) { Utility.DeleteFileHarder(tgt, true); } file.MoveTo(tgt); }) .Wait(); }); await Utility.DeleteDirectory(libDir.FullName); return target.FullName; })); }
public ReleasePackage CreateDeltaPackage(ReleasePackage basePackage, ReleasePackage newPackage, string outputFile) { if (basePackage.Version > newPackage.Version) { throw new InvalidOperationException($"You cannot create a delta package based on version {basePackage.Version} as it is a later version than {newPackage.Version}"); } if (basePackage.ReleasePackageFile == null) { throw new ArgumentException("The base package's release file is null", "basePackage"); } if (!File.Exists(basePackage.ReleasePackageFile)) { throw new FileNotFoundException("The base package release does not exist", basePackage.ReleasePackageFile); } if (!File.Exists(newPackage.ReleasePackageFile)) { throw new FileNotFoundException("The new package release does not exist", newPackage.ReleasePackageFile); } string path = null; string str2 = null; using (Utility.WithTempDirectory(out path, null)) { using (Utility.WithTempDirectory(out str2, null)) { DirectoryInfo baseTempInfo = new DirectoryInfo(path); DirectoryInfo workingDirectory = new DirectoryInfo(str2); this.Log <DeltaPackageBuilder>().Info <string, string, string>("Extracting {0} and {1} into {2}", basePackage.ReleasePackageFile, newPackage.ReleasePackageFile, str2); FastZip zip = new FastZip(); zip.ExtractZip(basePackage.ReleasePackageFile, baseTempInfo.FullName, null); zip.ExtractZip(newPackage.ReleasePackageFile, workingDirectory.FullName, null); Dictionary <string, string> baseFileListing = Enumerable.ToDictionary <FileInfo, string, string>(from x in baseTempInfo.GetAllFilesRecursively() where x.FullName.ToLowerInvariant().Contains("lib" + Path.DirectorySeparatorChar.ToString()) select x, k => k.FullName.Replace(baseTempInfo.FullName, ""), v => v.FullName); foreach (FileInfo info2 in Enumerable.First <DirectoryInfo>(workingDirectory.GetDirectories(), x => x.Name.ToLowerInvariant() == "lib").GetAllFilesRecursively()) { this.createDeltaForSingleFile(info2, workingDirectory, baseFileListing); } ReleasePackage.addDeltaFilesToContentTypes(workingDirectory.FullName); zip.CreateZip(outputFile, workingDirectory.FullName, true, null); } } return(new ReleasePackage(outputFile, false)); }
public void ApplyDeltaWithBothBsdiffAndNormalDiffDoesntFail() { var basePackage = new ReleasePackage(IntegrationTestHelper.GetPath("fixtures", "slack-1.1.8-full.nupkg")); var deltaPackage = new ReleasePackage(IntegrationTestHelper.GetPath("fixtures", "slack-1.2.0-delta.nupkg")); var outFile = Path.GetTempFileName() + ".nupkg"; try { var deltaBuilder = new DeltaPackageBuilder(); deltaBuilder.ApplyDeltaPackage(basePackage, deltaPackage, outFile); var result = new ZipPackage(outFile); result.Id.ShouldEqual("slack"); result.Version.ShouldEqual(new SemanticVersion("1.2.0")); } finally { if (File.Exists(outFile)) { File.Delete(outFile); } } }
public ReleasePackage ApplyDeltaPackage(ReleasePackage basePackage, ReleasePackage deltaPackage, string outputFile) { string deltaPath; using (Utility.WithTempDirectory(out deltaPath, this.localAppDirectory)) { string workingPath; using (Utility.WithTempDirectory(out workingPath, this.localAppDirectory)) { FastZip zip1 = new FastZip(); zip1.ExtractZip(deltaPackage.InputPackageFile, deltaPath, null); zip1.ExtractZip(basePackage.InputPackageFile, workingPath, null); List <string> pathsVisited = new List <string>(); string[] deltaPathRelativePaths = (from x in new DirectoryInfo(deltaPath).GetAllFilesRecursively() select x.FullName.Replace(deltaPath + Path.DirectorySeparatorChar.ToString(), "")).ToArray <string>(); (from x in deltaPathRelativePaths where x.StartsWith("lib", StringComparison.InvariantCultureIgnoreCase) where !x.EndsWith(".shasum", StringComparison.InvariantCultureIgnoreCase) where !x.EndsWith(".diff", StringComparison.InvariantCultureIgnoreCase) || !deltaPathRelativePaths.Contains <string>(x.Replace(".diff", ".bsdiff")) select x).ForEach <string>(delegate(string file) { pathsVisited.Add(Regex.Replace(file, @"\.(bs)?diff$", "").ToLowerInvariant()); this.applyDiffToFile(deltaPath, file, workingPath); }); (from x in new DirectoryInfo(workingPath).GetAllFilesRecursively() select x.FullName.Replace(workingPath + Path.DirectorySeparatorChar.ToString(), "").ToLowerInvariant() into x where x.StartsWith("lib", StringComparison.InvariantCultureIgnoreCase) && !pathsVisited.Contains(x) select x).ForEach <string>(delegate(string x) { this.Log <DeltaPackageBuilder>().Info <string>("{0} was in old package but not in new one, deleting", x); File.Delete(Path.Combine(workingPath, x)); }); (from x in deltaPathRelativePaths where !x.StartsWith("lib", StringComparison.InvariantCultureIgnoreCase) select x).ForEach <string>(delegate(string x) { this.Log <DeltaPackageBuilder>().Info <string>("Updating metadata file: {0}", x); File.Copy(Path.Combine(deltaPath, x), Path.Combine(workingPath, x), true); }); this.Log <DeltaPackageBuilder>().Info <string>("Repacking into full package: {0}", outputFile); zip1.CreateZip(outputFile, workingPath, true, null); } } return(new ReleasePackage(outputFile, false)); }
Task <string> installPackageToAppDir(UpdateInfo updateInfo, ReleaseEntry release, Action <int> progressCallback) { return(Task.Run(async() => { var target = getDirectoryForRelease(release.Version); // NB: This might happen if we got killed partially through applying the release if (target.Exists) { this.Log().Warn("Found partially applied release folder, killing it: " + target.FullName); await Utility.DeleteDirectory(target.FullName); } target.Create(); try { this.Log().Info("Writing files to app directory: {0}", target.FullName); await ReleasePackage.ExtractZipForInstall( Path.Combine(updateInfo.PackageDirectory, release.Filename), target.FullName, rootAppDirectory, progressCallback); } catch (Exception ex) { try { //Don't leave that empty directory there: its existence will prevent the user from even using the previous version. await Utility.DeleteDirectory(target.FullName); } catch (Exception error) { //This is going to be one very stuck user... this.Log().ErrorException("Failed to cleanup new directory after failed install: " + target.FullName, error); } throw ex; } return target.FullName; })); }
Task <string> installPackageToAppDir(UpdateInfo updateInfo, ReleaseEntry release) { return(Task.Run(async() => { var target = getDirectoryForRelease(release.Version); // NB: This might happen if we got killed partially through applying the release if (target.Exists) { this.Log().Warn("Found partially applied release folder, killing it: " + target.FullName); await Utility.DeleteDirectory(target.FullName); } target.Create(); this.Log().Info("Writing files to app directory: {0}", target.FullName); await ReleasePackage.ExtractZipForInstall( Path.Combine(updateInfo.PackageDirectory, release.Filename), target.FullName); return target.FullName; })); }
public void WhenMultipleReleaseMatchesReturnEarlierResult() { var expected = new SemanticVersion("1.7.5-beta"); var package = new ReleasePackage("Espera-1.7.6-beta.nupkg"); var releaseEntries = new[] { ReleaseEntry.ParseReleaseEntry(MockReleaseEntry("Espera-1.7.6-beta.nupkg")), ReleaseEntry.ParseReleaseEntry(MockReleaseEntry("Espera-1.7.5-beta.nupkg")) }; var actual = ReleaseEntry.GetPreviousRelease( releaseEntries, package, @"C:\temp\"); Assert.Equal(expected, actual.Version); }
public void Releasify(string package, string targetDir = null, string packagesDir = null, string bootstrapperExe = null) { targetDir = targetDir ?? ".\\Releases"; packagesDir = packagesDir ?? "."; bootstrapperExe = bootstrapperExe ?? ".\\Setup.exe"; if (!Directory.Exists(targetDir)) { Directory.CreateDirectory(targetDir); } if (!File.Exists(bootstrapperExe)) { bootstrapperExe = Path.Combine( Path.GetDirectoryName(Assembly.GetEntryAssembly().Location), "Setup.exe"); } this.Log().Info("Bootstrapper EXE found at:" + bootstrapperExe); var di = new DirectoryInfo(targetDir); File.Copy(package, Path.Combine(di.FullName, Path.GetFileName(package)), true); var allNuGetFiles = di.EnumerateFiles() .Where(x => x.Name.EndsWith(".nupkg", StringComparison.OrdinalIgnoreCase)); var toProcess = allNuGetFiles.Where(x => !x.Name.Contains("-delta") && !x.Name.Contains("-full")); var releaseFilePath = Path.Combine(di.FullName, "RELEASES"); var previousReleases = Enumerable.Empty<ReleaseEntry>(); if (File.Exists(releaseFilePath)) { previousReleases = ReleaseEntry.ParseReleaseFile(File.ReadAllText(releaseFilePath, Encoding.UTF8)); } foreach (var file in toProcess) { this.Log().Info("Creating release package: " + file.FullName); var rp = new ReleasePackage(file.FullName); rp.CreateReleasePackage(Path.Combine(di.FullName, rp.SuggestedReleaseFileName), packagesDir); var prev = ReleaseEntry.GetPreviousRelease(previousReleases, rp, targetDir); if (prev != null) { var deltaBuilder = new DeltaPackageBuilder(); deltaBuilder.CreateDeltaPackage(prev, rp, Path.Combine(di.FullName, rp.SuggestedReleaseFileName.Replace("full", "delta"))); } } foreach (var file in toProcess) { File.Delete(file.FullName); } var releaseEntries = allNuGetFiles.Select(x => ReleaseEntry.GenerateFromFile(x.FullName)); ReleaseEntry.WriteReleaseFile(releaseEntries, releaseFilePath); var targetSetupExe = Path.Combine(di.FullName, "Setup.exe"); var newestFullRelease = releaseEntries.MaxBy(x => x.Version).Where(x => !x.IsDelta).First(); File.Copy(bootstrapperExe, targetSetupExe, true); var zipPath = createSetupEmbeddedZip(Path.Combine(di.FullName, newestFullRelease.Filename), di.FullName); try { var zip = File.ReadAllBytes(zipPath); IntPtr handle = NativeMethods.BeginUpdateResource(targetSetupExe, false); if (handle == IntPtr.Zero) { throw new Win32Exception(); } if (!NativeMethods.UpdateResource(handle, "DATA", new IntPtr(131), 0x0409, zip, zip.Length)) { throw new Win32Exception(); } if (!NativeMethods.EndUpdateResource(handle, false)) { throw new Win32Exception(); } } catch (Exception ex) { this.Log().ErrorException("Failed to update Setup.exe with new Zip file", ex); } finally { File.Delete(zipPath); } }
public void CanResolveMultipleLevelsOfDependencies() { var inputPackage = IntegrationTestHelper.GetPath("fixtures", "Squirrel.Tests.0.1.0-pre.nupkg"); var outputPackage = Path.GetTempFileName() + ".nupkg"; var sourceDir = IntegrationTestHelper.GetPath("fixtures", "packages"); var fixture = new ReleasePackage(inputPackage); (new DirectoryInfo(sourceDir)).Exists.ShouldBeTrue(); try { fixture.CreateReleasePackage(outputPackage, sourceDir); this.Log().Info("Resulting package is at {0}", outputPackage); var pkg = new ZipPackage(outputPackage); int refs = pkg.FrameworkAssemblies.Count(); this.Log().Info("Found {0} refs", refs); refs.ShouldEqual(0); this.Log().Info("Files in release package:"); pkg.GetFiles().ForEach(x => this.Log().Info(x.Path)); var filesToLookFor = new[] { "xunit.assert.dll", // Tests => Xunit => Xunit.Assert "NuGet.Core.dll", // Tests => NuGet "Squirrel.Tests.dll", }; filesToLookFor.ForEach(name => { this.Log().Info("Looking for {0}", name); pkg.GetFiles().Any(y => y.Path.ToLowerInvariant().Contains(name.ToLowerInvariant())).ShouldBeTrue(); }); } finally { File.Delete(outputPackage); } }
public void CanLoadPackageWhichHasNoDependencies() { var inputPackage = IntegrationTestHelper.GetPath("fixtures", "Squirrel.Core.NoDependencies.1.0.0.0.nupkg"); var outputPackage = Path.GetTempFileName() + ".nupkg"; var fixture = new ReleasePackage(inputPackage); var sourceDir = IntegrationTestHelper.GetPath("fixtures", "packages"); try { fixture.CreateReleasePackage(outputPackage, sourceDir); } finally { File.Delete(outputPackage); } }
public ReleasePackage ApplyDeltaPackage(ReleasePackage basePackage, ReleasePackage deltaPackage, string outputFile) { return(ApplyDeltaPackage(basePackage, deltaPackage, outputFile, x => { })); }
public ReleasePackage ApplyDeltaPackage(ReleasePackage basePackage, ReleasePackage deltaPackage, string outputFile, Action <int> progress = null) { Contract.Requires(deltaPackage != null); Contract.Requires(!String.IsNullOrEmpty(outputFile) && !File.Exists(outputFile)); if (progress == null) { progress = i => { } } ; string workingPath; string deltaPath; using (Utility.WithTempDirectory(out deltaPath, localAppDirectory)) using (Utility.WithTempDirectory(out workingPath, localAppDirectory)) { var fz = new FastZip(); fz.ExtractZip(deltaPackage.InputPackageFile, deltaPath, null); // The percentages here are somewhat arbitrary and reflect typical Bloom file sizes. // Probably not appropriate to push upstream. // If you are thinking about improving this using FastZip's Progress event, check with JohnT. // I experimented with it and found that the PercentCompleted which it reports is useless, // toggling between 0 and 100% repeatedly...possibly it applies to a particular file? // I also found that it is VERY expensive to turn on progress reporting while unzipping; // seems to slow the process down to the point of making it take two to three times as long. // This may of course improve in a later version of the library. progress(10); fz.ExtractZip(basePackage.InputPackageFile, workingPath, null); progress(35); var pathsVisited = new List <string>(); var deltaPathRelativePaths = new DirectoryInfo(deltaPath).GetAllFilesRecursively() .Select(x => x.FullName.Replace(deltaPath + Path.DirectorySeparatorChar, "")) .ToArray(); // Apply all of the .diff files deltaPathRelativePaths .Where(x => x.StartsWith("lib", StringComparison.InvariantCultureIgnoreCase)) .Where(x => !x.EndsWith(".shasum", StringComparison.InvariantCultureIgnoreCase)) .Where(x => !x.EndsWith(".diff", StringComparison.InvariantCultureIgnoreCase) || !deltaPathRelativePaths.Contains(x.Replace(".diff", ".bsdiff"))) .ForEach(file => { pathsVisited.Add(Regex.Replace(file, @"\.(bs)?diff$", "").ToLowerInvariant()); applyDiffToFile(deltaPath, file, workingPath); }); // Delete all of the files that were in the old package but // not in the new one. new DirectoryInfo(workingPath).GetAllFilesRecursively() .Select(x => x.FullName.Replace(workingPath + Path.DirectorySeparatorChar, "").ToLowerInvariant()) .Where(x => x.StartsWith("lib", StringComparison.InvariantCultureIgnoreCase) && !pathsVisited.Contains(x)) .ForEach(x => { this.Log().Info("{0} was in old package but not in new one, deleting", x); File.Delete(Path.Combine(workingPath, x)); }); // Update all the files that aren't in 'lib' with the delta // package's versions (i.e. the nuspec file, etc etc). deltaPathRelativePaths .Where(x => !x.StartsWith("lib", StringComparison.InvariantCultureIgnoreCase)) .ForEach(x => { this.Log().Info("Updating metadata file: {0}", x); File.Copy(Path.Combine(deltaPath, x), Path.Combine(workingPath, x), true); }); progress(50); this.Log().Info("Repacking into full package: {0}", outputFile); fz.CreateZip(outputFile, workingPath, true, null); progress(100); } return(new ReleasePackage(outputFile)); } void createDeltaForSingleFile(FileInfo targetFile, DirectoryInfo workingDirectory, Dictionary <string, string> baseFileListing) { // NB: There are three cases here that we'll handle: // // 1. Exists only in new => leave it alone, we'll use it directly. // 2. Exists in both old and new => write a dummy file so we know // to keep it. // 3. Exists in old but changed in new => create a delta file // // The fourth case of "Exists only in old => delete it in new" // is handled when we apply the delta package var relativePath = targetFile.FullName.Replace(workingDirectory.FullName, ""); if (!baseFileListing.ContainsKey(relativePath)) { this.Log().Info("{0} not found in base package, marking as new", relativePath); return; } var oldData = File.ReadAllBytes(baseFileListing[relativePath]); var newData = File.ReadAllBytes(targetFile.FullName); if (bytesAreIdentical(oldData, newData)) { this.Log().Info("{0} hasn't changed, writing dummy file", relativePath); File.Create(targetFile.FullName + ".diff").Dispose(); File.Create(targetFile.FullName + ".shasum").Dispose(); targetFile.Delete(); return; } this.Log().Info("Delta patching {0} => {1}", baseFileListing[relativePath], targetFile.FullName); var msDelta = new MsDeltaCompression(); try { msDelta.CreateDelta(baseFileListing[relativePath], targetFile.FullName, targetFile.FullName + ".diff"); } catch (Win32Exception) { this.Log().Warn("We couldn't create a delta for {0}, attempting to create bsdiff", targetFile.Name); var of = default(FileStream); try { of = File.Create(targetFile.FullName + ".bsdiff"); BinaryPatchUtility.Create(oldData, newData, of); // NB: Create a dummy corrupt .diff file so that older // versions which don't understand bsdiff will fail out // until they get upgraded, instead of seeing the missing // file and just removing it. File.WriteAllText(targetFile.FullName + ".diff", "1"); } catch (Exception ex) { this.Log().WarnException(String.Format("We really couldn't create a delta for {0}", targetFile.Name), ex); return; } finally { if (of != null) { of.Dispose(); } } } var rl = ReleaseEntry.GenerateFromFile(new MemoryStream(newData), targetFile.Name + ".shasum"); File.WriteAllText(targetFile.FullName + ".shasum", rl.EntryAsString, Encoding.UTF8); targetFile.Delete(); } void applyDiffToFile(string deltaPath, string relativeFilePath, string workingDirectory) { var inputFile = Path.Combine(deltaPath, relativeFilePath); var finalTarget = Path.Combine(workingDirectory, Regex.Replace(relativeFilePath, @"\.(bs)?diff$", "")); var tempTargetFile = default(string); Utility.WithTempFile(out tempTargetFile, localAppDirectory); try { // NB: Zero-length diffs indicate the file hasn't actually changed if (new FileInfo(inputFile).Length == 0) { this.Log().Info("{0} exists unchanged, skipping", relativeFilePath); return; } if (relativeFilePath.EndsWith(".bsdiff", StringComparison.InvariantCultureIgnoreCase)) { using (var of = File.OpenWrite(tempTargetFile)) using (var inf = File.OpenRead(finalTarget)) { this.Log().Info("Applying BSDiff to {0}", relativeFilePath); BinaryPatchUtility.Apply(inf, () => File.OpenRead(inputFile), of); } verifyPatchedFile(relativeFilePath, inputFile, tempTargetFile); } else if (relativeFilePath.EndsWith(".diff", StringComparison.InvariantCultureIgnoreCase)) { this.Log().Info("Applying MSDiff to {0}", relativeFilePath); var msDelta = new MsDeltaCompression(); msDelta.ApplyDelta(inputFile, finalTarget, tempTargetFile); verifyPatchedFile(relativeFilePath, inputFile, tempTargetFile); } else { using (var of = File.OpenWrite(tempTargetFile)) using (var inf = File.OpenRead(inputFile)) { this.Log().Info("Adding new file: {0}", relativeFilePath); inf.CopyTo(of); } } if (File.Exists(finalTarget)) { File.Delete(finalTarget); } var targetPath = Directory.GetParent(finalTarget); if (!targetPath.Exists) { targetPath.Create(); } File.Move(tempTargetFile, finalTarget); } finally { if (File.Exists(tempTargetFile)) { Utility.DeleteFileHarder(tempTargetFile, true); } } } void verifyPatchedFile(string relativeFilePath, string inputFile, string tempTargetFile) { var shaFile = Regex.Replace(inputFile, @"\.(bs)?diff$", ".shasum"); var expectedReleaseEntry = ReleaseEntry.ParseReleaseEntry(File.ReadAllText(shaFile, Encoding.UTF8)); var actualReleaseEntry = ReleaseEntry.GenerateFromFile(tempTargetFile); if (expectedReleaseEntry.Filesize != actualReleaseEntry.Filesize) { this.Log().Warn("Patched file {0} has incorrect size, expected {1}, got {2}", relativeFilePath, expectedReleaseEntry.Filesize, actualReleaseEntry.Filesize); throw new ChecksumFailedException() { Filename = relativeFilePath }; } if (expectedReleaseEntry.SHA1 != actualReleaseEntry.SHA1) { this.Log().Warn("Patched file {0} has incorrect SHA1, expected {1}, got {2}", relativeFilePath, expectedReleaseEntry.SHA1, actualReleaseEntry.SHA1); throw new ChecksumFailedException() { Filename = relativeFilePath }; } } bool bytesAreIdentical(byte[] oldData, byte[] newData) { if (oldData == null || newData == null) { return(oldData == newData); } if (oldData.LongLength != newData.LongLength) { return(false); } for (long i = 0; i < newData.LongLength; i++) { if (oldData[i] != newData[i]) { return(false); } } return(true); } }
public void DependentPackageNotFoundAndThrowsError() { string packagesDir; // use empty packages folder using (Utility.WithTempDirectory(out packagesDir)) { var inputPackage = IntegrationTestHelper.GetPath("fixtures", "ProjectDependsOnJsonDotNet.1.0.nupkg"); var outputPackage = Path.GetTempFileName() + ".nupkg"; try { var package = new ReleasePackage(inputPackage); Assert.Throws<Exception>(() => package.CreateReleasePackage(outputPackage, packagesDir)); } finally { File.Delete(outputPackage); } } }
public void UsesTheRightVersionOfADependencyWhenMultipleAreInPackages() { var outputPackage = Path.GetTempFileName() + ".nupkg"; string outputFile = null; var inputPackage = IntegrationTestHelper.GetPath("fixtures", "CaliburnMicroDemo.1.0.0.nupkg"); var wrongPackage = "Caliburn.Micro.1.4.1.nupkg"; var wrongPackagePath = IntegrationTestHelper.GetPath("fixtures", wrongPackage); var rightPackage = "Caliburn.Micro.1.5.2.nupkg"; var rightPackagePath = IntegrationTestHelper.GetPath("fixtures", rightPackage); try { var sourceDir = IntegrationTestHelper.GetPath("fixtures", "packages"); (new DirectoryInfo(sourceDir)).Exists.ShouldBeTrue(); File.Copy(wrongPackagePath, Path.Combine(sourceDir, wrongPackage), true); File.Copy(rightPackagePath, Path.Combine(sourceDir, rightPackage), true); var package = new ReleasePackage(inputPackage); var outputFileName = package.CreateReleasePackage(outputPackage, sourceDir); var zipPackage = new ZipPackage(outputFileName); var fileName = "Caliburn.Micro.dll"; var dependency = zipPackage.GetLibFiles() .Where(f => f.Path.EndsWith(fileName)) .Single(f => f.TargetFramework == FrameworkTargetVersion.Net40); outputFile = new FileInfo(Path.Combine(sourceDir, fileName)).FullName; using (var of = File.Create(outputFile)) { dependency.GetStream().CopyTo(of); } var assemblyName = AssemblyName.GetAssemblyName(outputFile); Assert.Equal(1, assemblyName.Version.Major); Assert.Equal(5, assemblyName.Version.Minor); } finally { File.Delete(outputPackage); File.Delete(outputFile); } }
public ReleasePackage ApplyDeltaPackage(ReleasePackage basePackage, ReleasePackage deltaPackage, string outputFile, Action <int> progress) { Contract.Requires(deltaPackage != null); Contract.Requires(!String.IsNullOrEmpty(outputFile) && !File.Exists(outputFile)); string workingPath; string deltaPath; using (Utility.WithTempDirectory(out deltaPath, localAppDirectory)) using (Utility.WithTempDirectory(out workingPath, localAppDirectory)) { var opts = new ExtractionOptions() { ExtractFullPath = true, Overwrite = true, PreserveFileTime = true }; using (var za = ZipArchive.Open(deltaPackage.InputPackageFile)) using (var reader = za.ExtractAllEntries()) { reader.WriteAllToDirectory(deltaPath, opts); } progress(25); using (var za = ZipArchive.Open(basePackage.InputPackageFile)) using (var reader = za.ExtractAllEntries()) { reader.WriteAllToDirectory(workingPath, opts); } progress(50); var pathsVisited = new List <string>(); var deltaPathRelativePaths = new DirectoryInfo(deltaPath).GetAllFilesRecursively() .Select(x => x.FullName.Replace(deltaPath + Path.DirectorySeparatorChar, "")) .ToArray(); // Apply all of the .diff files deltaPathRelativePaths .Where(x => x.StartsWith("lib", StringComparison.InvariantCultureIgnoreCase)) .Where(x => !x.EndsWith(".shasum", StringComparison.InvariantCultureIgnoreCase)) .Where(x => !x.EndsWith(".diff", StringComparison.InvariantCultureIgnoreCase) || !deltaPathRelativePaths.Contains(x.Replace(".diff", ".bsdiff"))) .ForEach(file => { pathsVisited.Add(Regex.Replace(file, @"\.(bs)?diff$", "").ToLowerInvariant()); applyDiffToFile(deltaPath, file, workingPath); }); progress(75); // Delete all of the files that were in the old package but // not in the new one. new DirectoryInfo(workingPath).GetAllFilesRecursively() .Select(x => x.FullName.Replace(workingPath + Path.DirectorySeparatorChar, "").ToLowerInvariant()) .Where(x => x.StartsWith("lib", StringComparison.InvariantCultureIgnoreCase) && !pathsVisited.Contains(x)) .ForEach(x => { this.Log().Info("{0} was in old package but not in new one, deleting", x); File.Delete(Path.Combine(workingPath, x)); }); progress(80); // Update all the files that aren't in 'lib' with the delta // package's versions (i.e. the nuspec file, etc etc). deltaPathRelativePaths .Where(x => !x.StartsWith("lib", StringComparison.InvariantCultureIgnoreCase)) .ForEach(x => { this.Log().Info("Updating metadata file: {0}", x); File.Copy(Path.Combine(deltaPath, x), Path.Combine(workingPath, x), true); }); this.Log().Info("Repacking into full package: {0}", outputFile); using (var za = ZipArchive.Create()) using (var tgt = File.OpenWrite(outputFile)) { za.DeflateCompressionLevel = CompressionLevel.BestSpeed; za.AddAllFromDirectory(workingPath); za.SaveTo(tgt); } progress(100); } return(new ReleasePackage(outputFile)); }
public ReleasePackage CreateDeltaPackage(ReleasePackage basePackage, ReleasePackage newPackage, string outputFile) { Contract.Requires(basePackage != null); Contract.Requires(!String.IsNullOrEmpty(outputFile) && !File.Exists(outputFile)); if (basePackage.Version > newPackage.Version) { var message = String.Format( "You cannot create a delta package based on version {0} as it is a later version than {1}", basePackage.Version, newPackage.Version); throw new InvalidOperationException(message); } if (basePackage.ReleasePackageFile == null) { throw new ArgumentException("The base package's release file is null", "basePackage"); } if (!File.Exists(basePackage.ReleasePackageFile)) { throw new FileNotFoundException("The base package release does not exist", basePackage.ReleasePackageFile); } if (!File.Exists(newPackage.ReleasePackageFile)) { throw new FileNotFoundException("The new package release does not exist", newPackage.ReleasePackageFile); } string baseTempPath = null; string tempPath = null; using (Utility.WithTempDirectory(out baseTempPath, null)) using (Utility.WithTempDirectory(out tempPath, null)) { var baseTempInfo = new DirectoryInfo(baseTempPath); var tempInfo = new DirectoryInfo(tempPath); this.Log().Info("Extracting {0} and {1} into {2}", basePackage.ReleasePackageFile, newPackage.ReleasePackageFile, tempPath); var fz = new FastZip(); fz.ExtractZip(basePackage.ReleasePackageFile, baseTempInfo.FullName, null); fz.ExtractZip(newPackage.ReleasePackageFile, tempInfo.FullName, null); // Collect a list of relative paths under 'lib' and map them // to their full name. We'll use this later to determine in // the new version of the package whether the file exists or // not. var baseLibFiles = baseTempInfo.GetAllFilesRecursively() .Where(x => x.FullName.ToLowerInvariant().Contains("lib" + Path.DirectorySeparatorChar)) .ToDictionary(k => k.FullName.Replace(baseTempInfo.FullName, ""), v => v.FullName); var newLibDir = tempInfo.GetDirectories().First(x => x.Name.ToLowerInvariant() == "lib"); foreach (var libFile in newLibDir.GetAllFilesRecursively()) { createDeltaForSingleFile(libFile, tempInfo, baseLibFiles); } ReleasePackage.addDeltaFilesToContentTypes(tempInfo.FullName); fz.CreateZip(outputFile, tempInfo.FullName, true, null); } return(new ReleasePackage(outputFile)); }
public void WhenBasePackageReleaseIsNullThrowsException() { var basePackage = IntegrationTestHelper.GetPath("fixtures", "Squirrel.Core.1.0.0.0.nupkg"); var newPackage = IntegrationTestHelper.GetPath("fixtures", "Squirrel.Core.1.1.0.0.nupkg"); var sourceDir = IntegrationTestHelper.GetPath("fixtures", "packages"); (new DirectoryInfo(sourceDir)).Exists.ShouldBeTrue(); var baseFixture = new ReleasePackage(basePackage); var fixture = new ReleasePackage(newPackage); var tempFile = Path.GetTempPath() + Guid.NewGuid() + ".nupkg"; try { Assert.Throws<ArgumentException>(() => { var deltaBuilder = new DeltaPackageBuilder(); deltaBuilder.CreateDeltaPackage(baseFixture, fixture, tempFile); }); } finally { File.Delete(tempFile); } }
public void WhenMultipleReleasesFoundInOtherOrderReturnPreviousVersion() { var expected = new SemanticVersion("1.7.6-beta"); var input = new ReleasePackage("Espera-1.7.7-beta.nupkg"); var releaseEntries = new[] { ReleaseEntry.ParseReleaseEntry(MockReleaseEntry("Espera-1.7.5-beta.nupkg")), ReleaseEntry.ParseReleaseEntry(MockReleaseEntry("Espera-1.7.6-beta.nupkg")) }; var actual = ReleaseEntry.GetPreviousRelease( releaseEntries, input, @"C:\temp\"); Assert.Equal(expected, actual.Version); }
public void ContentFilesAreIncludedInCreatedPackage() { var inputPackage = IntegrationTestHelper.GetPath("fixtures", "ProjectWithContent.1.0.0.0-beta.nupkg"); var outputPackage = Path.GetTempFileName() + ".nupkg"; var sourceDir = IntegrationTestHelper.GetPath("fixtures", "packages"); var fixture = new ReleasePackage(inputPackage); (new DirectoryInfo(sourceDir)).Exists.ShouldBeTrue(); try { fixture.CreateReleasePackage(outputPackage, sourceDir); this.Log().Info("Resulting package is at {0}", outputPackage); var pkg = new ZipPackage(outputPackage); int refs = pkg.FrameworkAssemblies.Count(); this.Log().Info("Found {0} refs", refs); refs.ShouldEqual(0); this.Log().Info("Files in release package:"); var contentFiles = pkg.GetContentFiles(); Assert.Equal(2, contentFiles.Count()); var contentFilePaths = contentFiles.Select(f => f.EffectivePath); Assert.Contains("some-words.txt", contentFilePaths); Assert.Contains("dir\\item-in-subdirectory.txt", contentFilePaths); Assert.Equal(1, pkg.GetLibFiles().Count()); } finally { File.Delete(outputPackage); } }
public void WhenAProjectContainsNet45BinariesItContainsTheNecessaryDependency() { var outputPackage = Path.GetTempFileName() + ".nupkg"; var inputPackage = IntegrationTestHelper.GetPath("fixtures", "ThisShouldBeANet45Project.1.0.nupkg"); var rightPackage = "Caliburn.Micro.1.5.2.nupkg"; var rightPackagePath = IntegrationTestHelper.GetPath("fixtures", rightPackage); try { var sourceDir = IntegrationTestHelper.GetPath("fixtures", "packages"); (new DirectoryInfo(sourceDir)).Exists.ShouldBeTrue(); File.Copy(rightPackagePath, Path.Combine(sourceDir, rightPackage), true); var package = new ReleasePackage(inputPackage); var outputFileName = package.CreateReleasePackage(outputPackage, sourceDir); var zipPackage = new ZipPackage(outputFileName); var dependency = zipPackage.GetLibFiles() .Where(f => f.Path.EndsWith("Caliburn.Micro.dll")) .FirstOrDefault(f => f.TargetFramework == FrameworkTargetVersion.Net45); Assert.NotNull(dependency); } finally { File.Delete(outputPackage); } }
public void WhenNewPackageDoesNotExistThrowException() { var basePackage = IntegrationTestHelper.GetPath("fixtures", "Squirrel.Tests.0.1.0-pre.nupkg"); var newPackage = IntegrationTestHelper.GetPath("fixtures", "Squirrel.Tests.0.2.0-pre.nupkg"); var sourceDir = IntegrationTestHelper.GetPath("fixtures", "packages"); (new DirectoryInfo(sourceDir)).Exists.ShouldBeTrue(); var baseFixture = new ReleasePackage(basePackage); var fixture = new ReleasePackage(newPackage); var tempFiles = Enumerable.Range(0, 3) .Select(_ => Path.GetTempPath() + Guid.NewGuid().ToString() + ".nupkg") .ToArray(); try { baseFixture.CreateReleasePackage(tempFiles[0], sourceDir); fixture.CreateReleasePackage(tempFiles[1], sourceDir); (new FileInfo(baseFixture.ReleasePackageFile)).Exists.ShouldBeTrue(); (new FileInfo(fixture.ReleasePackageFile)).Exists.ShouldBeTrue(); // NOW WATCH AS THE FILE DISAPPEARS File.Delete(fixture.ReleasePackageFile); Assert.Throws<FileNotFoundException>(() => { var deltaBuilder = new DeltaPackageBuilder(); deltaBuilder.CreateDeltaPackage(baseFixture, fixture, tempFiles[2]); }); } finally { tempFiles.ForEach(File.Delete); } }
async Task <string> installFromDelta(UpdateInfo updateInfo) { IEnumerable <ReleaseEntry> releasesToApply = updateInfo.ReleasesToApply; ReleaseEntry currentVersion = updateInfo.CurrentlyInstalledVersion; var packageDirectory = updateInfo.PackageDirectory; Contract.Requires(releasesToApply != null); // If there are no remote releases at all, bail if (!releasesToApply.Any()) { return(null); } // If there are no deltas in our list, install the last full one if (releasesToApply.All(x => !x.IsDelta)) { return(await installPackageToAppDir(updateInfo, releasesToApply.MaxBy(x => x.Version).FirstOrDefault())); } if (!releasesToApply.All(x => x.IsDelta)) { throw new Exception("Cannot apply combinations of delta and full packages"); } string finalOutputPath = getDirectoryForRelease(releasesToApply.Last().Version).ToString(); string localAppDirectory = Directory.GetParent(this.rootAppDirectory).FullName; string workingPath; using (Utility.WithTempDirectory(out workingPath, localAppDirectory)) { var opts = new ExtractionOptions() { ExtractFullPath = true, Overwrite = true, PreserveFileTime = true }; //Extract base file to working folder this.Log().Info("Extracting base file to working folder {0}", currentVersion.Filename); using (var za = ZipArchive.Open(Path.Combine(rootAppDirectory, "packages", currentVersion.Filename))) using (var reader = za.ExtractAllEntries()) { reader.WriteAllToDirectory(workingPath, opts); } //Apply each incremental release foreach (var delta in releasesToApply) { this.Log().Info("Applying delta release {0} to working folder", delta.Filename); var deltaPkg = new ReleasePackage(Path.Combine(rootAppDirectory, "packages", delta.Filename)); var deltaBuilder = new DeltaPackageBuilder(Directory.GetParent(this.rootAppDirectory).FullName); deltaBuilder.ApplyDeltaPackageToWorkingDirectory(workingPath, deltaPkg); } //Save the final thing into a local full package var lastDeltaPkgFullPath = Path.Combine(rootAppDirectory, "packages", releasesToApply.Last().Filename); var fullPackageOutput = Regex.Replace(lastDeltaPkgFullPath, @"-delta.nupkg$", ".nupkg", RegexOptions.IgnoreCase | RegexOptions.CultureInvariant); this.Log().Info("Repacking into full package: {0}", fullPackageOutput); using (var za = ZipArchive.Create()) using (var tgt = File.OpenWrite(fullPackageOutput)) { za.DeflateCompressionLevel = CompressionLevel.BestSpeed; za.AddAllFromDirectory(workingPath); za.SaveTo(tgt); } //Convert this from NuGet package format to raw folder format ReleasePackage.ConvertNuGetWorkingDirectoryForInstall(workingPath, finalOutputPath, rootAppDirectory); } return(finalOutputPath); }
public void Releasify(string package, string targetDir = null, string packagesDir = null, string bootstrapperExe = null, string backgroundGif = null, string signingOpts = null, string baseUrl = null, string setupIcon = null) { if (baseUrl != null) { if (!Utility.IsHttpUrl(baseUrl)) { throw new Exception(string.Format("Invalid --baseUrl '{0}'. A base URL must start with http or https and be a valid URI.", baseUrl)); } if (!baseUrl.EndsWith("/")) { baseUrl += "/"; } } targetDir = targetDir ?? ".\\Releases"; packagesDir = packagesDir ?? "."; bootstrapperExe = bootstrapperExe ?? ".\\Setup.exe"; if (!Directory.Exists(targetDir)) { Directory.CreateDirectory(targetDir); } if (!File.Exists(bootstrapperExe)) { bootstrapperExe = Path.Combine( Path.GetDirectoryName(Assembly.GetEntryAssembly().Location), "Setup.exe"); } this.Log().Info("Bootstrapper EXE found at:" + bootstrapperExe); var di = new DirectoryInfo(targetDir); File.Copy(package, Path.Combine(di.FullName, Path.GetFileName(package)), true); var allNuGetFiles = di.EnumerateFiles() .Where(x => x.Name.EndsWith(".nupkg", StringComparison.OrdinalIgnoreCase)); var toProcess = allNuGetFiles.Where(x => !x.Name.Contains("-delta") && !x.Name.Contains("-full")); var processed = new List<string>(); var releaseFilePath = Path.Combine(di.FullName, "RELEASES"); var previousReleases = new List<ReleaseEntry>(); if (File.Exists(releaseFilePath)) { previousReleases.AddRange(ReleaseEntry.ParseReleaseFile(File.ReadAllText(releaseFilePath, Encoding.UTF8))); } foreach (var file in toProcess) { this.Log().Info("Creating release package: " + file.FullName); var rp = new ReleasePackage(file.FullName); rp.CreateReleasePackage(Path.Combine(di.FullName, rp.SuggestedReleaseFileName), packagesDir, contentsPostProcessHook: pkgPath => { if (signingOpts == null) return; new DirectoryInfo(pkgPath).GetAllFilesRecursively() .Where(x => x.Name.ToLowerInvariant().EndsWith(".exe")) .ForEachAsync(x => signPEFile(x.FullName, signingOpts)) .Wait(); }); processed.Add(rp.ReleasePackageFile); var prev = ReleaseEntry.GetPreviousRelease(previousReleases, rp, targetDir); if (prev != null) { var deltaBuilder = new DeltaPackageBuilder(null); var dp = deltaBuilder.CreateDeltaPackage(prev, rp, Path.Combine(di.FullName, rp.SuggestedReleaseFileName.Replace("full", "delta"))); processed.Insert(0, dp.InputPackageFile); } } foreach (var file in toProcess) { File.Delete(file.FullName); } var newReleaseEntries = processed.Select(packageFilename => ReleaseEntry.GenerateFromFile(packageFilename, baseUrl)).ToList(); var distinctPreviousReleases = previousReleases.Where(x => !newReleaseEntries.Select(e => e.Version).Contains(x.Version)); var releaseEntries = distinctPreviousReleases.Concat(newReleaseEntries).ToList(); ReleaseEntry.WriteReleaseFile(releaseEntries, releaseFilePath); var targetSetupExe = Path.Combine(di.FullName, "Setup.exe"); var newestFullRelease = releaseEntries.MaxBy(x => x.Version).Where(x => !x.IsDelta).First(); File.Copy(bootstrapperExe, targetSetupExe, true); var zipPath = createSetupEmbeddedZip(Path.Combine(di.FullName, newestFullRelease.Filename), di.FullName, backgroundGif, signingOpts).Result; try { var zip = File.ReadAllBytes(zipPath); IntPtr handle = NativeMethods.BeginUpdateResource(targetSetupExe, false); if (handle == IntPtr.Zero) { throw new Win32Exception(); } if (!NativeMethods.UpdateResource(handle, "DATA", new IntPtr(131), 0x0409, zip, zip.Length)) { throw new Win32Exception(); } if (!NativeMethods.EndUpdateResource(handle, false)) { throw new Win32Exception(); } } catch (Exception ex) { this.Log().ErrorException("Failed to update Setup.exe with new Zip file", ex); } finally { File.Delete(zipPath); } Utility.Retry(() => setPEVersionInfoAndIcon(targetSetupExe, new ZipPackage(package), setupIcon).Wait()); if (signingOpts != null) { signPEFile(targetSetupExe, signingOpts).Wait(); } }
public void CreateDeltaPackageIntegrationTest() { var basePackage = IntegrationTestHelper.GetPath("fixtures", "Squirrel.Tests.0.1.0-pre.nupkg"); var newPackage = IntegrationTestHelper.GetPath("fixtures", "Squirrel.Tests.0.2.0-pre.nupkg"); var sourceDir = IntegrationTestHelper.GetPath("fixtures", "packages"); (new DirectoryInfo(sourceDir)).Exists.ShouldBeTrue(); var baseFixture = new ReleasePackage(basePackage); var fixture = new ReleasePackage(newPackage); var tempFiles = Enumerable.Range(0, 3) .Select(_ => Path.GetTempPath() + Guid.NewGuid().ToString() + ".nupkg") .ToArray(); try { baseFixture.CreateReleasePackage(tempFiles[0], sourceDir); fixture.CreateReleasePackage(tempFiles[1], sourceDir); (new FileInfo(baseFixture.ReleasePackageFile)).Exists.ShouldBeTrue(); (new FileInfo(fixture.ReleasePackageFile)).Exists.ShouldBeTrue(); var deltaBuilder = new DeltaPackageBuilder(); deltaBuilder.CreateDeltaPackage(baseFixture, fixture, tempFiles[2]); var fullPkg = new ZipPackage(tempFiles[1]); var deltaPkg = new ZipPackage(tempFiles[2]); // // Package Checks // fullPkg.Id.ShouldEqual(deltaPkg.Id); fullPkg.Version.CompareTo(deltaPkg.Version).ShouldEqual(0); // Delta packages should be smaller than the original! var fileInfos = tempFiles.Select(x => new FileInfo(x)).ToArray(); this.Log().Info("Base Size: {0}, Current Size: {1}, Delta Size: {2}", fileInfos[0].Length, fileInfos[1].Length, fileInfos[2].Length); (fileInfos[2].Length - fileInfos[1].Length).ShouldBeLessThan(0); // // File Checks /// var deltaPkgFiles = deltaPkg.GetFiles().ToList(); deltaPkgFiles.Count.ShouldBeGreaterThan(0); this.Log().Info("Files in delta package:"); deltaPkgFiles.ForEach(x => this.Log().Info(x.Path)); var newFilesAdded = new[] { "Newtonsoft.Json.dll", "Refit.dll", "Refit-Portable.dll", "Castle.Core.dll", }.Select(x => x.ToLowerInvariant()); // vNext adds a dependency on Refit newFilesAdded .All(x => deltaPkgFiles.Any(y => y.Path.ToLowerInvariant().Contains(x))) .ShouldBeTrue(); // All the other files should be diffs and shasums deltaPkgFiles .Where(x => !newFilesAdded.Any(y => x.Path.ToLowerInvariant().Contains(y))) .All(x => x.Path.ToLowerInvariant().EndsWith("diff") || x.Path.ToLowerInvariant().EndsWith("shasum")) .ShouldBeTrue(); // Every .diff file should have a shasum file deltaPkg.GetFiles().Any(x => x.Path.ToLowerInvariant().EndsWith(".diff")).ShouldBeTrue(); deltaPkg.GetFiles() .Where(x => x.Path.ToLowerInvariant().EndsWith(".diff")) .ForEach(x => { var lookingFor = x.Path.Replace(".diff", ".shasum"); this.Log().Info("Looking for corresponding shasum file: {0}", lookingFor); deltaPkg.GetFiles().Any(y => y.Path == lookingFor).ShouldBeTrue(); }); } finally { tempFiles.ForEach(File.Delete); } }
async Task<ReleaseEntry> createFullPackagesFromDeltas(IEnumerable<ReleaseEntry> releasesToApply, ReleaseEntry currentVersion) { Contract.Requires(releasesToApply != null); // If there are no remote releases at all, bail if (!releasesToApply.Any()) { return null; } // If there are no deltas in our list, we're already done if (releasesToApply.All(x => !x.IsDelta)) { return releasesToApply.MaxBy(x => x.Version).FirstOrDefault(); } if (!releasesToApply.All(x => x.IsDelta)) { throw new Exception("Cannot apply combinations of delta and full packages"); } // Smash together our base full package and the nearest delta var ret = await Task.Run(() => { var basePkg = new ReleasePackage(Path.Combine(rootAppDirectory, "packages", currentVersion.Filename)); var deltaPkg = new ReleasePackage(Path.Combine(rootAppDirectory, "packages", releasesToApply.First().Filename)); var deltaBuilder = new DeltaPackageBuilder(Directory.GetParent(this.rootAppDirectory).FullName); return deltaBuilder.ApplyDeltaPackage(basePkg, deltaPkg, Regex.Replace(deltaPkg.InputPackageFile, @"-delta.nupkg$", ".nupkg", RegexOptions.IgnoreCase | RegexOptions.CultureInvariant)); }); if (releasesToApply.Count() == 1) { return ReleaseEntry.GenerateFromFile(ret.InputPackageFile); } var fi = new FileInfo(ret.InputPackageFile); var entry = ReleaseEntry.GenerateFromFile(fi.OpenRead(), fi.Name); // Recursively combine the rest of them return await createFullPackagesFromDeltas(releasesToApply.Skip(1), entry); }
public void SpecFileMarkdownRenderingTest() { var dontcare = IntegrationTestHelper.GetPath("fixtures", "Squirrel.Core.1.1.0.0.nupkg"); var inputSpec = IntegrationTestHelper.GetPath("fixtures", "Squirrel.Core.1.1.0.0.nuspec"); var fixture = new ReleasePackage(dontcare); var targetFile = Path.GetTempFileName(); File.Copy(inputSpec, targetFile, true); try { var processor = new Func<string, string>(input => (new Markdown()).Transform(input)); // NB: For No Reason At All, renderReleaseNotesMarkdown is // invulnerable to ExposedObject. Whyyyyyyyyy var renderMinfo = fixture.GetType().GetMethod("renderReleaseNotesMarkdown", BindingFlags.NonPublic | BindingFlags.Instance); renderMinfo.Invoke(fixture, new object[] {targetFile, processor}); var doc = XDocument.Load(targetFile); XNamespace ns = "http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd"; var relNotesElement = doc.Descendants(ns + "releaseNotes").First(); var htmlText = relNotesElement.Value; this.Log().Info("HTML Text:\n{0}", htmlText); htmlText.Contains("## Release Notes").ShouldBeFalse(); } finally { File.Delete(targetFile); } }