main.go 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. package main
  2. import (
  3. "os"
  4. "os/exec"
  5. "path/filepath"
  6. "runtime"
  7. "runtime/pprof"
  8. "strconv"
  9. "strings"
  10. "time"
  11. "github.com/cdelorme/go-log"
  12. "github.com/cdelorme/go-maps"
  13. "github.com/cdelorme/go-option"
  14. )
  15. // check that a path exists
  16. // does not care if it is a directory
  17. // will not say whether user has rw access, but
  18. // will throw an error if the user cannot read the parent directory
  19. func exists(path string) (bool, error) {
  20. _, err := os.Stat(path)
  21. if err == nil {
  22. return true, nil
  23. }
  24. if os.IsNotExist(err) {
  25. return false, nil
  26. }
  27. return false, err
  28. }
  29. // if within a git repo, gets git version as a short-hash
  30. // otherwise falls back to a unix timestamp
  31. func Version() string {
  32. version := strconv.FormatInt(time.Now().Unix(), 10)
  33. out, err := exec.Command("sh", "-c", "git rev-parse --short HEAD").Output()
  34. if err == nil {
  35. version = strings.Trim(string(out), "\n")
  36. }
  37. return version
  38. }
  39. func main() {
  40. // prepare staticmd with dependencies
  41. staticmd := Staticmd{
  42. Logger: log.Logger{Level: log.Error},
  43. Subdirectories: make(map[string][]string),
  44. Indexes: make(map[string][]string),
  45. }
  46. // optimize concurrent processing
  47. staticmd.MaxParallelism = runtime.NumCPU()
  48. runtime.GOMAXPROCS(staticmd.MaxParallelism)
  49. // get current directory
  50. cwd, _ := os.Getwd()
  51. // prepare cli options
  52. appOptions := option.App{Description: "command line tool for generating deliverable static content"}
  53. appOptions.Flag("template", "path to the template file", "--template", "-t")
  54. appOptions.Flag("input", "path to the markdown files", "--input", "-i")
  55. appOptions.Flag("output", "path to place generated content", "--output", "-o")
  56. appOptions.Flag("book", "combine all content into a single file", "--book", "-b")
  57. appOptions.Flag("relative", "use relative paths instead of absolute paths", "--relative", "-r")
  58. appOptions.Flag("debug", "verbose debug output", "--debug", "-d")
  59. appOptions.Flag("profile", "produce profile output to supplied path", "--profile", "-p")
  60. appOptions.Example("-t template.tmpl -i . -b")
  61. appOptions.Example("-t template.tmpl -i src/ -o out/ -r")
  62. flags := appOptions.Parse()
  63. // apply flags
  64. staticmd.Template, _ = maps.String(&flags, staticmd.Template, "template")
  65. staticmd.Input, _ = maps.String(&flags, cwd, "input")
  66. staticmd.Output, _ = maps.String(&flags, filepath.Join(cwd, "public/"), "output")
  67. staticmd.Book, _ = maps.Bool(&flags, staticmd.Book, "book")
  68. // sanitize input & output
  69. staticmd.Input, _ = filepath.Abs(staticmd.Input)
  70. staticmd.Output, _ = filepath.Abs(staticmd.Output)
  71. // optionally enable debugging
  72. if debug, _ := maps.Bool(&flags, false, "debug"); debug {
  73. staticmd.Logger.Level = log.Debug
  74. }
  75. // optionally enable profiling
  76. if profile, _ := maps.String(&flags, "", "profile"); profile != "" {
  77. f, _ := os.Create(profile)
  78. pprof.StartCPUProfile(f)
  79. defer pprof.StopCPUProfile()
  80. }
  81. // sanitize & validate properties
  82. staticmd.Input = filepath.Clean(staticmd.Input)
  83. staticmd.Output = filepath.Clean(staticmd.Output)
  84. // print debug status
  85. staticmd.Logger.Debug("Staticmd State: %+v", staticmd)
  86. if err := filepath.Walk(staticmd.Input, staticmd.Walk); err != nil {
  87. staticmd.Logger.Error("failed to walk directory: %s", err)
  88. }
  89. staticmd.Logger.Debug("Pages: %+v", staticmd.Pages)
  90. // build indexes (includes navigation)
  91. staticmd.Index()
  92. staticmd.Logger.Debug("Navigation: %+v", staticmd.Navigation)
  93. staticmd.Logger.Debug("Indexes: %+v", staticmd.Indexes)
  94. // parse files
  95. if staticmd.Book {
  96. staticmd.BuildSingle()
  97. } else {
  98. staticmd.BuildMulti()
  99. }
  100. }