Skip to content

Commit

Permalink
Add generate-syscall-docs command.
Browse files Browse the repository at this point in the history
Adds a new command to automatically generate the syscall compatibility
docs from runsc.
  • Loading branch information
ianlewis committed Jul 10, 2019
1 parent 82b3d5f commit 6714bee
Show file tree
Hide file tree
Showing 9 changed files with 279 additions and 723 deletions.
2 changes: 2 additions & 0 deletions .gcloudignore
@@ -1,3 +1,5 @@
bin/
public/
resources/
node_modules/
upstream/
1 change: 1 addition & 0 deletions .gitignore
@@ -1,3 +1,4 @@
bin/
public/
resources/
node_modules/
Expand Down
20 changes: 16 additions & 4 deletions Makefile
Expand Up @@ -6,6 +6,7 @@ GCLOUD := gcloud
GCP_PROJECT := gvisor-website

# Source Go files, example: main.go, foo/bar.go.
GEN_SOURCE = $(wildcard cmd/generate-syscall-docs/*)
APP_SOURCE = $(wildcard cmd/gvisor-website/*)
# Target Go files, example: public/main.go, public/foo/bar.go.
APP_TARGET = $(patsubst cmd/gvisor-website/%,public/%,$(APP_SOURCE))
Expand Down Expand Up @@ -40,16 +41,27 @@ content/docs/community/sigs: upstream/community $(wildcard upstream/community/si
$(APP_TARGET): public $(APP_SOURCE)
cp -a cmd/gvisor-website/$(patsubst public/%,%,$@) public/

public/static: node_modules config.toml $(shell find archetypes assets content themes -type f | sed 's/ /\\ /g')
public/static: compatibility-docs node_modules config.toml $(shell find archetypes assets content themes -type f | sed 's/ /\\ /g')
HUGO_ENV="production" $(HUGO)

node_modules: package.json package-lock.json
# Use npm ci because npm install will update the package-lock.json.
# See: https://github.com/npm/npm/issues/18286
$(NPM) ci

upstream/gvisor/bazel-bin/runsc/linux_amd64_pure_stripped/runsc: upstream-gvisor
cd upstream/gvisor && bazel build runsc

bin/generate-syscall-docs: $(GEN_SOURCE)
mkdir -p bin/
go build -o bin/generate-syscall-docs gvisor.dev/website/cmd/generate-syscall-docs

.PHONY: compatibility-docs
compatibility-docs: bin/generate-syscall-docs upstream/gvisor/bazel-bin/runsc/linux_amd64_pure_stripped/runsc
./upstream/gvisor/bazel-bin/runsc/linux_amd64_pure_stripped/runsc help syscalls -o json | ./bin/generate-syscall-docs -out ./content/docs/user_guide/compatibility/

# Run a local content development server. Redirects will not be supported.
server: all-upstream
server: all-upstream compatibility-docs
$(HUGO) server -FD --port 8080
.PHONY: server

Expand All @@ -63,7 +75,7 @@ deploy: $(APP_TARGET)

# Submit a build to Cloud Build manually. Used to test cloudbuild.yaml changes.
cloud-build:
gcloud builds submit --config cloudbuild/cloudbuild.yaml .
gcloud builds submit --config cloudbuild.yaml .

# Build and push the hugo Docker image used by Cloud Build.
hugo-docker-image:
Expand All @@ -78,5 +90,5 @@ htmlproofer-docker-image:
.PHONY: htmlproofer-docker-image

clean:
rm -rf public/ resources/ node_modules/ upstream/
rm -rf public/ resources/ node_modules/ upstream/ content/docs/user_guide/compatibility/linux/
.PHONY: clean
55 changes: 51 additions & 4 deletions cloudbuild.yaml
Expand Up @@ -13,15 +13,62 @@
# limitations under the License.

steps:
- name: 'bash'
args: ['bash', '-c', 'mkdir -p upstream/']
# Clone the upstream repos
- name: 'gcr.io/cloud-builders/git'
args: ['clone', 'https://github.com/google/gvisor.git']
dir: 'upstream'
- name: 'gcr.io/cloud-builders/git'
args: ['clone', 'https://gvisor.googlesource.com/community']
dir: 'upstream'
# Build runsc
- name: 'gcr.io/cloud-builders/bazel'
args:
- 'build'
- '--show_timestamps'
- '--test_output=errors'
- '--keep_going'
- '--verbose_failures'
- 'runsc'
dir: 'upstream/gvisor'
# Build the compatibility doc generator tool
- name: 'golang'
env: ['GO111MODULE=on']
args:
- 'go'
- 'build'
- '-o'
- 'bin/generate-syscall-docs'
- 'gvisor.dev/website/cmd/generate-syscall-docs'
# Generate compatibility docs.
- name: 'bash'
args:
- 'bash'
- '-c'
- >
./upstream/gvisor/bazel-bin/runsc/linux_amd64_pure_stripped/runsc help syscalls -o json |
./bin/generate-syscall-docs -out ./content/docs/user_guide/compatibility/
# Pull npm dependencies for scss
- name: 'gcr.io/cloud-builders/npm'
args: ['ci']
# Generate the website.
- name: 'gcr.io/gvisor-website/hugo:0.53'
args: ["make"]
env: ['HUGO_ENV=production']
args: ["hugo"]
# Test the HTML for issues.
- name: 'gcr.io/gvisor-website/html-proofer:3.10.2'
args: ["htmlproofer", "--disable-external", "--check-html", "public/static"]
args:
- "htmlproofer"
- "--disable-external"
- "--check-html"
- "public/static"
# Deploy to App Engine only for master branch.
- name: 'gcr.io/cloud-builders/gcloud'
entrypoint: 'bash'
args:
args:
- '-c'
- 'if [[ "$PROJECT_ID" == "gvisor-website" && "$BRANCH_NAME" == "master" ]]; then gcloud app deploy public/app.yaml; fi'
- >
if [[ "$PROJECT_ID" == "gvisor-website" && "$BRANCH_NAME" == "master" ]]; then
gcloud app deploy public/app.yaml;
fi
203 changes: 203 additions & 0 deletions 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)
}
}
}
}
4 changes: 2 additions & 2 deletions cmd/gvisor-website/main.go
Expand Up @@ -37,7 +37,7 @@ var redirects = map[string]string{

// Redirects to compatibility docs.
"/c": "/docs/user_guide/compatibility",
"/c/linux/amd64": "/docs/user_guide/compatibility/amd64",
"/c/linux/amd64": "/docs/user_guide/compatibility/linux/amd64",

// Deprecated, but links continue to work.
"/cl": "https://gvisor-review.googlesource.com",
Expand All @@ -49,7 +49,7 @@ var prefixHelpers = map[string]string{
"pr": "https://github.com/google/gvisor/pull/%s",

// Redirects to compatibility docs.
"c/linux/amd64": "/docs/user_guide/compatibility/amd64/#%s",
"c/linux/amd64": "/docs/user_guide/compatibility/linux/amd64/#%s",

// Deprecated, but links continue to work.
"cl": "https://gvisor-review.googlesource.com/c/gvisor/+/%s",
Expand Down

0 comments on commit 6714bee

Please sign in to comment.