-
Notifications
You must be signed in to change notification settings - Fork 277
/
mapper.go
163 lines (141 loc) · 4.41 KB
/
mapper.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
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
// Copyright 2020-2022 Buf Technologies, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package storage
import (
"github.com/bufbuild/buf/private/pkg/normalpath"
)
// Mapper is a path mapper.
//
// This will cause a Bucket to operate as if the Mapper has all paths mapped.
type Mapper interface {
// Map maps the path to the full path.
//
// The path is expected to be normalized and validated.
// The returned path is expected to be normalized and validated.
// If the path cannot be mapped, this returns false.
MapPath(path string) (string, bool)
// Map maps the prefix to the full prefix.
//
// The path is expected to be normalized and validated.
// The returned path is expected to be normalized and validated.
// If the path cannot be mapped, this returns false.
MapPrefix(prefix string) (string, bool)
// UnmapFullPath maps the full path to the path.
//
// Returns false if the full path does not apply.
// The path is expected to be normalized and validated.
// The returned path is expected to be normalized and validated.
UnmapFullPath(fullPath string) (string, bool, error)
isMapper()
}
// MapOnPrefix returns a Mapper that will map the Bucket as if it was created on the given prefix.
//
// The prefix is expected to be normalized and validated.
func MapOnPrefix(prefix string) Mapper {
return prefixMapper{prefix}
}
// MapChain chains the mappers.
//
// If any mapper does not match, this stops checking Mappers and returns
// an empty path and false. This is as opposed to MatchAnd, that runs
// every Matcher and returns the path regardless.
//
// If the Mappers are empty, a no-op Mapper is returned.
// If there is more than one Mapper, the Mappers are called in order
// for UnmapFullPath, with the order reversed for MapPath and MapPrefix.
//
// That is, order these assuming you are starting with a full path and
// working to a path.
func MapChain(mappers ...Mapper) Mapper {
switch len(mappers) {
case 0:
return nopMapper{}
case 1:
return mappers[0]
default:
return chainMapper{mappers}
}
}
// ***** private *****
type prefixMapper struct {
prefix string
}
func (p prefixMapper) MapPath(path string) (string, bool) {
return normalpath.Join(p.prefix, path), true
}
func (p prefixMapper) MapPrefix(prefix string) (string, bool) {
return normalpath.Join(p.prefix, prefix), true
}
func (p prefixMapper) UnmapFullPath(fullPath string) (string, bool, error) {
if !normalpath.EqualsOrContainsPath(p.prefix, fullPath, normalpath.Relative) {
return "", false, nil
}
path, err := normalpath.Rel(p.prefix, fullPath)
if err != nil {
return "", false, err
}
return path, true, nil
}
func (prefixMapper) isMapper() {}
type chainMapper struct {
mappers []Mapper
}
func (c chainMapper) MapPath(path string) (string, bool) {
return c.mapFunc(path, Mapper.MapPath)
}
func (c chainMapper) MapPrefix(prefix string) (string, bool) {
return c.mapFunc(prefix, Mapper.MapPrefix)
}
func (c chainMapper) UnmapFullPath(fullPath string) (string, bool, error) {
path := fullPath
var matches bool
var err error
for _, mapper := range c.mappers {
path, matches, err = mapper.UnmapFullPath(path)
if err != nil {
return "", false, err
}
if !matches {
return "", false, nil
}
}
return path, true, nil
}
func (c chainMapper) mapFunc(
pathOrPrefix string,
f func(Mapper, string) (string, bool),
) (string, bool) {
fullPathOrPrefix := pathOrPrefix
var matches bool
for i := len(c.mappers) - 1; i >= 0; i-- {
mapper := c.mappers[i]
fullPathOrPrefix, matches = f(mapper, fullPathOrPrefix)
if !matches {
return "", false
}
}
return fullPathOrPrefix, true
}
func (chainMapper) isMapper() {}
type nopMapper struct{}
func (n nopMapper) MapPath(path string) (string, bool) {
return path, true
}
func (n nopMapper) MapPrefix(prefix string) (string, bool) {
return prefix, true
}
func (nopMapper) UnmapFullPath(fullPath string) (string, bool, error) {
return fullPath, true, nil
}
func (nopMapper) isMapper() {}