forked from princjef/gomarkdoc
/
output.go
158 lines (125 loc) · 3.47 KB
/
output.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
package cmd
import (
"bytes"
"errors"
"fmt"
"io/ioutil"
"os"
"path/filepath"
"regexp"
"github.com/ag5denis/gomarkdoc"
"github.com/ag5denis/gomarkdoc/lang"
"github.com/ag5denis/gomarkdoc/logger"
)
// WriteOutput writes the Output of the documentation to the specified files.
func WriteOutput(specs []*PackageSpec, opts CommandOptions) error {
log := logger.New(GetLogLevel(opts.Verbosity))
overrides, err := ResolveOverrides(opts)
if err != nil {
return err
}
out, err := gomarkdoc.NewRenderer(overrides...)
if err != nil {
return err
}
header, err := ResolveHeader(opts)
if err != nil {
return err
}
footer, err := ResolveFooter(opts)
if err != nil {
return err
}
filePkgs := make(map[string][]*lang.Package)
for _, spec := range specs {
if spec.Pkg == nil {
continue
}
filePkgs[spec.OutputFile] = append(filePkgs[spec.OutputFile], spec.Pkg)
}
for fileName, pkgs := range filePkgs {
file := lang.NewFile(header, footer, pkgs)
text, err := out.File(file)
if err != nil {
return err
}
if opts.Embed && fileName != "" {
text = EmbedContents(log, fileName, text)
}
switch {
case fileName == "":
fmt.Fprint(os.Stdout, text)
case opts.Check:
var b bytes.Buffer
fmt.Fprint(&b, text)
if err := CheckFile(&b, fileName); err != nil {
return err
}
default:
if err := WriteFile(fileName, text); err != nil {
return fmt.Errorf("failed to write Output file %s: %w", fileName, err)
}
}
}
return nil
}
// WriteFile writes the specified text to the specified file.
func WriteFile(fileName string, text string) error {
folder := filepath.Dir(fileName)
if folder != "" {
if err := os.MkdirAll(folder, 0755); err != nil {
return fmt.Errorf("failed to create folder %s: %w", folder, err)
}
}
if err := ioutil.WriteFile(fileName, []byte(text), 0664); err != nil {
return fmt.Errorf("failed to write file %s: %w", fileName, err)
}
return nil
}
func CheckFile(b *bytes.Buffer, path string) error {
checkErr := errors.New("Output does not match current files. Did you forget to run gomarkdoc?")
f, err := os.Open(path)
if err != nil {
if err == os.ErrNotExist {
return checkErr
}
return fmt.Errorf("failed to open file %s for checking: %w", path, err)
}
defer f.Close()
match, err := Compare(b, f)
if err != nil {
return fmt.Errorf("failure while attempting to Check contents of %s: %w", path, err)
}
if !match {
return checkErr
}
return nil
}
var (
embedStandaloneRegex = regexp.MustCompile(`(?m:^ *)<!--\s*gomarkdoc:Embed\s*-->(?m:\s*?$)`)
embedStartRegex = regexp.MustCompile(
`(?m:^ *)<!--\s*gomarkdoc:Embed:start\s*-->(?s:.*?)<!--\s*gomarkdoc:Embed:end\s*-->(?m:\s*?$)`,
)
)
func EmbedContents(log logger.Logger, fileName string, text string) string {
embedText := fmt.Sprintf("<!-- gomarkdoc:Embed:start -->\n\n%s\n\n<!-- gomarkdoc:Embed:end -->", text)
data, err := os.ReadFile(fileName)
if err != nil {
log.Debugf("unable to find Output file %s for embedding. Creating a new file instead", fileName)
return embedText
}
var replacements int
data = embedStandaloneRegex.ReplaceAllFunc(data, func(_ []byte) []byte {
replacements++
return []byte(embedText)
})
data = embedStartRegex.ReplaceAllFunc(data, func(_ []byte) []byte {
replacements++
return []byte(embedText)
})
if replacements == 0 {
log.Debugf("no Embed markers found. Appending documentation to the end of the file instead")
return fmt.Sprintf("%s\n\n%s", string(data), text)
}
return string(data)
}