private 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) { Log.WarnFormat("Found partially applied release folder, killing it: " + target.FullName); await Utility.DeleteDirectory(target.FullName); } target.Create(); Log.InfoFormat("Writing files to app directory: {0}", target.FullName); await ReleasePackage.ExtractZipForInstall( Path.Combine(updateInfo.PackageDirectory, release.Filename), target.FullName, rootAppDirectory); return target.FullName; })); }
private async Task <ReleaseEntry> CreateFullPackagesFromDeltas(IEnumerable <ReleaseEntry> releasesToApply, ReleaseEntry currentVersion) { Guard.ArgumentIsTrue(releasesToApply != null, "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(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 ReleasePackage ApplyDeltaPackage(ReleasePackage basePackage, ReleasePackage deltaPackage, string outputFile) { Guard.ArgumentIsTrue(deltaPackage != null, "deltaPackage != null"); Guard.ArgumentIsTrue(!string.IsNullOrEmpty(outputFile) && !File.Exists(outputFile), "!string.IsNullOrEmpty(outputFile) && !File.Exists(outputFile)"); using (Utility.WithTempDirectory(out var deltaPath, localAppDirectory)) using (Utility.WithTempDirectory(out var 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); } using (var za = ZipArchive.Open(basePackage.InputPackageFile)) using (var reader = za.ExtractAllEntries()) { reader.WriteAllToDirectory(workingPath, 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 => { Log.InfoFormat("{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 => { Log.InfoFormat("Updating metadata file: {0}", x); File.Copy(Path.Combine(deltaPath, x), Path.Combine(workingPath, x), true); }); Log.InfoFormat("Repacking into full package: {0}", outputFile); using (var za = ZipArchive.Create()) using (var tgt = File.OpenWrite(outputFile ?? throw new ArgumentNullException(nameof(outputFile)))) { za.DeflateCompressionLevel = CompressionLevel.BestSpeed; za.AddAllFromDirectory(workingPath); za.SaveTo(tgt); } } return(new ReleasePackage(outputFile)); }
public ReleasePackage CreateDeltaPackage(ReleasePackage basePackage, ReleasePackage newPackage, string outputFile) { Guard.ArgumentIsTrue(basePackage != null, "basePackage != null"); Guard.ArgumentIsTrue(!string.IsNullOrEmpty(outputFile) && !File.Exists(outputFile), "!string.IsNullOrEmpty(outputFile) && !File.Exists(outputFile)"); if (basePackage.Version > newPackage.Version) { var message = $"You cannot create a delta package based on version {basePackage.Version} as it is a later version than {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); } using (Utility.WithTempDirectory(out var baseTempPath)) using (Utility.WithTempDirectory(out var tempPath)) { var baseTempInfo = new DirectoryInfo(baseTempPath); var tempInfo = new DirectoryInfo(tempPath); Log.InfoFormat( "Extracting {0} and {1} into {2}", basePackage.ReleasePackageFile, newPackage.ReleasePackageFile, tempPath); Utility.ExtractZipToDirectory(basePackage.ReleasePackageFile, baseTempInfo.FullName).Wait(); Utility.ExtractZipToDirectory(newPackage.ReleasePackageFile, tempInfo.FullName).Wait(); // 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); Utility.CreateZipFromDirectory(outputFile, tempInfo.FullName).Wait(); } return(new ReleasePackage(outputFile)); }