2022-07-29 06:29:21 +02:00
|
|
|
// Copyright (C) 2022 NHR@FAU, University Erlangen-Nuremberg.
|
|
|
|
// All rights reserved.
|
|
|
|
// Use of this source code is governed by a MIT-style
|
|
|
|
// license that can be found in the LICENSE file.
|
2022-09-05 17:46:38 +02:00
|
|
|
package archive
|
2022-03-14 10:18:56 +01:00
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"strconv"
|
|
|
|
"strings"
|
|
|
|
|
2022-06-21 17:52:36 +02:00
|
|
|
"github.com/ClusterCockpit/cc-backend/pkg/log"
|
2022-03-14 10:18:56 +01:00
|
|
|
)
|
|
|
|
|
2022-05-16 09:10:55 +02:00
|
|
|
type NodeList [][]interface {
|
|
|
|
consume(input string) (next string, ok bool)
|
2023-03-30 15:21:35 +02:00
|
|
|
limits() []map[string]int64
|
|
|
|
prefix() string
|
2022-05-16 09:10:55 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
func (nl *NodeList) Contains(name string) bool {
|
|
|
|
var ok bool
|
|
|
|
for _, term := range *nl {
|
|
|
|
str := name
|
|
|
|
for _, expr := range term {
|
|
|
|
str, ok = expr.consume(str)
|
|
|
|
if !ok {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if ok && str == "" {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
2023-03-30 15:21:35 +02:00
|
|
|
func (nl *NodeList) PrintList() []string {
|
|
|
|
var out []string
|
|
|
|
for _, term := range *nl {
|
|
|
|
prefix := term[0].prefix()
|
|
|
|
limitArr := term[1].limits()
|
|
|
|
for _, inner := range limitArr {
|
|
|
|
for i := inner["start"]; i < inner["end"]+1; i++ {
|
|
|
|
node := fmt.Sprintf("%s%02d", prefix, i)
|
|
|
|
out = append(out, node)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return out
|
|
|
|
}
|
|
|
|
|
2022-03-14 10:18:56 +01:00
|
|
|
type NLExprString string
|
|
|
|
|
|
|
|
func (nle NLExprString) consume(input string) (next string, ok bool) {
|
|
|
|
str := string(nle)
|
|
|
|
if strings.HasPrefix(input, str) {
|
|
|
|
return strings.TrimPrefix(input, str), true
|
|
|
|
}
|
|
|
|
return "", false
|
|
|
|
}
|
|
|
|
|
2023-03-30 15:21:35 +02:00
|
|
|
func (nle NLExprString) limits() []map[string]int64 {
|
|
|
|
// Null implementation to fullfill interface requirement
|
|
|
|
l := make([]map[string]int64, 0)
|
|
|
|
return l
|
|
|
|
}
|
|
|
|
|
|
|
|
func (nle NLExprString) prefix() string {
|
|
|
|
return string(nle)
|
|
|
|
}
|
|
|
|
|
2022-05-16 09:10:55 +02:00
|
|
|
type NLExprIntRanges []NLExprIntRange
|
|
|
|
|
|
|
|
func (nles NLExprIntRanges) consume(input string) (next string, ok bool) {
|
|
|
|
for _, nle := range nles {
|
|
|
|
if next, ok := nle.consume(input); ok {
|
|
|
|
return next, ok
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return "", false
|
|
|
|
}
|
|
|
|
|
2023-03-30 15:21:35 +02:00
|
|
|
func (nles NLExprIntRanges) limits() []map[string]int64 {
|
|
|
|
l := make([]map[string]int64, 0)
|
|
|
|
for _, nle := range nles {
|
|
|
|
inner := nle.limits()
|
|
|
|
l = append(l, inner[0])
|
|
|
|
}
|
|
|
|
return l
|
|
|
|
}
|
|
|
|
|
|
|
|
func (nles NLExprIntRanges) prefix() string {
|
|
|
|
// Null implementation to fullfill interface requirement
|
|
|
|
var s string
|
|
|
|
return s
|
|
|
|
}
|
|
|
|
|
2022-03-14 10:18:56 +01:00
|
|
|
type NLExprIntRange struct {
|
|
|
|
start, end int64
|
|
|
|
zeroPadded bool
|
|
|
|
digits int
|
|
|
|
}
|
|
|
|
|
|
|
|
func (nle NLExprIntRange) consume(input string) (next string, ok bool) {
|
|
|
|
if !nle.zeroPadded || nle.digits < 1 {
|
|
|
|
log.Error("node list: only zero-padded ranges are allowed")
|
|
|
|
return "", false
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(input) < nle.digits {
|
|
|
|
return "", false
|
|
|
|
}
|
|
|
|
|
|
|
|
numerals, rest := input[:nle.digits], input[nle.digits:]
|
|
|
|
for len(numerals) > 1 && numerals[0] == '0' {
|
|
|
|
numerals = numerals[1:]
|
|
|
|
}
|
|
|
|
|
|
|
|
x, err := strconv.ParseInt(numerals, 10, 32)
|
|
|
|
if err != nil {
|
|
|
|
return "", false
|
|
|
|
}
|
|
|
|
|
|
|
|
if nle.start <= x && x <= nle.end {
|
|
|
|
return rest, true
|
|
|
|
}
|
|
|
|
|
|
|
|
return "", false
|
|
|
|
}
|
|
|
|
|
2023-03-30 15:21:35 +02:00
|
|
|
func (nle NLExprIntRange) limits() []map[string]int64 {
|
|
|
|
l := make([]map[string]int64, 0)
|
|
|
|
m := make(map[string]int64)
|
|
|
|
m["start"] = nle.start
|
|
|
|
m["end"] = nle.end
|
|
|
|
l = append(l, m)
|
|
|
|
return l
|
|
|
|
}
|
|
|
|
|
|
|
|
func (nles NLExprIntRange) prefix() string {
|
|
|
|
// Null implementation to fullfill interface requirement
|
|
|
|
var s string
|
|
|
|
return s
|
|
|
|
}
|
|
|
|
|
2022-05-16 09:10:55 +02:00
|
|
|
func ParseNodeList(raw string) (NodeList, error) {
|
|
|
|
isLetter := func(r byte) bool { return ('a' <= r && r <= 'z') || ('A' <= r && r <= 'Z') }
|
|
|
|
isDigit := func(r byte) bool { return '0' <= r && r <= '9' }
|
2022-03-14 10:18:56 +01:00
|
|
|
|
2022-05-16 09:10:55 +02:00
|
|
|
rawterms := []string{}
|
|
|
|
prevterm := 0
|
|
|
|
for i := 0; i < len(raw); i++ {
|
|
|
|
if raw[i] == '[' {
|
|
|
|
for i < len(raw) && raw[i] != ']' {
|
|
|
|
i++
|
2022-03-14 10:18:56 +01:00
|
|
|
}
|
2022-05-16 09:10:55 +02:00
|
|
|
if i == len(raw) {
|
|
|
|
return nil, fmt.Errorf("node list: unclosed '['")
|
|
|
|
}
|
|
|
|
} else if raw[i] == ',' {
|
|
|
|
rawterms = append(rawterms, raw[prevterm:i])
|
|
|
|
prevterm = i + 1
|
2022-03-14 10:18:56 +01:00
|
|
|
}
|
|
|
|
}
|
2022-05-16 09:10:55 +02:00
|
|
|
if prevterm != len(raw) {
|
|
|
|
rawterms = append(rawterms, raw[prevterm:])
|
|
|
|
}
|
2022-03-14 10:18:56 +01:00
|
|
|
|
|
|
|
nl := NodeList{}
|
2022-05-16 09:10:55 +02:00
|
|
|
for _, rawterm := range rawterms {
|
2022-03-14 10:18:56 +01:00
|
|
|
exprs := []interface {
|
|
|
|
consume(input string) (next string, ok bool)
|
2023-03-30 15:21:35 +02:00
|
|
|
limits() []map[string]int64
|
|
|
|
prefix() string
|
2022-03-14 10:18:56 +01:00
|
|
|
}{}
|
|
|
|
for i := 0; i < len(rawterm); i++ {
|
|
|
|
c := rawterm[i]
|
|
|
|
if isLetter(c) || isDigit(c) {
|
|
|
|
j := i
|
|
|
|
for j < len(rawterm) && (isLetter(rawterm[j]) || isDigit(rawterm[j])) {
|
|
|
|
j++
|
|
|
|
}
|
|
|
|
exprs = append(exprs, NLExprString(rawterm[i:j]))
|
|
|
|
i = j - 1
|
|
|
|
} else if c == '[' {
|
|
|
|
end := strings.Index(rawterm[i:], "]")
|
|
|
|
if end == -1 {
|
|
|
|
return nil, fmt.Errorf("node list: unclosed '['")
|
|
|
|
}
|
|
|
|
|
2022-05-16 09:10:55 +02:00
|
|
|
parts := strings.Split(rawterm[i+1:i+end], ",")
|
|
|
|
nles := NLExprIntRanges{}
|
|
|
|
for _, part := range parts {
|
|
|
|
minus := strings.Index(part, "-")
|
|
|
|
if minus == -1 {
|
|
|
|
return nil, fmt.Errorf("node list: no '-' found inside '[...]'")
|
|
|
|
}
|
|
|
|
|
|
|
|
s1, s2 := part[0:minus], part[minus+1:]
|
|
|
|
if len(s1) != len(s2) || len(s1) == 0 {
|
|
|
|
return nil, fmt.Errorf("node list: %#v and %#v are not of equal length or of length zero", s1, s2)
|
|
|
|
}
|
|
|
|
|
|
|
|
x1, err := strconv.ParseInt(s1, 10, 32)
|
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("node list: %w", err)
|
|
|
|
}
|
|
|
|
x2, err := strconv.ParseInt(s2, 10, 32)
|
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("node list: %w", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
nles = append(nles, NLExprIntRange{
|
|
|
|
start: x1,
|
|
|
|
end: x2,
|
|
|
|
digits: len(s1),
|
|
|
|
zeroPadded: true,
|
|
|
|
})
|
2022-03-14 10:18:56 +01:00
|
|
|
}
|
|
|
|
|
2022-05-16 09:10:55 +02:00
|
|
|
exprs = append(exprs, nles)
|
2022-03-14 10:18:56 +01:00
|
|
|
i += end
|
|
|
|
} else {
|
|
|
|
return nil, fmt.Errorf("node list: invalid character: %#v", rune(c))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
nl = append(nl, exprs)
|
|
|
|
}
|
|
|
|
|
|
|
|
return nl, nil
|
|
|
|
}
|