hswg: an initial attempt at refactoring main()
This commit is contained in:
		
							
								
								
									
										229
									
								
								hswg/main.go
									
									
									
									
									
								
							
							
						
						
									
										229
									
								
								hswg/main.go
									
									
									
									
									
								
							@@ -187,6 +187,127 @@ func expand(m *map[string]*Entry, name string, chunk []byte) []byte {
 | 
				
			|||||||
	})
 | 
						})
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var tagRE = regexp.MustCompile(`<[^<>]+>`)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func renderEntry(name string, entries *map[string]*Entry) error {
 | 
				
			||||||
 | 
						e := (*entries)[name]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						f, err := os.Open(e.PathSource)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if i, err := f.Stat(); err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							e.mtime = i.ModTime()
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var html *bytes.Buffer
 | 
				
			||||||
 | 
						if html, e.Metadata, err = Render(f, configuration.NewConfiguration(
 | 
				
			||||||
 | 
							configuration.WithFilename(e.PathSource),
 | 
				
			||||||
 | 
							configuration.WithLastUpdated(e.mtime),
 | 
				
			||||||
 | 
						)); err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Every page needs to have a title.
 | 
				
			||||||
 | 
						if e.Title == "" {
 | 
				
			||||||
 | 
							e.Title = name
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Expand LinkWords anywhere between <tags>.
 | 
				
			||||||
 | 
						// We want something like the inverse of Regexp.ReplaceAllStringFunc.
 | 
				
			||||||
 | 
						raw, last, expanded := html.Bytes(), 0, bytes.NewBuffer(nil)
 | 
				
			||||||
 | 
						for _, where := range tagRE.FindAllIndex(raw, -1) {
 | 
				
			||||||
 | 
							_, _ = expanded.Write(expand(entries, name, raw[last:where[0]]))
 | 
				
			||||||
 | 
							_, _ = expanded.Write(raw[where[0]:where[1]])
 | 
				
			||||||
 | 
							last = where[1]
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						_, _ = expanded.Write(expand(entries, name, raw[last:]))
 | 
				
			||||||
 | 
						e.Content = template.HTML(expanded.String())
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func loadEntries(globs []string) (map[string]*Entry, error) {
 | 
				
			||||||
 | 
						// Create a map from document names to their page entries.
 | 
				
			||||||
 | 
						entries := map[string]*Entry{}
 | 
				
			||||||
 | 
						for _, glob := range globs {
 | 
				
			||||||
 | 
							matches, err := filepath.Glob(glob)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								return nil, fmt.Errorf("%s: %s\n", glob, err)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							for _, path := range matches {
 | 
				
			||||||
 | 
								name := stripExtension(filepath.Base(path))
 | 
				
			||||||
 | 
								if conflict, ok := entries[name]; ok {
 | 
				
			||||||
 | 
									return nil, fmt.Errorf("%s: conflicts with %s\n",
 | 
				
			||||||
 | 
										name, conflict.PathSource)
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								entries[name] = &Entry{
 | 
				
			||||||
 | 
									PathSource:      path,
 | 
				
			||||||
 | 
									PathDestination: resultPath(path),
 | 
				
			||||||
 | 
									backlinks:       map[string]bool{},
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for name := range entries {
 | 
				
			||||||
 | 
							if err := renderEntry(name, &entries); err != nil {
 | 
				
			||||||
 | 
								return nil, err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return entries, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func writeEntry(e *Entry, t *template.Template,
 | 
				
			||||||
 | 
						entries *map[string]*Entry) error {
 | 
				
			||||||
 | 
						f, err := os.Create(e.PathDestination)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						backlinks := []string{}
 | 
				
			||||||
 | 
						for name := range e.backlinks {
 | 
				
			||||||
 | 
							backlinks = append(backlinks, name)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						sort.Strings(backlinks)
 | 
				
			||||||
 | 
						for _, name := range backlinks {
 | 
				
			||||||
 | 
							e.Backlinks =
 | 
				
			||||||
 | 
								append(e.Backlinks, template.HTML(makeLink(entries, name)))
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return t.Execute(f, e)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func writeIndex(t *template.Template, entries *map[string]*Entry) error {
 | 
				
			||||||
 | 
						// Reorder entries reversely, primarily by date, secondarily by filename.
 | 
				
			||||||
 | 
						ordered := []*Entry{}
 | 
				
			||||||
 | 
						for _, e := range *entries {
 | 
				
			||||||
 | 
							ordered = append(ordered, e)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						sort.Slice(ordered, func(i, j int) bool {
 | 
				
			||||||
 | 
							a, b := ordered[i], ordered[j]
 | 
				
			||||||
 | 
							p1, p2 := a.Published(), b.Published()
 | 
				
			||||||
 | 
							if p1 == nil && p2 != nil {
 | 
				
			||||||
 | 
								return true
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if p1 == nil && p2 == nil {
 | 
				
			||||||
 | 
								return a.PathSource > b.PathSource
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if p2 == nil {
 | 
				
			||||||
 | 
								return false
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if p1.Equal(*p2) {
 | 
				
			||||||
 | 
								return a.PathSource > b.PathSource
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return p2.Before(*p1)
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// TODO(p): Splitting content to categories would be nice.
 | 
				
			||||||
 | 
						return t.Execute(os.Stdout, ordered)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func singleFile() {
 | 
					func singleFile() {
 | 
				
			||||||
	html, meta, err := Render(os.Stdin, configuration.NewConfiguration())
 | 
						html, meta, err := Render(os.Stdin, configuration.NewConfiguration())
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
@@ -213,124 +334,32 @@ func main() {
 | 
				
			|||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		log.Fatalln(err)
 | 
							log.Fatalln(err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					 | 
				
			||||||
	t, err := template.New("page").Parse(string(header))
 | 
						t, err := template.New("page").Parse(string(header))
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		log.Fatalln(err)
 | 
							log.Fatalln(err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Create a map from document names to their page entries.
 | 
						// Process all entries.
 | 
				
			||||||
	entries := map[string]*Entry{}
 | 
						entries, err := loadEntries(os.Args[2:])
 | 
				
			||||||
	for _, glob := range os.Args[2:] {
 | 
					 | 
				
			||||||
		matches, err := filepath.Glob(glob)
 | 
					 | 
				
			||||||
		if err != nil {
 | 
					 | 
				
			||||||
			log.Fatalf("%s: %s\n", glob, err)
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		for _, path := range matches {
 | 
					 | 
				
			||||||
			name := stripExtension(filepath.Base(path))
 | 
					 | 
				
			||||||
			if conflict, ok := entries[name]; ok {
 | 
					 | 
				
			||||||
				log.Fatalf("%s: conflicts with %s\n", name, conflict.PathSource)
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			entries[name] = &Entry{
 | 
					 | 
				
			||||||
				PathSource:      path,
 | 
					 | 
				
			||||||
				PathDestination: resultPath(path),
 | 
					 | 
				
			||||||
				backlinks:       map[string]bool{},
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	tagRE := regexp.MustCompile(`<[^<>]+>`)
 | 
					 | 
				
			||||||
	for name, e := range entries {
 | 
					 | 
				
			||||||
		f, err := os.Open(e.PathSource)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		log.Fatalln(err)
 | 
							log.Fatalln(err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					 | 
				
			||||||
		if i, err := f.Stat(); err != nil {
 | 
					 | 
				
			||||||
			log.Fatalln(err)
 | 
					 | 
				
			||||||
		} else {
 | 
					 | 
				
			||||||
			e.mtime = i.ModTime()
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		var html *bytes.Buffer
 | 
					 | 
				
			||||||
		if html, e.Metadata, err = Render(f, configuration.NewConfiguration(
 | 
					 | 
				
			||||||
			configuration.WithFilename(e.PathSource),
 | 
					 | 
				
			||||||
			configuration.WithLastUpdated(e.mtime),
 | 
					 | 
				
			||||||
		)); err != nil {
 | 
					 | 
				
			||||||
			log.Fatalln(err)
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		// Every page needs to have a title.
 | 
					 | 
				
			||||||
		if e.Title == "" {
 | 
					 | 
				
			||||||
			e.Title = name
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		// Expand LinkWords anywhere between <tags>.
 | 
					 | 
				
			||||||
		// We want something like the inverse of Regexp.ReplaceAllStringFunc.
 | 
					 | 
				
			||||||
		raw, last, expanded := html.Bytes(), 0, bytes.NewBuffer(nil)
 | 
					 | 
				
			||||||
		for _, where := range tagRE.FindAllIndex(raw, -1) {
 | 
					 | 
				
			||||||
			_, _ = expanded.Write(expand(&entries, name, raw[last:where[0]]))
 | 
					 | 
				
			||||||
			_, _ = expanded.Write(raw[where[0]:where[1]])
 | 
					 | 
				
			||||||
			last = where[1]
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		_, _ = expanded.Write(expand(&entries, name, raw[last:]))
 | 
					 | 
				
			||||||
		e.Content = template.HTML(expanded.String())
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	for _, e := range entries {
 | 
						for _, e := range entries {
 | 
				
			||||||
		f, err := os.Create(e.PathDestination)
 | 
							if err := writeEntry(e, t, &entries); err != nil {
 | 
				
			||||||
		if err != nil {
 | 
					 | 
				
			||||||
			log.Fatalln(err)
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		backlinks := []string{}
 | 
					 | 
				
			||||||
		for name := range e.backlinks {
 | 
					 | 
				
			||||||
			backlinks = append(backlinks, name)
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		sort.Strings(backlinks)
 | 
					 | 
				
			||||||
		for _, name := range backlinks {
 | 
					 | 
				
			||||||
			e.Backlinks =
 | 
					 | 
				
			||||||
				append(e.Backlinks, template.HTML(makeLink(&entries, name)))
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if err = t.Execute(f, e); err != nil {
 | 
					 | 
				
			||||||
			log.Fatalln(err)
 | 
								log.Fatalln(err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Reorder entries reversely, primarily by date, secondarily by filename.
 | 
						// Read a template from the standard input, write an index.
 | 
				
			||||||
	ordered := []*Entry{}
 | 
					 | 
				
			||||||
	for _, e := range entries {
 | 
					 | 
				
			||||||
		ordered = append(ordered, e)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	sort.Slice(ordered, func(i, j int) bool {
 | 
					 | 
				
			||||||
		a, b := ordered[i], ordered[j]
 | 
					 | 
				
			||||||
		p1, p2 := a.Published(), b.Published()
 | 
					 | 
				
			||||||
		if p1 == nil && p2 != nil {
 | 
					 | 
				
			||||||
			return true
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		if p1 == nil && p2 == nil {
 | 
					 | 
				
			||||||
			return a.PathSource > b.PathSource
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		if p2 == nil {
 | 
					 | 
				
			||||||
			return false
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		if p1.Equal(*p2) {
 | 
					 | 
				
			||||||
			return a.PathSource > b.PathSource
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		return p2.Before(*p1)
 | 
					 | 
				
			||||||
	})
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Execute a template from the standard input.
 | 
					 | 
				
			||||||
	var input []byte
 | 
						var input []byte
 | 
				
			||||||
	if input, err = ioutil.ReadAll(os.Stdin); err != nil {
 | 
						if input, err = ioutil.ReadAll(os.Stdin); err != nil {
 | 
				
			||||||
		log.Fatalln(err)
 | 
							log.Fatalln(err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					 | 
				
			||||||
	// TODO(p): Splitting content to categories would be nice.
 | 
					 | 
				
			||||||
	t, err = template.New("-").Parse(string(input))
 | 
						t, err = template.New("-").Parse(string(input))
 | 
				
			||||||
	if err = t.Execute(os.Stdout, ordered); err != nil {
 | 
						if err != nil {
 | 
				
			||||||
 | 
							log.Fatalln(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if err := writeIndex(t, &entries); err != nil {
 | 
				
			||||||
		log.Fatalln(err)
 | 
							log.Fatalln(err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user