232 lines
8.3 KiB
Go
232 lines
8.3 KiB
Go
package main
|
|
|
|
import (
|
|
"bufio"
|
|
"bytes"
|
|
"fmt"
|
|
"hash/crc32"
|
|
"log"
|
|
"math/rand"
|
|
"os"
|
|
"os/exec"
|
|
"path/filepath"
|
|
"regexp"
|
|
"runtime"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/PumpkinSeed/cage"
|
|
"github.com/gohugoio/hugo/commands"
|
|
"github.com/spf13/viper"
|
|
)
|
|
|
|
func check(e error) {
|
|
if e != nil {
|
|
log.Fatal(e)
|
|
panic(e)
|
|
}
|
|
}
|
|
|
|
func isPublished(gitRepoPath, gitIndexPath, prevcommit, lastcommit string) bool {
|
|
var sout bytes.Buffer
|
|
//var serr bytes.Buffer
|
|
commits := exec.Command("git", "-C", gitRepoPath, "rev-list", fmt.Sprintf("%s..%s", prevcommit, lastcommit))
|
|
commits.Env = os.Environ()
|
|
commits.Env = append(commits.Env, fmt.Sprintf("GIT_INDEX_FILE=%s%s", gitRepoPath, gitIndexPath))
|
|
commits.Stdout = &sout
|
|
//commits.Stderr = &serr
|
|
err := commits.Run()
|
|
check(err)
|
|
for _, commit := range strings.Fields(sout.String()) {
|
|
committedFiles, err := exec.Command("git", "-C", gitRepoPath, "diff-tree", "--no-commit-id", "--name-only", commit).Output()
|
|
check(err)
|
|
for _, commitFile := range strings.Fields(string(committedFiles)) {
|
|
if commitFile == "PUBLISH.trigger.md" {
|
|
return true
|
|
}
|
|
}
|
|
|
|
commitMessages, err := exec.Command("git", "-C", gitRepoPath, "show", "-s", "--format=%B", commit).Output()
|
|
check(err)
|
|
|
|
if strings.Contains(string(commitMessages), "!publish!") {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
func hugoLogs(logLines string, lines []string, hugoInstance string) string {
|
|
logLines = logLines + fmt.Sprintf("~~~~~~~~~~ Hugo's logs %s ~~~~~~~~~~\n", hugoInstance)
|
|
for _, d := range lines {
|
|
logLines = logLines + d + "\n"
|
|
|
|
}
|
|
logLines = logLines + "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n"
|
|
return logLines
|
|
}
|
|
|
|
func getOutdir(tmpRepoPath, gitRepoPath string) string {
|
|
viper.SetConfigName("config")
|
|
viper.SetConfigType("toml")
|
|
viper.AddConfigPath(filepath.Join(tmpRepoPath, "config", "_default"))
|
|
err := viper.ReadInConfig()
|
|
check(err)
|
|
//outdirBasePath := viper.GetString("params.sandpointsOutputDirectory")
|
|
outdirChecksum := strconv.FormatUint(uint64(crc32.ChecksumIEEE([]byte(gitRepoPath))), 16)
|
|
reg, err := regexp.Compile("[^a-zA-Z0-9]+")
|
|
check(err)
|
|
outdirRepoName := reg.ReplaceAllString(viper.GetString("params.title"), "")
|
|
return strings.ToLower(outdirRepoName) + "-" + outdirChecksum
|
|
}
|
|
|
|
func main() {
|
|
|
|
defer os.Exit(0)
|
|
|
|
// outDir is where the output of hugo will end up
|
|
// make sure the last part of the path has the right permissions
|
|
// os.TempDir() as first argument in filepath.Join is probably good choice for testing
|
|
outDir := filepath.Join("/", "var", "www", "html", "sandpoints")
|
|
|
|
startTime := time.Now()
|
|
logLines := startTime.Format(time.RFC822) + "\n"
|
|
logGiteaLines := ""
|
|
|
|
ex, err := os.Executable()
|
|
check(err)
|
|
|
|
var gitRepoPath, prevCommit, lastCommit, branchName, gitIndexPath string
|
|
|
|
scanner := bufio.NewScanner(os.Stdin)
|
|
scanner.Scan()
|
|
if scanner.Text() == "" {
|
|
// if it has no output it comes as post-commit hook
|
|
gitRepoPath = strings.Replace(filepath.Dir(ex), filepath.Join("/", ".git", "hooks"), "", 1)
|
|
//gitRepoPath = "/home/m/gitea-repositories/sandpoints/dev.git"
|
|
gitLastCommit, err := exec.Command("git", "-C", gitRepoPath, "rev-parse", "HEAD").Output()
|
|
check(err)
|
|
gitPrevCommit, err := exec.Command("git", "-C", gitRepoPath, "rev-parse", "HEAD^").Output()
|
|
check(err)
|
|
gitBranchName, err := exec.Command("git", "-C", gitRepoPath, "branch", "-a", "--contains", "HEAD").Output()
|
|
check(err)
|
|
branchName = strings.Replace(strings.TrimSpace(string(gitBranchName)), "* ", "", 1)
|
|
prevCommit, lastCommit, gitIndexPath = strings.TrimSpace(string(gitPrevCommit)), strings.TrimSpace(string(gitLastCommit)), filepath.Join("/", ".git", "index")
|
|
} else {
|
|
// if it has output it comes as post-receive.d/sphook from gitea repo
|
|
revs := strings.Fields(scanner.Text())
|
|
gitRepoPath = strings.Replace(filepath.Dir(ex), filepath.Join("/", "hooks", "post-receive.d"), "", 1)
|
|
prevCommit, lastCommit, branchName, gitIndexPath = revs[0], revs[1], strings.Split(revs[2], "/")[2], filepath.Join("/", "index")
|
|
}
|
|
|
|
// there's third one here, revs[2], usually saying refs/heads/master
|
|
// branchName := fmt.Sprintf(strings.Split(revs[2])[2])
|
|
|
|
logLines = logLines + "\n" + fmt.Sprintf("Repo: %s\n", gitRepoPath)
|
|
logLines = logLines + fmt.Sprintf("Repo's branch: %s\n", branchName)
|
|
|
|
rand.Seed(time.Now().UnixNano())
|
|
worktreeName := fmt.Sprintf("sandpoints_repo_%06d", rand.Intn(100001))
|
|
tmpRepoPath := filepath.Join(os.TempDir(), worktreeName)
|
|
logLines = logLines + fmt.Sprintf("cloned into temporary directory: %s\n", tmpRepoPath)
|
|
|
|
if _, err := os.Stat(tmpRepoPath); err == nil {
|
|
err := os.RemoveAll(tmpRepoPath)
|
|
check(err)
|
|
}
|
|
|
|
err = os.MkdirAll(tmpRepoPath, 0755)
|
|
check(err)
|
|
|
|
//var sout bytes.Buffer
|
|
//var serr bytes.Buffer
|
|
gitAddWorktree := exec.Command("git", "-C", gitRepoPath, "worktree", "add", "--detach", tmpRepoPath)
|
|
gitRemoveWorktree := exec.Command("git", "-C", gitRepoPath, "worktree", "remove", worktreeName)
|
|
gitAddWorktree.Env = os.Environ()
|
|
gitAddWorktree.Env = append(gitAddWorktree.Env, fmt.Sprintf("GIT_INDEX_FILE=%s%s", gitRepoPath, gitIndexPath))
|
|
//gitAddWorktree.Stdout = &sout
|
|
//gitAddWorktree.Stderr = &serr
|
|
err = gitAddWorktree.Run()
|
|
check(err)
|
|
|
|
gitRemoveWorktree.Env = os.Environ()
|
|
gitRemoveWorktree.Env = append(gitRemoveWorktree.Env, fmt.Sprintf("GIT_INDEX_FILE=%s%s", gitRepoPath, gitIndexPath))
|
|
defer gitRemoveWorktree.Run()
|
|
|
|
outSandpointsDir := getOutdir(tmpRepoPath, gitRepoPath)
|
|
logLines = logLines + fmt.Sprintf("to be moved to: %s\n", filepath.Join(outDir, outSandpointsDir))
|
|
tmpHugoGiteaPath := filepath.Join(os.TempDir(), fmt.Sprintf("sandpoints_hugo_%06d", rand.Intn(100001)))
|
|
tmpHugoPreviewPath := filepath.Join(tmpHugoGiteaPath, "_preview")
|
|
|
|
err = os.RemoveAll(tmpHugoGiteaPath)
|
|
check(err)
|
|
|
|
err = os.MkdirAll(tmpHugoPreviewPath, 0755)
|
|
check(err)
|
|
|
|
err = os.MkdirAll(filepath.Join(outDir, outSandpointsDir, "_preview"), 0755)
|
|
check(err)
|
|
|
|
defer func() {
|
|
lastPreviewCommitLog, err := os.Create(filepath.Join(outDir, outSandpointsDir, "_preview", "last-commit-log.txt"))
|
|
check(err)
|
|
defer lastPreviewCommitLog.Close()
|
|
fmt.Fprintln(lastPreviewCommitLog, logLines)
|
|
log.Printf(logLines)
|
|
}()
|
|
defer func() {
|
|
if isPublished(gitRepoPath, gitIndexPath, prevCommit, lastCommit) {
|
|
lastGiteaCommitLog, err := os.Create(filepath.Join(outDir, outSandpointsDir, "last-commit-log.txt"))
|
|
check(err)
|
|
defer lastGiteaCommitLog.Close()
|
|
fmt.Fprintln(lastGiteaCommitLog, logGiteaLines)
|
|
}
|
|
}()
|
|
|
|
if isPublished(gitRepoPath, gitIndexPath, prevCommit, lastCommit) {
|
|
hugoGiteaLogs := cage.Start()
|
|
respGitea := commands.Execute([]string{"-s", tmpRepoPath, "-d", tmpHugoGiteaPath, "-e", "gitea"})
|
|
cage.Stop(hugoGiteaLogs)
|
|
|
|
if respGitea.Err != nil {
|
|
logGiteaLines = fmt.Sprintf("Attempt to publish web site ended up with an Error! Check out the last commit to capture possible errors.\n\n%s\n~~~~~~~~~~\n\n%s", respGitea.Err, logLines)
|
|
logLines = fmt.Sprintf("Rendering _preview of the web site ended up with an ERROR! Check out the last commit to capture possible errors.\n\n%s\n~~~~~~~~~~\n\n%s", respGitea.Err, logLines)
|
|
runtime.Goexit()
|
|
}
|
|
|
|
logGiteaLines = hugoLogs(logLines, hugoGiteaLogs.Data, "for published instance")
|
|
}
|
|
|
|
hugoPreviewLogs := cage.Start()
|
|
respPreview := commands.Execute([]string{"-s", tmpRepoPath, "-d", tmpHugoPreviewPath, "-e", "preview", "--templateMetrics"})
|
|
cage.Stop(hugoPreviewLogs)
|
|
|
|
if respPreview.Err != nil {
|
|
logLines = fmt.Sprintf("Rendering _preview of the web site ended up with an ERROR! Check out the last commit to capture possible errors.\n\n%s\n~~~~~~~~~~\n\n%s", respPreview.Err, logLines)
|
|
runtime.Goexit()
|
|
}
|
|
|
|
logLines = hugoLogs(logLines, hugoPreviewLogs.Data, "for _preview instance")
|
|
|
|
if _, err := os.Stat(filepath.Join(outDir, outSandpointsDir)); err == nil {
|
|
err := os.RemoveAll(filepath.Join(outDir, outSandpointsDir))
|
|
check(err)
|
|
}
|
|
|
|
err = os.MkdirAll(outDir, 0755)
|
|
check(err)
|
|
|
|
err = os.Rename(tmpHugoGiteaPath, filepath.Join(outDir, outSandpointsDir))
|
|
check(err)
|
|
|
|
published := ""
|
|
if isPublished(gitRepoPath, gitIndexPath, prevCommit, lastCommit) {
|
|
published = " + published instance"
|
|
}
|
|
|
|
durationMillseconds := int64(time.Since(startTime) / time.Millisecond)
|
|
logLines = logLines + fmt.Sprintf("Total processing time (_preview%s): %d ms", published, durationMillseconds)
|
|
logGiteaLines = logGiteaLines + fmt.Sprintf("Total processing time (published + _preview instance): %d ms", durationMillseconds)
|
|
}
|