Refactor: migrate POSIX scaffolding to CBOR and JSONC

This commit is contained in:
MangoPig
2026-07-06 13:06:32 +01:00
parent 2c8338d1cd
commit 58bc285748
14 changed files with 860 additions and 268 deletions
@@ -9,6 +9,22 @@ import (
"path/filepath"
"strings"
"unicode"
"github.com/fxamacker/cbor/v2"
"github.com/tailscale/hujson"
)
const (
posixSettingsFileName = "settings.cbor"
posixLayoutFileName = "layout.cbor"
posixHomeFileName = "home.cbor"
posixUsersFileName = "users.cbor"
posixACLFileName = "acl.cbor"
posixFolderFileName = "folder.cbor"
posixItemFileName = "item.cbor"
posixDataFileName = "data.cbor"
posixSchemaFileName = "schema.json"
posixManifestFileName = "manifest.jsonc"
)
func samePath(left, right string) bool {
@@ -125,14 +141,93 @@ func writeJSONFile(path string, payload any) error {
return os.WriteFile(path, data, 0o644)
}
func readJSONFileMap(path string) map[string]any {
func writeJSONCFile(path string, payload any) error {
parentDir := filepath.Dir(path)
if err := os.MkdirAll(parentDir, 0o755); err != nil {
return err
}
data, err := json.MarshalIndent(payload, "", " ")
if err != nil {
return err
}
content := append([]byte("// This file is JSONC. Comments and trailing commas are allowed.\n"), data...)
content = append(content, '\n')
return os.WriteFile(path, content, 0o644)
}
func writeCBORFile(path string, payload any) error {
parentDir := filepath.Dir(path)
if err := os.MkdirAll(parentDir, 0o755); err != nil {
return err
}
data, err := cbor.Marshal(payload)
if err != nil {
return err
}
return os.WriteFile(path, data, 0o644)
}
func readStructuredFileMap(path string) map[string]any {
data, err := os.ReadFile(path)
if err != nil {
return map[string]any{}
}
var payload map[string]any
if err := json.Unmarshal(data, &payload); err != nil || payload == nil {
var payload any
switch strings.ToLower(filepath.Ext(path)) {
case ".cbor":
err = cbor.Unmarshal(data, &payload)
case ".json":
err = json.Unmarshal(data, &payload)
case ".jsonc":
payload, err = decodeJSONCToAny(data)
default:
return map[string]any{}
}
return payload
if err != nil || payload == nil {
return map[string]any{}
}
normalized, ok := normalizeStructuredValue(payload).(map[string]any)
if !ok || normalized == nil {
return map[string]any{}
}
return normalized
}
func decodeJSONCToAny(data []byte) (any, error) {
ast, err := hujson.Parse(data)
if err != nil {
return nil, err
}
ast.Standardize()
standardized := ast.Pack()
var payload any
if err := json.Unmarshal(standardized, &payload); err != nil {
return nil, err
}
return payload, nil
}
func normalizeStructuredValue(value any) any {
switch typed := value.(type) {
case map[string]any:
normalized := make(map[string]any, len(typed))
for key, child := range typed {
normalized[key] = normalizeStructuredValue(child)
}
return normalized
case map[any]any:
normalized := make(map[string]any, len(typed))
for key, child := range typed {
normalized[fmt.Sprint(key)] = normalizeStructuredValue(child)
}
return normalized
case []any:
normalized := make([]any, len(typed))
for index, child := range typed {
normalized[index] = normalizeStructuredValue(child)
}
return normalized
default:
return value
}
}