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); Utility.ExtractZipToDirectory(basePackage.ReleasePackageFile, baseTempInfo.FullName).Wait(); var opts = new ExtractionOptions() { ExtractFullPath = true, Overwrite = true, PreserveFileTime = true }; 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)); }
public string CreateReleasePackage(string outputFile, string packagesRootDir = null, Func <string, string> releaseNotesProcessor = null, Action <string> contentsPostProcessHook = null) { Contract.Requires(!String.IsNullOrEmpty(outputFile)); releaseNotesProcessor = releaseNotesProcessor ?? (x => (new Markdown()).Transform(x)); if (ReleasePackageFile != null) { return(ReleasePackageFile); } var package = new ZipPackage(InputPackageFile); var dontcare = default(SemanticVersion); // NB: Our test fixtures use packages that aren't SemVer compliant, // we don't really care that they aren't valid if (!ModeDetector.InUnitTestRunner() && !SemanticVersion.TryParseStrict(package.Version.ToString(), out dontcare)) { throw new Exception( String.Format( "Your package version is currently {0}, which is *not* SemVer-compatible, change this to be a SemVer version number", package.Version.ToString())); } // we can tell from here what platform(s) the package targets // but given this is a simple package we only // ever expect one entry here (crash hard otherwise) var frameworks = package.GetSupportedFrameworks(); if (frameworks.Count() > 1) { var platforms = frameworks .Aggregate(new StringBuilder(), (sb, f) => sb.Append(f.ToString() + "; ")); throw new InvalidOperationException(String.Format( "The input package file {0} targets multiple platforms - {1} - and cannot be transformed into a release package.", InputPackageFile, platforms)); } else if (!frameworks.Any()) { throw new InvalidOperationException(String.Format( "The input package file {0} targets no platform and cannot be transformed into a release package.", InputPackageFile)); } var targetFramework = frameworks.Single(); // Recursively walk the dependency tree and extract all of the // dependent packages into the a temporary directory this.Log().Info("Creating release package: {0} => {1}", InputPackageFile, outputFile); var dependencies = findAllDependentPackages( package, new LocalPackageRepository(packagesRootDir), frameworkName: targetFramework) .ToArray(); string tempPath = null; using (Utility.WithTempDirectory(out tempPath, null)) { var tempDir = new DirectoryInfo(tempPath); extractZipWithEscaping(InputPackageFile, tempPath).Wait(); this.Log().Info("Extracting dependent packages: [{0}]", String.Join(",", dependencies.Select(x => x.Id))); extractDependentPackages(dependencies, tempDir, targetFramework); var specPath = tempDir.GetFiles("*.nuspec").First().FullName; this.Log().Info("Removing unnecessary data"); removeDependenciesFromPackageSpec(specPath); removeDeveloperDocumentation(tempDir); if (releaseNotesProcessor != null) { renderReleaseNotesMarkdown(specPath, releaseNotesProcessor); } addDeltaFilesToContentTypes(tempDir.FullName); contentsPostProcessHook?.Invoke(tempPath); Utility.CreateZipFromDirectory(outputFile, tempPath).Wait(); ReleasePackageFile = outputFile; return(ReleasePackageFile); } }