-
Notifications
You must be signed in to change notification settings - Fork 546
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
adds support for the /v2/_catalog API #548
Conversation
Thanks for your pull request. It looks like this may be your first contribution to a Google open source project (if not, look below for help). Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA). 📝 Please visit https://cla.developers.google.com/ to sign. Once you've signed (or fixed any issues), please reply here with What to do if you already signed the CLAIndividual signers
Corporate signers
ℹ️ Googlers: Go here for more info. |
CLA-wise I just use a different email for github than what I used to commit that |
pkg/v1/remote/catalog.go
Outdated
} | ||
|
||
// GetCatalog calls /_catalog, returning the list of repositories on the registry | ||
func GetCatalog(target name.Registry, options ...Option) ([]string, error) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Given that the results of catalog can be paginated, there might be a better return type than []string
-- I'm not sure what the most go idiomatic thing to do here is...
We could return a channel? Or do callbacks for each "page"?
Or maybe this is just fine...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what about now? (sorry to double comment)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it'd make sense for GetCatalog
to do pagination itself, and return all the results it could find from however many requests were necessary to find them. That seems simpler than making callers deal with pagination, or pass a channel, or whatever.
Codecov Report
@@ Coverage Diff @@
## master #548 +/- ##
==========================================
+ Coverage 72.34% 72.87% +0.52%
==========================================
Files 95 102 +7
Lines 4245 4486 +241
==========================================
+ Hits 3071 3269 +198
- Misses 777 806 +29
- Partials 397 411 +14
Continue to review full report at Codecov.
|
CLAs look good, thanks! ℹ️ Googlers: Go here for more info. |
How about now? |
pkg/v1/remote/catalog.go
Outdated
|
||
var query string | ||
|
||
query = fmt.Sprintf("last=%s&n=%d", url.QueryEscape(last), n) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
query := fmt.Sprintf(...)
pkg/v1/remote/catalog.go
Outdated
|
||
// GetCatalog calls /_catalog, returning the list of repositories on the registry | ||
func GetCatalog(target name.Registry, last string, n int, options ...Option) ([]string, error) { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: unnecessary blank line
pkg/v1/remote/catalog.go
Outdated
return nil, err | ||
} | ||
|
||
//TKTK:JM iterate through results with "last" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this meant to be a TODO?
pkg/v1/remote/catalog.go
Outdated
return parsed.Repos, nil | ||
} | ||
|
||
//TKTK:JM write tests |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, please do. 😄
pkg/v1/remote/catalog.go
Outdated
return nil, err | ||
} | ||
|
||
parsed := catalog{} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
supernit: I typically see this as var parsed catalog
which has the same effect but is infinitesimally more idiomatic.
Thanks for the comments, back atcha |
pkg/v1/remote/catalog.go
Outdated
} | ||
|
||
// GetCatalog calls /_catalog, returning the list of repositories on the registry | ||
func GetCatalog(target name.Registry, last string, n int, options ...Option) ([]string, error) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How do you feel about GetCatalog
just doing pagination itself and returning all the values it can find? How many pages of results do we expect to get from this? Tens of thousands?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's why I was hesitant to implement it because I'm not sure of the scale.
I was planning on writing a helper for my own purposes that I can add later, but I just needed this at a minimum.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The scale might be a concern, but for (most?) users who should expect only a couple pages, it sucks that this makes them handle pagination themselves.
I'd prefer to expose the pagination-handling version for the users that don't want to deal with it, and maybe if we hear that this method is a pain for whatever scaling reason, we can export the DIY method later. If we never hear that we need to expose the guts, that's great.
Does that make any sense?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we're going to handle the pagination internally, we should probably make GetCatalog
take a context.Context
so that you can cancel it.
it sucks that this makes them handle pagination themselves
This is basically why the crane
package exists. IMO we should (within reason) expose all the complexity that the API itself has, then we can expose the happy path in crane
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Another pattern I've seen that is nice, is to have the GetCatalog take a callback function that gets called per page. It allows users to abort early (via returning an error / cancelling the context), but it hides the pagination detail from the user.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@imjasonh thinks they're not idiomatic go. There's this presentation for inspiration.
I'm not sure if we could borrow something from that, but it also doesn't like callbacks (from here):
Bryan briefly mentions asynchronous callbacks as something programmers from other certain languages sometimes try to use. But he notes that most Go programmers already know not to use them in Go, and moves on to talking about Futures and Producer–Consumer Queues.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a synchronous callback - not a async one. The next page wouldn't be fetched until the callback returns.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, how do we feel about my new crane.GetCatalog
?
@jmakinen-ncc so, let's just punt on figuring out a reasonable API for paginated requests. I'd say just add your original, easy-to-use implementation under Sorry for the back and forth! |
Sorry, so does that mean that this can be merged? |
pkg/v1/remote/catalog.go
Outdated
} | ||
|
||
// GetCatalogPage calls /_catalog, returning the list of repositories on the registry | ||
func GetCatalogPage(target name.Registry, last string, n int, options ...Option) ([]string, error) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the idea is to just make this a private method in the crane/catalog.go file. At some point in the future it can get moved to the remote library when we have interface concensus.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think I'm actually okay with leaving this in. If we ever come up with a good API for this, we can name it GetCatalog
, and GetCatalogPage
would still be useful.
I am a little bit unhappy with this because it doesn't allow clients to adhere to the spec:
Compliant client implementations should always use the Link header value when proceeding through results linearly.
However, this does enable you to skip ahead, which is immediately after:
The client may construct URLs to skip forward in the catalog.
I think we're basically making it impossible (sometimes, depends on implementation) for a registry to implement this efficiently by handing us a cursor in the Link header, but maybe we don't care.
Would anyone be able to help me figure out why the build is failing here? |
It's complaining that you haven't run
Yeah, definitely. I'm just not sure if this is the API we want to support forever. It has the same drawback as this, where we can't reuse the auth handshake results across multiple pages. I'm also not sure if we want to return just the On the other hand, the crane API is pretty straightforward, so I think it's reasonable to merge that now (so you can use it) until we can figure out the best way to represent this. Do you need the ability to list individual pages? Or is the crane API sufficient for now? |
cmd/crane/cmd/catalog.go
Outdated
// NewCmdGetCatalog creates a new cobra.Command for the repos subcommand. | ||
func NewCmdGetCatalog() *cobra.Command { | ||
return &cobra.Command{ | ||
Use: "repos", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think I'd rather this just be catalog
than repos
@jmakinen-ncc any interest in pushing this over the finish line? I feel like it's pretty close to merge-able. |
Yeah, sorry been looking for the free time in my personal life to close up some loose threads.
Will do asap.
On Oct 18, 2019 2:00 PM, jonjohnsonjr <[email protected]> wrote:
@jmakinen-ncc<https://github.com/jmakinen-ncc> any interest in pushing this over the finish line? I feel like it's pretty close to merge-able.
-
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub<#548?email_source=notifications&email_token=AGKDKP3JOEHHVXTGNYM3A5TQPIPXZA5CNFSM4IY3XYZ2YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEBV6Z7Y#issuecomment-543943935>, or unsubscribe<https://github.com/notifications/unsubscribe-auth/AGKDKP2V4D6YZAX7U37KODTQPIPXZANCNFSM4IY3XYZQ>.
|
No worries! I was just running through old issues and PRs trying to clean things up, there's no rush 😄 |
Do we have a winner? |
cmd/crane/doc/crane_repos.md
Outdated
@@ -0,0 +1,22 @@ | |||
## crane repos |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: drop this file
cmd/crane/cmd/catalog.go
Outdated
func init() { Root.AddCommand(NewCmdGetCatalog()) } | ||
|
||
// NewCmdGetCatalog creates a new cobra.Command for the repos subcommand. | ||
func NewCmdGetCatalog() *cobra.Command { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: I'd name this "NewCmdCatalog" to be consistent with the rest of the commands.
pkg/crane/catalog.go
Outdated
"github.com/google/go-containerregistry/pkg/v1/remote" | ||
) | ||
|
||
// GetCatalog returns the repositories in a registry's catalog |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
supernit: add a period at the end of this sentence
pkg/crane/catalog.go
Outdated
n := 100 | ||
last := "" | ||
for { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
supernit: drop this line
pkg/crane/catalog.go
Outdated
if len(page) < n { | ||
break | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
supernit: drop this line
pkg/v1/remote/catalog.go
Outdated
Repos []string `json:"repositories"` | ||
} | ||
|
||
// GetCatalogPage calls /_catalog, returning the list of repositories on the registry |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
supernit: add a period at the end of this sentence
pkg/v1/remote/catalog.go
Outdated
} | ||
|
||
// GetCatalogPage calls /_catalog, returning the list of repositories on the registry | ||
func GetCatalogPage(target name.Registry, last string, n int, options ...Option) ([]string, error) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think I'm actually okay with leaving this in. If we ever come up with a good API for this, we can name it GetCatalog
, and GetCatalogPage
would still be useful.
I am a little bit unhappy with this because it doesn't allow clients to adhere to the spec:
Compliant client implementations should always use the Link header value when proceeding through results linearly.
However, this does enable you to skip ahead, which is immediately after:
The client may construct URLs to skip forward in the catalog.
I think we're basically making it impossible (sometimes, depends on implementation) for a registry to implement this efficiently by handing us a cursor in the Link header, but maybe we don't care.
pkg/v1/remote/catalog_test.go
Outdated
responseBody: []byte("notjson"), | ||
wantErr: true, | ||
}} | ||
//TODO: add test cases for pagination |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Planning to do this later? 😄
supernit: add a space between //
and TODO
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Potentially, but I just wanted to note that they are missing if anyone runs into issues there later and wants to write some.
Do you need this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, thanks!
Thanks everyone! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@jmakinen-ncc sorry I don't mean to renege, but I just saw these final nits right before I hit merge 😅
The nits mean we care ❤️
cmd/crane/cmd/catalog.go
Outdated
|
||
func init() { Root.AddCommand(NewCmdCatalog()) } | ||
|
||
// NewCmdGetCatalog creates a new cobra.Command for the repos subcommand. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: NewCmdCatalog
pkg/crane/catalog.go
Outdated
"github.com/google/go-containerregistry/pkg/v1/remote" | ||
) | ||
|
||
// GetCatalog returns the repositories in a registry's catalog. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can You change these to just Catalog
?
pkg/v1/remote/catalog.go
Outdated
Repos []string `json:"repositories"` | ||
} | ||
|
||
// GetCatalogPage calls /_catalog, returning the list of repositories on the registry. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can You change these to just CatalogPage
?
pkg/v1/remote/catalog_test.go
Outdated
"github.com/google/go-containerregistry/pkg/name" | ||
) | ||
|
||
func TestGetCatalogPage(t *testing.T) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TestCatalogPage
cmd/crane/cmd/catalog.go
Outdated
@@ -0,0 +1,45 @@ | |||
// Copyright 2018 Google LLC All Rights Reserved. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: 2019
pkg/crane/catalog.go
Outdated
@@ -0,0 +1,49 @@ | |||
// Copyright 2018 Google LLC All Rights Reserved. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: 2019
pkg/v1/remote/catalog.go
Outdated
@@ -0,0 +1,70 @@ | |||
// Copyright 2018 Google LLC All Rights Reserved. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: 2019
pkg/v1/remote/catalog_test.go
Outdated
@@ -0,0 +1,83 @@ | |||
// Copyright 2018 Google LLC All Rights Reserved. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: 2019
…ity in!(no worries if I'm still not there tho)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(no worries if I'm still not there tho)
😆
git is my favorite chat protocol
Thanks! Sorry again for all the back and forth :)
Ask @clrprod about "Big changes, no promises" |
This reverts commit f9947dc.
No description provided.