{"action":"created","comment":{"url":"https://api.github.com/repos/OctopusDeploy/Calamari/pulls/comments/28568321","id":28568321,"diff_hunk":"@@ -0,0 +1,131 @@\n+﻿using System;\n+using System.IO;\n+using System.Net.Configuration;\n+using System.Runtime.Remoting.Messaging;\n+using System.Text;\n+using Calamari.Commands.Support;\n+using Calamari.Integration.FileSystem;\n+using Calamari.Integration.Processes;\n+using Calamari.Integration.ServiceMessages;\n+using Octostache;\n+\n+namespace Calamari.Commands\n+{\n+    [Command(\"apply-delta\", Description = \"Applies a delta file to a package to create a new version of the package\")]\n+    public class ApplyDeltaCommand : Command\n+    {\n+        string basisFileName;\n+        string fileHash;\n+        string deltaFileName;\n+        string newFileName;\n+        bool showProgress;\n+        bool skipVerification;\n+        readonly PackageStore packageStore = new PackageStore();\n+        readonly ICalamariFileSystem fileSystem = new CalamariPhysicalFileSystem();\n+        readonly ISemaphore semaphore = new SystemSemaphore();\n+\n+        public ApplyDeltaCommand()\n+        {\n+            Options.Add(\"basisFileName=\", \"The file that the delta was created for.\", v => basisFileName = v);\n+            Options.Add(\"fileHash=\", \"\", v => fileHash = v);\n+            Options.Add(\"deltaFileName=\", \"The delta to apply to the basis file\", v => deltaFileName = v);\n+            Options.Add(\"newFileName=\", \"The file to write the result to.\", v => newFileName = v);\n+            Options.Add(\"progress\", \"Whether progress should be written to stdout\", v => showProgress = true);\n+            Options.Add(\"skipVerification\",\n+                \"Skip checking whether the basis file is the same as the file used to produce the signature that created the delta.\",\n+                v => skipVerification = true);\n+        }\n+        public override int Execute(string[] commandLineArguments)\n+        {\n+            Options.Parse(commandLineArguments);\n+            string deltaFilePath;\n+            string newFilePath;\n+            string basisFilePath;\n+            ValidateParameters(out basisFilePath, out deltaFilePath, out newFilePath);\n+            fileSystem.EnsureDiskHasEnoughFreeSpace(packageStore.GetPackagesDirectory());\n+\n+            var commandLineRunner = new CommandLineRunner(new SplitCommandOutput(new ConsoleCommandOutput(),\n+                new ServiceMessageCommandOutput(new VariableDictionary())));\n+\n+            var tempNewFilePath = newFilePath + \".partial\";\n+            var executable = FindOctoDiffExecutable();\n+            var octoDiff = CommandLine.Execute(executable)\n+                .Action(\"patch\")\n+                .PositionalArgument(basisFilePath)\n+                .PositionalArgument(deltaFilePath)\n+                .PositionalArgument(tempNewFilePath)\n+                .Build();\n+\n+            Log.Info(\"Applying delta to {0} with hash {1} and storing as {2}\", basisFilePath, fileHash,\n+                newFilePath);\n+\n+            var result = commandLineRunner.Execute(octoDiff);\n+            if (result.ExitCode != 0)\n+            {\n+                fileSystem.DeleteFile(tempNewFilePath, DeletionOptions.TryThreeTimes);\n+                throw new CommandLineException(executable, result.ExitCode, result.Errors);\n+            }\n+\n+            File.Move(tempNewFilePath, newFilePath);\n+\n+            if (!File.Exists(newFilePath))\n+                throw new CommandException(\"Failed to apply delta file \" + deltaFilePath + \" to \" +\n+                                           basisFilePath);\n+\n+            var package = packageStore.GetPackage(newFilePath);\n+            if (package == null) return 0;\n+\n+            using (var file = new FileStream(package.FullPath, FileMode.Open, FileAccess.Read, FileShare.Read))\n+            {\n+                var size = file.Length;\n+                Log.ServiceMessages.DeltaVerification(package.FullPath, package.Metadata.Hash, size);\n+            }\n+\n+            return 0;\n+        }\n+\n+        void ValidateParameters(out string basisFilePath, out string deltaFilePath, out string newFilePath)\n+        {\n+            Guard.NotNullOrWhiteSpace(basisFileName, \"No basis file was specified. Please pass --basisFileName MyPackage.1.0.0.0.nupkg\");\n+            Guard.NotNullOrWhiteSpace(fileHash, \"No file hash was specified. Please pass --fileHash MyFileHash\");\n+            Guard.NotNullOrWhiteSpace(deltaFileName, \"No delta file was specified. Please pass --deltaFileName MyPackage.1.0.0.0_to_1.0.0.1.octodelta\");\n+            Guard.NotNullOrWhiteSpace(newFileName, \"No new file name was specified. Please pass --newFileName MyPackage.1.0.0.1.nupkg\");\n+\n+            basisFilePath = Path.GetFullPath(basisFileName);\n+            deltaFilePath = Path.GetFullPath(deltaFileName);\n+            newFilePath = Path.Combine(packageStore.GetPackagesDirectory(), newFileName + \"-\" + Guid.NewGuid());\n+            if (!File.Exists(basisFilePath)) throw new CommandException(\"Could not find basis file: \" + basisFileName);\n+            if (!File.Exists(deltaFilePath)) throw new CommandException(\"Could not find delta file: \" + deltaFileName);\n+\n+            var previousPackage = packageStore.GetPackage(basisFilePath);\n+            if (previousPackage.Metadata.Hash != fileHash)\n+            {\n+                throw new CommandException(\"Basis file hash \" + previousPackage.Metadata.Hash +\n+                                           \" does not match the file hash specified \" + fileHash);\n+            }\n+        }\n+\n+        string FindOctoDiffExecutable()\n+        {\n+            var basePath = Path.GetDirectoryName(GetType().Assembly.FullLocalPath());\n+            var exePath = Path.Combine(basePath, \"Octodiff.exe\");\n+            if (!File.Exists(exePath))\n+                throw new CommandException(\"Unable to find Octodiff.exe in \" + basePath);\n+            return exePath;\n+        }\n+\n+        string FormatCommandArguments(string basisFilePath, string deltaFilePath, string newFilePath)","path":"source/Calamari/Commands/ApplyDeltaCommand.cs","position":117,"original_position":117,"commit_id":"a792b717304a0fa37f75ab7e976ed0f242e8e4c8","original_commit_id":"a792b717304a0fa37f75ab7e976ed0f242e8e4c8","user":{"login":"mjrichardson","id":113759,"avatar_url":"https://avatars.githubusercontent.com/u/113759?v=3","gravatar_id":"","url":"https://api.github.com/users/mjrichardson","html_url":"https://github.com/mjrichardson","followers_url":"https://api.github.com/users/mjrichardson/followers","following_url":"https://api.github.com/users/mjrichardson/following{/other_user}","gists_url":"https://api.github.com/users/mjrichardson/gists{/gist_id}","starred_url":"https://api.github.com/users/mjrichardson/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mjrichardson/subscriptions","organizations_url":"https://api.github.com/users/mjrichardson/orgs","repos_url":"https://api.github.com/users/mjrichardson/repos","events_url":"https://api.github.com/users/mjrichardson/events{/privacy}","received_events_url":"https://api.github.com/users/mjrichardson/received_events","type":"User","site_admin":false},"body":"This method isn't used.\r\nGiven that, are the skip-verification and progress options may no longer be required either?","created_at":"2015-04-17T03:46:00Z","updated_at":"2015-04-17T03:46:00Z","html_url":"https://github.com/OctopusDeploy/Calamari/pull/11#discussion_r28568321","pull_request_url":"https://api.github.com/repos/OctopusDeploy/Calamari/pulls/11","_links":{"self":{"href":"https://api.github.com/repos/OctopusDeploy/Calamari/pulls/comments/28568321"},"html":{"href":"https://github.com/OctopusDeploy/Calamari/pull/11#discussion_r28568321"},"pull_request":{"href":"https://api.github.com/repos/OctopusDeploy/Calamari/pulls/11"}}},"pull_request":{"url":"https://api.github.com/repos/OctopusDeploy/Calamari/pulls/11","id":32223454,"html_url":"https://github.com/OctopusDeploy/Calamari/pull/11","diff_url":"https://github.com/OctopusDeploy/Calamari/pull/11.diff","patch_url":"https://github.com/OctopusDeploy/Calamari/pull/11.patch","issue_url":"https://api.github.com/repos/OctopusDeploy/Calamari/issues/11","number":11,"state":"open","locked":false,"title":"Delta compression","user":{"login":"alfhenrik","id":1035315,"avatar_url":"https://avatars.githubusercontent.com/u/1035315?v=3","gravatar_id":"","url":"https://api.github.com/users/alfhenrik","html_url":"https://github.com/alfhenrik","followers_url":"https://api.github.com/users/alfhenrik/followers","following_url":"https://api.github.com/users/alfhenrik/following{/other_user}","gists_url":"https://api.github.com/users/alfhenrik/gists{/gist_id}","starred_url":"https://api.github.com/users/alfhenrik/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/alfhenrik/subscriptions","organizations_url":"https://api.github.com/users/alfhenrik/orgs","repos_url":"https://api.github.com/users/alfhenrik/repos","events_url":"https://api.github.com/users/alfhenrik/events{/privacy}","received_events_url":"https://api.github.com/users/alfhenrik/received_events","type":"User","site_admin":false},"body":"- [x] Find package\r\n- [x] Find nearest packages\r\n- [x] Apply delta file to existing package\r\n- [x] Add tests\r\n - [x] Add test for applying delta\r\n- [x] Rebase `master` on top of this PR\r\n- [x] Locking so that we don't apply same delta multiple times ~~(or upload the resulting package)~~\r\n\r\n\r\nThis goes :couple: with OctopusDeploy/OctopusDeploy#183","created_at":"2015-03-30T12:56:32Z","updated_at":"2015-04-17T03:46:00Z","closed_at":null,"merged_at":null,"merge_commit_sha":"6d5930d17af06a173addcd3bd6d8d815fd5b257d","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/OctopusDeploy/Calamari/pulls/11/commits","review_comments_url":"https://api.github.com/repos/OctopusDeploy/Calamari/pulls/11/comments","review_comment_url":"https://api.github.com/repos/OctopusDeploy/Calamari/pulls/comments{/number}","comments_url":"https://api.github.com/repos/OctopusDeploy/Calamari/issues/11/comments","statuses_url":"https://api.github.com/repos/OctopusDeploy/Calamari/statuses/a792b717304a0fa37f75ab7e976ed0f242e8e4c8","head":{"label":"OctopusDeploy:feature-deltacompression","ref":"feature-deltacompression","sha":"a792b717304a0fa37f75ab7e976ed0f242e8e4c8","user":{"login":"OctopusDeploy","id":1287123,"avatar_url":"https://avatars.githubusercontent.com/u/1287123?v=3","gravatar_id":"","url":"https://api.github.com/users/OctopusDeploy","html_url":"https://github.com/OctopusDeploy","followers_url":"https://api.github.com/users/OctopusDeploy/followers","following_url":"https://api.github.com/users/OctopusDeploy/following{/other_user}","gists_url":"https://api.github.com/users/OctopusDeploy/gists{/gist_id}","starred_url":"https://api.github.com/users/OctopusDeploy/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/OctopusDeploy/subscriptions","organizations_url":"https://api.github.com/users/OctopusDeploy/orgs","repos_url":"https://api.github.com/users/OctopusDeploy/repos","events_url":"https://api.github.com/users/OctopusDeploy/events{/privacy}","received_events_url":"https://api.github.com/users/OctopusDeploy/received_events","type":"Organization","site_admin":false},"repo":{"id":31401355,"name":"Calamari","full_name":"OctopusDeploy/Calamari","owner":{"login":"OctopusDeploy","id":1287123,"avatar_url":"https://avatars.githubusercontent.com/u/1287123?v=3","gravatar_id":"","url":"https://api.github.com/users/OctopusDeploy","html_url":"https://github.com/OctopusDeploy","followers_url":"https://api.github.com/users/OctopusDeploy/followers","following_url":"https://api.github.com/users/OctopusDeploy/following{/other_user}","gists_url":"https://api.github.com/users/OctopusDeploy/gists{/gist_id}","starred_url":"https://api.github.com/users/OctopusDeploy/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/OctopusDeploy/subscriptions","organizations_url":"https://api.github.com/users/OctopusDeploy/orgs","repos_url":"https://api.github.com/users/OctopusDeploy/repos","events_url":"https://api.github.com/users/OctopusDeploy/events{/privacy}","received_events_url":"https://api.github.com/users/OctopusDeploy/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/OctopusDeploy/Calamari","description":"The core deployment scripts and tools used by Octopus Deploy","fork":false,"url":"https://api.github.com/repos/OctopusDeploy/Calamari","forks_url":"https://api.github.com/repos/OctopusDeploy/Calamari/forks","keys_url":"https://api.github.com/repos/OctopusDeploy/Calamari/keys{/key_id}","collaborators_url":"https://api.github.com/repos/OctopusDeploy/Calamari/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/OctopusDeploy/Calamari/teams","hooks_url":"https://api.github.com/repos/OctopusDeploy/Calamari/hooks","issue_events_url":"https://api.github.com/repos/OctopusDeploy/Calamari/issues/events{/number}","events_url":"https://api.github.com/repos/OctopusDeploy/Calamari/events","assignees_url":"https://api.github.com/repos/OctopusDeploy/Calamari/assignees{/user}","branches_url":"https://api.github.com/repos/OctopusDeploy/Calamari/branches{/branch}","tags_url":"https://api.github.com/repos/OctopusDeploy/Calamari/tags","blobs_url":"https://api.github.com/repos/OctopusDeploy/Calamari/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/OctopusDeploy/Calamari/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/OctopusDeploy/Calamari/git/refs{/sha}","trees_url":"https://api.github.com/repos/OctopusDeploy/Calamari/git/trees{/sha}","statuses_url":"https://api.github.com/repos/OctopusDeploy/Calamari/statuses/{sha}","languages_url":"https://api.github.com/repos/OctopusDeploy/Calamari/languages","stargazers_url":"https://api.github.com/repos/OctopusDeploy/Calamari/stargazers","contributors_url":"https://api.github.com/repos/OctopusDeploy/Calamari/contributors","subscribers_url":"https://api.github.com/repos/OctopusDeploy/Calamari/subscribers","subscription_url":"https://api.github.com/repos/OctopusDeploy/Calamari/subscription","commits_url":"https://api.github.com/repos/OctopusDeploy/Calamari/commits{/sha}","git_commits_url":"https://api.github.com/repos/OctopusDeploy/Calamari/git/commits{/sha}","comments_url":"https://api.github.com/repos/OctopusDeploy/Calamari/comments{/number}","issue_comment_url":"https://api.github.com/repos/OctopusDeploy/Calamari/issues/comments{/number}","contents_url":"https://api.github.com/repos/OctopusDeploy/Calamari/contents/{+path}","compare_url":"https://api.github.com/repos/OctopusDeploy/Calamari/compare/{base}...{head}","merges_url":"https://api.github.com/repos/OctopusDeploy/Calamari/merges","archive_url":"https://api.github.com/repos/OctopusDeploy/Calamari/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/OctopusDeploy/Calamari/downloads","issues_url":"https://api.github.com/repos/OctopusDeploy/Calamari/issues{/number}","pulls_url":"https://api.github.com/repos/OctopusDeploy/Calamari/pulls{/number}","milestones_url":"https://api.github.com/repos/OctopusDeploy/Calamari/milestones{/number}","notifications_url":"https://api.github.com/repos/OctopusDeploy/Calamari/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/OctopusDeploy/Calamari/labels{/name}","releases_url":"https://api.github.com/repos/OctopusDeploy/Calamari/releases{/id}","created_at":"2015-02-27T03:16:02Z","updated_at":"2015-04-16T15:26:09Z","pushed_at":"2015-04-15T02:05:10Z","git_url":"git://github.com/OctopusDeploy/Calamari.git","ssh_url":"git@github.com:OctopusDeploy/Calamari.git","clone_url":"https://github.com/OctopusDeploy/Calamari.git","svn_url":"https://github.com/OctopusDeploy/Calamari","homepage":null,"size":1360,"stargazers_count":19,"watchers_count":19,"language":"C#","has_issues":false,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":2,"mirror_url":null,"open_issues_count":1,"forks":2,"open_issues":1,"watchers":19,"default_branch":"master"}},"base":{"label":"OctopusDeploy:master","ref":"master","sha":"7ab78931c1346759ce9b99f4c6c6c877a8547821","user":{"login":"OctopusDeploy","id":1287123,"avatar_url":"https://avatars.githubusercontent.com/u/1287123?v=3","gravatar_id":"","url":"https://api.github.com/users/OctopusDeploy","html_url":"https://github.com/OctopusDeploy","followers_url":"https://api.github.com/users/OctopusDeploy/followers","following_url":"https://api.github.com/users/OctopusDeploy/following{/other_user}","gists_url":"https://api.github.com/users/OctopusDeploy/gists{/gist_id}","starred_url":"https://api.github.com/users/OctopusDeploy/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/OctopusDeploy/subscriptions","organizations_url":"https://api.github.com/users/OctopusDeploy/orgs","repos_url":"https://api.github.com/users/OctopusDeploy/repos","events_url":"https://api.github.com/users/OctopusDeploy/events{/privacy}","received_events_url":"https://api.github.com/users/OctopusDeploy/received_events","type":"Organization","site_admin":false},"repo":{"id":31401355,"name":"Calamari","full_name":"OctopusDeploy/Calamari","owner":{"login":"OctopusDeploy","id":1287123,"avatar_url":"https://avatars.githubusercontent.com/u/1287123?v=3","gravatar_id":"","url":"https://api.github.com/users/OctopusDeploy","html_url":"https://github.com/OctopusDeploy","followers_url":"https://api.github.com/users/OctopusDeploy/followers","following_url":"https://api.github.com/users/OctopusDeploy/following{/other_user}","gists_url":"https://api.github.com/users/OctopusDeploy/gists{/gist_id}","starred_url":"https://api.github.com/users/OctopusDeploy/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/OctopusDeploy/subscriptions","organizations_url":"https://api.github.com/users/OctopusDeploy/orgs","repos_url":"https://api.github.com/users/OctopusDeploy/repos","events_url":"https://api.github.com/users/OctopusDeploy/events{/privacy}","received_events_url":"https://api.github.com/users/OctopusDeploy/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/OctopusDeploy/Calamari","description":"The core deployment scripts and tools used by Octopus Deploy","fork":false,"url":"https://api.github.com/repos/OctopusDeploy/Calamari","forks_url":"https://api.github.com/repos/OctopusDeploy/Calamari/forks","keys_url":"https://api.github.com/repos/OctopusDeploy/Calamari/keys{/key_id}","collaborators_url":"https://api.github.com/repos/OctopusDeploy/Calamari/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/OctopusDeploy/Calamari/teams","hooks_url":"https://api.github.com/repos/OctopusDeploy/Calamari/hooks","issue_events_url":"https://api.github.com/repos/OctopusDeploy/Calamari/issues/events{/number}","events_url":"https://api.github.com/repos/OctopusDeploy/Calamari/events","assignees_url":"https://api.github.com/repos/OctopusDeploy/Calamari/assignees{/user}","branches_url":"https://api.github.com/repos/OctopusDeploy/Calamari/branches{/branch}","tags_url":"https://api.github.com/repos/OctopusDeploy/Calamari/tags","blobs_url":"https://api.github.com/repos/OctopusDeploy/Calamari/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/OctopusDeploy/Calamari/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/OctopusDeploy/Calamari/git/refs{/sha}","trees_url":"https://api.github.com/repos/OctopusDeploy/Calamari/git/trees{/sha}","statuses_url":"https://api.github.com/repos/OctopusDeploy/Calamari/statuses/{sha}","languages_url":"https://api.github.com/repos/OctopusDeploy/Calamari/languages","stargazers_url":"https://api.github.com/repos/OctopusDeploy/Calamari/stargazers","contributors_url":"https://api.github.com/repos/OctopusDeploy/Calamari/contributors","subscribers_url":"https://api.github.com/repos/OctopusDeploy/Calamari/subscribers","subscription_url":"https://api.github.com/repos/OctopusDeploy/Calamari/subscription","commits_url":"https://api.github.com/repos/OctopusDeploy/Calamari/commits{/sha}","git_commits_url":"https://api.github.com/repos/OctopusDeploy/Calamari/git/commits{/sha}","comments_url":"https://api.github.com/repos/OctopusDeploy/Calamari/comments{/number}","issue_comment_url":"https://api.github.com/repos/OctopusDeploy/Calamari/issues/comments{/number}","contents_url":"https://api.github.com/repos/OctopusDeploy/Calamari/contents/{+path}","compare_url":"https://api.github.com/repos/OctopusDeploy/Calamari/compare/{base}...{head}","merges_url":"https://api.github.com/repos/OctopusDeploy/Calamari/merges","archive_url":"https://api.github.com/repos/OctopusDeploy/Calamari/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/OctopusDeploy/Calamari/downloads","issues_url":"https://api.github.com/repos/OctopusDeploy/Calamari/issues{/number}","pulls_url":"https://api.github.com/repos/OctopusDeploy/Calamari/pulls{/number}","milestones_url":"https://api.github.com/repos/OctopusDeploy/Calamari/milestones{/number}","notifications_url":"https://api.github.com/repos/OctopusDeploy/Calamari/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/OctopusDeploy/Calamari/labels{/name}","releases_url":"https://api.github.com/repos/OctopusDeploy/Calamari/releases{/id}","created_at":"2015-02-27T03:16:02Z","updated_at":"2015-04-16T15:26:09Z","pushed_at":"2015-04-15T02:05:10Z","git_url":"git://github.com/OctopusDeploy/Calamari.git","ssh_url":"git@github.com:OctopusDeploy/Calamari.git","clone_url":"https://github.com/OctopusDeploy/Calamari.git","svn_url":"https://github.com/OctopusDeploy/Calamari","homepage":null,"size":1360,"stargazers_count":19,"watchers_count":19,"language":"C#","has_issues":false,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":2,"mirror_url":null,"open_issues_count":1,"forks":2,"open_issues":1,"watchers":19,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/OctopusDeploy/Calamari/pulls/11"},"html":{"href":"https://github.com/OctopusDeploy/Calamari/pull/11"},"issue":{"href":"https://api.github.com/repos/OctopusDeploy/Calamari/issues/11"},"comments":{"href":"https://api.github.com/repos/OctopusDeploy/Calamari/issues/11/comments"},"review_comments":{"href":"https://api.github.com/repos/OctopusDeploy/Calamari/pulls/11/comments"},"review_comment":{"href":"https://api.github.com/repos/OctopusDeploy/Calamari/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/OctopusDeploy/Calamari/pulls/11/commits"},"statuses":{"href":"https://api.github.com/repos/OctopusDeploy/Calamari/statuses/a792b717304a0fa37f75ab7e976ed0f242e8e4c8"}}}}