{"action":"created","comment":{"url":"https://api.github.com/repos/coreos/ignition/pulls/comments/73960170","id":73960170,"diff_hunk":"@@ -0,0 +1,174 @@\n+// Copyright 2015 CoreOS, Inc.\n+//\n+// Licensed under the Apache License, Version 2.0 (the \"License\");\n+// you may not use this file except in compliance with the License.\n+// You may obtain a copy of the License at\n+//\n+//     http://www.apache.org/licenses/LICENSE-2.0\n+//\n+// Unless required by applicable law or agreed to in writing, software\n+// distributed under the License is distributed on an \"AS IS\" BASIS,\n+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n+// See the License for the specific language governing permissions and\n+// limitations under the License.\n+\n+package validate\n+\n+import (\n+\t\"fmt\"\n+\t\"io\"\n+\t\"reflect\"\n+\t\"strings\"\n+\n+\tjson \"github.com/ajeddeloh/go-json\"\n+\t\"github.com/coreos/ignition/config/types\"\n+\t\"github.com/coreos/ignition/config/validate/report\"\n+\t\"go4.org/errorutil\"\n+)\n+\n+type canValidate interface {\n+\tAssertValid() error\n+}\n+\n+func canCallAssertValid(v reflect.Value) (canValidate, bool) {\n+\tval, ok := v.Interface().(canValidate)\n+\tif v.Kind() != reflect.Ptr {\n+\t\treturn val, ok\n+\t}\n+\tif v.IsNil() {\n+\t\treturn nil, false\n+\t}\n+\t// If the pointee can be called, don't call it on the pointer, otherwise it'll get called twice\n+\t// due to Go automatically deferencing pointers\n+\tif _, ok := v.Elem().Interface().(canValidate); ok {\n+\t\treturn nil, false\n+\t}\n+\treturn val, ok\n+}\n+\n+// wrapper for errorutil that handles invalid offsets sanely and resets the reader afterwards\n+func posFromOffset(offset int, source io.ReadSeeker) (int, int, string) {\n+\tif offset == -1 || source == nil {\n+\t\treturn 0, 0, \"\"\n+\t}\n+\tline, col, highlight := errorutil.HighlightBytePosition(source, int64(offset))\n+\tsource.Seek(0, 0) // Reset the reader to the start so the next call isn't relative to this position\n+\treturn line, col, highlight\n+}\n+\n+func Validate(cfg types.Config, ast json.Node, source io.ReadSeeker) report.Report {\n+\tv := reflect.ValueOf(cfg)\n+\treport := validate(v, ast, source)\n+\treturn report\n+}\n+\n+// Validate walks down a struct tree calling AssertValid on every node that implements it, building\n+// A report of all the errors, warnings, info, and deprecations it encounters\n+func validate(vObj reflect.Value, ast json.Node, source io.ReadSeeker) (r report.Report) {\n+\tif !vObj.IsValid() {\n+\t\treturn\n+\t}\n+\n+\toff := ast.End\n+\n+\tif obj, ok := canCallAssertValid(vObj); ok {\n+\t\tif err := obj.AssertValid(); err != nil {\n+\t\t\tline, col, highlight := posFromOffset(off, source)\n+\t\t\tr.Add(report.Entry{\n+\t\t\t\tKind:      report.EntryError,\n+\t\t\t\tMessage:   err.Error(),\n+\t\t\t\tLine:      line,\n+\t\t\t\tColumn:    col,\n+\t\t\t\tHighlight: highlight,\n+\t\t\t})\n+\t\t\treturn //dont recurse on invalid inner nodes, it mostly leads to bogus messages\n+\t\t}\n+\t}\n+\n+\tswitch vObj.Kind() {\n+\tcase reflect.Ptr:\n+\t\tsub_report := validate(vObj.Elem(), ast, source)\n+\t\tsub_report.AddLines(off)\n+\t\tr.Merge(sub_report)\n+\tcase reflect.Struct:\n+\t\tsub_report := validateStruct(vObj, ast, source)\n+\t\tsub_report.AddLines(off)\n+\t\tr.Merge(sub_report)\n+\tcase reflect.Slice:\n+\t\tfor i := 0; i < vObj.Len(); i++ {\n+\t\t\tsub_node := ast\n+\t\t\tif val, ok := ast.Value.([]json.Node); ok {\n+\t\t\t\tsub_node = val[i]\n+\t\t\t}\n+\t\t\tsub_report := validate(vObj.Index(i), sub_node, source)\n+\t\t\tsub_report.AddLines(off)\n+\t\t\tr.Merge(sub_report)\n+\t\t}\n+\t}\n+\treturn\n+}\n+\n+func ValidateWithoutSource(cfg types.Config) (report report.Report) {\n+\treturn Validate(cfg, json.Node{}, nil)\n+}\n+\n+func validateStruct(vObj reflect.Value, ast json.Node, source io.ReadSeeker) report.Report {\n+\toff := ast.Start\n+\tr := report.Report{}\n+\tkeys, ok := ast.Value.(map[string]json.Node)\n+\tusedKeys := map[string]bool{} // Maintain a set of key's that have been used\n+\ttags := []string{}            // Maintain a list of all the tags in the struct for fuzzy matching later\n+\n+\tfor i := 0; i < vObj.Type().NumField(); i++ {\n+\t\t// Default to deepest node if the node's type isn't an object,\n+\t\t// such as when a json string actually unmarshal to structs (like with version)\n+\t\tsub_node := ast\n+\t\ttag := strings.Split(vObj.Type().Field(i).Tag.Get(\"json\"), \",\")[0]\n+\t\ttags = append(tags, tag) //build list of json key names\n+\t\tif ok {\n+\t\t\tsub_node = keys[tag]\n+\t\t\tusedKeys[tag] = true\n+\t\t}\n+\n+\t\tsub_report := validate(vObj.Field(i), sub_node, source)\n+\t\tsub_report.AddLines(off)\n+\t\tr.Merge(sub_report)\n+\t}\n+\tif !ok {","path":"config/validate/validate.go","position":138,"original_position":137,"commit_id":"e5a5bcba82d052c2c005e5c4507964e177407d89","original_commit_id":"0b5aa6bd08ea56b960c183a80468c4d72f3ccfd9","user":{"login":"crawford","id":368848,"avatar_url":"https://avatars.githubusercontent.com/u/368848?v=3","gravatar_id":"","url":"https://api.github.com/users/crawford","html_url":"https://github.com/crawford","followers_url":"https://api.github.com/users/crawford/followers","following_url":"https://api.github.com/users/crawford/following{/other_user}","gists_url":"https://api.github.com/users/crawford/gists{/gist_id}","starred_url":"https://api.github.com/users/crawford/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/crawford/subscriptions","organizations_url":"https://api.github.com/users/crawford/orgs","repos_url":"https://api.github.com/users/crawford/repos","events_url":"https://api.github.com/users/crawford/events{/privacy}","received_events_url":"https://api.github.com/users/crawford/received_events","type":"User","site_admin":false},"body":"Why is this checked all the way down here?","created_at":"2016-08-08T21:37:53Z","updated_at":"2016-08-08T21:37:53Z","html_url":"https://github.com/coreos/ignition/pull/260#discussion_r73960170","pull_request_url":"https://api.github.com/repos/coreos/ignition/pulls/260","_links":{"self":{"href":"https://api.github.com/repos/coreos/ignition/pulls/comments/73960170"},"html":{"href":"https://github.com/coreos/ignition/pull/260#discussion_r73960170"},"pull_request":{"href":"https://api.github.com/repos/coreos/ignition/pulls/260"}}},"pull_request":{"url":"https://api.github.com/repos/coreos/ignition/pulls/260","id":78772293,"html_url":"https://github.com/coreos/ignition/pull/260","diff_url":"https://github.com/coreos/ignition/pull/260.diff","patch_url":"https://github.com/coreos/ignition/pull/260.patch","issue_url":"https://api.github.com/repos/coreos/ignition/issues/260","number":260,"state":"open","locked":false,"title":"Improve validation","user":{"login":"ajeddeloh","id":2753421,"avatar_url":"https://avatars.githubusercontent.com/u/2753421?v=3","gravatar_id":"","url":"https://api.github.com/users/ajeddeloh","html_url":"https://github.com/ajeddeloh","followers_url":"https://api.github.com/users/ajeddeloh/followers","following_url":"https://api.github.com/users/ajeddeloh/following{/other_user}","gists_url":"https://api.github.com/users/ajeddeloh/gists{/gist_id}","starred_url":"https://api.github.com/users/ajeddeloh/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ajeddeloh/subscriptions","organizations_url":"https://api.github.com/users/ajeddeloh/orgs","repos_url":"https://api.github.com/users/ajeddeloh/repos","events_url":"https://api.github.com/users/ajeddeloh/events{/privacy}","received_events_url":"https://api.github.com/users/ajeddeloh/received_events","type":"User","site_admin":false},"body":"WIP. Currently requires modified encoding/json, see https://github.com/golang/go/issues/16433#issuecomment-234498412.\r\n\r\nAdd support for multiple errors, warnings, info, deprecations.","created_at":"2016-07-26T00:03:33Z","updated_at":"2016-08-08T21:37:53Z","closed_at":null,"merged_at":null,"merge_commit_sha":"b4adcd5de0da8d6a2eecb8288e07f431a24daba0","assignee":null,"assignees":[],"milestone":null,"commits_url":"https://api.github.com/repos/coreos/ignition/pulls/260/commits","review_comments_url":"https://api.github.com/repos/coreos/ignition/pulls/260/comments","review_comment_url":"https://api.github.com/repos/coreos/ignition/pulls/comments{/number}","comments_url":"https://api.github.com/repos/coreos/ignition/issues/260/comments","statuses_url":"https://api.github.com/repos/coreos/ignition/statuses/e5a5bcba82d052c2c005e5c4507964e177407d89","head":{"label":"ajeddeloh:validation","ref":"validation","sha":"e5a5bcba82d052c2c005e5c4507964e177407d89","user":{"login":"ajeddeloh","id":2753421,"avatar_url":"https://avatars.githubusercontent.com/u/2753421?v=3","gravatar_id":"","url":"https://api.github.com/users/ajeddeloh","html_url":"https://github.com/ajeddeloh","followers_url":"https://api.github.com/users/ajeddeloh/followers","following_url":"https://api.github.com/users/ajeddeloh/following{/other_user}","gists_url":"https://api.github.com/users/ajeddeloh/gists{/gist_id}","starred_url":"https://api.github.com/users/ajeddeloh/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ajeddeloh/subscriptions","organizations_url":"https://api.github.com/users/ajeddeloh/orgs","repos_url":"https://api.github.com/users/ajeddeloh/repos","events_url":"https://api.github.com/users/ajeddeloh/events{/privacy}","received_events_url":"https://api.github.com/users/ajeddeloh/received_events","type":"User","site_admin":false},"repo":{"id":59787248,"name":"ignition","full_name":"ajeddeloh/ignition","owner":{"login":"ajeddeloh","id":2753421,"avatar_url":"https://avatars.githubusercontent.com/u/2753421?v=3","gravatar_id":"","url":"https://api.github.com/users/ajeddeloh","html_url":"https://github.com/ajeddeloh","followers_url":"https://api.github.com/users/ajeddeloh/followers","following_url":"https://api.github.com/users/ajeddeloh/following{/other_user}","gists_url":"https://api.github.com/users/ajeddeloh/gists{/gist_id}","starred_url":"https://api.github.com/users/ajeddeloh/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ajeddeloh/subscriptions","organizations_url":"https://api.github.com/users/ajeddeloh/orgs","repos_url":"https://api.github.com/users/ajeddeloh/repos","events_url":"https://api.github.com/users/ajeddeloh/events{/privacy}","received_events_url":"https://api.github.com/users/ajeddeloh/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/ajeddeloh/ignition","description":"CoreOS first-boot installer and configuration tool","fork":true,"url":"https://api.github.com/repos/ajeddeloh/ignition","forks_url":"https://api.github.com/repos/ajeddeloh/ignition/forks","keys_url":"https://api.github.com/repos/ajeddeloh/ignition/keys{/key_id}","collaborators_url":"https://api.github.com/repos/ajeddeloh/ignition/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/ajeddeloh/ignition/teams","hooks_url":"https://api.github.com/repos/ajeddeloh/ignition/hooks","issue_events_url":"https://api.github.com/repos/ajeddeloh/ignition/issues/events{/number}","events_url":"https://api.github.com/repos/ajeddeloh/ignition/events","assignees_url":"https://api.github.com/repos/ajeddeloh/ignition/assignees{/user}","branches_url":"https://api.github.com/repos/ajeddeloh/ignition/branches{/branch}","tags_url":"https://api.github.com/repos/ajeddeloh/ignition/tags","blobs_url":"https://api.github.com/repos/ajeddeloh/ignition/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/ajeddeloh/ignition/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/ajeddeloh/ignition/git/refs{/sha}","trees_url":"https://api.github.com/repos/ajeddeloh/ignition/git/trees{/sha}","statuses_url":"https://api.github.com/repos/ajeddeloh/ignition/statuses/{sha}","languages_url":"https://api.github.com/repos/ajeddeloh/ignition/languages","stargazers_url":"https://api.github.com/repos/ajeddeloh/ignition/stargazers","contributors_url":"https://api.github.com/repos/ajeddeloh/ignition/contributors","subscribers_url":"https://api.github.com/repos/ajeddeloh/ignition/subscribers","subscription_url":"https://api.github.com/repos/ajeddeloh/ignition/subscription","commits_url":"https://api.github.com/repos/ajeddeloh/ignition/commits{/sha}","git_commits_url":"https://api.github.com/repos/ajeddeloh/ignition/git/commits{/sha}","comments_url":"https://api.github.com/repos/ajeddeloh/ignition/comments{/number}","issue_comment_url":"https://api.github.com/repos/ajeddeloh/ignition/issues/comments{/number}","contents_url":"https://api.github.com/repos/ajeddeloh/ignition/contents/{+path}","compare_url":"https://api.github.com/repos/ajeddeloh/ignition/compare/{base}...{head}","merges_url":"https://api.github.com/repos/ajeddeloh/ignition/merges","archive_url":"https://api.github.com/repos/ajeddeloh/ignition/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/ajeddeloh/ignition/downloads","issues_url":"https://api.github.com/repos/ajeddeloh/ignition/issues{/number}","pulls_url":"https://api.github.com/repos/ajeddeloh/ignition/pulls{/number}","milestones_url":"https://api.github.com/repos/ajeddeloh/ignition/milestones{/number}","notifications_url":"https://api.github.com/repos/ajeddeloh/ignition/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/ajeddeloh/ignition/labels{/name}","releases_url":"https://api.github.com/repos/ajeddeloh/ignition/releases{/id}","deployments_url":"https://api.github.com/repos/ajeddeloh/ignition/deployments","created_at":"2016-05-26T22:29:28Z","updated_at":"2016-05-26T22:29:29Z","pushed_at":"2016-08-08T21:03:21Z","git_url":"git://github.com/ajeddeloh/ignition.git","ssh_url":"git@github.com:ajeddeloh/ignition.git","clone_url":"https://github.com/ajeddeloh/ignition.git","svn_url":"https://github.com/ajeddeloh/ignition","homepage":"https://coreos.com/ignition","size":1075,"stargazers_count":0,"watchers_count":0,"language":"Go","has_issues":false,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"coreos:master","ref":"master","sha":"f48954dd7eb600152cf966438fe0351ed1e449d3","user":{"login":"coreos","id":3730757,"avatar_url":"https://avatars.githubusercontent.com/u/3730757?v=3","gravatar_id":"","url":"https://api.github.com/users/coreos","html_url":"https://github.com/coreos","followers_url":"https://api.github.com/users/coreos/followers","following_url":"https://api.github.com/users/coreos/following{/other_user}","gists_url":"https://api.github.com/users/coreos/gists{/gist_id}","starred_url":"https://api.github.com/users/coreos/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/coreos/subscriptions","organizations_url":"https://api.github.com/users/coreos/orgs","repos_url":"https://api.github.com/users/coreos/repos","events_url":"https://api.github.com/users/coreos/events{/privacy}","received_events_url":"https://api.github.com/users/coreos/received_events","type":"Organization","site_admin":false},"repo":{"id":33020174,"name":"ignition","full_name":"coreos/ignition","owner":{"login":"coreos","id":3730757,"avatar_url":"https://avatars.githubusercontent.com/u/3730757?v=3","gravatar_id":"","url":"https://api.github.com/users/coreos","html_url":"https://github.com/coreos","followers_url":"https://api.github.com/users/coreos/followers","following_url":"https://api.github.com/users/coreos/following{/other_user}","gists_url":"https://api.github.com/users/coreos/gists{/gist_id}","starred_url":"https://api.github.com/users/coreos/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/coreos/subscriptions","organizations_url":"https://api.github.com/users/coreos/orgs","repos_url":"https://api.github.com/users/coreos/repos","events_url":"https://api.github.com/users/coreos/events{/privacy}","received_events_url":"https://api.github.com/users/coreos/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/coreos/ignition","description":"CoreOS first-boot installer and configuration tool","fork":false,"url":"https://api.github.com/repos/coreos/ignition","forks_url":"https://api.github.com/repos/coreos/ignition/forks","keys_url":"https://api.github.com/repos/coreos/ignition/keys{/key_id}","collaborators_url":"https://api.github.com/repos/coreos/ignition/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/coreos/ignition/teams","hooks_url":"https://api.github.com/repos/coreos/ignition/hooks","issue_events_url":"https://api.github.com/repos/coreos/ignition/issues/events{/number}","events_url":"https://api.github.com/repos/coreos/ignition/events","assignees_url":"https://api.github.com/repos/coreos/ignition/assignees{/user}","branches_url":"https://api.github.com/repos/coreos/ignition/branches{/branch}","tags_url":"https://api.github.com/repos/coreos/ignition/tags","blobs_url":"https://api.github.com/repos/coreos/ignition/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/coreos/ignition/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/coreos/ignition/git/refs{/sha}","trees_url":"https://api.github.com/repos/coreos/ignition/git/trees{/sha}","statuses_url":"https://api.github.com/repos/coreos/ignition/statuses/{sha}","languages_url":"https://api.github.com/repos/coreos/ignition/languages","stargazers_url":"https://api.github.com/repos/coreos/ignition/stargazers","contributors_url":"https://api.github.com/repos/coreos/ignition/contributors","subscribers_url":"https://api.github.com/repos/coreos/ignition/subscribers","subscription_url":"https://api.github.com/repos/coreos/ignition/subscription","commits_url":"https://api.github.com/repos/coreos/ignition/commits{/sha}","git_commits_url":"https://api.github.com/repos/coreos/ignition/git/commits{/sha}","comments_url":"https://api.github.com/repos/coreos/ignition/comments{/number}","issue_comment_url":"https://api.github.com/repos/coreos/ignition/issues/comments{/number}","contents_url":"https://api.github.com/repos/coreos/ignition/contents/{+path}","compare_url":"https://api.github.com/repos/coreos/ignition/compare/{base}...{head}","merges_url":"https://api.github.com/repos/coreos/ignition/merges","archive_url":"https://api.github.com/repos/coreos/ignition/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/coreos/ignition/downloads","issues_url":"https://api.github.com/repos/coreos/ignition/issues{/number}","pulls_url":"https://api.github.com/repos/coreos/ignition/pulls{/number}","milestones_url":"https://api.github.com/repos/coreos/ignition/milestones{/number}","notifications_url":"https://api.github.com/repos/coreos/ignition/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/coreos/ignition/labels{/name}","releases_url":"https://api.github.com/repos/coreos/ignition/releases{/id}","deployments_url":"https://api.github.com/repos/coreos/ignition/deployments","created_at":"2015-03-28T03:52:33Z","updated_at":"2016-08-03T03:04:00Z","pushed_at":"2016-08-08T21:03:21Z","git_url":"git://github.com/coreos/ignition.git","ssh_url":"git@github.com:coreos/ignition.git","clone_url":"https://github.com/coreos/ignition.git","svn_url":"https://github.com/coreos/ignition","homepage":"https://coreos.com/ignition","size":1181,"stargazers_count":106,"watchers_count":106,"language":"Go","has_issues":false,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":31,"mirror_url":null,"open_issues_count":2,"forks":31,"open_issues":2,"watchers":106,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/coreos/ignition/pulls/260"},"html":{"href":"https://github.com/coreos/ignition/pull/260"},"issue":{"href":"https://api.github.com/repos/coreos/ignition/issues/260"},"comments":{"href":"https://api.github.com/repos/coreos/ignition/issues/260/comments"},"review_comments":{"href":"https://api.github.com/repos/coreos/ignition/pulls/260/comments"},"review_comment":{"href":"https://api.github.com/repos/coreos/ignition/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/coreos/ignition/pulls/260/commits"},"statuses":{"href":"https://api.github.com/repos/coreos/ignition/statuses/e5a5bcba82d052c2c005e5c4507964e177407d89"}}}}
{"actor":{"display_login":"crawford"}}