// registry-api-descriptor-template uses the APIDescriptor defined in the // api/v2 package to execute templates passed to the command line. // // For example, to generate a new API specification, one would execute the // following command from the repo root: // // $ registry-api-descriptor-template docs/spec/api.md.tmpl > docs/spec/api.md // // The templates are passed in the api/v2.APIDescriptor object. Please see the // package documentation for fields available on that object. The template // syntax is from Go's standard library text/template package. For information // on Go's template syntax, please see golang.org/pkg/text/template. package main import ( "log" "net/http" "os" "path/filepath" "regexp" "text/template" "github.com/distribution/distribution/v3/registry/api/errcode" v2 "github.com/distribution/distribution/v3/registry/api/v2" ) var spaceRegex = regexp.MustCompile(`\n\s*`) func main() { if len(os.Args) != 2 { log.Fatalln("please specify a template to execute.") } path := os.Args[1] filename := filepath.Base(path) funcMap := template.FuncMap{ "removenewlines": func(s string) string { return spaceRegex.ReplaceAllString(s, " ") }, "statustext": http.StatusText, "prettygorilla": prettyGorillaMuxPath, } tmpl := template.Must(template.New(filename).Funcs(funcMap).ParseFiles(path)) data := struct { RouteDescriptors []v2.RouteDescriptor ErrorDescriptors []errcode.ErrorDescriptor }{ RouteDescriptors: v2.APIDescriptor.RouteDescriptors, ErrorDescriptors: append(errcode.GetErrorCodeGroup("registry.api.v2"), // The following are part of the specification but provided by errcode default. errcode.ErrorCodeUnauthorized.Descriptor(), errcode.ErrorCodeDenied.Descriptor(), errcode.ErrorCodeUnsupported.Descriptor()), } if err := tmpl.Execute(os.Stdout, data); err != nil { log.Fatalln(err) } } // prettyGorillaMuxPath removes the regular expressions from a gorilla/mux // route string, making it suitable for documentation. func prettyGorillaMuxPath(s string) string { // Stateful parser that removes regular expressions from gorilla // routes. It correctly handles balanced bracket pairs. var output string var label string var level int start: if s[0] == '{' { s = s[1:] level++ goto capture } output += string(s[0]) s = s[1:] goto end capture: switch s[0] { case '{': level++ case '}': level-- if level == 0 { s = s[1:] goto label } case ':': s = s[1:] goto skip default: label += string(s[0]) } s = s[1:] goto capture skip: switch s[0] { case '{': level++ case '}': level-- } s = s[1:] if level == 0 { goto label } goto skip label: if label != "" { output += "<" + label + ">" label = "" } end: if s != "" { goto start } return output }