Fix Lockfile Schematics

This commit is contained in:
2026-04-10 12:32:27 +02:00
parent 543945f099
commit 9300033e95
2 changed files with 130 additions and 2 deletions
+107 -2
View File
@@ -1,6 +1,7 @@
package topdata
import (
"bytes"
"encoding/json"
"errors"
"fmt"
@@ -3600,17 +3601,121 @@ func saveLockfile(path string, lockData map[string]int) error {
if err := os.MkdirAll(filepath.Dir(path), 0o755); err != nil {
return fmt.Errorf("create lockfile parent: %w", err)
}
raw, err := json.MarshalIndent(lockData, "", " ")
keys, err := orderedLockfileKeys(path, lockData)
if err != nil {
return fmt.Errorf("read lockfile order: %w", err)
}
raw, err := marshalOrderedLockfile(keys, lockData)
if err != nil {
return fmt.Errorf("marshal lockfile: %w", err)
}
raw = append(raw, '\n')
if err := os.WriteFile(path, raw, 0o644); err != nil {
return fmt.Errorf("write lockfile %s: %w", path, err)
}
return nil
}
func orderedLockfileKeys(path string, lockData map[string]int) ([]string, error) {
existingKeys, err := readLockfileKeyOrder(path)
if err != nil && !errors.Is(err, os.ErrNotExist) {
return nil, err
}
keys := make([]string, 0, len(lockData))
seen := make(map[string]struct{}, len(lockData))
for _, key := range existingKeys {
if _, ok := lockData[key]; !ok {
continue
}
keys = append(keys, key)
seen[key] = struct{}{}
}
extraKeys := make([]string, 0, len(lockData)-len(keys))
for key := range lockData {
if _, ok := seen[key]; ok {
continue
}
extraKeys = append(extraKeys, key)
}
slices.Sort(extraKeys)
keys = append(keys, extraKeys...)
return keys, nil
}
func readLockfileKeyOrder(path string) ([]string, error) {
raw, err := os.ReadFile(path)
if err != nil {
return nil, err
}
decoder := json.NewDecoder(bytes.NewReader(raw))
token, err := decoder.Token()
if err != nil {
return nil, err
}
delim, ok := token.(json.Delim)
if !ok || delim != '{' {
return nil, fmt.Errorf("%s must contain a JSON object", path)
}
keys := []string{}
for decoder.More() {
token, err := decoder.Token()
if err != nil {
return nil, err
}
key, ok := token.(string)
if !ok {
return nil, fmt.Errorf("%s contains a non-string object key", path)
}
var value json.RawMessage
if err := decoder.Decode(&value); err != nil {
return nil, err
}
keys = append(keys, key)
}
token, err = decoder.Token()
if err != nil {
return nil, err
}
delim, ok = token.(json.Delim)
if !ok || delim != '}' {
return nil, fmt.Errorf("%s must contain a JSON object", path)
}
return keys, nil
}
func marshalOrderedLockfile(keys []string, lockData map[string]int) ([]byte, error) {
if len(keys) == 0 {
return []byte("{}\n"), nil
}
var buffer bytes.Buffer
buffer.WriteString("{\n")
for index, key := range keys {
keyRaw, err := json.Marshal(key)
if err != nil {
return nil, err
}
valueRaw, err := json.Marshal(lockData[key])
if err != nil {
return nil, err
}
buffer.WriteString(" ")
buffer.Write(keyRaw)
buffer.WriteString(": ")
buffer.Write(valueRaw)
if index < len(keys)-1 {
buffer.WriteByte(',')
}
buffer.WriteByte('\n')
}
buffer.WriteString("}\n")
return buffer.Bytes(), nil
}
func loadLegacyTLK(root string) (*legacyTLKData, error) {
info, err := os.Stat(root)
if err != nil {