{"action":"created","comment":{"url":"https://api.github.com/repos/docker/distribution/pulls/comments/46743731","id":46743731,"diff_hunk":"@@ -3,47 +3,123 @@ package reference\n import \"regexp\"\n \n var (\n-\t// nameSubComponentRegexp defines the part of the name which must be\n-\t// begin and end with an alphanumeric character. These characters can\n-\t// be separated by any number of dashes.\n-\tnameSubComponentRegexp = regexp.MustCompile(`[a-z0-9]+(?:[-]+[a-z0-9]+)*`)\n+\t// alphaNumericRegexp defines the alpha numeric atom, typically a\n+\t// component of names. This only allows lower case characters and digits.\n+\talphaNumericRegexp = match(`[a-z0-9]+`)\n \n-\t// nameComponentRegexp restricts registry path component names to\n-\t// start with at least one letter or number, with following parts able to\n-\t// be separated by one period, underscore or double underscore.\n-\tnameComponentRegexp = regexp.MustCompile(nameSubComponentRegexp.String() + `(?:(?:[._]|__)` + nameSubComponentRegexp.String() + `)*`)\n+\t// separatorRegexp defines the separators allowed to be embedded in name\n+\t// components. This allow one period, one or two underscore and multiple\n+\t// dashes.\n+\tseparatorRegexp = match(`(?:[._]|__|[-]*)`)\n \n-\tnameRegexp = regexp.MustCompile(`(?:` + nameComponentRegexp.String() + `/)*` + nameComponentRegexp.String())\n+\t// nameComponentRegexp restricts registry path component names to start\n+\t// with at least one letter or number, with following parts able to be\n+\t// separated by one period, one or two underscore and multiple dashes.\n+\tnameComponentRegexp = expression(\n+\t\talphaNumericRegexp,\n+\t\toptional(repeated(separatorRegexp, alphaNumericRegexp)))\n \n-\thostnameComponentRegexp = regexp.MustCompile(`(?:[a-z0-9]|[a-z0-9][a-z0-9-]*[a-z0-9])`)\n+\t// hostnameComponentRegexp restricts the registry hostname component of a\n+\t// repository name to start with a component as defined by hostnameRegexp\n+\t// and followed by an optional port.\n+\thostnameComponentRegexp = match(`(?:[a-z0-9]|[a-z0-9][a-z0-9-]*[a-z0-9])`)\n \n-\t// hostnameComponentRegexp restricts the registry hostname component of a repository name to\n-\t// start with a component as defined by hostnameRegexp and followed by an optional port.\n-\thostnameRegexp = regexp.MustCompile(`(?:` + hostnameComponentRegexp.String() + `\\.)*` + hostnameComponentRegexp.String() + `(?::[0-9]+)?`)\n+\t// hostnameRegexp defines the structure of potential hostname components\n+\t// that may be part of image names. This is purposely a subset of what is\n+\t// allowed by DNS to ensure backwards compatibility with Docker image\n+\t// names.\n+\thostnameRegexp = expression(\n+\t\thostnameComponentRegexp,\n+\t\toptional(repeated(literal(`.`), hostnameComponentRegexp)),\n+\t\toptional(literal(`:`), match(`[0-9]+`)))\n \n \t// TagRegexp matches valid tag names. From docker/docker:graph/tags.go.\n-\tTagRegexp = regexp.MustCompile(`[\\w][\\w.-]{0,127}`)\n+\tTagRegexp = match(`[\\w][\\w.-]{0,127}`)\n \n \t// anchoredTagRegexp matches valid tag names, anchored at the start and\n \t// end of the matched string.\n-\tanchoredTagRegexp = regexp.MustCompile(`^` + TagRegexp.String() + `$`)\n+\tanchoredTagRegexp = anchored(TagRegexp)\n \n \t// DigestRegexp matches valid digests.\n-\tDigestRegexp = regexp.MustCompile(`[A-Za-z][A-Za-z0-9]*(?:[-_+.][A-Za-z][A-Za-z0-9]*)*[:][[:xdigit:]]{32,}`)\n+\tDigestRegexp = match(`[A-Za-z][A-Za-z0-9]*(?:[-_+.][A-Za-z][A-Za-z0-9]*)*[:][[:xdigit:]]{32,}`)\n \n \t// anchoredDigestRegexp matches valid digests, anchored at the start and\n \t// end of the matched string.\n-\tanchoredDigestRegexp = regexp.MustCompile(`^` + DigestRegexp.String() + `$`)\n+\tanchoredDigestRegexp = anchored(DigestRegexp)\n \n \t// NameRegexp is the format for the name component of references. The\n \t// regexp has capturing groups for the hostname and name part omitting\n \t// the seperating forward slash from either.\n-\tNameRegexp = regexp.MustCompile(`(?:` + hostnameRegexp.String() + `/)?` + nameRegexp.String())\n+\tNameRegexp = expression(\n+\t\toptional(hostnameRegexp, literal(`/`)),\n+\t\tnameComponentRegexp,\n+\t\toptional(repeated(literal(`/`), nameComponentRegexp)))\n \n-\t// ReferenceRegexp is the full supported format of a reference. The\n-\t// regexp has capturing groups for name, tag, and digest components.\n-\tReferenceRegexp = regexp.MustCompile(`^((?:` + hostnameRegexp.String() + `/)?` + nameRegexp.String() + `)(?:[:](` + TagRegexp.String() + `))?(?:[@](` + DigestRegexp.String() + `))?$`)\n+\t// anchoredNameRegexp is used to parse a name value, capturing the\n+\t// hostname and trailing components.\n+\tanchoredNameRegexp = anchored(\n+\t\toptional(capture(hostnameRegexp), literal(`/`)),\n+\t\tcapture(nameComponentRegexp,\n+\t\t\toptional(repeated(literal(`/`), nameComponentRegexp))))\n \n-\t// anchoredNameRegexp is used to parse a name value, capturing hostname\n-\tanchoredNameRegexp = regexp.MustCompile(`^(?:(` + hostnameRegexp.String() + `)/)?(` + nameRegexp.String() + `)$`)\n+\t// ReferenceRegexp is the full supported format of a reference. The regexp\n+\t// is anchored and has capturing groups for name, tag, and digest\n+\t// components.\n+\tReferenceRegexp = anchored(capture(NameRegexp),\n+\t\toptional(literal(\":\"), capture(TagRegexp)),\n+\t\toptional(literal(\"@\"), capture(DigestRegexp)))\n )\n+\n+// match compiles the string to a regular expression.\n+var match = regexp.MustCompile\n+\n+// literal compiles s into a literal regular expression, escaping any regexp\n+// reserved characters.\n+func literal(s string) *regexp.Regexp {\n+\tre := match(regexp.QuoteMeta(s))\n+\n+\tif _, complete := re.LiteralPrefix(); !complete {\n+\t\tpanic(\"must be a literal\")\n+\t}\n+\n+\treturn re\n+}\n+\n+// expression defines a full expression, where each regular expression must\n+// follow the previous.\n+func expression(res ...*regexp.Regexp) *regexp.Regexp {\n+\ts := res[0].String()\n+\n+\tfor _, re := range res[1:] {\n+\t\ts += re.String()\n+\t}","path":"reference/regexp.go","position":116,"original_position":116,"commit_id":"46d82e194f8e70cb6e8a691fc6b92c3b51b68358","original_commit_id":"46d82e194f8e70cb6e8a691fc6b92c3b51b68358","user":{"login":"aaronlehmann","id":10601430,"avatar_url":"https://avatars.githubusercontent.com/u/10601430?v=3","gravatar_id":"","url":"https://api.github.com/users/aaronlehmann","html_url":"https://github.com/aaronlehmann","followers_url":"https://api.github.com/users/aaronlehmann/followers","following_url":"https://api.github.com/users/aaronlehmann/following{/other_user}","gists_url":"https://api.github.com/users/aaronlehmann/gists{/gist_id}","starred_url":"https://api.github.com/users/aaronlehmann/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/aaronlehmann/subscriptions","organizations_url":"https://api.github.com/users/aaronlehmann/orgs","repos_url":"https://api.github.com/users/aaronlehmann/repos","events_url":"https://api.github.com/users/aaronlehmann/events{/privacy}","received_events_url":"https://api.github.com/users/aaronlehmann/received_events","type":"User","site_admin":false},"body":"Why not:\r\n\r\n```\r\ns := \"\"\r\nfor _, re := range res {\r\n        s += re.String()\r\n}\r\n```","created_at":"2015-12-04T23:09:22Z","updated_at":"2015-12-04T23:09:22Z","html_url":"https://github.com/docker/distribution/pull/1239#discussion_r46743731","pull_request_url":"https://api.github.com/repos/docker/distribution/pulls/1239","_links":{"self":{"href":"https://api.github.com/repos/docker/distribution/pulls/comments/46743731"},"html":{"href":"https://github.com/docker/distribution/pull/1239#discussion_r46743731"},"pull_request":{"href":"https://api.github.com/repos/docker/distribution/pulls/1239"}}},"pull_request":{"url":"https://api.github.com/repos/docker/distribution/pulls/1239","id":52731876,"html_url":"https://github.com/docker/distribution/pull/1239","diff_url":"https://github.com/docker/distribution/pull/1239.diff","patch_url":"https://github.com/docker/distribution/pull/1239.patch","issue_url":"https://api.github.com/repos/docker/distribution/issues/1239","number":1239,"state":"open","locked":false,"title":"reference: refactor grammar and regular expressions","user":{"login":"stevvooe","id":120601,"avatar_url":"https://avatars.githubusercontent.com/u/120601?v=3","gravatar_id":"","url":"https://api.github.com/users/stevvooe","html_url":"https://github.com/stevvooe","followers_url":"https://api.github.com/users/stevvooe/followers","following_url":"https://api.github.com/users/stevvooe/following{/other_user}","gists_url":"https://api.github.com/users/stevvooe/gists{/gist_id}","starred_url":"https://api.github.com/users/stevvooe/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/stevvooe/subscriptions","organizations_url":"https://api.github.com/users/stevvooe/orgs","repos_url":"https://api.github.com/users/stevvooe/repos","events_url":"https://api.github.com/users/stevvooe/events{/privacy}","received_events_url":"https://api.github.com/users/stevvooe/received_events","type":"User","site_admin":false},"body":"To resolve some inconsistencies between the grammar and the regular\r\nexpressions, the grammar has been slightly refactored to match the intent. The\r\nregular expressions have been redefined with the same structure to make it\r\neasier to verify the grammar is correct.\r\n\r\nSigned-off-by: Stephen J Day <stephen.day@docker.com>","created_at":"2015-12-04T22:49:38Z","updated_at":"2015-12-04T23:09:22Z","closed_at":null,"merged_at":null,"merge_commit_sha":"8ff13219ff08c9be94588dd17bd98ee73e476d1e","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/docker/distribution/pulls/1239/commits","review_comments_url":"https://api.github.com/repos/docker/distribution/pulls/1239/comments","review_comment_url":"https://api.github.com/repos/docker/distribution/pulls/comments{/number}","comments_url":"https://api.github.com/repos/docker/distribution/issues/1239/comments","statuses_url":"https://api.github.com/repos/docker/distribution/statuses/46d82e194f8e70cb6e8a691fc6b92c3b51b68358","head":{"label":"stevvooe:refactor-reference-grammar","ref":"refactor-reference-grammar","sha":"46d82e194f8e70cb6e8a691fc6b92c3b51b68358","user":{"login":"stevvooe","id":120601,"avatar_url":"https://avatars.githubusercontent.com/u/120601?v=3","gravatar_id":"","url":"https://api.github.com/users/stevvooe","html_url":"https://github.com/stevvooe","followers_url":"https://api.github.com/users/stevvooe/followers","following_url":"https://api.github.com/users/stevvooe/following{/other_user}","gists_url":"https://api.github.com/users/stevvooe/gists{/gist_id}","starred_url":"https://api.github.com/users/stevvooe/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/stevvooe/subscriptions","organizations_url":"https://api.github.com/users/stevvooe/orgs","repos_url":"https://api.github.com/users/stevvooe/repos","events_url":"https://api.github.com/users/stevvooe/events{/privacy}","received_events_url":"https://api.github.com/users/stevvooe/received_events","type":"User","site_admin":false},"repo":{"id":28724012,"name":"distribution","full_name":"stevvooe/distribution","owner":{"login":"stevvooe","id":120601,"avatar_url":"https://avatars.githubusercontent.com/u/120601?v=3","gravatar_id":"","url":"https://api.github.com/users/stevvooe","html_url":"https://github.com/stevvooe","followers_url":"https://api.github.com/users/stevvooe/followers","following_url":"https://api.github.com/users/stevvooe/following{/other_user}","gists_url":"https://api.github.com/users/stevvooe/gists{/gist_id}","starred_url":"https://api.github.com/users/stevvooe/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/stevvooe/subscriptions","organizations_url":"https://api.github.com/users/stevvooe/orgs","repos_url":"https://api.github.com/users/stevvooe/repos","events_url":"https://api.github.com/users/stevvooe/events{/privacy}","received_events_url":"https://api.github.com/users/stevvooe/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/stevvooe/distribution","description":"The Docker toolset to pack, ship, store, and deliver content","fork":true,"url":"https://api.github.com/repos/stevvooe/distribution","forks_url":"https://api.github.com/repos/stevvooe/distribution/forks","keys_url":"https://api.github.com/repos/stevvooe/distribution/keys{/key_id}","collaborators_url":"https://api.github.com/repos/stevvooe/distribution/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/stevvooe/distribution/teams","hooks_url":"https://api.github.com/repos/stevvooe/distribution/hooks","issue_events_url":"https://api.github.com/repos/stevvooe/distribution/issues/events{/number}","events_url":"https://api.github.com/repos/stevvooe/distribution/events","assignees_url":"https://api.github.com/repos/stevvooe/distribution/assignees{/user}","branches_url":"https://api.github.com/repos/stevvooe/distribution/branches{/branch}","tags_url":"https://api.github.com/repos/stevvooe/distribution/tags","blobs_url":"https://api.github.com/repos/stevvooe/distribution/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/stevvooe/distribution/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/stevvooe/distribution/git/refs{/sha}","trees_url":"https://api.github.com/repos/stevvooe/distribution/git/trees{/sha}","statuses_url":"https://api.github.com/repos/stevvooe/distribution/statuses/{sha}","languages_url":"https://api.github.com/repos/stevvooe/distribution/languages","stargazers_url":"https://api.github.com/repos/stevvooe/distribution/stargazers","contributors_url":"https://api.github.com/repos/stevvooe/distribution/contributors","subscribers_url":"https://api.github.com/repos/stevvooe/distribution/subscribers","subscription_url":"https://api.github.com/repos/stevvooe/distribution/subscription","commits_url":"https://api.github.com/repos/stevvooe/distribution/commits{/sha}","git_commits_url":"https://api.github.com/repos/stevvooe/distribution/git/commits{/sha}","comments_url":"https://api.github.com/repos/stevvooe/distribution/comments{/number}","issue_comment_url":"https://api.github.com/repos/stevvooe/distribution/issues/comments{/number}","contents_url":"https://api.github.com/repos/stevvooe/distribution/contents/{+path}","compare_url":"https://api.github.com/repos/stevvooe/distribution/compare/{base}...{head}","merges_url":"https://api.github.com/repos/stevvooe/distribution/merges","archive_url":"https://api.github.com/repos/stevvooe/distribution/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/stevvooe/distribution/downloads","issues_url":"https://api.github.com/repos/stevvooe/distribution/issues{/number}","pulls_url":"https://api.github.com/repos/stevvooe/distribution/pulls{/number}","milestones_url":"https://api.github.com/repos/stevvooe/distribution/milestones{/number}","notifications_url":"https://api.github.com/repos/stevvooe/distribution/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/stevvooe/distribution/labels{/name}","releases_url":"https://api.github.com/repos/stevvooe/distribution/releases{/id}","created_at":"2015-01-02T19:42:04Z","updated_at":"2015-05-06T23:19:54Z","pushed_at":"2015-12-04T22:42:05Z","git_url":"git://github.com/stevvooe/distribution.git","ssh_url":"git@github.com:stevvooe/distribution.git","clone_url":"https://github.com/stevvooe/distribution.git","svn_url":"https://github.com/stevvooe/distribution","homepage":null,"size":7571,"stargazers_count":0,"watchers_count":0,"language":"Go","has_issues":false,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":2,"mirror_url":null,"open_issues_count":0,"forks":2,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"docker:master","ref":"master","sha":"568bf038af6d65b376165d02886b1c7fcaef1f61","user":{"login":"docker","id":5429470,"avatar_url":"https://avatars.githubusercontent.com/u/5429470?v=3","gravatar_id":"","url":"https://api.github.com/users/docker","html_url":"https://github.com/docker","followers_url":"https://api.github.com/users/docker/followers","following_url":"https://api.github.com/users/docker/following{/other_user}","gists_url":"https://api.github.com/users/docker/gists{/gist_id}","starred_url":"https://api.github.com/users/docker/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/docker/subscriptions","organizations_url":"https://api.github.com/users/docker/orgs","repos_url":"https://api.github.com/users/docker/repos","events_url":"https://api.github.com/users/docker/events{/privacy}","received_events_url":"https://api.github.com/users/docker/received_events","type":"Organization","site_admin":false},"repo":{"id":28366058,"name":"distribution","full_name":"docker/distribution","owner":{"login":"docker","id":5429470,"avatar_url":"https://avatars.githubusercontent.com/u/5429470?v=3","gravatar_id":"","url":"https://api.github.com/users/docker","html_url":"https://github.com/docker","followers_url":"https://api.github.com/users/docker/followers","following_url":"https://api.github.com/users/docker/following{/other_user}","gists_url":"https://api.github.com/users/docker/gists{/gist_id}","starred_url":"https://api.github.com/users/docker/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/docker/subscriptions","organizations_url":"https://api.github.com/users/docker/orgs","repos_url":"https://api.github.com/users/docker/repos","events_url":"https://api.github.com/users/docker/events{/privacy}","received_events_url":"https://api.github.com/users/docker/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/docker/distribution","description":"The Docker toolset to pack, ship, store, and deliver content","fork":false,"url":"https://api.github.com/repos/docker/distribution","forks_url":"https://api.github.com/repos/docker/distribution/forks","keys_url":"https://api.github.com/repos/docker/distribution/keys{/key_id}","collaborators_url":"https://api.github.com/repos/docker/distribution/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/docker/distribution/teams","hooks_url":"https://api.github.com/repos/docker/distribution/hooks","issue_events_url":"https://api.github.com/repos/docker/distribution/issues/events{/number}","events_url":"https://api.github.com/repos/docker/distribution/events","assignees_url":"https://api.github.com/repos/docker/distribution/assignees{/user}","branches_url":"https://api.github.com/repos/docker/distribution/branches{/branch}","tags_url":"https://api.github.com/repos/docker/distribution/tags","blobs_url":"https://api.github.com/repos/docker/distribution/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/docker/distribution/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/docker/distribution/git/refs{/sha}","trees_url":"https://api.github.com/repos/docker/distribution/git/trees{/sha}","statuses_url":"https://api.github.com/repos/docker/distribution/statuses/{sha}","languages_url":"https://api.github.com/repos/docker/distribution/languages","stargazers_url":"https://api.github.com/repos/docker/distribution/stargazers","contributors_url":"https://api.github.com/repos/docker/distribution/contributors","subscribers_url":"https://api.github.com/repos/docker/distribution/subscribers","subscription_url":"https://api.github.com/repos/docker/distribution/subscription","commits_url":"https://api.github.com/repos/docker/distribution/commits{/sha}","git_commits_url":"https://api.github.com/repos/docker/distribution/git/commits{/sha}","comments_url":"https://api.github.com/repos/docker/distribution/comments{/number}","issue_comment_url":"https://api.github.com/repos/docker/distribution/issues/comments{/number}","contents_url":"https://api.github.com/repos/docker/distribution/contents/{+path}","compare_url":"https://api.github.com/repos/docker/distribution/compare/{base}...{head}","merges_url":"https://api.github.com/repos/docker/distribution/merges","archive_url":"https://api.github.com/repos/docker/distribution/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/docker/distribution/downloads","issues_url":"https://api.github.com/repos/docker/distribution/issues{/number}","pulls_url":"https://api.github.com/repos/docker/distribution/pulls{/number}","milestones_url":"https://api.github.com/repos/docker/distribution/milestones{/number}","notifications_url":"https://api.github.com/repos/docker/distribution/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/docker/distribution/labels{/name}","releases_url":"https://api.github.com/repos/docker/distribution/releases{/id}","created_at":"2014-12-22T23:49:26Z","updated_at":"2015-12-04T23:06:31Z","pushed_at":"2015-12-04T22:49:39Z","git_url":"git://github.com/docker/distribution.git","ssh_url":"git@github.com:docker/distribution.git","clone_url":"https://github.com/docker/distribution.git","svn_url":"https://github.com/docker/distribution","homepage":null,"size":10276,"stargazers_count":1417,"watchers_count":1417,"language":"Go","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":523,"mirror_url":null,"open_issues_count":175,"forks":523,"open_issues":175,"watchers":1417,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/docker/distribution/pulls/1239"},"html":{"href":"https://github.com/docker/distribution/pull/1239"},"issue":{"href":"https://api.github.com/repos/docker/distribution/issues/1239"},"comments":{"href":"https://api.github.com/repos/docker/distribution/issues/1239/comments"},"review_comments":{"href":"https://api.github.com/repos/docker/distribution/pulls/1239/comments"},"review_comment":{"href":"https://api.github.com/repos/docker/distribution/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/docker/distribution/pulls/1239/commits"},"statuses":{"href":"https://api.github.com/repos/docker/distribution/statuses/46d82e194f8e70cb6e8a691fc6b92c3b51b68358"}}}}