Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

docs: move reference into its own chapter #382

Merged
merged 4 commits into from
Jul 6, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ status.json

# documentation
/docs/content/configuration/reference/index.md
/docs/content/reference/**/*.md
/docs/static/jsonschema
/public
.hugo_build.lock
Expand Down
96 changes: 0 additions & 96 deletions commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,22 @@ package main

import (
"crypto/rand"
_ "embed"
"encoding/base64"
"errors"
"fmt"
"io"
"regexp"
"slices"
"sort"
"strconv"
"strings"

"github.com/creativeprojects/clog"
"github.com/creativeprojects/resticprofile/config"
"github.com/creativeprojects/resticprofile/config/jsonschema"
"github.com/creativeprojects/resticprofile/constants"
"github.com/creativeprojects/resticprofile/platform"
"github.com/creativeprojects/resticprofile/remote"
"github.com/creativeprojects/resticprofile/restic"
"github.com/creativeprojects/resticprofile/schedule"
"github.com/creativeprojects/resticprofile/term"
"github.com/creativeprojects/resticprofile/util/templates"
"github.com/creativeprojects/resticprofile/win"
"golang.org/x/exp/maps"
)
Expand Down Expand Up @@ -201,97 +196,6 @@ func completeCommand(output io.Writer, ctx commandContext) error {
return nil
}

//go:embed contrib/completion/bash-completion.sh
var bashCompletionScript string

//go:embed contrib/completion/zsh-completion.sh
var zshCompletionScript string

func generateCommand(output io.Writer, ctx commandContext) (err error) {
args := ctx.request.arguments
// enforce no-log
logger := clog.GetDefaultLogger()
handler := logger.GetHandler()
logger.SetHandler(clog.NewDiscardHandler())

if slices.Contains(args, "--bash-completion") {
_, err = fmt.Fprintln(output, bashCompletionScript)
} else if slices.Contains(args, "--config-reference") {
err = generateConfigReference(output, args[slices.Index(args, "--config-reference")+1:])
} else if slices.Contains(args, "--json-schema") {
err = generateJsonSchema(output, args[slices.Index(args, "--json-schema")+1:])
} else if slices.Contains(args, "--random-key") {
ctx.flags.resticArgs = args[slices.Index(args, "--random-key"):]
err = randomKey(output, ctx)
} else if slices.Contains(args, "--zsh-completion") {
_, err = fmt.Fprintln(output, zshCompletionScript)
} else {
err = fmt.Errorf("nothing to generate for: %s", strings.Join(args, ", "))
}

if err != nil {
logger.SetHandler(handler)
}
return
}

//go:embed contrib/templates/config-reference.gomd
var configReferenceTemplate string

func generateConfigReference(output io.Writer, args []string) (err error) {
resticVersion := restic.AnyVersion
if slices.Contains(args, "--version") {
args = args[slices.Index(args, "--version"):]
if len(args) > 1 {
resticVersion = args[1]
args = args[2:]
}
}

data := config.NewTemplateInfoData(resticVersion)
tpl := templates.New("config-reference", data.GetFuncs())

if len(args) > 0 {
tpl, err = tpl.ParseFiles(args...)
} else {
tpl, err = tpl.Parse(configReferenceTemplate)
}

if err != nil {
err = fmt.Errorf("parsing failed: %w", err)
} else {
err = tpl.Execute(output, data)
}
return
}

func generateJsonSchema(output io.Writer, args []string) (err error) {
resticVersion := restic.AnyVersion
if slices.Contains(args, "--version") {
args = args[slices.Index(args, "--version"):]
if len(args) > 1 {
resticVersion = args[1]
args = args[2:]
}
}

version := config.Version02
if len(args) > 0 && args[0] == "v1" {
version = config.Version01
}

return jsonschema.WriteJsonSchema(version, resticVersion, output)
}

func sortedProfileKeys(data map[string]*config.Profile) []string {
keys := make([]string, 0, len(data))
for key := range data {
keys = append(keys, key)
}
sort.Strings(keys)
return keys
}

func showProfile(output io.Writer, ctx commandContext) error {
c := ctx.config
flags := ctx.flags
Expand Down
9 changes: 9 additions & 0 deletions commands_display.go
Original file line number Diff line number Diff line change
Expand Up @@ -322,6 +322,15 @@ func displayGroups(output io.Writer, configuration *config.Config, flags command
out("\n")
}

func sortedProfileKeys(data map[string]*config.Profile) []string {
keys := make([]string, 0, len(data))
for key := range data {
keys = append(keys, key)
}
sort.Strings(keys)
return keys
}

// lineLengthWriter limits the max line length, adding line breaks ('\n') as needed.
// the writer detects the right most column (consecutive whitespace) and aligns content if possible.
type lineLengthWriter struct {
Expand Down
180 changes: 180 additions & 0 deletions commands_generate.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
package main

import (
"embed"
"fmt"
"io"
"io/fs"
"os"
"path/filepath"
"slices"
"strings"
"text/template"

"github.com/creativeprojects/clog"
"github.com/creativeprojects/resticprofile/config"
"github.com/creativeprojects/resticprofile/config/jsonschema"
"github.com/creativeprojects/resticprofile/restic"
"github.com/creativeprojects/resticprofile/util/templates"
)

//go:embed contrib/completion/bash-completion.sh
var bashCompletionScript string

//go:embed contrib/completion/zsh-completion.sh
var zshCompletionScript string

func generateCommand(output io.Writer, ctx commandContext) (err error) {
args := ctx.request.arguments
// enforce no-log
logger := clog.GetDefaultLogger()
handler := logger.GetHandler()
logger.SetHandler(clog.NewDiscardHandler())

if slices.Contains(args, "--bash-completion") {
_, err = fmt.Fprintln(output, bashCompletionScript)
} else if slices.Contains(args, "--config-reference") {
err = generateConfigReference(output, args[slices.Index(args, "--config-reference")+1:])
} else if slices.Contains(args, "--json-schema") {
err = generateJsonSchema(output, args[slices.Index(args, "--json-schema")+1:])
} else if slices.Contains(args, "--random-key") {
ctx.flags.resticArgs = args[slices.Index(args, "--random-key"):]
err = randomKey(output, ctx)
} else if slices.Contains(args, "--zsh-completion") {
_, err = fmt.Fprintln(output, zshCompletionScript)
} else {
err = fmt.Errorf("nothing to generate for: %s", strings.Join(args, ", "))
}

if err != nil {
logger.SetHandler(handler)
}
return
}

//go:embed contrib/templates/*
var configReferenceTemplates embed.FS

func generateConfigReference(output io.Writer, args []string) error {
resticVersion := restic.AnyVersion
if slices.Contains(args, "--version") {
args = args[slices.Index(args, "--version"):]
if len(args) > 1 {
resticVersion = args[1]
args = args[2:]
}
}

data := config.NewTemplateInfoData(resticVersion)
tpl := templates.New("config-reference", data.GetFuncs())
templates, err := fs.Sub(configReferenceTemplates, "contrib/templates")
if err != nil {
return fmt.Errorf("cannot load templates: %w", err)
}

if len(args) > 0 {
tpl, err = tpl.ParseFiles(args...)
} else {
tpl, err = tpl.ParseFS(templates, "*.gomd")
}

if err != nil {
return fmt.Errorf("parsing failed: %w", err)
}

staticPages := []struct {
templateName string
fileName string
}{
{"reference.gomd", "_index.md"},
{"global.gomd", "global.md"},
{"profile.gomd", "profile/_index.md"},
{"nested.gomd", "nested/_index.md"},
{"groups.gomd", "groups.md"},
{"value-types.gomd", "value-types.md"},
{"json-schema.gomd", "json-schema.md"},
}

for _, staticPage := range staticPages {
fmt.Fprintf(output, "generating %s...\n", staticPage.templateName)
err = generatePage(tpl, data, staticPage.fileName, staticPage.templateName)
if err != nil {
return fmt.Errorf("unable to generate page %s: %w", staticPage.fileName, err)
}
}

weight := 1
for _, profileSection := range data.ProfileSections() {
fmt.Fprintf(output, "generating profile section %s (weight %d)...\n", profileSection.Name(), weight)
sectionData := SectionInfoData{
DefaultData: data.DefaultData,
Section: profileSection,
Weight: weight,
}
err = generatePage(tpl, sectionData, filepath.Join("profile", profileSection.Name()+".md"), "profile.sub-section.gomd")
if err != nil {
return fmt.Errorf("unable to generate profile section %s: %w", profileSection.Name(), err)
}
weight++
}

weight = 1
for _, nestedSection := range data.NestedSections() {
fmt.Fprintf(output, "generating nested section %s (weight %d)...\n", nestedSection.Name(), weight)
sectionData := SectionInfoData{
DefaultData: data.DefaultData,
Section: nestedSection,
Weight: weight,
}
err = generatePage(tpl, sectionData, filepath.Join("nested", nestedSection.Name()+".md"), "profile.nested-section.gomd")
if err != nil {
return fmt.Errorf("unable to generate nested section %s: %w", nestedSection.Name(), err)
}
weight++
}
return nil
}

func generatePage(tpl *template.Template, data any, fileName, templateName string) error {
fullname := filepath.Join("docs/content/reference", fileName)
err := os.MkdirAll(filepath.Dir(fullname), 0o755)
if err != nil {
return fmt.Errorf("cannot create directory: %w", err)
}
file, err := os.Create(fullname)
if err != nil {
return fmt.Errorf("cannot open file: %w", err)
}
defer file.Close()

err = tpl.ExecuteTemplate(file, templateName, data)
if err != nil {
return fmt.Errorf("cannot execute template: %w", err)
}
return nil
}

func generateJsonSchema(output io.Writer, args []string) (err error) {
resticVersion := restic.AnyVersion
if slices.Contains(args, "--version") {
args = args[slices.Index(args, "--version"):]
if len(args) > 1 {
resticVersion = args[1]
args = args[2:]
}
}

version := config.Version02
if len(args) > 0 && args[0] == "v1" {
version = config.Version01
}

return jsonschema.WriteJsonSchema(version, resticVersion, output)
}

// SectionInfoData is used as data for go templates that render profile section references
type SectionInfoData struct {
templates.DefaultData
Section config.SectionInfo
Weight int
}
Loading
Loading