-
Notifications
You must be signed in to change notification settings - Fork 338
/
manifest.go
136 lines (106 loc) · 2.98 KB
/
manifest.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
// Copyright 2020 The Swarm Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package simple
import (
"encoding"
"encoding/json"
"errors"
"fmt"
"strings"
"sync"
)
// Error used when lookup path does not match
var (
ErrNotFound = errors.New("not found")
ErrEmptyPath = errors.New("empty path")
)
// Manifest is a representation of a manifest.
type Manifest interface {
// Add adds a manifest entry to the specified path.
Add(string, string, map[string]string) error
// Remove removes a manifest entry on the specified path.
Remove(string) error
// Lookup returns a manifest node entry if one is found in the specified path.
Lookup(string) (Entry, error)
// HasPrefix tests whether the specified prefix path exists.
HasPrefix(string) bool
// Length returns an implementation-specific count of elements in the manifest.
// For Manifest, this means the number of all the existing entries.
Length() int
// WalkEntry walks all entries, calling walkFn for each entry in the map.
// All errors that arise visiting entires are filtered by walkFn.
WalkEntry(string, WalkEntryFunc) error
encoding.BinaryMarshaler
encoding.BinaryUnmarshaler
}
// manifest is a JSON representation of a manifest.
// It stores manifest entries in a map based on string keys.
type manifest struct {
Entries map[string]*entry `json:"entries,omitempty"`
mu sync.RWMutex // mutex for accessing the entries map
}
// NewManifest creates a new Manifest struct and returns a pointer to it.
func NewManifest() Manifest {
return &manifest{
Entries: make(map[string]*entry),
}
}
func notFound(path string) error {
return fmt.Errorf("entry on '%s': %w", path, ErrNotFound)
}
func (m *manifest) Add(path, entry string, metadata map[string]string) error {
if path == "" {
return ErrEmptyPath
}
m.mu.Lock()
defer m.mu.Unlock()
m.Entries[path] = newEntry(entry, metadata)
return nil
}
func (m *manifest) Remove(path string) error {
if path == "" {
return ErrEmptyPath
}
m.mu.Lock()
defer m.mu.Unlock()
delete(m.Entries, path)
return nil
}
func (m *manifest) Lookup(path string) (Entry, error) {
m.mu.RLock()
defer m.mu.RUnlock()
entry, ok := m.Entries[path]
if !ok {
return nil, notFound(path)
}
// return a copy to prevent external modification
return newEntry(entry.Reference(), entry.Metadata()), nil
}
func (m *manifest) HasPrefix(path string) bool {
m.mu.RLock()
defer m.mu.RUnlock()
for k := range m.Entries {
if strings.HasPrefix(k, path) {
return true
}
}
return false
}
func (m *manifest) Length() int {
m.mu.RLock()
defer m.mu.RUnlock()
return len(m.Entries)
}
// MarshalBinary implements encoding.BinaryMarshaler.
func (m *manifest) MarshalBinary() ([]byte, error) {
m.mu.RLock()
defer m.mu.RUnlock()
return json.Marshal(m)
}
// UnmarshalBinary implements encoding.BinaryUnmarshaler.
func (m *manifest) UnmarshalBinary(b []byte) error {
m.mu.Lock()
defer m.mu.Unlock()
return json.Unmarshal(b, m)
}