github.com/containers/podman/v2@v2.2.2-0.20210501105131-c1e07d070c4c/docs/varlink/apidoc.go (about) 1 package main 2 3 import ( 4 "bytes" 5 "fmt" 6 "io/ioutil" 7 "os" 8 "sort" 9 "strings" 10 11 "github.com/varlink/go/varlink/idl" 12 ) 13 14 func readFileToString(path string) (string, error) { 15 content, err := ioutil.ReadFile(path) 16 if err != nil { 17 return "", err 18 } 19 return string(content), nil 20 } 21 22 func exit(err error) { 23 fmt.Println(err.Error()) 24 os.Exit(1) 25 } 26 27 func typeToString(input *idl.Type) string { 28 switch input.Kind { 29 case idl.TypeString: 30 return "string" 31 case idl.TypeBool: 32 return "bool" 33 case idl.TypeFloat: 34 return "float" 35 case idl.TypeArray: 36 result := input.ElementType.Alias 37 if result == "" { 38 return fmt.Sprintf("[]%s", typeToString(input.ElementType)) 39 } 40 return result 41 case idl.TypeAlias: 42 return input.Alias 43 case idl.TypeMap: 44 return "map[string]" 45 case idl.TypeInt: 46 return "int" 47 case idl.TypeMaybe: 48 return fmt.Sprintf("?%s", typeToString(input.ElementType)) 49 } 50 return "" 51 } 52 53 func typeToLink(input string) string { 54 switch input { 55 case "string": 56 return "https://godoc.org/builtin#string" 57 case "int": 58 return "https://godoc.org/builtin#int" 59 case "bool": 60 return "https://godoc.org/builtin#bool" 61 case "float": 62 return "https://golang.org/src/builtin/builtin.go#L58" 63 default: 64 return fmt.Sprintf("#%s", input) 65 } 66 } 67 68 type funcArgs struct { 69 paramName string 70 paramKind string 71 } 72 type funcDescriber struct { 73 Name string 74 inputParams []funcArgs 75 returnParams []funcArgs 76 doc string 77 } 78 79 type funcSorter []funcDescriber 80 81 func (a funcSorter) Len() int { return len(a) } 82 func (a funcSorter) Swap(i, j int) { a[i], a[j] = a[j], a[i] } 83 func (a funcSorter) Less(i, j int) bool { return a[i].Name < a[j].Name } 84 85 type typeAttrs struct { 86 Name string 87 AttrType string 88 } 89 type typeDescriber struct { 90 Name string 91 doc string 92 Attrs []typeAttrs 93 } 94 95 type typeSorter []typeDescriber 96 97 func (a typeSorter) Len() int { return len(a) } 98 func (a typeSorter) Swap(i, j int) { a[i], a[j] = a[j], a[i] } 99 func (a typeSorter) Less(i, j int) bool { return a[i].Name < a[j].Name } 100 101 type err struct { 102 Name string 103 doc string 104 } 105 106 type errorSorter []err 107 108 func (a errorSorter) Len() int { return len(a) } 109 func (a errorSorter) Swap(i, j int) { a[i], a[j] = a[j], a[i] } 110 func (a errorSorter) Less(i, j int) bool { return a[i].Name < a[j].Name } 111 112 // collects defined types in the idl 113 func getTypes(tidl *idl.IDL) []typeDescriber { 114 var types []typeDescriber 115 for _, x := range tidl.Aliases { 116 i := typeDescriber{ 117 Name: x.Name, 118 doc: x.Doc, 119 } 120 ta := []typeAttrs{} 121 for _, y := range x.Type.Fields { 122 result := typeToString(y.Type) 123 ta = append(ta, typeAttrs{Name: y.Name, AttrType: result}) 124 } 125 i.Attrs = ta 126 types = append(types, i) 127 } 128 return types 129 } 130 131 // collects defined methods in the idl 132 func getMethods(midl *idl.IDL) []funcDescriber { 133 var methods []funcDescriber 134 for _, t := range midl.Methods { 135 m := funcDescriber{ 136 Name: t.Name, 137 doc: t.Doc, 138 } 139 fa := []funcArgs{} 140 fo := []funcArgs{} 141 142 for _, i := range t.In.Fields { 143 fa = append(fa, funcArgs{paramName: i.Name, paramKind: typeToString(i.Type)}) 144 145 } 146 for _, f := range t.Out.Fields { 147 fo = append(fo, funcArgs{paramName: f.Name, paramKind: typeToString(f.Type)}) 148 } 149 m.inputParams = fa 150 m.returnParams = fo 151 methods = append(methods, m) 152 } 153 return methods 154 } 155 156 // collects defined errors in the idl 157 func getErrors(midl *idl.IDL) []err { 158 var errors []err 159 for _, e := range midl.Errors { 160 myError := err{ 161 Name: e.Name, 162 doc: e.Doc, 163 } 164 errors = append(errors, myError) 165 } 166 return errors 167 } 168 169 // generates the index for the top of the markdown page 170 func generateIndex(methods []funcDescriber, types []typeDescriber, errors []err, b bytes.Buffer) bytes.Buffer { 171 // Sort the methods, types, and errors by alphabetical order 172 sort.Sort(funcSorter(methods)) 173 sort.Sort(typeSorter(types)) 174 sort.Sort(errorSorter(errors)) 175 176 for _, method := range methods { 177 var inArgs []string 178 var outArgs []string 179 for _, inArg := range method.inputParams { 180 inArgs = append(inArgs, fmt.Sprintf("%s: %s", inArg.paramName, inArg.paramKind)) 181 182 } 183 for _, outArg := range method.returnParams { 184 outArgs = append(outArgs, outArg.paramKind) 185 186 } 187 b.WriteString(fmt.Sprintf("\n[func %s(%s) %s](#%s)\n", method.Name, strings.Join(inArgs, ", "), strings.Join(outArgs, ", "), method.Name)) 188 } 189 b.WriteString("\n") 190 for _, t := range types { 191 b.WriteString(fmt.Sprintf("[type %s](#%s)\n\n", t.Name, t.Name)) 192 } 193 for _, e := range errors { 194 b.WriteString(fmt.Sprintf("[error %s](#%s)\n\n", e.Name, e.Name)) 195 } 196 return b 197 } 198 199 // performs the output for defined methods 200 func generateFuncDescriptions(methods []funcDescriber, b bytes.Buffer) bytes.Buffer { 201 for _, method := range methods { 202 b.WriteString(fmt.Sprintf("### <a name=\"%s\"></a>func %s\n", method.Name, method.Name)) 203 var inArgs []string 204 var outArgs []string 205 for _, inArg := range method.inputParams { 206 inArgs = append(inArgs, fmt.Sprintf("%s: [%s](%s)", inArg.paramName, inArg.paramKind, typeToLink(inArg.paramKind))) 207 } 208 for _, outArg := range method.returnParams { 209 outArgs = append(outArgs, fmt.Sprintf("[%s](%s)", outArg.paramKind, typeToLink(outArg.paramKind))) 210 } 211 b.WriteString(fmt.Sprintf("<div style=\"background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;\">\n\nmethod %s(%s) %s</div>", method.Name, strings.Join(inArgs, ", "), strings.Join(outArgs, ", "))) 212 b.WriteString("\n") 213 b.WriteString(method.doc) 214 b.WriteString("\n") 215 } 216 return b 217 } 218 219 // performs the output for defined types/structs 220 func generateTypeDescriptions(types []typeDescriber, b bytes.Buffer) bytes.Buffer { 221 for _, t := range types { 222 b.WriteString(fmt.Sprintf("### <a name=\"%s\"></a>type %s\n", t.Name, t.Name)) 223 b.WriteString(fmt.Sprintf("\n%s\n", t.doc)) 224 for _, i := range t.Attrs { 225 b.WriteString(fmt.Sprintf("\n%s [%s](%s)\n", i.Name, i.AttrType, typeToLink(i.AttrType))) 226 } 227 } 228 return b 229 } 230 231 // performs the output for defined errors 232 func generateErrorDescriptions(errors []err, b bytes.Buffer) bytes.Buffer { 233 for _, e := range errors { 234 b.WriteString(fmt.Sprintf("### <a name=\"%s\"></a>type %s\n", e.Name, e.Name)) 235 b.WriteString(fmt.Sprintf("\n%s\n", e.doc)) 236 } 237 return b 238 } 239 240 func main() { 241 args := os.Args 242 if len(args) < 2 { 243 exit(fmt.Errorf("you must provide an input and output path")) 244 } 245 varlinkFile := args[1] 246 mdFile := args[2] 247 248 varlinkInput, err := readFileToString(varlinkFile) 249 if err != nil { 250 exit(err) 251 } 252 varlinkInput = strings.TrimRight(varlinkInput, "\n") 253 254 // Run the idl parser 255 midl, err := idl.New(varlinkInput) 256 if err != nil { 257 exit(err) 258 } 259 // Collect up the info from the idl 260 methods := getMethods(midl) 261 types := getTypes(midl) 262 errors := getErrors(midl) 263 264 out := bytes.Buffer{} 265 out.WriteString(fmt.Sprintf("# %s\n", midl.Name)) 266 out.WriteString(fmt.Sprintf("%s\n", midl.Doc)) 267 out.WriteString("## Index\n") 268 out = generateIndex(methods, types, errors, out) 269 out.WriteString("## Methods\n") 270 out = generateFuncDescriptions(methods, out) 271 out.WriteString("## Types\n") 272 out = generateTypeDescriptions(types, out) 273 out.WriteString("## Errors\n") 274 out = generateErrorDescriptions(errors, out) 275 if err := ioutil.WriteFile(mdFile, out.Bytes(), 0755); err != nil { 276 fmt.Fprintf(os.Stderr, "Error writing file: %v\n", err) 277 os.Exit(1) 278 } 279 }