|
@@ -0,0 +1,118 @@
|
|
|
|
+package main
|
|
|
|
+
|
|
|
|
+import (
|
|
|
|
+ "os"
|
|
|
|
+ "os/exec"
|
|
|
|
+ "path/filepath"
|
|
|
|
+ "runtime"
|
|
|
|
+ "runtime/pprof"
|
|
|
|
+ "strconv"
|
|
|
|
+ "strings"
|
|
|
|
+ "time"
|
|
|
|
+
|
|
|
|
+ "github.com/cdelorme/go-log"
|
|
|
|
+ "github.com/cdelorme/go-maps"
|
|
|
|
+ "github.com/cdelorme/go-option"
|
|
|
|
+)
|
|
|
|
+
|
|
|
|
+// 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 := os.Stat(path)
|
|
|
|
+ if err == nil {
|
|
|
|
+ return true, nil
|
|
|
|
+ }
|
|
|
|
+ if os.IsNotExist(err) {
|
|
|
|
+ return false, nil
|
|
|
|
+ }
|
|
|
|
+ return false, err
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// if within a git repo, gets git version as a short-hash
|
|
|
|
+// otherwise falls back to a unix timestamp
|
|
|
|
+func Version() string {
|
|
|
|
+ version := strconv.FormatInt(time.Now().Unix(), 10)
|
|
|
|
+ out, err := exec.Command("sh", "-c", "git rev-parse --short HEAD").Output()
|
|
|
|
+ if err == nil {
|
|
|
|
+ version = strings.Trim(string(out), "\n")
|
|
|
|
+ }
|
|
|
|
+ return version
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+func main() {
|
|
|
|
+
|
|
|
|
+ // prepare staticmd with dependencies
|
|
|
|
+ staticmd := Staticmd{
|
|
|
|
+ Logger: log.Logger{Level: log.Error},
|
|
|
|
+ Subdirectories: make(map[string][]string),
|
|
|
|
+ Indexes: make(map[string][]string),
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // optimize concurrent processing
|
|
|
|
+ staticmd.MaxParallelism = runtime.NumCPU()
|
|
|
|
+ runtime.GOMAXPROCS(staticmd.MaxParallelism)
|
|
|
|
+
|
|
|
|
+ // get current directory
|
|
|
|
+ cwd, _ := os.Getwd()
|
|
|
|
+
|
|
|
|
+ // prepare cli options
|
|
|
|
+ appOptions := option.App{Description: "command line tool for generating deliverable static content"}
|
|
|
|
+ appOptions.Flag("template", "path to the template file", "--template", "-t")
|
|
|
|
+ appOptions.Flag("input", "path to the markdown files", "--input", "-i")
|
|
|
|
+ appOptions.Flag("output", "path to place generated content", "--output", "-o")
|
|
|
|
+ appOptions.Flag("book", "combine all content into a single file", "--book", "-b")
|
|
|
|
+ appOptions.Flag("relative", "use relative paths instead of absolute paths", "--relative", "-r")
|
|
|
|
+ appOptions.Flag("debug", "verbose debug output", "--debug", "-d")
|
|
|
|
+ appOptions.Flag("profile", "produce profile output to supplied path", "--profile", "-p")
|
|
|
|
+ appOptions.Example("-t template.tmpl -i . -b")
|
|
|
|
+ appOptions.Example("-t template.tmpl -i src/ -o out/ -r")
|
|
|
|
+ flags := appOptions.Parse()
|
|
|
|
+
|
|
|
|
+ // apply flags
|
|
|
|
+ staticmd.Template, _ = maps.String(&flags, staticmd.Template, "template")
|
|
|
|
+ staticmd.Input, _ = maps.String(&flags, cwd, "input")
|
|
|
|
+ staticmd.Output, _ = maps.String(&flags, filepath.Join(cwd, "public/"), "output")
|
|
|
|
+ staticmd.Book, _ = maps.Bool(&flags, staticmd.Book, "book")
|
|
|
|
+
|
|
|
|
+ // sanitize input & output
|
|
|
|
+ staticmd.Input, _ = filepath.Abs(staticmd.Input)
|
|
|
|
+ staticmd.Output, _ = filepath.Abs(staticmd.Output)
|
|
|
|
+
|
|
|
|
+ // optionally enable debugging
|
|
|
|
+ if debug, _ := maps.Bool(&flags, false, "debug"); debug {
|
|
|
|
+ staticmd.Logger.Level = log.Debug
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // optionally enable profiling
|
|
|
|
+ if profile, _ := maps.String(&flags, "", "profile"); profile != "" {
|
|
|
|
+ f, _ := os.Create(profile)
|
|
|
|
+ pprof.StartCPUProfile(f)
|
|
|
|
+ defer pprof.StopCPUProfile()
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // sanitize & validate properties
|
|
|
|
+ staticmd.Input = filepath.Clean(staticmd.Input)
|
|
|
|
+ staticmd.Output = filepath.Clean(staticmd.Output)
|
|
|
|
+
|
|
|
|
+ // print debug status
|
|
|
|
+ staticmd.Logger.Debug("Staticmd State: %+v", staticmd)
|
|
|
|
+
|
|
|
|
+ if err := filepath.Walk(staticmd.Input, staticmd.Walk); err != nil {
|
|
|
|
+ staticmd.Logger.Error("failed to walk directory: %s", err)
|
|
|
|
+ }
|
|
|
|
+ staticmd.Logger.Debug("Pages: %+v", staticmd.Pages)
|
|
|
|
+
|
|
|
|
+ // build indexes (includes navigation)
|
|
|
|
+ staticmd.Index()
|
|
|
|
+ staticmd.Logger.Debug("Navigation: %+v", staticmd.Navigation)
|
|
|
|
+ staticmd.Logger.Debug("Indexes: %+v", staticmd.Indexes)
|
|
|
|
+
|
|
|
|
+ // parse files
|
|
|
|
+ if staticmd.Book {
|
|
|
|
+ staticmd.BuildSingle()
|
|
|
|
+ } else {
|
|
|
|
+ staticmd.BuildMulti()
|
|
|
|
+ }
|
|
|
|
+}
|