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);
            }
        }
Exemple #3
0
            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;
                }));
            }
Exemple #13
0
        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);
                }
            }
        }
Exemple #15
0
        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;
                }));
            }
Exemple #17
0
            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);
     }
 }
Exemple #22
0
 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);
            }
        }
Exemple #26
0
        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);
            }
Exemple #34
0
        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);
            }
        }