mirror of
https://codeberg.org/git-pages/git-pages.git
synced 2026-05-14 11:11:35 +00:00
This commit changes the git fetch algorithm to only retrieve blobs that aren't included in the previously deployed site manifest, if git filters are supported by the remote. It also changes how manifest entry sizes are represented, such that both decompressed and compressed sizes are stored. This enables computing accurate (and repeatable) sizes even after incremental updates. Co-authored-by: David Leadbeater <dgl@dgl.cx>
155 lines
3.6 KiB
Go
155 lines
3.6 KiB
Go
package git_pages
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"io"
|
|
"strings"
|
|
)
|
|
|
|
type UpdateOutcome int
|
|
|
|
const (
|
|
UpdateError UpdateOutcome = iota
|
|
UpdateTimeout
|
|
UpdateCreated
|
|
UpdateReplaced
|
|
UpdateDeleted
|
|
UpdateNoChange
|
|
)
|
|
|
|
type UpdateResult struct {
|
|
outcome UpdateOutcome
|
|
manifest *Manifest
|
|
err error
|
|
}
|
|
|
|
func Update(ctx context.Context, webRoot string, manifest *Manifest) UpdateResult {
|
|
var oldManifest, newManifest *Manifest
|
|
var err error
|
|
|
|
outcome := UpdateError
|
|
oldManifest, _, _ = backend.GetManifest(ctx, webRoot, GetManifestOptions{})
|
|
if IsManifestEmpty(manifest) {
|
|
newManifest, err = manifest, backend.DeleteManifest(ctx, webRoot)
|
|
if err == nil {
|
|
if oldManifest == nil {
|
|
outcome = UpdateNoChange
|
|
} else {
|
|
outcome = UpdateDeleted
|
|
}
|
|
}
|
|
} else if err = PrepareManifest(ctx, manifest); err == nil {
|
|
newManifest, err = StoreManifest(ctx, webRoot, manifest)
|
|
if err == nil {
|
|
domain, _, _ := strings.Cut(webRoot, "/")
|
|
err = backend.CreateDomain(ctx, domain)
|
|
}
|
|
if err == nil {
|
|
if oldManifest == nil {
|
|
outcome = UpdateCreated
|
|
} else if CompareManifest(oldManifest, newManifest) {
|
|
outcome = UpdateNoChange
|
|
} else {
|
|
outcome = UpdateReplaced
|
|
}
|
|
}
|
|
}
|
|
|
|
if err == nil {
|
|
status := ""
|
|
switch outcome {
|
|
case UpdateCreated:
|
|
status = "created"
|
|
case UpdateReplaced:
|
|
status = "replaced"
|
|
case UpdateDeleted:
|
|
status = "deleted"
|
|
case UpdateNoChange:
|
|
status = "unchanged"
|
|
}
|
|
if newManifest.Commit != nil {
|
|
logc.Printf(ctx, "update %s ok: %s %s", webRoot, status, *newManifest.Commit)
|
|
} else {
|
|
logc.Printf(ctx, "update %s ok: %s", webRoot, status)
|
|
}
|
|
} else {
|
|
logc.Printf(ctx, "update %s err: %s", webRoot, err)
|
|
}
|
|
|
|
return UpdateResult{outcome, newManifest, err}
|
|
}
|
|
|
|
func UpdateFromRepository(
|
|
ctx context.Context,
|
|
webRoot string,
|
|
repoURL string,
|
|
branch string,
|
|
) (result UpdateResult) {
|
|
span, ctx := ObserveFunction(ctx, "UpdateFromRepository", "repo.url", repoURL)
|
|
defer span.Finish()
|
|
|
|
logc.Printf(ctx, "update %s: %s %s\n", webRoot, repoURL, branch)
|
|
|
|
oldManifest, _, _ := backend.GetManifest(ctx, webRoot, GetManifestOptions{})
|
|
// Ignore errors; worst case we have to re-fetch all of the blobs.
|
|
|
|
manifest, err := FetchRepository(ctx, repoURL, branch, oldManifest)
|
|
if errors.Is(err, context.DeadlineExceeded) {
|
|
result = UpdateResult{UpdateTimeout, nil, fmt.Errorf("update timeout")}
|
|
} else if err != nil {
|
|
result = UpdateResult{UpdateError, nil, err}
|
|
} else {
|
|
result = Update(ctx, webRoot, manifest)
|
|
}
|
|
|
|
observeUpdateResult(result)
|
|
return result
|
|
}
|
|
|
|
var errArchiveFormat = errors.New("unsupported archive format")
|
|
|
|
func UpdateFromArchive(
|
|
ctx context.Context,
|
|
webRoot string,
|
|
contentType string,
|
|
reader io.Reader,
|
|
) (result UpdateResult) {
|
|
var manifest *Manifest
|
|
var err error
|
|
|
|
switch contentType {
|
|
case "application/x-tar":
|
|
logc.Printf(ctx, "update %s: (tar)", webRoot)
|
|
manifest, err = ExtractTar(reader) // yellow?
|
|
case "application/x-tar+gzip":
|
|
logc.Printf(ctx, "update %s: (tar.gz)", webRoot)
|
|
manifest, err = ExtractTarGzip(reader) // definitely yellow.
|
|
case "application/x-tar+zstd":
|
|
logc.Printf(ctx, "update %s: (tar.zst)", webRoot)
|
|
manifest, err = ExtractTarZstd(reader)
|
|
case "application/zip":
|
|
logc.Printf(ctx, "update %s: (zip)", webRoot)
|
|
manifest, err = ExtractZip(reader)
|
|
default:
|
|
err = errArchiveFormat
|
|
}
|
|
|
|
if err != nil {
|
|
logc.Printf(ctx, "update %s err: %s", webRoot, err)
|
|
result = UpdateResult{UpdateError, nil, err}
|
|
} else {
|
|
result = Update(ctx, webRoot, manifest)
|
|
}
|
|
|
|
observeUpdateResult(result)
|
|
return
|
|
}
|
|
|
|
func observeUpdateResult(result UpdateResult) {
|
|
if result.err != nil {
|
|
ObserveError(result.err)
|
|
}
|
|
}
|