harbor/src/pkg/reg/util/pattern.go
Wenkai Yin(尹文开) 28596c3ffb
Refactor registry API (#14528)
* Refactor registry API

Refactor registry API

Signed-off-by: Wenkai Yin <yinw@vmware.com>

* Fix bugs of replications

1. Fix the scheduled replication doesn't work issue
2. Fix the destination name lost issue when updating replication policy

Signed-off-by: Wenkai Yin <yinw@vmware.com>
2021-03-31 15:49:23 +08:00

122 lines
3.7 KiB
Go

// Copyright Project Harbor Authors
//
// 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 util
import (
"fmt"
"strings"
"github.com/bmatcuk/doublestar"
)
// Match returns whether the str matches the pattern
func Match(pattern, str string) (bool, error) {
if len(pattern) == 0 {
return true, nil
}
return doublestar.Match(pattern, str)
}
// IsSpecificPath checks whether the input path is a specified string
// If it is, the function returns a string array that parsed from the input path
// A specified string means we can get a specific string array after parsing it
// "library/hello-world" is a specified string as it only matches "library/hello-world"
// "library/**" isn't a specified string as it can match all string that starts with "library/"
// "library/{test,busybox}" is a specified string as it only matches "library/hello-world" and "library/busybox"
func IsSpecificPath(path string) ([]string, bool) {
if len(path) == 0 {
return nil, false
}
components := [][]string{}
for _, component := range strings.Split(path, "/") {
strs, ok := IsSpecificPathComponent(component)
if !ok {
return nil, false
}
components = append(components, strs)
}
result := []string{}
for _, component := range components {
result = combinationPathComponents(result, component)
}
return result, true
}
func combinationPathComponents(components1, components2 []string) []string {
if len(components1) == 0 {
return components2
}
if len(components2) == 0 {
return components1
}
components := []string{}
for _, component1 := range components1 {
for _, component2 := range components2 {
components = append(components, fmt.Sprintf("%s/%s", component1, component2))
}
}
return components
}
// IsSpecificPathComponent checks whether the input path component is a specified string
// If it is, the function returns a string array that parsed from the input component
// A specified string means we can get a specific string array after parsing it
// "library" is a specified string as it only matches "library"
// "library*" isn't a specified string as it can match all string that starts with "library"
// "{library, test}" is a specified string as it only matches "library" and "test"
// Note: the function doesn't support the component that contains more than one "{"
// such as "a{b{c,d}e}f"
func IsSpecificPathComponent(component string) ([]string, bool) {
if len(component) == 0 {
return nil, false
}
// contains any of *?[\\]^
if strings.ContainsAny(component, "*?[\\]^/") {
return nil, false
}
// doesn't contain {},
if !strings.ContainsAny(component, "{},") {
return []string{component}, true
}
// support only one pair of {} currently
n := strings.Count(component, "{")
if n > 1 {
return nil, false
}
i := strings.Index(component, "{")
if i == -1 {
return nil, false
}
j := strings.LastIndex(component, "}")
if j == -1 {
return nil, false
}
if i > j {
return nil, false
}
prefix := component[:i]
suffix := ""
if j+1 < len(component) {
suffix = component[j+1:]
}
components := []string{}
strs := strings.Split(component[i+1:j], ",")
for _, str := range strs {
components = append(components, prefix+str+suffix)
}
return components, true
}