diff --git a/CHANGELOG.md b/CHANGELOG.md index db431233..c9ab323f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ### Features * Adds CLI flag `--strict` to break with an error instead of warnings (#68) +* Adds CLI flag `--dry-run` to run without file output (#71) * Checks package re-exports, giving warning or error on fail (#68) * Allows for cross-refs to aliases in modules and structs (#69) diff --git a/README.md b/README.md index 7a687773..16edab8e 100644 --- a/README.md +++ b/README.md @@ -56,17 +56,18 @@ Usage: modo OUT-PATH [flags] Examples: - modo docs -i docs.json # from a file + modo docs -i docs.json # from a file mojo doc ./src | modo docs # from 'mojo doc' Flags: - -i, --input string 'mojo doc' JSON file to process. Reads from STDIN if not specified. + -i, --input string 'mojo doc' JSON file to process. Reads from STDIN if not specified. -f, --format string Output format. One of (plain|mdbook|hugo). (default "plain") -e, --exports Process according to 'Exports:' sections in packages. --short-links Render shortened link labels, stripping packages and modules. - --case-insensitive Build for systems that are not case-sensitive regarding file names. + --case-insensitive Build for systems that are not case-sensitive regarding file names. Appends hyphen (-) to capitalized file names. - -s, --strict Strict mode. Errors instead of warnings. + --strict Strict mode. Errors instead of warnings. + --dry-run Dry-run without any file output. -t, --templates strings Optional directories with templates for (partial) overwrite. See folder assets/templates in the repository. -h, --help help for modo diff --git a/document/processor.go b/document/processor.go index 6b6cbcb3..8918cce0 100644 --- a/document/processor.go +++ b/document/processor.go @@ -8,6 +8,17 @@ import ( "text/template" ) +type Config struct { + InputFile string + OutputDir string + TemplateDirs []string + UseExports bool + ShortLinks bool + CaseInsensitive bool + Strict bool + DryRun bool +} + type Processor struct { Config *Config Template *template.Template @@ -26,7 +37,7 @@ func NewProcessor(docs *Docs, f Formatter, t *template.Template, config *Config) }) } -func NewProcessorWithWriter(docs *Docs, f Formatter, t *template.Template, config *Config, writer func(text, file string) error) *Processor { +func NewProcessorWithWriter(docs *Docs, f Formatter, t *template.Template, config *Config, writer func(file, text string) error) *Processor { return &Processor{ Config: config, Template: t, @@ -86,3 +97,13 @@ func (proc *Processor) addElementPath(elPath, filePath []string, kind string, is proc.allPaths[strings.Join(elPath, ".")] = true _, _ = filePath, kind } + +func (proc *Processor) mkDirs(path string) error { + if proc.Config.DryRun { + return nil + } + if err := os.MkdirAll(path, os.ModePerm); err != nil && !os.IsExist(err) { + return err + } + return nil +} diff --git a/document/render.go b/document/render.go index 7477a8d4..36383777 100644 --- a/document/render.go +++ b/document/render.go @@ -1,6 +1,7 @@ package document import ( + "fmt" "io/fs" "os" "path" @@ -11,26 +12,35 @@ import ( "github.com/mlange-42/modo/assets" ) -type Config struct { - OutputDir string - TemplateDirs []string - UseExports bool - ShortLinks bool - CaseSensitive bool - Strict bool -} - func Render(docs *Docs, config *Config, form Formatter) error { t, err := loadTemplates(form, config.TemplateDirs...) if err != nil { return err } - proc := NewProcessor(docs, form, t, config) - return renderWith(config, proc) + if !config.DryRun { + proc := NewProcessor(docs, form, t, config) + return renderWith(config, proc) + } + + files := []string{} + proc := NewProcessorWithWriter(docs, form, t, config, func(file, text string) error { + files = append(files, file) + return nil + }) + err = renderWith(config, proc) + if err != nil { + return err + } + + fmt.Println("Dry-run. Would write these files:") + for _, f := range files { + fmt.Println(f) + } + return nil } func renderWith(config *Config, proc *Processor) error { - caseSensitiveSystem = config.CaseSensitive + caseSensitiveSystem = !config.CaseInsensitive if err := proc.PrepareDocs(); err != nil { return err } @@ -58,7 +68,7 @@ func renderElement(data interface { func renderPackage(p *Package, dir []string, proc *Processor) error { newDir := appendNew(dir, p.GetFileName()) pkgPath := path.Join(newDir...) - if err := mkDirs(pkgPath); err != nil { + if err := proc.mkDirs(pkgPath); err != nil { return err } @@ -97,7 +107,7 @@ func renderPackage(p *Package, dir []string, proc *Processor) error { func renderModule(mod *Module, dir []string, proc *Processor) error { newDir := appendNew(dir, mod.GetFileName()) - if err := mkDirs(path.Join(newDir...)); err != nil { + if err := proc.mkDirs(path.Join(newDir...)); err != nil { return err } @@ -210,10 +220,3 @@ func linkAndWrite(text string, dir []string, modElems int, kind string, proc *Pr } return proc.WriteFile(outFile, text) } - -func mkDirs(path string) error { - if err := os.MkdirAll(path, os.ModePerm); err != nil && !os.IsExist(err) { - return err - } - return nil -} diff --git a/format/mdbook.go b/format/mdbook.go index 117f47a5..d762ff57 100644 --- a/format/mdbook.go +++ b/format/mdbook.go @@ -27,10 +27,10 @@ func (f *MdBookFormatter) WriteAuxiliary(p *document.Package, dir string, proc * if err := f.writeSummary(p, dir, proc); err != nil { return err } - if err := f.writeToml(p, dir, proc.Template); err != nil { + if err := f.writeToml(p, dir, proc); err != nil { return err } - if err := f.writeCss(dir); err != nil { + if err := f.writeCss(dir, proc); err != nil { return err } return nil @@ -62,6 +62,9 @@ func (f *MdBookFormatter) writeSummary(p *document.Package, dir string, proc *do return err } summaryPath := path.Join(dir, p.GetFileName(), "SUMMARY.md") + if proc.Config.DryRun { + return nil + } if err := os.WriteFile(summaryPath, []byte(summary), 0666); err != nil { return err } @@ -205,11 +208,14 @@ func (f *MdBookFormatter) renderModuleMember(mem document.Named, pathStr string, return nil } -func (f *MdBookFormatter) writeToml(p *document.Package, dir string, t *template.Template) error { - toml, err := f.renderToml(p, t) +func (f *MdBookFormatter) writeToml(p *document.Package, dir string, proc *document.Processor) error { + toml, err := f.renderToml(p, proc.Template) if err != nil { return err } + if proc.Config.DryRun { + return nil + } tomlPath := path.Join(dir, "book.toml") if err := os.WriteFile(tomlPath, []byte(toml), 0666); err != nil { return err @@ -225,17 +231,21 @@ func (f *MdBookFormatter) renderToml(p *document.Package, t *template.Template) return b.String(), nil } -func (f *MdBookFormatter) writeCss(dir string) error { +func (f *MdBookFormatter) writeCss(dir string, proc *document.Processor) error { cssDir := path.Join(dir, "css") - if err := os.MkdirAll(cssDir, os.ModePerm); err != nil && !os.IsExist(err) { - return err + if !proc.Config.DryRun { + if err := os.MkdirAll(cssDir, os.ModePerm); err != nil && !os.IsExist(err) { + return err + } } css, err := fs.ReadFile(assets.CSS, "css/mdbook.css") if err != nil { return err } - if err := os.WriteFile(path.Join(cssDir, "custom.css"), css, 0666); err != nil { - return err + if !proc.Config.DryRun { + if err := os.WriteFile(path.Join(cssDir, "custom.css"), css, 0666); err != nil { + return err + } } return nil } diff --git a/main.go b/main.go index ef7dd270..622c5992 100644 --- a/main.go +++ b/main.go @@ -21,19 +21,9 @@ func main() { fmt.Printf("Completed in %.1fms 🧯\n", float64(time.Since(start).Microseconds())/1000.0) } -type args struct { - file string - renderFormat string - caseInsensitive bool - useExports bool - shortLinks bool - strict bool - outDir string - templateDirs []string -} - func rootCommand() *cobra.Command { - var cliArgs args + var cliArgs document.Config + var renderFormat string root := &cobra.Command{ Use: "modo OUT-PATH", @@ -46,18 +36,19 @@ Modo generates Markdown for static site generators (SSGs) from 'mojo doc' JSON o Args: cobra.ExactArgs(1), SilenceUsage: true, RunE: func(cmd *cobra.Command, args []string) error { - cliArgs.outDir = args[0] - return run(&cliArgs) + cliArgs.OutputDir = args[0] + return run(&cliArgs, renderFormat) }, } - root.Flags().StringVarP(&cliArgs.file, "input", "i", "", "'mojo doc' JSON file to process. Reads from STDIN if not specified.") - root.Flags().StringVarP(&cliArgs.renderFormat, "format", "f", "plain", "Output format. One of (plain|mdbook|hugo).") - root.Flags().BoolVarP(&cliArgs.useExports, "exports", "e", false, "Process according to 'Exports:' sections in packages.") - root.Flags().BoolVar(&cliArgs.shortLinks, "short-links", false, "Render shortened link labels, stripping packages and modules.") - root.Flags().BoolVar(&cliArgs.caseInsensitive, "case-insensitive", false, "Build for systems that are not case-sensitive regarding file names.\nAppends hyphen (-) to capitalized file names.") - root.Flags().BoolVarP(&cliArgs.strict, "strict", "s", false, "Strict mode. Errors instead of warnings.") - root.Flags().StringSliceVarP(&cliArgs.templateDirs, "templates", "t", []string{}, "Optional directories with templates for (partial) overwrite.\nSee folder assets/templates in the repository.") + root.Flags().StringVarP(&cliArgs.InputFile, "input", "i", "", "'mojo doc' JSON file to process. Reads from STDIN if not specified.") + root.Flags().StringVarP(&renderFormat, "format", "f", "plain", "Output format. One of (plain|mdbook|hugo).") + root.Flags().BoolVarP(&cliArgs.UseExports, "exports", "e", false, "Process according to 'Exports:' sections in packages.") + root.Flags().BoolVar(&cliArgs.ShortLinks, "short-links", false, "Render shortened link labels, stripping packages and modules.") + root.Flags().BoolVar(&cliArgs.CaseInsensitive, "case-insensitive", false, "Build for systems that are not case-sensitive regarding file names.\nAppends hyphen (-) to capitalized file names.") + root.Flags().BoolVar(&cliArgs.Strict, "strict", false, "Strict mode. Errors instead of warnings.") + root.Flags().BoolVar(&cliArgs.DryRun, "dry-run", false, "Dry-run without any file output.") + root.Flags().StringSliceVarP(&cliArgs.TemplateDirs, "templates", "t", []string{}, "Optional directories with templates for (partial) overwrite.\nSee folder assets/templates in the repository.") root.Flags().SortFlags = false root.MarkFlagFilename("input", "json") @@ -66,29 +57,22 @@ Modo generates Markdown for static site generators (SSGs) from 'mojo doc' JSON o return root } -func run(args *args) error { - if args.outDir == "" { +func run(args *document.Config, renderFormat string) error { + if args.OutputDir == "" { return fmt.Errorf("no output path given") } - docs, err := readDocs(args.file) + docs, err := readDocs(args.InputFile) if err != nil { return err } - rFormat, err := format.GetFormat(args.renderFormat) + rFormat, err := format.GetFormat(renderFormat) if err != nil { return err } formatter := format.GetFormatter(rFormat) - err = formatter.Render(docs, &document.Config{ - OutputDir: args.outDir, - TemplateDirs: args.templateDirs, - UseExports: args.useExports, - ShortLinks: args.shortLinks, - CaseSensitive: !args.caseInsensitive, - Strict: args.strict, - }) + err = formatter.Render(docs, args) if err != nil { return err }