{"action":"created","comment":{"url":"https://api.github.com/repos/wagoodman/dive/pulls/comments/223189092","pull_request_review_id":162264887,"id":223189092,"node_id":"MDI0OlB1bGxSZXF1ZXN0UmV2aWV3Q29tbWVudDIyMzE4OTA5Mg==","diff_hunk":"@@ -48,18 +67,78 @@ func NewManifest(reader *tar.Reader, header *tar.Header) ImageManifest {\n \treturn manifest[0]\n }\n \n+func NewImageConfig(reader *tar.Reader, header *tar.Header) ImageConfig {\n+\tsize := header.Size\n+\tconfigBytes := make([]byte, size)\n+\t_, err := reader.Read(configBytes)\n+\tif err != nil && err != io.EOF {\n+\t\tpanic(err)\n+\t}\n+\tvar imageConfig ImageConfig\n+\terr = json.Unmarshal(configBytes, &imageConfig)\n+\tif err != nil {\n+\t\tpanic(err)\n+\t}\n+\n+\tlayerIdx := 0\n+\tfor idx := range imageConfig.History {\n+\t\tif imageConfig.History[idx].EmptyLayer {\n+\t\t\timageConfig.History[idx].ID = \"<missing>\"\n+\t\t} else {\n+\t\t\timageConfig.History[idx].ID = imageConfig.RootFs.DiffIds[layerIdx]\n+\t\t\tlayerIdx++\n+\t\t}\n+\t}\n+\n+\treturn imageConfig\n+}\n+\n+func GetImageConfig(imageTarPath string, manifest ImageManifest) ImageConfig{\n+\tvar config ImageConfig\n+\t// read through the image contents and build a tree\n+\tfmt.Println(\"Fetching image config...\")\n+\ttarFile, err := os.Open(imageTarPath)\n+\tif err != nil {\n+\t\tfmt.Println(err)\n+\t\tos.Exit(1)\n+\t}\n+\tdefer tarFile.Close()","path":"image/image.go","position":67,"original_position":67,"commit_id":"23a20797eab8ffba2614a53752a3b012ad7df06d","original_commit_id":"23a20797eab8ffba2614a53752a3b012ad7df06d","user":{"login":"wagoodman","id":590471,"node_id":"MDQ6VXNlcjU5MDQ3MQ==","avatar_url":"https://avatars3.githubusercontent.com/u/590471?v=4","gravatar_id":"","url":"https://api.github.com/users/wagoodman","html_url":"https://github.com/wagoodman","followers_url":"https://api.github.com/users/wagoodman/followers","following_url":"https://api.github.com/users/wagoodman/following{/other_user}","gists_url":"https://api.github.com/users/wagoodman/gists{/gist_id}","starred_url":"https://api.github.com/users/wagoodman/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/wagoodman/subscriptions","organizations_url":"https://api.github.com/users/wagoodman/orgs","repos_url":"https://api.github.com/users/wagoodman/repos","events_url":"https://api.github.com/users/wagoodman/events{/privacy}","received_events_url":"https://api.github.com/users/wagoodman/received_events","type":"User","site_admin":false},"body":"I'm not certain if there is a case where the file is open before exit is called, however, I still think this is the preferred way to go for a couple reasons:\r\n\r\n1.  os.Exit cleans up file descriptors\r\n2. since we're not guaranteed to have an open file we shouldn't attempt to close it until after we've checked it was opened with no error. ","created_at":"2018-10-06T17:52:46Z","updated_at":"2018-10-06T17:52:46Z","html_url":"https://github.com/wagoodman/dive/pull/17#discussion_r223189092","pull_request_url":"https://api.github.com/repos/wagoodman/dive/pulls/17","author_association":"OWNER","_links":{"self":{"href":"https://api.github.com/repos/wagoodman/dive/pulls/comments/223189092"},"html":{"href":"https://github.com/wagoodman/dive/pull/17#discussion_r223189092"},"pull_request":{"href":"https://api.github.com/repos/wagoodman/dive/pulls/17"}},"in_reply_to_id":223188547},"pull_request":{"url":"https://api.github.com/repos/wagoodman/dive/pulls/17","id":220895513,"node_id":"MDExOlB1bGxSZXF1ZXN0MjIwODk1NTEz","html_url":"https://github.com/wagoodman/dive/pull/17","diff_url":"https://github.com/wagoodman/dive/pull/17.diff","patch_url":"https://github.com/wagoodman/dive/pull/17.patch","issue_url":"https://api.github.com/repos/wagoodman/dive/issues/17","number":17,"state":"open","locked":false,"title":"Reconcile history from image manifest and config","user":{"login":"wagoodman","id":590471,"node_id":"MDQ6VXNlcjU5MDQ3MQ==","avatar_url":"https://avatars3.githubusercontent.com/u/590471?v=4","gravatar_id":"","url":"https://api.github.com/users/wagoodman","html_url":"https://github.com/wagoodman","followers_url":"https://api.github.com/users/wagoodman/followers","following_url":"https://api.github.com/users/wagoodman/following{/other_user}","gists_url":"https://api.github.com/users/wagoodman/gists{/gist_id}","starred_url":"https://api.github.com/users/wagoodman/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/wagoodman/subscriptions","organizations_url":"https://api.github.com/users/wagoodman/orgs","repos_url":"https://api.github.com/users/wagoodman/repos","events_url":"https://api.github.com/users/wagoodman/events{/privacy}","received_events_url":"https://api.github.com/users/wagoodman/received_events","type":"User","site_admin":false},"body":"Pulling history from the docker API doesn't make sense for two reasons:\r\n- the API does not include `empty_content` bool, and inferring this from the `created_by` attribute is not accurate (sometimes a layer with content has a `created_by` attribute that starts with a `nop` statement).\r\n- we already have the necessary information from the image.tar that we've saved\r\n\r\nDownside is that we have to calculate the layer size manually, but since we're already iterating across all contents, I don't see the harm. The upside is that we're not coupling to a docker API type?\r\n\r\nThis will require further cleanup.","created_at":"2018-10-06T16:11:36Z","updated_at":"2018-10-06T17:52:46Z","closed_at":null,"merged_at":null,"merge_commit_sha":"ada276a128c286a03f0c509338180c1e91eb326b","assignee":null,"assignees":[],"requested_reviewers":[],"requested_teams":[],"labels":[],"milestone":null,"commits_url":"https://api.github.com/repos/wagoodman/dive/pulls/17/commits","review_comments_url":"https://api.github.com/repos/wagoodman/dive/pulls/17/comments","review_comment_url":"https://api.github.com/repos/wagoodman/dive/pulls/comments{/number}","comments_url":"https://api.github.com/repos/wagoodman/dive/issues/17/comments","statuses_url":"https://api.github.com/repos/wagoodman/dive/statuses/23a20797eab8ffba2614a53752a3b012ad7df06d","head":{"label":"wagoodman:reconsile-history","ref":"reconsile-history","sha":"23a20797eab8ffba2614a53752a3b012ad7df06d","user":{"login":"wagoodman","id":590471,"node_id":"MDQ6VXNlcjU5MDQ3MQ==","avatar_url":"https://avatars3.githubusercontent.com/u/590471?v=4","gravatar_id":"","url":"https://api.github.com/users/wagoodman","html_url":"https://github.com/wagoodman","followers_url":"https://api.github.com/users/wagoodman/followers","following_url":"https://api.github.com/users/wagoodman/following{/other_user}","gists_url":"https://api.github.com/users/wagoodman/gists{/gist_id}","starred_url":"https://api.github.com/users/wagoodman/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/wagoodman/subscriptions","organizations_url":"https://api.github.com/users/wagoodman/orgs","repos_url":"https://api.github.com/users/wagoodman/repos","events_url":"https://api.github.com/users/wagoodman/events{/privacy}","received_events_url":"https://api.github.com/users/wagoodman/received_events","type":"User","site_admin":false},"repo":{"id":133251103,"node_id":"MDEwOlJlcG9zaXRvcnkxMzMyNTExMDM=","name":"dive","full_name":"wagoodman/dive","private":false,"owner":{"login":"wagoodman","id":590471,"node_id":"MDQ6VXNlcjU5MDQ3MQ==","avatar_url":"https://avatars3.githubusercontent.com/u/590471?v=4","gravatar_id":"","url":"https://api.github.com/users/wagoodman","html_url":"https://github.com/wagoodman","followers_url":"https://api.github.com/users/wagoodman/followers","following_url":"https://api.github.com/users/wagoodman/following{/other_user}","gists_url":"https://api.github.com/users/wagoodman/gists{/gist_id}","starred_url":"https://api.github.com/users/wagoodman/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/wagoodman/subscriptions","organizations_url":"https://api.github.com/users/wagoodman/orgs","repos_url":"https://api.github.com/users/wagoodman/repos","events_url":"https://api.github.com/users/wagoodman/events{/privacy}","received_events_url":"https://api.github.com/users/wagoodman/received_events","type":"User","site_admin":false},"html_url":"https://github.com/wagoodman/dive","description":"A tool for interrogating docker images","fork":false,"url":"https://api.github.com/repos/wagoodman/dive","forks_url":"https://api.github.com/repos/wagoodman/dive/forks","keys_url":"https://api.github.com/repos/wagoodman/dive/keys{/key_id}","collaborators_url":"https://api.github.com/repos/wagoodman/dive/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/wagoodman/dive/teams","hooks_url":"https://api.github.com/repos/wagoodman/dive/hooks","issue_events_url":"https://api.github.com/repos/wagoodman/dive/issues/events{/number}","events_url":"https://api.github.com/repos/wagoodman/dive/events","assignees_url":"https://api.github.com/repos/wagoodman/dive/assignees{/user}","branches_url":"https://api.github.com/repos/wagoodman/dive/branches{/branch}","tags_url":"https://api.github.com/repos/wagoodman/dive/tags","blobs_url":"https://api.github.com/repos/wagoodman/dive/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/wagoodman/dive/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/wagoodman/dive/git/refs{/sha}","trees_url":"https://api.github.com/repos/wagoodman/dive/git/trees{/sha}","statuses_url":"https://api.github.com/repos/wagoodman/dive/statuses/{sha}","languages_url":"https://api.github.com/repos/wagoodman/dive/languages","stargazers_url":"https://api.github.com/repos/wagoodman/dive/stargazers","contributors_url":"https://api.github.com/repos/wagoodman/dive/contributors","subscribers_url":"https://api.github.com/repos/wagoodman/dive/subscribers","subscription_url":"https://api.github.com/repos/wagoodman/dive/subscription","commits_url":"https://api.github.com/repos/wagoodman/dive/commits{/sha}","git_commits_url":"https://api.github.com/repos/wagoodman/dive/git/commits{/sha}","comments_url":"https://api.github.com/repos/wagoodman/dive/comments{/number}","issue_comment_url":"https://api.github.com/repos/wagoodman/dive/issues/comments{/number}","contents_url":"https://api.github.com/repos/wagoodman/dive/contents/{+path}","compare_url":"https://api.github.com/repos/wagoodman/dive/compare/{base}...{head}","merges_url":"https://api.github.com/repos/wagoodman/dive/merges","archive_url":"https://api.github.com/repos/wagoodman/dive/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/wagoodman/dive/downloads","issues_url":"https://api.github.com/repos/wagoodman/dive/issues{/number}","pulls_url":"https://api.github.com/repos/wagoodman/dive/pulls{/number}","milestones_url":"https://api.github.com/repos/wagoodman/dive/milestones{/number}","notifications_url":"https://api.github.com/repos/wagoodman/dive/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/wagoodman/dive/labels{/name}","releases_url":"https://api.github.com/repos/wagoodman/dive/releases{/id}","deployments_url":"https://api.github.com/repos/wagoodman/dive/deployments","created_at":"2018-05-13T15:44:01Z","updated_at":"2018-10-06T13:45:10Z","pushed_at":"2018-10-06T16:24:35Z","git_url":"git://github.com/wagoodman/dive.git","ssh_url":"git@github.com:wagoodman/dive.git","clone_url":"https://github.com/wagoodman/dive.git","svn_url":"https://github.com/wagoodman/dive","homepage":"","size":127,"stargazers_count":0,"watchers_count":0,"language":"Go","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"archived":false,"open_issues_count":3,"license":{"key":"mit","name":"MIT License","spdx_id":"MIT","url":"https://api.github.com/licenses/mit","node_id":"MDc6TGljZW5zZTEz"},"forks":0,"open_issues":3,"watchers":0,"default_branch":"master"}},"base":{"label":"wagoodman:master","ref":"master","sha":"c599ca5ad20bf52b6fde06f9462d8830cab90b7f","user":{"login":"wagoodman","id":590471,"node_id":"MDQ6VXNlcjU5MDQ3MQ==","avatar_url":"https://avatars3.githubusercontent.com/u/590471?v=4","gravatar_id":"","url":"https://api.github.com/users/wagoodman","html_url":"https://github.com/wagoodman","followers_url":"https://api.github.com/users/wagoodman/followers","following_url":"https://api.github.com/users/wagoodman/following{/other_user}","gists_url":"https://api.github.com/users/wagoodman/gists{/gist_id}","starred_url":"https://api.github.com/users/wagoodman/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/wagoodman/subscriptions","organizations_url":"https://api.github.com/users/wagoodman/orgs","repos_url":"https://api.github.com/users/wagoodman/repos","events_url":"https://api.github.com/users/wagoodman/events{/privacy}","received_events_url":"https://api.github.com/users/wagoodman/received_events","type":"User","site_admin":false},"repo":{"id":133251103,"node_id":"MDEwOlJlcG9zaXRvcnkxMzMyNTExMDM=","name":"dive","full_name":"wagoodman/dive","private":false,"owner":{"login":"wagoodman","id":590471,"node_id":"MDQ6VXNlcjU5MDQ3MQ==","avatar_url":"https://avatars3.githubusercontent.com/u/590471?v=4","gravatar_id":"","url":"https://api.github.com/users/wagoodman","html_url":"https://github.com/wagoodman","followers_url":"https://api.github.com/users/wagoodman/followers","following_url":"https://api.github.com/users/wagoodman/following{/other_user}","gists_url":"https://api.github.com/users/wagoodman/gists{/gist_id}","starred_url":"https://api.github.com/users/wagoodman/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/wagoodman/subscriptions","organizations_url":"https://api.github.com/users/wagoodman/orgs","repos_url":"https://api.github.com/users/wagoodman/repos","events_url":"https://api.github.com/users/wagoodman/events{/privacy}","received_events_url":"https://api.github.com/users/wagoodman/received_events","type":"User","site_admin":false},"html_url":"https://github.com/wagoodman/dive","description":"A tool for interrogating docker images","fork":false,"url":"https://api.github.com/repos/wagoodman/dive","forks_url":"https://api.github.com/repos/wagoodman/dive/forks","keys_url":"https://api.github.com/repos/wagoodman/dive/keys{/key_id}","collaborators_url":"https://api.github.com/repos/wagoodman/dive/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/wagoodman/dive/teams","hooks_url":"https://api.github.com/repos/wagoodman/dive/hooks","issue_events_url":"https://api.github.com/repos/wagoodman/dive/issues/events{/number}","events_url":"https://api.github.com/repos/wagoodman/dive/events","assignees_url":"https://api.github.com/repos/wagoodman/dive/assignees{/user}","branches_url":"https://api.github.com/repos/wagoodman/dive/branches{/branch}","tags_url":"https://api.github.com/repos/wagoodman/dive/tags","blobs_url":"https://api.github.com/repos/wagoodman/dive/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/wagoodman/dive/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/wagoodman/dive/git/refs{/sha}","trees_url":"https://api.github.com/repos/wagoodman/dive/git/trees{/sha}","statuses_url":"https://api.github.com/repos/wagoodman/dive/statuses/{sha}","languages_url":"https://api.github.com/repos/wagoodman/dive/languages","stargazers_url":"https://api.github.com/repos/wagoodman/dive/stargazers","contributors_url":"https://api.github.com/repos/wagoodman/dive/contributors","subscribers_url":"https://api.github.com/repos/wagoodman/dive/subscribers","subscription_url":"https://api.github.com/repos/wagoodman/dive/subscription","commits_url":"https://api.github.com/repos/wagoodman/dive/commits{/sha}","git_commits_url":"https://api.github.com/repos/wagoodman/dive/git/commits{/sha}","comments_url":"https://api.github.com/repos/wagoodman/dive/comments{/number}","issue_comment_url":"https://api.github.com/repos/wagoodman/dive/issues/comments{/number}","contents_url":"https://api.github.com/repos/wagoodman/dive/contents/{+path}","compare_url":"https://api.github.com/repos/wagoodman/dive/compare/{base}...{head}","merges_url":"https://api.github.com/repos/wagoodman/dive/merges","archive_url":"https://api.github.com/repos/wagoodman/dive/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/wagoodman/dive/downloads","issues_url":"https://api.github.com/repos/wagoodman/dive/issues{/number}","pulls_url":"https://api.github.com/repos/wagoodman/dive/pulls{/number}","milestones_url":"https://api.github.com/repos/wagoodman/dive/milestones{/number}","notifications_url":"https://api.github.com/repos/wagoodman/dive/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/wagoodman/dive/labels{/name}","releases_url":"https://api.github.com/repos/wagoodman/dive/releases{/id}","deployments_url":"https://api.github.com/repos/wagoodman/dive/deployments","created_at":"2018-05-13T15:44:01Z","updated_at":"2018-10-06T13:45:10Z","pushed_at":"2018-10-06T16:24:35Z","git_url":"git://github.com/wagoodman/dive.git","ssh_url":"git@github.com:wagoodman/dive.git","clone_url":"https://github.com/wagoodman/dive.git","svn_url":"https://github.com/wagoodman/dive","homepage":"","size":127,"stargazers_count":0,"watchers_count":0,"language":"Go","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"archived":false,"open_issues_count":3,"license":{"key":"mit","name":"MIT License","spdx_id":"MIT","url":"https://api.github.com/licenses/mit","node_id":"MDc6TGljZW5zZTEz"},"forks":0,"open_issues":3,"watchers":0,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/wagoodman/dive/pulls/17"},"html":{"href":"https://github.com/wagoodman/dive/pull/17"},"issue":{"href":"https://api.github.com/repos/wagoodman/dive/issues/17"},"comments":{"href":"https://api.github.com/repos/wagoodman/dive/issues/17/comments"},"review_comments":{"href":"https://api.github.com/repos/wagoodman/dive/pulls/17/comments"},"review_comment":{"href":"https://api.github.com/repos/wagoodman/dive/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/wagoodman/dive/pulls/17/commits"},"statuses":{"href":"https://api.github.com/repos/wagoodman/dive/statuses/23a20797eab8ffba2614a53752a3b012ad7df06d"}},"author_association":"OWNER"}}
{"actor":{"display_login":"wagoodman"}}