Browse Source

remove comments as redundancy upon code

eliminate unneeded variables in tests

address test parallelism bugs

correct capitolization of error messsages (eg. remove capitols)

place proper logging and error tracking into the code
Casey DeLorme 8 years ago
parent
commit
ece5269de0
4 changed files with 69 additions and 154 deletions
  1. 29 97
      generator.go
  2. 36 46
      generator_test.go
  3. 0 10
      staticmd.go
  4. 4 1
      staticmd_test.go

+ 29 - 97
generator.go

@@ -35,14 +35,10 @@ type Generator struct {
 	template ht
 }
 
-// convert markdown input path to html output path
-// @note: we cannot reverse since we do not track the extension
-// we support `.md`, `.mkd`, and `.markdown`
 func (self *Generator) ior(path string) string {
 	return strings.TrimSuffix(strings.Replace(path, self.Input, self.Output, 1), filepath.Ext(path)) + ".html"
 }
 
-// for relative rendering generate relative depth string, or fallback to empty
 func (self *Generator) depth(path string) string {
 	if self.Relative {
 		if rel, err := filepath.Rel(filepath.Dir(path), self.Output); err == nil {
@@ -52,7 +48,6 @@ func (self *Generator) depth(path string) string {
 	return ""
 }
 
-// walk the directories and build a list of markdown files with content
 func (self *Generator) walk(path string, file os.FileInfo, err error) error {
 	if file != nil && file.Mode().IsRegular() && file.Size() > 0 && isMarkdown(path) {
 		self.pages = append(self.pages, path)
@@ -60,43 +55,25 @@ func (self *Generator) walk(path string, file os.FileInfo, err error) error {
 	return err
 }
 
-// build output concurrently to many pages
 func (self *Generator) multi() (err error) {
-
-	// prepare navigation storage
 	navi := make(map[string][]navigation)
+	var terr error
 
-	// loop pages to build table of contents
 	for i, _ := range self.pages {
-
-		// build output directory
 		out := self.ior(self.pages[i])
 		dir := filepath.Dir(self.ior(out))
-
-		// create navigation object
 		nav := navigation{}
 
-		// sub-index condition changes name, dir, and link
 		if filepath.Dir(out) != self.Output && strings.ToLower(basename(out)) == "index" {
-
-			// set name to containing folder
 			nav.Title = basename(dir)
-
-			// set relative or absolute link
 			if self.Relative {
 				nav.Link = filepath.Join(strings.TrimPrefix(dir, filepath.Dir(dir)+string(os.PathSeparator)), filepath.Base(out))
 			} else {
 				nav.Link = strings.TrimPrefix(dir, self.Output) + string(os.PathSeparator)
 			}
-
-			// update dir to dir of dir
 			dir = filepath.Dir(dir)
 		} else {
-
-			// set name to files name
 			nav.Title = basename(out)
-
-			// set relative or absolute link
 			if self.Relative {
 				nav.Link = strings.TrimPrefix(out, filepath.Dir(out)+string(os.PathSeparator))
 			} else {
@@ -104,37 +81,28 @@ func (self *Generator) multi() (err error) {
 			}
 		}
 
-		// build indexes first-match
 		if _, ok := navi[dir]; !ok {
 			navi[dir] = make([]navigation, 0)
-
-			// create output directory for when we create files
 			if ok, _ := exists(dir); !ok {
-				if err = mkdirall(dir, 0770); err != nil {
-					self.Logger.Error("Failed to create path: %s, %s", dir, err)
+				if e := mkdirall(dir, 0770); e != nil {
+					self.Logger.Error("failed to create path: %s, %s", dir, e)
+					terr = e
 				}
 			}
 		}
 
-		// append to navigational list
 		navi[dir] = append(navi[dir], nav)
 	}
 
-	// process all pages
 	for _, p := range self.pages {
-
-		// attempt to read entire document
 		var markdown []byte
 		if markdown, err = readfile(p); err != nil {
 			self.Logger.Error("failed to read file: %s, %s", p, err)
 			return
 		}
 
-		// acquire output filepath
 		out := self.ior(p)
 		dir := filepath.Dir(out)
-
-		// prepare a new page object for our template to render
 		page := page{
 			Name:    basename(p),
 			Version: self.version,
@@ -142,158 +110,122 @@ func (self *Generator) multi() (err error) {
 			Depth:   self.depth(out),
 		}
 
-		// if this page happens to be a sub-index we can generate the table of contents
 		if dir != self.Output && strings.ToLower(basename(p)) == "index" {
-
-			// iterate and build table of contents as basic markdown
 			toc := "\n## Table of Contents:\n\n"
 			for i, _ := range navi[dir] {
 				toc = toc + "- [" + navi[dir][i].Title + "](" + navi[dir][i].Link + ")\n"
 			}
-
-			// debug: table of contents output
 			self.Logger.Debug("table of contents for %s, %s", out, toc)
-
-			// prepend table of contents
 			markdown = append([]byte(toc), markdown...)
 		}
 
-		// convert to html, and accept as part of the template
 		page.Content = template.HTML(blackfriday.MarkdownCommon(markdown))
 
-		// attempt to open file for output
 		var f *os.File
 		if f, err = create(out); err != nil {
+			self.Logger.Error("%s\n", err)
 			return err
 		}
 		defer f.Close()
 
-		// prepare a writer /w buffer
 		fb := bufio.NewWriter(f)
 		defer fb.Flush()
 
-		// attempt to use template to write output with page context
-		err = self.template.Execute(fb, page)
+		if err = self.template.Execute(fb, page); err != nil {
+			self.Logger.Error("%s\n", err)
+		}
+	}
+
+	if err == nil {
+		err = terr
 	}
 
 	return
 }
 
-// build output synchronously to a single page
 func (self *Generator) single() (err error) {
-
-	// prepare []byte array to store all files markdown
 	content := make([]byte, 0)
-
-	// prepare a table-of-contents
 	toc := "\n"
-
 	previous_depth := 0
+	var terr error
 
-	// iterate and append all files contents
 	for _, p := range self.pages {
-
-		// shorthand
 		shorthand := strings.TrimPrefix(p, self.Input+string(os.PathSeparator))
-
-		// acquire depth
 		depth := strings.Count(shorthand, string(os.PathSeparator))
-
-		// if depth > previous depth then prepend with basename of dir for sub-section-headings
 		if depth > previous_depth {
 			toc = toc + strings.Repeat("\t", depth-1) + "- " + basename(filepath.Dir(p)) + "\n"
 		}
-
-		// prepare anchor text
 		anchor := strings.Replace(shorthand, string(os.PathSeparator), "-", -1)
-
-		// create new toc record
 		toc = toc + strings.Repeat("\t", depth) + "- [" + basename(p) + "](#" + anchor + ")\n"
 
-		// read markdown from file or skip to next file
-		var markdown []byte
-		markdown, err = readfile(p)
-		if err != nil {
-			self.Logger.Error("failed to read file: %s (%s)", p, err)
+		markdown, e := readfile(p)
+		if e != nil {
+			self.Logger.Error("failed to read file: %s (%s)", p, e)
+			terr = e
 			continue
 		}
 
-		// prepend anchor to content
 		markdown = append([]byte("\n<a id='"+anchor+"'/>\n\n"), markdown...)
-
-		// append a "back-to-top" anchor
 		markdown = append(markdown, []byte("\n[back to top](#top)\n\n")...)
-
-		// append to content
 		content = append(content, markdown...)
-
-		// update depth
 		previous_depth = depth
 	}
 
-	// prepend toc
 	content = append([]byte(toc), content...)
 
-	// prepare output directory
 	if ok, _ := exists(self.Output); !ok {
 		if err = mkdirall(self.Output, 0770); err != nil {
+			self.Logger.Error("failed to create path: %s (%s)", self.Output, err)
 			return err
 		}
 	}
 
-	// create page object with version & content
 	page := page{
 		Version: self.version,
 		Content: template.HTML(blackfriday.MarkdownCommon(content)),
 	}
-
-	// prepare output file path
 	out := filepath.Join(self.Output, "index.html")
 
-	// attempt to open file for output
 	var f *os.File
 	if f, err = create(out); err != nil {
+		self.Logger.Error("%s\n", err)
 		return err
 	}
 	defer f.Close()
 
-	// prepare a writer /w buffer
 	fb := bufio.NewWriter(f)
 	defer fb.Flush()
 
-	// attempt to use template to write output with page context
-	err = self.template.Execute(fb, page)
+	if err = self.template.Execute(fb, page); err != nil {
+		self.Logger.Error("%s\n", err)
+	}
+
+	if err == nil {
+		err = terr
+	}
+
 	return
 }
 
 func (self *Generator) Generate() error {
-
-	// process template
 	var err error
 	if self.template, err = parseFiles(self.TemplateFile); err != nil {
+		self.Logger.Error("%s\n", err)
 		return err
 	}
 
-	// acquire version
 	self.version = version(self.Input)
-
-	// sanitize input & output
 	self.Input, _ = filepath.Abs(self.Input)
 	self.Output, _ = filepath.Abs(self.Output)
-
-	// sanitize & validate properties
 	self.Input = filepath.Clean(self.Input)
 	self.Output = filepath.Clean(self.Output)
 
-	// walk the file system
 	if err := walk(self.Input, self.walk); err != nil {
+		self.Logger.Error("%s\n", err)
 		return err
 	}
-
-	// debug: print state
 	self.Logger.Debug("generator state: %+v", self)
 
-	// determine assembly method
 	if self.Book {
 		return self.single()
 	}

+ 36 - 46
generator_test.go

@@ -9,22 +9,15 @@ import (
 	"time"
 )
 
-var mockReadfileBytes []byte
-var mockReadfileError error
-var mockTemplateError error
-var mockCreateFile *os.File
-var mockCreateError error
-var mockMkdirError error
-var mockParseTemplate *template.Template
-var mockParseError error
-var mockWalkError error
+var parseTemplate *template.Template
+var readfileError, templateError, createError, mkdirallError, parseError, walkError error
 
 func init() {
-	readfile = func(_ string) ([]byte, error) { return mockReadfileBytes, mockReadfileError }
-	create = func(_ string) (*os.File, error) { return mockCreateFile, mockCreateError }
-	mkdirall = func(_ string, _ os.FileMode) error { return mockMkdirError }
-	parseFiles = func(...string) (*template.Template, error) { return mockParseTemplate, mockParseError }
-	walk = func(_ string, _ filepath.WalkFunc) error { return mockWalkError }
+	readfile = func(_ string) ([]byte, error) { return nil, readfileError }
+	create = func(_ string) (*os.File, error) { return nil, createError }
+	mkdirall = func(_ string, _ os.FileMode) error { return mkdirallError }
+	parseFiles = func(...string) (*template.Template, error) { return parseTemplate, parseError }
+	walk = func(_ string, _ filepath.WalkFunc) error { return walkError }
 }
 
 type mockLogger struct{}
@@ -35,7 +28,7 @@ func (self *mockLogger) Info(_ string, _ ...interface{})  {}
 
 type mockTemplate struct{}
 
-func (self *mockTemplate) Execute(_ io.Writer, _ interface{}) error { return mockTemplateError }
+func (self *mockTemplate) Execute(_ io.Writer, _ interface{}) error { return templateError }
 
 type mockFileInfo struct {
 	N  string
@@ -96,13 +89,9 @@ func TestWalk(t *testing.T) {
 func TestMulti(t *testing.T) {
 	g := Generator{Logger: &mockLogger{}, template: &mockTemplate{}, pages: []string{"fuck.md", "deeper/than/index.md", "deeper/than/data.md"}}
 
-	// reset defaults for parameters
-	mockCreateError = nil
-	mockReadfileError = nil
-	mockMkdirError = nil
-	statError = nil
+	// set expected defaults
 	notExist = false
-	mockCreateFile = &os.File{}
+	statError = nil
 
 	// no pages
 	if e := g.multi(); e != nil {
@@ -120,76 +109,77 @@ func TestMulti(t *testing.T) {
 		t.FailNow()
 	}
 
+	// test failing execute
+	templateError = mockError
+	if e := g.multi(); e == nil {
+		t.FailNow()
+	}
+
 	// test failing file creation
-	mockCreateError = mockError
+	createError = mockError
 	if e := g.multi(); e == nil {
 		t.FailNow()
 	}
 
 	// test failing to read the file
-	mockReadfileError = mockError
+	readfileError = mockError
 	if e := g.multi(); e == nil {
 		t.FailNow()
 	}
 
 	// test dir creation failure
-	mockMkdirError = mockError
+	mkdirallError = mockError
 	statError = mockError
-	notExist = true
 	if e := g.multi(); e == nil {
 		t.FailNow()
 	}
 }
 
 func TestSingle(t *testing.T) {
-	t.Parallel()
 	g := Generator{Logger: &mockLogger{}, template: &mockTemplate{}, pages: []string{"fuck.md", "deeper/than/index.md", "deeper/than/data.md"}}
 
-	// reset defaults for parameters
-	mockCreateError = nil
-	mockReadfileError = nil
-	mockMkdirError = nil
+	// reset expected defaults
 	statError = nil
-	notExist = false
-	mockCreateFile = &os.File{}
+	readfileError = nil
+	createError = nil
+	templateError = nil
 
 	// test full pass
 	if e := g.single(); e != nil {
 		t.FailNow()
 	}
 
+	// test failing execute
+	templateError = mockError
+	if e := g.single(); e == nil {
+		t.FailNow()
+	}
+
 	// test create error
-	mockCreateError = mockError
+	createError = mockError
 	if e := g.single(); e == nil {
 		t.FailNow()
 	}
 
 	// test fail mkdirall
-	mockMkdirError = mockError
+	mkdirallError = mockError
 	statError = mockError
 	if e := g.single(); e == nil {
 		t.FailNow()
 	}
 
 	// test fail readfile
-	mockReadfileError = mockError
+	readfileError = mockError
 	if e := g.single(); e == nil {
 		t.FailNow()
 	}
 }
 
 func TestGenerate(t *testing.T) {
-	t.Parallel()
 	g := Generator{Logger: &mockLogger{}}
 
-	// reset defaults for parameters
-	mockParseTemplate = template.New("test")
-	mockCreateError = nil
-	mockReadfileError = nil
-	mockMkdirError = nil
-	statError = nil
-	notExist = false
-	mockTemplateError = nil
+	// set template for stand-alone execution
+	parseTemplate = template.New("test")
 
 	// test full pass
 	if e := g.Generate(); e != nil {
@@ -203,13 +193,13 @@ func TestGenerate(t *testing.T) {
 	}
 
 	// test walk error
-	mockWalkError = mockError
+	walkError = mockError
 	if e := g.Generate(); e == nil {
 		t.FailNow()
 	}
 
 	// test template error
-	mockParseError = mockError
+	parseError = mockError
 	if e := g.Generate(); e == nil {
 		t.FailNow()
 	}

+ 0 - 10
staticmd.go

@@ -13,7 +13,6 @@ func init() {
 	runnable = cmd{}
 }
 
-// logger component for printing status messages to stderr
 type logger interface {
 	Debug(string, ...interface{})
 	Error(string, ...interface{})
@@ -31,15 +30,10 @@ var runnable runner
 
 type cmd struct{}
 
-// a command runner to abstract exec
 func (self cmd) Run(command string, args ...string) ([]byte, error) {
 	return exec.Command(command, args...).Output()
 }
 
-// check that a path exists
-// does not care if it is a directory
-// will not say whether user has rw access, but
-// will throw an error if the user cannot read the parent directory
 func exists(path string) (bool, error) {
 	_, err := stat(path)
 	if err == nil {
@@ -51,8 +45,6 @@ func exists(path string) (bool, error) {
 	return false, err
 }
 
-// if within a git repo, gets git version as a short-hash
-// otherwise falls back to a unix timestamp
 func version(dir string) string {
 	version := strconv.FormatInt(time.Now().Unix(), 10)
 	out, err := runnable.Run("sh", "-c", "git", "-C", dir, "rev-parse", "--short", "HEAD")
@@ -62,12 +54,10 @@ func version(dir string) string {
 	return version
 }
 
-// remove the path and extension from a given filename
 func basename(name string) string {
 	return filepath.Base(strings.TrimSuffix(name, filepath.Ext(name)))
 }
 
-// check for markdown in supported extensions array
 func isMarkdown(path string) bool {
 	for i := range extensions {
 		if strings.HasSuffix(path, extensions[i]) {

+ 4 - 1
staticmd_test.go

@@ -36,7 +36,10 @@ func TestCmd(t *testing.T) {
 }
 
 func TestExists(t *testing.T) {
-	t.Parallel()
+
+	// set expected defaults
+	notExist = false
+	statError = nil
 
 	// test stat success exists fail
 	if _, e := exists(""); e != nil {