ref: 9f3796a31dc217b2b8094f948266b23ac3808aa6
parent: ca6ca4f4fc29906e491b5ac6b63fb65125c9c9e4
author: Steve Francia <steve.francia@gmail.com>
date: Thu Jan 7 16:48:13 EST 2016
Read/reread individual source content files next is incremental conversion
--- a/commands/hugo.go
+++ b/commands/hugo.go
@@ -594,7 +594,7 @@
for _, ev := range evs {ext := filepath.Ext(ev.Name)
- istemp := strings.HasSuffix(ext, "~") || (ext == ".swp") || (ext == ".swx") || (ext == ".tmp") || strings.HasPrefix(ext, ".goutputstream") || strings.HasSuffix(ext, "jb_old___")|| strings.HasSuffix(ext, "jb_bak___")
+ istemp := strings.HasSuffix(ext, "~") || (ext == ".swp") || (ext == ".swx") || (ext == ".tmp") || strings.HasPrefix(ext, ".goutputstream") || strings.HasSuffix(ext, "jb_old___") || strings.HasSuffix(ext, "jb_bak___")
if istemp {continue
}
@@ -703,7 +703,7 @@
fmt.Println(time.Now().Format(layout))
//TODO here
- // utils.CheckErr(buildSite(true))
+ // utils.CheckErr(buildSite(true))
rebuildSite(dynamicFilesChanged)
if !BuildWatch && !viper.GetBool("DisableLiveReload") {--- a/docs/content/meta/roadmap.md
+++ b/docs/content/meta/roadmap.md
@@ -19,7 +19,6 @@
* Import from other website systems
* from Drupal (See https://bitbucket.org/rickb777/drupal2hugo by Rick Beton (@rickb777))
* from WordPress (See [#100][], especially https://github.com/SchumacherFM/wordpress-to-hugo-exporter by Cyrill Schumacher (@SchumacherFM), but volunteers are needed to make it work with latest versions of WordPress.)
- * from Jekyll (See [#101][])
* An interactive web based editor (See http://discuss.gohugo.io/t/web-based-editor/155)
* Additional [themes](https://github.com/spf13/hugoThemes) (always on-going, contributions welcome!)
* Dynamic image resizing via shortcodes
--- a/hugolib/handler_page.go
+++ b/hugolib/handler_page.go
@@ -32,6 +32,7 @@
func (b basicPageHandler) Read(f *source.File, s *Site) HandledResult {page, err := NewPage(f.Path())
+
if err != nil { return HandledResult{file: f, err: err}}
--- a/hugolib/page.go
+++ b/hugolib/page.go
@@ -48,20 +48,19 @@
)
type Page struct {- Params map[string]interface{}- Content template.HTML
- Summary template.HTML
- Aliases []string
- Status string
- Images []Image
- Videos []Video
- TableOfContents template.HTML
- Truncated bool
- Draft bool
- PublishDate time.Time
- Tmpl tpl.Template
- Markup string
-
+ Params map[string]interface{}+ Content template.HTML
+ Summary template.HTML
+ Aliases []string
+ Status string
+ Images []Image
+ Videos []Video
+ TableOfContents template.HTML
+ Truncated bool
+ Draft bool
+ PublishDate time.Time
+ Tmpl tpl.Template
+ Markup string
extension string
contentType string
renderable bool
@@ -77,13 +76,13 @@
plainSecondaryInit sync.Once
renderingConfig *helpers.Blackfriday
renderingConfigInit sync.Once
+ pageMenus PageMenus
+ pageMenusInit sync.Once
+ isCJKLanguage bool
PageMeta
Source
Position `json:"-"`
Node
- pageMenus PageMenus
- pageMenusInit sync.Once
- isCJKLanguage bool
}
type Source struct {@@ -106,6 +105,42 @@
}
type Pages []*Page
+//
+//func (ps Pages) Replace(page *Page) {+// if i := ps.FindPagePos(page); i >= 0 {+// ps[i] = page
+// }
+//}
+
+//func (ps Pages) FindPageByFilePath(inPath string) *Page {+// for _, x := range ps {+// if x.Source.LogicalName() == inPath {+// return x
+// }
+// }
+// return nil
+//}
+
+// FindPagePos Given a page, it will find the position in Pages
+// will return -1 if not found
+func (ps Pages) FindPagePos(page *Page) int {+ for i, x := range ps {+ if x.Source.LogicalName() == page.Source.LogicalName() {+ return i
+ }
+ }
+ return -1
+}
+
+// FindPage Given a page, it will return the page in Pages
+// will return nil if not found
+//func (ps Pages) FindPage(page *Page) *Page {+// if i := ps.FindPagePos(page); i >= 0 {+// return ps[i]
+// }
+//
+// return nil
+//}
func (p *Page) Plain() string {p.initPlain()
--- a/hugolib/site.go
+++ b/hugolib/site.go
@@ -451,7 +451,6 @@
}
}
-
if len(tmplChanged) > 0 {s.prepTemplates()
s.Tmpl.PrintErrors()
@@ -462,10 +461,41 @@
s.ReadDataFromSourceFS()
}
- if len (sourceChanged) > 0 {- if err = s.CreatePages(); err != nil {- return err
+ if len(sourceChanged) > 0 {+
+ results := make(chan HandledResult)
+ filechan := make(chan *source.File)
+ errs := make(chan error)
+ wg := &sync.WaitGroup{}+
+ wg.Add(2)
+ for i := 0; i < 2; i++ {+ go sourceReader(s, filechan, results, wg)
}
+
+ go incrementalReadCollator(s, results, errs)
+
+ for _, x := range sourceChanged {+ file, err := s.ReReadFile(x)
+ if err != nil {+ errs <- err
+ }
+
+ filechan <- file
+ }
+
+ close(filechan)
+ wg.Wait()
+ close(results)
+
+ s.timerStep("read pages from source")+
+ //renderErrs := <-s.ConvertSource()
+ s.timerStep("convert source")+ // TODO(spf13) port this
+
+ fmt.Errorf("%s", errs)+
s.setupPrevNext()
if err = s.BuildSiteMeta(); err != nil {return err
@@ -497,7 +527,6 @@
return nil
}
-
func (s *Site) Analyze() error { if err := s.Process(); err != nil {return err
@@ -764,6 +793,47 @@
err error
}
+// ReReadFile resets file to be read from disk again
+func (s *Site) ReReadFile(absFilePath string) (*source.File, error) {+ fmt.Println("rereading", absFilePath)+ var file *source.File
+
+ reader, err := source.NewLazyFileReader(absFilePath)
+ if err != nil {+ return nil, err
+ }
+ fmt.Println(s.absDataDir())
+
+ file, err = source.NewFileFromAbs(s.absContentDir(), absFilePath, reader)
+
+ fmt.Println("file created", file.Path())+
+ if err != nil {+ return nil, err
+ }
+
+ // maybe none of this rest needs to be here.
+ // replaced := false
+
+ // fmt.Println(len(s.Files))
+
+ // for i, x := range s.Files {+ // fmt.Println(x)
+ // fmt.Println("*** COMPARING:")+ // fmt.Println(" ", x.LogicalName())+ // fmt.Println(" ", absFilePath)+ // if x.LogicalName() == absFilePath {+ // s.Files[i] = file
+ // replaced = true
+ // }
+ // }
+
+ // if !replaced {+ // s.Files = append(s.Files, file)
+ // }
+ return file, nil
+}
+
func (s *Site) ReadPagesFromSource() chan error { if s.Source == nil { panic(fmt.Sprintf("s.Source not set %s", s.absContentDir()))@@ -856,15 +926,20 @@
func sourceReader(s *Site, files <-chan *source.File, results chan<- HandledResult, wg *sync.WaitGroup) {defer wg.Done()
for file := range files {- h := NewMetaHandler(file.Extension())
- if h != nil {- h.Read(file, s, results)
- } else {- jww.ERROR.Println("Unsupported File Type", file.Path())- }
+ fmt.Println("reading", file.Path())+ readSourceFile(s, file, results)
}
}
+func readSourceFile(s *Site, file *source.File, results chan<- HandledResult) {+ h := NewMetaHandler(file.Extension())
+ if h != nil {+ h.Read(file, s, results)
+ } else {+ jww.ERROR.Println("Unsupported File Type", file.Path())+ }
+}
+
func pageConverter(s *Site, pages <-chan *Page, results HandleResults, wg *sync.WaitGroup) {defer wg.Done()
for page := range pages {@@ -905,7 +980,41 @@
errs <- fmt.Errorf("Errors rendering pages: %s", strings.Join(errMsgs, "\n"))}
-func readCollator(s *Site, results <-chan HandledResult, errs chan<- error) {+func (s *Site) AddPage(page *Page) {+ if page.ShouldBuild() {+ s.Pages = append(s.Pages, page)
+ }
+
+ if page.IsDraft() {+ s.draftCount++
+ }
+
+ if page.IsFuture() {+ s.futureCount++
+ }
+}
+
+func (s *Site) RemovePage(page *Page) {+ if i := s.Pages.FindPagePos(page); i >= 0 {+ if page.IsDraft() {+ s.draftCount--
+ }
+
+ if page.IsFuture() {+ s.futureCount--
+ }
+
+ s.Pages = append(s.Pages[:i], s.Pages[i+1:]...)
+ }
+}
+
+func (s *Site) ReplacePage(page *Page) {+ // will find existing page that matches filepath and remove it
+ s.RemovePage(page)
+ s.AddPage(page)
+}
+
+func incrementalReadCollator(s *Site, results <-chan HandledResult, errs chan<- error) { errMsgs := []string{} for r := range results { if r.err != nil {@@ -915,19 +1024,34 @@
// !page == file
if r.page == nil {+ // TODO(spf13): Make this incremental as well
s.Files = append(s.Files, r.file)
} else {- if r.page.ShouldBuild() {- s.Pages = append(s.Pages, r.page)
- }
+ s.ReplacePage(r.page)
+ }
+ }
- if r.page.IsDraft() {- s.draftCount++
- }
+ s.Pages.Sort()
+ if len(errMsgs) == 0 {+ errs <- nil
+ return
+ }
+ errs <- fmt.Errorf("Errors reading pages: %s", strings.Join(errMsgs, "\n"))+}
- if r.page.IsFuture() {- s.futureCount++
- }
+func readCollator(s *Site, results <-chan HandledResult, errs chan<- error) {+ errMsgs := []string{}+ for r := range results {+ if r.err != nil {+ errMsgs = append(errMsgs, r.Error())
+ continue
+ }
+
+ // !page == file
+ if r.page == nil {+ s.Files = append(s.Files, r.file)
+ } else {+ s.AddPage(r.page)
}
}
--- a/source/file.go
+++ b/source/file.go
@@ -14,14 +14,16 @@
package source
import (
- "github.com/spf13/hugo/helpers"
"io"
"path/filepath"
"strings"
+
+ "github.com/spf13/hugo/helpers"
)
+// All paths are relative from the source directory base
type File struct {- relpath string // Original Full Path eg. /Users/Home/Hugo/foo.txt
+ relpath string // Original Full Path eg. content/foo.txt
logicalName string // foo.txt
Contents io.Reader
section string // The first directory
@@ -30,6 +32,7 @@
uniqueID string // MD5 of the filename
}
+// UniqueID: MD5 of the filename
func (f *File) UniqueID() string {return f.uniqueID
}
@@ -42,15 +45,17 @@
return helpers.ReaderToBytes(f.Contents)
}
-// Filename without extension
+// BaseFileName Filename without extension
func (f *File) BaseFileName() string {return helpers.Filename(f.LogicalName())
}
+// Section The first directory
func (f *File) Section() string {return f.section
}
+// LogicalName The filename and extension of the file
func (f *File) LogicalName() string {return f.logicalName
}
@@ -71,6 +76,7 @@
return f.Extension()
}
+// Path the relative path including file name and extension from the base of the source directory
func (f *File) Path() string {return f.relpath
}
--- a/source/filesystem.go
+++ b/source/filesystem.go
@@ -14,7 +14,6 @@
package source
import (
- "github.com/spf13/viper"
"io"
"os"
"path/filepath"
@@ -21,6 +20,8 @@
"regexp"
"strings"
+ "github.com/spf13/viper"
+
"github.com/spf13/hugo/helpers"
jww "github.com/spf13/jwalterweatherman"
)
@@ -59,14 +60,11 @@
return f.files
}
+// add populates a file in the Filesystem.files
func (f *Filesystem) add(name string, reader io.Reader) (err error) {var file *File
- //if f.Base == "" {- //file = NewFileWithContents(name, reader)
- //} else {file, err = NewFileFromAbs(f.Base, name, reader)
- //}
if err == nil {f.files = append(f.files, file)
@@ -79,48 +77,57 @@
}
func (f *Filesystem) captureFiles() {-
walker := func(filePath string, fi os.FileInfo, err error) error { if err != nil {return nil
}
- if fi.Mode()&os.ModeSymlink == os.ModeSymlink {- link, err := filepath.EvalSymlinks(filePath)
+ b, err := f.shouldRead(filePath, fi)
+ if err != nil {+ return err
+ }
+ if b {+ rd, err := NewLazyFileReader(filePath)
if err != nil {- jww.ERROR.Printf("Cannot read symbolic link '%s', error was: %s", filePath, err)- return nil
+ return err
}
- linkfi, err := os.Stat(link)
- if err != nil {- jww.ERROR.Printf("Cannot stat '%s', error was: %s", link, err)- return nil
- }
- if !linkfi.Mode().IsRegular() {- jww.ERROR.Printf("Symbolic links for directories not supported, skipping '%s'", filePath)- }
- return nil
+ f.add(filePath, rd)
}
+ return err
+ }
- if fi.IsDir() {- if f.avoid(filePath) || isNonProcessablePath(filePath) {- return filepath.SkipDir
- }
- return nil
- }
+ filepath.Walk(f.Base, walker)
+}
- if isNonProcessablePath(filePath) {- return nil
+func (f *Filesystem) shouldRead(filePath string, fi os.FileInfo) (bool, error) {+ if fi.Mode()&os.ModeSymlink == os.ModeSymlink {+ link, err := filepath.EvalSymlinks(filePath)
+ if err != nil {+ jww.ERROR.Printf("Cannot read symbolic link '%s', error was: %s", filePath, err)+ return false, nil
}
- rd, err := NewLazyFileReader(filePath)
+ linkfi, err := os.Stat(link)
if err != nil {- return err
+ jww.ERROR.Printf("Cannot stat '%s', error was: %s", link, err)+ return false, nil
}
- f.add(filePath, rd)
- return nil
+ if !linkfi.Mode().IsRegular() {+ jww.ERROR.Printf("Symbolic links for directories not supported, skipping '%s'", filePath)+ }
+ return false, nil
}
- filepath.Walk(f.Base, walker)
+ if fi.IsDir() {+ if f.avoid(filePath) || isNonProcessablePath(filePath) {+ return false, filepath.SkipDir
+ }
+ return false, nil
+ }
+
+ if isNonProcessablePath(filePath) {+ return false, nil
+ }
+ return true, nil
}
func (f *Filesystem) avoid(filePath string) bool {--
⑨