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); using (var of = File.Create(targetFile.FullName + ".diff")) { BinaryPatchUtility.Create(oldData, newData, of); var rl = ReleaseEntry.GenerateFromFile(new MemoryStream(newData), targetFile.Name + ".shasum"); File.WriteAllText(targetFile.FullName + ".shasum", rl.EntryAsString, Encoding.UTF8); targetFile.Delete(); } }
public ReleasePackage CreateDeltaPackage(ReleasePackage baseFixture, string outputFile) { Contract.Requires(baseFixture != null && baseFixture.ReleasePackageFile != null); Contract.Requires(!String.IsNullOrEmpty(outputFile) && !File.Exists(outputFile)); string baseTempPath = null; string tempPath = null; using (Utility.WithTempDirectory(out baseTempPath)) using (Utility.WithTempDirectory(out tempPath)) { var baseTempInfo = new DirectoryInfo(baseTempPath); var tempInfo = new DirectoryInfo(tempPath); using (var zf = new ZipFile(baseFixture.ReleasePackageFile)) { zf.ExtractAll(baseTempInfo.FullName); } using (var zf = new ZipFile(ReleasePackageFile)) { zf.ExtractAll(tempInfo.FullName); } // 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"); // 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 newLibDir.GetAllFilesRecursively().ForEach(libFile => { var relativePath = libFile.FullName.Replace(tempInfo.FullName, ""); if (!baseLibFiles.ContainsKey(relativePath)) { this.Log().Info("{0} not found in base package, marking as new", relativePath); return; } var oldData = File.ReadAllBytes(baseLibFiles[relativePath]); var newData = File.ReadAllBytes(libFile.FullName); if (bytesAreIdentical(oldData, newData)) { this.Log().Info("{0} hasn't changed, writing dummy file", relativePath); File.Create(libFile.FullName + ".diff").Dispose(); File.Create(libFile.FullName + ".shasum").Dispose(); libFile.Delete(); return; } this.Log().Info("Delta patching {0} => {1}", baseLibFiles[relativePath], libFile.FullName); using (var of = File.Create(libFile.FullName + ".diff")) { BinaryPatchUtility.Create(oldData, newData, of); var rl = ReleaseEntry.GenerateFromFile(new MemoryStream(newData), libFile.Name + ".shasum"); File.WriteAllText(libFile.FullName + ".shasum", rl.EntryAsString, Encoding.UTF8); libFile.Delete(); } }); addDeltaFilesToContentTypes(tempInfo.FullName); using (var zf = new ZipFile(outputFile)) { zf.AddDirectory(tempInfo.FullName); zf.Save(); } } return(new ReleasePackage(outputFile)); }