Run all munges on all docs

Rather than terminating, Collect the errors and print them per-file-per-munge.
This commit is contained in:
Tim Hockin 2015-07-10 14:35:47 -07:00
parent 3f2ac7864b
commit 698b212491
2 changed files with 64 additions and 43 deletions

View File

@ -58,7 +58,7 @@ func checkLinks(filePath string, fileBytes []byte) ([]byte, error) {
if err != nil {
errors = append(
errors,
fmt.Sprintf("%v, link %q is unparsable: %v", filePath, linkText, err),
fmt.Sprintf("link %q is unparsable: %v", linkText, err),
)
return in
}
@ -74,7 +74,7 @@ func checkLinks(filePath string, fileBytes []byte) ([]byte, error) {
if !targetExists {
errors = append(
errors,
fmt.Sprintf("%v, %q: target not found\n", filePath, linkText),
fmt.Sprintf("%q: target not found", linkText),
)
}
u.Path = newPath

View File

@ -34,30 +34,32 @@ var (
ErrChangesNeeded = errors.New("mungedocs: changes required")
// All of the munge operations to perform.
// TODO: allow selection from command line. (e.g., just check links in the examples directory.)
mungesToMake = munges{
munger(updateTOC),
munger(checkLinks),
allMunges = []munge{
{"table-of-contents", updateTOC},
{"check-links", checkLinks},
}
)
// Munger processes a document, returning an updated document xor an error.
// Munger is NOT allowed to mutate 'before', if changes are needed it must copy
// data into a new byte array.
type munger func(filePath string, before []byte) (after []byte, err error)
type munges []munger
// a munge processes a document, returning an updated document xor an error.
// The fn is NOT allowed to mutate 'before', if changes are needed it must copy
// data into a new byte array and return that.
type munge struct {
name string
fn func(filePath string, before []byte) (after []byte, err error)
}
type fileProcessor struct {
// Which munge functions should we call?
munges munges
munges []munge
// Are we allowed to make changes?
verifyOnly bool
}
// Either change a file or verify that it needs no changes (according to modify argument)
func (f fileProcessor) visit(path string, i os.FileInfo, e error) error {
func (f fileProcessor) visit(path string) error {
if !strings.HasSuffix(path, ".md") {
return nil
}
@ -68,31 +70,55 @@ func (f fileProcessor) visit(path string, i os.FileInfo, e error) error {
}
modificationsMade := false
errFound := false
filePrinted := false
for _, munge := range f.munges {
after, err := munge(path, fileBytes)
if err != nil {
return err
}
if !modificationsMade {
if !bytes.Equal(after, fileBytes) {
modificationsMade = true
if f.verifyOnly {
// We're not allowed to make changes.
return ErrChangesNeeded
}
after, err := munge.fn(path, fileBytes)
if err != nil || !bytes.Equal(after, fileBytes) {
if !filePrinted {
fmt.Printf("%s\n----\n", path)
filePrinted = true
}
fmt.Printf("%s:\n", munge.name)
if err != nil {
fmt.Println(err)
errFound = true
} else {
fmt.Println("contents were modified")
modificationsMade = true
}
fmt.Println("")
}
fileBytes = after
}
// Write out new file with any changes.
if modificationsMade {
if f.verifyOnly {
// We're not allowed to make changes.
return ErrChangesNeeded
}
ioutil.WriteFile(path, fileBytes, 0644)
}
if errFound {
return ErrChangesNeeded
}
return nil
}
func newWalkFunc(fp *fileProcessor, changesNeeded *bool) filepath.WalkFunc {
return func(path string, info os.FileInfo, err error) error {
if err := fp.visit(path); err != nil {
*changesNeeded = true
if err != ErrChangesNeeded {
return err
}
}
return nil
}
}
func main() {
flag.Parse()
@ -102,30 +128,25 @@ func main() {
}
fp := fileProcessor{
munges: mungesToMake,
munges: allMunges,
verifyOnly: *verify,
}
// For each markdown file under source docs root, process the doc.
// If any error occurs, will exit with failure.
// If verify is true, then status is 0 for no changes needed, 1 for changes needed
// and >1 for an error during processing.
// If verify is false, then status is 0 if changes successfully made or no changes needed,
// 1 if changes were needed but require human intervention, and >1 for an unexpected
// error during processing.
err := filepath.Walk(*rootDir, fp.visit)
// - If any error occurs: exit with failure (exit >1).
// - If verify is true: exit 0 if no changes needed, exit 1 if changes
// needed.
// - If verify is false: exit 0 if changes successfully made or no
// changes needed.
var changesNeeded bool
err := filepath.Walk(*rootDir, newWalkFunc(&fp, &changesNeeded))
if err != nil {
if err == ErrChangesNeeded {
if *verify {
fmt.Fprintf(os.Stderr,
"Some changes needed but not made due to --verify=true\n")
} else {
fmt.Fprintf(os.Stderr,
"Some changes needed but human intervention is required\n")
}
os.Exit(1)
}
fmt.Fprintf(os.Stderr, "filepath.Walk() returned %v\n", err)
fmt.Fprintf(os.Stderr, "ERROR: %v\n", err)
os.Exit(2)
}
if changesNeeded && *verify {
fmt.Fprintf(os.Stderr, "FAIL: changes needed but not made due to --verify\n")
os.Exit(1)
}
}