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  }