Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
dadgar committed Mar 4, 2024
1 parent 71bd667 commit 8e9831a
Show file tree
Hide file tree
Showing 5 changed files with 240 additions and 13 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,6 @@ tmp/

# bin/ directory
bin/*

# web-docs/ directory
web-docs/*
6 changes: 6 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,12 @@ build: ## Build the HCP CLI binary
screenshot: go/install ## Create a screenshot of the HCP CLI
@go run github.com/homeport/termshot/cmd/[email protected] -c -f assets/hcp.png -- hcp

.PHONY: gen/docs
gen/docs: build ## Generate the HCP CLI documentation
@mkdir -p web-docs
@rm -rf web-docs/*
@./bin/gendocs -output-dir web-docs/

.PHONY: go/install
go/install: ## Install the HCP CLI binary
@go install
Expand Down
68 changes: 68 additions & 0 deletions cmd/gendocs/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package main

import (
"context"
"flag"
"fmt"
"os"

"github.com/hashicorp/hcp/internal/commands/hcp"
"github.com/hashicorp/hcp/internal/pkg/cmd"
"github.com/hashicorp/hcp/internal/pkg/format"
"github.com/hashicorp/hcp/internal/pkg/iostreams"
"github.com/hashicorp/hcp/internal/pkg/profile"
)

func main() {
if err := run(); err != nil {
fmt.Fprintf(os.Stderr, "%v\n", err)
os.Exit(1)
}
}

func run() error {
// Define the flags
var outputDir string
var linkPrefix string

flag.StringVar(&outputDir, "output-dir", "docs", "The output directory for the generated documentation")
flag.StringVar(&linkPrefix, "cmd-link-prefix", "hcp/docs/cli/commands/", "Link prefix for the commands")

// Parse the flags
flag.Parse()

// Create the command context
l, err := profile.NewLoader()
if err != nil {
return fmt.Errorf("failed to create profile loader: %v", err)
}

// Create the IO streams and configure for generating markdown
io, err := iostreams.System(context.Background())
if err != nil {
return fmt.Errorf("failed to create IO streams: %v", err)
}
io.ForceNoColor()

ctx := &cmd.Context{
IO: io,
Profile: l.DefaultProfile(),
Output: format.New(io),
ShutdownCtx: context.Background(),
}

// Get the root command
rootCmd := hcp.NewCmdHcp(ctx)

// Create the link handler
linkHandler := func(cmd string) string {
return linkPrefix + cmd
}

// Generate the markdown
if err := cmd.GenMarkdownTree(rootCmd, outputDir, linkHandler); err != nil {
return fmt.Errorf("failed to generate markdown: %v", err)
}

return nil
}
37 changes: 24 additions & 13 deletions internal/pkg/cmd/command_internal.go
Original file line number Diff line number Diff line change
Expand Up @@ -172,19 +172,10 @@ func (c *Command) help() string {

// Print any available aliases
if len(c.Aliases) > 0 {
aliases := make([]string, len(c.Aliases))
for i, a := range c.Aliases {
var useline string
if c.hasParent() {
useline = c.parent.commandPath() + " " + a
} else {
useline = a
}
if c.RunF == nil {
useline += " <command>"
}

aliases[i] = fmt.Sprintf("%s - %s", a, useline)
usages := c.aliasUsages()
var aliases []string
for a, u := range usages {
aliases = append(aliases, fmt.Sprintf("%s - %s", a, u))
}

helpEntries = append(helpEntries, helpEntry{"ALIASES", strings.Join(aliases, "\n")})
Expand Down Expand Up @@ -387,6 +378,26 @@ func (a PositionalArgument) text(cs *iostreams.ColorScheme) string {
return buf.String()
}

// aliasUsages returns a map from the alias to its usage
func (c *Command) aliasUsages() map[string]string {
aliases := make(map[string]string)
for _, a := range c.Aliases {
var useline string
if c.hasParent() {
useline = c.parent.commandPath() + " " + a
} else {
useline = a
}
if c.RunF == nil {
useline += " <command>"
}

aliases[a] = useline
}

return aliases
}

// usageHelp returns the short usage help that displays the commands usage and
// flags.
func (c *Command) usageHelp() string {
Expand Down
139 changes: 139 additions & 0 deletions internal/pkg/cmd/gen_md.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
package cmd

import (
"bytes"
"fmt"
"io"
"os"
"path/filepath"
"strings"
)

const markdownExtension = ".mdx"

// LinkHandler is a function that can be used to modify the links in the
// generated markdown. The path string is the unmodified path to the file.
type LinkHandler func(path string) string

func GenMarkdownTree(c *Command, dir string, link LinkHandler) error {
// Create the directory if it doesn't exist
if err := os.MkdirAll(dir, 0766); err != nil {
return err
}

// Determine the filename
filename := "index" + markdownExtension
if c.RunF != nil {
filename = c.Name + markdownExtension
}

// Create the file
f, err := os.Create(filepath.Join(dir, filename))
if err != nil {
return err
}
defer f.Close()

// Generate the markdown
if err := GenMarkdown(c, f, link); err != nil {
return err
}

for _, c := range c.children {
dir := dir
if len(c.children) > 0 {
dir = filepath.Join(dir, c.Name)
}

if err := GenMarkdownTree(c, dir, link); err != nil {
return err
}
}

return nil
}

// GenMarkdown creates custom markdown output.
func GenMarkdown(c *Command, w io.Writer, link LinkHandler) error {
cs := c.getIO().ColorScheme()

buf := new(bytes.Buffer)
name := c.commandPath()

buf.WriteString("---\n")
buf.WriteString(fmt.Sprintf("page_title: %s\n", name))
buf.WriteString(fmt.Sprintf("description: |-\n %s\n", c.ShortHelp))
buf.WriteString("---\n\n")

buf.WriteString("# " + name + "\n\n")

buf.WriteString("## Name\n\n")
buf.WriteString(fmt.Sprintf("%s - %s\n\n", name, c.ShortHelp))

buf.WriteString("## Usage\n\n")
buf.WriteString(fmt.Sprintf("```shell-session\n$ %s\n```\n\n", c.useLine()))

// Description
if len(c.LongHelp) > 0 {
buf.WriteString("## Description\n\n")
buf.WriteString(c.LongHelp + "\n\n")
}

// Aliases
if len(c.Aliases) > 0 {
buf.WriteString("## Aliases\n\n")
for a, u := range c.aliasUsages() {
buf.WriteString(fmt.Sprintf("%s - `%s`\n", a, u))
}
buf.WriteString("\n")
}

// Examples
if len(c.Examples) > 0 {
buf.WriteString("## Examples\n\n")

for _, e := range c.Examples {
buf.WriteString(fmt.Sprintf("%s\n\n", e.Preamble))
buf.WriteString(fmt.Sprintf("```shell-session\n%s\n```\n\n", e.Command))
}
}

// Children commands
if len(c.children) > 0 {
var commands, groups []string
for _, c := range c.children {
path := strings.ReplaceAll(c.commandPath(), " ", "/") + markdownExtension
entry := fmt.Sprintf("- [%s](%s) - %s", c.Name, link(path), c.ShortHelp)

if c.RunF != nil {
commands = append(commands, entry)
} else {
groups = append(groups, entry)
}
}
if len(groups) > 0 {
buf.WriteString("## Command Groups\n\n")
buf.WriteString(strings.Join(groups, "\n") + "\n\n")
}

if len(commands) > 0 {
buf.WriteString("## Commands\n\n")
buf.WriteString(strings.Join(commands, "\n") + "\n\n")
}
}

// Positional arguments
if len(c.Args.Args) > 0 {
buf.WriteString("## Positional Arguments\n\n")
buf.WriteString(fmt.Sprintf("%s", c.Args.text(cs)))
}

// TODO Print flags

// TODO Additional help

// TODO Print global flags. Handle being the root command

_, err := buf.WriteTo(w)
return err
}

0 comments on commit 8e9831a

Please sign in to comment.