package cli import ( "encoding/hex" "encoding/json" "fmt" "time" "github.com/urfave/cli/v2" "sneak.berlin/go/mfer/mfer" ) // ExportEntry represents a single file entry in the exported JSON output. type ExportEntry struct { Path string `json:"path"` Size int64 `json:"size"` Hashes []string `json:"hashes"` Mtime *string `json:"mtime,omitempty"` Ctime *string `json:"ctime,omitempty"` } func (mfa *CLIApp) exportManifestOperation(ctx *cli.Context) error { pathOrURL, err := mfa.resolveManifestArg(ctx) if err != nil { return fmt.Errorf("export: %w", err) } rc, err := mfa.openManifestReader(pathOrURL) if err != nil { return fmt.Errorf("export: %w", err) } defer func() { _ = rc.Close() }() manifest, err := mfer.NewManifestFromReader(rc) if err != nil { return fmt.Errorf("export: failed to parse manifest: %w", err) } files := manifest.Files() entries := make([]ExportEntry, 0, len(files)) for _, f := range files { entry := ExportEntry{ Path: f.GetPath(), Size: f.GetSize(), Hashes: make([]string, 0, len(f.GetHashes())), } for _, h := range f.GetHashes() { entry.Hashes = append(entry.Hashes, hex.EncodeToString(h.GetMultiHash())) } if mtime, ok := entryMtime(f); ok { t := mtime.UTC().Format(time.RFC3339Nano) entry.Mtime = &t } if f.GetCtime() != nil { t := time.Unix(f.GetCtime().GetSeconds(), int64(f.GetCtime().GetNanos())). UTC().Format(time.RFC3339Nano) entry.Ctime = &t } entries = append(entries, entry) } enc := json.NewEncoder(mfa.Stdout) enc.SetIndent("", " ") err = enc.Encode(entries) if err != nil { return fmt.Errorf("export: failed to encode JSON: %w", err) } return nil }