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);
                        });
                    }
            }
        }
        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));
        }
Beispiel #3
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));
        }
Beispiel #4
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));
        }
Beispiel #5
0
        public string CreateReleasePackage(string outputFile, string packagesRootDir = null, Func <string, string> releaseNotesProcessor = null)
        {
            Contract.Requires(!String.IsNullOrEmpty(outputFile));
            releaseNotesProcessor = releaseNotesProcessor ?? (x => (new Markdown()).Transform(x));

            if (ReleasePackageFile != null)
            {
                return(ReleasePackageFile);
            }

            var package = new ZipPackage(InputPackageFile);

            // 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);

            string tempPath = null;

            using (Utility.WithTempDirectory(out tempPath)) {
                var tempDir = new DirectoryInfo(tempPath);

                using (var zf = new ZipFile(InputPackageFile)) {
                    zf.ExtractAll(tempPath);
                }

                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);

                using (var zf = new ZipFile(outputFile)) {
                    this.Log().Info("Succeeeded, saving to " + outputFile);
                    zf.AddDirectory(tempPath);
                    zf.Save();
                }

                ReleasePackageFile = outputFile;
                return(ReleasePackageFile);
            }
        }
        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 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);
        }
    }
Beispiel #8
0
        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);
            }
        }
            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);
            }
Beispiel #10
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));
        }