posts-go/main.go

148 lines
3.3 KiB
Go

package main
import (
"context"
"fmt"
"log"
"os"
"path/filepath"
"strings"
"text/template"
"github.com/google/go-github/v60/github"
"golang.org/x/oauth2"
"golang.org/x/sync/errgroup"
"github.com/make-go-great/netrc-go"
)
const (
postFilesPath = "posts"
templatePostPath = "templates/post.html"
generatedPath = "docs"
extHTML = ".html"
netrcPath = "~/.netrc"
netrcMachineGitHub = "github.com"
)
type templatePostData struct {
Index string
Body string
}
func main() {
ctx := context.Background()
// Cleanup generated path
if err := os.RemoveAll(generatedPath); err != nil {
log.Fatalln("Failed to remove all", generatedPath, err)
}
if err := os.MkdirAll(generatedPath, 0o777); err != nil {
log.Fatalln("Failed to mkdir all", generatedPath)
}
// Read post files directory
postFiles, err := os.ReadDir(postFilesPath)
if err != nil {
log.Fatalln("Failed to read dir", postFilesPath)
}
// Prepare template
templatePostBytes, err := os.ReadFile(templatePostPath)
if err != nil {
log.Fatalln("Failed to read file", templatePostPath, err)
}
templatePost, err := template.New("post").Parse(string(templatePostBytes))
if err != nil {
log.Fatalln("Failed to parse template", err)
}
// Prepare GitHub
netrcData, err := netrc.ParseFile(netrcPath)
if err != nil {
log.Fatalln("Failed to read file netrc", err)
}
var ghAccessToken string
for _, machine := range netrcData.Machines {
if machine.Name == netrcMachineGitHub {
ghAccessToken = machine.Password
break
}
}
if ghAccessToken == "" {
log.Fatalln("Empty GitHub token in netrc")
}
ghTokenSrc := oauth2.StaticTokenSource(
&oauth2.Token{
AccessToken: strings.TrimSpace(ghAccessToken),
},
)
ghHTTPClient := oauth2.NewClient(ctx, ghTokenSrc)
ghClient := github.NewClient(ghHTTPClient)
eg := new(errgroup.Group)
// Generate post files
for _, postFile := range postFiles {
if postFile.IsDir() {
continue
}
postFilename := postFile.Name()
eg.Go(func() error {
// Prepare post file
mdFilename := filepath.Join(postFilesPath, postFilename)
mdFileBytes, err := os.ReadFile(mdFilename)
if err != nil {
return fmt.Errorf("os: failed to read file %s: %w", mdFilename, err)
}
ghMarkdown, _, err := ghClient.Markdown.Render(ctx, string(mdFileBytes), nil)
if err != nil {
return fmt.Errorf("github: failed to markdown: %w", err)
}
// Prepare html file
htmlFilename := strings.TrimSuffix(postFilename, filepath.Ext(postFilename)) + extHTML
htmlFilepath := filepath.Join(generatedPath, htmlFilename)
htmlFile, err := os.OpenFile(htmlFilepath, os.O_RDWR|os.O_CREATE, 0o600)
if err != nil {
return fmt.Errorf("os: failed to open file %s: %w", htmlFilepath, err)
}
defer htmlFile.Close()
// Ignore index in index file
indexHTML := `<h2><a href="index.html"><code>~</code></a></h2>`
if strings.Contains(postFilename, "index") {
indexHTML = ""
}
if err := templatePost.Execute(htmlFile, templatePostData{
Index: indexHTML,
Body: ghMarkdown,
}); err != nil {
return fmt.Errorf("template: failed to execute: %w", err)
}
return nil
})
}
// Wait for all HTTP fetches to complete.
if err := eg.Wait(); err != nil {
log.Fatalln("I am sorry :(", err)
} else {
log.Println("Build successfully. Are you happy now?")
}
}