Implement migration from v1 data layout.

This commit is contained in:
Catherine
2025-09-17 13:13:58 +00:00
parent 31131a6360
commit a0bd7d8650
4 changed files with 115 additions and 2 deletions

View File

@@ -5,6 +5,7 @@ import (
"log"
"net"
"net/http"
"os"
)
var backend Backend
@@ -26,6 +27,7 @@ func main() {
var err error
configPath := flag.String("config", "config.toml", "path to configuration file")
migrateV1Path := flag.String("migrate-v1", "", "path to v1 data directory to upload")
flag.Parse()
if err := ReadConfig(*configPath); err != nil {
@@ -55,6 +57,20 @@ func main() {
log.Fatalln("unknown backend:", config.Backend.Type)
}
if *migrateV1Path != "" {
root, err := os.OpenRoot(*migrateV1Path)
if err != nil {
log.Fatalln("migrate v1:", err)
}
err = MigrateFromV1(root)
if err != nil {
log.Fatalln("migrate v1:", err)
}
log.Println("migrate v1 ok")
}
log.Println("ready")
if config.Caddy != (ListenConfig{}) {

View File

@@ -103,7 +103,7 @@ const ManifestSizeMax int = 1048576
// Accepts a manifest with inline files, returns a manifest with external files after writing
// file contents and the manifest itself to the storage.
func StoreManifest(backend Backend, name string, manifest *Manifest) (*Manifest, error) {
func StoreManifest(name string, manifest *Manifest) (*Manifest, error) {
extManifest := ExternalizeFiles(manifest)
extManifestData := EncodeManifest(extManifest)
if len(extManifestData) > ManifestSizeMax {

97
src/migrate.go Normal file
View File

@@ -0,0 +1,97 @@
package main
import (
"fmt"
"io/fs"
"log"
"os"
"path/filepath"
)
func readToManifest(root *os.Root) (*Manifest, error) {
manifest := Manifest{}
manifest.Tree = make(map[string]*Entry)
err := fs.WalkDir(root.FS(), ".", func(path string, dirEntry fs.DirEntry, err error) error {
if err != nil {
return err
}
manifestEntry := Entry{}
if dirEntry.IsDir() {
manifestEntry.Type = Type_Directory
} else if dirEntry.Type().IsRegular() {
data, err := root.ReadFile(path)
if err != nil {
return err
}
manifestEntry.Type = Type_InlineFile
manifestEntry.Size = int64(len(data))
manifestEntry.Data = data
} else if dirEntry.Type().Type() == fs.ModeSymlink {
target, err := root.Readlink(path)
if err != nil {
return err
}
manifestEntry.Type = Type_Symlink
manifestEntry.Size = int64(len(target))
manifestEntry.Data = []byte(target)
} else {
log.Println("migrate v1: illegal %s/%s", root.Name(), path)
}
if path == "." {
path = ""
}
manifest.Tree[path] = &manifestEntry
return nil
})
return &manifest, err
}
type ReadDirLinkFS interface { // aaaaahh!!! Why is Go like this!!
fs.ReadDirFS
fs.ReadLinkFS
}
func MigrateFromV1(root *os.Root) error {
data := root.FS().(ReadDirLinkFS)
domainDirEntries, err := data.ReadDir("www")
if err != nil {
return err
}
for _, domainDirEntry := range domainDirEntries {
domain := domainDirEntry.Name()
if !domainDirEntry.IsDir() {
return fmt.Errorf("migrate v1: www/%s: not a directory", domain)
}
projectDirEntries, err := data.ReadDir(filepath.Join("www", domain))
if err != nil {
return err
}
for _, projectDirEntry := range projectDirEntries {
projectName := projectDirEntry.Name()
if projectDirEntry.Type().Type() != fs.ModeSymlink {
return fmt.Errorf("migrate v1: www/%s/%s: not a symlink", domain, projectName)
}
treeRoot, err := root.OpenRoot(filepath.Join("www", domain, projectName))
if err != nil {
return err
}
manifest, err := readToManifest(treeRoot)
if err != nil {
return fmt.Errorf("migrate v1: read %s/%s: %w", domain, projectName, err)
}
_, err = StoreManifest(fmt.Sprintf("%s/%s", domain, projectName), manifest)
if err != nil {
return fmt.Errorf("migrate v1: store %s/%s: %w", domain, projectName, err)
}
}
}
return nil
}

View File

@@ -41,7 +41,7 @@ func Update(
err = fmt.Errorf("update timeout")
} else if err == nil {
oldManifest, _ = backend.GetManifest(webRoot)
newManifest, err = StoreManifest(backend, webRoot, fetchManifest)
newManifest, err = StoreManifest(webRoot, fetchManifest)
if err == nil {
if oldManifest == nil {
outcome = UpdateCreated