Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ require (
k8s.io/apimachinery v0.18.2
k8s.io/cli-runtime v0.18.2
k8s.io/client-go v0.18.2
k8s.io/gengo v0.0.0-20200114144118-36b2048a9120
k8s.io/klog v1.0.0
k8s.io/kubectl v0.18.2
rsc.io/letsencrypt v0.0.3 // indirect
Expand Down
76 changes: 76 additions & 0 deletions hack/generate/migrate-markers.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
#!/usr/bin/env bash

# Migrate old CSV annotations to new markers.
# Example:
# $ ./migrate-markers.sh *.go

OLD_MARKER_BASE="operator-sdk:gen-csv:customresourcedefinitions"
NEW_MARKER_BASE="operator-sdk:csv:customresourcedefinitions"

SPEC_TYPE="spec"
STATUS_TYPE="status"

function migrate_displayName() {
local old_marker_pattern="${OLD_MARKER_BASE}"'\.displayName="([^"]+)"'
local new_marker_pattern="${NEW_MARKER_BASE}"':displayName="\1"'

sed -i -E 's/'$old_marker_pattern'/'$new_marker_pattern'/g' "$1"
}

function migrate_resources() {
local old_marker_pattern_1="${OLD_MARKER_BASE}"'\.resources="([^\,]+)\,([^\,]+)\,\\"([^\\]+)\\""'
local old_marker_pattern_2="${OLD_MARKER_BASE}"'\.resources="([^\,]+)\,([^\,]+)\,"'
local new_marker_pattern_1="${NEW_MARKER_BASE}"':resources={\1,\2,"\3"}'
local new_marker_pattern_2="${NEW_MARKER_BASE}"':resources={\1,\2,}'

Comment on lines +21 to +25
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Impressive! regex always impresses me :)

sed -i -E 's/'$old_marker_pattern_1'/'$new_marker_pattern_1'/g' "$1"
sed -i -E 's/'$old_marker_pattern_2'/'$new_marker_pattern_2'/g' "$1"
}

function migrate_typeDescriptors() {
local type=$2
local old_marker_true_pattern="${OLD_MARKER_BASE}\.${type}Descriptors=true"
local old_marker_false_pattern="${OLD_MARKER_BASE}\.${type}Descriptors=false"
local new_marker_pattern="${NEW_MARKER_BASE}:type=${type}"

sed -i -E 's/'$old_marker_true_pattern'/'$new_marker_pattern'/g' "$1"
sed -i -E 's/'$old_marker_false_pattern'//g' "$1"
}

function migrate_typeDescriptors_displayName() {
local type=$2
local old_marker_pattern="${OLD_MARKER_BASE}\.${type}Descriptors"'\.displayName="([^"]+)"'
local new_marker_pattern="${NEW_MARKER_BASE}:type=${type}"',displayName="\1"'

sed -i -E 's/'$old_marker_pattern'/'$new_marker_pattern'/g' "$1"
}

function migrate_typeDescriptors_xDescriptors() {
local type=$2
local old_marker_pattern="${OLD_MARKER_BASE}\.${type}Descriptors"'\.x-descriptors="([^"]+)"'
local new_marker_pattern="${NEW_MARKER_BASE}:type=${type}"',xDescriptors="\1"'

sed -i -E 's/'$old_marker_pattern'/'$new_marker_pattern'/g' "$1"
}

set -eu
shopt -s extglob nullglob
FILES=$*
shopt -u extglob nullglob

for file in $FILES; do
if ! [[ "$file" =~ .*\.go ]]; then
continue
fi
# Globals
migrate_displayName "$file"
migrate_resources "$file"
# Spec descriptors
migrate_typeDescriptors "$file" $SPEC_TYPE
migrate_typeDescriptors_displayName "$file" $SPEC_TYPE
migrate_typeDescriptors_xDescriptors "$file" $SPEC_TYPE
# Status descriptors
migrate_typeDescriptors "$file" $STATUS_TYPE
migrate_typeDescriptors_displayName "$file" $STATUS_TYPE
migrate_typeDescriptors_xDescriptors "$file" $STATUS_TYPE
done
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import (
"k8s.io/apimachinery/pkg/runtime/schema"
"sigs.k8s.io/yaml"

"github.com/operator-framework/operator-sdk/internal/generate/clusterserviceversion/bases/definitions"
"github.com/operator-framework/operator-sdk/internal/util/k8sutil"
"github.com/operator-framework/operator-sdk/internal/util/projutil"
)
Expand Down Expand Up @@ -80,9 +81,11 @@ func (b ClusterServiceVersion) GetBase() (base *v1alpha1.ClusterServiceVersion,
if b.APIsDir != "" {
switch b.OperatorType {
case projutil.OperatorTypeGo:
if err := updateDescriptionsForGVKs(base, b.APIsDir, b.GVKs); err != nil {
return nil, fmt.Errorf("error generating ClusterServiceVersion base metadata: %w", err)
}
// Update descriptions from the APIs dir.
err = definitions.ApplyDefinitionsForKeysGo(base, b.APIsDir, b.GVKs)
}
if err != nil {
return nil, fmt.Errorf("error generating ClusterServiceVersion definitions metadata: %w", err)
}
}

Expand Down
105 changes: 105 additions & 0 deletions internal/generate/clusterserviceversion/bases/definitions/ast.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
// Copyright 2020 The Operator-SDK 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 definitions

import (
"errors"
"fmt"
"go/ast"
"strings"

"sigs.k8s.io/controller-tools/pkg/markers"
)

// getMarkedChildrenOfField collects all marked fields from type declarations starting at root in depth-first order.
func (g generator) getMarkedChildrenOfField(root markers.FieldInfo) (map[string][]*fieldInfo, error) {
// ast.Inspect will not traverse into fields, so iteratively collect them and to check for markers.
nextFields := []*fieldInfo{{FieldInfo: root}}
markedFields := map[string][]*fieldInfo{}
for len(nextFields) > 0 {
fields := []*fieldInfo{}
for _, field := range nextFields {
errs := []error{}
ast.Inspect(field.RawField, func(n ast.Node) bool {
if n == nil {
return true
}
switch expr := n.(type) {
case *ast.Ident:
// Only look at type names.
if expr.Obj == nil || expr.Obj.Kind != ast.Typ {
return true
}
// Check if the field's type exists in the known types.
info, hasInfo := g.types[expr.Name]
if !hasInfo {
return true
}
// Add all child fields to the list to search next.
for _, finfo := range info.Fields {
segment, err := getPathSegmentForField(finfo)
if err != nil {
errs = append(errs, fmt.Errorf("error getting path from type %s field %s: %v",
info.Name, finfo.Name, err),
)
return true
}
// Add extra information to the segment if it comes from a certain field type.
switch finfo.RawField.Type.(type) {
case (*ast.ArrayType):
// arrayFieldGroup case.
if segment != ignoredTag && segment != inlinedTag {
segment += "[0]"
}
}
// Create a new set of path segments using the parent's segments
// and add the field to the next fields to search.
f := &fieldInfo{
FieldInfo: finfo,
pathSegments: append(field.pathSegments, segment),
}
fields = append(fields, f)
// Marked fields get collected for the caller to parse.
if len(finfo.Markers) != 0 {
markedFields[info.Name] = append(markedFields[info.Name], f)
}
}
}
return true
})
if err := fmtParseErrors(errs); err != nil {
return nil, err
}
}
nextFields = fields
}
return markedFields, nil
}

// fmtParseErrors prettifies a list of errors to make them easier to read.
func fmtParseErrors(errs []error) error {
switch len(errs) {
case 0:
return nil
case 1:
return errs[0]
}
sb := strings.Builder{}
for _, err := range errs {
sb.WriteString("\n")
sb.WriteString(err.Error())
}
return errors.New(sb.String())
}
Loading