Skip to content

Commit c8497c1

Browse files
committed
Add error suggestions
Adds an option error wrapper that will output raw unescaped HTML. This can be used to attach optional suggestions for common errors / next steps we expect people to take. For the first impl, adds a suggestion to prompt people to go to the catalog view if the repository doesn't exist. Also removes the special casing for cgr.dev/chainguard as a result.
1 parent b14dddc commit c8497c1

1 file changed

Lines changed: 32 additions & 50 deletions

File tree

internal/explore/explore.go

Lines changed: 32 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
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+
178209
func (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-
330312
func (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

Comments
 (0)