Merge pull request 'staging' (#10) from staging into main
All checks were successful
release-tag / release-image (push) Successful in 2m21s
All checks were successful
release-tag / release-image (push) Successful in 2m21s
Reviewed-on: #10
This commit is contained in:
@@ -41,7 +41,7 @@ FROM debian:bookworm-slim
|
|||||||
|
|
||||||
# (optional) MySQL‑Client für später
|
# (optional) MySQL‑Client für später
|
||||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||||
ca-certificates \
|
ca-certificates git \
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
# ─── Binärdatei ─────
|
# ─── Binärdatei ─────
|
||||||
@@ -60,6 +60,11 @@ ENV BLOG_STATIC_DIR=/static
|
|||||||
ENV BLOG_PAGES_DIR=/pages
|
ENV BLOG_PAGES_DIR=/pages
|
||||||
ENV BLOG_TEMPLATES_DIR=/templates
|
ENV BLOG_TEMPLATES_DIR=/templates
|
||||||
ENV BLOG_TICKS_DIR=/ticks
|
ENV BLOG_TICKS_DIR=/ticks
|
||||||
|
ENV GIT_ENABLE=false
|
||||||
|
ENV GIT_REPO=null
|
||||||
|
ENV GIT_BRANCH=main
|
||||||
|
ENV GIT_DIR=/git-temp
|
||||||
|
ENV GIT_INTERVAL=10
|
||||||
|
|
||||||
EXPOSE 8080
|
EXPOSE 8080
|
||||||
CMD ["blog"]
|
CMD ["blog"]
|
||||||
|
41
Dockerfile_Slim
Normal file
41
Dockerfile_Slim
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
############################
|
||||||
|
# 1) Go‑Build
|
||||||
|
############################
|
||||||
|
FROM golang:1.23.1 AS build
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
COPY go.mod go.sum ./
|
||||||
|
RUN go mod download
|
||||||
|
COPY . .
|
||||||
|
RUN CGO_ENABLED=0 go build -o /blog ./cmd/blog
|
||||||
|
|
||||||
|
############################
|
||||||
|
# 3) Runtime‑Image
|
||||||
|
############################
|
||||||
|
FROM debian:bookworm-slim
|
||||||
|
|
||||||
|
# (optional) MySQL‑Client für später
|
||||||
|
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||||
|
ca-certificates git \
|
||||||
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
# ─── Binärdatei ─────
|
||||||
|
COPY --from=build /blog /usr/local/bin/blog
|
||||||
|
|
||||||
|
# ─── Content + Assets ───
|
||||||
|
RUN mkdir -p /content /static /pages /app /templates /ticks /git-temp
|
||||||
|
COPY . /app
|
||||||
|
|
||||||
|
ENV BLOG_CONTENT_DIR=/content
|
||||||
|
ENV BLOG_STATIC_DIR=/static
|
||||||
|
ENV BLOG_PAGES_DIR=/pages
|
||||||
|
ENV BLOG_TEMPLATES_DIR=/templates
|
||||||
|
ENV BLOG_TICKS_DIR=/ticks
|
||||||
|
ENV GIT_ENABLE=false
|
||||||
|
ENV GIT_REPO=null
|
||||||
|
ENV GIT_BRANCH=main
|
||||||
|
ENV GIT_DIR=/git-temp
|
||||||
|
ENV GIT_INTERVAL=10
|
||||||
|
|
||||||
|
EXPOSE 8080
|
||||||
|
CMD ["blog"]
|
189
cmd/blog/main.go
189
cmd/blog/main.go
@@ -4,9 +4,12 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"html/template"
|
"html/template"
|
||||||
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
|
"os/exec"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
|
"path/filepath"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"syscall"
|
"syscall"
|
||||||
@@ -93,6 +96,8 @@ var (
|
|||||||
tplArticle *template.Template
|
tplArticle *template.Template
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var Xarticles []article.Article
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|
||||||
// Signal-Kanal einrichten
|
// Signal-Kanal einrichten
|
||||||
@@ -113,6 +118,11 @@ func main() {
|
|||||||
pagesDir := getenv("BLOG_PAGES_DIR", "/pages")
|
pagesDir := getenv("BLOG_PAGES_DIR", "/pages")
|
||||||
templatesDir := getenv("BLOG_TEMPLATES_DIR", "/templates")
|
templatesDir := getenv("BLOG_TEMPLATES_DIR", "/templates")
|
||||||
ticksDir := getenv("BLOG_TICKS_DIR", "/ticks")
|
ticksDir := getenv("BLOG_TICKS_DIR", "/ticks")
|
||||||
|
gitEnable := enabled("GIT_ENABLE", false)
|
||||||
|
gitRepo := getenv("GIT_REPO", "null")
|
||||||
|
gitBranch := getenv("GIT_BRANCH", "main")
|
||||||
|
gitDir := getenv("GIT_DIR", "/git-temp")
|
||||||
|
gitInterval := getenv("GIT_INTERVAL", "10")
|
||||||
|
|
||||||
TickCatalog = nil
|
TickCatalog = nil
|
||||||
if err := LoadTickCatalog(ticksDir + "/ticks.json"); err != nil {
|
if err := LoadTickCatalog(ticksDir + "/ticks.json"); err != nil {
|
||||||
@@ -146,6 +156,8 @@ func main() {
|
|||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Xarticles = articles
|
||||||
|
|
||||||
staticPages, err := article.LoadStatic(pagesDir)
|
staticPages, err := article.LoadStatic(pagesDir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
@@ -162,8 +174,8 @@ func main() {
|
|||||||
|
|
||||||
/* */
|
/* */
|
||||||
|
|
||||||
for a, b := range articles {
|
for a, b := range Xarticles {
|
||||||
articles[a].Counter = getTick(b.Slug)
|
Xarticles[a].Counter = getTick(b.Slug)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* */
|
/* */
|
||||||
@@ -171,7 +183,7 @@ func main() {
|
|||||||
if err := tplList.ExecuteTemplate(w, "layout", article.ListPage{
|
if err := tplList.ExecuteTemplate(w, "layout", article.ListPage{
|
||||||
Title: "Startseite",
|
Title: "Startseite",
|
||||||
Description: "Alle Artikel im Überblick",
|
Description: "Alle Artikel im Überblick",
|
||||||
Articles: articles,
|
Articles: Xarticles,
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
http.Error(w, err.Error(), 500)
|
http.Error(w, err.Error(), 500)
|
||||||
}
|
}
|
||||||
@@ -179,7 +191,7 @@ func main() {
|
|||||||
|
|
||||||
mux.HandleFunc("/post/", func(w http.ResponseWriter, r *http.Request) {
|
mux.HandleFunc("/post/", func(w http.ResponseWriter, r *http.Request) {
|
||||||
slug := strings.TrimPrefix(r.URL.Path, "/post/")
|
slug := strings.TrimPrefix(r.URL.Path, "/post/")
|
||||||
for _, a := range articles {
|
for _, a := range Xarticles {
|
||||||
if a.Slug == slug {
|
if a.Slug == slug {
|
||||||
IncTick(slug)
|
IncTick(slug)
|
||||||
t := getTick(slug)
|
t := getTick(slug)
|
||||||
@@ -206,9 +218,13 @@ func main() {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
mux.Handle("/static/",
|
mux.Handle("/static/", cacheControl(http.StripPrefix("/static/", http.FileServer(http.Dir(staticDir)))))
|
||||||
cacheControl(http.StripPrefix("/static/",
|
|
||||||
http.FileServer(http.Dir(staticDir)))))
|
if gitEnable {
|
||||||
|
xMinute, _ := strconv.Atoi(gitInterval)
|
||||||
|
xDuration := time.Duration(xMinute) * time.Minute
|
||||||
|
go startAutoClone(gitRepo, gitBranch, gitDir, xDuration)
|
||||||
|
}
|
||||||
|
|
||||||
StopServer(http.ListenAndServe(":8080", mux))
|
StopServer(http.ListenAndServe(":8080", mux))
|
||||||
|
|
||||||
@@ -228,3 +244,162 @@ func StopServer(e error) {
|
|||||||
prepareExit()
|
prepareExit()
|
||||||
fmt.Println("~", "Server stopped!")
|
fmt.Println("~", "Server stopped!")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func cloneRepo(repoURL, branch, dir string) {
|
||||||
|
fmt.Printf("Starte Klonvorgang für Branch '%s'...\n", branch)
|
||||||
|
|
||||||
|
// Verzeichnis löschen
|
||||||
|
if err := os.RemoveAll(dir); err != nil {
|
||||||
|
fmt.Println("Fehler beim Löschen des Verzeichnisses:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Git-Clone mit Branch
|
||||||
|
cmd := exec.Command("git", "clone", "--branch", branch, "--single-branch", repoURL, dir)
|
||||||
|
cmd.Stdout = os.Stdout
|
||||||
|
cmd.Stderr = os.Stderr
|
||||||
|
|
||||||
|
if err := cmd.Run(); err != nil {
|
||||||
|
fmt.Println("Fehler beim Klonen:", err)
|
||||||
|
} else {
|
||||||
|
fmt.Println("Repo erfolgreich geklont.")
|
||||||
|
}
|
||||||
|
|
||||||
|
contentDir := getenv("BLOG_CONTENT_DIR", "/content")
|
||||||
|
|
||||||
|
err := os.RemoveAll("/content")
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err, "/content")
|
||||||
|
}
|
||||||
|
|
||||||
|
err = os.RemoveAll("/static")
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err, "/static")
|
||||||
|
}
|
||||||
|
|
||||||
|
err = os.RemoveAll("/pages")
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err, "/pages")
|
||||||
|
}
|
||||||
|
|
||||||
|
err = os.RemoveAll("/templates")
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err, "/templates")
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := os.MkdirAll("/content", 0755); err != nil {
|
||||||
|
fmt.Println("Fehler beim Erstellen des Zielordners:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := os.MkdirAll("/static", 0755); err != nil {
|
||||||
|
fmt.Println("Fehler beim Erstellen des Zielordners:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := os.MkdirAll("/pages", 0755); err != nil {
|
||||||
|
fmt.Println("Fehler beim Erstellen des Zielordners:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := os.MkdirAll("/templates", 0755); err != nil {
|
||||||
|
fmt.Println("Fehler beim Erstellen des Zielordners:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := copyDirContents("/git-temp/articles", "/content"); err != nil {
|
||||||
|
fmt.Println("Fehler beim Kopieren:", err)
|
||||||
|
} else {
|
||||||
|
fmt.Println("Kopieren abgeschlossen.")
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := copyDirContents("/git-temp/static", "/static"); err != nil {
|
||||||
|
fmt.Println("Fehler beim Kopieren:", err)
|
||||||
|
} else {
|
||||||
|
fmt.Println("Kopieren abgeschlossen.")
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := copyDirContents("/git-temp/pages", "/pages"); err != nil {
|
||||||
|
fmt.Println("Fehler beim Kopieren:", err)
|
||||||
|
} else {
|
||||||
|
fmt.Println("Kopieren abgeschlossen.")
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := copyDirContents("/git-temp/templates", "/templates"); err != nil {
|
||||||
|
fmt.Println("Fehler beim Kopieren:", err)
|
||||||
|
} else {
|
||||||
|
fmt.Println("Kopieren abgeschlossen.")
|
||||||
|
}
|
||||||
|
|
||||||
|
articles, err := article.LoadDir(contentDir)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
Xarticles = articles
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func copyDirContents(srcDir, destDir string) error {
|
||||||
|
entries, err := os.ReadDir(srcDir)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Fehler beim Lesen von %s: %w", srcDir, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, entry := range entries {
|
||||||
|
srcPath := filepath.Join(srcDir, entry.Name())
|
||||||
|
destPath := filepath.Join(destDir, entry.Name())
|
||||||
|
|
||||||
|
info, err := entry.Info()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if info.IsDir() {
|
||||||
|
if err := os.MkdirAll(destPath, info.Mode()); err != nil {
|
||||||
|
return fmt.Errorf("Fehler beim Erstellen von Ordner %s: %w", destPath, err)
|
||||||
|
}
|
||||||
|
// rekursiv kopieren
|
||||||
|
if err := copyDirContents(srcPath, destPath); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if err := copyFile(srcPath, destPath, info); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func copyFile(src, dest string, info os.FileInfo) error {
|
||||||
|
in, err := os.Open(src)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer in.Close()
|
||||||
|
|
||||||
|
out, err := os.Create(dest)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer out.Close()
|
||||||
|
|
||||||
|
if _, err := io.Copy(out, in); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return os.Chmod(dest, info.Mode())
|
||||||
|
}
|
||||||
|
|
||||||
|
func startAutoClone(repoURL, branch, dir string, interval time.Duration) {
|
||||||
|
go cloneRepo(repoURL, branch, dir) // sofortiger Start
|
||||||
|
|
||||||
|
ticker := time.NewTicker(interval)
|
||||||
|
defer ticker.Stop()
|
||||||
|
|
||||||
|
for range ticker.C {
|
||||||
|
go cloneRepo(repoURL, branch, dir)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user