aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--cmd/mbf/main.go41
-rw-r--r--internal/rosa/mirror.go109
2 files changed, 150 insertions, 0 deletions
diff --git a/cmd/mbf/main.go b/cmd/mbf/main.go
index 471b595a..a6c74a0f 100644
--- a/cmd/mbf/main.go
+++ b/cmd/mbf/main.go
@@ -568,6 +568,47 @@ func main() {
},
)
+ c.NewCommand(
+ "snapshot",
+ "Populate an empty directory with a static mirror snapshot",
+ func(args []string) error {
+ if len(args) != 1 {
+ return errors.New("snapshot requires 1 argument")
+ }
+
+ var key ed25519.PrivateKey
+ if p, err := os.ReadFile(filepath.Join(cm.base, "ed25519")); err != nil {
+ return err
+ } else if len(p) != ed25519.PrivateKeySize {
+ return errors.New("invalid private key")
+ } else {
+ key = p
+ }
+
+ var m rosa.Mirror
+ if base, err := os.OpenRoot(cm.base); err != nil {
+ return err
+ } else {
+ m = rosa.NewMirror(msg, base.FS(), key)
+ }
+
+ retry:
+ root, err := os.OpenRoot(args[0])
+ if err != nil {
+ if os.IsNotExist(err) {
+ if err = os.MkdirAll(args[0], 0755); err != nil {
+ return err
+ }
+ goto retry
+ }
+ return err
+ }
+
+ go func() { <-ctx.Done(); _ = root.Close() }()
+ return m.Populate(root)
+ },
+ )
+
{
var (
flagGentoo string
diff --git a/internal/rosa/mirror.go b/internal/rosa/mirror.go
index d4dfba1e..80d4509c 100644
--- a/internal/rosa/mirror.go
+++ b/internal/rosa/mirror.go
@@ -14,6 +14,7 @@ import (
"path/filepath"
"strconv"
"strings"
+ "syscall"
"unique"
"hakurei.app/internal/pkg"
@@ -211,6 +212,114 @@ type Mirror struct {
msg message.Msg
}
+// Populate fills an empty root with a static mirror snapshot.
+func (m Mirror) Populate(root *os.Root) error {
+ if dents, err := fs.ReadDir(root.FS(), "."); err != nil {
+ return err
+ } else if len(dents) > 0 {
+ return syscall.ENOTEMPTY
+ }
+
+ for _, name := range []string{
+ dirArtifact,
+ dirOutcome,
+ dirStatus,
+ } {
+ if err := root.Mkdir(name, 0755); err != nil {
+ return err
+ }
+ }
+ var w *os.File
+
+ if dents, err := fs.ReadDir(m.fsys, "identifier"); err != nil {
+ return err
+ } else {
+ for _, dent := range dents {
+ name := dent.Name()
+ var buf [2 * len(pkg.Checksum{})]byte
+ if err = pkg.Decode(
+ (*pkg.Checksum)(buf[:len(pkg.Checksum{})]),
+ name,
+ ); err != nil {
+ return err
+ }
+
+ if w, err = root.OpenFile(
+ filepath.Join(dirArtifact, name),
+ syscall.O_WRONLY|syscall.O_CREAT|syscall.O_EXCL,
+ 0444,
+ ); err != nil {
+ return err
+ }
+ err = m.writeArtifact(&buf, w, nil)
+ if err = errors.Join(err, w.Close()); err != nil {
+ return err
+ }
+ }
+ }
+
+ if dents, err := fs.ReadDir(m.fsys, "checksum"); err != nil {
+ return err
+ } else {
+ for _, dent := range dents {
+ name := dent.Name()
+ var buf pkg.Checksum
+ if err = pkg.Decode(&buf, name); err != nil {
+ return err
+ }
+
+ var fsys fs.FS
+ fsys, err = fs.Sub(m.fsys, filepath.Join("checksum", name))
+ if err != nil {
+ return err
+ }
+
+ if w, err = root.OpenFile(
+ filepath.Join(dirOutcome, name),
+ syscall.O_WRONLY|syscall.O_CREAT|syscall.O_EXCL,
+ 0444,
+ ); err != nil {
+ return err
+ }
+
+ m.msg.Verbosef("exporting outcome %s", name)
+ err = pkg.Write(fsys, ".", w)
+ if err = errors.Join(err, w.Close()); err != nil {
+ return err
+ }
+ }
+ }
+
+ if dents, err := fs.ReadDir(m.fsys, "status"); err != nil {
+ return err
+ } else {
+ for _, dent := range dents {
+ name := dent.Name()
+ var buf [2 * len(pkg.Checksum{})]byte
+ if err = pkg.Decode(
+ (*pkg.Checksum)(buf[:len(pkg.Checksum{})]),
+ name,
+ ); err != nil {
+ return err
+ }
+
+ if w, err = root.OpenFile(
+ filepath.Join(dirStatus, name),
+ syscall.O_WRONLY|syscall.O_CREAT|syscall.O_EXCL,
+ 0444,
+ ); err != nil {
+ return err
+ }
+ err = m.writeStatus(&buf, w, nil)
+ if err = errors.Join(err, w.Close()); err != nil {
+ return err
+ }
+ }
+ }
+
+ return nil
+}
+
// NewMirror returns a populated [Mirror] for servicing mirror requests.
func NewMirror(
msg message.Msg,