Skip to content

Commit d5c34b8

Browse files
committed
add generator
1 parent c7daefb commit d5c34b8

File tree

4 files changed

+192
-1
lines changed

4 files changed

+192
-1
lines changed

Dockerfile

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
#syntax=docker/dockerfile:1
22

33
ARG GO_VERSION=1.24.4
4+
ARG ALPINE_VERSION=3.21
5+
ARG DOCS_FORMATS="md,yaml"
46

57
FROM --platform=${BUILDPLATFORM} golangci/golangci-lint:v2.1.6-alpine AS lint-base
68

@@ -129,3 +131,45 @@ EOF
129131
RUN chmod +x /run.sh
130132
ENV PORT=8080
131133
ENTRYPOINT ["/run.sh"]
134+
135+
FROM --platform=${BUILDPLATFORM} golang:${GO_VERSION}-alpine${ALPINE_VERSION} AS alpine
136+
RUN apk add --no-cache rsync git
137+
ENV CGO_ENABLED=0
138+
WORKDIR /src
139+
140+
FROM alpine AS docs-gen
141+
WORKDIR /src
142+
RUN --mount=target=. \
143+
--mount=target=/root/.cache,type=cache \
144+
go build -mod=vendor -o /out/docsgen ./docs/generator/generate.go
145+
146+
FROM alpine AS docs-build
147+
COPY --from=docs-gen /out/docsgen /usr/bin
148+
ENV DOCKER_CLI_PLUGIN_ORIGINAL_CLI_COMMAND="mcp"
149+
ARG DOCS_FORMATS
150+
RUN --mount=target=/context \
151+
--mount=target=.,type=tmpfs <<EOT
152+
set -e
153+
rsync -a /context/. .
154+
docsgen --formats "$DOCS_FORMATS" --source "docs/generator/reference"
155+
mkdir /out
156+
cp -r docs/generator/reference/* /out/
157+
EOT
158+
159+
FROM scratch AS docs-update
160+
COPY --from=docs-build /out /
161+
162+
FROM docs-build AS docs-validate
163+
RUN --mount=target=/context \
164+
--mount=target=.,type=tmpfs <<EOT
165+
set -e
166+
rsync -a /context/. .
167+
git add -A
168+
rm -rf docs/generator/reference/*
169+
cp -rf /out/* ./docs/generator/reference/
170+
if [ -n "$(git status --porcelain -- docs/generator/reference)" ]; then
171+
echo >&2 'ERROR: Docs result differs. Please update with "make docs"'
172+
git status --porcelain -- docs/generator/reference
173+
exit 1
174+
fi
175+
EOT

Makefile

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,13 @@ docker-mcp-cross:
3434
docker-mcp-%:
3535
docker buildx build $(DOCKER_BUILD_ARGS) --target=package-docker-mcp --platform=$*/amd64,$*/arm64 -o ./dist .
3636

37+
docs:
38+
$(eval $@_TMP_OUT := $(shell mktemp -d -t mcp-cli-output.XXXXXXXXXX))
39+
docker buildx bake --set "*.output=type=local,dest=$($@_TMP_OUT)" update-docs
40+
rm -rf ./docs/generator/reference/*
41+
cp -R "$($@_TMP_OUT)"/* ./docs/generator/reference/
42+
rm -rf "$($@_TMP_OUT)"/*
43+
3744
push-module-image:
3845
cp -r dist ./module-image
3946
docker buildx build --push --platform=linux/amd64,linux/arm64,darwin/amd64,darwin/arm64,windows/amd64,windows/arm64 --build-arg TAG=$(TAG) --tag=docker/docker-mcp-cli-desktop-module:$(TAG) ./module-image
@@ -70,4 +77,4 @@ push-l7proxy-image:
7077
push-dns-forwarder-image:
7178
docker buildx bake dns-forwarder --push
7279

73-
.PHONY: format lint clean docker-mcp-cross push-module-image mcp-package test docker-mcp push-mcp-gateway push-l4proxy-image push-l7proxy-image push-dns-forwarder-image
80+
.PHONY: format lint clean docker-mcp-cross push-module-image mcp-package test docker-mcp push-mcp-gateway push-l4proxy-image push-l7proxy-image push-dns-forwarder-image docs

docker-bake.hcl

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,17 @@
1+
variable "GO_VERSION" {
2+
default = null
3+
}
4+
5+
target "_common" {
6+
args = {
7+
GO_VERSION = GO_VERSION
8+
BUILDKIT_CONTEXT_KEEP_GIT_DIR = 1
9+
}
10+
}
11+
12+
variable "DOCS_FORMATS" {
13+
default = "md,yaml"
14+
}
115

216
group default {
317
targets = [
@@ -13,6 +27,7 @@ group all {
1327
"l4proxy",
1428
"l7proxy",
1529
"dns-forwarder",
30+
"validate-docs",
1631
]
1732
}
1833

@@ -76,4 +91,22 @@ target mcp-gateway-dind {
7691
output = [
7792
"type=image,name=docker/mcp-gateway:dind",
7893
]
94+
}
95+
96+
target "validate-docs" {
97+
inherits = ["_common"]
98+
args = {
99+
DOCS_FORMATS = DOCS_FORMATS
100+
}
101+
target = "docs-validate"
102+
output = ["type=cacheonly"]
103+
}
104+
105+
target "update-docs" {
106+
inherits = ["_common"]
107+
args = {
108+
DOCS_FORMATS = DOCS_FORMATS
109+
}
110+
target = "docs-update"
111+
output = ["./docs/generator/reference"]
79112
}

docs/generator/generate.go

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
package main
2+
3+
import (
4+
"log"
5+
"os"
6+
"strings"
7+
8+
clidocstool "github.com/docker/cli-docs-tool"
9+
"github.com/docker/cli/cli/command"
10+
"github.com/docker/mcp-gateway/cmd/docker-mcp"
11+
"github.com/pkg/errors"
12+
"github.com/spf13/cobra"
13+
"github.com/spf13/pflag"
14+
)
15+
16+
const defaultSourcePath = "/reference/"
17+
18+
type options struct {
19+
source string
20+
formats []string
21+
}
22+
23+
func gen(opts *options) error {
24+
log.SetFlags(0)
25+
26+
dockerCLI, err := command.NewDockerCli()
27+
if err != nil {
28+
return err
29+
}
30+
cmd := &cobra.Command{
31+
Use: "docker [OPTIONS] COMMAND [ARG...]",
32+
Short: "The base command for the Docker CLI.",
33+
DisableAutoGenTag: true,
34+
}
35+
36+
cmd.AddCommand(commands.NewRootCmd(dockerCLI))
37+
38+
c, err := clidocstool.New(clidocstool.Options{
39+
Root: cmd,
40+
SourceDir: opts.source,
41+
Plugin: true,
42+
})
43+
if err != nil {
44+
return err
45+
}
46+
47+
for _, format := range opts.formats {
48+
switch format {
49+
case "md":
50+
if err = c.GenMarkdownTree(cmd); err != nil {
51+
return err
52+
}
53+
case "yaml":
54+
fixUpExperimentalCLI(cmd)
55+
if err = c.GenYamlTree(cmd); err != nil {
56+
return err
57+
}
58+
default:
59+
return errors.Errorf("unknown format %q", format)
60+
}
61+
}
62+
63+
return nil
64+
}
65+
66+
func run() error {
67+
opts := &options{}
68+
flags := pflag.NewFlagSet(os.Args[0], pflag.ContinueOnError)
69+
flags.StringVar(&opts.source, "source", defaultSourcePath, "Docs source folder")
70+
flags.StringSliceVar(&opts.formats, "formats", []string{}, "Format (md, yaml)")
71+
if err := flags.Parse(os.Args[1:]); err != nil {
72+
return err
73+
}
74+
if len(opts.formats) == 0 {
75+
return errors.New("Docs format required")
76+
}
77+
return gen(opts)
78+
}
79+
80+
func main() {
81+
if err := run(); err != nil {
82+
log.Printf("ERROR: %+v", err)
83+
os.Exit(1)
84+
}
85+
}
86+
87+
// fixUpExperimentalCLI trims the " (EXPERIMENTAL)" suffix from the CLI output,
88+
// as docs.docker.com already displays "experimental (CLI)",
89+
//
90+
// https://github.com/docker/buildx/pull/2188#issuecomment-1889487022
91+
func fixUpExperimentalCLI(cmd *cobra.Command) {
92+
const (
93+
annotationExperimentalCLI = "experimentalCLI"
94+
suffixExperimental = " (EXPERIMENTAL)"
95+
)
96+
if _, ok := cmd.Annotations[annotationExperimentalCLI]; ok {
97+
cmd.Short = strings.TrimSuffix(cmd.Short, suffixExperimental)
98+
}
99+
cmd.Flags().VisitAll(func(f *pflag.Flag) {
100+
if _, ok := f.Annotations[annotationExperimentalCLI]; ok {
101+
f.Usage = strings.TrimSuffix(f.Usage, suffixExperimental)
102+
}
103+
})
104+
for _, c := range cmd.Commands() {
105+
fixUpExperimentalCLI(c)
106+
}
107+
}

0 commit comments

Comments
 (0)