diff options
author | Ian Lewis <ianmlewis@gmail.com> | 2019-07-03 00:38:04 -0400 |
---|---|---|
committer | Ian Lewis <ianlewis@google.com> | 2019-07-10 11:46:34 +0900 |
commit | 6714bee53bbe6cdc3943e59f30ec7765907e80b0 (patch) | |
tree | 5483dd5a678ef82a3bd1251f90471312677f8baf /cmd/generate-syscall-docs | |
parent | 82b3d5ffd3e6448664829f65ee6efe427c615879 (diff) |
Add generate-syscall-docs command.
Adds a new command to automatically generate the syscall compatibility
docs from runsc.
Diffstat (limited to 'cmd/generate-syscall-docs')
-rw-r--r-- | cmd/generate-syscall-docs/main.go | 203 |
1 files changed, 203 insertions, 0 deletions
diff --git a/cmd/generate-syscall-docs/main.go b/cmd/generate-syscall-docs/main.go new file mode 100644 index 000000000..006bd1ce5 --- /dev/null +++ b/cmd/generate-syscall-docs/main.go @@ -0,0 +1,203 @@ +// Copyright 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package main + +import ( + "bufio" + "encoding/json" + "flag" + "fmt" + "io" + "os" + "path/filepath" + "sort" + "strings" + "text/template" +) + +type CompatibilityInfo map[string]map[string]ArchInfo + +// ArchInfo is compatbility doc for an architecture. +type ArchInfo struct { + // Syscalls maps syscall number for the architecture to the doc. + Syscalls map[uintptr]SyscallDoc `json:"syscalls"` +} + +// SyscallDoc represents a single item of syscall documentation. +type SyscallDoc struct { + Name string `json:"name"` + Support string `json:"support"` + Note string `json:"note,omitempty"` + URLs []string `json:"urls,omitempty"` +} + +var mdTemplate = template.Must(template.New("out").Parse(` ++++ +title = "{{.OS}}/{{.Arch}}" +description = "Syscall Compatibility Reference Documentation for {{.OS}}/{{.Arch}}" +weight = {{.Weight}} ++++ + +This table is a reference of {{.OS}} syscalls for the {{.Arch}} architecture and +their compatibility status in gVisor. gVisor does not support all syscalls and +some syscalls may have a partial implementation. + +Of {{.Total}} syscalls, {{.Supported}} syscalls have a full or partial +implementation. There are currently {{.Unsupported}} unsupported +syscalls. {{if .Undocumented}}{{.Undocumented}} syscalls are not yet documented.{{end}} + +<table> + <thead> + <tr> + <th>#</th> + <th>Name</th> + <th>Support</th> + <th>Notes</th> + </tr> + </thead> + <tbody> + {{range $i, $syscall := .Syscalls}} + <tr> + <td><a class="doc-table-anchor" id="{{.Name}}"></a>{{.Number}}</td> + <td><a href="http://man7.org/linux/man-pages/man2/{{.Name}}.2.html" target="_blank" rel="noopener">{{.Name}}</a></td> + <td>{{.Support}}</td> + <td>{{.Note}} {{range $i, $url := .URLs}}<br/>See: <a href="{{.}}">{{.}}</a>{{end}}</td> + </tr> + {{end}} + </tbody> +</table> +`)) + +// Fatalf writes a message to stderr and exits with error code 1 +func Fatalf(format string, a ...interface{}) { + fmt.Fprintf(os.Stderr, format, a...) + os.Exit(1) +} + +func main() { + inputFlag := flag.String("in", "-", "File to input ('-' for stdin)") + outputDir := flag.String("out", ".", "Directory to output files.") + + flag.Parse() + + var input io.Reader + if *inputFlag == "-" { + input = os.Stdin + } else { + i, err := os.Open(*inputFlag) + if err != nil { + Fatalf("Error opening %q: %v", *inputFlag, err) + } + input = i + } + input = bufio.NewReader(input) + + var info CompatibilityInfo + d := json.NewDecoder(input) + if err := d.Decode(&info); err != nil { + Fatalf("Error reading json: %v") + } + + weight := 0 + for osName, osInfo := range info { + for archName, archInfo := range osInfo { + outDir := filepath.Join(*outputDir, osName) + outFile := filepath.Join(outDir, archName+".md") + + if err := os.MkdirAll(outDir, 0755); err != nil { + Fatalf("Error creating directory %q: %v", *outputDir, err) + } + + f, err := os.OpenFile(outFile, os.O_RDWR|os.O_CREATE, 0644) + if err != nil { + Fatalf("Error opening file %q: %v", outFile, err) + } + defer f.Close() + + weight += 10 + data := struct { + OS string + Arch string + Weight int + Total int + Supported int + Unsupported int + Undocumented int + Syscalls []struct { + Name string + Number uintptr + Support string + Note string + URLs []string + } + }{ + OS: strings.Title(osName), + Arch: archName, + Weight: weight, + Total: 0, + Supported: 0, + Unsupported: 0, + Undocumented: 0, + Syscalls: []struct { + Name string + Number uintptr + Support string + Note string + URLs []string + }{}, + } + + for num, s := range archInfo.Syscalls { + switch s.Support { + case "Full Support", "Partial Support": + data.Supported++ + case "Unimplemented": + data.Unsupported++ + default: + data.Undocumented++ + } + data.Total++ + + for i := range s.URLs { + if !strings.HasPrefix(s.URLs[i], "http://") && !strings.HasPrefix(s.URLs[i], "https://") { + s.URLs[i] = "https://" + s.URLs[i] + } + } + + data.Syscalls = append(data.Syscalls, struct { + Name string + Number uintptr + Support string + Note string + URLs []string + }{ + Name: s.Name, + Number: num, + Support: s.Support, + Note: s.Note, // TODO urls + URLs: s.URLs, + }) + } + + sort.Slice(data.Syscalls, func(i, j int) bool { + return data.Syscalls[i].Number < data.Syscalls[j].Number + }) + + if err := mdTemplate.Execute(f, data); err != nil { + Fatalf("Error writing file %q: %v", outFile, err) + } + } + } +} |