package main import ( "slices" "bufio" "fmt" "io" "os" "os/exec" "strings" "path/filepath" //"flag" "html/template" "time" ) type post struct { InPath string OutPath string ModTime time.Time } type ParsedPost struct { Path string Metadata PostMetadata } type PostMetadata struct { Name string Description string } func buildTemplate(w io.Writer, data interface{}) error { tmpl, err := template.ParseFiles("base.html", "head.html", "body.html") if err != nil { return err } err = tmpl.Execute(w, data) if err != nil { return err } return nil } func main() { args := os.Args if len(args) != 2 { fmt.Fprintf(os.Stderr, "USAGE: %s [postsfolder]", args[0]) os.Exit(1) } postsOutDir := "public/posts/" err := os.MkdirAll(postsOutDir, 0o777) if err != nil { fmt.Fprintln(os.Stderr, err) os.Exit(1) } f, err := os.Open(args[1]) if err != nil { fmt.Fprintln(os.Stderr, err) os.Exit(1) } defer f.Close() entries, err := f.ReadDir(0) if err != nil { fmt.Fprintln(os.Stderr, err) os.Exit(1) } var files []post = nil for _, entry := range entries { name := entry.Name() outName := strings.TrimSuffix(name, filepath.Ext(name)) + ".html" fi, err := entry.Info() if err != nil { fmt.Fprintln(os.Stderr, err) os.Exit(1) } p := post { InPath: filepath.Join(args[1], name), OutPath: filepath.Join(postsOutDir, outName), ModTime: fi.ModTime(), } files = append(files, p) } slices.SortFunc(files, func(a, b post) int { if a.ModTime.After(b.ModTime) { return -1 } else { return 1 } }) pposts, err := parseMetadata(files) if err != nil { fmt.Fprintln(os.Stderr, err) os.Exit(1) } err = md2html(files) if err != nil { fmt.Fprintln(os.Stderr, err) os.Exit(1) } idx, err := os.Create("public/index.html") if err != nil { fmt.Fprintln(os.Stderr, err) os.Exit(1) } //var data []string = nil //for _, post := range files { // data = append(data, filepath.Join("posts", filepath.Base(post.OutPath))) //} for _, ppost := range pposts { fmt.Fprintf(os.Stderr, "name: %s, description: %s\n", ppost.Metadata.Name, ppost.Metadata.Description) } err = buildTemplate(idx, pposts) if err != nil { fmt.Fprintln(os.Stderr, err) os.Exit(1) } } func parseMetadata(files []post) ([]ParsedPost, error) { var pposts []ParsedPost = nil for _, file := range files { f, err := os.Open(file.InPath) if err != nil { return pposts, err } defer f.Close() sc := bufio.NewScanner(f) lnb := 1 var metadata PostMetadata = PostMetadata {} for sc.Scan() { line := sc.Text() if line == "----" { break } spl := strings.Split(line, "=") if len(spl) != 2 { return pposts, fmt.Errorf("Invalid Metadata: %s:%d", file.InPath, lnb) } switch spl[0] { case "name": metadata.Name = spl[1] case "description": metadata.Description = spl[1] default: fmt.Fprintf(os.Stderr, "Invalid key: %s (%s:%d)\n", spl[0], file.InPath, lnb) } lnb += 1 } pposts = append(pposts, ParsedPost { Path: filepath.Join("posts", filepath.Base(file.OutPath)), Metadata: metadata, }) } return pposts, nil } func md2html(files []post) error { for _, file := range files { //err = os.WriteFile(file.OutPath, out, 0600) //if err != nil { // return err //} out, err := execcmd(file) if err != nil { return err } fmt.Println(string(out)) tmpl, err := template.New("base.html").ParseFiles("base.html", "head.html") if err != nil { return err } _, err = tmpl.New("body").Parse(string(out)) if err != nil { return err } f, err := os.Create(file.OutPath) if err != nil { return err } defer f.Close() err = tmpl.Execute(f, nil) if err != nil { return err } } return nil } func execcmd(file post) ([]byte, error) { cmd := exec.Command("converter/md2html", file.InPath) inPipe, err := cmd.StdinPipe() if err != nil { return nil, err } outPipe, err := cmd.StdoutPipe() if err != nil { return nil, err } errPipe, err := cmd.StderrPipe() if err != nil { return nil, err } go func() { defer inPipe.Close() f, _ := os.Open(file.InPath) defer f.Close() sc := bufio.NewScanner(f) doPrint := false for sc.Scan() { line := sc.Text() if doPrint { io.WriteString(inPipe, line + "\n") } if line == "----" { doPrint = true } } io.Copy(inPipe, f) }() fmt.Fprintln(os.Stderr, "stdout") var out []byte = nil go func() { out, _ = io.ReadAll(outPipe) }() fmt.Fprintln(os.Stderr, "stderr") var cmdErr []byte = nil go func() { cmdErr, _ = io.ReadAll(errPipe) }() if err := cmd.Start(); err != nil { return nil, err } if err := cmd.Wait(); err != nil { return nil, fmt.Errorf("%s\nstderr: %s\n", err, string(cmdErr)) } return out, nil }