chore: migrate mail themes to shared framework and locked upstream inputs
Release / Validate Templates (push) Canceled after 0s
Release / Package & Release (push) Canceled after 0s
Release / Update Latest Release Documentation (push) Canceled after 0s

This commit is contained in:
KenanZhu committed 2026-10-09 18:34:36 +08:00
1 parent 5c0589f6f6
commit fec3ace600
225 files changed
+4718 -15807

No files matched your search

+139
View File
@@ -0,0 +1,139 @@
package upstream
import (
"context"
"encoding/json"
"fmt"
"io"
"net/http"
"os"
"path/filepath"
"reflect"
"time"
)
func CacheDir(root string) string { return filepath.Join(root, "build", "upstream") }
func ReadLock(root string) (Lock, error) {
var lock Lock
b, err := os.ReadFile(filepath.Join(root, "gitea.lock.json"))
if err != nil {
return lock, err
}
if err = json.Unmarshal(b, &lock); err != nil {
return lock, err
}
return lock, lock.validateIdentity()
}
func LoadPinned(root string) (*Snapshot, error) {
lock, err := ReadLock(root)
if err != nil {
return nil, err
}
s, err := Load(CacheDir(root))
if err != nil {
return nil, err
}
if !reflect.DeepEqual(lock, s.Lock) {
return nil, fmt.Errorf("upstream cache differs from gitea.lock.json; run upstream prepare after reviewing the lock")
}
return s, nil
}
// Prepare fetches immutable commit files only if the cache is absent. A corrupt
// cache is an error, not permission to silently replace local evidence.
func Prepare(ctx context.Context, root string) (*Snapshot, error) {
return prepareFrom(ctx, root, "https://raw.githubusercontent.com/go-gitea/gitea/")
}
func prepareFrom(ctx context.Context, root, rawBase string) (*Snapshot, error) {
lock, err := ReadLock(root)
if err != nil {
return nil, err
}
if _, err = os.Stat(filepath.Join(CacheDir(root), "lock.json")); err == nil {
return LoadPinned(root)
} else if !os.IsNotExist(err) {
return nil, err
}
client := &http.Client{Timeout: 45 * time.Second}
s := &Snapshot{Lock: lock, Files: map[string][]byte{}}
for name, hash := range lock.Files {
if !SafePath(name) {
return nil, fmt.Errorf("unsafe locked path %q", name)
}
req, err := http.NewRequestWithContext(ctx, http.MethodGet, rawBase+lock.Commit+"/"+name, nil)
if err != nil {
return nil, err
}
req.Header.Set("User-Agent", "GiteaMailTemplates-locked-cache")
resp, err := client.Do(req)
if err != nil {
return nil, err
}
b, readErr := io.ReadAll(io.LimitReader(resp.Body, 16<<20))
resp.Body.Close()
if readErr != nil {
return nil, readErr
}
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("%s: HTTP %d", name, resp.StatusCode)
}
if Digest(b) != hash {
return nil, fmt.Errorf("download checksum mismatch: %s", name)
}
s.Files[name] = b
}
if err = s.validate(); err != nil {
return nil, err
}
dir := CacheDir(root)
if err = os.MkdirAll(filepath.Dir(dir), 0755); err != nil {
return nil, err
}
stage, err := os.MkdirTemp(filepath.Dir(dir), ".upstream-cache-")
if err != nil {
return nil, err
}
defer os.RemoveAll(stage)
for name, b := range s.Files {
target := filepath.Join(stage, filepath.FromSlash(name))
if err = os.MkdirAll(filepath.Dir(target), 0755); err != nil {
return nil, err
}
if err = os.WriteFile(target, b, 0644); err != nil {
return nil, err
}
}
b, _ := json.MarshalIndent(lock, "", " ")
if err = os.WriteFile(filepath.Join(stage, "lock.json"), append(b, '\n'), 0644); err != nil {
return nil, err
}
if _, err = os.Stat(dir); err == nil {
return nil, fmt.Errorf("incomplete upstream cache exists at %s; inspect it before removing it", dir)
}
if err = os.Rename(stage, dir); err != nil {
return nil, err
}
fmt.Printf("[PASS] Downloaded locked Gitea %s (%s) to build cache\n", lock.Tag, lock.Commit)
return LoadPinned(root)
}
func SyncRoot(ctx context.Context, tag, root string) error {
if err := os.MkdirAll(filepath.Join(root, "build"), 0755); err != nil {
return err
}
if err := Sync(ctx, tag, CacheDir(root)); err != nil {
return err
}
s, err := Load(CacheDir(root))
if err != nil {
return err
}
b, err := json.MarshalIndent(s.Lock, "", " ")
if err != nil {
return err
}
return os.WriteFile(filepath.Join(root, "gitea.lock.json"), append(b, '\n'), 0644)
}