77 "compress/gzip"
88 "encoding/base64"
99 "encoding/json"
10+ "errors"
1011 "fmt"
1112 "html"
1213 "io"
@@ -170,11 +171,41 @@ func (h *handler) errHandler(hfe HandleFuncE) http.HandlerFunc {
170171 if err := h .maybeOauthErr (w , r , err ); err != nil {
171172 log .Printf ("%s: %v" , r .URL .Path , err )
172173 fmt .Fprintf (w , "failed: %s" , html .EscapeString (err .Error ()))
174+
175+ var serr * ErrorSuggestion
176+ if errors .As (err , & serr ) {
177+ fmt .Fprintf (w , "<p><i>suggestion: %s</i></p>" , serr .Suggestion ())
178+ }
173179 }
174180 }
175181 }
176182}
177183
184+ // ErrorSuggestion wraps an upstream error with a server-provided suggestion for the user.
185+ type ErrorSuggestion struct {
186+ err error
187+ suggest string
188+ }
189+
190+ func NewErrorSuggestion (err error , suggest string ) * ErrorSuggestion {
191+ return & ErrorSuggestion {
192+ err : err ,
193+ suggest : suggest ,
194+ }
195+ }
196+
197+ func (e * ErrorSuggestion ) Error () string {
198+ return e .err .Error ()
199+ }
200+
201+ func (e * ErrorSuggestion ) Unwrap () error {
202+ return e .err
203+ }
204+
205+ func (e * ErrorSuggestion ) Suggestion () string {
206+ return e .suggest
207+ }
208+
178209func (h * handler ) renderResponse (w http.ResponseWriter , r * http.Request ) error {
179210 qs := r .URL .Query ()
180211
@@ -208,10 +239,6 @@ func (h *handler) renderRepo(w http.ResponseWriter, r *http.Request, repo string
208239 return err
209240 }
210241
211- if repo == "cgr.dev/chainguard" {
212- return h .renderChainguardRepo (w , r , repo )
213- }
214-
215242 reg := ref .RegistryStr ()
216243 googleRepo := reg == "registry.k8s.io" || reg == "mirror.gcr.io" || (isGoogle (reg ) && ref .RepositoryStr () != "" )
217244 hubRepo := (strings .HasPrefix (repo , "index.docker.io" ) || strings .HasPrefix (repo , "docker.io" )) && strings .Count (repo , "/" ) == 1
@@ -263,7 +290,7 @@ func (h *handler) renderRepo(w http.ResponseWriter, r *http.Request, repo string
263290 tags , err := h .listTags (w , r , ref , repo )
264291 if err != nil {
265292 if tags == nil {
266- return err
293+ return NewErrorSuggestion ( err , fmt . Sprintf ( `try <a href="/?repo=%s">catalog</a>?` , ref . RegistryStr ()))
267294 }
268295
269296 // Sometimes we time out (or other issues), render whatever we got.
@@ -282,51 +309,6 @@ func (h *handler) renderRepo(w http.ResponseWriter, r *http.Request, repo string
282309 return nil
283310}
284311
285- func (h * handler ) renderChainguardRepo (w http.ResponseWriter , r * http.Request , repo string ) error {
286- // ls ../../chainguard-images/images/images | jq -Rn '{"child": [inputs] }' > cmd/oci/kodata/chainguard.json
287- fn := filepath .Join (os .Getenv ("KO_DATA_PATH" ), "chainguard.json" )
288- b , err := os .ReadFile (fn )
289- if err != nil {
290- return err
291- }
292-
293- if err := headerTmpl .Execute (w , TitleData {repo }); err != nil {
294- return err
295- }
296- header := HeaderData {
297- Repo : repo ,
298- Reference : repo ,
299- JQ : "chainctl img repo ls | jq . # kind of..." ,
300- }
301- if strings .Contains (repo , "/" ) {
302- base := path .Base (repo )
303- dir := path .Dir (strings .TrimRight (repo , "/" ))
304- if base != "." && dir != "." {
305- header .Up = & RepoParent {
306- Parent : dir ,
307- Child : base ,
308- Separator : "/" ,
309- }
310- }
311- }
312- if err := bodyTmpl .Execute (w , header ); err != nil {
313- return err
314- }
315-
316- output := & jsonOutputter {
317- w : w ,
318- u : r .URL ,
319- fresh : []bool {},
320- repo : repo ,
321- }
322- if err := renderJSON (output , b ); err != nil {
323- return err
324- }
325-
326- fmt .Fprintf (w , footer )
327- return nil
328- }
329-
330312func (h * handler ) renderGoogleRepo (w http.ResponseWriter , r * http.Request , repo string ) error {
331313 ref , err := name .NewRepository (repo )
332314 if err != nil {
0 commit comments