private Task <string> InstallPackageToAppDir(UpdateInfo updateInfo, ReleaseEntry release)
            {
                return(Task.Run(
                           async() =>
                {
                    var target = GetDirectoryForRelease(release.Version);

                    // NB: This might happen if we got killed partially through applying the release
                    if (target.Exists)
                    {
                        Log.WarnFormat("Found partially applied release folder, killing it: " + target.FullName);
                        await Utility.DeleteDirectory(target.FullName);
                    }

                    target.Create();

                    Log.InfoFormat("Writing files to app directory: {0}", target.FullName);
                    await ReleasePackage.ExtractZipForInstall(
                        Path.Combine(updateInfo.PackageDirectory, release.Filename),
                        target.FullName,
                        rootAppDirectory);

                    return target.FullName;
                }));
            }
            private async Task <ReleaseEntry> CreateFullPackagesFromDeltas(IEnumerable <ReleaseEntry> releasesToApply, ReleaseEntry currentVersion)
            {
                Guard.ArgumentIsTrue(releasesToApply != null, "releasesToApply != null");

                // If there are no remote releases at all, bail
                if (!releasesToApply.Any())
                {
                    return(null);
                }

                // If there are no deltas in our list, we're already done
                if (releasesToApply.All(x => !x.IsDelta))
                {
                    return(releasesToApply.MaxBy(x => x.Version).FirstOrDefault());
                }

                if (!releasesToApply.All(x => x.IsDelta))
                {
                    throw new Exception("Cannot apply combinations of delta and full packages");
                }

                // Smash together our base full package and the nearest delta
                var ret = await Task.Run(
                    () =>
                {
                    var basePkg  = new ReleasePackage(Path.Combine(rootAppDirectory, "packages", currentVersion.Filename));
                    var deltaPkg = new ReleasePackage(Path.Combine(rootAppDirectory, "packages", releasesToApply.First().Filename));

                    var deltaBuilder = new DeltaPackageBuilder(Directory.GetParent(rootAppDirectory).FullName);

                    return(deltaBuilder.ApplyDeltaPackage(
                               basePkg,
                               deltaPkg,
                               Regex.Replace(deltaPkg.InputPackageFile, @"-delta.nupkg$", ".nupkg", RegexOptions.IgnoreCase | RegexOptions.CultureInvariant)));
                });

                if (releasesToApply.Count() == 1)
                {
                    return(ReleaseEntry.GenerateFromFile(ret.InputPackageFile));
                }

                var fi    = new FileInfo(ret.InputPackageFile);
                var entry = ReleaseEntry.GenerateFromFile(fi.OpenRead(), fi.Name);

                // Recursively combine the rest of them
                return(await CreateFullPackagesFromDeltas(releasesToApply.Skip(1), entry));
            }
Example #3
0
        public ReleasePackage ApplyDeltaPackage(ReleasePackage basePackage, ReleasePackage deltaPackage, string outputFile)
        {
            Guard.ArgumentIsTrue(deltaPackage != null, "deltaPackage != null");
            Guard.ArgumentIsTrue(!string.IsNullOrEmpty(outputFile) && !File.Exists(outputFile), "!string.IsNullOrEmpty(outputFile) && !File.Exists(outputFile)");

            using (Utility.WithTempDirectory(out var deltaPath, localAppDirectory))
                using (Utility.WithTempDirectory(out var workingPath, localAppDirectory))
                {
                    var opts = new ExtractionOptions {
                        ExtractFullPath = true, Overwrite = true, PreserveFileTime = true
                    };

                    using (var za = ZipArchive.Open(deltaPackage.InputPackageFile))
                        using (var reader = za.ExtractAllEntries())
                        {
                            reader.WriteAllToDirectory(deltaPath, opts);
                        }

                    using (var za = ZipArchive.Open(basePackage.InputPackageFile))
                        using (var reader = za.ExtractAllEntries())
                        {
                            reader.WriteAllToDirectory(workingPath, opts);
                        }

                    var pathsVisited = new List <string>();

                    var deltaPathRelativePaths = new DirectoryInfo(deltaPath).GetAllFilesRecursively()
                                                 .Select(x => x.FullName.Replace(deltaPath + Path.DirectorySeparatorChar, ""))
                                                 .ToArray();

                    // Apply all of the .diff files
                    deltaPathRelativePaths
                    .Where(x => x.StartsWith("lib", StringComparison.InvariantCultureIgnoreCase))
                    .Where(x => !x.EndsWith(".shasum", StringComparison.InvariantCultureIgnoreCase))
                    .Where(
                        x => !x.EndsWith(".diff", StringComparison.InvariantCultureIgnoreCase) ||
                        !deltaPathRelativePaths.Contains(x.Replace(".diff", ".bsdiff")))
                    .ForEach(
                        file =>
                    {
                        pathsVisited.Add(Regex.Replace(file, @"\.(bs)?diff$", "").ToLowerInvariant());
                        ApplyDiffToFile(deltaPath, file, workingPath);
                    });

                    // Delete all of the files that were in the old package but
                    // not in the new one.
                    new DirectoryInfo(workingPath).GetAllFilesRecursively()
                    .Select(x => x.FullName.Replace(workingPath + Path.DirectorySeparatorChar, "").ToLowerInvariant())
                    .Where(x => x.StartsWith("lib", StringComparison.InvariantCultureIgnoreCase) && !pathsVisited.Contains(x))
                    .ForEach(
                        x =>
                    {
                        Log.InfoFormat("{0} was in old package but not in new one, deleting", x);
                        File.Delete(Path.Combine(workingPath, x));
                    });

                    // Update all the files that aren't in 'lib' with the delta
                    // package's versions (i.e. the nuspec file, etc etc).
                    deltaPathRelativePaths
                    .Where(x => !x.StartsWith("lib", StringComparison.InvariantCultureIgnoreCase))
                    .ForEach(
                        x =>
                    {
                        Log.InfoFormat("Updating metadata file: {0}", x);
                        File.Copy(Path.Combine(deltaPath, x), Path.Combine(workingPath, x), true);
                    });

                    Log.InfoFormat("Repacking into full package: {0}", outputFile);
                    using (var za = ZipArchive.Create())
                        using (var tgt = File.OpenWrite(outputFile ?? throw new ArgumentNullException(nameof(outputFile))))
                        {
                            za.DeflateCompressionLevel = CompressionLevel.BestSpeed;
                            za.AddAllFromDirectory(workingPath);
                            za.SaveTo(tgt);
                        }
                }

            return(new ReleasePackage(outputFile));
        }
Example #4
0
        public ReleasePackage CreateDeltaPackage(ReleasePackage basePackage, ReleasePackage newPackage, string outputFile)
        {
            Guard.ArgumentIsTrue(basePackage != null, "basePackage != null");
            Guard.ArgumentIsTrue(!string.IsNullOrEmpty(outputFile) && !File.Exists(outputFile), "!string.IsNullOrEmpty(outputFile) && !File.Exists(outputFile)");

            if (basePackage.Version > newPackage.Version)
            {
                var message = $"You cannot create a delta package based on version {basePackage.Version} as it is a later version than {newPackage.Version}";
                throw new InvalidOperationException(message);
            }

            if (basePackage.ReleasePackageFile == null)
            {
                throw new ArgumentException("The base package's release file is null", "basePackage");
            }

            if (!File.Exists(basePackage.ReleasePackageFile))
            {
                throw new FileNotFoundException("The base package release does not exist", basePackage.ReleasePackageFile);
            }

            if (!File.Exists(newPackage.ReleasePackageFile))
            {
                throw new FileNotFoundException("The new package release does not exist", newPackage.ReleasePackageFile);
            }

            using (Utility.WithTempDirectory(out var baseTempPath))
                using (Utility.WithTempDirectory(out var tempPath))
                {
                    var baseTempInfo = new DirectoryInfo(baseTempPath);
                    var tempInfo     = new DirectoryInfo(tempPath);

                    Log.InfoFormat(
                        "Extracting {0} and {1} into {2}",
                        basePackage.ReleasePackageFile,
                        newPackage.ReleasePackageFile,
                        tempPath);

                    Utility.ExtractZipToDirectory(basePackage.ReleasePackageFile, baseTempInfo.FullName).Wait();
                    Utility.ExtractZipToDirectory(newPackage.ReleasePackageFile, tempInfo.FullName).Wait();

                    // Collect a list of relative paths under 'lib' and map them
                    // to their full name. We'll use this later to determine in
                    // the new version of the package whether the file exists or
                    // not.
                    var baseLibFiles = baseTempInfo.GetAllFilesRecursively()
                                       .Where(x => x.FullName.ToLowerInvariant().Contains("lib" + Path.DirectorySeparatorChar))
                                       .ToDictionary(k => k.FullName.Replace(baseTempInfo.FullName, ""), v => v.FullName);

                    var newLibDir = tempInfo.GetDirectories().First(x => x.Name.ToLowerInvariant() == "lib");

                    foreach (var libFile in newLibDir.GetAllFilesRecursively())
                    {
                        CreateDeltaForSingleFile(libFile, tempInfo, baseLibFiles);
                    }

                    ReleasePackage.AddDeltaFilesToContentTypes(tempInfo.FullName);
                    Utility.CreateZipFromDirectory(outputFile, tempInfo.FullName).Wait();
                }

            return(new ReleasePackage(outputFile));
        }