Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
K
k3s
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Jacklull
k3s
Commits
b1a3235f
Unverified
Commit
b1a3235f
authored
Aug 30, 2017
by
Michal Fojtik
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
code-generator: allow to customize generated verbs and add custom verb
parent
c026b62d
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
249 additions
and
7 deletions
+249
-7
generator_fake_for_type.go
...cmd/client-gen/generators/fake/generator_fake_for_type.go
+0
-0
generator_for_type.go
...generator/cmd/client-gen/generators/generator_for_type.go
+0
-0
tags.go
....io/code-generator/cmd/client-gen/generators/util/tags.go
+185
-7
tags_test.go
...ode-generator/cmd/client-gen/generators/util/tags_test.go
+64
-0
No files found.
staging/src/k8s.io/code-generator/cmd/client-gen/generators/fake/generator_fake_for_type.go
View file @
b1a3235f
This diff is collapsed.
Click to expand it.
staging/src/k8s.io/code-generator/cmd/client-gen/generators/generator_for_type.go
View file @
b1a3235f
This diff is collapsed.
Click to expand it.
staging/src/k8s.io/code-generator/cmd/client-gen/generators/util/tags.go
View file @
b1a3235f
...
...
@@ -32,6 +32,7 @@ var supportedTags = []string{
"genclient:skipVerbs"
,
"genclient:noStatus"
,
"genclient:readonly"
,
"genclient:method"
,
}
// SupportedVerbs is a list of supported verbs for +onlyVerbs and +skipVerbs.
...
...
@@ -54,6 +55,96 @@ var ReadonlyVerbs = []string{
"watch"
,
}
// genClientPrefix is the default prefix for all genclient tags.
const
genClientPrefix
=
"genclient:"
// unsupportedExtensionVerbs is a list of verbs we don't support generating
// extension client functions for.
var
unsupportedExtensionVerbs
=
[]
string
{
"updateStatus"
,
"deleteCollection"
,
"watch"
,
"delete"
,
}
// inputTypeSupportedVerbs is a list of verb types that supports overriding the
// input argument type.
var
inputTypeSupportedVerbs
=
[]
string
{
"create"
,
"update"
,
}
// resultTypeSupportedVerbs is a list of verb types that supports overriding the
// resulting type.
var
resultTypeSupportedVerbs
=
[]
string
{
"create"
,
"update"
,
"get"
,
"list"
,
"patch"
,
}
// Extensions allows to extend the default set of client verbs
// (CRUD+watch+patch+list+deleteCollection) for a given type with custom defined
// verbs. Custom verbs can have custom input and result types and also allow to
// use a sub-resource in a request instead of top-level resource type.
//
// Example:
//
// +genclient:method=UpdateScale,verb=update,subresource=scale,input=Scale,result=Scale
//
// type ReplicaSet struct { ... }
//
// The 'method=UpdateScale' is the name of the client function.
// The 'verb=update' here means the client function will use 'PUT' action.
// The 'subresource=scale' means we will use SubResource template to generate this client function.
// The 'input' is the input type used for creation (function argument).
// The 'result' (not needed in this case) is the result type returned from the
// client function.
//
type
extension
struct
{
// VerbName is the name of the custom verb (Scale, Instantiate, etc..)
VerbName
string
// VerbType is the type of the verb (only verbs from SupportedVerbs are
// supported)
VerbType
string
// SubResourcePath defines a path to a sub-resource to use in the request.
// (optional)
SubResourcePath
string
// InputTypeOverride overrides the input parameter type for the verb. By
// default the original type is used. Overriding the input type only works for
// "create" and "update" verb types. The given type must exists in the same
// package as the original type.
// (optional)
InputTypeOverride
string
// ResultTypeOverride overrides the resulting object type for the verb. By
// default the original type is used. Overriding the result type works.
// (optional)
ResultTypeOverride
string
}
// IsSubresource indicates if this extension should generate the sub-resource.
func
(
e
*
extension
)
IsSubresource
()
bool
{
return
len
(
e
.
SubResourcePath
)
>
0
}
// HasVerb checks if the extension matches the given verb.
func
(
e
*
extension
)
HasVerb
(
verb
string
)
bool
{
return
e
.
VerbType
==
verb
}
// Input returns the input override package path and the type.
func
(
e
*
extension
)
Input
()
(
string
,
string
)
{
parts
:=
strings
.
Split
(
e
.
InputTypeOverride
,
"."
)
return
parts
[
len
(
parts
)
-
1
],
strings
.
Join
(
parts
[
0
:
len
(
parts
)
-
1
],
"."
)
}
// Result returns the result override package path and the type.
func
(
e
*
extension
)
Result
()
(
string
,
string
)
{
parts
:=
strings
.
Split
(
e
.
ResultTypeOverride
,
"."
)
return
parts
[
len
(
parts
)
-
1
],
strings
.
Join
(
parts
[
0
:
len
(
parts
)
-
1
],
"."
)
}
// Tags represents a genclient configuration for a single type.
type
Tags
struct
{
// +genclient
...
...
@@ -67,6 +158,8 @@ type Tags struct {
// +genclient:skipVerbs=get,update
// +genclient:onlyVerbs=create,delete
SkipVerbs
[]
string
// +genclient:method=UpdateScale,verb=update,subresource=scale,input=Scale,result=Scale
Extensions
[]
extension
}
// HasVerb returns true if we should include the given verb in final client interface and
...
...
@@ -103,25 +196,25 @@ func ParseClientGenTags(lines []string) (Tags, error) {
if
len
(
value
)
>
0
&&
len
(
value
[
0
])
>
0
{
return
ret
,
fmt
.
Errorf
(
"+genclient=%s is invalid, use //+genclient if you want to generate client or omit it when you want to disable generation"
,
value
)
}
_
,
ret
.
NonNamespaced
=
values
[
"genclient:
nonNamespaced"
]
_
,
ret
.
NonNamespaced
=
values
[
genClientPrefix
+
"
nonNamespaced"
]
// Check the old format and error when used
if
value
:=
values
[
"nonNamespaced"
];
len
(
value
)
>
0
&&
len
(
value
[
0
])
>
0
{
return
ret
,
fmt
.
Errorf
(
"+nonNamespaced=%s is invalid, use //+genclient:nonNamespaced instead"
,
value
[
0
])
}
_
,
ret
.
NoVerbs
=
values
[
"genclient:
noVerbs"
]
_
,
ret
.
NoStatus
=
values
[
"genclient:
noStatus"
]
_
,
ret
.
NoVerbs
=
values
[
genClientPrefix
+
"
noVerbs"
]
_
,
ret
.
NoStatus
=
values
[
genClientPrefix
+
"
noStatus"
]
onlyVerbs
:=
[]
string
{}
if
_
,
isReadonly
:=
values
[
"genclient:
readonly"
];
isReadonly
{
if
_
,
isReadonly
:=
values
[
genClientPrefix
+
"
readonly"
];
isReadonly
{
onlyVerbs
=
ReadonlyVerbs
}
// Check the old format and error when used
if
value
:=
values
[
"readonly"
];
len
(
value
)
>
0
&&
len
(
value
[
0
])
>
0
{
return
ret
,
fmt
.
Errorf
(
"+readonly=%s is invalid, use //+genclient:readonly instead"
,
value
[
0
])
}
if
v
,
exists
:=
values
[
"genclient:
skipVerbs"
];
exists
{
if
v
,
exists
:=
values
[
genClientPrefix
+
"
skipVerbs"
];
exists
{
ret
.
SkipVerbs
=
strings
.
Split
(
v
[
0
],
","
)
}
if
v
,
exists
:=
values
[
"genclient:
onlyVerbs"
];
exists
||
len
(
onlyVerbs
)
>
0
{
if
v
,
exists
:=
values
[
genClientPrefix
+
"
onlyVerbs"
];
exists
||
len
(
onlyVerbs
)
>
0
{
if
len
(
v
)
>
0
{
onlyVerbs
=
append
(
onlyVerbs
,
strings
.
Split
(
v
[
0
],
","
)
...
)
}
...
...
@@ -146,16 +239,101 @@ func ParseClientGenTags(lines []string) (Tags, error) {
}
ret
.
SkipVerbs
=
skipVerbs
}
var
err
error
if
ret
.
Extensions
,
err
=
parseClientExtensions
(
values
);
err
!=
nil
{
return
ret
,
err
}
return
ret
,
validateClientGenTags
(
values
)
}
func
parseClientExtensions
(
tags
map
[
string
][]
string
)
([]
extension
,
error
)
{
var
ret
[]
extension
for
name
,
values
:=
range
tags
{
if
!
strings
.
HasPrefix
(
name
,
genClientPrefix
+
"method"
)
{
continue
}
for
_
,
value
:=
range
values
{
// the value comes in this form: "Foo,verb=create"
ext
:=
extension
{}
parts
:=
strings
.
Split
(
value
,
","
)
if
len
(
parts
)
==
0
{
return
nil
,
fmt
.
Errorf
(
"invalid of empty extension verb name: %q"
,
value
)
}
// The first part represents the name of the extension
ext
.
VerbName
=
parts
[
0
]
if
len
(
ext
.
VerbName
)
==
0
{
return
nil
,
fmt
.
Errorf
(
"must specify a verb name (// +genclient:method=Foo,verb=create)"
)
}
// Parse rest of the arguments
params
:=
parts
[
1
:
]
for
_
,
p
:=
range
params
{
parts
:=
strings
.
Split
(
p
,
"="
)
if
len
(
parts
)
!=
2
{
return
nil
,
fmt
.
Errorf
(
"invalid extension tag specification %q"
,
p
)
}
key
,
val
:=
strings
.
TrimSpace
(
parts
[
0
]),
strings
.
TrimSpace
(
parts
[
1
])
if
len
(
val
)
==
0
{
return
nil
,
fmt
.
Errorf
(
"empty value of %q for %q extension"
,
key
,
ext
.
VerbName
)
}
switch
key
{
case
"verb"
:
ext
.
VerbType
=
val
case
"subresource"
:
ext
.
SubResourcePath
=
val
case
"input"
:
ext
.
InputTypeOverride
=
val
case
"result"
:
ext
.
ResultTypeOverride
=
val
default
:
return
nil
,
fmt
.
Errorf
(
"unknown extension configuration key %q"
,
key
)
}
}
// Validate resulting extension configuration
if
len
(
ext
.
VerbType
)
==
0
{
return
nil
,
fmt
.
Errorf
(
"verb type must be specified (use '// +genclient:method=%s,verb=create')"
,
ext
.
VerbName
)
}
if
len
(
ext
.
ResultTypeOverride
)
>
0
{
supported
:=
false
for
_
,
v
:=
range
resultTypeSupportedVerbs
{
if
ext
.
VerbType
==
v
{
supported
=
true
break
}
}
if
!
supported
{
return
nil
,
fmt
.
Errorf
(
"%s: result type is not supported for %q verbs (supported verbs: %#v)"
,
ext
.
VerbName
,
ext
.
VerbType
,
resultTypeSupportedVerbs
)
}
}
if
len
(
ext
.
InputTypeOverride
)
>
0
{
supported
:=
false
for
_
,
v
:=
range
inputTypeSupportedVerbs
{
if
ext
.
VerbType
==
v
{
supported
=
true
break
}
}
if
!
supported
{
return
nil
,
fmt
.
Errorf
(
"%s: input type is not supported for %q verbs (supported verbs: %#v)"
,
ext
.
VerbName
,
ext
.
VerbType
,
inputTypeSupportedVerbs
)
}
}
for
_
,
t
:=
range
unsupportedExtensionVerbs
{
if
ext
.
VerbType
==
t
{
return
nil
,
fmt
.
Errorf
(
"verb %q is not supported by extension generator"
,
ext
.
VerbType
)
}
}
ret
=
append
(
ret
,
ext
)
}
}
return
ret
,
nil
}
// validateTags validates that only supported genclient tags were provided.
func
validateClientGenTags
(
values
map
[
string
][]
string
)
error
{
for
_
,
k
:=
range
supportedTags
{
delete
(
values
,
k
)
}
for
key
:=
range
values
{
if
strings
.
HasPrefix
(
key
,
"genclient"
)
{
if
strings
.
HasPrefix
(
key
,
strings
.
TrimSuffix
(
genClientPrefix
,
":"
)
)
{
return
errors
.
New
(
"unknown tag detected: "
+
key
)
}
}
...
...
staging/src/k8s.io/code-generator/cmd/client-gen/generators/util/tags_test.go
View file @
b1a3235f
...
...
@@ -82,3 +82,67 @@ func TestParseTags(t *testing.T) {
}
}
}
func
TestParseTagsExtension
(
t
*
testing
.
T
)
{
testCases
:=
map
[
string
]
struct
{
lines
[]
string
expectedExtensions
[]
extension
expectError
bool
}{
"simplest extension"
:
{
lines
:
[]
string
{
`+genclient:method=Foo,verb=create`
},
expectedExtensions
:
[]
extension
{{
VerbName
:
"Foo"
,
VerbType
:
"create"
}},
},
"multiple extensions"
:
{
lines
:
[]
string
{
`+genclient:method=Foo,verb=create`
,
`+genclient:method=Bar,verb=get`
},
expectedExtensions
:
[]
extension
{{
VerbName
:
"Foo"
,
VerbType
:
"create"
},
{
VerbName
:
"Bar"
,
VerbType
:
"get"
}},
},
"extension without verb"
:
{
lines
:
[]
string
{
`+genclient:method`
},
expectError
:
true
,
},
"extension without verb type"
:
{
lines
:
[]
string
{
`+genclient:method=Foo`
},
expectError
:
true
,
},
"sub-resource extension"
:
{
lines
:
[]
string
{
`+genclient:method=Foo,verb=create,subresource=bar`
},
expectedExtensions
:
[]
extension
{{
VerbName
:
"Foo"
,
VerbType
:
"create"
,
SubResourcePath
:
"bar"
}},
},
"output type extension"
:
{
lines
:
[]
string
{
`+genclient:method=Foos,verb=list,result=Bars`
},
expectedExtensions
:
[]
extension
{{
VerbName
:
"Foos"
,
VerbType
:
"list"
,
ResultTypeOverride
:
"Bars"
}},
},
"input type extension"
:
{
lines
:
[]
string
{
`+genclient:method=Foo,verb=update,input=Bar`
},
expectedExtensions
:
[]
extension
{{
VerbName
:
"Foo"
,
VerbType
:
"update"
,
InputTypeOverride
:
"Bar"
}},
},
"unknown verb type extension"
:
{
lines
:
[]
string
{
`+genclient:method=Foo,verb=explode`
},
expectedExtensions
:
nil
,
expectError
:
true
,
},
"invalid verb extension"
:
{
lines
:
[]
string
{
`+genclient:method=Foo,unknown=bar`
},
expectedExtensions
:
nil
,
expectError
:
true
,
},
"empty verb extension subresource"
:
{
lines
:
[]
string
{
`+genclient:method=Foo,verb=get,subresource=`
},
expectedExtensions
:
nil
,
expectError
:
true
,
},
}
for
key
,
c
:=
range
testCases
{
result
,
err
:=
ParseClientGenTags
(
c
.
lines
)
if
err
!=
nil
&&
!
c
.
expectError
{
t
.
Fatalf
(
"[%s] unexpected error: %v"
,
key
,
err
)
}
if
err
!=
nil
&&
c
.
expectError
{
t
.
Logf
(
"[%s] got expected error: %+v"
,
key
,
err
)
}
if
!
c
.
expectError
&&
!
reflect
.
DeepEqual
(
result
.
Extensions
,
c
.
expectedExtensions
)
{
t
.
Errorf
(
"[%s] expected %#+v to be %#+v"
,
key
,
result
.
Extensions
,
c
.
expectedExtensions
)
}
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment