Remove k8s.io/code-generator dependency

Signed-off-by: Andy Goldstein <andy.goldstein@gmail.com>
pull/383/head
Andy Goldstein 2018-03-14 17:24:48 -04:00
parent 1455d67152
commit b0a2a0bf7b
71 changed files with 1 additions and 12345 deletions

39
Gopkg.lock generated
View File

@ -586,8 +586,6 @@
"pkg/api/errors",
"pkg/api/meta",
"pkg/api/resource",
"pkg/apimachinery",
"pkg/apimachinery/registered",
"pkg/apis/meta/internalversion",
"pkg/apis/meta/v1",
"pkg/apis/meta/v1/unstructured",
@ -702,41 +700,6 @@
revision = "78700dec6369ba22221b72770783300f143df150"
version = "v6.0.0"
[[projects]]
name = "k8s.io/code-generator"
packages = [
"cmd/client-gen",
"cmd/client-gen/args",
"cmd/client-gen/generators",
"cmd/client-gen/generators/fake",
"cmd/client-gen/generators/scheme",
"cmd/client-gen/generators/util",
"cmd/client-gen/path",
"cmd/client-gen/types",
"cmd/deepcopy-gen",
"cmd/defaulter-gen",
"cmd/informer-gen",
"cmd/informer-gen/generators",
"cmd/lister-gen",
"cmd/lister-gen/generators"
]
revision = "fef8bcdbaf36ac6a1a18c9ef7d85200b249fad30"
version = "kubernetes-1.9.0"
[[projects]]
name = "k8s.io/gengo"
packages = [
"args",
"examples/deepcopy-gen/generators",
"examples/defaulter-gen/generators",
"examples/set-gen/sets",
"generator",
"namer",
"parser",
"types"
]
revision = "b58fc7edb82e0c6ffc9b8aef61813c7261b785d4"
[[projects]]
branch = "master"
name = "k8s.io/kube-openapi"
@ -758,6 +721,6 @@
[solve-meta]
analyzer-name = "dep"
analyzer-version = 1
inputs-digest = "99dc2ee46b7dc9b2e81f0d63b3f478554bed2e767e8cc1703684cde80ccff0df"
inputs-digest = "4b39ff1fb04dedf398ef1e5695bb6b34491b312c55a2626f153f25a6ce3ffc95"
solver-name = "gps-cdcl"
solver-version = 1

View File

@ -20,17 +20,6 @@
# name = "github.com/x/y"
# version = "2.4.0"
required = [
"k8s.io/code-generator/cmd/client-gen",
# needed by generated clientsets, but not an explicit dep in client-gen itself
"k8s.io/apimachinery/pkg/apimachinery/registered",
"k8s.io/code-generator/cmd/deepcopy-gen",
"k8s.io/code-generator/cmd/defaulter-gen",
"k8s.io/code-generator/cmd/lister-gen",
"k8s.io/code-generator/cmd/informer-gen",
]
[prune]
unused-packages = true
non-go = true
@ -108,14 +97,6 @@ required = [
name = "k8s.io/api"
version = "kubernetes-1.9.0"
[[constraint]]
name = "k8s.io/code-generator"
version = "kubernetes-1.9.0"
[[override]]
name = "k8s.io/gengo"
revision = "b58fc7edb82e0c6ffc9b8aef61813c7261b785d4"
[[override]]
name = "github.com/russross/blackfriday"
revision = "93622da34e54fb6529bfb7c57e710f37a8d9cbd8"

View File

@ -1,20 +0,0 @@
/*
Copyright 2014 The Kubernetes 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 apimachinery contains the generic API machinery code that
// is common to both server and clients.
// This package should never import specific API objects.
package apimachinery // import "k8s.io/apimachinery/pkg/apimachinery"

View File

@ -1,336 +0,0 @@
/*
Copyright 2015 The Kubernetes 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 to keep track of API Versions that can be registered and are enabled in a Scheme.
package registered
import (
"fmt"
"sort"
"strings"
"github.com/golang/glog"
"k8s.io/apimachinery/pkg/api/meta"
"k8s.io/apimachinery/pkg/apimachinery"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/util/sets"
)
// APIRegistrationManager provides the concept of what API groups are enabled.
//
// TODO: currently, it also provides a "registered" concept. But it's wrong to
// have both concepts in the same object. Therefore the "announced" package is
// going to take over the registered concept. After all the install packages
// are switched to using the announce package instead of this package, then we
// can combine the registered/enabled concepts in this object. Simplifying this
// isn't easy right now because there are so many callers of this package.
type APIRegistrationManager struct {
// registeredGroupVersions stores all API group versions for which RegisterGroup is called.
registeredVersions map[schema.GroupVersion]struct{}
// enabledVersions represents all enabled API versions. It should be a
// subset of registeredVersions. Please call EnableVersions() to add
// enabled versions.
enabledVersions map[schema.GroupVersion]struct{}
// map of group meta for all groups.
groupMetaMap map[string]*apimachinery.GroupMeta
// envRequestedVersions represents the versions requested via the
// KUBE_API_VERSIONS environment variable. The install package of each group
// checks this list before add their versions to the latest package and
// Scheme. This list is small and order matters, so represent as a slice
envRequestedVersions []schema.GroupVersion
}
// NewAPIRegistrationManager constructs a new manager. The argument ought to be
// the value of the KUBE_API_VERSIONS env var, or a value of this which you
// wish to test.
func NewAPIRegistrationManager(kubeAPIVersions string) (*APIRegistrationManager, error) {
m := &APIRegistrationManager{
registeredVersions: map[schema.GroupVersion]struct{}{},
enabledVersions: map[schema.GroupVersion]struct{}{},
groupMetaMap: map[string]*apimachinery.GroupMeta{},
envRequestedVersions: []schema.GroupVersion{},
}
if len(kubeAPIVersions) != 0 {
for _, version := range strings.Split(kubeAPIVersions, ",") {
gv, err := schema.ParseGroupVersion(version)
if err != nil {
return nil, fmt.Errorf("invalid api version: %s in KUBE_API_VERSIONS: %s.",
version, kubeAPIVersions)
}
m.envRequestedVersions = append(m.envRequestedVersions, gv)
}
}
return m, nil
}
func NewOrDie(kubeAPIVersions string) *APIRegistrationManager {
m, err := NewAPIRegistrationManager(kubeAPIVersions)
if err != nil {
glog.Fatalf("Could not construct version manager: %v (KUBE_API_VERSIONS=%q)", err, kubeAPIVersions)
}
return m
}
// RegisterVersions adds the given group versions to the list of registered group versions.
func (m *APIRegistrationManager) RegisterVersions(availableVersions []schema.GroupVersion) {
for _, v := range availableVersions {
m.registeredVersions[v] = struct{}{}
}
}
// RegisterGroup adds the given group to the list of registered groups.
func (m *APIRegistrationManager) RegisterGroup(groupMeta apimachinery.GroupMeta) error {
groupName := groupMeta.GroupVersion.Group
if _, found := m.groupMetaMap[groupName]; found {
return fmt.Errorf("group %q is already registered in groupsMap: %v", groupName, m.groupMetaMap)
}
m.groupMetaMap[groupName] = &groupMeta
return nil
}
// EnableVersions adds the versions for the given group to the list of enabled versions.
// Note that the caller should call RegisterGroup before calling this method.
// The caller of this function is responsible to add the versions to scheme and RESTMapper.
func (m *APIRegistrationManager) EnableVersions(versions ...schema.GroupVersion) error {
var unregisteredVersions []schema.GroupVersion
for _, v := range versions {
if _, found := m.registeredVersions[v]; !found {
unregisteredVersions = append(unregisteredVersions, v)
}
m.enabledVersions[v] = struct{}{}
}
if len(unregisteredVersions) != 0 {
return fmt.Errorf("Please register versions before enabling them: %v", unregisteredVersions)
}
return nil
}
// IsAllowedVersion returns if the version is allowed by the KUBE_API_VERSIONS
// environment variable. If the environment variable is empty, then it always
// returns true.
func (m *APIRegistrationManager) IsAllowedVersion(v schema.GroupVersion) bool {
if len(m.envRequestedVersions) == 0 {
return true
}
for _, envGV := range m.envRequestedVersions {
if v == envGV {
return true
}
}
return false
}
// IsEnabledVersion returns if a version is enabled.
func (m *APIRegistrationManager) IsEnabledVersion(v schema.GroupVersion) bool {
_, found := m.enabledVersions[v]
return found
}
// EnabledVersions returns all enabled versions. Groups are randomly ordered, but versions within groups
// are priority order from best to worst
func (m *APIRegistrationManager) EnabledVersions() []schema.GroupVersion {
ret := []schema.GroupVersion{}
for _, groupMeta := range m.groupMetaMap {
for _, version := range groupMeta.GroupVersions {
if m.IsEnabledVersion(version) {
ret = append(ret, version)
}
}
}
return ret
}
// EnabledVersionsForGroup returns all enabled versions for a group in order of best to worst
func (m *APIRegistrationManager) EnabledVersionsForGroup(group string) []schema.GroupVersion {
groupMeta, ok := m.groupMetaMap[group]
if !ok {
return []schema.GroupVersion{}
}
ret := []schema.GroupVersion{}
for _, version := range groupMeta.GroupVersions {
if m.IsEnabledVersion(version) {
ret = append(ret, version)
}
}
return ret
}
// Group returns the metadata of a group if the group is registered, otherwise
// an error is returned.
func (m *APIRegistrationManager) Group(group string) (*apimachinery.GroupMeta, error) {
groupMeta, found := m.groupMetaMap[group]
if !found {
return nil, fmt.Errorf("group %v has not been registered", group)
}
groupMetaCopy := *groupMeta
return &groupMetaCopy, nil
}
// IsRegistered takes a string and determines if it's one of the registered groups
func (m *APIRegistrationManager) IsRegistered(group string) bool {
_, found := m.groupMetaMap[group]
return found
}
// IsRegisteredVersion returns if a version is registered.
func (m *APIRegistrationManager) IsRegisteredVersion(v schema.GroupVersion) bool {
_, found := m.registeredVersions[v]
return found
}
// RegisteredGroupVersions returns all registered group versions.
func (m *APIRegistrationManager) RegisteredGroupVersions() []schema.GroupVersion {
ret := []schema.GroupVersion{}
for groupVersion := range m.registeredVersions {
ret = append(ret, groupVersion)
}
return ret
}
// InterfacesFor is a union meta.VersionInterfacesFunc func for all registered types
func (m *APIRegistrationManager) InterfacesFor(version schema.GroupVersion) (*meta.VersionInterfaces, error) {
groupMeta, err := m.Group(version.Group)
if err != nil {
return nil, err
}
return groupMeta.InterfacesFor(version)
}
// TODO: This is an expedient function, because we don't check if a Group is
// supported throughout the code base. We will abandon this function and
// checking the error returned by the Group() function.
func (m *APIRegistrationManager) GroupOrDie(group string) *apimachinery.GroupMeta {
groupMeta, found := m.groupMetaMap[group]
if !found {
if group == "" {
panic("The legacy v1 API is not registered.")
} else {
panic(fmt.Sprintf("Group %s is not registered.", group))
}
}
groupMetaCopy := *groupMeta
return &groupMetaCopy
}
// RESTMapper returns a union RESTMapper of all known types with priorities chosen in the following order:
// 1. if KUBE_API_VERSIONS is specified, then KUBE_API_VERSIONS in order, OR
// 1. legacy kube group preferred version, extensions preferred version, metrics perferred version, legacy
// kube any version, extensions any version, metrics any version, all other groups alphabetical preferred version,
// all other groups alphabetical.
func (m *APIRegistrationManager) RESTMapper(versionPatterns ...schema.GroupVersion) meta.RESTMapper {
unionMapper := meta.MultiRESTMapper{}
unionedGroups := sets.NewString()
for enabledVersion := range m.enabledVersions {
if !unionedGroups.Has(enabledVersion.Group) {
unionedGroups.Insert(enabledVersion.Group)
groupMeta := m.groupMetaMap[enabledVersion.Group]
unionMapper = append(unionMapper, groupMeta.RESTMapper)
}
}
if len(versionPatterns) != 0 {
resourcePriority := []schema.GroupVersionResource{}
kindPriority := []schema.GroupVersionKind{}
for _, versionPriority := range versionPatterns {
resourcePriority = append(resourcePriority, versionPriority.WithResource(meta.AnyResource))
kindPriority = append(kindPriority, versionPriority.WithKind(meta.AnyKind))
}
return meta.PriorityRESTMapper{Delegate: unionMapper, ResourcePriority: resourcePriority, KindPriority: kindPriority}
}
if len(m.envRequestedVersions) != 0 {
resourcePriority := []schema.GroupVersionResource{}
kindPriority := []schema.GroupVersionKind{}
for _, versionPriority := range m.envRequestedVersions {
resourcePriority = append(resourcePriority, versionPriority.WithResource(meta.AnyResource))
kindPriority = append(kindPriority, versionPriority.WithKind(meta.AnyKind))
}
return meta.PriorityRESTMapper{Delegate: unionMapper, ResourcePriority: resourcePriority, KindPriority: kindPriority}
}
prioritizedGroups := []string{"", "extensions", "metrics"}
resourcePriority, kindPriority := m.prioritiesForGroups(prioritizedGroups...)
prioritizedGroupsSet := sets.NewString(prioritizedGroups...)
remainingGroups := sets.String{}
for enabledVersion := range m.enabledVersions {
if !prioritizedGroupsSet.Has(enabledVersion.Group) {
remainingGroups.Insert(enabledVersion.Group)
}
}
remainingResourcePriority, remainingKindPriority := m.prioritiesForGroups(remainingGroups.List()...)
resourcePriority = append(resourcePriority, remainingResourcePriority...)
kindPriority = append(kindPriority, remainingKindPriority...)
return meta.PriorityRESTMapper{Delegate: unionMapper, ResourcePriority: resourcePriority, KindPriority: kindPriority}
}
// prioritiesForGroups returns the resource and kind priorities for a PriorityRESTMapper, preferring the preferred version of each group first,
// then any non-preferred version of the group second.
func (m *APIRegistrationManager) prioritiesForGroups(groups ...string) ([]schema.GroupVersionResource, []schema.GroupVersionKind) {
resourcePriority := []schema.GroupVersionResource{}
kindPriority := []schema.GroupVersionKind{}
for _, group := range groups {
availableVersions := m.EnabledVersionsForGroup(group)
if len(availableVersions) > 0 {
resourcePriority = append(resourcePriority, availableVersions[0].WithResource(meta.AnyResource))
kindPriority = append(kindPriority, availableVersions[0].WithKind(meta.AnyKind))
}
}
for _, group := range groups {
resourcePriority = append(resourcePriority, schema.GroupVersionResource{Group: group, Version: meta.AnyVersion, Resource: meta.AnyResource})
kindPriority = append(kindPriority, schema.GroupVersionKind{Group: group, Version: meta.AnyVersion, Kind: meta.AnyKind})
}
return resourcePriority, kindPriority
}
// AllPreferredGroupVersions returns the preferred versions of all registered
// groups in the form of "group1/version1,group2/version2,..."
func (m *APIRegistrationManager) AllPreferredGroupVersions() string {
if len(m.groupMetaMap) == 0 {
return ""
}
var defaults []string
for _, groupMeta := range m.groupMetaMap {
defaults = append(defaults, groupMeta.GroupVersion.String())
}
sort.Strings(defaults)
return strings.Join(defaults, ",")
}
// ValidateEnvRequestedVersions returns a list of versions that are requested in
// the KUBE_API_VERSIONS environment variable, but not enabled.
func (m *APIRegistrationManager) ValidateEnvRequestedVersions() []schema.GroupVersion {
var missingVersions []schema.GroupVersion
for _, v := range m.envRequestedVersions {
if _, found := m.enabledVersions[v]; !found {
missingVersions = append(missingVersions, v)
}
}
return missingVersions
}

View File

@ -1,87 +0,0 @@
/*
Copyright 2016 The Kubernetes 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 apimachinery
import (
"fmt"
"k8s.io/apimachinery/pkg/api/meta"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
)
// GroupMeta stores the metadata of a group.
type GroupMeta struct {
// GroupVersion represents the preferred version of the group.
GroupVersion schema.GroupVersion
// GroupVersions is Group + all versions in that group.
GroupVersions []schema.GroupVersion
// SelfLinker can set or get the SelfLink field of all API types.
// TODO: when versioning changes, make this part of each API definition.
// TODO(lavalamp): Combine SelfLinker & ResourceVersioner interfaces, force all uses
// to go through the InterfacesFor method below.
SelfLinker runtime.SelfLinker
// RESTMapper provides the default mapping between REST paths and the objects declared in a Scheme and all known
// versions.
RESTMapper meta.RESTMapper
// InterfacesFor returns the default Codec and ResourceVersioner for a given version
// string, or an error if the version is not known.
// TODO: make this stop being a func pointer and always use the default
// function provided below once every place that populates this field has been changed.
InterfacesFor func(version schema.GroupVersion) (*meta.VersionInterfaces, error)
// InterfacesByVersion stores the per-version interfaces.
InterfacesByVersion map[schema.GroupVersion]*meta.VersionInterfaces
}
// DefaultInterfacesFor returns the default Codec and ResourceVersioner for a given version
// string, or an error if the version is not known.
// TODO: Remove the "Default" prefix.
func (gm *GroupMeta) DefaultInterfacesFor(version schema.GroupVersion) (*meta.VersionInterfaces, error) {
if v, ok := gm.InterfacesByVersion[version]; ok {
return v, nil
}
return nil, fmt.Errorf("unsupported storage version: %s (valid: %v)", version, gm.GroupVersions)
}
// AddVersionInterfaces adds the given version to the group. Only call during
// init, after that GroupMeta objects should be immutable. Not thread safe.
// (If you use this, be sure to set .InterfacesFor = .DefaultInterfacesFor)
// TODO: remove the "Interfaces" suffix and make this also maintain the
// .GroupVersions member.
func (gm *GroupMeta) AddVersionInterfaces(version schema.GroupVersion, interfaces *meta.VersionInterfaces) error {
if e, a := gm.GroupVersion.Group, version.Group; a != e {
return fmt.Errorf("got a version in group %v, but am in group %v", a, e)
}
if gm.InterfacesByVersion == nil {
gm.InterfacesByVersion = make(map[schema.GroupVersion]*meta.VersionInterfaces)
}
gm.InterfacesByVersion[version] = interfaces
// TODO: refactor to make the below error not possible, this function
// should *set* GroupVersions rather than depend on it.
for _, v := range gm.GroupVersions {
if v == version {
return nil
}
}
return fmt.Errorf("added a version interface without the corresponding version %v being in the list %#v", version, gm.GroupVersions)
}

202
vendor/k8s.io/code-generator/LICENSE generated vendored
View File

@ -1,202 +0,0 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
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.

View File

@ -1,65 +0,0 @@
/*
Copyright 2015 The Kubernetes 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 args
import (
"github.com/spf13/pflag"
"k8s.io/code-generator/cmd/client-gen/types"
)
// ClientGenArgs is a wrapper for arguments to client-gen.
type CustomArgs struct {
// A sorted list of group versions to generate. For each of them the package path is found
// in GroupVersionToInputPath.
Groups []types.GroupVersions
// GroupVersionToInputPath is a map between GroupVersion and the path to the respective
// types.go, relative to InputBasePath. We still need GroupVersions in the
// struct because we need an order.
GroupVersionToInputPath map[types.GroupVersion]string
// The base for the path of GroupVersionToInputPath.
InputBasePath string
// Overrides for which types should be included in the client.
IncludedTypesOverrides map[types.GroupVersion][]string
// ClientsetName is the name of the clientset to be generated. It's
// populated from command-line arguments.
ClientsetName string
// ClientsetOutputPath is the path the clientset will be generated at. It's
// populated from command-line arguments.
ClientsetOutputPath string
// ClientsetAPIPath is the default API path for generated clients.
ClientsetAPIPath string
// ClientsetOnly determines if we should generate the clients for groups and
// types along with the clientset. It's populated from command-line
// arguments.
ClientsetOnly bool
// FakeClient determines if client-gen generates the fake clients.
FakeClient bool
}
func (ca *CustomArgs) AddFlags(fs *pflag.FlagSet) {
pflag.Var(NewGVPackagesValue(&ca.GroupVersionToInputPath, &ca.Groups, nil), "input", "group/versions that client-gen will generate clients for. At most one version per group is allowed. Specified in the format \"group1/version1,group2/version2...\".")
pflag.Var(NewGVTypesValue(&ca.IncludedTypesOverrides, []string{}), "included-types-overrides", "list of group/version/type for which client should be generated. By default, client is generated for all types which have genclient in types.go. This overrides that. For each groupVersion in this list, only the types mentioned here will be included. The default check of genclient will be used for other group versions.")
pflag.StringVar(&ca.InputBasePath, "input-base", "k8s.io/kubernetes/pkg/apis", "base path to look for the api group.")
pflag.StringVarP(&ca.ClientsetName, "clientset-name", "n", "internalclientset", "the name of the generated clientset package.")
pflag.StringVarP(&ca.ClientsetAPIPath, "clientset-api-path", "", "", "the value of default API path.")
pflag.StringVar(&ca.ClientsetOutputPath, "clientset-path", "k8s.io/kubernetes/pkg/client/clientset_generated/", "the generated clientset will be output to <clientset-path>/<clientset-name>.")
pflag.BoolVar(&ca.ClientsetOnly, "clientset-only", false, "when set, client-gen only generates the clientset shell, without generating the individual typed clients")
pflag.BoolVar(&ca.FakeClient, "fake-clientset", true, "when set, client-gen will generate the fake clientset that can be used in tests")
}

View File

@ -1,160 +0,0 @@
/*
Copyright 2017 The Kubernetes 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 args
import (
"bytes"
"encoding/csv"
"flag"
"path"
"strings"
"path/filepath"
"sort"
"k8s.io/code-generator/cmd/client-gen/types"
)
type gvPackagesValue struct {
gvToPath *map[types.GroupVersion]string
groups *[]types.GroupVersions
changed bool
}
func NewGVPackagesValue(gvToPath *map[types.GroupVersion]string, groups *[]types.GroupVersions, def []string) *gvPackagesValue {
gvp := new(gvPackagesValue)
gvp.gvToPath = gvToPath
gvp.groups = groups
if def != nil {
if err := gvp.set(def); err != nil {
panic(err)
}
}
return gvp
}
var _ flag.Value = &gvPackagesValue{}
func readAsCSV(val string) ([]string, error) {
if val == "" {
return []string{}, nil
}
stringReader := strings.NewReader(val)
csvReader := csv.NewReader(stringReader)
return csvReader.Read()
}
func writeAsCSV(vals []string) (string, error) {
b := &bytes.Buffer{}
w := csv.NewWriter(b)
err := w.Write(vals)
if err != nil {
return "", err
}
w.Flush()
return strings.TrimSuffix(b.String(), "\n"), nil
}
func (s *gvPackagesValue) set(vs []string) error {
if !s.changed {
*s.gvToPath = map[types.GroupVersion]string{}
*s.groups = []types.GroupVersions{}
}
var seenGroups = make(map[types.Group]*types.GroupVersions)
for _, g := range *s.groups {
seenGroups[g.Group] = &g
}
for _, v := range vs {
pth, gvString := parsePathGroupVersion(v)
gv, err := types.ToGroupVersion(gvString)
if err != nil {
return err
}
if group, ok := seenGroups[gv.Group]; ok {
seenGroups[gv.Group].Versions = append(group.Versions, gv.Version)
} else {
seenGroups[gv.Group] = &types.GroupVersions{
PackageName: gv.Group.NonEmpty(),
Group: gv.Group,
Versions: []types.Version{gv.Version},
}
}
(*s.gvToPath)[gv] = groupVersionPath(pth, gv.Group.String(), gv.Version.String())
}
var groupNames []string
for groupName := range seenGroups {
groupNames = append(groupNames, groupName.String())
}
sort.Strings(groupNames)
*s.groups = []types.GroupVersions{}
for _, groupName := range groupNames {
*s.groups = append(*s.groups, *seenGroups[types.Group(groupName)])
}
return nil
}
func (s *gvPackagesValue) Set(val string) error {
vs, err := readAsCSV(val)
if err != nil {
return err
}
if err := s.set(vs); err != nil {
return err
}
s.changed = true
return nil
}
func (s *gvPackagesValue) Type() string {
return "stringSlice"
}
func (s *gvPackagesValue) String() string {
strs := make([]string, 0, len(*s.gvToPath))
for gv, pth := range *s.gvToPath {
strs = append(strs, path.Join(pth, gv.Group.String(), gv.Version.String()))
}
str, _ := writeAsCSV(strs)
return "[" + str + "]"
}
func parsePathGroupVersion(pgvString string) (gvPath string, gvString string) {
subs := strings.Split(pgvString, "/")
length := len(subs)
switch length {
case 0, 1, 2:
return "", pgvString
default:
return strings.Join(subs[:length-2], "/"), strings.Join(subs[length-2:], "/")
}
}
func groupVersionPath(gvPath string, group string, version string) (path string) {
// special case for the core group
if group == "api" {
path = filepath.Join("core", version)
} else {
path = filepath.Join(gvPath, group, version)
}
return
}

View File

@ -1,110 +0,0 @@
/*
Copyright 2017 The Kubernetes 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 args
import (
"flag"
"fmt"
"strings"
"k8s.io/code-generator/cmd/client-gen/types"
)
type gvTypeValue struct {
gvToTypes *map[types.GroupVersion][]string
changed bool
}
func NewGVTypesValue(gvToTypes *map[types.GroupVersion][]string, def []string) *gvTypeValue {
gvt := new(gvTypeValue)
gvt.gvToTypes = gvToTypes
if def != nil {
if err := gvt.set(def); err != nil {
panic(err)
}
}
return gvt
}
var _ flag.Value = &gvTypeValue{}
func (s *gvTypeValue) set(vs []string) error {
if !s.changed {
*s.gvToTypes = map[types.GroupVersion][]string{}
}
for _, input := range vs {
gvString, typeStr, err := parseGroupVersionType(input)
if err != nil {
return err
}
gv, err := types.ToGroupVersion(gvString)
if err != nil {
return err
}
types, ok := (*s.gvToTypes)[gv]
if !ok {
types = []string{}
}
types = append(types, typeStr)
(*s.gvToTypes)[gv] = types
}
return nil
}
func (s *gvTypeValue) Set(val string) error {
vs, err := readAsCSV(val)
if err != nil {
return err
}
if err := s.set(vs); err != nil {
return err
}
s.changed = true
return nil
}
func (s *gvTypeValue) Type() string {
return "stringSlice"
}
func (s *gvTypeValue) String() string {
strs := make([]string, 0, len(*s.gvToTypes))
for gv, ts := range *s.gvToTypes {
for _, t := range ts {
strs = append(strs, gv.Group.String()+"/"+gv.Version.String()+"/"+t)
}
}
str, _ := writeAsCSV(strs)
return "[" + str + "]"
}
func parseGroupVersionType(gvtString string) (gvString string, typeStr string, err error) {
invalidFormatErr := fmt.Errorf("invalid value: %s, should be of the form group/version/type", gvtString)
subs := strings.Split(gvtString, "/")
length := len(subs)
switch length {
case 2:
// gvtString of the form group/type, e.g. api/Service,extensions/ReplicaSet
return subs[0] + "/", subs[1], nil
case 3:
return strings.Join(subs[:length-1], "/"), subs[length-1], nil
default:
return "", "", invalidFormatErr
}
}

View File

@ -1,438 +0,0 @@
/*
Copyright 2015 The Kubernetes 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 generators has the generators for the client-gen utility.
package generators
import (
"path/filepath"
"strings"
clientgenargs "k8s.io/code-generator/cmd/client-gen/args"
"k8s.io/code-generator/cmd/client-gen/generators/fake"
"k8s.io/code-generator/cmd/client-gen/generators/scheme"
"k8s.io/code-generator/cmd/client-gen/generators/util"
"k8s.io/code-generator/cmd/client-gen/path"
clientgentypes "k8s.io/code-generator/cmd/client-gen/types"
"k8s.io/gengo/args"
"k8s.io/gengo/generator"
"k8s.io/gengo/namer"
"k8s.io/gengo/types"
"github.com/golang/glog"
)
// NameSystems returns the name system used by the generators in this package.
func NameSystems() namer.NameSystems {
pluralExceptions := map[string]string{
"Endpoints": "Endpoints",
}
lowercaseNamer := namer.NewAllLowercasePluralNamer(pluralExceptions)
publicNamer := &ExceptionNamer{
Exceptions: map[string]string{
// these exceptions are used to deconflict the generated code
// you can put your fully qualified package like
// to generate a name that doesn't conflict with your group.
// "k8s.io/apis/events/v1beta1.Event": "EventResource"
},
KeyFunc: func(t *types.Type) string {
return t.Name.Package + "." + t.Name.Name
},
Delegate: namer.NewPublicNamer(0),
}
privateNamer := &ExceptionNamer{
Exceptions: map[string]string{
// these exceptions are used to deconflict the generated code
// you can put your fully qualified package like
// to generate a name that doesn't conflict with your group.
// "k8s.io/apis/events/v1beta1.Event": "eventResource"
},
KeyFunc: func(t *types.Type) string {
return t.Name.Package + "." + t.Name.Name
},
Delegate: namer.NewPrivateNamer(0),
}
publicPluralNamer := &ExceptionNamer{
Exceptions: map[string]string{
// these exceptions are used to deconflict the generated code
// you can put your fully qualified package like
// to generate a name that doesn't conflict with your group.
// "k8s.io/apis/events/v1beta1.Event": "EventResource"
},
KeyFunc: func(t *types.Type) string {
return t.Name.Package + "." + t.Name.Name
},
Delegate: namer.NewPublicPluralNamer(pluralExceptions),
}
privatePluralNamer := &ExceptionNamer{
Exceptions: map[string]string{
// you can put your fully qualified package like
// to generate a name that doesn't conflict with your group.
// "k8s.io/apis/events/v1beta1.Event": "eventResource"
// these exceptions are used to deconflict the generated code
"k8s.io/apis/events/v1beta1.Event": "eventResources",
"k8s.io/kubernetes/pkg/apis/events.Event": "eventResources",
},
KeyFunc: func(t *types.Type) string {
return t.Name.Package + "." + t.Name.Name
},
Delegate: namer.NewPrivatePluralNamer(pluralExceptions),
}
return namer.NameSystems{
"singularKind": namer.NewPublicNamer(0),
"public": publicNamer,
"private": privateNamer,
"raw": namer.NewRawNamer("", nil),
"publicPlural": publicPluralNamer,
"privatePlural": privatePluralNamer,
"allLowercasePlural": lowercaseNamer,
"resource": NewTagOverrideNamer("resourceName", lowercaseNamer),
}
}
// ExceptionNamer allows you specify exceptional cases with exact names. This allows you to have control
// for handling various conflicts, like group and resource names for instance.
type ExceptionNamer struct {
Exceptions map[string]string
KeyFunc func(*types.Type) string
Delegate namer.Namer
}
// Name provides the requested name for a type.
func (n *ExceptionNamer) Name(t *types.Type) string {
key := n.KeyFunc(t)
if exception, ok := n.Exceptions[key]; ok {
return exception
}
return n.Delegate.Name(t)
}
// DefaultNameSystem returns the default name system for ordering the types to be
// processed by the generators in this package.
func DefaultNameSystem() string {
return "public"
}
func packageForGroup(gv clientgentypes.GroupVersion, typeList []*types.Type, clientsetPackage string, groupPackageName string, groupGoName string, apiPath string, srcTreePath string, inputPackage string, boilerplate []byte) generator.Package {
groupVersionClientPackage := strings.ToLower(filepath.Join(clientsetPackage, "typed", groupPackageName, gv.Version.NonEmpty()))
return &generator.DefaultPackage{
PackageName: strings.ToLower(gv.Version.NonEmpty()),
PackagePath: groupVersionClientPackage,
HeaderText: boilerplate,
PackageDocumentation: []byte(
`// This package has the automatically generated typed clients.
`),
// GeneratorFunc returns a list of generators. Each generator makes a
// single file.
GeneratorFunc: func(c *generator.Context) (generators []generator.Generator) {
generators = []generator.Generator{
// Always generate a "doc.go" file.
generator.DefaultGen{OptionalName: "doc"},
}
// Since we want a file per type that we generate a client for, we
// have to provide a function for this.
for _, t := range typeList {
generators = append(generators, &genClientForType{
DefaultGen: generator.DefaultGen{
OptionalName: strings.ToLower(c.Namers["private"].Name(t)),
},
outputPackage: groupVersionClientPackage,
clientsetPackage: clientsetPackage,
group: gv.Group.NonEmpty(),
version: gv.Version.String(),
groupGoName: groupGoName,
typeToMatch: t,
imports: generator.NewImportTracker(),
})
}
generators = append(generators, &genGroup{
DefaultGen: generator.DefaultGen{
OptionalName: groupPackageName + "_client",
},
outputPackage: groupVersionClientPackage,
inputPackage: inputPackage,
clientsetPackage: clientsetPackage,
group: gv.Group.NonEmpty(),
version: gv.Version.String(),
groupGoName: groupGoName,
apiPath: apiPath,
types: typeList,
imports: generator.NewImportTracker(),
})
expansionFileName := "generated_expansion"
generators = append(generators, &genExpansion{
groupPackagePath: filepath.Join(srcTreePath, groupVersionClientPackage),
DefaultGen: generator.DefaultGen{
OptionalName: expansionFileName,
},
types: typeList,
})
return generators
},
FilterFunc: func(c *generator.Context, t *types.Type) bool {
return util.MustParseClientGenTags(append(t.SecondClosestCommentLines, t.CommentLines...)).GenerateClient
},
}
}
func packageForClientset(customArgs *clientgenargs.CustomArgs, clientsetPackage string, groupGoNames map[clientgentypes.GroupVersion]string, boilerplate []byte) generator.Package {
return &generator.DefaultPackage{
PackageName: customArgs.ClientsetName,
PackagePath: clientsetPackage,
HeaderText: boilerplate,
PackageDocumentation: []byte(
`// This package has the automatically generated clientset.
`),
// GeneratorFunc returns a list of generators. Each generator generates a
// single file.
GeneratorFunc: func(c *generator.Context) (generators []generator.Generator) {
generators = []generator.Generator{
// Always generate a "doc.go" file.
generator.DefaultGen{OptionalName: "doc"},
&genClientset{
DefaultGen: generator.DefaultGen{
OptionalName: "clientset",
},
groups: customArgs.Groups,
groupGoNames: groupGoNames,
clientsetPackage: clientsetPackage,
outputPackage: customArgs.ClientsetName,
imports: generator.NewImportTracker(),
},
}
return generators
},
}
}
func packageForScheme(customArgs *clientgenargs.CustomArgs, clientsetPackage string, srcTreePath string, groupGoNames map[clientgentypes.GroupVersion]string, boilerplate []byte) generator.Package {
schemePackage := filepath.Join(clientsetPackage, "scheme")
// create runtime.Registry for internal client because it has to know about group versions
internalClient := false
NextGroup:
for _, group := range customArgs.Groups {
for _, v := range group.Versions {
if v == "" {
internalClient = true
break NextGroup
}
}
}
return &generator.DefaultPackage{
PackageName: "scheme",
PackagePath: schemePackage,
HeaderText: boilerplate,
PackageDocumentation: []byte(
`// This package contains the scheme of the automatically generated clientset.
`),
// GeneratorFunc returns a list of generators. Each generator generates a
// single file.
GeneratorFunc: func(c *generator.Context) (generators []generator.Generator) {
generators = []generator.Generator{
// Always generate a "doc.go" file.
generator.DefaultGen{OptionalName: "doc"},
&scheme.GenScheme{
DefaultGen: generator.DefaultGen{
OptionalName: "register",
},
InputPackages: customArgs.GroupVersionToInputPath,
OutputPackage: schemePackage,
OutputPath: filepath.Join(srcTreePath, schemePackage),
Groups: customArgs.Groups,
GroupGoNames: groupGoNames,
ImportTracker: generator.NewImportTracker(),
CreateRegistry: internalClient,
},
}
return generators
},
}
}
// applyGroupOverrides applies group name overrides to each package, if applicable. If there is a
// comment of the form "// +groupName=somegroup" or "// +groupName=somegroup.foo.bar.io", use the
// first field (somegroup) as the name of the group when generating.
//
// If the first field of the groupName is not unique within the clientset, use "// +groupName=unique
func applyGroupOverrides(universe types.Universe, customArgs *clientgenargs.CustomArgs) {
// Create a map from "old GV" to "new GV" so we know what changes we need to make.
changes := make(map[clientgentypes.GroupVersion]clientgentypes.GroupVersion)
for gv, inputDir := range customArgs.GroupVersionToInputPath {
p := universe.Package(inputDir)
if override := types.ExtractCommentTags("+", p.Comments)["groupName"]; override != nil {
newGV := clientgentypes.GroupVersion{
Group: clientgentypes.Group(override[0]),
Version: gv.Version,
}
changes[gv] = newGV
}
}
// Modify customArgs.Groups based on the groupName overrides.
newGroups := make([]clientgentypes.GroupVersions, 0, len(customArgs.Groups))
for _, gvs := range customArgs.Groups {
gv := clientgentypes.GroupVersion{
Group: gvs.Group,
Version: gvs.Versions[0], // we only need a version, and the first will do
}
if newGV, ok := changes[gv]; ok {
// There's an override, so use it.
newGVS := clientgentypes.GroupVersions{
PackageName: gvs.PackageName,
Group: newGV.Group,
Versions: gvs.Versions,
}
newGroups = append(newGroups, newGVS)
} else {
// No override.
newGroups = append(newGroups, gvs)
}
}
customArgs.Groups = newGroups
// Modify customArgs.GroupVersionToInputPath based on the groupName overrides.
newGVToInputPath := make(map[clientgentypes.GroupVersion]string)
for gv, inputDir := range customArgs.GroupVersionToInputPath {
if newGV, ok := changes[gv]; ok {
// There's an override, so use it.
newGVToInputPath[newGV] = inputDir
} else {
// No override.
newGVToInputPath[gv] = inputDir
}
}
customArgs.GroupVersionToInputPath = newGVToInputPath
}
// Packages makes the client package definition.
func Packages(context *generator.Context, arguments *args.GeneratorArgs) generator.Packages {
boilerplate, err := arguments.LoadGoBoilerplate()
if err != nil {
glog.Fatalf("Failed loading boilerplate: %v", err)
}
customArgs, ok := arguments.CustomArgs.(*clientgenargs.CustomArgs)
if !ok {
glog.Fatalf("cannot convert arguments.CustomArgs to clientgenargs.CustomArgs")
}
includedTypesOverrides := customArgs.IncludedTypesOverrides
applyGroupOverrides(context.Universe, customArgs)
gvToTypes := map[clientgentypes.GroupVersion][]*types.Type{}
groupGoNames := make(map[clientgentypes.GroupVersion]string)
for gv, inputDir := range customArgs.GroupVersionToInputPath {
p := context.Universe.Package(path.Vendorless(inputDir))
// If there's a comment of the form "// +groupGoName=SomeUniqueShortName", use that as
// the Go group identifier in CamelCase. It defaults
groupGoNames[gv] = namer.IC(strings.Split(gv.Group.NonEmpty(), ".")[0])
if override := types.ExtractCommentTags("+", p.Comments)["groupGoName"]; override != nil {
groupGoNames[gv] = namer.IC(override[0])
}
// Package are indexed with the vendor prefix stripped
for n, t := range p.Types {
// filter out types which are not included in user specified overrides.
typesOverride, ok := includedTypesOverrides[gv]
if ok {
found := false
for _, typeStr := range typesOverride {
if typeStr == n {
found = true
break
}
}
if !found {
continue
}
} else {
// User has not specified any override for this group version.
// filter out types which dont have genclient.
if tags := util.MustParseClientGenTags(append(t.SecondClosestCommentLines, t.CommentLines...)); !tags.GenerateClient {
continue
}
}
if _, found := gvToTypes[gv]; !found {
gvToTypes[gv] = []*types.Type{}
}
gvToTypes[gv] = append(gvToTypes[gv], t)
}
}
var packageList []generator.Package
clientsetPackage := filepath.Join(customArgs.ClientsetOutputPath, customArgs.ClientsetName)
packageList = append(packageList, packageForClientset(customArgs, clientsetPackage, groupGoNames, boilerplate))
packageList = append(packageList, packageForScheme(customArgs, clientsetPackage, arguments.OutputBase, groupGoNames, boilerplate))
if customArgs.FakeClient {
packageList = append(packageList, fake.PackageForClientset(customArgs, clientsetPackage, groupGoNames, boilerplate))
}
// If --clientset-only=true, we don't regenerate the individual typed clients.
if customArgs.ClientsetOnly {
return generator.Packages(packageList)
}
orderer := namer.Orderer{Namer: namer.NewPrivateNamer(0)}
for _, group := range customArgs.Groups {
for _, version := range group.Versions {
gv := clientgentypes.GroupVersion{Group: group.Group, Version: version}
types := gvToTypes[gv]
inputPath := customArgs.GroupVersionToInputPath[gv]
packageList = append(packageList, packageForGroup(gv, orderer.OrderTypes(types), clientsetPackage, group.PackageName, groupGoNames[gv], customArgs.ClientsetAPIPath, arguments.OutputBase, inputPath, boilerplate))
if customArgs.FakeClient {
packageList = append(packageList, fake.PackageForGroup(gv, orderer.OrderTypes(types), clientsetPackage, group.PackageName, groupGoNames[gv], inputPath, boilerplate))
}
}
}
return generator.Packages(packageList)
}
// tagOverrideNamer is a namer which pulls names from a given tag, if specified,
// and otherwise falls back to a different namer.
type tagOverrideNamer struct {
tagName string
fallback namer.Namer
}
func (n *tagOverrideNamer) Name(t *types.Type) string {
if nameOverride := extractTag(n.tagName, append(t.SecondClosestCommentLines, t.CommentLines...)); nameOverride != "" {
return nameOverride
}
return n.fallback.Name(t)
}
// NewTagOverrideNamer creates a namer.Namer which uses the contents of the given tag as
// the name, or falls back to another Namer if the tag is not present.
func NewTagOverrideNamer(tagName string, fallback namer.Namer) namer.Namer {
return &tagOverrideNamer{
tagName: tagName,
fallback: fallback,
}
}

View File

@ -1,130 +0,0 @@
/*
Copyright 2015 The Kubernetes 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 fake
import (
"path/filepath"
"strings"
"k8s.io/gengo/generator"
"k8s.io/gengo/types"
clientgenargs "k8s.io/code-generator/cmd/client-gen/args"
scheme "k8s.io/code-generator/cmd/client-gen/generators/scheme"
"k8s.io/code-generator/cmd/client-gen/generators/util"
clientgentypes "k8s.io/code-generator/cmd/client-gen/types"
)
func PackageForGroup(gv clientgentypes.GroupVersion, typeList []*types.Type, clientsetPackage string, groupPackageName string, groupGoName string, inputPackage string, boilerplate []byte) generator.Package {
outputPackage := strings.ToLower(filepath.Join(clientsetPackage, "typed", groupPackageName, gv.Version.NonEmpty(), "fake"))
// TODO: should make this a function, called by here and in client-generator.go
realClientPackage := filepath.Join(clientsetPackage, "typed", groupPackageName, gv.Version.NonEmpty())
return &generator.DefaultPackage{
PackageName: "fake",
PackagePath: outputPackage,
HeaderText: boilerplate,
PackageDocumentation: []byte(
`// Package fake has the automatically generated clients.
`),
// GeneratorFunc returns a list of generators. Each generator makes a
// single file.
GeneratorFunc: func(c *generator.Context) (generators []generator.Generator) {
generators = []generator.Generator{
// Always generate a "doc.go" file.
generator.DefaultGen{OptionalName: "doc"},
}
// Since we want a file per type that we generate a client for, we
// have to provide a function for this.
for _, t := range typeList {
generators = append(generators, &genFakeForType{
DefaultGen: generator.DefaultGen{
OptionalName: "fake_" + strings.ToLower(c.Namers["private"].Name(t)),
},
outputPackage: outputPackage,
inputPackage: inputPackage,
group: gv.Group.NonEmpty(),
version: gv.Version.String(),
groupGoName: groupGoName,
typeToMatch: t,
imports: generator.NewImportTracker(),
})
}
generators = append(generators, &genFakeForGroup{
DefaultGen: generator.DefaultGen{
OptionalName: "fake_" + groupPackageName + "_client",
},
outputPackage: outputPackage,
realClientPackage: realClientPackage,
group: gv.Group.NonEmpty(),
version: gv.Version.String(),
groupGoName: groupGoName,
types: typeList,
imports: generator.NewImportTracker(),
})
return generators
},
FilterFunc: func(c *generator.Context, t *types.Type) bool {
return util.MustParseClientGenTags(append(t.SecondClosestCommentLines, t.CommentLines...)).GenerateClient
},
}
}
func PackageForClientset(customArgs *clientgenargs.CustomArgs, fakeClientsetPackage string, groupGoNames map[clientgentypes.GroupVersion]string, boilerplate []byte) generator.Package {
return &generator.DefaultPackage{
// TODO: we'll generate fake clientset for different release in the future.
// Package name and path are hard coded for now.
PackageName: "fake",
PackagePath: filepath.Join(fakeClientsetPackage, "fake"),
HeaderText: boilerplate,
PackageDocumentation: []byte(
`// This package has the automatically generated fake clientset.
`),
// GeneratorFunc returns a list of generators. Each generator generates a
// single file.
GeneratorFunc: func(c *generator.Context) (generators []generator.Generator) {
generators = []generator.Generator{
// Always generate a "doc.go" file.
generator.DefaultGen{OptionalName: "doc"},
&genClientset{
DefaultGen: generator.DefaultGen{
OptionalName: "clientset_generated",
},
groups: customArgs.Groups,
groupGoNames: groupGoNames,
fakeClientsetPackage: fakeClientsetPackage,
outputPackage: "fake",
imports: generator.NewImportTracker(),
realClientsetPackage: filepath.Join(customArgs.ClientsetOutputPath, customArgs.ClientsetName),
},
&scheme.GenScheme{
DefaultGen: generator.DefaultGen{
OptionalName: "register",
},
InputPackages: customArgs.GroupVersionToInputPath,
OutputPackage: fakeClientsetPackage,
Groups: customArgs.Groups,
GroupGoNames: groupGoNames,
ImportTracker: generator.NewImportTracker(),
PrivateScheme: true,
},
}
return generators
},
}
}

View File

@ -1,164 +0,0 @@
/*
Copyright 2016 The Kubernetes 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 fake
import (
"fmt"
"io"
"path/filepath"
"strings"
clientgentypes "k8s.io/code-generator/cmd/client-gen/types"
"k8s.io/gengo/generator"
"k8s.io/gengo/namer"
"k8s.io/gengo/types"
)
// genClientset generates a package for a clientset.
type genClientset struct {
generator.DefaultGen
groups []clientgentypes.GroupVersions
groupGoNames map[clientgentypes.GroupVersion]string
fakeClientsetPackage string
outputPackage string
imports namer.ImportTracker
clientsetGenerated bool
// the import path of the generated real clientset.
realClientsetPackage string
}
var _ generator.Generator = &genClientset{}
func (g *genClientset) Namers(c *generator.Context) namer.NameSystems {
return namer.NameSystems{
"raw": namer.NewRawNamer(g.outputPackage, g.imports),
}
}
// We only want to call GenerateType() once.
func (g *genClientset) Filter(c *generator.Context, t *types.Type) bool {
ret := !g.clientsetGenerated
g.clientsetGenerated = true
return ret
}
func (g *genClientset) Imports(c *generator.Context) (imports []string) {
imports = append(imports, g.imports.ImportLines()...)
for _, group := range g.groups {
for _, version := range group.Versions {
groupClientPackage := filepath.Join(g.fakeClientsetPackage, "typed", group.PackageName, version.NonEmpty())
fakeGroupClientPackage := filepath.Join(groupClientPackage, "fake")
groupAlias := strings.ToLower(g.groupGoNames[clientgentypes.GroupVersion{group.Group, version}])
imports = append(imports, strings.ToLower(fmt.Sprintf("%s%s \"%s\"", groupAlias, version.NonEmpty(), groupClientPackage)))
imports = append(imports, strings.ToLower(fmt.Sprintf("fake%s%s \"%s\"", groupAlias, version.NonEmpty(), fakeGroupClientPackage)))
}
}
// the package that has the clientset Interface
imports = append(imports, fmt.Sprintf("clientset \"%s\"", g.realClientsetPackage))
// imports for the code in commonTemplate
imports = append(imports,
"k8s.io/client-go/testing",
"k8s.io/client-go/discovery",
"fakediscovery \"k8s.io/client-go/discovery/fake\"",
"k8s.io/apimachinery/pkg/runtime",
"k8s.io/apimachinery/pkg/watch",
)
return
}
func (g *genClientset) GenerateType(c *generator.Context, t *types.Type, w io.Writer) error {
// TODO: We actually don't need any type information to generate the clientset,
// perhaps we can adapt the go2ild framework to this kind of usage.
sw := generator.NewSnippetWriter(w, c, "$", "$")
allGroups := clientgentypes.ToGroupVersionPackages(g.groups, g.groupGoNames)
sw.Do(common, nil)
sw.Do(checkImpl, nil)
for _, group := range allGroups {
m := map[string]interface{}{
"group": group.Group,
"version": group.Version,
"PackageAlias": group.PackageAlias,
"GroupGoName": group.GroupGoName,
"Version": namer.IC(group.Version.String()),
}
sw.Do(clientsetInterfaceImplTemplate, m)
// don't generated the default method if generating internalversion clientset
if group.IsDefaultVersion && group.Version != "" {
sw.Do(clientsetInterfaceDefaultVersionImpl, m)
}
}
return sw.Error()
}
// This part of code is version-independent, unchanging.
var common = `
// NewSimpleClientset returns a clientset that will respond with the provided objects.
// It's backed by a very simple object tracker that processes creates, updates and deletions as-is,
// without applying any validations and/or defaults. It shouldn't be considered a replacement
// for a real clientset and is mostly useful in simple unit tests.
func NewSimpleClientset(objects ...runtime.Object) *Clientset {
o := testing.NewObjectTracker(scheme, codecs.UniversalDecoder())
for _, obj := range objects {
if err := o.Add(obj); err != nil {
panic(err)
}
}
fakePtr := testing.Fake{}
fakePtr.AddReactor("*", "*", testing.ObjectReaction(o))
fakePtr.AddWatchReactor("*", testing.DefaultWatchReactor(watch.NewFake(), nil))
return &Clientset{fakePtr, &fakediscovery.FakeDiscovery{Fake: &fakePtr}}
}
// Clientset implements clientset.Interface. Meant to be embedded into a
// struct to get a default implementation. This makes faking out just the method
// you want to test easier.
type Clientset struct {
testing.Fake
discovery *fakediscovery.FakeDiscovery
}
func (c *Clientset) Discovery() discovery.DiscoveryInterface {
return c.discovery
}
`
var checkImpl = `
var _ clientset.Interface = &Clientset{}
`
var clientsetInterfaceImplTemplate = `
// $.GroupGoName$$.Version$ retrieves the $.GroupGoName$$.Version$Client
func (c *Clientset) $.GroupGoName$$.Version$() $.PackageAlias$.$.GroupGoName$$.Version$Interface {
return &fake$.PackageAlias$.Fake$.GroupGoName$$.Version${Fake: &c.Fake}
}
`
var clientsetInterfaceDefaultVersionImpl = `
// $.GroupGoName$ retrieves the $.GroupGoName$$.Version$Client
func (c *Clientset) $.GroupGoName$() $.PackageAlias$.$.GroupGoName$$.Version$Interface {
return &fake$.PackageAlias$.Fake$.GroupGoName$$.Version${Fake: &c.Fake}
}
`

View File

@ -1,130 +0,0 @@
/*
Copyright 2015 The Kubernetes 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 fake
import (
"fmt"
"io"
"path/filepath"
"strings"
"k8s.io/gengo/generator"
"k8s.io/gengo/namer"
"k8s.io/gengo/types"
"k8s.io/code-generator/cmd/client-gen/generators/util"
)
// genFakeForGroup produces a file for a group client, e.g. ExtensionsClient for the extension group.
type genFakeForGroup struct {
generator.DefaultGen
outputPackage string
realClientPackage string
group string
version string
groupGoName string
// types in this group
types []*types.Type
imports namer.ImportTracker
// If the genGroup has been called. This generator should only execute once.
called bool
}
var _ generator.Generator = &genFakeForGroup{}
// We only want to call GenerateType() once per group.
func (g *genFakeForGroup) Filter(c *generator.Context, t *types.Type) bool {
if !g.called {
g.called = true
return true
}
return false
}
func (g *genFakeForGroup) Namers(c *generator.Context) namer.NameSystems {
return namer.NameSystems{
"raw": namer.NewRawNamer(g.outputPackage, g.imports),
}
}
func (g *genFakeForGroup) Imports(c *generator.Context) (imports []string) {
imports = g.imports.ImportLines()
if len(g.types) != 0 {
imports = append(imports, strings.ToLower(fmt.Sprintf("%s \"%s\"", filepath.Base(g.realClientPackage), g.realClientPackage)))
}
return imports
}
func (g *genFakeForGroup) GenerateType(c *generator.Context, t *types.Type, w io.Writer) error {
sw := generator.NewSnippetWriter(w, c, "$", "$")
m := map[string]interface{}{
"GroupGoName": g.groupGoName,
"Version": namer.IC(g.version),
"Fake": c.Universe.Type(types.Name{Package: "k8s.io/client-go/testing", Name: "Fake"}),
"RESTClientInterface": c.Universe.Type(types.Name{Package: "k8s.io/client-go/rest", Name: "Interface"}),
"RESTClient": c.Universe.Type(types.Name{Package: "k8s.io/client-go/rest", Name: "RESTClient"}),
}
sw.Do(groupClientTemplate, m)
for _, t := range g.types {
tags, err := util.ParseClientGenTags(append(t.SecondClosestCommentLines, t.CommentLines...))
if err != nil {
return err
}
wrapper := map[string]interface{}{
"type": t,
"GroupGoName": g.groupGoName,
"Version": namer.IC(g.version),
"realClientPackage": strings.ToLower(filepath.Base(g.realClientPackage)),
}
if tags.NonNamespaced {
sw.Do(getterImplNonNamespaced, wrapper)
continue
}
sw.Do(getterImplNamespaced, wrapper)
}
sw.Do(getRESTClient, m)
return sw.Error()
}
var groupClientTemplate = `
type Fake$.GroupGoName$$.Version$ struct {
*$.Fake|raw$
}
`
var getterImplNamespaced = `
func (c *Fake$.GroupGoName$$.Version$) $.type|publicPlural$(namespace string) $.realClientPackage$.$.type|public$Interface {
return &Fake$.type|publicPlural${c, namespace}
}
`
var getterImplNonNamespaced = `
func (c *Fake$.GroupGoName$$.Version$) $.type|publicPlural$() $.realClientPackage$.$.type|public$Interface {
return &Fake$.type|publicPlural${c}
}
`
var getRESTClient = `
// RESTClient returns a RESTClient that is used to communicate
// with API server by this client implementation.
func (c *Fake$.GroupGoName$$.Version$) RESTClient() $.RESTClientInterface|raw$ {
var ret *$.RESTClient|raw$
return ret
}
`

View File

@ -1,494 +0,0 @@
/*
Copyright 2015 The Kubernetes 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 fake
import (
"io"
"path/filepath"
"strings"
"k8s.io/gengo/generator"
"k8s.io/gengo/namer"
"k8s.io/gengo/types"
"k8s.io/code-generator/cmd/client-gen/generators/util"
"k8s.io/code-generator/cmd/client-gen/path"
)
// genFakeForType produces a file for each top-level type.
type genFakeForType struct {
generator.DefaultGen
outputPackage string
group string
version string
groupGoName string
inputPackage string
typeToMatch *types.Type
imports namer.ImportTracker
}
var _ generator.Generator = &genFakeForType{}
// Filter ignores all but one type because we're making a single file per type.
func (g *genFakeForType) Filter(c *generator.Context, t *types.Type) bool { return t == g.typeToMatch }
func (g *genFakeForType) Namers(c *generator.Context) namer.NameSystems {
return namer.NameSystems{
"raw": namer.NewRawNamer(g.outputPackage, g.imports),
}
}
func (g *genFakeForType) Imports(c *generator.Context) (imports []string) {
return g.imports.ImportLines()
}
// Ideally, we'd like genStatus to return true if there is a subresource path
// registered for "status" in the API server, but we do not have that
// information, so genStatus returns true if the type has a status field.
func genStatus(t *types.Type) bool {
// Default to true if we have a Status member
hasStatus := false
for _, m := range t.Members {
if m.Name == "Status" {
hasStatus = true
break
}
}
tags := util.MustParseClientGenTags(append(t.SecondClosestCommentLines, t.CommentLines...))
return hasStatus && !tags.NoStatus
}
// hasObjectMeta returns true if the type has a ObjectMeta field.
func hasObjectMeta(t *types.Type) bool {
for _, m := range t.Members {
if m.Embedded == true && m.Name == "ObjectMeta" {
return true
}
}
return false
}
// GenerateType makes the body of a file implementing the individual typed client for type t.
func (g *genFakeForType) GenerateType(c *generator.Context, t *types.Type, w io.Writer) error {
sw := generator.NewSnippetWriter(w, c, "$", "$")
pkg := filepath.Base(t.Name.Package)
tags, err := util.ParseClientGenTags(append(t.SecondClosestCommentLines, t.CommentLines...))
if err != nil {
return err
}
canonicalGroup := g.group
if canonicalGroup == "core" {
canonicalGroup = ""
}
groupName := g.group
if g.group == "core" {
groupName = ""
}
// allow user to define a group name that's different from the one parsed from the directory.
p := c.Universe.Package(path.Vendorless(g.inputPackage))
if override := types.ExtractCommentTags("+", p.Comments)["groupName"]; override != nil {
groupName = override[0]
}
const pkgClientGoTesting = "k8s.io/client-go/testing"
m := map[string]interface{}{
"type": t,
"inputType": t,
"resultType": t,
"subresourcePath": "",
"package": pkg,
"Package": namer.IC(pkg),
"namespaced": !tags.NonNamespaced,
"Group": namer.IC(g.group),
"GroupGoName": g.groupGoName,
"Version": namer.IC(g.version),
"group": canonicalGroup,
"groupName": groupName,
"version": g.version,
"DeleteOptions": c.Universe.Type(types.Name{Package: "k8s.io/apimachinery/pkg/apis/meta/v1", Name: "DeleteOptions"}),
"ListOptions": c.Universe.Type(types.Name{Package: "k8s.io/apimachinery/pkg/apis/meta/v1", Name: "ListOptions"}),
"GetOptions": c.Universe.Type(types.Name{Package: "k8s.io/apimachinery/pkg/apis/meta/v1", Name: "GetOptions"}),
"Everything": c.Universe.Function(types.Name{Package: "k8s.io/apimachinery/pkg/labels", Name: "Everything"}),
"GroupVersionResource": c.Universe.Type(types.Name{Package: "k8s.io/apimachinery/pkg/runtime/schema", Name: "GroupVersionResource"}),
"GroupVersionKind": c.Universe.Type(types.Name{Package: "k8s.io/apimachinery/pkg/runtime/schema", Name: "GroupVersionKind"}),
"PatchType": c.Universe.Type(types.Name{Package: "k8s.io/apimachinery/pkg/types", Name: "PatchType"}),
"watchInterface": c.Universe.Type(types.Name{Package: "k8s.io/apimachinery/pkg/watch", Name: "Interface"}),
"NewRootListAction": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "NewRootListAction"}),
"NewListAction": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "NewListAction"}),
"NewRootGetAction": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "NewRootGetAction"}),
"NewGetAction": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "NewGetAction"}),
"NewRootDeleteAction": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "NewRootDeleteAction"}),
"NewDeleteAction": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "NewDeleteAction"}),
"NewRootDeleteCollectionAction": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "NewRootDeleteCollectionAction"}),
"NewDeleteCollectionAction": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "NewDeleteCollectionAction"}),
"NewRootUpdateAction": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "NewRootUpdateAction"}),
"NewUpdateAction": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "NewUpdateAction"}),
"NewRootCreateAction": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "NewRootCreateAction"}),
"NewCreateAction": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "NewCreateAction"}),
"NewRootWatchAction": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "NewRootWatchAction"}),
"NewWatchAction": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "NewWatchAction"}),
"NewCreateSubresourceAction": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "NewCreateSubresourceAction"}),
"NewUpdateSubresourceAction": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "NewUpdateSubresourceAction"}),
"NewGetSubresourceAction": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "NewGetSubresourceAction"}),
"NewListSubresourceAction": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "NewListSubresourceAction"}),
"NewRootUpdateSubresourceAction": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "NewRootUpdateSubresourceAction"}),
"NewRootPatchAction": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "NewRootPatchAction"}),
"NewPatchAction": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "NewPatchAction"}),
"NewRootPatchSubresourceAction": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "NewRootPatchSubresourceAction"}),
"NewPatchSubresourceAction": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "NewPatchSubresourceAction"}),
"ExtractFromListOptions": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "ExtractFromListOptions"}),
}
if tags.NonNamespaced {
sw.Do(structNonNamespaced, m)
} else {
sw.Do(structNamespaced, m)
}
if tags.NoVerbs {
return sw.Error()
}
sw.Do(resource, m)
sw.Do(kind, m)
if tags.HasVerb("get") {
sw.Do(getTemplate, m)
}
if tags.HasVerb("list") {
if hasObjectMeta(t) {
sw.Do(listUsingOptionsTemplate, m)
} else {
sw.Do(listTemplate, m)
}
}
if tags.HasVerb("watch") {
sw.Do(watchTemplate, m)
}
if tags.HasVerb("create") {
sw.Do(createTemplate, m)
}
if tags.HasVerb("update") {
sw.Do(updateTemplate, m)
}
if tags.HasVerb("updateStatus") && genStatus(t) {
sw.Do(updateStatusTemplate, m)
}
if tags.HasVerb("delete") {
sw.Do(deleteTemplate, m)
}
if tags.HasVerb("deleteCollection") {
sw.Do(deleteCollectionTemplate, m)
}
if tags.HasVerb("patch") {
sw.Do(patchTemplate, m)
}
// generate extended client methods
for _, e := range tags.Extensions {
inputType := *t
resultType := *t
if len(e.InputTypeOverride) > 0 {
if name, pkg := e.Input(); len(pkg) > 0 {
newType := c.Universe.Type(types.Name{Package: pkg, Name: name})
inputType = *newType
} else {
inputType.Name.Name = e.InputTypeOverride
}
}
if len(e.ResultTypeOverride) > 0 {
if name, pkg := e.Result(); len(pkg) > 0 {
newType := c.Universe.Type(types.Name{Package: pkg, Name: name})
resultType = *newType
} else {
resultType.Name.Name = e.ResultTypeOverride
}
}
m["inputType"] = &inputType
m["resultType"] = &resultType
m["subresourcePath"] = e.SubResourcePath
if e.HasVerb("get") {
if e.IsSubresource() {
sw.Do(adjustTemplate(e.VerbName, e.VerbType, getSubresourceTemplate), m)
} else {
sw.Do(adjustTemplate(e.VerbName, e.VerbType, getTemplate), m)
}
}
if e.HasVerb("list") {
if e.IsSubresource() {
sw.Do(adjustTemplate(e.VerbName, e.VerbType, listSubresourceTemplate), m)
} else {
sw.Do(adjustTemplate(e.VerbName, e.VerbType, listTemplate), m)
}
}
// TODO: Figure out schemantic for watching a sub-resource.
if e.HasVerb("watch") {
sw.Do(adjustTemplate(e.VerbName, e.VerbType, watchTemplate), m)
}
if e.HasVerb("create") {
if e.IsSubresource() {
sw.Do(adjustTemplate(e.VerbName, e.VerbType, createSubresourceTemplate), m)
} else {
sw.Do(adjustTemplate(e.VerbName, e.VerbType, createTemplate), m)
}
}
if e.HasVerb("update") {
if e.IsSubresource() {
sw.Do(adjustTemplate(e.VerbName, e.VerbType, updateSubresourceTemplate), m)
} else {
sw.Do(adjustTemplate(e.VerbName, e.VerbType, updateTemplate), m)
}
}
// TODO: Figure out schemantic for deleting a sub-resource (what arguments
// are passed, does it need two names? etc.
if e.HasVerb("delete") {
sw.Do(adjustTemplate(e.VerbName, e.VerbType, deleteTemplate), m)
}
if e.HasVerb("patch") {
sw.Do(adjustTemplate(e.VerbName, e.VerbType, patchTemplate), m)
}
}
return sw.Error()
}
// adjustTemplate adjust the origin verb template using the expansion name.
// TODO: Make the verbs in templates parametrized so the strings.Replace() is
// not needed.
func adjustTemplate(name, verbType, template string) string {
return strings.Replace(template, " "+strings.Title(verbType), " "+name, -1)
}
// template for the struct that implements the type's interface
var structNamespaced = `
// Fake$.type|publicPlural$ implements $.type|public$Interface
type Fake$.type|publicPlural$ struct {
Fake *Fake$.GroupGoName$$.Version$
ns string
}
`
// template for the struct that implements the type's interface
var structNonNamespaced = `
// Fake$.type|publicPlural$ implements $.type|public$Interface
type Fake$.type|publicPlural$ struct {
Fake *Fake$.GroupGoName$$.Version$
}
`
var resource = `
var $.type|allLowercasePlural$Resource = $.GroupVersionResource|raw${Group: "$.groupName$", Version: "$.version$", Resource: "$.type|resource$"}
`
var kind = `
var $.type|allLowercasePlural$Kind = $.GroupVersionKind|raw${Group: "$.groupName$", Version: "$.version$", Kind: "$.type|singularKind$"}
`
var listTemplate = `
// List takes label and field selectors, and returns the list of $.type|publicPlural$ that match those selectors.
func (c *Fake$.type|publicPlural$) List(opts $.ListOptions|raw$) (result *$.type|raw$List, err error) {
obj, err := c.Fake.
$if .namespaced$Invokes($.NewListAction|raw$($.type|allLowercasePlural$Resource, $.type|allLowercasePlural$Kind, c.ns, opts), &$.type|raw$List{})
$else$Invokes($.NewRootListAction|raw$($.type|allLowercasePlural$Resource, $.type|allLowercasePlural$Kind, opts), &$.type|raw$List{})$end$
if obj == nil {
return nil, err
}
return obj.(*$.type|raw$List), err
}
`
var listSubresourceTemplate = `
// List takes label and field selectors, and returns the list of $.resultType|publicPlural$ that match those selectors.
func (c *Fake$.type|publicPlural$) List($.type|private$Name string, opts $.ListOptions|raw$) (result *$.resultType|raw$List, err error) {
obj, err := c.Fake.
$if .namespaced$Invokes($.NewListSubresourceAction|raw$($.type|allLowercasePlural$Resource, $.type|private$Name, "$.subresourcePath$", $.type|allLowercasePlural$Kind, c.ns, opts), &$.resultType|raw$List{})
$else$Invokes($.NewRootListAction|raw$($.type|allLowercasePlural$Resource, $.type|allLowercasePlural$Kind, opts), &$.resultType|raw$List{})$end$
if obj == nil {
return nil, err
}
return obj.(*$.resultType|raw$List), err
}
`
var listUsingOptionsTemplate = `
// List takes label and field selectors, and returns the list of $.type|publicPlural$ that match those selectors.
func (c *Fake$.type|publicPlural$) List(opts $.ListOptions|raw$) (result *$.type|raw$List, err error) {
obj, err := c.Fake.
$if .namespaced$Invokes($.NewListAction|raw$($.type|allLowercasePlural$Resource, $.type|allLowercasePlural$Kind, c.ns, opts), &$.type|raw$List{})
$else$Invokes($.NewRootListAction|raw$($.type|allLowercasePlural$Resource, $.type|allLowercasePlural$Kind, opts), &$.type|raw$List{})$end$
if obj == nil {
return nil, err
}
label, _, _ := $.ExtractFromListOptions|raw$(opts)
if label == nil {
label = $.Everything|raw$()
}
list := &$.type|raw$List{}
for _, item := range obj.(*$.type|raw$List).Items {
if label.Matches(labels.Set(item.Labels)) {
list.Items = append(list.Items, item)
}
}
return list, err
}
`
var getTemplate = `
// Get takes name of the $.type|private$, and returns the corresponding $.resultType|private$ object, and an error if there is any.
func (c *Fake$.type|publicPlural$) Get(name string, options $.GetOptions|raw$) (result *$.resultType|raw$, err error) {
obj, err := c.Fake.
$if .namespaced$Invokes($.NewGetAction|raw$($.type|allLowercasePlural$Resource, c.ns, name), &$.resultType|raw${})
$else$Invokes($.NewRootGetAction|raw$($.type|allLowercasePlural$Resource, name), &$.resultType|raw${})$end$
if obj == nil {
return nil, err
}
return obj.(*$.resultType|raw$), err
}
`
var getSubresourceTemplate = `
// Get takes name of the $.type|private$, and returns the corresponding $.resultType|private$ object, and an error if there is any.
func (c *Fake$.type|publicPlural$) Get($.type|private$Name string, options $.GetOptions|raw$) (result *$.resultType|raw$, err error) {
obj, err := c.Fake.
$if .namespaced$Invokes($.NewGetSubresourceAction|raw$($.type|allLowercasePlural$Resource, c.ns, "$.subresourcePath$", $.type|private$Name), &$.resultType|raw${})
$else$Invokes($.NewRootGetAction|raw$($.type|allLowercasePlural$Resource, $.type|private$Name), &$.resultType|raw${})$end$
if obj == nil {
return nil, err
}
return obj.(*$.resultType|raw$), err
}
`
var deleteTemplate = `
// Delete takes name of the $.type|private$ and deletes it. Returns an error if one occurs.
func (c *Fake$.type|publicPlural$) Delete(name string, options *$.DeleteOptions|raw$) error {
_, err := c.Fake.
$if .namespaced$Invokes($.NewDeleteAction|raw$($.type|allLowercasePlural$Resource, c.ns, name), &$.type|raw${})
$else$Invokes($.NewRootDeleteAction|raw$($.type|allLowercasePlural$Resource, name), &$.type|raw${})$end$
return err
}
`
var deleteCollectionTemplate = `
// DeleteCollection deletes a collection of objects.
func (c *Fake$.type|publicPlural$) DeleteCollection(options *$.DeleteOptions|raw$, listOptions $.ListOptions|raw$) error {
$if .namespaced$action := $.NewDeleteCollectionAction|raw$($.type|allLowercasePlural$Resource, c.ns, listOptions)
$else$action := $.NewRootDeleteCollectionAction|raw$($.type|allLowercasePlural$Resource, listOptions)
$end$
_, err := c.Fake.Invokes(action, &$.type|raw$List{})
return err
}
`
var createTemplate = `
// Create takes the representation of a $.inputType|private$ and creates it. Returns the server's representation of the $.resultType|private$, and an error, if there is any.
func (c *Fake$.type|publicPlural$) Create($.inputType|private$ *$.inputType|raw$) (result *$.resultType|raw$, err error) {
obj, err := c.Fake.
$if .namespaced$Invokes($.NewCreateAction|raw$($.inputType|allLowercasePlural$Resource, c.ns, $.inputType|private$), &$.resultType|raw${})
$else$Invokes($.NewRootCreateAction|raw$($.inputType|allLowercasePlural$Resource, $.inputType|private$), &$.resultType|raw${})$end$
if obj == nil {
return nil, err
}
return obj.(*$.resultType|raw$), err
}
`
var createSubresourceTemplate = `
// Create takes the representation of a $.inputType|private$ and creates it. Returns the server's representation of the $.resultType|private$, and an error, if there is any.
func (c *Fake$.type|publicPlural$) Create($.type|private$Name string, $.inputType|private$ *$.inputType|raw$) (result *$.resultType|raw$, err error) {
obj, err := c.Fake.
$if .namespaced$Invokes($.NewCreateSubresourceAction|raw$($.type|allLowercasePlural$Resource, $.type|private$Name, "$.subresourcePath$", c.ns, $.inputType|private$), &$.resultType|raw${})
$else$Invokes($.NewRootCreateAction|raw$($.inputType|allLowercasePlural$Resource, $.inputType|private$), &$.resultType|raw${})$end$
if obj == nil {
return nil, err
}
return obj.(*$.resultType|raw$), err
}
`
var updateTemplate = `
// Update takes the representation of a $.inputType|private$ and updates it. Returns the server's representation of the $.resultType|private$, and an error, if there is any.
func (c *Fake$.type|publicPlural$) Update($.inputType|private$ *$.inputType|raw$) (result *$.resultType|raw$, err error) {
obj, err := c.Fake.
$if .namespaced$Invokes($.NewUpdateAction|raw$($.inputType|allLowercasePlural$Resource, c.ns, $.inputType|private$), &$.resultType|raw${})
$else$Invokes($.NewRootUpdateAction|raw$($.inputType|allLowercasePlural$Resource, $.inputType|private$), &$.resultType|raw${})$end$
if obj == nil {
return nil, err
}
return obj.(*$.resultType|raw$), err
}
`
var updateSubresourceTemplate = `
// Update takes the representation of a $.inputType|private$ and updates it. Returns the server's representation of the $.resultType|private$, and an error, if there is any.
func (c *Fake$.type|publicPlural$) Update($.type|private$Name string, $.inputType|private$ *$.inputType|raw$) (result *$.resultType|raw$, err error) {
obj, err := c.Fake.
$if .namespaced$Invokes($.NewUpdateSubresourceAction|raw$($.type|allLowercasePlural$Resource, "$.subresourcePath$", c.ns, $.inputType|private$), &$.inputType|raw${})
$else$Invokes($.NewRootUpdateAction|raw$($.type|allLowercasePlural$Resource, $.type|private$), &$.type|raw${})$end$
if obj == nil {
return nil, err
}
return obj.(*$.resultType|raw$), err
}
`
var updateStatusTemplate = `
// UpdateStatus was generated because the type contains a Status member.
// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus().
func (c *Fake$.type|publicPlural$) UpdateStatus($.type|private$ *$.type|raw$) (*$.type|raw$, error) {
obj, err := c.Fake.
$if .namespaced$Invokes($.NewUpdateSubresourceAction|raw$($.type|allLowercasePlural$Resource, "status", c.ns, $.type|private$), &$.type|raw${})
$else$Invokes($.NewRootUpdateSubresourceAction|raw$($.type|allLowercasePlural$Resource, "status", $.type|private$), &$.type|raw${})$end$
if obj == nil {
return nil, err
}
return obj.(*$.type|raw$), err
}
`
var watchTemplate = `
// Watch returns a $.watchInterface|raw$ that watches the requested $.type|privatePlural$.
func (c *Fake$.type|publicPlural$) Watch(opts $.ListOptions|raw$) ($.watchInterface|raw$, error) {
return c.Fake.
$if .namespaced$InvokesWatch($.NewWatchAction|raw$($.type|allLowercasePlural$Resource, c.ns, opts))
$else$InvokesWatch($.NewRootWatchAction|raw$($.type|allLowercasePlural$Resource, opts))$end$
}
`
var patchTemplate = `
// Patch applies the patch and returns the patched $.resultType|private$.
func (c *Fake$.type|publicPlural$) Patch(name string, pt $.PatchType|raw$, data []byte, subresources ...string) (result *$.resultType|raw$, err error) {
obj, err := c.Fake.
$if .namespaced$Invokes($.NewPatchSubresourceAction|raw$($.type|allLowercasePlural$Resource, c.ns, name, data, subresources... ), &$.resultType|raw${})
$else$Invokes($.NewRootPatchSubresourceAction|raw$($.type|allLowercasePlural$Resource, name, data, subresources...), &$.resultType|raw${})$end$
if obj == nil {
return nil, err
}
return obj.(*$.resultType|raw$), err
}
`

View File

@ -1,194 +0,0 @@
/*
Copyright 2016 The Kubernetes 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 generators
import (
"fmt"
"io"
"path/filepath"
"strings"
clientgentypes "k8s.io/code-generator/cmd/client-gen/types"
"k8s.io/gengo/generator"
"k8s.io/gengo/namer"
"k8s.io/gengo/types"
)
// genClientset generates a package for a clientset.
type genClientset struct {
generator.DefaultGen
groups []clientgentypes.GroupVersions
groupGoNames map[clientgentypes.GroupVersion]string
clientsetPackage string
outputPackage string
imports namer.ImportTracker
clientsetGenerated bool
}
var _ generator.Generator = &genClientset{}
func (g *genClientset) Namers(c *generator.Context) namer.NameSystems {
return namer.NameSystems{
"raw": namer.NewRawNamer(g.outputPackage, g.imports),
}
}
// We only want to call GenerateType() once.
func (g *genClientset) Filter(c *generator.Context, t *types.Type) bool {
ret := !g.clientsetGenerated
g.clientsetGenerated = true
return ret
}
func (g *genClientset) Imports(c *generator.Context) (imports []string) {
imports = append(imports, g.imports.ImportLines()...)
for _, group := range g.groups {
for _, version := range group.Versions {
typedClientPath := filepath.Join(g.clientsetPackage, "typed", group.PackageName, version.NonEmpty())
groupAlias := strings.ToLower(g.groupGoNames[clientgentypes.GroupVersion{group.Group, version}])
imports = append(imports, strings.ToLower(fmt.Sprintf("%s%s \"%s\"", groupAlias, version.NonEmpty(), typedClientPath)))
}
}
return
}
func (g *genClientset) GenerateType(c *generator.Context, t *types.Type, w io.Writer) error {
// TODO: We actually don't need any type information to generate the clientset,
// perhaps we can adapt the go2ild framework to this kind of usage.
sw := generator.NewSnippetWriter(w, c, "$", "$")
allGroups := clientgentypes.ToGroupVersionPackages(g.groups, g.groupGoNames)
m := map[string]interface{}{
"allGroups": allGroups,
"Config": c.Universe.Type(types.Name{Package: "k8s.io/client-go/rest", Name: "Config"}),
"DefaultKubernetesUserAgent": c.Universe.Function(types.Name{Package: "k8s.io/client-go/rest", Name: "DefaultKubernetesUserAgent"}),
"RESTClientInterface": c.Universe.Type(types.Name{Package: "k8s.io/client-go/rest", Name: "Interface"}),
"DiscoveryInterface": c.Universe.Type(types.Name{Package: "k8s.io/client-go/discovery", Name: "DiscoveryInterface"}),
"DiscoveryClient": c.Universe.Type(types.Name{Package: "k8s.io/client-go/discovery", Name: "DiscoveryClient"}),
"NewDiscoveryClientForConfig": c.Universe.Function(types.Name{Package: "k8s.io/client-go/discovery", Name: "NewDiscoveryClientForConfig"}),
"NewDiscoveryClientForConfigOrDie": c.Universe.Function(types.Name{Package: "k8s.io/client-go/discovery", Name: "NewDiscoveryClientForConfigOrDie"}),
"NewDiscoveryClient": c.Universe.Function(types.Name{Package: "k8s.io/client-go/discovery", Name: "NewDiscoveryClient"}),
"flowcontrolNewTokenBucketRateLimiter": c.Universe.Function(types.Name{Package: "k8s.io/client-go/util/flowcontrol", Name: "NewTokenBucketRateLimiter"}),
"glogErrorf": c.Universe.Function(types.Name{Package: "github.com/golang/glog", Name: "Errorf"}),
}
sw.Do(clientsetInterface, m)
sw.Do(clientsetTemplate, m)
for _, g := range allGroups {
sw.Do(clientsetInterfaceImplTemplate, g)
// don't generated the default method if generating internalversion clientset
if g.IsDefaultVersion && g.Version != "" {
sw.Do(clientsetInterfaceDefaultVersionImpl, g)
}
}
sw.Do(getDiscoveryTemplate, m)
sw.Do(newClientsetForConfigTemplate, m)
sw.Do(newClientsetForConfigOrDieTemplate, m)
sw.Do(newClientsetForRESTClientTemplate, m)
return sw.Error()
}
var clientsetInterface = `
type Interface interface {
Discovery() $.DiscoveryInterface|raw$
$range .allGroups$$.GroupGoName$$.Version$() $.PackageAlias$.$.GroupGoName$$.Version$Interface
$if .IsDefaultVersion$// Deprecated: please explicitly pick a version if possible.
$.GroupGoName$() $.PackageAlias$.$.GroupGoName$$.Version$Interface
$end$$end$
}
`
var clientsetTemplate = `
// Clientset contains the clients for groups. Each group has exactly one
// version included in a Clientset.
type Clientset struct {
*$.DiscoveryClient|raw$
$range .allGroups$$.LowerCaseGroupGoName$$.Version$ *$.PackageAlias$.$.GroupGoName$$.Version$Client
$end$
}
`
var clientsetInterfaceImplTemplate = `
// $.GroupGoName$$.Version$ retrieves the $.GroupGoName$$.Version$Client
func (c *Clientset) $.GroupGoName$$.Version$() $.PackageAlias$.$.GroupGoName$$.Version$Interface {
return c.$.LowerCaseGroupGoName$$.Version$
}
`
var clientsetInterfaceDefaultVersionImpl = `
// Deprecated: $.GroupGoName$ retrieves the default version of $.GroupGoName$Client.
// Please explicitly pick a version.
func (c *Clientset) $.GroupGoName$() $.PackageAlias$.$.GroupGoName$$.Version$Interface {
return c.$.LowerCaseGroupGoName$$.Version$
}
`
var getDiscoveryTemplate = `
// Discovery retrieves the DiscoveryClient
func (c *Clientset) Discovery() $.DiscoveryInterface|raw$ {
if c == nil {
return nil
}
return c.DiscoveryClient
}
`
var newClientsetForConfigTemplate = `
// NewForConfig creates a new Clientset for the given config.
func NewForConfig(c *$.Config|raw$) (*Clientset, error) {
configShallowCopy := *c
if configShallowCopy.RateLimiter == nil && configShallowCopy.QPS > 0 {
configShallowCopy.RateLimiter = $.flowcontrolNewTokenBucketRateLimiter|raw$(configShallowCopy.QPS, configShallowCopy.Burst)
}
var cs Clientset
var err error
$range .allGroups$ cs.$.LowerCaseGroupGoName$$.Version$, err =$.PackageAlias$.NewForConfig(&configShallowCopy)
if err!=nil {
return nil, err
}
$end$
cs.DiscoveryClient, err = $.NewDiscoveryClientForConfig|raw$(&configShallowCopy)
if err!=nil {
$.glogErrorf|raw$("failed to create the DiscoveryClient: %v", err)
return nil, err
}
return &cs, nil
}
`
var newClientsetForConfigOrDieTemplate = `
// NewForConfigOrDie creates a new Clientset for the given config and
// panics if there is an error in the config.
func NewForConfigOrDie(c *$.Config|raw$) *Clientset {
var cs Clientset
$range .allGroups$ cs.$.LowerCaseGroupGoName$$.Version$ =$.PackageAlias$.NewForConfigOrDie(c)
$end$
cs.DiscoveryClient = $.NewDiscoveryClientForConfigOrDie|raw$(c)
return &cs
}
`
var newClientsetForRESTClientTemplate = `
// New creates a new Clientset for the given RESTClient.
func New(c $.RESTClientInterface|raw$) *Clientset {
var cs Clientset
$range .allGroups$ cs.$.LowerCaseGroupGoName$$.Version$ =$.PackageAlias$.New(c)
$end$
cs.DiscoveryClient = $.NewDiscoveryClient|raw$(c)
return &cs
}
`

View File

@ -1,54 +0,0 @@
/*
Copyright 2016 The Kubernetes 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 generators
import (
"io"
"os"
"path/filepath"
"strings"
"k8s.io/gengo/generator"
"k8s.io/gengo/types"
)
// genExpansion produces a file for a group client, e.g. ExtensionsClient for the extension group.
type genExpansion struct {
generator.DefaultGen
groupPackagePath string
// types in a group
types []*types.Type
}
// We only want to call GenerateType() once per group.
func (g *genExpansion) Filter(c *generator.Context, t *types.Type) bool {
return len(g.types) == 0 || t == g.types[0]
}
func (g *genExpansion) GenerateType(c *generator.Context, t *types.Type, w io.Writer) error {
sw := generator.NewSnippetWriter(w, c, "$", "$")
for _, t := range g.types {
if _, err := os.Stat(filepath.Join(g.groupPackagePath, strings.ToLower(t.Name.Name+"_expansion.go"))); os.IsNotExist(err) {
sw.Do(expansionInterfaceTemplate, t)
}
}
return sw.Error()
}
var expansionInterfaceTemplate = `
type $.|public$Expansion interface {}
`

View File

@ -1,255 +0,0 @@
/*
Copyright 2015 The Kubernetes 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 generators
import (
"io"
"path/filepath"
"k8s.io/gengo/generator"
"k8s.io/gengo/namer"
"k8s.io/gengo/types"
"k8s.io/code-generator/cmd/client-gen/generators/util"
"k8s.io/code-generator/cmd/client-gen/path"
)
// genGroup produces a file for a group client, e.g. ExtensionsClient for the extension group.
type genGroup struct {
generator.DefaultGen
outputPackage string
group string
version string
groupGoName string
apiPath string
// types in this group
types []*types.Type
imports namer.ImportTracker
inputPackage string
clientsetPackage string
// If the genGroup has been called. This generator should only execute once.
called bool
}
var _ generator.Generator = &genGroup{}
// We only want to call GenerateType() once per group.
func (g *genGroup) Filter(c *generator.Context, t *types.Type) bool {
if !g.called {
g.called = true
return true
}
return false
}
func (g *genGroup) Namers(c *generator.Context) namer.NameSystems {
return namer.NameSystems{
"raw": namer.NewRawNamer(g.outputPackage, g.imports),
}
}
func (g *genGroup) Imports(c *generator.Context) (imports []string) {
imports = append(imports, g.imports.ImportLines()...)
imports = append(imports, filepath.Join(g.clientsetPackage, "scheme"))
return
}
func (g *genGroup) GenerateType(c *generator.Context, t *types.Type, w io.Writer) error {
sw := generator.NewSnippetWriter(w, c, "$", "$")
apiPath := func(group string) string {
if len(g.apiPath) > 0 {
return `"` + g.apiPath + `"`
}
if group == "core" {
return `"/api"`
}
return `"/apis"`
}
groupName := g.group
if g.group == "core" {
groupName = ""
}
// allow user to define a group name that's different from the one parsed from the directory.
p := c.Universe.Package(path.Vendorless(g.inputPackage))
if override := types.ExtractCommentTags("+", p.Comments)["groupName"]; override != nil {
groupName = override[0]
}
m := map[string]interface{}{
"group": g.group,
"version": g.version,
"groupName": groupName,
"GroupGoName": g.groupGoName,
"Version": namer.IC(g.version),
"types": g.types,
"apiPath": apiPath(g.group),
"schemaGroupVersion": c.Universe.Type(types.Name{Package: "k8s.io/apimachinery/pkg/runtime/schema", Name: "GroupVersion"}),
"runtimeAPIVersionInternal": c.Universe.Variable(types.Name{Package: "k8s.io/apimachinery/pkg/runtime", Name: "APIVersionInternal"}),
"serializerDirectCodecFactory": c.Universe.Type(types.Name{Package: "k8s.io/apimachinery/pkg/runtime/serializer", Name: "DirectCodecFactory"}),
"restConfig": c.Universe.Type(types.Name{Package: "k8s.io/client-go/rest", Name: "Config"}),
"restDefaultKubernetesUserAgent": c.Universe.Function(types.Name{Package: "k8s.io/client-go/rest", Name: "DefaultKubernetesUserAgent"}),
"restRESTClientInterface": c.Universe.Type(types.Name{Package: "k8s.io/client-go/rest", Name: "Interface"}),
"restRESTClientFor": c.Universe.Function(types.Name{Package: "k8s.io/client-go/rest", Name: "RESTClientFor"}),
"SchemeGroupVersion": c.Universe.Variable(types.Name{Package: path.Vendorless(g.inputPackage), Name: "SchemeGroupVersion"}),
}
sw.Do(groupInterfaceTemplate, m)
sw.Do(groupClientTemplate, m)
for _, t := range g.types {
tags, err := util.ParseClientGenTags(append(t.SecondClosestCommentLines, t.CommentLines...))
if err != nil {
return err
}
wrapper := map[string]interface{}{
"type": t,
"GroupGoName": g.groupGoName,
"Version": namer.IC(g.version),
}
if tags.NonNamespaced {
sw.Do(getterImplNonNamespaced, wrapper)
} else {
sw.Do(getterImplNamespaced, wrapper)
}
}
sw.Do(newClientForConfigTemplate, m)
sw.Do(newClientForConfigOrDieTemplate, m)
sw.Do(newClientForRESTClientTemplate, m)
if g.version == "" {
sw.Do(setInternalVersionClientDefaultsTemplate, m)
} else {
sw.Do(setClientDefaultsTemplate, m)
}
sw.Do(getRESTClient, m)
return sw.Error()
}
var groupInterfaceTemplate = `
type $.GroupGoName$$.Version$Interface interface {
RESTClient() $.restRESTClientInterface|raw$
$range .types$ $.|publicPlural$Getter
$end$
}
`
var groupClientTemplate = `
// $.GroupGoName$$.Version$Client is used to interact with features provided by the $.groupName$ group.
type $.GroupGoName$$.Version$Client struct {
restClient $.restRESTClientInterface|raw$
}
`
var getterImplNamespaced = `
func (c *$.GroupGoName$$.Version$Client) $.type|publicPlural$(namespace string) $.type|public$Interface {
return new$.type|publicPlural$(c, namespace)
}
`
var getterImplNonNamespaced = `
func (c *$.GroupGoName$$.Version$Client) $.type|publicPlural$() $.type|public$Interface {
return new$.type|publicPlural$(c)
}
`
var newClientForConfigTemplate = `
// NewForConfig creates a new $.GroupGoName$$.Version$Client for the given config.
func NewForConfig(c *$.restConfig|raw$) (*$.GroupGoName$$.Version$Client, error) {
config := *c
if err := setConfigDefaults(&config); err != nil {
return nil, err
}
client, err := $.restRESTClientFor|raw$(&config)
if err != nil {
return nil, err
}
return &$.GroupGoName$$.Version$Client{client}, nil
}
`
var newClientForConfigOrDieTemplate = `
// NewForConfigOrDie creates a new $.GroupGoName$$.Version$Client for the given config and
// panics if there is an error in the config.
func NewForConfigOrDie(c *$.restConfig|raw$) *$.GroupGoName$$.Version$Client {
client, err := NewForConfig(c)
if err != nil {
panic(err)
}
return client
}
`
var getRESTClient = `
// RESTClient returns a RESTClient that is used to communicate
// with API server by this client implementation.
func (c *$.GroupGoName$$.Version$Client) RESTClient() $.restRESTClientInterface|raw$ {
if c == nil {
return nil
}
return c.restClient
}
`
var newClientForRESTClientTemplate = `
// New creates a new $.GroupGoName$$.Version$Client for the given RESTClient.
func New(c $.restRESTClientInterface|raw$) *$.GroupGoName$$.Version$Client {
return &$.GroupGoName$$.Version$Client{c}
}
`
var setInternalVersionClientDefaultsTemplate = `
func setConfigDefaults(config *$.restConfig|raw$) error {
g, err := scheme.Registry.Group("$.groupName$")
if err != nil {
return err
}
config.APIPath = $.apiPath$
if config.UserAgent == "" {
config.UserAgent = $.restDefaultKubernetesUserAgent|raw$()
}
if config.GroupVersion == nil || config.GroupVersion.Group != g.GroupVersion.Group {
gv := g.GroupVersion
config.GroupVersion = &gv
}
config.NegotiatedSerializer = scheme.Codecs
if config.QPS == 0 {
config.QPS = 5
}
if config.Burst == 0 {
config.Burst = 10
}
return nil
}
`
var setClientDefaultsTemplate = `
func setConfigDefaults(config *$.restConfig|raw$) error {
gv := $.SchemeGroupVersion|raw$
config.GroupVersion = &gv
config.APIPath = $.apiPath$
config.NegotiatedSerializer = $.serializerDirectCodecFactory|raw${CodecFactory: scheme.Codecs}
if config.UserAgent == "" {
config.UserAgent = $.restDefaultKubernetesUserAgent|raw$()
}
return nil
}
`

View File

@ -1,579 +0,0 @@
/*
Copyright 2015 The Kubernetes 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 generators
import (
"io"
"path/filepath"
"strings"
"k8s.io/gengo/generator"
"k8s.io/gengo/namer"
"k8s.io/gengo/types"
"k8s.io/code-generator/cmd/client-gen/generators/util"
)
// genClientForType produces a file for each top-level type.
type genClientForType struct {
generator.DefaultGen
outputPackage string
clientsetPackage string
group string
version string
groupGoName string
typeToMatch *types.Type
imports namer.ImportTracker
}
var _ generator.Generator = &genClientForType{}
// Filter ignores all but one type because we're making a single file per type.
func (g *genClientForType) Filter(c *generator.Context, t *types.Type) bool { return t == g.typeToMatch }
func (g *genClientForType) Namers(c *generator.Context) namer.NameSystems {
return namer.NameSystems{
"raw": namer.NewRawNamer(g.outputPackage, g.imports),
}
}
func (g *genClientForType) Imports(c *generator.Context) (imports []string) {
return g.imports.ImportLines()
}
// Ideally, we'd like genStatus to return true if there is a subresource path
// registered for "status" in the API server, but we do not have that
// information, so genStatus returns true if the type has a status field.
func genStatus(t *types.Type) bool {
// Default to true if we have a Status member
hasStatus := false
for _, m := range t.Members {
if m.Name == "Status" {
hasStatus = true
break
}
}
return hasStatus && !util.MustParseClientGenTags(append(t.SecondClosestCommentLines, t.CommentLines...)).NoStatus
}
// GenerateType makes the body of a file implementing the individual typed client for type t.
func (g *genClientForType) GenerateType(c *generator.Context, t *types.Type, w io.Writer) error {
sw := generator.NewSnippetWriter(w, c, "$", "$")
pkg := filepath.Base(t.Name.Package)
tags, err := util.ParseClientGenTags(append(t.SecondClosestCommentLines, t.CommentLines...))
if err != nil {
return err
}
type extendedInterfaceMethod struct {
template string
args map[string]interface{}
}
extendedMethods := []extendedInterfaceMethod{}
for _, e := range tags.Extensions {
inputType := *t
resultType := *t
// TODO: Extract this to some helper method as this code is copied into
// 2 other places.
if len(e.InputTypeOverride) > 0 {
if name, pkg := e.Input(); len(pkg) > 0 {
newType := c.Universe.Type(types.Name{Package: pkg, Name: name})
inputType = *newType
} else {
inputType.Name.Name = e.InputTypeOverride
}
}
if len(e.ResultTypeOverride) > 0 {
if name, pkg := e.Result(); len(pkg) > 0 {
newType := c.Universe.Type(types.Name{Package: pkg, Name: name})
resultType = *newType
} else {
resultType.Name.Name = e.ResultTypeOverride
}
}
var updatedVerbtemplate string
if _, exists := subresourceDefaultVerbTemplates[e.VerbType]; e.IsSubresource() && exists {
updatedVerbtemplate = e.VerbName + "(" + strings.TrimPrefix(subresourceDefaultVerbTemplates[e.VerbType], strings.Title(e.VerbType)+"(")
} else {
updatedVerbtemplate = e.VerbName + "(" + strings.TrimPrefix(defaultVerbTemplates[e.VerbType], strings.Title(e.VerbType)+"(")
}
extendedMethods = append(extendedMethods, extendedInterfaceMethod{
template: updatedVerbtemplate,
args: map[string]interface{}{
"type": t,
"inputType": &inputType,
"resultType": &resultType,
"DeleteOptions": c.Universe.Type(types.Name{Package: "k8s.io/apimachinery/pkg/apis/meta/v1", Name: "DeleteOptions"}),
"ListOptions": c.Universe.Type(types.Name{Package: "k8s.io/apimachinery/pkg/apis/meta/v1", Name: "ListOptions"}),
"GetOptions": c.Universe.Type(types.Name{Package: "k8s.io/apimachinery/pkg/apis/meta/v1", Name: "GetOptions"}),
"PatchType": c.Universe.Type(types.Name{Package: "k8s.io/apimachinery/pkg/types", Name: "PatchType"}),
},
})
}
m := map[string]interface{}{
"type": t,
"inputType": t,
"resultType": t,
"package": pkg,
"Package": namer.IC(pkg),
"namespaced": !tags.NonNamespaced,
"Group": namer.IC(g.group),
"subresource": false,
"subresourcePath": "",
"GroupGoName": g.groupGoName,
"Version": namer.IC(g.version),
"DeleteOptions": c.Universe.Type(types.Name{Package: "k8s.io/apimachinery/pkg/apis/meta/v1", Name: "DeleteOptions"}),
"ListOptions": c.Universe.Type(types.Name{Package: "k8s.io/apimachinery/pkg/apis/meta/v1", Name: "ListOptions"}),
"GetOptions": c.Universe.Type(types.Name{Package: "k8s.io/apimachinery/pkg/apis/meta/v1", Name: "GetOptions"}),
"PatchType": c.Universe.Type(types.Name{Package: "k8s.io/apimachinery/pkg/types", Name: "PatchType"}),
"watchInterface": c.Universe.Type(types.Name{Package: "k8s.io/apimachinery/pkg/watch", Name: "Interface"}),
"RESTClientInterface": c.Universe.Type(types.Name{Package: "k8s.io/client-go/rest", Name: "Interface"}),
"schemeParameterCodec": c.Universe.Variable(types.Name{Package: filepath.Join(g.clientsetPackage, "scheme"), Name: "ParameterCodec"}),
}
sw.Do(getterComment, m)
if tags.NonNamespaced {
sw.Do(getterNonNamespaced, m)
} else {
sw.Do(getterNamespaced, m)
}
sw.Do(interfaceTemplate1, m)
if !tags.NoVerbs {
if !genStatus(t) {
tags.SkipVerbs = append(tags.SkipVerbs, "updateStatus")
}
interfaceSuffix := ""
if len(extendedMethods) > 0 {
interfaceSuffix = "\n"
}
sw.Do("\n"+generateInterface(tags)+interfaceSuffix, m)
// add extended verbs into interface
for _, v := range extendedMethods {
sw.Do(v.template+interfaceSuffix, v.args)
}
}
sw.Do(interfaceTemplate4, m)
if tags.NonNamespaced {
sw.Do(structNonNamespaced, m)
sw.Do(newStructNonNamespaced, m)
} else {
sw.Do(structNamespaced, m)
sw.Do(newStructNamespaced, m)
}
if tags.NoVerbs {
return sw.Error()
}
if tags.HasVerb("get") {
sw.Do(getTemplate, m)
}
if tags.HasVerb("list") {
sw.Do(listTemplate, m)
}
if tags.HasVerb("watch") {
sw.Do(watchTemplate, m)
}
if tags.HasVerb("create") {
sw.Do(createTemplate, m)
}
if tags.HasVerb("update") {
sw.Do(updateTemplate, m)
}
if tags.HasVerb("updateStatus") {
sw.Do(updateStatusTemplate, m)
}
if tags.HasVerb("delete") {
sw.Do(deleteTemplate, m)
}
if tags.HasVerb("deleteCollection") {
sw.Do(deleteCollectionTemplate, m)
}
if tags.HasVerb("patch") {
sw.Do(patchTemplate, m)
}
// generate expansion methods
for _, e := range tags.Extensions {
inputType := *t
resultType := *t
if len(e.InputTypeOverride) > 0 {
if name, pkg := e.Input(); len(pkg) > 0 {
newType := c.Universe.Type(types.Name{Package: pkg, Name: name})
inputType = *newType
} else {
inputType.Name.Name = e.InputTypeOverride
}
}
if len(e.ResultTypeOverride) > 0 {
if name, pkg := e.Result(); len(pkg) > 0 {
newType := c.Universe.Type(types.Name{Package: pkg, Name: name})
resultType = *newType
} else {
resultType.Name.Name = e.ResultTypeOverride
}
}
m["inputType"] = &inputType
m["resultType"] = &resultType
m["subresourcePath"] = e.SubResourcePath
if e.HasVerb("get") {
if e.IsSubresource() {
sw.Do(adjustTemplate(e.VerbName, e.VerbType, getSubresourceTemplate), m)
} else {
sw.Do(adjustTemplate(e.VerbName, e.VerbType, getTemplate), m)
}
}
if e.HasVerb("list") {
if e.IsSubresource() {
sw.Do(adjustTemplate(e.VerbName, e.VerbType, listSubresourceTemplate), m)
} else {
sw.Do(adjustTemplate(e.VerbName, e.VerbType, listTemplate), m)
}
}
// TODO: Figure out schemantic for watching a sub-resource.
if e.HasVerb("watch") {
sw.Do(adjustTemplate(e.VerbName, e.VerbType, watchTemplate), m)
}
if e.HasVerb("create") {
if e.IsSubresource() {
sw.Do(adjustTemplate(e.VerbName, e.VerbType, createSubresourceTemplate), m)
} else {
sw.Do(adjustTemplate(e.VerbName, e.VerbType, createTemplate), m)
}
}
if e.HasVerb("update") {
if e.IsSubresource() {
sw.Do(adjustTemplate(e.VerbName, e.VerbType, updateSubresourceTemplate), m)
} else {
sw.Do(adjustTemplate(e.VerbName, e.VerbType, updateTemplate), m)
}
}
// TODO: Figure out schemantic for deleting a sub-resource (what arguments
// are passed, does it need two names? etc.
if e.HasVerb("delete") {
sw.Do(adjustTemplate(e.VerbName, e.VerbType, deleteTemplate), m)
}
if e.HasVerb("patch") {
sw.Do(adjustTemplate(e.VerbName, e.VerbType, patchTemplate), m)
}
}
return sw.Error()
}
// adjustTemplate adjust the origin verb template using the expansion name.
// TODO: Make the verbs in templates parametrized so the strings.Replace() is
// not needed.
func adjustTemplate(name, verbType, template string) string {
return strings.Replace(template, " "+strings.Title(verbType), " "+name, -1)
}
func generateInterface(tags util.Tags) string {
// need an ordered list here to guarantee order of generated methods.
out := []string{}
for _, m := range util.SupportedVerbs {
if tags.HasVerb(m) {
out = append(out, defaultVerbTemplates[m])
}
}
return strings.Join(out, "\n")
}
var subresourceDefaultVerbTemplates = map[string]string{
"create": `Create($.type|private$Name string, $.inputType|private$ *$.inputType|raw$) (*$.resultType|raw$, error)`,
"list": `List($.type|private$Name string, opts $.ListOptions|raw$) (*$.resultType|raw$List, error)`,
"update": `Update($.type|private$Name string, $.inputType|private$ *$.inputType|raw$) (*$.resultType|raw$, error)`,
"get": `Get($.type|private$Name string, options $.GetOptions|raw$) (*$.resultType|raw$, error)`,
}
var defaultVerbTemplates = map[string]string{
"create": `Create(*$.inputType|raw$) (*$.resultType|raw$, error)`,
"update": `Update(*$.inputType|raw$) (*$.resultType|raw$, error)`,
"updateStatus": `UpdateStatus(*$.type|raw$) (*$.type|raw$, error)`,
"delete": `Delete(name string, options *$.DeleteOptions|raw$) error`,
"deleteCollection": `DeleteCollection(options *$.DeleteOptions|raw$, listOptions $.ListOptions|raw$) error`,
"get": `Get(name string, options $.GetOptions|raw$) (*$.resultType|raw$, error)`,
"list": `List(opts $.ListOptions|raw$) (*$.resultType|raw$List, error)`,
"watch": `Watch(opts $.ListOptions|raw$) ($.watchInterface|raw$, error)`,
"patch": `Patch(name string, pt $.PatchType|raw$, data []byte, subresources ...string) (result *$.resultType|raw$, err error)`,
}
// group client will implement this interface.
var getterComment = `
// $.type|publicPlural$Getter has a method to return a $.type|public$Interface.
// A group's client should implement this interface.`
var getterNamespaced = `
type $.type|publicPlural$Getter interface {
$.type|publicPlural$(namespace string) $.type|public$Interface
}
`
var getterNonNamespaced = `
type $.type|publicPlural$Getter interface {
$.type|publicPlural$() $.type|public$Interface
}
`
// this type's interface, typed client will implement this interface.
var interfaceTemplate1 = `
// $.type|public$Interface has methods to work with $.type|public$ resources.
type $.type|public$Interface interface {`
var interfaceTemplate4 = `
$.type|public$Expansion
}
`
// template for the struct that implements the type's interface
var structNamespaced = `
// $.type|privatePlural$ implements $.type|public$Interface
type $.type|privatePlural$ struct {
client $.RESTClientInterface|raw$
ns string
}
`
// template for the struct that implements the type's interface
var structNonNamespaced = `
// $.type|privatePlural$ implements $.type|public$Interface
type $.type|privatePlural$ struct {
client $.RESTClientInterface|raw$
}
`
var newStructNamespaced = `
// new$.type|publicPlural$ returns a $.type|publicPlural$
func new$.type|publicPlural$(c *$.GroupGoName$$.Version$Client, namespace string) *$.type|privatePlural$ {
return &$.type|privatePlural${
client: c.RESTClient(),
ns: namespace,
}
}
`
var newStructNonNamespaced = `
// new$.type|publicPlural$ returns a $.type|publicPlural$
func new$.type|publicPlural$(c *$.GroupGoName$$.Version$Client) *$.type|privatePlural$ {
return &$.type|privatePlural${
client: c.RESTClient(),
}
}
`
var listTemplate = `
// List takes label and field selectors, and returns the list of $.resultType|publicPlural$ that match those selectors.
func (c *$.type|privatePlural$) List(opts $.ListOptions|raw$) (result *$.resultType|raw$List, err error) {
result = &$.resultType|raw$List{}
err = c.client.Get().
$if .namespaced$Namespace(c.ns).$end$
Resource("$.type|resource$").
VersionedParams(&opts, $.schemeParameterCodec|raw$).
Do().
Into(result)
return
}
`
var listSubresourceTemplate = `
// List takes $.type|raw$ name, label and field selectors, and returns the list of $.resultType|publicPlural$ that match those selectors.
func (c *$.type|privatePlural$) List($.type|private$Name string, opts $.ListOptions|raw$) (result *$.resultType|raw$List, err error) {
result = &$.resultType|raw$List{}
err = c.client.Get().
$if .namespaced$Namespace(c.ns).$end$
Resource("$.type|resource$").
Name($.type|private$Name).
SubResource("$.subresourcePath$").
VersionedParams(&opts, $.schemeParameterCodec|raw$).
Do().
Into(result)
return
}
`
var getTemplate = `
// Get takes name of the $.type|private$, and returns the corresponding $.resultType|private$ object, and an error if there is any.
func (c *$.type|privatePlural$) Get(name string, options $.GetOptions|raw$) (result *$.resultType|raw$, err error) {
result = &$.resultType|raw${}
err = c.client.Get().
$if .namespaced$Namespace(c.ns).$end$
Resource("$.type|resource$").
Name(name).
VersionedParams(&options, $.schemeParameterCodec|raw$).
Do().
Into(result)
return
}
`
var getSubresourceTemplate = `
// Get takes name of the $.type|private$, and returns the corresponding $.resultType|raw$ object, and an error if there is any.
func (c *$.type|privatePlural$) Get($.type|private$Name string, options $.GetOptions|raw$) (result *$.resultType|raw$, err error) {
result = &$.resultType|raw${}
err = c.client.Get().
$if .namespaced$Namespace(c.ns).$end$
Resource("$.type|resource$").
Name($.type|private$Name).
SubResource("$.subresourcePath$").
VersionedParams(&options, $.schemeParameterCodec|raw$).
Do().
Into(result)
return
}
`
var deleteTemplate = `
// Delete takes name of the $.type|private$ and deletes it. Returns an error if one occurs.
func (c *$.type|privatePlural$) Delete(name string, options *$.DeleteOptions|raw$) error {
return c.client.Delete().
$if .namespaced$Namespace(c.ns).$end$
Resource("$.type|resource$").
Name(name).
Body(options).
Do().
Error()
}
`
var deleteCollectionTemplate = `
// DeleteCollection deletes a collection of objects.
func (c *$.type|privatePlural$) DeleteCollection(options *$.DeleteOptions|raw$, listOptions $.ListOptions|raw$) error {
return c.client.Delete().
$if .namespaced$Namespace(c.ns).$end$
Resource("$.type|resource$").
VersionedParams(&listOptions, $.schemeParameterCodec|raw$).
Body(options).
Do().
Error()
}
`
var createSubresourceTemplate = `
// Create takes the representation of a $.inputType|private$ and creates it. Returns the server's representation of the $.resultType|private$, and an error, if there is any.
func (c *$.type|privatePlural$) Create($.type|private$Name string, $.inputType|private$ *$.inputType|raw$) (result *$.resultType|raw$, err error) {
result = &$.resultType|raw${}
err = c.client.Post().
$if .namespaced$Namespace(c.ns).$end$
Resource("$.type|resource$").
Name($.type|private$Name).
SubResource("$.subresourcePath$").
Body($.inputType|private$).
Do().
Into(result)
return
}
`
var createTemplate = `
// Create takes the representation of a $.inputType|private$ and creates it. Returns the server's representation of the $.resultType|private$, and an error, if there is any.
func (c *$.type|privatePlural$) Create($.inputType|private$ *$.inputType|raw$) (result *$.resultType|raw$, err error) {
result = &$.resultType|raw${}
err = c.client.Post().
$if .namespaced$Namespace(c.ns).$end$
Resource("$.type|resource$").
Body($.inputType|private$).
Do().
Into(result)
return
}
`
var updateSubresourceTemplate = `
// Update takes the top resource name and the representation of a $.inputType|private$ and updates it. Returns the server's representation of the $.resultType|private$, and an error, if there is any.
func (c *$.type|privatePlural$) Update($.type|private$Name string, $.inputType|private$ *$.inputType|raw$) (result *$.resultType|raw$, err error) {
result = &$.resultType|raw${}
err = c.client.Put().
$if .namespaced$Namespace(c.ns).$end$
Resource("$.type|resource$").
Name($.type|private$Name).
SubResource("$.subresourcePath$").
Body($.inputType|private$).
Do().
Into(result)
return
}
`
var updateTemplate = `
// Update takes the representation of a $.inputType|private$ and updates it. Returns the server's representation of the $.resultType|private$, and an error, if there is any.
func (c *$.type|privatePlural$) Update($.inputType|private$ *$.inputType|raw$) (result *$.resultType|raw$, err error) {
result = &$.resultType|raw${}
err = c.client.Put().
$if .namespaced$Namespace(c.ns).$end$
Resource("$.type|resource$").
Name($.inputType|private$.Name).
Body($.inputType|private$).
Do().
Into(result)
return
}
`
var updateStatusTemplate = `
// UpdateStatus was generated because the type contains a Status member.
// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus().
func (c *$.type|privatePlural$) UpdateStatus($.type|private$ *$.type|raw$) (result *$.type|raw$, err error) {
result = &$.type|raw${}
err = c.client.Put().
$if .namespaced$Namespace(c.ns).$end$
Resource("$.type|resource$").
Name($.type|private$.Name).
SubResource("status").
Body($.type|private$).
Do().
Into(result)
return
}
`
var watchTemplate = `
// Watch returns a $.watchInterface|raw$ that watches the requested $.type|privatePlural$.
func (c *$.type|privatePlural$) Watch(opts $.ListOptions|raw$) ($.watchInterface|raw$, error) {
opts.Watch = true
return c.client.Get().
$if .namespaced$Namespace(c.ns).$end$
Resource("$.type|resource$").
VersionedParams(&opts, $.schemeParameterCodec|raw$).
Watch()
}
`
var patchTemplate = `
// Patch applies the patch and returns the patched $.resultType|private$.
func (c *$.type|privatePlural$) Patch(name string, pt $.PatchType|raw$, data []byte, subresources ...string) (result *$.resultType|raw$, err error) {
result = &$.resultType|raw${}
err = c.client.Patch(pt).
$if .namespaced$Namespace(c.ns).$end$
Resource("$.type|resource$").
SubResource(subresources...).
Name(name).
Body(data).
Do().
Into(result)
return
}
`

View File

@ -1,185 +0,0 @@
/*
Copyright 2017 The Kubernetes 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 scheme
import (
"fmt"
"io"
"os"
"path/filepath"
"strings"
"k8s.io/code-generator/cmd/client-gen/path"
clientgentypes "k8s.io/code-generator/cmd/client-gen/types"
"k8s.io/gengo/generator"
"k8s.io/gengo/namer"
"k8s.io/gengo/types"
)
// GenScheme produces a package for a clientset with the scheme, codecs and parameter codecs.
type GenScheme struct {
generator.DefaultGen
OutputPackage string
Groups []clientgentypes.GroupVersions
GroupGoNames map[clientgentypes.GroupVersion]string
InputPackages map[clientgentypes.GroupVersion]string
OutputPath string
ImportTracker namer.ImportTracker
PrivateScheme bool
CreateRegistry bool
schemeGenerated bool
}
func (g *GenScheme) Namers(c *generator.Context) namer.NameSystems {
return namer.NameSystems{
"raw": namer.NewRawNamer(g.OutputPackage, g.ImportTracker),
}
}
// We only want to call GenerateType() once.
func (g *GenScheme) Filter(c *generator.Context, t *types.Type) bool {
ret := !g.schemeGenerated
g.schemeGenerated = true
return ret
}
func (g *GenScheme) Imports(c *generator.Context) (imports []string) {
imports = append(imports, g.ImportTracker.ImportLines()...)
for _, group := range g.Groups {
for _, version := range group.Versions {
packagePath := g.InputPackages[clientgentypes.GroupVersion{Group: group.Group, Version: version}]
groupAlias := strings.ToLower(g.GroupGoNames[clientgentypes.GroupVersion{group.Group, version}])
if g.CreateRegistry {
// import the install package for internal clientsets instead of the type package with register.go
if version != "" {
packagePath = filepath.Dir(packagePath)
}
packagePath = filepath.Join(packagePath, "install")
imports = append(imports, strings.ToLower(fmt.Sprintf("%s \"%s\"", groupAlias, path.Vendorless(packagePath))))
break
} else {
imports = append(imports, strings.ToLower(fmt.Sprintf("%s%s \"%s\"", groupAlias, version.NonEmpty(), path.Vendorless(packagePath))))
}
}
}
return
}
func (g *GenScheme) GenerateType(c *generator.Context, t *types.Type, w io.Writer) error {
sw := generator.NewSnippetWriter(w, c, "$", "$")
allGroupVersions := clientgentypes.ToGroupVersionPackages(g.Groups, g.GroupGoNames)
allInstallGroups := clientgentypes.ToGroupInstallPackages(g.Groups, g.GroupGoNames)
m := map[string]interface{}{
"allGroupVersions": allGroupVersions,
"allInstallGroups": allInstallGroups,
"customRegister": false,
"osGetenv": c.Universe.Function(types.Name{Package: "os", Name: "Getenv"}),
"runtimeNewParameterCodec": c.Universe.Function(types.Name{Package: "k8s.io/apimachinery/pkg/runtime", Name: "NewParameterCodec"}),
"runtimeNewScheme": c.Universe.Function(types.Name{Package: "k8s.io/apimachinery/pkg/runtime", Name: "NewScheme"}),
"serializerNewCodecFactory": c.Universe.Function(types.Name{Package: "k8s.io/apimachinery/pkg/runtime/serializer", Name: "NewCodecFactory"}),
"runtimeScheme": c.Universe.Type(types.Name{Package: "k8s.io/apimachinery/pkg/runtime", Name: "Scheme"}),
"schemaGroupVersion": c.Universe.Type(types.Name{Package: "k8s.io/apimachinery/pkg/runtime/schema", Name: "GroupVersion"}),
"metav1AddToGroupVersion": c.Universe.Function(types.Name{Package: "k8s.io/apimachinery/pkg/apis/meta/v1", Name: "AddToGroupVersion"}),
"announcedAPIGroupFactoryRegistry": c.Universe.Type(types.Name{Package: "k8s.io/apimachinery/pkg/apimachinery/announced", Name: "APIGroupFactoryRegistry"}),
"registeredNewOrDie": c.Universe.Function(types.Name{Package: "k8s.io/apimachinery/pkg/apimachinery/registered", Name: "NewOrDie"}),
"registeredAPIRegistrationManager": c.Universe.Type(types.Name{Package: "k8s.io/apimachinery/pkg/apimachinery/registered", Name: "APIRegistrationManager"}),
}
globals := map[string]string{
"Scheme": "Scheme",
"Codecs": "Codecs",
"ParameterCodec": "ParameterCodec",
"Registry": "Registry",
"GroupFactoryRegistry": "GroupFactoryRegistry",
}
for k, v := range globals {
if g.PrivateScheme {
m[k] = strings.ToLower(v[0:1]) + v[1:]
} else {
m[k] = v
}
}
sw.Do(globalsTemplate, m)
if g.OutputPath != "" {
if _, err := os.Stat(filepath.Join(g.OutputPath, strings.ToLower("register_custom.go"))); err == nil {
m["customRegister"] = true
}
}
if g.CreateRegistry {
sw.Do(registryRegistration, m)
} else {
sw.Do(simpleRegistration, m)
}
return sw.Error()
}
var globalsTemplate = `
var $.Scheme$ = $.runtimeNewScheme|raw$()
var $.Codecs$ = $.serializerNewCodecFactory|raw$($.Scheme$)
var $.ParameterCodec$ = $.runtimeNewParameterCodec|raw$($.Scheme$)
`
var registryRegistration = `
var $.Registry$ = $.registeredNewOrDie|raw$($.osGetenv|raw$("KUBE_API_VERSIONS"))
var $.GroupFactoryRegistry$ = make($.announcedAPIGroupFactoryRegistry|raw$)
func init() {
$.metav1AddToGroupVersion|raw$($.Scheme$, $.schemaGroupVersion|raw${Version: "v1"})
Install($.GroupFactoryRegistry$, $.Registry$, $.Scheme$)
}
// Install registers the API group and adds types to a scheme
func Install(groupFactoryRegistry $.announcedAPIGroupFactoryRegistry|raw$, registry *$.registeredAPIRegistrationManager|raw$, scheme *$.runtimeScheme|raw$) {
$range .allInstallGroups$ $.InstallPackageAlias$.Install(groupFactoryRegistry, registry, scheme)
$end$
$if .customRegister$ExtraInstall(groupFactoryRegistry, registry, scheme)$end$
}
`
var simpleRegistration = `
func init() {
$.metav1AddToGroupVersion|raw$($.Scheme$, $.schemaGroupVersion|raw${Version: "v1"})
AddToScheme($.Scheme$)
}
// AddToScheme adds all types of this clientset into the given scheme. This allows composition
// of clientsets, like in:
//
// import (
// "k8s.io/client-go/kubernetes"
// clientsetscheme "k8s.io/client-go/kuberentes/scheme"
// aggregatorclientsetscheme "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/scheme"
// )
//
// kclientset, _ := kubernetes.NewForConfig(c)
// aggregatorclientsetscheme.AddToScheme(clientsetscheme.Scheme)
//
// After this, RawExtensions in Kubernetes types will serialize kube-aggregator types
// correctly.
func AddToScheme(scheme *$.runtimeScheme|raw$) {
$range .allGroupVersions$ $.PackageAlias$.AddToScheme(scheme)
$end$
$if .customRegister$ExtraAddToScheme(scheme)$end$
}
`

View File

@ -1,32 +0,0 @@
/*
Copyright 2016 The Kubernetes 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 generators
import (
"k8s.io/gengo/types"
)
// extractTag gets the comment-tags for the key. If the tag did not exist, it
// returns the empty string.
func extractTag(key string, lines []string) string {
val, present := types.ExtractCommentTags("+", lines)[key]
if !present || len(val) < 1 {
return ""
}
return val[0]
}

View File

@ -1,341 +0,0 @@
/*
Copyright 2016 The Kubernetes 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 (
"errors"
"fmt"
"strings"
"k8s.io/gengo/types"
)
var supportedTags = []string{
"genclient",
"genclient:nonNamespaced",
"genclient:noVerbs",
"genclient:onlyVerbs",
"genclient:skipVerbs",
"genclient:noStatus",
"genclient:readonly",
"genclient:method",
}
// SupportedVerbs is a list of supported verbs for +onlyVerbs and +skipVerbs.
var SupportedVerbs = []string{
"create",
"update",
"updateStatus",
"delete",
"deleteCollection",
"get",
"list",
"watch",
"patch",
}
// ReadonlyVerbs represents a list of read-only verbs.
var ReadonlyVerbs = []string{
"get",
"list",
"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
GenerateClient bool
// +genclient:nonNamespaced
NonNamespaced bool
// +genclient:noStatus
NoStatus bool
// +genclient:noVerbs
NoVerbs bool
// +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
// generate the function for it.
func (t Tags) HasVerb(verb string) bool {
if len(t.SkipVerbs) == 0 {
return true
}
for _, s := range t.SkipVerbs {
if verb == s {
return false
}
}
return true
}
// MustParseClientGenTags calls ParseClientGenTags but instead of returning error it panics.
func MustParseClientGenTags(lines []string) Tags {
tags, err := ParseClientGenTags(lines)
if err != nil {
panic(err.Error())
}
return tags
}
// ParseClientGenTags parse the provided genclient tags and validates that no unknown
// tags are provided.
func ParseClientGenTags(lines []string) (Tags, error) {
ret := Tags{}
values := types.ExtractCommentTags("+", lines)
value := []string{}
value, ret.GenerateClient = values["genclient"]
// Check the old format and error when used to avoid generating client when //+genclient=false
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[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[genClientPrefix+"noVerbs"]
_, ret.NoStatus = values[genClientPrefix+"noStatus"]
onlyVerbs := []string{}
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[genClientPrefix+"skipVerbs"]; exists {
ret.SkipVerbs = strings.Split(v[0], ",")
}
if v, exists := values[genClientPrefix+"onlyVerbs"]; exists || len(onlyVerbs) > 0 {
if len(v) > 0 {
onlyVerbs = append(onlyVerbs, strings.Split(v[0], ",")...)
}
skipVerbs := []string{}
for _, m := range SupportedVerbs {
skip := true
for _, o := range onlyVerbs {
if o == m {
skip = false
break
}
}
// Check for conflicts
for _, v := range skipVerbs {
if v == m {
return ret, fmt.Errorf("verb %q used both in genclient:skipVerbs and genclient:onlyVerbs", v)
}
}
if skip {
skipVerbs = append(skipVerbs, m)
}
}
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, strings.TrimSuffix(genClientPrefix, ":")) {
return errors.New("unknown tag detected: " + key)
}
}
return nil
}

View File

@ -1,71 +0,0 @@
/*
Copyright 2015 The Kubernetes 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.
*/
// client-gen makes the individual typed clients using gengo.
package main
import (
"flag"
"path"
"path/filepath"
"github.com/golang/glog"
"github.com/spf13/pflag"
clientgenargs "k8s.io/code-generator/cmd/client-gen/args"
"k8s.io/code-generator/cmd/client-gen/generators"
"k8s.io/gengo/args"
)
func main() {
arguments := args.Default().WithoutDefaultFlagParsing()
// Custom args.
customArgs := &clientgenargs.CustomArgs{}
customArgs.AddFlags(pflag.CommandLine)
// Override defaults.
arguments.GoHeaderFilePath = filepath.Join(args.DefaultSourceTree(), "k8s.io/kubernetes/hack/boilerplate/boilerplate.go.txt")
arguments.CustomArgs = customArgs
arguments.InputDirs = []string{
"k8s.io/apimachinery/pkg/fields",
"k8s.io/apimachinery/pkg/labels",
"k8s.io/apimachinery/pkg/watch",
"k8s.io/apimachinery/pkg/apimachinery/registered",
}
// Register default flags. We do this manually here because we have to override InputDirs below after additional
// input dirs are parse fromt he command-line.
arguments.AddFlags(pflag.CommandLine)
pflag.CommandLine.AddGoFlagSet(flag.CommandLine)
pflag.Parse()
// Prefix with InputBaseDir and add client dirs as input dirs.
for gv, pth := range customArgs.GroupVersionToInputPath {
customArgs.GroupVersionToInputPath[gv] = path.Join(customArgs.InputBasePath, pth)
}
for _, pkg := range customArgs.GroupVersionToInputPath {
arguments.InputDirs = append(arguments.InputDirs, pkg)
}
if err := arguments.Execute(
generators.NameSystems(),
generators.DefaultNameSystem(),
generators.Packages,
); err != nil {
glog.Fatalf("Error: %v", err)
}
}

View File

@ -1,31 +0,0 @@
/*
Copyright 2017 The Kubernetes 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 path
import "strings"
// Vendorless removes the longest match of "*/vendor/" from the front of p.
// It is useful if a package locates in vendor/, e.g.,
// k8s.io/kubernetes/vendor/k8s.io/apimachinery/pkg/apis/meta/v1, because gengo
// indexes the package with its import path, e.g.,
// k8s.io/apimachinery/pkg/apis/meta/v1,
func Vendorless(p string) string {
if pos := strings.LastIndex(p, "/vendor/"); pos != -1 {
return p[pos+len("/vendor/"):]
}
return p
}

View File

@ -1,123 +0,0 @@
/*
Copyright 2016 The Kubernetes 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 types
import (
"fmt"
"regexp"
"sort"
"strings"
"k8s.io/gengo/namer"
)
// ToGroupVersion turns "group/version" string into a GroupVersion struct. It reports error
// if it cannot parse the string.
func ToGroupVersion(gv string) (GroupVersion, error) {
// this can be the internal version for the legacy kube types
// TODO once we've cleared the last uses as strings, this special case should be removed.
if (len(gv) == 0) || (gv == "/") {
return GroupVersion{}, nil
}
switch strings.Count(gv, "/") {
case 0:
return GroupVersion{Group(gv), ""}, nil
case 1:
i := strings.Index(gv, "/")
return GroupVersion{Group(gv[:i]), Version(gv[i+1:])}, nil
default:
return GroupVersion{}, fmt.Errorf("unexpected GroupVersion string: %v", gv)
}
}
type sortableSliceOfVersions []string
func (a sortableSliceOfVersions) Len() int { return len(a) }
func (a sortableSliceOfVersions) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a sortableSliceOfVersions) Less(i, j int) bool {
vi, vj := strings.TrimLeft(a[i], "v"), strings.TrimLeft(a[j], "v")
major := regexp.MustCompile("^[0-9]+")
viMajor, vjMajor := major.FindString(vi), major.FindString(vj)
viRemaining, vjRemaining := strings.TrimLeft(vi, viMajor), strings.TrimLeft(vj, vjMajor)
switch {
case len(viRemaining) == 0 && len(vjRemaining) == 0:
return viMajor < vjMajor
case len(viRemaining) == 0 && len(vjRemaining) != 0:
// stable version is greater than unstable version
return false
case len(viRemaining) != 0 && len(vjRemaining) == 0:
// stable version is greater than unstable version
return true
}
// neither are stable versions
if viMajor != vjMajor {
return viMajor < vjMajor
}
// assuming at most we have one alpha or one beta version, so if vi contains "alpha", it's the lesser one.
return strings.Contains(viRemaining, "alpha")
}
// Determine the default version among versions. If a user calls a group client
// without specifying the version (e.g., c.Core(), instead of c.CoreV1()), the
// default version will be returned.
func defaultVersion(versions []Version) Version {
var versionStrings []string
for _, version := range versions {
versionStrings = append(versionStrings, string(version))
}
sort.Sort(sortableSliceOfVersions(versionStrings))
return Version(versionStrings[len(versionStrings)-1])
}
// ToGroupVersionPackages is a helper function used by generators for groups.
func ToGroupVersionPackages(groups []GroupVersions, groupGoNames map[GroupVersion]string) []GroupVersionPackage {
var groupVersionPackages []GroupVersionPackage
for _, group := range groups {
defaultVersion := defaultVersion(group.Versions)
for _, version := range group.Versions {
groupGoName := groupGoNames[GroupVersion{Group: group.Group, Version: version}]
groupVersionPackages = append(groupVersionPackages, GroupVersionPackage{
Group: Group(namer.IC(group.Group.NonEmpty())),
Version: Version(namer.IC(version.String())),
PackageAlias: strings.ToLower(groupGoName + version.NonEmpty()),
IsDefaultVersion: version == defaultVersion && version != "",
GroupGoName: groupGoName,
LowerCaseGroupGoName: namer.IL(groupGoName),
})
}
}
return groupVersionPackages
}
func ToGroupInstallPackages(groups []GroupVersions, groupGoNames map[GroupVersion]string) []GroupInstallPackage {
var groupInstallPackages []GroupInstallPackage
for _, group := range groups {
defaultVersion := defaultVersion(group.Versions)
groupGoName := groupGoNames[GroupVersion{Group: group.Group, Version: defaultVersion}]
groupInstallPackages = append(groupInstallPackages, GroupInstallPackage{
Group: Group(namer.IC(group.Group.NonEmpty())),
InstallPackageAlias: strings.ToLower(groupGoName),
})
}
return groupInstallPackages
}
// NormalizeGroupVersion calls normalizes the GroupVersion.
//func NormalizeGroupVersion(gv GroupVersion) GroupVersion {
// return GroupVersion{Group: gv.Group.NonEmpty(), Version: gv.Version, NonEmptyVersion: normalization.Version(gv.Version)}
//}

View File

@ -1,72 +0,0 @@
/*
Copyright 2016 The Kubernetes 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 types
type Version string
func (v Version) String() string {
return string(v)
}
func (v Version) NonEmpty() string {
if v == "" {
return "internalVersion"
}
return v.String()
}
type Group string
func (g Group) String() string {
return string(g)
}
func (g Group) NonEmpty() string {
if g == "api" {
return "core"
}
return string(g)
}
type GroupVersion struct {
Group Group
Version Version
}
type GroupVersions struct {
// The package name of the group, e.g. extensions or networking
PackageName string
Group Group
Versions []Version
}
// GroupVersionPackage contains group name, version name, and the package name client-gen will generate for this group version.
type GroupVersionPackage struct {
Group Group
Version Version
// If a user calls a group client without specifying the version (e.g.,
// c.Core(), instead of c.CoreV1()), the default version will be returned.
IsDefaultVersion bool
PackageAlias string
GroupGoName string
LowerCaseGroupGoName string
}
type GroupInstallPackage struct {
Group Group
InstallPackageAlias string
}

View File

@ -1,77 +0,0 @@
/*
Copyright 2015 The Kubernetes 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.
*/
// deepcopy-gen is a tool for auto-generating DeepCopy functions.
//
// Given a list of input directories, it will generate functions that
// efficiently perform a full deep-copy of each type. For any type that
// offers a `.DeepCopy()` method, it will simply call that. Otherwise it will
// use standard value assignment whenever possible. If that is not possible it
// will try to call its own generated copy function for the type, if the type is
// within the allowed root packages. Failing that, it will fall back on
// `conversion.Cloner.DeepCopy(val)` to make the copy. The resulting file will
// be stored in the same directory as the processed source package.
//
// Generation is governed by comment tags in the source. Any package may
// request DeepCopy generation by including a comment in the file-comments of
// one file, of the form:
// // +k8s:deepcopy-gen=package
//
// DeepCopy functions can be generated for individual types, rather than the
// entire package by specifying a comment on the type definion of the form:
// // +k8s:deepcopy-gen=true
//
// When generating for a whole package, individual types may opt out of
// DeepCopy generation by specifying a comment on the of the form:
// // +k8s:deepcopy-gen=false
//
// Note that registration is a whole-package option, and is not available for
// individual types.
package main
import (
"path/filepath"
"k8s.io/gengo/args"
"k8s.io/gengo/examples/deepcopy-gen/generators"
"github.com/golang/glog"
"github.com/spf13/pflag"
)
func main() {
arguments := args.Default()
// Custom args.
customArgs := &generators.CustomArgs{}
pflag.CommandLine.StringSliceVar(&customArgs.BoundingDirs, "bounding-dirs", customArgs.BoundingDirs,
"Comma-separated list of import paths which bound the types for which deep-copies will be generated.")
// Override defaults.
arguments.GoHeaderFilePath = filepath.Join(args.DefaultSourceTree(), "k8s.io/kubernetes/hack/boilerplate/boilerplate.go.txt")
arguments.OutputFileBaseName = "deepcopy_generated"
arguments.CustomArgs = customArgs
// Run it.
if err := arguments.Execute(
generators.NameSystems(),
generators.DefaultNameSystem(),
generators.Packages,
); err != nil {
glog.Fatalf("Error: %v", err)
}
glog.V(2).Info("Completed successfully.")
}

View File

@ -1,78 +0,0 @@
/*
Copyright 2016 The Kubernetes 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.
*/
// defaulter-gen is a tool for auto-generating Defaulter functions.
//
// Given a list of input directories, it will scan for top level types
// and generate efficient defaulters for an entire object from the sum
// of the SetDefault_* methods contained in the object tree.
//
// Generation is governed by comment tags in the source. Any package may
// request defaulter generation by including one or more comment tags at
// the package comment level:
//
// // +k8s:defaulter-gen=<field-name-to-flag>
//
// which will create defaulters for any type that contains the provided
// field name (if the type has defaulters). Any type may request explicit
// defaulting by providing the comment tag:
//
// // +k8s:defaulter-gen=true|false
//
// An existing defaulter method (`SetDefaults_TYPE`) can provide the
// comment tag:
//
// // +k8s:defaulter-gen=covers
//
// to indicate that the defaulter does not or should not call any nested
// defaulters.
package main
import (
"path/filepath"
"k8s.io/gengo/args"
"k8s.io/gengo/examples/defaulter-gen/generators"
"github.com/golang/glog"
"github.com/spf13/pflag"
)
func main() {
arguments := args.Default()
// Custom args.
customArgs := &generators.CustomArgs{
ExtraPeerDirs: []string{},
}
pflag.CommandLine.StringSliceVar(&customArgs.ExtraPeerDirs, "extra-peer-dirs", customArgs.ExtraPeerDirs,
"Comma-separated list of import paths which are considered, after tag-specified peers, for conversions.")
// Override defaults.
arguments.GoHeaderFilePath = filepath.Join(args.DefaultSourceTree(), "k8s.io/kubernetes/hack/boilerplate/boilerplate.go.txt")
arguments.OutputFileBaseName = "zz_generated.defaults"
arguments.CustomArgs = customArgs
// Run it.
if err := arguments.Execute(
generators.NameSystems(),
generators.DefaultNameSystem(),
generators.Packages,
); err != nil {
glog.Fatalf("Error: %v", err)
}
glog.V(2).Info("Completed successfully.")
}

View File

@ -1,33 +0,0 @@
/*
Copyright 2016 The Kubernetes 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 generators
import "github.com/spf13/pflag"
type CustomArgs struct {
VersionedClientSetPackage string
InternalClientSetPackage string
ListersPackage string
SingleDirectory bool
}
func (ca *CustomArgs) AddFlags(fs *pflag.FlagSet) {
fs.StringVar(&ca.InternalClientSetPackage, "internal-clientset-package", ca.InternalClientSetPackage, "the full package name for the internal clientset to use")
fs.StringVar(&ca.VersionedClientSetPackage, "versioned-clientset-package", ca.VersionedClientSetPackage, "the full package name for the versioned clientset to use")
fs.StringVar(&ca.ListersPackage, "listers-package", ca.ListersPackage, "the full package name for the listers to use")
fs.BoolVar(&ca.SingleDirectory, "single-directory", ca.SingleDirectory, "if true, omit the intermediate \"internalversion\" and \"externalversions\" subdirectories")
}

View File

@ -1,208 +0,0 @@
/*
Copyright 2016 The Kubernetes 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 generators
import (
"io"
"path"
clientgentypes "k8s.io/code-generator/cmd/client-gen/types"
"k8s.io/gengo/generator"
"k8s.io/gengo/namer"
"k8s.io/gengo/types"
"github.com/golang/glog"
)
// factoryGenerator produces a file of listers for a given GroupVersion and
// type.
type factoryGenerator struct {
generator.DefaultGen
outputPackage string
imports namer.ImportTracker
groupVersions map[string]clientgentypes.GroupVersions
gvGoNames map[string]string
clientSetPackage string
internalInterfacesPackage string
filtered bool
}
var _ generator.Generator = &factoryGenerator{}
func (g *factoryGenerator) Filter(c *generator.Context, t *types.Type) bool {
if !g.filtered {
g.filtered = true
return true
}
return false
}
func (g *factoryGenerator) Namers(c *generator.Context) namer.NameSystems {
return namer.NameSystems{
"raw": namer.NewRawNamer(g.outputPackage, g.imports),
}
}
func (g *factoryGenerator) Imports(c *generator.Context) (imports []string) {
imports = append(imports, g.imports.ImportLines()...)
return
}
func (g *factoryGenerator) GenerateType(c *generator.Context, t *types.Type, w io.Writer) error {
sw := generator.NewSnippetWriter(w, c, "{{", "}}")
glog.V(5).Infof("processing type %v", t)
gvInterfaces := make(map[string]*types.Type)
gvNewFuncs := make(map[string]*types.Type)
for groupPkgName := range g.groupVersions {
gvInterfaces[groupPkgName] = c.Universe.Type(types.Name{Package: path.Join(g.outputPackage, groupPkgName), Name: "Interface"})
gvNewFuncs[groupPkgName] = c.Universe.Function(types.Name{Package: path.Join(g.outputPackage, groupPkgName), Name: "New"})
}
m := map[string]interface{}{
"cacheSharedIndexInformer": c.Universe.Type(cacheSharedIndexInformer),
"groupVersions": g.groupVersions,
"gvInterfaces": gvInterfaces,
"gvNewFuncs": gvNewFuncs,
"gvGoNames": g.gvGoNames,
"interfacesNewInformerFunc": c.Universe.Type(types.Name{Package: g.internalInterfacesPackage, Name: "NewInformerFunc"}),
"interfacesTweakListOptionsFunc": c.Universe.Type(types.Name{Package: g.internalInterfacesPackage, Name: "TweakListOptionsFunc"}),
"informerFactoryInterface": c.Universe.Type(types.Name{Package: g.internalInterfacesPackage, Name: "SharedInformerFactory"}),
"clientSetInterface": c.Universe.Type(types.Name{Package: g.clientSetPackage, Name: "Interface"}),
"reflectType": c.Universe.Type(reflectType),
"runtimeObject": c.Universe.Type(runtimeObject),
"schemaGroupVersionResource": c.Universe.Type(schemaGroupVersionResource),
"syncMutex": c.Universe.Type(syncMutex),
"timeDuration": c.Universe.Type(timeDuration),
"namespaceAll": c.Universe.Type(metav1NamespaceAll),
}
sw.Do(sharedInformerFactoryStruct, m)
sw.Do(sharedInformerFactoryInterface, m)
return sw.Error()
}
var sharedInformerFactoryStruct = `
type sharedInformerFactory struct {
client {{.clientSetInterface|raw}}
namespace string
tweakListOptions {{.interfacesTweakListOptionsFunc|raw}}
lock {{.syncMutex|raw}}
defaultResync {{.timeDuration|raw}}
informers map[{{.reflectType|raw}}]{{.cacheSharedIndexInformer|raw}}
// startedInformers is used for tracking which informers have been started.
// This allows Start() to be called multiple times safely.
startedInformers map[{{.reflectType|raw}}]bool
}
// NewSharedInformerFactory constructs a new instance of sharedInformerFactory
func NewSharedInformerFactory(client {{.clientSetInterface|raw}}, defaultResync {{.timeDuration|raw}}) SharedInformerFactory {
return NewFilteredSharedInformerFactory(client, defaultResync, {{.namespaceAll|raw}}, nil)
}
// NewFilteredSharedInformerFactory constructs a new instance of sharedInformerFactory.
// Listers obtained via this SharedInformerFactory will be subject to the same filters
// as specified here.
func NewFilteredSharedInformerFactory(client {{.clientSetInterface|raw}}, defaultResync {{.timeDuration|raw}}, namespace string, tweakListOptions {{.interfacesTweakListOptionsFunc|raw}}) SharedInformerFactory {
return &sharedInformerFactory{
client: client,
namespace: namespace,
tweakListOptions: tweakListOptions,
defaultResync: defaultResync,
informers: make(map[{{.reflectType|raw}}]{{.cacheSharedIndexInformer|raw}}),
startedInformers: make(map[{{.reflectType|raw}}]bool),
}
}
// Start initializes all requested informers.
func (f *sharedInformerFactory) Start(stopCh <-chan struct{}) {
f.lock.Lock()
defer f.lock.Unlock()
for informerType, informer := range f.informers {
if !f.startedInformers[informerType] {
go informer.Run(stopCh)
f.startedInformers[informerType] = true
}
}
}
// WaitForCacheSync waits for all started informers' cache were synced.
func (f *sharedInformerFactory) WaitForCacheSync(stopCh <-chan struct{}) map[reflect.Type]bool {
informers := func()map[reflect.Type]cache.SharedIndexInformer{
f.lock.Lock()
defer f.lock.Unlock()
informers := map[reflect.Type]cache.SharedIndexInformer{}
for informerType, informer := range f.informers {
if f.startedInformers[informerType] {
informers[informerType] = informer
}
}
return informers
}()
res := map[reflect.Type]bool{}
for informType, informer := range informers {
res[informType] = cache.WaitForCacheSync(stopCh, informer.HasSynced)
}
return res
}
// InternalInformerFor returns the SharedIndexInformer for obj using an internal
// client.
func (f *sharedInformerFactory) InformerFor(obj {{.runtimeObject|raw}}, newFunc {{.interfacesNewInformerFunc|raw}}) {{.cacheSharedIndexInformer|raw}} {
f.lock.Lock()
defer f.lock.Unlock()
informerType := reflect.TypeOf(obj)
informer, exists := f.informers[informerType]
if exists {
return informer
}
informer = newFunc(f.client, f.defaultResync)
f.informers[informerType] = informer
return informer
}
`
var sharedInformerFactoryInterface = `
// SharedInformerFactory provides shared informers for resources in all known
// API group versions.
type SharedInformerFactory interface {
{{.informerFactoryInterface|raw}}
ForResource(resource {{.schemaGroupVersionResource|raw}}) (GenericInformer, error)
WaitForCacheSync(stopCh <-chan struct{}) map[reflect.Type]bool
{{$gvInterfaces := .gvInterfaces}}
{{$gvGoNames := .gvGoNames}}
{{range $groupName, $group := .groupVersions}}{{index $gvGoNames $groupName}}() {{index $gvInterfaces $groupName|raw}}
{{end}}
}
{{$gvNewFuncs := .gvNewFuncs}}
{{$gvGoNames := .gvGoNames}}
{{range $groupPkgName, $group := .groupVersions}}
func (f *sharedInformerFactory) {{index $gvGoNames $groupPkgName}}() {{index $gvInterfaces $groupPkgName|raw}} {
return {{index $gvNewFuncs $groupPkgName|raw}}(f, f.namespace, f.tweakListOptions)
}
{{end}}
`

View File

@ -1,88 +0,0 @@
/*
Copyright 2016 The Kubernetes 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 generators
import (
"io"
"k8s.io/gengo/generator"
"k8s.io/gengo/namer"
"k8s.io/gengo/types"
"github.com/golang/glog"
)
// factoryInterfaceGenerator produces a file of interfaces used to break a dependency cycle for
// informer registration
type factoryInterfaceGenerator struct {
generator.DefaultGen
outputPackage string
imports namer.ImportTracker
clientSetPackage string
filtered bool
}
var _ generator.Generator = &factoryInterfaceGenerator{}
func (g *factoryInterfaceGenerator) Filter(c *generator.Context, t *types.Type) bool {
if !g.filtered {
g.filtered = true
return true
}
return false
}
func (g *factoryInterfaceGenerator) Namers(c *generator.Context) namer.NameSystems {
return namer.NameSystems{
"raw": namer.NewRawNamer(g.outputPackage, g.imports),
}
}
func (g *factoryInterfaceGenerator) Imports(c *generator.Context) (imports []string) {
imports = append(imports, g.imports.ImportLines()...)
return
}
func (g *factoryInterfaceGenerator) GenerateType(c *generator.Context, t *types.Type, w io.Writer) error {
sw := generator.NewSnippetWriter(w, c, "{{", "}}")
glog.V(5).Infof("processing type %v", t)
m := map[string]interface{}{
"cacheSharedIndexInformer": c.Universe.Type(cacheSharedIndexInformer),
"clientSetPackage": c.Universe.Type(types.Name{Package: g.clientSetPackage, Name: "Interface"}),
"runtimeObject": c.Universe.Type(runtimeObject),
"timeDuration": c.Universe.Type(timeDuration),
"v1ListOptions": c.Universe.Type(v1ListOptions),
}
sw.Do(externalSharedInformerFactoryInterface, m)
return sw.Error()
}
var externalSharedInformerFactoryInterface = `
type NewInformerFunc func({{.clientSetPackage|raw}}, {{.timeDuration|raw}}) cache.SharedIndexInformer
// SharedInformerFactory a small interface to allow for adding an informer without an import cycle
type SharedInformerFactory interface {
Start(stopCh <-chan struct{})
InformerFor(obj {{.runtimeObject|raw}}, newFunc NewInformerFunc) {{.cacheSharedIndexInformer|raw}}
}
type TweakListOptionsFunc func(*{{.v1ListOptions|raw}})
`

View File

@ -1,180 +0,0 @@
/*
Copyright 2016 The Kubernetes 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 generators
import (
"io"
"sort"
"strings"
clientgentypes "k8s.io/code-generator/cmd/client-gen/types"
"k8s.io/gengo/generator"
"k8s.io/gengo/namer"
"k8s.io/gengo/types"
)
// genericGenerator generates the generic informer.
type genericGenerator struct {
generator.DefaultGen
outputPackage string
imports namer.ImportTracker
groupVersions map[string]clientgentypes.GroupVersions
groupGoNames map[string]string
typesForGroupVersion map[clientgentypes.GroupVersion][]*types.Type
filtered bool
}
var _ generator.Generator = &genericGenerator{}
func (g *genericGenerator) Filter(c *generator.Context, t *types.Type) bool {
if !g.filtered {
g.filtered = true
return true
}
return false
}
func (g *genericGenerator) Namers(c *generator.Context) namer.NameSystems {
pluralExceptions := map[string]string{
"Endpoints": "Endpoints",
}
return namer.NameSystems{
"raw": namer.NewRawNamer(g.outputPackage, g.imports),
"allLowercasePlural": namer.NewAllLowercasePluralNamer(pluralExceptions),
"publicPlural": namer.NewPublicPluralNamer(pluralExceptions),
}
}
func (g *genericGenerator) Imports(c *generator.Context) (imports []string) {
imports = append(imports, g.imports.ImportLines()...)
imports = append(imports, "fmt")
return
}
type group struct {
GroupGoName string
Name string
Versions []*version
}
type groupSort []group
func (g groupSort) Len() int { return len(g) }
func (g groupSort) Less(i, j int) bool { return strings.ToLower(g[i].Name) < strings.ToLower(g[j].Name) }
func (g groupSort) Swap(i, j int) { g[i], g[j] = g[j], g[i] }
type version struct {
Name string
GoName string
Resources []*types.Type
}
type versionSort []*version
func (v versionSort) Len() int { return len(v) }
func (v versionSort) Less(i, j int) bool {
return strings.ToLower(v[i].Name) < strings.ToLower(v[j].Name)
}
func (v versionSort) Swap(i, j int) { v[i], v[j] = v[j], v[i] }
func (g *genericGenerator) GenerateType(c *generator.Context, t *types.Type, w io.Writer) error {
sw := generator.NewSnippetWriter(w, c, "{{", "}}")
groups := []group{}
schemeGVs := make(map[*version]*types.Type)
orderer := namer.Orderer{Namer: namer.NewPrivateNamer(0)}
for groupPackageName, groupVersions := range g.groupVersions {
group := group{
GroupGoName: g.groupGoNames[groupPackageName],
Name: groupVersions.Group.NonEmpty(),
Versions: []*version{},
}
for _, v := range groupVersions.Versions {
gv := clientgentypes.GroupVersion{Group: groupVersions.Group, Version: v}
version := &version{
Name: v.NonEmpty(),
GoName: namer.IC(v.NonEmpty()),
Resources: orderer.OrderTypes(g.typesForGroupVersion[gv]),
}
schemeGVs[version] = c.Universe.Variable(types.Name{Package: g.typesForGroupVersion[gv][0].Name.Package, Name: "SchemeGroupVersion"})
group.Versions = append(group.Versions, version)
}
sort.Sort(versionSort(group.Versions))
groups = append(groups, group)
}
sort.Sort(groupSort(groups))
m := map[string]interface{}{
"cacheGenericLister": c.Universe.Type(cacheGenericLister),
"cacheNewGenericLister": c.Universe.Function(cacheNewGenericLister),
"cacheSharedIndexInformer": c.Universe.Type(cacheSharedIndexInformer),
"groups": groups,
"schemeGVs": schemeGVs,
"schemaGroupResource": c.Universe.Type(schemaGroupResource),
"schemaGroupVersionResource": c.Universe.Type(schemaGroupVersionResource),
}
sw.Do(genericInformer, m)
sw.Do(forResource, m)
return sw.Error()
}
var genericInformer = `
// GenericInformer is type of SharedIndexInformer which will locate and delegate to other
// sharedInformers based on type
type GenericInformer interface {
Informer() {{.cacheSharedIndexInformer|raw}}
Lister() {{.cacheGenericLister|raw}}
}
type genericInformer struct {
informer {{.cacheSharedIndexInformer|raw}}
resource {{.schemaGroupResource|raw}}
}
// Informer returns the SharedIndexInformer.
func (f *genericInformer) Informer() {{.cacheSharedIndexInformer|raw}} {
return f.informer
}
// Lister returns the GenericLister.
func (f *genericInformer) Lister() {{.cacheGenericLister|raw}} {
return {{.cacheNewGenericLister|raw}}(f.Informer().GetIndexer(), f.resource)
}
`
var forResource = `
// ForResource gives generic access to a shared informer of the matching type
// TODO extend this to unknown resources with a client pool
func (f *sharedInformerFactory) ForResource(resource {{.schemaGroupVersionResource|raw}}) (GenericInformer, error) {
switch resource {
{{range $group := .groups -}}{{$GroupGoName := .GroupGoName -}}
{{range $version := .Versions -}}
// Group={{$group.Name}}, Version={{.Name}}
{{range .Resources -}}
case {{index $.schemeGVs $version|raw}}.WithResource("{{.|allLowercasePlural}}"):
return &genericInformer{resource: resource.GroupResource(), informer: f.{{$GroupGoName}}().{{$version.GoName}}().{{.|publicPlural}}().Informer()}, nil
{{end}}
{{end}}
{{end -}}
}
return nil, fmt.Errorf("no informer found for %v", resource)
}
`

View File

@ -1,118 +0,0 @@
/*
Copyright 2016 The Kubernetes 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 generators
import (
"io"
"path/filepath"
"strings"
clientgentypes "k8s.io/code-generator/cmd/client-gen/types"
"k8s.io/gengo/generator"
"k8s.io/gengo/namer"
"k8s.io/gengo/types"
)
// groupInterfaceGenerator generates the per-group interface file.
type groupInterfaceGenerator struct {
generator.DefaultGen
outputPackage string
imports namer.ImportTracker
groupVersions clientgentypes.GroupVersions
filtered bool
internalInterfacesPackage string
}
var _ generator.Generator = &groupInterfaceGenerator{}
func (g *groupInterfaceGenerator) Filter(c *generator.Context, t *types.Type) bool {
if !g.filtered {
g.filtered = true
return true
}
return false
}
func (g *groupInterfaceGenerator) Namers(c *generator.Context) namer.NameSystems {
return namer.NameSystems{
"raw": namer.NewRawNamer(g.outputPackage, g.imports),
}
}
func (g *groupInterfaceGenerator) Imports(c *generator.Context) (imports []string) {
imports = append(imports, g.imports.ImportLines()...)
return
}
type versionData struct {
Name string
Interface *types.Type
New *types.Type
}
func (g *groupInterfaceGenerator) GenerateType(c *generator.Context, t *types.Type, w io.Writer) error {
sw := generator.NewSnippetWriter(w, c, "$", "$")
versions := make([]versionData, 0, len(g.groupVersions.Versions))
for _, version := range g.groupVersions.Versions {
gv := clientgentypes.GroupVersion{Group: g.groupVersions.Group, Version: version}
versionPackage := filepath.Join(g.outputPackage, strings.ToLower(gv.Version.NonEmpty()))
iface := c.Universe.Type(types.Name{Package: versionPackage, Name: "Interface"})
versions = append(versions, versionData{
Name: namer.IC(version.NonEmpty()),
Interface: iface,
New: c.Universe.Function(types.Name{Package: versionPackage, Name: "New"}),
})
}
m := map[string]interface{}{
"interfacesTweakListOptionsFunc": c.Universe.Type(types.Name{Package: g.internalInterfacesPackage, Name: "TweakListOptionsFunc"}),
"interfacesSharedInformerFactory": c.Universe.Type(types.Name{Package: g.internalInterfacesPackage, Name: "SharedInformerFactory"}),
"versions": versions,
}
sw.Do(groupTemplate, m)
return sw.Error()
}
var groupTemplate = `
// Interface provides access to each of this group's versions.
type Interface interface {
$range .versions -$
// $.Name$ provides access to shared informers for resources in $.Name$.
$.Name$() $.Interface|raw$
$end$
}
type group struct {
factory $.interfacesSharedInformerFactory|raw$
namespace string
tweakListOptions $.interfacesTweakListOptionsFunc|raw$
}
// New returns a new Interface.
func New(f $.interfacesSharedInformerFactory|raw$, namespace string, tweakListOptions $.interfacesTweakListOptionsFunc|raw$) Interface {
return &group{factory: f, namespace: namespace, tweakListOptions: tweakListOptions}
}
$range .versions$
// $.Name$ returns a new $.Interface|raw$.
func (g *group) $.Name$() $.Interface|raw$ {
return $.New|raw$(g.factory, g.namespace, g.tweakListOptions)
}
$end$
`

View File

@ -1,186 +0,0 @@
/*
Copyright 2016 The Kubernetes 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 generators
import (
"fmt"
"io"
"strings"
"k8s.io/gengo/generator"
"k8s.io/gengo/namer"
"k8s.io/gengo/types"
"k8s.io/code-generator/cmd/client-gen/generators/util"
clientgentypes "k8s.io/code-generator/cmd/client-gen/types"
"github.com/golang/glog"
)
// informerGenerator produces a file of listers for a given GroupVersion and
// type.
type informerGenerator struct {
generator.DefaultGen
outputPackage string
groupPkgName string
groupVersion clientgentypes.GroupVersion
groupGoName string
typeToGenerate *types.Type
imports namer.ImportTracker
clientSetPackage string
listersPackage string
internalInterfacesPackage string
}
var _ generator.Generator = &informerGenerator{}
func (g *informerGenerator) Filter(c *generator.Context, t *types.Type) bool {
return t == g.typeToGenerate
}
func (g *informerGenerator) Namers(c *generator.Context) namer.NameSystems {
return namer.NameSystems{
"raw": namer.NewRawNamer(g.outputPackage, g.imports),
}
}
func (g *informerGenerator) Imports(c *generator.Context) (imports []string) {
imports = append(imports, g.imports.ImportLines()...)
return
}
func (g *informerGenerator) GenerateType(c *generator.Context, t *types.Type, w io.Writer) error {
sw := generator.NewSnippetWriter(w, c, "$", "$")
glog.V(5).Infof("processing type %v", t)
listerPackage := fmt.Sprintf("%s/%s/%s", g.listersPackage, g.groupPkgName, strings.ToLower(g.groupVersion.Version.NonEmpty()))
clientSetInterface := c.Universe.Type(types.Name{Package: g.clientSetPackage, Name: "Interface"})
informerFor := "InformerFor"
tags, err := util.ParseClientGenTags(append(t.SecondClosestCommentLines, t.CommentLines...))
if err != nil {
return err
}
m := map[string]interface{}{
"apiScheme": c.Universe.Type(apiScheme),
"cacheIndexers": c.Universe.Type(cacheIndexers),
"cacheListWatch": c.Universe.Type(cacheListWatch),
"cacheMetaNamespaceIndexFunc": c.Universe.Function(cacheMetaNamespaceIndexFunc),
"cacheNamespaceIndex": c.Universe.Variable(cacheNamespaceIndex),
"cacheNewSharedIndexInformer": c.Universe.Function(cacheNewSharedIndexInformer),
"cacheSharedIndexInformer": c.Universe.Type(cacheSharedIndexInformer),
"clientSetInterface": clientSetInterface,
"group": namer.IC(g.groupGoName),
"informerFor": informerFor,
"interfacesTweakListOptionsFunc": c.Universe.Type(types.Name{Package: g.internalInterfacesPackage, Name: "TweakListOptionsFunc"}),
"interfacesSharedInformerFactory": c.Universe.Type(types.Name{Package: g.internalInterfacesPackage, Name: "SharedInformerFactory"}),
"listOptions": c.Universe.Type(listOptions),
"lister": c.Universe.Type(types.Name{Package: listerPackage, Name: t.Name.Name + "Lister"}),
"namespaceAll": c.Universe.Type(metav1NamespaceAll),
"namespaced": !tags.NonNamespaced,
"newLister": c.Universe.Function(types.Name{Package: listerPackage, Name: "New" + t.Name.Name + "Lister"}),
"runtimeObject": c.Universe.Type(runtimeObject),
"timeDuration": c.Universe.Type(timeDuration),
"type": t,
"v1ListOptions": c.Universe.Type(v1ListOptions),
"version": namer.IC(g.groupVersion.Version.String()),
"watchInterface": c.Universe.Type(watchInterface),
}
sw.Do(typeInformerInterface, m)
sw.Do(typeInformerStruct, m)
sw.Do(typeInformerPublicConstructor, m)
sw.Do(typeFilteredInformerPublicConstructor, m)
sw.Do(typeInformerConstructor, m)
sw.Do(typeInformerInformer, m)
sw.Do(typeInformerLister, m)
return sw.Error()
}
var typeInformerInterface = `
// $.type|public$Informer provides access to a shared informer and lister for
// $.type|publicPlural$.
type $.type|public$Informer interface {
Informer() $.cacheSharedIndexInformer|raw$
Lister() $.lister|raw$
}
`
var typeInformerStruct = `
type $.type|private$Informer struct {
factory $.interfacesSharedInformerFactory|raw$
tweakListOptions $.interfacesTweakListOptionsFunc|raw$
$if .namespaced$namespace string$end$
}
`
var typeInformerPublicConstructor = `
// New$.type|public$Informer constructs a new informer for $.type|public$ type.
// Always prefer using an informer factory to get a shared informer instead of getting an independent
// one. This reduces memory footprint and number of connections to the server.
func New$.type|public$Informer(client $.clientSetInterface|raw$$if .namespaced$, namespace string$end$, resyncPeriod $.timeDuration|raw$, indexers $.cacheIndexers|raw$) $.cacheSharedIndexInformer|raw$ {
return NewFiltered$.type|public$Informer(client$if .namespaced$, namespace$end$, resyncPeriod, indexers, nil)
}
`
var typeFilteredInformerPublicConstructor = `
// NewFiltered$.type|public$Informer constructs a new informer for $.type|public$ type.
// Always prefer using an informer factory to get a shared informer instead of getting an independent
// one. This reduces memory footprint and number of connections to the server.
func NewFiltered$.type|public$Informer(client $.clientSetInterface|raw$$if .namespaced$, namespace string$end$, resyncPeriod $.timeDuration|raw$, indexers $.cacheIndexers|raw$, tweakListOptions $.interfacesTweakListOptionsFunc|raw$) $.cacheSharedIndexInformer|raw$ {
return $.cacheNewSharedIndexInformer|raw$(
&$.cacheListWatch|raw${
ListFunc: func(options $.v1ListOptions|raw$) ($.runtimeObject|raw$, error) {
if tweakListOptions != nil {
tweakListOptions(&options)
}
return client.$.group$$.version$().$.type|publicPlural$($if .namespaced$namespace$end$).List(options)
},
WatchFunc: func(options $.v1ListOptions|raw$) ($.watchInterface|raw$, error) {
if tweakListOptions != nil {
tweakListOptions(&options)
}
return client.$.group$$.version$().$.type|publicPlural$($if .namespaced$namespace$end$).Watch(options)
},
},
&$.type|raw${},
resyncPeriod,
indexers,
)
}
`
var typeInformerConstructor = `
func (f *$.type|private$Informer) defaultInformer(client $.clientSetInterface|raw$, resyncPeriod $.timeDuration|raw$) $.cacheSharedIndexInformer|raw$ {
return NewFiltered$.type|public$Informer(client$if .namespaced$, f.namespace$end$, resyncPeriod, $.cacheIndexers|raw${$.cacheNamespaceIndex|raw$: $.cacheMetaNamespaceIndexFunc|raw$}, f.tweakListOptions)
}
`
var typeInformerInformer = `
func (f *$.type|private$Informer) Informer() $.cacheSharedIndexInformer|raw$ {
return f.factory.$.informerFor$(&$.type|raw${}, f.defaultInformer)
}
`
var typeInformerLister = `
func (f *$.type|private$Informer) Lister() $.lister|raw$ {
return $.newLister|raw$(f.Informer().GetIndexer())
}
`

View File

@ -1,358 +0,0 @@
/*
Copyright 2016 The Kubernetes 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 generators
import (
"fmt"
"path/filepath"
"strings"
"k8s.io/gengo/args"
"k8s.io/gengo/generator"
"k8s.io/gengo/namer"
"k8s.io/gengo/types"
"k8s.io/code-generator/cmd/client-gen/generators/util"
clientgentypes "k8s.io/code-generator/cmd/client-gen/types"
"github.com/golang/glog"
)
// NameSystems returns the name system used by the generators in this package.
func NameSystems() namer.NameSystems {
pluralExceptions := map[string]string{
"Endpoints": "Endpoints",
}
return namer.NameSystems{
"public": namer.NewPublicNamer(0),
"private": namer.NewPrivateNamer(0),
"raw": namer.NewRawNamer("", nil),
"publicPlural": namer.NewPublicPluralNamer(pluralExceptions),
"allLowercasePlural": namer.NewAllLowercasePluralNamer(pluralExceptions),
"lowercaseSingular": &lowercaseSingularNamer{},
}
}
// lowercaseSingularNamer implements Namer
type lowercaseSingularNamer struct{}
// Name returns t's name in all lowercase.
func (n *lowercaseSingularNamer) Name(t *types.Type) string {
return strings.ToLower(t.Name.Name)
}
// DefaultNameSystem returns the default name system for ordering the types to be
// processed by the generators in this package.
func DefaultNameSystem() string {
return "public"
}
// generatedBy returns information about the arguments used to invoke
// lister-gen.
func generatedBy() string {
return fmt.Sprintf("\n// This file was automatically generated by informer-gen\n\n")
}
// objectMetaForPackage returns the type of ObjectMeta used by package p.
func objectMetaForPackage(p *types.Package) (*types.Type, bool, error) {
generatingForPackage := false
for _, t := range p.Types {
if !util.MustParseClientGenTags(append(t.SecondClosestCommentLines, t.CommentLines...)).GenerateClient {
continue
}
generatingForPackage = true
for _, member := range t.Members {
if member.Name == "ObjectMeta" {
return member.Type, isInternal(member), nil
}
}
}
if generatingForPackage {
return nil, false, fmt.Errorf("unable to find ObjectMeta for any types in package %s", p.Path)
}
return nil, false, nil
}
// isInternal returns true if the tags for a member do not contain a json tag
func isInternal(m types.Member) bool {
return !strings.Contains(m.Tags, "json")
}
func packageForInternalInterfaces(base string) string {
return filepath.Join(base, "internalinterfaces")
}
func vendorless(p string) string {
if pos := strings.LastIndex(p, "/vendor/"); pos != -1 {
return p[pos+len("/vendor/"):]
}
return p
}
// Packages makes the client package definition.
func Packages(context *generator.Context, arguments *args.GeneratorArgs) generator.Packages {
boilerplate, err := arguments.LoadGoBoilerplate()
if err != nil {
glog.Fatalf("Failed loading boilerplate: %v", err)
}
boilerplate = append(boilerplate, []byte(generatedBy())...)
customArgs, ok := arguments.CustomArgs.(*CustomArgs)
if !ok {
glog.Fatalf("Wrong CustomArgs type: %T", arguments.CustomArgs)
}
internalVersionPackagePath := filepath.Join(arguments.OutputPackagePath)
externalVersionPackagePath := filepath.Join(arguments.OutputPackagePath)
if !customArgs.SingleDirectory {
internalVersionPackagePath = filepath.Join(arguments.OutputPackagePath, "internalversion")
externalVersionPackagePath = filepath.Join(arguments.OutputPackagePath, "externalversions")
}
var packageList generator.Packages
typesForGroupVersion := make(map[clientgentypes.GroupVersion][]*types.Type)
externalGroupVersions := make(map[string]clientgentypes.GroupVersions)
internalGroupVersions := make(map[string]clientgentypes.GroupVersions)
groupGoNames := make(map[string]string)
for _, inputDir := range arguments.InputDirs {
p := context.Universe.Package(vendorless(inputDir))
objectMeta, internal, err := objectMetaForPackage(p)
if err != nil {
glog.Fatal(err)
}
if objectMeta == nil {
// no types in this package had genclient
continue
}
var gv clientgentypes.GroupVersion
var targetGroupVersions map[string]clientgentypes.GroupVersions
if internal {
lastSlash := strings.LastIndex(p.Path, "/")
if lastSlash == -1 {
glog.Fatalf("error constructing internal group version for package %q", p.Path)
}
gv.Group = clientgentypes.Group(p.Path[lastSlash+1:])
targetGroupVersions = internalGroupVersions
} else {
parts := strings.Split(p.Path, "/")
gv.Group = clientgentypes.Group(parts[len(parts)-2])
gv.Version = clientgentypes.Version(parts[len(parts)-1])
targetGroupVersions = externalGroupVersions
}
groupPkgName := strings.ToLower(gv.Group.NonEmpty())
// If there's a comment of the form "// +groupName=somegroup" or
// "// +groupName=somegroup.foo.bar.io", use the first field (somegroup) as the name of the
// group when generating.
if override := types.ExtractCommentTags("+", p.Comments)["groupName"]; override != nil {
gv.Group = clientgentypes.Group(override[0])
}
// If there's a comment of the form "// +groupGoName=SomeUniqueShortName", use that as
// the Go group identifier in CamelCase. It defaults
groupGoNames[groupPkgName] = namer.IC(strings.Split(gv.Group.NonEmpty(), ".")[0])
if override := types.ExtractCommentTags("+", p.Comments)["groupGoName"]; override != nil {
groupGoNames[groupPkgName] = namer.IC(override[0])
}
var typesToGenerate []*types.Type
for _, t := range p.Types {
tags := util.MustParseClientGenTags(append(t.SecondClosestCommentLines, t.CommentLines...))
if !tags.GenerateClient || tags.NoVerbs || !tags.HasVerb("list") || !tags.HasVerb("watch") {
continue
}
typesToGenerate = append(typesToGenerate, t)
if _, ok := typesForGroupVersion[gv]; !ok {
typesForGroupVersion[gv] = []*types.Type{}
}
typesForGroupVersion[gv] = append(typesForGroupVersion[gv], t)
}
if len(typesToGenerate) == 0 {
continue
}
groupVersionsEntry, ok := targetGroupVersions[groupPkgName]
if !ok {
groupVersionsEntry = clientgentypes.GroupVersions{
PackageName: groupPkgName,
Group: gv.Group,
}
}
groupVersionsEntry.Versions = append(groupVersionsEntry.Versions, gv.Version)
targetGroupVersions[groupPkgName] = groupVersionsEntry
orderer := namer.Orderer{Namer: namer.NewPrivateNamer(0)}
typesToGenerate = orderer.OrderTypes(typesToGenerate)
if internal {
packageList = append(packageList, versionPackage(internalVersionPackagePath, groupPkgName, gv, groupGoNames[groupPkgName], boilerplate, typesToGenerate, customArgs.InternalClientSetPackage, customArgs.ListersPackage))
} else {
packageList = append(packageList, versionPackage(externalVersionPackagePath, groupPkgName, gv, groupGoNames[groupPkgName], boilerplate, typesToGenerate, customArgs.VersionedClientSetPackage, customArgs.ListersPackage))
}
}
if len(externalGroupVersions) != 0 {
packageList = append(packageList, factoryInterfacePackage(externalVersionPackagePath, boilerplate, customArgs.VersionedClientSetPackage))
packageList = append(packageList, factoryPackage(externalVersionPackagePath, boilerplate, groupGoNames, externalGroupVersions, customArgs.VersionedClientSetPackage, typesForGroupVersion))
for _, gvs := range externalGroupVersions {
packageList = append(packageList, groupPackage(externalVersionPackagePath, gvs, boilerplate))
}
}
if len(internalGroupVersions) != 0 {
packageList = append(packageList, factoryInterfacePackage(internalVersionPackagePath, boilerplate, customArgs.InternalClientSetPackage))
packageList = append(packageList, factoryPackage(internalVersionPackagePath, boilerplate, groupGoNames, internalGroupVersions, customArgs.InternalClientSetPackage, typesForGroupVersion))
for _, gvs := range internalGroupVersions {
packageList = append(packageList, groupPackage(internalVersionPackagePath, gvs, boilerplate))
}
}
return packageList
}
func factoryPackage(basePackage string, boilerplate []byte, groupGoNames map[string]string, groupVersions map[string]clientgentypes.GroupVersions, clientSetPackage string, typesForGroupVersion map[clientgentypes.GroupVersion][]*types.Type) generator.Package {
return &generator.DefaultPackage{
PackageName: filepath.Base(basePackage),
PackagePath: basePackage,
HeaderText: boilerplate,
GeneratorFunc: func(c *generator.Context) (generators []generator.Generator) {
generators = append(generators, &factoryGenerator{
DefaultGen: generator.DefaultGen{
OptionalName: "factory",
},
outputPackage: basePackage,
imports: generator.NewImportTracker(),
groupVersions: groupVersions,
clientSetPackage: clientSetPackage,
internalInterfacesPackage: packageForInternalInterfaces(basePackage),
gvGoNames: groupGoNames,
})
generators = append(generators, &genericGenerator{
DefaultGen: generator.DefaultGen{
OptionalName: "generic",
},
outputPackage: basePackage,
imports: generator.NewImportTracker(),
groupVersions: groupVersions,
typesForGroupVersion: typesForGroupVersion,
groupGoNames: groupGoNames,
})
return generators
},
}
}
func factoryInterfacePackage(basePackage string, boilerplate []byte, clientSetPackage string) generator.Package {
packagePath := packageForInternalInterfaces(basePackage)
return &generator.DefaultPackage{
PackageName: filepath.Base(packagePath),
PackagePath: packagePath,
HeaderText: boilerplate,
GeneratorFunc: func(c *generator.Context) (generators []generator.Generator) {
generators = append(generators, &factoryInterfaceGenerator{
DefaultGen: generator.DefaultGen{
OptionalName: "factory_interfaces",
},
outputPackage: packagePath,
imports: generator.NewImportTracker(),
clientSetPackage: clientSetPackage,
})
return generators
},
}
}
func groupPackage(basePackage string, groupVersions clientgentypes.GroupVersions, boilerplate []byte) generator.Package {
packagePath := filepath.Join(basePackage, groupVersions.PackageName)
groupPkgName := strings.Split(string(groupVersions.Group), ".")[0]
return &generator.DefaultPackage{
PackageName: groupPkgName,
PackagePath: packagePath,
HeaderText: boilerplate,
GeneratorFunc: func(c *generator.Context) (generators []generator.Generator) {
generators = append(generators, &groupInterfaceGenerator{
DefaultGen: generator.DefaultGen{
OptionalName: "interface",
},
outputPackage: packagePath,
groupVersions: groupVersions,
imports: generator.NewImportTracker(),
internalInterfacesPackage: packageForInternalInterfaces(basePackage),
})
return generators
},
FilterFunc: func(c *generator.Context, t *types.Type) bool {
tags := util.MustParseClientGenTags(append(t.SecondClosestCommentLines, t.CommentLines...))
return tags.GenerateClient && tags.HasVerb("list") && tags.HasVerb("watch")
},
}
}
func versionPackage(basePackage string, groupPkgName string, gv clientgentypes.GroupVersion, groupGoName string, boilerplate []byte, typesToGenerate []*types.Type, clientSetPackage, listersPackage string) generator.Package {
packagePath := filepath.Join(basePackage, groupPkgName, strings.ToLower(gv.Version.NonEmpty()))
return &generator.DefaultPackage{
PackageName: strings.ToLower(gv.Version.NonEmpty()),
PackagePath: packagePath,
HeaderText: boilerplate,
GeneratorFunc: func(c *generator.Context) (generators []generator.Generator) {
generators = append(generators, &versionInterfaceGenerator{
DefaultGen: generator.DefaultGen{
OptionalName: "interface",
},
outputPackage: packagePath,
imports: generator.NewImportTracker(),
types: typesToGenerate,
internalInterfacesPackage: packageForInternalInterfaces(basePackage),
})
for _, t := range typesToGenerate {
generators = append(generators, &informerGenerator{
DefaultGen: generator.DefaultGen{
OptionalName: strings.ToLower(t.Name.Name),
},
outputPackage: packagePath,
groupPkgName: groupPkgName,
groupVersion: gv,
groupGoName: groupGoName,
typeToGenerate: t,
imports: generator.NewImportTracker(),
clientSetPackage: clientSetPackage,
listersPackage: listersPackage,
internalInterfacesPackage: packageForInternalInterfaces(basePackage),
})
}
return generators
},
FilterFunc: func(c *generator.Context, t *types.Type) bool {
tags := util.MustParseClientGenTags(append(t.SecondClosestCommentLines, t.CommentLines...))
return tags.GenerateClient && tags.HasVerb("list") && tags.HasVerb("watch")
},
}
}

View File

@ -1,33 +0,0 @@
/*
Copyright 2016 The Kubernetes 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 generators
import (
"github.com/golang/glog"
"k8s.io/gengo/types"
)
// extractBoolTagOrDie gets the comment-tags for the key and asserts that, if
// it exists, the value is boolean. If the tag did not exist, it returns
// false.
func extractBoolTagOrDie(key string, lines []string) bool {
val, err := types.ExtractSingleBoolCommentTag("+", key, false, lines)
if err != nil {
glog.Fatal(err)
}
return val
}

View File

@ -1,41 +0,0 @@
/*
Copyright 2016 The Kubernetes 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 generators
import "k8s.io/gengo/types"
var (
apiScheme = types.Name{Package: "k8s.io/kubernetes/pkg/api/legacyscheme", Name: "Scheme"}
cacheGenericLister = types.Name{Package: "k8s.io/client-go/tools/cache", Name: "GenericLister"}
cacheIndexers = types.Name{Package: "k8s.io/client-go/tools/cache", Name: "Indexers"}
cacheListWatch = types.Name{Package: "k8s.io/client-go/tools/cache", Name: "ListWatch"}
cacheMetaNamespaceIndexFunc = types.Name{Package: "k8s.io/client-go/tools/cache", Name: "MetaNamespaceIndexFunc"}
cacheNamespaceIndex = types.Name{Package: "k8s.io/client-go/tools/cache", Name: "NamespaceIndex"}
cacheNewGenericLister = types.Name{Package: "k8s.io/client-go/tools/cache", Name: "NewGenericLister"}
cacheNewSharedIndexInformer = types.Name{Package: "k8s.io/client-go/tools/cache", Name: "NewSharedIndexInformer"}
cacheSharedIndexInformer = types.Name{Package: "k8s.io/client-go/tools/cache", Name: "SharedIndexInformer"}
listOptions = types.Name{Package: "k8s.io/kubernetes/pkg/apis/core", Name: "ListOptions"}
reflectType = types.Name{Package: "reflect", Name: "Type"}
runtimeObject = types.Name{Package: "k8s.io/apimachinery/pkg/runtime", Name: "Object"}
schemaGroupResource = types.Name{Package: "k8s.io/apimachinery/pkg/runtime/schema", Name: "GroupResource"}
schemaGroupVersionResource = types.Name{Package: "k8s.io/apimachinery/pkg/runtime/schema", Name: "GroupVersionResource"}
syncMutex = types.Name{Package: "sync", Name: "Mutex"}
timeDuration = types.Name{Package: "time", Name: "Duration"}
v1ListOptions = types.Name{Package: "k8s.io/apimachinery/pkg/apis/meta/v1", Name: "ListOptions"}
metav1NamespaceAll = types.Name{Package: "k8s.io/apimachinery/pkg/apis/meta/v1", Name: "NamespaceAll"}
watchInterface = types.Name{Package: "k8s.io/apimachinery/pkg/watch", Name: "Interface"}
)

View File

@ -1,109 +0,0 @@
/*
Copyright 2016 The Kubernetes 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 generators
import (
"io"
"k8s.io/gengo/generator"
"k8s.io/gengo/namer"
"k8s.io/gengo/types"
"k8s.io/code-generator/cmd/client-gen/generators/util"
)
// versionInterfaceGenerator generates the per-version interface file.
type versionInterfaceGenerator struct {
generator.DefaultGen
outputPackage string
imports namer.ImportTracker
types []*types.Type
filtered bool
internalInterfacesPackage string
}
var _ generator.Generator = &versionInterfaceGenerator{}
func (g *versionInterfaceGenerator) Filter(c *generator.Context, t *types.Type) bool {
if !g.filtered {
g.filtered = true
return true
}
return false
}
func (g *versionInterfaceGenerator) Namers(c *generator.Context) namer.NameSystems {
return namer.NameSystems{
"raw": namer.NewRawNamer(g.outputPackage, g.imports),
}
}
func (g *versionInterfaceGenerator) Imports(c *generator.Context) (imports []string) {
imports = append(imports, g.imports.ImportLines()...)
return
}
func (g *versionInterfaceGenerator) GenerateType(c *generator.Context, t *types.Type, w io.Writer) error {
sw := generator.NewSnippetWriter(w, c, "$", "$")
m := map[string]interface{}{
"interfacesTweakListOptionsFunc": c.Universe.Type(types.Name{Package: g.internalInterfacesPackage, Name: "TweakListOptionsFunc"}),
"interfacesSharedInformerFactory": c.Universe.Type(types.Name{Package: g.internalInterfacesPackage, Name: "SharedInformerFactory"}),
"types": g.types,
}
sw.Do(versionTemplate, m)
for _, typeDef := range g.types {
tags, err := util.ParseClientGenTags(typeDef.SecondClosestCommentLines)
if err != nil {
return err
}
m["namespaced"] = !tags.NonNamespaced
m["type"] = typeDef
sw.Do(versionFuncTemplate, m)
}
return sw.Error()
}
var versionTemplate = `
// Interface provides access to all the informers in this group version.
type Interface interface {
$range .types -$
// $.|publicPlural$ returns a $.|public$Informer.
$.|publicPlural$() $.|public$Informer
$end$
}
type version struct {
factory $.interfacesSharedInformerFactory|raw$
namespace string
tweakListOptions $.interfacesTweakListOptionsFunc|raw$
}
// New returns a new Interface.
func New(f $.interfacesSharedInformerFactory|raw$, namespace string, tweakListOptions $.interfacesTweakListOptionsFunc|raw$) Interface {
return &version{factory: f, namespace: namespace, tweakListOptions: tweakListOptions}
}
`
var versionFuncTemplate = `
// $.type|publicPlural$ returns a $.type|public$Informer.
func (v *version) $.type|publicPlural$() $.type|public$Informer {
return &$.type|private$Informer{factory: v.factory$if .namespaced$, namespace: v.namespace$end$, tweakListOptions: v.tweakListOptions}
}
`

View File

@ -1,55 +0,0 @@
/*
Copyright 2016 The Kubernetes 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 main
import (
"path/filepath"
"k8s.io/code-generator/cmd/informer-gen/generators"
"k8s.io/gengo/args"
"github.com/golang/glog"
"github.com/spf13/pflag"
)
func main() {
arguments := args.Default()
// Custom arguments.
customArgs := &generators.CustomArgs{
VersionedClientSetPackage: "k8s.io/kubernetes/pkg/client/clientset_generated/clientset",
InternalClientSetPackage: "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset",
ListersPackage: "k8s.io/kubernetes/pkg/client/listers",
SingleDirectory: false,
}
customArgs.AddFlags(pflag.CommandLine)
// Override defaults.
arguments.GoHeaderFilePath = filepath.Join(args.DefaultSourceTree(), "k8s.io/kubernetes/hack/boilerplate/boilerplate.go.txt")
arguments.OutputPackagePath = "k8s.io/kubernetes/pkg/client/informers/informers_generated"
arguments.CustomArgs = customArgs
// Run it.
if err := arguments.Execute(
generators.NameSystems(),
generators.DefaultNameSystem(),
generators.Packages,
); err != nil {
glog.Fatalf("Error: %v", err)
}
glog.V(2).Info("Completed successfully.")
}

View File

@ -1,67 +0,0 @@
/*
Copyright 2016 The Kubernetes 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 generators
import (
"io"
"os"
"path/filepath"
"strings"
"k8s.io/gengo/generator"
"k8s.io/gengo/types"
"k8s.io/code-generator/cmd/client-gen/generators/util"
)
// expansionGenerator produces a file for a expansion interfaces.
type expansionGenerator struct {
generator.DefaultGen
packagePath string
types []*types.Type
}
// We only want to call GenerateType() once per group.
func (g *expansionGenerator) Filter(c *generator.Context, t *types.Type) bool {
return t == g.types[0]
}
func (g *expansionGenerator) GenerateType(c *generator.Context, t *types.Type, w io.Writer) error {
sw := generator.NewSnippetWriter(w, c, "$", "$")
for _, t := range g.types {
tags := util.MustParseClientGenTags(append(t.SecondClosestCommentLines, t.CommentLines...))
if _, err := os.Stat(filepath.Join(g.packagePath, strings.ToLower(t.Name.Name+"_expansion.go"))); os.IsNotExist(err) {
sw.Do(expansionInterfaceTemplate, t)
if !tags.NonNamespaced {
sw.Do(namespacedExpansionInterfaceTemplate, t)
}
}
}
return sw.Error()
}
var expansionInterfaceTemplate = `
// $.|public$ListerExpansion allows custom methods to be added to
// $.|public$Lister.
type $.|public$ListerExpansion interface {}
`
var namespacedExpansionInterfaceTemplate = `
// $.|public$NamespaceListerExpansion allows custom methods to be added to
// $.|public$NamespaceLister.
type $.|public$NamespaceListerExpansion interface {}
`

View File

@ -1,379 +0,0 @@
/*
Copyright 2016 The Kubernetes 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 generators
import (
"fmt"
"io"
"path/filepath"
"strings"
"k8s.io/gengo/args"
"k8s.io/gengo/generator"
"k8s.io/gengo/namer"
"k8s.io/gengo/types"
"k8s.io/code-generator/cmd/client-gen/generators/util"
clientgentypes "k8s.io/code-generator/cmd/client-gen/types"
"github.com/golang/glog"
)
// NameSystems returns the name system used by the generators in this package.
func NameSystems() namer.NameSystems {
pluralExceptions := map[string]string{
"Endpoints": "Endpoints",
}
return namer.NameSystems{
"public": namer.NewPublicNamer(0),
"private": namer.NewPrivateNamer(0),
"raw": namer.NewRawNamer("", nil),
"publicPlural": namer.NewPublicPluralNamer(pluralExceptions),
"allLowercasePlural": namer.NewAllLowercasePluralNamer(pluralExceptions),
"lowercaseSingular": &lowercaseSingularNamer{},
}
}
// lowercaseSingularNamer implements Namer
type lowercaseSingularNamer struct{}
// Name returns t's name in all lowercase.
func (n *lowercaseSingularNamer) Name(t *types.Type) string {
return strings.ToLower(t.Name.Name)
}
// DefaultNameSystem returns the default name system for ordering the types to be
// processed by the generators in this package.
func DefaultNameSystem() string {
return "public"
}
// generatedBy returns information about the arguments used to invoke
// lister-gen.
func generatedBy() string {
return fmt.Sprintf("\n// This file was automatically generated by lister-gen\n\n")
}
// Packages makes the client package definition.
func Packages(context *generator.Context, arguments *args.GeneratorArgs) generator.Packages {
boilerplate, err := arguments.LoadGoBoilerplate()
if err != nil {
glog.Fatalf("Failed loading boilerplate: %v", err)
}
boilerplate = append(boilerplate, []byte(generatedBy())...)
var packageList generator.Packages
for _, inputDir := range arguments.InputDirs {
p := context.Universe.Package(inputDir)
objectMeta, internal, err := objectMetaForPackage(p)
if err != nil {
glog.Fatal(err)
}
if objectMeta == nil {
// no types in this package had genclient
continue
}
var gv clientgentypes.GroupVersion
var internalGVPkg string
if internal {
lastSlash := strings.LastIndex(p.Path, "/")
if lastSlash == -1 {
glog.Fatalf("error constructing internal group version for package %q", p.Path)
}
gv.Group = clientgentypes.Group(p.Path[lastSlash+1:])
internalGVPkg = p.Path
} else {
parts := strings.Split(p.Path, "/")
gv.Group = clientgentypes.Group(parts[len(parts)-2])
gv.Version = clientgentypes.Version(parts[len(parts)-1])
internalGVPkg = strings.Join(parts[0:len(parts)-1], "/")
}
groupPackageName := strings.ToLower(gv.Group.NonEmpty())
// If there's a comment of the form "// +groupName=somegroup" or
// "// +groupName=somegroup.foo.bar.io", use the first field (somegroup) as the name of the
// group when generating.
if override := types.ExtractCommentTags("+", p.Comments)["groupName"]; override != nil {
gv.Group = clientgentypes.Group(strings.SplitN(override[0], ".", 2)[0])
}
var typesToGenerate []*types.Type
for _, t := range p.Types {
tags := util.MustParseClientGenTags(append(t.SecondClosestCommentLines, t.CommentLines...))
if !tags.GenerateClient || !tags.HasVerb("list") || !tags.HasVerb("get") {
continue
}
typesToGenerate = append(typesToGenerate, t)
}
if len(typesToGenerate) == 0 {
continue
}
orderer := namer.Orderer{Namer: namer.NewPrivateNamer(0)}
typesToGenerate = orderer.OrderTypes(typesToGenerate)
packagePath := filepath.Join(arguments.OutputPackagePath, groupPackageName, strings.ToLower(gv.Version.NonEmpty()))
packageList = append(packageList, &generator.DefaultPackage{
PackageName: strings.ToLower(gv.Version.NonEmpty()),
PackagePath: packagePath,
HeaderText: boilerplate,
GeneratorFunc: func(c *generator.Context) (generators []generator.Generator) {
generators = append(generators, &expansionGenerator{
DefaultGen: generator.DefaultGen{
OptionalName: "expansion_generated",
},
packagePath: filepath.Join(arguments.OutputBase, packagePath),
types: typesToGenerate,
})
for _, t := range typesToGenerate {
generators = append(generators, &listerGenerator{
DefaultGen: generator.DefaultGen{
OptionalName: strings.ToLower(t.Name.Name),
},
outputPackage: arguments.OutputPackagePath,
groupVersion: gv,
internalGVPkg: internalGVPkg,
typeToGenerate: t,
imports: generator.NewImportTracker(),
objectMeta: objectMeta,
})
}
return generators
},
FilterFunc: func(c *generator.Context, t *types.Type) bool {
tags := util.MustParseClientGenTags(append(t.SecondClosestCommentLines, t.CommentLines...))
return tags.GenerateClient && tags.HasVerb("list") && tags.HasVerb("get")
},
})
}
return packageList
}
// objectMetaForPackage returns the type of ObjectMeta used by package p.
func objectMetaForPackage(p *types.Package) (*types.Type, bool, error) {
generatingForPackage := false
for _, t := range p.Types {
// filter out types which dont have genclient.
if !util.MustParseClientGenTags(append(t.SecondClosestCommentLines, t.CommentLines...)).GenerateClient {
continue
}
generatingForPackage = true
for _, member := range t.Members {
if member.Name == "ObjectMeta" {
return member.Type, isInternal(member), nil
}
}
}
if generatingForPackage {
return nil, false, fmt.Errorf("unable to find ObjectMeta for any types in package %s", p.Path)
}
return nil, false, nil
}
// isInternal returns true if the tags for a member do not contain a json tag
func isInternal(m types.Member) bool {
return !strings.Contains(m.Tags, "json")
}
// listerGenerator produces a file of listers for a given GroupVersion and
// type.
type listerGenerator struct {
generator.DefaultGen
outputPackage string
groupVersion clientgentypes.GroupVersion
internalGVPkg string
typeToGenerate *types.Type
imports namer.ImportTracker
objectMeta *types.Type
}
var _ generator.Generator = &listerGenerator{}
func (g *listerGenerator) Filter(c *generator.Context, t *types.Type) bool {
return t == g.typeToGenerate
}
func (g *listerGenerator) Namers(c *generator.Context) namer.NameSystems {
return namer.NameSystems{
"raw": namer.NewRawNamer(g.outputPackage, g.imports),
}
}
func (g *listerGenerator) Imports(c *generator.Context) (imports []string) {
imports = append(imports, g.imports.ImportLines()...)
imports = append(imports, "k8s.io/apimachinery/pkg/api/errors")
imports = append(imports, "k8s.io/apimachinery/pkg/labels")
// for Indexer
imports = append(imports, "k8s.io/client-go/tools/cache")
return
}
func (g *listerGenerator) GenerateType(c *generator.Context, t *types.Type, w io.Writer) error {
sw := generator.NewSnippetWriter(w, c, "$", "$")
glog.V(5).Infof("processing type %v", t)
m := map[string]interface{}{
"Resource": c.Universe.Function(types.Name{Package: t.Name.Package, Name: "Resource"}),
"type": t,
"objectMeta": g.objectMeta,
}
tags, err := util.ParseClientGenTags(append(t.SecondClosestCommentLines, t.CommentLines...))
if err != nil {
return err
}
if tags.NonNamespaced {
sw.Do(typeListerInterface_NonNamespaced, m)
} else {
sw.Do(typeListerInterface, m)
}
sw.Do(typeListerStruct, m)
sw.Do(typeListerConstructor, m)
sw.Do(typeLister_List, m)
if tags.NonNamespaced {
sw.Do(typeLister_NonNamespacedGet, m)
return sw.Error()
}
sw.Do(typeLister_NamespaceLister, m)
sw.Do(namespaceListerInterface, m)
sw.Do(namespaceListerStruct, m)
sw.Do(namespaceLister_List, m)
sw.Do(namespaceLister_Get, m)
return sw.Error()
}
var typeListerInterface = `
// $.type|public$Lister helps list $.type|publicPlural$.
type $.type|public$Lister interface {
// List lists all $.type|publicPlural$ in the indexer.
List(selector labels.Selector) (ret []*$.type|raw$, err error)
// $.type|publicPlural$ returns an object that can list and get $.type|publicPlural$.
$.type|publicPlural$(namespace string) $.type|public$NamespaceLister
$.type|public$ListerExpansion
}
`
var typeListerInterface_NonNamespaced = `
// $.type|public$Lister helps list $.type|publicPlural$.
type $.type|public$Lister interface {
// List lists all $.type|publicPlural$ in the indexer.
List(selector labels.Selector) (ret []*$.type|raw$, err error)
// Get retrieves the $.type|public$ from the index for a given name.
Get(name string) (*$.type|raw$, error)
$.type|public$ListerExpansion
}
`
var typeListerStruct = `
// $.type|private$Lister implements the $.type|public$Lister interface.
type $.type|private$Lister struct {
indexer cache.Indexer
}
`
var typeListerConstructor = `
// New$.type|public$Lister returns a new $.type|public$Lister.
func New$.type|public$Lister(indexer cache.Indexer) $.type|public$Lister {
return &$.type|private$Lister{indexer: indexer}
}
`
var typeLister_List = `
// List lists all $.type|publicPlural$ in the indexer.
func (s *$.type|private$Lister) List(selector labels.Selector) (ret []*$.type|raw$, err error) {
err = cache.ListAll(s.indexer, selector, func(m interface{}) {
ret = append(ret, m.(*$.type|raw$))
})
return ret, err
}
`
var typeLister_NamespaceLister = `
// $.type|publicPlural$ returns an object that can list and get $.type|publicPlural$.
func (s *$.type|private$Lister) $.type|publicPlural$(namespace string) $.type|public$NamespaceLister {
return $.type|private$NamespaceLister{indexer: s.indexer, namespace: namespace}
}
`
var typeLister_NonNamespacedGet = `
// Get retrieves the $.type|public$ from the index for a given name.
func (s *$.type|private$Lister) Get(name string) (*$.type|raw$, error) {
obj, exists, err := s.indexer.GetByKey(name)
if err != nil {
return nil, err
}
if !exists {
return nil, errors.NewNotFound($.Resource|raw$("$.type|lowercaseSingular$"), name)
}
return obj.(*$.type|raw$), nil
}
`
var namespaceListerInterface = `
// $.type|public$NamespaceLister helps list and get $.type|publicPlural$.
type $.type|public$NamespaceLister interface {
// List lists all $.type|publicPlural$ in the indexer for a given namespace.
List(selector labels.Selector) (ret []*$.type|raw$, err error)
// Get retrieves the $.type|public$ from the indexer for a given namespace and name.
Get(name string) (*$.type|raw$, error)
$.type|public$NamespaceListerExpansion
}
`
var namespaceListerStruct = `
// $.type|private$NamespaceLister implements the $.type|public$NamespaceLister
// interface.
type $.type|private$NamespaceLister struct {
indexer cache.Indexer
namespace string
}
`
var namespaceLister_List = `
// List lists all $.type|publicPlural$ in the indexer for a given namespace.
func (s $.type|private$NamespaceLister) List(selector labels.Selector) (ret []*$.type|raw$, err error) {
err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) {
ret = append(ret, m.(*$.type|raw$))
})
return ret, err
}
`
var namespaceLister_Get = `
// Get retrieves the $.type|public$ from the indexer for a given namespace and name.
func (s $.type|private$NamespaceLister) Get(name string) (*$.type|raw$, error) {
obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name)
if err != nil {
return nil, err
}
if !exists {
return nil, errors.NewNotFound($.Resource|raw$("$.type|lowercaseSingular$"), name)
}
return obj.(*$.type|raw$), nil
}
`

View File

@ -1,33 +0,0 @@
/*
Copyright 2016 The Kubernetes 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 generators
import (
"github.com/golang/glog"
"k8s.io/gengo/types"
)
// extractBoolTagOrDie gets the comment-tags for the key and asserts that, if
// it exists, the value is boolean. If the tag did not exist, it returns
// false.
func extractBoolTagOrDie(key string, lines []string) bool {
val, err := types.ExtractSingleBoolCommentTag("+", key, false, lines)
if err != nil {
glog.Fatal(err)
}
return val
}

View File

@ -1,44 +0,0 @@
/*
Copyright 2016 The Kubernetes 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 main
import (
"path/filepath"
"k8s.io/code-generator/cmd/lister-gen/generators"
"k8s.io/gengo/args"
"github.com/golang/glog"
)
func main() {
arguments := args.Default()
// Override defaults.
arguments.GoHeaderFilePath = filepath.Join(args.DefaultSourceTree(), "k8s.io/kubernetes/hack/boilerplate/boilerplate.go.txt")
arguments.OutputPackagePath = "k8s.io/kubernetes/pkg/client/listers"
// Run it.
if err := arguments.Execute(
generators.NameSystems(),
generators.DefaultNameSystem(),
generators.Packages,
); err != nil {
glog.Fatalf("Error: %v", err)
}
glog.V(2).Info("Completed successfully.")
}

202
vendor/k8s.io/gengo/LICENSE generated vendored
View File

@ -1,202 +0,0 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright 2014 The Kubernetes 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.

182
vendor/k8s.io/gengo/args/args.go generated vendored
View File

@ -1,182 +0,0 @@
/*
Copyright 2015 The Kubernetes 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 args has common command-line flags for generation programs.
package args
import (
"bytes"
goflag "flag"
"fmt"
"io/ioutil"
"os"
"path/filepath"
"strconv"
"strings"
"time"
"k8s.io/gengo/generator"
"k8s.io/gengo/namer"
"k8s.io/gengo/parser"
"k8s.io/gengo/types"
"github.com/spf13/pflag"
)
// Default returns a defaulted GeneratorArgs. You may change the defaults
// before calling AddFlags.
func Default() *GeneratorArgs {
return &GeneratorArgs{
OutputBase: DefaultSourceTree(),
GoHeaderFilePath: filepath.Join(DefaultSourceTree(), "k8s.io/gengo/boilerplate/boilerplate.go.txt"),
GeneratedBuildTag: "ignore_autogenerated",
defaultCommandLineFlags: true,
}
}
// GeneratorArgs has arguments that are passed to generators.
type GeneratorArgs struct {
// Which directories to parse.
InputDirs []string
// Source tree to write results to.
OutputBase string
// Package path within the source tree.
OutputPackagePath string
// Output file name.
OutputFileBaseName string
// Where to get copyright header text.
GoHeaderFilePath string
// If true, only verify, don't write anything.
VerifyOnly bool
// GeneratedBuildTag is the tag used to identify code generated by execution
// of this type. Each generator should use a different tag, and different
// groups of generators (external API that depends on Kube generations) should
// keep tags distinct as well.
GeneratedBuildTag string
// Any custom arguments go here
CustomArgs interface{}
// Whether to use default command line flags
defaultCommandLineFlags bool
}
// WithoutDefaultFlagParsing disables implicit addition of command line flags and parsing.
func (g *GeneratorArgs) WithoutDefaultFlagParsing() *GeneratorArgs {
g.defaultCommandLineFlags = false
return g
}
func (g *GeneratorArgs) AddFlags(fs *pflag.FlagSet) {
fs.StringSliceVarP(&g.InputDirs, "input-dirs", "i", g.InputDirs, "Comma-separated list of import paths to get input types from.")
fs.StringVarP(&g.OutputBase, "output-base", "o", g.OutputBase, "Output base; defaults to $GOPATH/src/ or ./ if $GOPATH is not set.")
fs.StringVarP(&g.OutputPackagePath, "output-package", "p", g.OutputPackagePath, "Base package path.")
fs.StringVarP(&g.OutputFileBaseName, "output-file-base", "O", g.OutputFileBaseName, "Base name (without .go suffix) for output files.")
fs.StringVarP(&g.GoHeaderFilePath, "go-header-file", "h", g.GoHeaderFilePath, "File containing boilerplate header text. The string YEAR will be replaced with the current 4-digit year.")
fs.BoolVar(&g.VerifyOnly, "verify-only", g.VerifyOnly, "If true, only verify existing output, do not write anything.")
fs.StringVar(&g.GeneratedBuildTag, "build-tag", g.GeneratedBuildTag, "A Go build tag to use to identify files generated by this command. Should be unique.")
}
// LoadGoBoilerplate loads the boilerplate file passed to --go-header-file.
func (g *GeneratorArgs) LoadGoBoilerplate() ([]byte, error) {
b, err := ioutil.ReadFile(g.GoHeaderFilePath)
if err != nil {
return nil, err
}
b = bytes.Replace(b, []byte("YEAR"), []byte(strconv.Itoa(time.Now().Year())), -1)
return b, nil
}
// NewBuilder makes a new parser.Builder and populates it with the input
// directories.
func (g *GeneratorArgs) NewBuilder() (*parser.Builder, error) {
b := parser.New()
// Ignore all auto-generated files.
b.AddBuildTags(g.GeneratedBuildTag)
for _, d := range g.InputDirs {
var err error
if strings.HasSuffix(d, "/...") {
err = b.AddDirRecursive(strings.TrimSuffix(d, "/..."))
} else {
err = b.AddDir(d)
}
if err != nil {
return nil, fmt.Errorf("unable to add directory %q: %v", d, err)
}
}
return b, nil
}
// InputIncludes returns true if the given package is a (sub) package of one of
// the InputDirs.
func (g *GeneratorArgs) InputIncludes(p *types.Package) bool {
for _, dir := range g.InputDirs {
d := dir
if strings.HasSuffix(d, "...") {
d = strings.TrimSuffix(d, "...")
}
if strings.HasPrefix(p.Path, d) {
return true
}
}
return false
}
// DefaultSourceTree returns the /src directory of the first entry in $GOPATH.
// If $GOPATH is empty, it returns "./". Useful as a default output location.
func DefaultSourceTree() string {
paths := strings.Split(os.Getenv("GOPATH"), string(filepath.ListSeparator))
if len(paths) > 0 && len(paths[0]) > 0 {
return filepath.Join(paths[0], "src")
}
return "./"
}
// Execute implements main().
// If you don't need any non-default behavior, use as:
// args.Default().Execute(...)
func (g *GeneratorArgs) Execute(nameSystems namer.NameSystems, defaultSystem string, pkgs func(*generator.Context, *GeneratorArgs) generator.Packages) error {
if g.defaultCommandLineFlags {
g.AddFlags(pflag.CommandLine)
pflag.CommandLine.AddGoFlagSet(goflag.CommandLine)
pflag.Parse()
}
b, err := g.NewBuilder()
if err != nil {
return fmt.Errorf("Failed making a parser: %v", err)
}
c, err := generator.NewContext(b, nameSystems, defaultSystem)
if err != nil {
return fmt.Errorf("Failed making a context: %v", err)
}
c.Verify = g.VerifyOnly
packages := pkgs(c, g)
if err := c.ExecutePackages(g.OutputBase, packages); err != nil {
return fmt.Errorf("Failed executing generator: %v", err)
}
return nil
}

View File

@ -1,771 +0,0 @@
/*
Copyright 2015 The Kubernetes 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 generators
import (
"fmt"
"io"
"path/filepath"
"sort"
"strings"
"k8s.io/gengo/args"
"k8s.io/gengo/examples/set-gen/sets"
"k8s.io/gengo/generator"
"k8s.io/gengo/namer"
"k8s.io/gengo/types"
"github.com/golang/glog"
)
// CustomArgs is used tby the go2idl framework to pass args specific to this
// generator.
type CustomArgs struct {
BoundingDirs []string // Only deal with types rooted under these dirs.
}
// This is the comment tag that carries parameters for deep-copy generation.
const (
tagName = "k8s:deepcopy-gen"
interfacesTagName = tagName + ":interfaces"
interfacesNonPointerTagName = tagName + ":nonpointer-interfaces" // attach the DeepCopy<Interface> methods to the
)
// Known values for the comment tag.
const tagValuePackage = "package"
// tagValue holds parameters from a tagName tag.
type tagValue struct {
value string
register bool
}
func extractTag(comments []string) *tagValue {
tagVals := types.ExtractCommentTags("+", comments)[tagName]
if tagVals == nil {
// No match for the tag.
return nil
}
// If there are multiple values, abort.
if len(tagVals) > 1 {
glog.Fatalf("Found %d %s tags: %q", len(tagVals), tagName, tagVals)
}
// If we got here we are returning something.
tag := &tagValue{}
// Get the primary value.
parts := strings.Split(tagVals[0], ",")
if len(parts) >= 1 {
tag.value = parts[0]
}
// Parse extra arguments.
parts = parts[1:]
for i := range parts {
kv := strings.SplitN(parts[i], "=", 2)
k := kv[0]
v := ""
if len(kv) == 2 {
v = kv[1]
}
switch k {
case "register":
if v != "false" {
tag.register = true
}
default:
glog.Fatalf("Unsupported %s param: %q", tagName, parts[i])
}
}
return tag
}
// TODO: This is created only to reduce number of changes in a single PR.
// Remove it and use PublicNamer instead.
func deepCopyNamer() *namer.NameStrategy {
return &namer.NameStrategy{
Join: func(pre string, in []string, post string) string {
return strings.Join(in, "_")
},
PrependPackageNames: 1,
}
}
// NameSystems returns the name system used by the generators in this package.
func NameSystems() namer.NameSystems {
return namer.NameSystems{
"public": deepCopyNamer(),
"raw": namer.NewRawNamer("", nil),
}
}
// DefaultNameSystem returns the default name system for ordering the types to be
// processed by the generators in this package.
func DefaultNameSystem() string {
return "public"
}
func Packages(context *generator.Context, arguments *args.GeneratorArgs) generator.Packages {
boilerplate, err := arguments.LoadGoBoilerplate()
if err != nil {
glog.Fatalf("Failed loading boilerplate: %v", err)
}
inputs := sets.NewString(context.Inputs...)
packages := generator.Packages{}
header := append([]byte(fmt.Sprintf("// +build !%s\n\n", arguments.GeneratedBuildTag)), boilerplate...)
header = append(header, []byte(`
// This file was autogenerated by deepcopy-gen. Do not edit it manually!
`)...)
boundingDirs := []string{}
if customArgs, ok := arguments.CustomArgs.(*CustomArgs); ok {
if customArgs.BoundingDirs == nil {
customArgs.BoundingDirs = context.Inputs
}
for i := range customArgs.BoundingDirs {
// Strip any trailing slashes - they are not exactly "correct" but
// this is friendlier.
boundingDirs = append(boundingDirs, strings.TrimRight(customArgs.BoundingDirs[i], "/"))
}
}
for i := range inputs {
glog.V(5).Infof("Considering pkg %q", i)
pkg := context.Universe[i]
if pkg == nil {
// If the input had no Go files, for example.
continue
}
ptag := extractTag(pkg.Comments)
ptagValue := ""
ptagRegister := false
if ptag != nil {
ptagValue = ptag.value
if ptagValue != tagValuePackage {
glog.Fatalf("Package %v: unsupported %s value: %q", i, tagName, ptagValue)
}
ptagRegister = ptag.register
glog.V(5).Infof(" tag.value: %q, tag.register: %t", ptagValue, ptagRegister)
} else {
glog.V(5).Infof(" no tag")
}
// If the pkg-scoped tag says to generate, we can skip scanning types.
pkgNeedsGeneration := (ptagValue == tagValuePackage)
if !pkgNeedsGeneration {
// If the pkg-scoped tag did not exist, scan all types for one that
// explicitly wants generation.
for _, t := range pkg.Types {
glog.V(5).Infof(" considering type %q", t.Name.String())
ttag := extractTag(t.CommentLines)
if ttag != nil && ttag.value == "true" {
glog.V(5).Infof(" tag=true")
if !copyableType(t) {
glog.Fatalf("Type %v requests deepcopy generation but is not copyable", t)
}
pkgNeedsGeneration = true
break
}
}
}
if pkgNeedsGeneration {
glog.V(3).Infof("Package %q needs generation", i)
path := pkg.Path
// if the source path is within a /vendor/ directory (for example,
// k8s.io/kubernetes/vendor/k8s.io/apimachinery/pkg/apis/meta/v1), allow
// generation to output to the proper relative path (under vendor).
// Otherwise, the generator will create the file in the wrong location
// in the output directory.
// TODO: build a more fundamental concept in gengo for dealing with modifications
// to vendored packages.
if strings.HasPrefix(pkg.SourcePath, arguments.OutputBase) {
expandedPath := strings.TrimPrefix(pkg.SourcePath, arguments.OutputBase)
if strings.Contains(expandedPath, "/vendor/") {
path = expandedPath
}
}
packages = append(packages,
&generator.DefaultPackage{
PackageName: strings.Split(filepath.Base(pkg.Path), ".")[0],
PackagePath: path,
HeaderText: header,
GeneratorFunc: func(c *generator.Context) (generators []generator.Generator) {
return []generator.Generator{
NewGenDeepCopy(arguments.OutputFileBaseName, pkg.Path, boundingDirs, (ptagValue == tagValuePackage), ptagRegister),
}
},
FilterFunc: func(c *generator.Context, t *types.Type) bool {
return t.Name.Package == pkg.Path
},
})
}
}
return packages
}
// genDeepCopy produces a file with autogenerated deep-copy functions.
type genDeepCopy struct {
generator.DefaultGen
targetPackage string
boundingDirs []string
allTypes bool
registerTypes bool
imports namer.ImportTracker
typesForInit []*types.Type
}
func NewGenDeepCopy(sanitizedName, targetPackage string, boundingDirs []string, allTypes, registerTypes bool) generator.Generator {
return &genDeepCopy{
DefaultGen: generator.DefaultGen{
OptionalName: sanitizedName,
},
targetPackage: targetPackage,
boundingDirs: boundingDirs,
allTypes: allTypes,
registerTypes: registerTypes,
imports: generator.NewImportTracker(),
typesForInit: make([]*types.Type, 0),
}
}
func (g *genDeepCopy) Namers(c *generator.Context) namer.NameSystems {
// Have the raw namer for this file track what it imports.
return namer.NameSystems{
"raw": namer.NewRawNamer(g.targetPackage, g.imports),
}
}
func (g *genDeepCopy) Filter(c *generator.Context, t *types.Type) bool {
// Filter out types not being processed or not copyable within the package.
enabled := g.allTypes
if !enabled {
ttag := extractTag(t.CommentLines)
if ttag != nil && ttag.value == "true" {
enabled = true
}
}
if !enabled {
return false
}
if !copyableType(t) {
glog.V(2).Infof("Type %v is not copyable", t)
return false
}
glog.V(4).Infof("Type %v is copyable", t)
g.typesForInit = append(g.typesForInit, t)
return true
}
func (g *genDeepCopy) copyableAndInBounds(t *types.Type) bool {
if !copyableType(t) {
return false
}
// Only packages within the restricted range can be processed.
if !isRootedUnder(t.Name.Package, g.boundingDirs) {
return false
}
return true
}
// hasDeepCopyMethod returns true if an appropriate DeepCopy() method is
// defined for the given type. This allows more efficient deep copy
// implementations to be defined by the type's author. The correct signature
// for a type T is:
// func (t T) DeepCopy() T
// or:
// func (t *T) DeepCopy() T
func hasDeepCopyMethod(t *types.Type) bool {
for mn, mt := range t.Methods {
if mn != "DeepCopy" {
continue
}
if len(mt.Signature.Parameters) != 0 {
return false
}
if len(mt.Signature.Results) != 1 || mt.Signature.Results[0].Name != t.Name {
return false
}
return true
}
return false
}
func isRootedUnder(pkg string, roots []string) bool {
// Add trailing / to avoid false matches, e.g. foo/bar vs foo/barn. This
// assumes that bounding dirs do not have trailing slashes.
pkg = pkg + "/"
for _, root := range roots {
if strings.HasPrefix(pkg, root+"/") {
return true
}
}
return false
}
func copyableType(t *types.Type) bool {
// If the type opts out of copy-generation, stop.
ttag := extractTag(t.CommentLines)
if ttag != nil && ttag.value == "false" {
return false
}
// TODO: Consider generating functions for other kinds too.
if t.Kind != types.Struct {
return false
}
// Also, filter out private types.
if namer.IsPrivateGoName(t.Name.Name) {
return false
}
return true
}
func (g *genDeepCopy) isOtherPackage(pkg string) bool {
if pkg == g.targetPackage {
return false
}
if strings.HasSuffix(pkg, "\""+g.targetPackage+"\"") {
return false
}
return true
}
func (g *genDeepCopy) Imports(c *generator.Context) (imports []string) {
importLines := []string{}
for _, singleImport := range g.imports.ImportLines() {
if g.isOtherPackage(singleImport) {
importLines = append(importLines, singleImport)
}
}
return importLines
}
func argsFromType(ts ...*types.Type) generator.Args {
a := generator.Args{
"type": ts[0],
}
for i, t := range ts {
a[fmt.Sprintf("type%d", i+1)] = t
}
return a
}
func (g *genDeepCopy) Init(c *generator.Context, w io.Writer) error {
return nil
}
func (g *genDeepCopy) needsGeneration(t *types.Type) bool {
tag := extractTag(t.CommentLines)
tv := ""
if tag != nil {
tv = tag.value
if tv != "true" && tv != "false" {
glog.Fatalf("Type %v: unsupported %s value: %q", t, tagName, tag.value)
}
}
if g.allTypes && tv == "false" {
// The whole package is being generated, but this type has opted out.
glog.V(5).Infof("Not generating for type %v because type opted out", t)
return false
}
if !g.allTypes && tv != "true" {
// The whole package is NOT being generated, and this type has NOT opted in.
glog.V(5).Infof("Not generating for type %v because type did not opt in", t)
return false
}
return true
}
func extractInterfacesTag(comments []string) []string {
var result []string
values := types.ExtractCommentTags("+", comments)[interfacesTagName]
for _, v := range values {
if len(v) == 0 {
continue
}
intfs := strings.Split(v, ",")
for _, intf := range intfs {
if intf == "" {
continue
}
result = append(result, intf)
}
}
return result
}
func extractNonPointerInterfaces(comments []string) (bool, error) {
values := types.ExtractCommentTags("+", comments)[interfacesNonPointerTagName]
if len(values) == 0 {
return false, nil
}
result := values[0] == "true"
for _, v := range values {
if v == "true" != result {
return false, fmt.Errorf("contradicting %v value %q found to previous value %v", interfacesNonPointerTagName, v, result)
}
}
return result, nil
}
func (g *genDeepCopy) deepCopyableInterfaces(c *generator.Context, t *types.Type) ([]*types.Type, error) {
if t.Kind != types.Struct {
return nil, nil
}
intfs := extractInterfacesTag(append(t.SecondClosestCommentLines, t.CommentLines...))
var ts []*types.Type
for _, intf := range intfs {
t := types.ParseFullyQualifiedName(intf)
c.AddDir(t.Package)
intfT := c.Universe.Type(t)
if intfT == nil {
return nil, fmt.Errorf("unknown type %q in %s tag of type %s", intf, interfacesTagName, intfT)
}
if intfT.Kind != types.Interface {
return nil, fmt.Errorf("type %q in %s tag of type %s is not an interface, but: %q", intf, interfacesTagName, t, intfT.Kind)
}
g.imports.AddType(intfT)
ts = append(ts, intfT)
}
return ts, nil
}
// DeepCopyableInterfaces returns the interface types to implement and whether they apply to a non-pointer receiver.
func (g *genDeepCopy) DeepCopyableInterfaces(c *generator.Context, t *types.Type) ([]*types.Type, bool, error) {
ts, err := g.deepCopyableInterfaces(c, t)
if err != nil {
return nil, false, err
}
set := map[string]*types.Type{}
for _, t := range ts {
set[t.String()] = t
}
result := []*types.Type{}
for _, t := range set {
result = append(result, t)
}
TypeSlice(result).Sort() // we need a stable sorting because it determines the order in generation
nonPointerReceiver, err := extractNonPointerInterfaces(append(t.SecondClosestCommentLines, t.CommentLines...))
if err != nil {
return nil, false, err
}
return result, nonPointerReceiver, nil
}
type TypeSlice []*types.Type
func (s TypeSlice) Len() int { return len(s) }
func (s TypeSlice) Less(i, j int) bool { return s[i].String() < s[j].String() }
func (s TypeSlice) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
func (s TypeSlice) Sort() { sort.Sort(s) }
func (g *genDeepCopy) GenerateType(c *generator.Context, t *types.Type, w io.Writer) error {
if !g.needsGeneration(t) {
return nil
}
glog.V(5).Infof("Generating deepcopy function for type %v", t)
sw := generator.NewSnippetWriter(w, c, "$", "$")
args := argsFromType(t)
_, foundDeepCopyInto := t.Methods["DeepCopyInto"]
_, foundDeepCopy := t.Methods["DeepCopy"]
if !foundDeepCopyInto {
sw.Do("// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.\n", args)
sw.Do("func (in *$.type|raw$) DeepCopyInto(out *$.type|raw$) {\n", args)
if foundDeepCopy {
if t.Methods["DeepCopy"].Signature.Receiver.Kind == types.Pointer {
sw.Do("clone := in.DeepCopy()\n", nil)
sw.Do("*out = *clone\n", nil)
} else {
sw.Do("*out = in.DeepCopy()\n", nil)
}
sw.Do("return\n", nil)
} else {
g.generateFor(t, sw)
sw.Do("return\n", nil)
}
sw.Do("}\n\n", nil)
}
if !foundDeepCopy {
sw.Do("// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new $.type|raw$.\n", args)
sw.Do("func (in *$.type|raw$) DeepCopy() *$.type|raw$ {\n", args)
sw.Do("if in == nil { return nil }\n", nil)
sw.Do("out := new($.type|raw$)\n", args)
sw.Do("in.DeepCopyInto(out)\n", nil)
sw.Do("return out\n", nil)
sw.Do("}\n\n", nil)
}
intfs, nonPointerReceiver, err := g.DeepCopyableInterfaces(c, t)
if err != nil {
return err
}
for _, intf := range intfs {
sw.Do(fmt.Sprintf("// DeepCopy%s is an autogenerated deepcopy function, copying the receiver, creating a new $.type2|raw$.\n", intf.Name.Name), argsFromType(t, intf))
if nonPointerReceiver {
sw.Do(fmt.Sprintf("func (in $.type|raw$) DeepCopy%s() $.type2|raw$ {\n", intf.Name.Name), argsFromType(t, intf))
sw.Do("return *in.DeepCopy()", nil)
sw.Do("}\n\n", nil)
} else {
sw.Do(fmt.Sprintf("func (in *$.type|raw$) DeepCopy%s() $.type2|raw$ {\n", intf.Name.Name), argsFromType(t, intf))
sw.Do("if c := in.DeepCopy(); c != nil {\n", nil)
sw.Do("return c\n", nil)
sw.Do("} else {\n", nil)
sw.Do("return nil\n", nil)
sw.Do("}}\n\n", nil)
}
}
return sw.Error()
}
// we use the system of shadowing 'in' and 'out' so that the same code is valid
// at any nesting level. This makes the autogenerator easy to understand, and
// the compiler shouldn't care.
func (g *genDeepCopy) generateFor(t *types.Type, sw *generator.SnippetWriter) {
var f func(*types.Type, *generator.SnippetWriter)
switch t.Kind {
case types.Builtin:
f = g.doBuiltin
case types.Map:
f = g.doMap
case types.Slice:
f = g.doSlice
case types.Struct:
f = g.doStruct
case types.Interface:
f = g.doInterface
case types.Pointer:
f = g.doPointer
case types.Alias:
f = g.doAlias
default:
f = g.doUnknown
}
f(t, sw)
}
func (g *genDeepCopy) doBuiltin(t *types.Type, sw *generator.SnippetWriter) {
sw.Do("*out = *in\n", nil)
}
func (g *genDeepCopy) doMap(t *types.Type, sw *generator.SnippetWriter) {
sw.Do("*out = make($.|raw$, len(*in))\n", t)
if t.Key.IsAssignable() {
switch {
case hasDeepCopyMethod(t.Elem):
sw.Do("for key, val := range *in {\n", nil)
sw.Do("(*out)[key] = val.DeepCopy()\n", nil)
sw.Do("}\n", nil)
case t.Elem.IsAnonymousStruct():
sw.Do("for key := range *in {\n", nil)
sw.Do("(*out)[key] = struct{}{}\n", nil)
sw.Do("}\n", nil)
case t.Elem.IsAssignable():
sw.Do("for key, val := range *in {\n", nil)
sw.Do("(*out)[key] = val\n", nil)
sw.Do("}\n", nil)
case t.Elem.Kind == types.Interface:
sw.Do("for key, val := range *in {\n", nil)
sw.Do("if val == nil {(*out)[key]=nil} else {\n", nil)
sw.Do(fmt.Sprintf("(*out)[key] = val.DeepCopy%s()\n", t.Elem.Name.Name), t)
sw.Do("}}\n", nil)
default:
sw.Do("for key, val := range *in {\n", nil)
if g.copyableAndInBounds(t.Elem) {
sw.Do("newVal := new($.|raw$)\n", t.Elem)
sw.Do("val.DeepCopyInto(newVal)\n", nil)
sw.Do("(*out)[key] = *newVal\n", nil)
} else if t.Elem.Kind == types.Slice && t.Elem.Elem.Kind == types.Builtin {
sw.Do("if val==nil { (*out)[key]=nil } else {\n", nil)
sw.Do("(*out)[key] = make($.|raw$, len(val))\n", t.Elem)
sw.Do("copy((*out)[key], val)\n", nil)
sw.Do("}\n", nil)
} else if t.Elem.Kind == types.Alias && t.Elem.Underlying.Kind == types.Slice && t.Elem.Underlying.Elem.Kind == types.Builtin {
sw.Do("(*out)[key] = make($.|raw$, len(val))\n", t.Elem)
sw.Do("copy((*out)[key], val)\n", nil)
} else if t.Elem.Kind == types.Pointer {
sw.Do("if val==nil { (*out)[key]=nil } else {\n", nil)
sw.Do("(*out)[key] = new($.Elem|raw$)\n", t.Elem)
sw.Do("val.DeepCopyInto((*out)[key])\n", nil)
sw.Do("}\n", nil)
} else {
sw.Do("(*out)[key] = *val.DeepCopy()\n", t.Elem)
}
sw.Do("}\n", nil)
}
} else {
// TODO: Implement it when necessary.
sw.Do("for range *in {\n", nil)
sw.Do("// FIXME: Copying unassignable keys unsupported $.|raw$\n", t.Key)
sw.Do("}\n", nil)
}
}
func (g *genDeepCopy) doSlice(t *types.Type, sw *generator.SnippetWriter) {
if hasDeepCopyMethod(t) {
sw.Do("*out = in.DeepCopy()\n", nil)
return
}
sw.Do("*out = make($.|raw$, len(*in))\n", t)
if hasDeepCopyMethod(t.Elem) {
sw.Do("for i := range *in {\n", nil)
sw.Do("(*out)[i] = (*in)[i].DeepCopy()\n", nil)
sw.Do("}\n", nil)
} else if t.Elem.Kind == types.Builtin || t.Elem.IsAssignable() {
sw.Do("copy(*out, *in)\n", nil)
} else {
sw.Do("for i := range *in {\n", nil)
if t.Elem.Kind == types.Slice {
sw.Do("if (*in)[i] != nil {\n", nil)
sw.Do("in, out := &(*in)[i], &(*out)[i]\n", nil)
g.generateFor(t.Elem, sw)
sw.Do("}\n", nil)
} else if hasDeepCopyMethod(t.Elem) {
sw.Do("(*out)[i] = (*in)[i].DeepCopy()\n", nil)
// REVISIT(sttts): the following is removed in master
//} else if t.Elem.IsAssignable() {
// sw.Do("(*out)[i] = (*in)[i]\n", nil)
} else if t.Elem.Kind == types.Interface {
sw.Do("if (*in)[i] == nil {(*out)[i]=nil} else {\n", nil)
sw.Do(fmt.Sprintf("(*out)[i] = (*in)[i].DeepCopy%s()\n", t.Elem.Name.Name), t)
sw.Do("}\n", nil)
} else if t.Elem.Kind == types.Pointer {
sw.Do("if (*in)[i]==nil { (*out)[i]=nil } else {\n", nil)
sw.Do("(*out)[i] = new($.Elem|raw$)\n", t.Elem)
sw.Do("(*in)[i].DeepCopyInto((*out)[i])\n", nil)
sw.Do("}\n", nil)
} else if t.Elem.Kind == types.Struct {
sw.Do("(*in)[i].DeepCopyInto(&(*out)[i])\n", nil)
} else {
sw.Do("(*out)[i] = (*in)[i].DeepCopy()\n", nil)
}
sw.Do("}\n", nil)
}
}
func (g *genDeepCopy) doStruct(t *types.Type, sw *generator.SnippetWriter) {
if hasDeepCopyMethod(t) {
sw.Do("*out = in.DeepCopy()\n", nil)
return
}
// Simple copy covers a lot of cases.
sw.Do("*out = *in\n", nil)
// Now fix-up fields as needed.
for _, m := range t.Members {
t := m.Type
hasMethod := hasDeepCopyMethod(t)
if t.Kind == types.Alias {
copied := *t.Underlying
copied.Name = t.Name
t = &copied
}
args := generator.Args{
"type": t,
"kind": t.Kind,
"name": m.Name,
}
switch t.Kind {
case types.Builtin:
if hasMethod {
sw.Do("out.$.name$ = in.$.name$.DeepCopy()\n", args)
}
// the initial *out = *in was enough
case types.Map, types.Slice, types.Pointer:
if hasMethod {
sw.Do("if in.$.name$ != nil {\n", args)
sw.Do("out.$.name$ = in.$.name$.DeepCopy()\n", args)
sw.Do("}\n", nil)
} else {
// Fixup non-nil reference-semantic types.
sw.Do("if in.$.name$ != nil {\n", args)
sw.Do("in, out := &in.$.name$, &out.$.name$\n", args)
g.generateFor(t, sw)
sw.Do("}\n", nil)
}
case types.Struct:
if hasMethod {
sw.Do("out.$.name$ = in.$.name$.DeepCopy()\n", args)
} else if t.IsAssignable() {
sw.Do("out.$.name$ = in.$.name$\n", args)
} else {
sw.Do("in.$.name$.DeepCopyInto(&out.$.name$)\n", args)
}
case types.Interface:
sw.Do("if in.$.name$ == nil {out.$.name$=nil} else {\n", args)
sw.Do(fmt.Sprintf("out.$.name$ = in.$.name$.DeepCopy%s()\n", t.Name.Name), args)
sw.Do("}\n", nil)
default:
sw.Do("out.$.name$ = in.$.name$.DeepCopy()\n", args)
}
}
}
func (g *genDeepCopy) doInterface(t *types.Type, sw *generator.SnippetWriter) {
// TODO: Add support for interfaces.
g.doUnknown(t, sw)
}
func (g *genDeepCopy) doPointer(t *types.Type, sw *generator.SnippetWriter) {
sw.Do("if *in == nil { *out = nil } else {\n", t)
if hasDeepCopyMethod(t.Elem) {
sw.Do("*out = new($.Elem|raw$)\n", t)
sw.Do("**out = (*in).DeepCopy()\n", nil)
} else if t.Elem.IsAssignable() {
sw.Do("*out = new($.Elem|raw$)\n", t)
sw.Do("**out = **in", nil)
} else {
switch t.Elem.Kind {
case types.Map, types.Slice:
sw.Do("*out = new($.Elem|raw$)\n", t)
sw.Do("if **in != nil {\n", t)
sw.Do("in, out := *in, *out\n", nil)
g.generateFor(t.Elem, sw)
sw.Do("}\n", nil)
default:
sw.Do("*out = new($.Elem|raw$)\n", t)
sw.Do("(*in).DeepCopyInto(*out)\n", nil)
}
}
sw.Do("}", t)
}
func (g *genDeepCopy) doAlias(t *types.Type, sw *generator.SnippetWriter) {
// TODO: Add support for aliases.
g.doUnknown(t, sw)
}
func (g *genDeepCopy) doUnknown(t *types.Type, sw *generator.SnippetWriter) {
sw.Do("// FIXME: Type $.|raw$ is unsupported.\n", t)
}

View File

@ -1,825 +0,0 @@
/*
Copyright 2016 The Kubernetes 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 generators
import (
"bytes"
"fmt"
"io"
"path/filepath"
"reflect"
"strings"
"k8s.io/gengo/args"
"k8s.io/gengo/generator"
"k8s.io/gengo/namer"
"k8s.io/gengo/types"
"github.com/golang/glog"
)
// CustomArgs is used tby the go2idl framework to pass args specific to this
// generator.
type CustomArgs struct {
ExtraPeerDirs []string // Always consider these as last-ditch possibilities for conversions.
}
// These are the comment tags that carry parameters for defaulter generation.
const tagName = "k8s:defaulter-gen"
const intputTagName = "k8s:defaulter-gen-input"
func extractTag(comments []string) []string {
return types.ExtractCommentTags("+", comments)[tagName]
}
func extractInputTag(comments []string) []string {
return types.ExtractCommentTags("+", comments)[intputTagName]
}
func checkTag(comments []string, require ...string) bool {
values := types.ExtractCommentTags("+", comments)[tagName]
if len(require) == 0 {
return len(values) == 1 && values[0] == ""
}
return reflect.DeepEqual(values, require)
}
func defaultFnNamer() *namer.NameStrategy {
return &namer.NameStrategy{
Prefix: "SetDefaults_",
Join: func(pre string, in []string, post string) string {
return pre + strings.Join(in, "_") + post
},
}
}
func objectDefaultFnNamer() *namer.NameStrategy {
return &namer.NameStrategy{
Prefix: "SetObjectDefaults_",
Join: func(pre string, in []string, post string) string {
return pre + strings.Join(in, "_") + post
},
}
}
// NameSystems returns the name system used by the generators in this package.
func NameSystems() namer.NameSystems {
return namer.NameSystems{
"public": namer.NewPublicNamer(1),
"raw": namer.NewRawNamer("", nil),
"defaultfn": defaultFnNamer(),
"objectdefaultfn": objectDefaultFnNamer(),
}
}
// DefaultNameSystem returns the default name system for ordering the types to be
// processed by the generators in this package.
func DefaultNameSystem() string {
return "public"
}
// defaults holds the declared defaulting functions for a given type (all defaulting functions
// are expected to be func(1))
type defaults struct {
// object is the defaulter function for a top level type (typically one with TypeMeta) that
// invokes all child defaulters. May be nil if the object defaulter has not yet been generated.
object *types.Type
// base is a defaulter function defined for a type SetDefaults_Pod which does not invoke all
// child defaults - the base defaulter alone is insufficient to default a type
base *types.Type
// additional is zero or more defaulter functions of the form SetDefaults_Pod_XXXX that can be
// included in the Object defaulter.
additional []*types.Type
}
// All of the types in conversions map are of type "DeclarationOf" with
// the underlying type being "Func".
type defaulterFuncMap map[*types.Type]defaults
// Returns all manually-defined defaulting functions in the package.
func getManualDefaultingFunctions(context *generator.Context, pkg *types.Package, manualMap defaulterFuncMap) {
buffer := &bytes.Buffer{}
sw := generator.NewSnippetWriter(buffer, context, "$", "$")
for _, f := range pkg.Functions {
if f.Underlying == nil || f.Underlying.Kind != types.Func {
glog.Errorf("Malformed function: %#v", f)
continue
}
if f.Underlying.Signature == nil {
glog.Errorf("Function without signature: %#v", f)
continue
}
signature := f.Underlying.Signature
// Check whether the function is defaulting function.
// Note that all of them have signature:
// object: func SetObjectDefaults_inType(*inType)
// base: func SetDefaults_inType(*inType)
// additional: func SetDefaults_inType_Qualifier(*inType)
if signature.Receiver != nil {
continue
}
if len(signature.Parameters) != 1 {
continue
}
if len(signature.Results) != 0 {
continue
}
inType := signature.Parameters[0]
if inType.Kind != types.Pointer {
continue
}
// Check if this is the primary defaulter.
args := defaultingArgsFromType(inType.Elem)
sw.Do("$.inType|defaultfn$", args)
switch {
case f.Name.Name == buffer.String():
key := inType.Elem
// We might scan the same package twice, and that's OK.
v, ok := manualMap[key]
if ok && v.base != nil && v.base.Name.Package != pkg.Path {
panic(fmt.Sprintf("duplicate static defaulter defined: %#v", key))
}
v.base = f
manualMap[key] = v
glog.V(6).Infof("found base defaulter function for %s from %s", key.Name, f.Name)
// Is one of the additional defaulters - a top level defaulter on a type that is
// also invoked.
case strings.HasPrefix(f.Name.Name, buffer.String()+"_"):
key := inType.Elem
v, ok := manualMap[key]
if ok {
exists := false
for _, existing := range v.additional {
if existing.Name == f.Name {
exists = true
break
}
}
if exists {
continue
}
}
v.additional = append(v.additional, f)
manualMap[key] = v
glog.V(6).Infof("found additional defaulter function for %s from %s", key.Name, f.Name)
}
buffer.Reset()
sw.Do("$.inType|objectdefaultfn$", args)
if f.Name.Name == buffer.String() {
key := inType.Elem
// We might scan the same package twice, and that's OK.
v, ok := manualMap[key]
if ok && v.base != nil && v.base.Name.Package != pkg.Path {
panic(fmt.Sprintf("duplicate static defaulter defined: %#v", key))
}
v.object = f
manualMap[key] = v
glog.V(6).Infof("found object defaulter function for %s from %s", key.Name, f.Name)
}
buffer.Reset()
}
}
func Packages(context *generator.Context, arguments *args.GeneratorArgs) generator.Packages {
boilerplate, err := arguments.LoadGoBoilerplate()
if err != nil {
glog.Fatalf("Failed loading boilerplate: %v", err)
}
packages := generator.Packages{}
header := append([]byte(fmt.Sprintf("// +build !%s\n\n", arguments.GeneratedBuildTag)), boilerplate...)
header = append(header, []byte(
`
// This file was autogenerated by defaulter-gen. Do not edit it manually!
`)...)
// Accumulate pre-existing default functions.
// TODO: This is too ad-hoc. We need a better way.
existingDefaulters := defaulterFuncMap{}
buffer := &bytes.Buffer{}
sw := generator.NewSnippetWriter(buffer, context, "$", "$")
// We are generating defaults only for packages that are explicitly
// passed as InputDir.
for _, i := range context.Inputs {
glog.V(5).Infof("considering pkg %q", i)
pkg := context.Universe[i]
if pkg == nil {
// If the input had no Go files, for example.
continue
}
// typesPkg is where the types that needs defaulter are defined.
// Sometimes it is different from pkg. For example, kubernetes core/v1
// types are defined in vendor/k8s.io/api/core/v1, while pkg is at
// pkg/api/v1.
typesPkg := pkg
// Add defaulting functions.
getManualDefaultingFunctions(context, pkg, existingDefaulters)
var peerPkgs []string
if customArgs, ok := arguments.CustomArgs.(*CustomArgs); ok {
for _, pkg := range customArgs.ExtraPeerDirs {
if i := strings.Index(pkg, "/vendor/"); i != -1 {
pkg = pkg[i+len("/vendor/"):]
}
peerPkgs = append(peerPkgs, pkg)
}
}
// Make sure our peer-packages are added and fully parsed.
for _, pp := range peerPkgs {
context.AddDir(pp)
getManualDefaultingFunctions(context, context.Universe[pp], existingDefaulters)
}
typesWith := extractTag(pkg.Comments)
shouldCreateObjectDefaulterFn := func(t *types.Type) bool {
if defaults, ok := existingDefaulters[t]; ok && defaults.object != nil {
// A default generator is defined
glog.V(5).Infof(" an object defaulter already exists as %s", defaults.base.Name)
return false
}
// opt-out
if checkTag(t.SecondClosestCommentLines, "false") {
return false
}
// opt-in
if checkTag(t.SecondClosestCommentLines, "true") {
return true
}
// For every k8s:defaulter-gen tag at the package level, interpret the value as a
// field name (like TypeMeta, ListMeta, ObjectMeta) and trigger defaulter generation
// for any type with any of the matching field names. Provides a more useful package
// level defaulting than global (because we only need defaulters on a subset of objects -
// usually those with TypeMeta).
if t.Kind == types.Struct && len(typesWith) > 0 {
for _, field := range t.Members {
for _, s := range typesWith {
if field.Name == s {
return true
}
}
}
}
return false
}
// if the types are not in the same package where the defaulter functions to be generated
inputTags := extractInputTag(pkg.Comments)
if len(inputTags) > 1 {
panic(fmt.Sprintf("there could only be one input tag, got %#v", inputTags))
}
if len(inputTags) == 1 {
var err error
typesPkg, err = context.AddDirectory(filepath.Join(pkg.Path, inputTags[0]))
if err != nil {
glog.Fatalf("cannot import package %s", inputTags[0])
}
// update context.Order to the latest context.Universe
orderer := namer.Orderer{Namer: namer.NewPublicNamer(1)}
context.Order = orderer.OrderUniverse(context.Universe)
}
newDefaulters := defaulterFuncMap{}
for _, t := range typesPkg.Types {
if !shouldCreateObjectDefaulterFn(t) {
continue
}
if namer.IsPrivateGoName(t.Name.Name) {
// We won't be able to convert to a private type.
glog.V(5).Infof(" found a type %v, but it is a private name", t)
continue
}
// create a synthetic type we can use during generation
newDefaulters[t] = defaults{}
}
// only generate defaulters for objects that actually have defined defaulters
// prevents empty defaulters from being registered
for {
promoted := 0
for t, d := range newDefaulters {
if d.object != nil {
continue
}
if newCallTreeForType(existingDefaulters, newDefaulters).build(t, true) != nil {
args := defaultingArgsFromType(t)
sw.Do("$.inType|objectdefaultfn$", args)
newDefaulters[t] = defaults{
object: &types.Type{
Name: types.Name{
Package: pkg.Path,
Name: buffer.String(),
},
Kind: types.Func,
},
}
buffer.Reset()
promoted++
}
}
if promoted != 0 {
continue
}
// prune any types that were not used
for t, d := range newDefaulters {
if d.object == nil {
glog.V(6).Infof("did not generate defaulter for %s because no child defaulters were registered", t.Name)
delete(newDefaulters, t)
}
}
break
}
if len(newDefaulters) == 0 {
glog.V(5).Infof("no defaulters in package %s", pkg.Name)
}
path := pkg.Path
// if the source path is within a /vendor/ directory (for example,
// k8s.io/kubernetes/vendor/k8s.io/apimachinery/pkg/apis/meta/v1), allow
// generation to output to the proper relative path (under vendor).
// Otherwise, the generator will create the file in the wrong location
// in the output directory.
// TODO: build a more fundamental concept in gengo for dealing with modifications
// to vendored packages.
if strings.HasPrefix(pkg.SourcePath, arguments.OutputBase) {
expandedPath := strings.TrimPrefix(pkg.SourcePath, arguments.OutputBase)
if strings.Contains(expandedPath, "/vendor/") {
path = expandedPath
}
}
packages = append(packages,
&generator.DefaultPackage{
PackageName: filepath.Base(pkg.Path),
PackagePath: path,
HeaderText: header,
GeneratorFunc: func(c *generator.Context) (generators []generator.Generator) {
return []generator.Generator{
NewGenDefaulter(arguments.OutputFileBaseName, typesPkg.Path, pkg.Path, existingDefaulters, newDefaulters, peerPkgs),
}
},
FilterFunc: func(c *generator.Context, t *types.Type) bool {
return t.Name.Package == typesPkg.Path
},
})
}
return packages
}
// callTreeForType contains fields necessary to build a tree for types.
type callTreeForType struct {
existingDefaulters defaulterFuncMap
newDefaulters defaulterFuncMap
currentlyBuildingTypes map[*types.Type]bool
}
func newCallTreeForType(existingDefaulters, newDefaulters defaulterFuncMap) *callTreeForType {
return &callTreeForType{
existingDefaulters: existingDefaulters,
newDefaulters: newDefaulters,
currentlyBuildingTypes: make(map[*types.Type]bool),
}
}
// build creates a tree of paths to fields (based on how they would be accessed in Go - pointer, elem,
// slice, or key) and the functions that should be invoked on each field. An in-order traversal of the resulting tree
// can be used to generate a Go function that invokes each nested function on the appropriate type. The return
// value may be nil if there are no functions to call on type or the type is a primitive (Defaulters can only be
// invoked on structs today). When root is true this function will not use a newDefaulter. existingDefaulters should
// contain all defaulting functions by type defined in code - newDefaulters should contain all object defaulters
// that could be or will be generated. If newDefaulters has an entry for a type, but the 'object' field is nil,
// this function skips adding that defaulter - this allows us to avoid generating object defaulter functions for
// list types that call empty defaulters.
func (c *callTreeForType) build(t *types.Type, root bool) *callNode {
parent := &callNode{}
if root {
// the root node is always a pointer
parent.elem = true
}
defaults, _ := c.existingDefaulters[t]
newDefaults, generated := c.newDefaulters[t]
switch {
case !root && generated && newDefaults.object != nil:
parent.call = append(parent.call, newDefaults.object)
// if we will be generating the defaulter, it by definition is a covering
// defaulter, so we halt recursion
glog.V(6).Infof("the defaulter %s will be generated as an object defaulter", t.Name)
return parent
case defaults.object != nil:
// object defaulters are always covering
parent.call = append(parent.call, defaults.object)
return parent
case defaults.base != nil:
parent.call = append(parent.call, defaults.base)
// if the base function indicates it "covers" (it already includes defaulters)
// we can halt recursion
if checkTag(defaults.base.CommentLines, "covers") {
glog.V(6).Infof("the defaulter %s indicates it covers all sub generators", t.Name)
return parent
}
}
// base has been added already, now add any additional defaulters defined for this object
parent.call = append(parent.call, defaults.additional...)
// if the type already exists, don't build the tree for it and don't generate anything.
// This is used to avoid recursion for nested recursive types.
if c.currentlyBuildingTypes[t] {
return nil
}
// if type doesn't exist, mark it as existing
c.currentlyBuildingTypes[t] = true
defer func() {
// The type will now acts as a parent, not a nested recursive type.
// We can now build the tree for it safely.
c.currentlyBuildingTypes[t] = false
}()
switch t.Kind {
case types.Pointer:
if child := c.build(t.Elem, false); child != nil {
child.elem = true
parent.children = append(parent.children, *child)
}
case types.Slice, types.Array:
if child := c.build(t.Elem, false); child != nil {
child.index = true
parent.children = append(parent.children, *child)
}
case types.Map:
if child := c.build(t.Elem, false); child != nil {
child.key = true
parent.children = append(parent.children, *child)
}
case types.Struct:
for _, field := range t.Members {
name := field.Name
if len(name) == 0 {
if field.Type.Kind == types.Pointer {
name = field.Type.Elem.Name.Name
} else {
name = field.Type.Name.Name
}
}
if child := c.build(field.Type, false); child != nil {
child.field = name
parent.children = append(parent.children, *child)
}
}
case types.Alias:
if child := c.build(t.Underlying, false); child != nil {
parent.children = append(parent.children, *child)
}
}
if len(parent.children) == 0 && len(parent.call) == 0 {
//glog.V(6).Infof("decided type %s needs no generation", t.Name)
return nil
}
return parent
}
const (
runtimePackagePath = "k8s.io/apimachinery/pkg/runtime"
conversionPackagePath = "k8s.io/apimachinery/pkg/conversion"
)
// genDefaulter produces a file with a autogenerated conversions.
type genDefaulter struct {
generator.DefaultGen
typesPackage string
outputPackage string
peerPackages []string
newDefaulters defaulterFuncMap
existingDefaulters defaulterFuncMap
imports namer.ImportTracker
typesForInit []*types.Type
}
func NewGenDefaulter(sanitizedName, typesPackage, outputPackage string, existingDefaulters, newDefaulters defaulterFuncMap, peerPkgs []string) generator.Generator {
return &genDefaulter{
DefaultGen: generator.DefaultGen{
OptionalName: sanitizedName,
},
typesPackage: typesPackage,
outputPackage: outputPackage,
peerPackages: peerPkgs,
newDefaulters: newDefaulters,
existingDefaulters: existingDefaulters,
imports: generator.NewImportTracker(),
typesForInit: make([]*types.Type, 0),
}
}
func (g *genDefaulter) Namers(c *generator.Context) namer.NameSystems {
// Have the raw namer for this file track what it imports.
return namer.NameSystems{
"raw": namer.NewRawNamer(g.outputPackage, g.imports),
}
}
func (g *genDefaulter) isOtherPackage(pkg string) bool {
if pkg == g.outputPackage {
return false
}
if strings.HasSuffix(pkg, `"`+g.outputPackage+`"`) {
return false
}
return true
}
func (g *genDefaulter) Filter(c *generator.Context, t *types.Type) bool {
defaults, ok := g.newDefaulters[t]
if !ok || defaults.object == nil {
return false
}
g.typesForInit = append(g.typesForInit, t)
return true
}
func (g *genDefaulter) Imports(c *generator.Context) (imports []string) {
var importLines []string
for _, singleImport := range g.imports.ImportLines() {
if g.isOtherPackage(singleImport) {
importLines = append(importLines, singleImport)
}
}
return importLines
}
func (g *genDefaulter) Init(c *generator.Context, w io.Writer) error {
sw := generator.NewSnippetWriter(w, c, "$", "$")
scheme := c.Universe.Type(types.Name{Package: runtimePackagePath, Name: "Scheme"})
schemePtr := &types.Type{
Kind: types.Pointer,
Elem: scheme,
}
sw.Do("// RegisterDefaults adds defaulters functions to the given scheme.\n", nil)
sw.Do("// Public to allow building arbitrary schemes.\n", nil)
sw.Do("// All generated defaulters are covering - they call all nested defaulters.\n", nil)
sw.Do("func RegisterDefaults(scheme $.|raw$) error {\n", schemePtr)
for _, t := range g.typesForInit {
args := defaultingArgsFromType(t)
sw.Do("scheme.AddTypeDefaultingFunc(&$.inType|raw${}, func(obj interface{}) { $.inType|objectdefaultfn$(obj.(*$.inType|raw$)) })\n", args)
}
sw.Do("return nil\n", nil)
sw.Do("}\n\n", nil)
return sw.Error()
}
func (g *genDefaulter) GenerateType(c *generator.Context, t *types.Type, w io.Writer) error {
if _, ok := g.newDefaulters[t]; !ok {
return nil
}
glog.V(5).Infof("generating for type %v", t)
callTree := newCallTreeForType(g.existingDefaulters, g.newDefaulters).build(t, true)
if callTree == nil {
glog.V(5).Infof(" no defaulters defined")
return nil
}
i := 0
callTree.VisitInOrder(func(ancestors []*callNode, current *callNode) {
if len(current.call) == 0 {
return
}
path := callPath(append(ancestors, current))
glog.V(5).Infof(" %d: %s", i, path)
i++
})
sw := generator.NewSnippetWriter(w, c, "$", "$")
g.generateDefaulter(t, callTree, sw)
return sw.Error()
}
func defaultingArgsFromType(inType *types.Type) generator.Args {
return generator.Args{
"inType": inType,
}
}
func (g *genDefaulter) generateDefaulter(inType *types.Type, callTree *callNode, sw *generator.SnippetWriter) {
sw.Do("func $.inType|objectdefaultfn$(in *$.inType|raw$) {\n", defaultingArgsFromType(inType))
callTree.WriteMethod("in", 0, nil, sw)
sw.Do("}\n\n", nil)
}
// callNode represents an entry in a tree of Go type accessors - the path from the root to a leaf represents
// how in Go code an access would be performed. For example, if a defaulting function exists on a container
// lifecycle hook, to invoke that defaulter correctly would require this Go code:
//
// for i := range pod.Spec.Containers {
// o := &pod.Spec.Containers[i]
// if o.LifecycleHook != nil {
// SetDefaults_LifecycleHook(o.LifecycleHook)
// }
// }
//
// That would be represented by a call tree like:
//
// callNode
// field: "Spec"
// children:
// - field: "Containers"
// children:
// - index: true
// children:
// - field: "LifecycleHook"
// elem: true
// call:
// - SetDefaults_LifecycleHook
//
// which we can traverse to build that Go struct (you must call the field Spec, then Containers, then range over
// that field, then check whether the LifecycleHook field is nil, before calling SetDefaults_LifecycleHook on
// the pointer to that field).
type callNode struct {
// field is the name of the Go member to access
field string
// key is true if this is a map and we must range over the key and values
key bool
// index is true if this is a slice and we must range over the slice values
index bool
// elem is true if the previous elements refer to a pointer (typically just field)
elem bool
// call is all of the functions that must be invoked on this particular node, in order
call []*types.Type
// children is the child call nodes that must also be traversed
children []callNode
}
// CallNodeVisitorFunc is a function for visiting a call tree. ancestors is the list of all parents
// of this node to the root of the tree - will be empty at the root.
type CallNodeVisitorFunc func(ancestors []*callNode, node *callNode)
func (n *callNode) VisitInOrder(fn CallNodeVisitorFunc) {
n.visitInOrder(nil, fn)
}
func (n *callNode) visitInOrder(ancestors []*callNode, fn CallNodeVisitorFunc) {
fn(ancestors, n)
ancestors = append(ancestors, n)
for i := range n.children {
n.children[i].visitInOrder(ancestors, fn)
}
}
var (
indexVariables = "ijklmnop"
localVariables = "abcdefgh"
)
// varsForDepth creates temporary variables guaranteed to be unique within lexical Go scopes
// of this depth in a function. It uses canonical Go loop variables for the first 7 levels
// and then resorts to uglier prefixes.
func varsForDepth(depth int) (index, local string) {
if depth > len(indexVariables) {
index = fmt.Sprintf("i%d", depth)
} else {
index = indexVariables[depth : depth+1]
}
if depth > len(localVariables) {
local = fmt.Sprintf("local%d", depth)
} else {
local = localVariables[depth : depth+1]
}
return
}
// writeCalls generates a list of function calls based on the calls field for the provided variable
// name and pointer.
func (n *callNode) writeCalls(varName string, isVarPointer bool, sw *generator.SnippetWriter) {
accessor := varName
if !isVarPointer {
accessor = "&" + accessor
}
for _, fn := range n.call {
sw.Do("$.fn|raw$($.var$)\n", generator.Args{
"fn": fn,
"var": accessor,
})
}
}
// WriteMethod performs an in-order traversal of the calltree, generating loops and if blocks as necessary
// to correctly turn the call tree into a method body that invokes all calls on all child nodes of the call tree.
// Depth is used to generate local variables at the proper depth.
func (n *callNode) WriteMethod(varName string, depth int, ancestors []*callNode, sw *generator.SnippetWriter) {
// if len(n.call) > 0 {
// sw.Do(fmt.Sprintf("// %s\n", callPath(append(ancestors, n)).String()), nil)
// }
if len(n.field) > 0 {
varName = varName + "." + n.field
}
index, local := varsForDepth(depth)
vars := generator.Args{
"index": index,
"local": local,
"var": varName,
}
isPointer := n.elem
if isPointer && len(ancestors) > 0 {
sw.Do("if $.var$ != nil {\n", vars)
}
switch {
case n.index:
sw.Do("for $.index$ := range $.var$ {\n", vars)
sw.Do("$.local$ := &$.var$[$.index$]\n", vars)
n.writeCalls(local, true, sw)
for i := range n.children {
n.children[i].WriteMethod(local, depth+1, append(ancestors, n), sw)
}
sw.Do("}\n", nil)
case n.key:
default:
n.writeCalls(varName, isPointer, sw)
for i := range n.children {
n.children[i].WriteMethod(varName, depth, append(ancestors, n), sw)
}
}
if isPointer && len(ancestors) > 0 {
sw.Do("}\n", nil)
}
}
type callPath []*callNode
// String prints a representation of a callPath that roughly approximates what a Go accessor
// would look like. Used for debugging only.
func (path callPath) String() string {
if len(path) == 0 {
return "<none>"
}
var parts []string
for _, p := range path {
last := len(parts) - 1
switch {
case p.elem:
if len(parts) > 0 {
parts[last] = "*" + parts[last]
} else {
parts = append(parts, "*")
}
case p.index:
if len(parts) > 0 {
parts[last] = parts[last] + "[i]"
} else {
parts = append(parts, "[i]")
}
case p.key:
if len(parts) > 0 {
parts[last] = parts[last] + "[key]"
} else {
parts = append(parts, "[key]")
}
default:
if len(p.field) > 0 {
parts = append(parts, p.field)
} else {
parts = append(parts, "<root>")
}
}
}
var calls []string
for _, fn := range path[len(path)-1].call {
calls = append(calls, fn.Name.String())
}
if len(calls) == 0 {
calls = append(calls, "<none>")
}
return strings.Join(parts, ".") + " calls " + strings.Join(calls, ", ")
}

View File

@ -1,203 +0,0 @@
/*
Copyright 2017 The Kubernetes 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.
*/
// This file was autogenerated by set-gen. Do not edit it manually!
package sets
import (
"reflect"
"sort"
)
// sets.Byte is a set of bytes, implemented via map[byte]struct{} for minimal memory consumption.
type Byte map[byte]Empty
// NewByte creates a Byte from a list of values.
func NewByte(items ...byte) Byte {
ss := Byte{}
ss.Insert(items...)
return ss
}
// ByteKeySet creates a Byte from a keys of a map[byte](? extends interface{}).
// If the value passed in is not actually a map, this will panic.
func ByteKeySet(theMap interface{}) Byte {
v := reflect.ValueOf(theMap)
ret := Byte{}
for _, keyValue := range v.MapKeys() {
ret.Insert(keyValue.Interface().(byte))
}
return ret
}
// Insert adds items to the set.
func (s Byte) Insert(items ...byte) {
for _, item := range items {
s[item] = Empty{}
}
}
// Delete removes all items from the set.
func (s Byte) Delete(items ...byte) {
for _, item := range items {
delete(s, item)
}
}
// Has returns true if and only if item is contained in the set.
func (s Byte) Has(item byte) bool {
_, contained := s[item]
return contained
}
// HasAll returns true if and only if all items are contained in the set.
func (s Byte) HasAll(items ...byte) bool {
for _, item := range items {
if !s.Has(item) {
return false
}
}
return true
}
// HasAny returns true if any items are contained in the set.
func (s Byte) HasAny(items ...byte) bool {
for _, item := range items {
if s.Has(item) {
return true
}
}
return false
}
// Difference returns a set of objects that are not in s2
// For example:
// s1 = {a1, a2, a3}
// s2 = {a1, a2, a4, a5}
// s1.Difference(s2) = {a3}
// s2.Difference(s1) = {a4, a5}
func (s Byte) Difference(s2 Byte) Byte {
result := NewByte()
for key := range s {
if !s2.Has(key) {
result.Insert(key)
}
}
return result
}
// Union returns a new set which includes items in either s1 or s2.
// For example:
// s1 = {a1, a2}
// s2 = {a3, a4}
// s1.Union(s2) = {a1, a2, a3, a4}
// s2.Union(s1) = {a1, a2, a3, a4}
func (s1 Byte) Union(s2 Byte) Byte {
result := NewByte()
for key := range s1 {
result.Insert(key)
}
for key := range s2 {
result.Insert(key)
}
return result
}
// Intersection returns a new set which includes the item in BOTH s1 and s2
// For example:
// s1 = {a1, a2}
// s2 = {a2, a3}
// s1.Intersection(s2) = {a2}
func (s1 Byte) Intersection(s2 Byte) Byte {
var walk, other Byte
result := NewByte()
if s1.Len() < s2.Len() {
walk = s1
other = s2
} else {
walk = s2
other = s1
}
for key := range walk {
if other.Has(key) {
result.Insert(key)
}
}
return result
}
// IsSuperset returns true if and only if s1 is a superset of s2.
func (s1 Byte) IsSuperset(s2 Byte) bool {
for item := range s2 {
if !s1.Has(item) {
return false
}
}
return true
}
// Equal returns true if and only if s1 is equal (as a set) to s2.
// Two sets are equal if their membership is identical.
// (In practice, this means same elements, order doesn't matter)
func (s1 Byte) Equal(s2 Byte) bool {
return len(s1) == len(s2) && s1.IsSuperset(s2)
}
type sortableSliceOfByte []byte
func (s sortableSliceOfByte) Len() int { return len(s) }
func (s sortableSliceOfByte) Less(i, j int) bool { return lessByte(s[i], s[j]) }
func (s sortableSliceOfByte) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
// List returns the contents as a sorted byte slice.
func (s Byte) List() []byte {
res := make(sortableSliceOfByte, 0, len(s))
for key := range s {
res = append(res, key)
}
sort.Sort(res)
return []byte(res)
}
// UnsortedList returns the slice with contents in random order.
func (s Byte) UnsortedList() []byte {
res := make([]byte, 0, len(s))
for key := range s {
res = append(res, key)
}
return res
}
// Returns a single element from the set.
func (s Byte) PopAny() (byte, bool) {
for key := range s {
s.Delete(key)
return key, true
}
var zeroValue byte
return zeroValue, false
}
// Len returns the size of the set.
func (s Byte) Len() int {
return len(s)
}
func lessByte(lhs, rhs byte) bool {
return lhs < rhs
}

View File

@ -1,20 +0,0 @@
/*
Copyright 2017 The Kubernetes 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.
*/
// This file was autogenerated by set-gen. Do not edit it manually!
// Package sets has auto-generated set types.
package sets

View File

@ -1,23 +0,0 @@
/*
Copyright 2017 The Kubernetes 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.
*/
// This file was autogenerated by set-gen. Do not edit it manually!
package sets
// Empty is public since it is used by some internal API objects for conversions between external
// string arrays and internal sets, and conversion logic requires public types today.
type Empty struct{}

View File

@ -1,203 +0,0 @@
/*
Copyright 2017 The Kubernetes 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.
*/
// This file was autogenerated by set-gen. Do not edit it manually!
package sets
import (
"reflect"
"sort"
)
// sets.Int is a set of ints, implemented via map[int]struct{} for minimal memory consumption.
type Int map[int]Empty
// NewInt creates a Int from a list of values.
func NewInt(items ...int) Int {
ss := Int{}
ss.Insert(items...)
return ss
}
// IntKeySet creates a Int from a keys of a map[int](? extends interface{}).
// If the value passed in is not actually a map, this will panic.
func IntKeySet(theMap interface{}) Int {
v := reflect.ValueOf(theMap)
ret := Int{}
for _, keyValue := range v.MapKeys() {
ret.Insert(keyValue.Interface().(int))
}
return ret
}
// Insert adds items to the set.
func (s Int) Insert(items ...int) {
for _, item := range items {
s[item] = Empty{}
}
}
// Delete removes all items from the set.
func (s Int) Delete(items ...int) {
for _, item := range items {
delete(s, item)
}
}
// Has returns true if and only if item is contained in the set.
func (s Int) Has(item int) bool {
_, contained := s[item]
return contained
}
// HasAll returns true if and only if all items are contained in the set.
func (s Int) HasAll(items ...int) bool {
for _, item := range items {
if !s.Has(item) {
return false
}
}
return true
}
// HasAny returns true if any items are contained in the set.
func (s Int) HasAny(items ...int) bool {
for _, item := range items {
if s.Has(item) {
return true
}
}
return false
}
// Difference returns a set of objects that are not in s2
// For example:
// s1 = {a1, a2, a3}
// s2 = {a1, a2, a4, a5}
// s1.Difference(s2) = {a3}
// s2.Difference(s1) = {a4, a5}
func (s Int) Difference(s2 Int) Int {
result := NewInt()
for key := range s {
if !s2.Has(key) {
result.Insert(key)
}
}
return result
}
// Union returns a new set which includes items in either s1 or s2.
// For example:
// s1 = {a1, a2}
// s2 = {a3, a4}
// s1.Union(s2) = {a1, a2, a3, a4}
// s2.Union(s1) = {a1, a2, a3, a4}
func (s1 Int) Union(s2 Int) Int {
result := NewInt()
for key := range s1 {
result.Insert(key)
}
for key := range s2 {
result.Insert(key)
}
return result
}
// Intersection returns a new set which includes the item in BOTH s1 and s2
// For example:
// s1 = {a1, a2}
// s2 = {a2, a3}
// s1.Intersection(s2) = {a2}
func (s1 Int) Intersection(s2 Int) Int {
var walk, other Int
result := NewInt()
if s1.Len() < s2.Len() {
walk = s1
other = s2
} else {
walk = s2
other = s1
}
for key := range walk {
if other.Has(key) {
result.Insert(key)
}
}
return result
}
// IsSuperset returns true if and only if s1 is a superset of s2.
func (s1 Int) IsSuperset(s2 Int) bool {
for item := range s2 {
if !s1.Has(item) {
return false
}
}
return true
}
// Equal returns true if and only if s1 is equal (as a set) to s2.
// Two sets are equal if their membership is identical.
// (In practice, this means same elements, order doesn't matter)
func (s1 Int) Equal(s2 Int) bool {
return len(s1) == len(s2) && s1.IsSuperset(s2)
}
type sortableSliceOfInt []int
func (s sortableSliceOfInt) Len() int { return len(s) }
func (s sortableSliceOfInt) Less(i, j int) bool { return lessInt(s[i], s[j]) }
func (s sortableSliceOfInt) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
// List returns the contents as a sorted int slice.
func (s Int) List() []int {
res := make(sortableSliceOfInt, 0, len(s))
for key := range s {
res = append(res, key)
}
sort.Sort(res)
return []int(res)
}
// UnsortedList returns the slice with contents in random order.
func (s Int) UnsortedList() []int {
res := make([]int, 0, len(s))
for key := range s {
res = append(res, key)
}
return res
}
// Returns a single element from the set.
func (s Int) PopAny() (int, bool) {
for key := range s {
s.Delete(key)
return key, true
}
var zeroValue int
return zeroValue, false
}
// Len returns the size of the set.
func (s Int) Len() int {
return len(s)
}
func lessInt(lhs, rhs int) bool {
return lhs < rhs
}

View File

@ -1,203 +0,0 @@
/*
Copyright 2017 The Kubernetes 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.
*/
// This file was autogenerated by set-gen. Do not edit it manually!
package sets
import (
"reflect"
"sort"
)
// sets.Int64 is a set of int64s, implemented via map[int64]struct{} for minimal memory consumption.
type Int64 map[int64]Empty
// NewInt64 creates a Int64 from a list of values.
func NewInt64(items ...int64) Int64 {
ss := Int64{}
ss.Insert(items...)
return ss
}
// Int64KeySet creates a Int64 from a keys of a map[int64](? extends interface{}).
// If the value passed in is not actually a map, this will panic.
func Int64KeySet(theMap interface{}) Int64 {
v := reflect.ValueOf(theMap)
ret := Int64{}
for _, keyValue := range v.MapKeys() {
ret.Insert(keyValue.Interface().(int64))
}
return ret
}
// Insert adds items to the set.
func (s Int64) Insert(items ...int64) {
for _, item := range items {
s[item] = Empty{}
}
}
// Delete removes all items from the set.
func (s Int64) Delete(items ...int64) {
for _, item := range items {
delete(s, item)
}
}
// Has returns true if and only if item is contained in the set.
func (s Int64) Has(item int64) bool {
_, contained := s[item]
return contained
}
// HasAll returns true if and only if all items are contained in the set.
func (s Int64) HasAll(items ...int64) bool {
for _, item := range items {
if !s.Has(item) {
return false
}
}
return true
}
// HasAny returns true if any items are contained in the set.
func (s Int64) HasAny(items ...int64) bool {
for _, item := range items {
if s.Has(item) {
return true
}
}
return false
}
// Difference returns a set of objects that are not in s2
// For example:
// s1 = {a1, a2, a3}
// s2 = {a1, a2, a4, a5}
// s1.Difference(s2) = {a3}
// s2.Difference(s1) = {a4, a5}
func (s Int64) Difference(s2 Int64) Int64 {
result := NewInt64()
for key := range s {
if !s2.Has(key) {
result.Insert(key)
}
}
return result
}
// Union returns a new set which includes items in either s1 or s2.
// For example:
// s1 = {a1, a2}
// s2 = {a3, a4}
// s1.Union(s2) = {a1, a2, a3, a4}
// s2.Union(s1) = {a1, a2, a3, a4}
func (s1 Int64) Union(s2 Int64) Int64 {
result := NewInt64()
for key := range s1 {
result.Insert(key)
}
for key := range s2 {
result.Insert(key)
}
return result
}
// Intersection returns a new set which includes the item in BOTH s1 and s2
// For example:
// s1 = {a1, a2}
// s2 = {a2, a3}
// s1.Intersection(s2) = {a2}
func (s1 Int64) Intersection(s2 Int64) Int64 {
var walk, other Int64
result := NewInt64()
if s1.Len() < s2.Len() {
walk = s1
other = s2
} else {
walk = s2
other = s1
}
for key := range walk {
if other.Has(key) {
result.Insert(key)
}
}
return result
}
// IsSuperset returns true if and only if s1 is a superset of s2.
func (s1 Int64) IsSuperset(s2 Int64) bool {
for item := range s2 {
if !s1.Has(item) {
return false
}
}
return true
}
// Equal returns true if and only if s1 is equal (as a set) to s2.
// Two sets are equal if their membership is identical.
// (In practice, this means same elements, order doesn't matter)
func (s1 Int64) Equal(s2 Int64) bool {
return len(s1) == len(s2) && s1.IsSuperset(s2)
}
type sortableSliceOfInt64 []int64
func (s sortableSliceOfInt64) Len() int { return len(s) }
func (s sortableSliceOfInt64) Less(i, j int) bool { return lessInt64(s[i], s[j]) }
func (s sortableSliceOfInt64) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
// List returns the contents as a sorted int64 slice.
func (s Int64) List() []int64 {
res := make(sortableSliceOfInt64, 0, len(s))
for key := range s {
res = append(res, key)
}
sort.Sort(res)
return []int64(res)
}
// UnsortedList returns the slice with contents in random order.
func (s Int64) UnsortedList() []int64 {
res := make([]int64, 0, len(s))
for key := range s {
res = append(res, key)
}
return res
}
// Returns a single element from the set.
func (s Int64) PopAny() (int64, bool) {
for key := range s {
s.Delete(key)
return key, true
}
var zeroValue int64
return zeroValue, false
}
// Len returns the size of the set.
func (s Int64) Len() int {
return len(s)
}
func lessInt64(lhs, rhs int64) bool {
return lhs < rhs
}

View File

@ -1,203 +0,0 @@
/*
Copyright 2017 The Kubernetes 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.
*/
// This file was autogenerated by set-gen. Do not edit it manually!
package sets
import (
"reflect"
"sort"
)
// sets.String is a set of strings, implemented via map[string]struct{} for minimal memory consumption.
type String map[string]Empty
// NewString creates a String from a list of values.
func NewString(items ...string) String {
ss := String{}
ss.Insert(items...)
return ss
}
// StringKeySet creates a String from a keys of a map[string](? extends interface{}).
// If the value passed in is not actually a map, this will panic.
func StringKeySet(theMap interface{}) String {
v := reflect.ValueOf(theMap)
ret := String{}
for _, keyValue := range v.MapKeys() {
ret.Insert(keyValue.Interface().(string))
}
return ret
}
// Insert adds items to the set.
func (s String) Insert(items ...string) {
for _, item := range items {
s[item] = Empty{}
}
}
// Delete removes all items from the set.
func (s String) Delete(items ...string) {
for _, item := range items {
delete(s, item)
}
}
// Has returns true if and only if item is contained in the set.
func (s String) Has(item string) bool {
_, contained := s[item]
return contained
}
// HasAll returns true if and only if all items are contained in the set.
func (s String) HasAll(items ...string) bool {
for _, item := range items {
if !s.Has(item) {
return false
}
}
return true
}
// HasAny returns true if any items are contained in the set.
func (s String) HasAny(items ...string) bool {
for _, item := range items {
if s.Has(item) {
return true
}
}
return false
}
// Difference returns a set of objects that are not in s2
// For example:
// s1 = {a1, a2, a3}
// s2 = {a1, a2, a4, a5}
// s1.Difference(s2) = {a3}
// s2.Difference(s1) = {a4, a5}
func (s String) Difference(s2 String) String {
result := NewString()
for key := range s {
if !s2.Has(key) {
result.Insert(key)
}
}
return result
}
// Union returns a new set which includes items in either s1 or s2.
// For example:
// s1 = {a1, a2}
// s2 = {a3, a4}
// s1.Union(s2) = {a1, a2, a3, a4}
// s2.Union(s1) = {a1, a2, a3, a4}
func (s1 String) Union(s2 String) String {
result := NewString()
for key := range s1 {
result.Insert(key)
}
for key := range s2 {
result.Insert(key)
}
return result
}
// Intersection returns a new set which includes the item in BOTH s1 and s2
// For example:
// s1 = {a1, a2}
// s2 = {a2, a3}
// s1.Intersection(s2) = {a2}
func (s1 String) Intersection(s2 String) String {
var walk, other String
result := NewString()
if s1.Len() < s2.Len() {
walk = s1
other = s2
} else {
walk = s2
other = s1
}
for key := range walk {
if other.Has(key) {
result.Insert(key)
}
}
return result
}
// IsSuperset returns true if and only if s1 is a superset of s2.
func (s1 String) IsSuperset(s2 String) bool {
for item := range s2 {
if !s1.Has(item) {
return false
}
}
return true
}
// Equal returns true if and only if s1 is equal (as a set) to s2.
// Two sets are equal if their membership is identical.
// (In practice, this means same elements, order doesn't matter)
func (s1 String) Equal(s2 String) bool {
return len(s1) == len(s2) && s1.IsSuperset(s2)
}
type sortableSliceOfString []string
func (s sortableSliceOfString) Len() int { return len(s) }
func (s sortableSliceOfString) Less(i, j int) bool { return lessString(s[i], s[j]) }
func (s sortableSliceOfString) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
// List returns the contents as a sorted string slice.
func (s String) List() []string {
res := make(sortableSliceOfString, 0, len(s))
for key := range s {
res = append(res, key)
}
sort.Sort(res)
return []string(res)
}
// UnsortedList returns the slice with contents in random order.
func (s String) UnsortedList() []string {
res := make([]string, 0, len(s))
for key := range s {
res = append(res, key)
}
return res
}
// Returns a single element from the set.
func (s String) PopAny() (string, bool) {
for key := range s {
s.Delete(key)
return key, true
}
var zeroValue string
return zeroValue, false
}
// Len returns the size of the set.
func (s String) Len() int {
return len(s)
}
func lessString(lhs, rhs string) bool {
return lhs < rhs
}

View File

@ -1,62 +0,0 @@
/*
Copyright 2015 The Kubernetes 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 generator
import (
"io"
"k8s.io/gengo/namer"
"k8s.io/gengo/types"
)
const (
GolangFileType = "golang"
)
// DefaultGen implements a do-nothing Generator.
//
// It can be used to implement static content files.
type DefaultGen struct {
// OptionalName, if present, will be used for the generator's name, and
// the filename (with ".go" appended).
OptionalName string
// OptionalBody, if present, will be used as the return from the "Init"
// method. This causes it to be static content for the entire file if
// no other generator touches the file.
OptionalBody []byte
}
func (d DefaultGen) Name() string { return d.OptionalName }
func (d DefaultGen) Filter(*Context, *types.Type) bool { return true }
func (d DefaultGen) Namers(*Context) namer.NameSystems { return nil }
func (d DefaultGen) Imports(*Context) []string { return []string{} }
func (d DefaultGen) PackageVars(*Context) []string { return []string{} }
func (d DefaultGen) PackageConsts(*Context) []string { return []string{} }
func (d DefaultGen) GenerateType(*Context, *types.Type, io.Writer) error { return nil }
func (d DefaultGen) Filename() string { return d.OptionalName + ".go" }
func (d DefaultGen) FileType() string { return GolangFileType }
func (d DefaultGen) Finalize(*Context, io.Writer) error { return nil }
func (d DefaultGen) Init(c *Context, w io.Writer) error {
_, err := w.Write(d.OptionalBody)
return err
}
var (
_ = Generator(DefaultGen{})
)

View File

@ -1,72 +0,0 @@
/*
Copyright 2015 The Kubernetes 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 generator
import (
"k8s.io/gengo/types"
)
// DefaultPackage contains a default implementation of Package.
type DefaultPackage struct {
// Short name of package, used in the "package xxxx" line.
PackageName string
// Import path of the package, and the location on disk of the package.
PackagePath string
// Emitted at the top of every file.
HeaderText []byte
// Emitted only for a "doc.go" file; appended to the HeaderText for
// that file.
PackageDocumentation []byte
// If non-nil, will be called on "Generators"; otherwise, the static
// list will be used. So you should set only one of these two fields.
GeneratorFunc func(*Context) []Generator
GeneratorList []Generator
// Optional; filters the types exposed to the generators.
FilterFunc func(*Context, *types.Type) bool
}
func (d *DefaultPackage) Name() string { return d.PackageName }
func (d *DefaultPackage) Path() string { return d.PackagePath }
func (d *DefaultPackage) Filter(c *Context, t *types.Type) bool {
if d.FilterFunc != nil {
return d.FilterFunc(c, t)
}
return true
}
func (d *DefaultPackage) Generators(c *Context) []Generator {
if d.GeneratorFunc != nil {
return d.GeneratorFunc(c)
}
return d.GeneratorList
}
func (d *DefaultPackage) Header(filename string) []byte {
if filename == "doc.go" {
return append(d.HeaderText, d.PackageDocumentation...)
}
return d.HeaderText
}
var (
_ = Package(&DefaultPackage{})
)

31
vendor/k8s.io/gengo/generator/doc.go generated vendored
View File

@ -1,31 +0,0 @@
/*
Copyright 2015 The Kubernetes 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 generator defines an interface for code generators to implement.
//
// To use this package, you'll implement the "Package" and "Generator"
// interfaces; you'll call NewContext to load up the types you want to work
// with, and then you'll call one or more of the Execute methods. See the
// interface definitions for explanations. All output will have gofmt called on
// it automatically, so you do not need to worry about generating correct
// indentation.
//
// This package also exposes SnippetWriter. SnippetWriter reduces to a minimum
// the boilerplate involved in setting up a template from go's text/template
// package. Additionally, all naming systems in the Context will be added as
// functions to the parsed template, so that they can be called directly from
// your templates!
package generator // import "k8s.io/gengo/generator"

View File

@ -1,50 +0,0 @@
/*
Copyright 2015 The Kubernetes 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 generator
import (
"io"
)
// ErrorTracker tracks errors to the underlying writer, so that you can ignore
// them until you're ready to return.
type ErrorTracker struct {
io.Writer
err error
}
// NewErrorTracker makes a new error tracker; note that it implements io.Writer.
func NewErrorTracker(w io.Writer) *ErrorTracker {
return &ErrorTracker{Writer: w}
}
// Write intercepts calls to Write.
func (et *ErrorTracker) Write(p []byte) (n int, err error) {
if et.err != nil {
return 0, et.err
}
n, err = et.Writer.Write(p)
if err != nil {
et.err = err
}
return n, err
}
// Error returns nil if no error has occurred, otherwise it returns the error.
func (et *ErrorTracker) Error() error {
return et.err
}

View File

@ -1,309 +0,0 @@
/*
Copyright 2015 The Kubernetes 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 generator
import (
"bytes"
"fmt"
"go/format"
"io"
"io/ioutil"
"os"
"path/filepath"
"strings"
"k8s.io/gengo/namer"
"k8s.io/gengo/types"
"github.com/golang/glog"
)
func errs2strings(errors []error) []string {
strs := make([]string, len(errors))
for i := range errors {
strs[i] = errors[i].Error()
}
return strs
}
// ExecutePackages runs the generators for every package in 'packages'. 'outDir'
// is the base directory in which to place all the generated packages; it
// should be a physical path on disk, not an import path. e.g.:
// /path/to/home/path/to/gopath/src/
// Each package has its import path already, this will be appended to 'outDir'.
func (c *Context) ExecutePackages(outDir string, packages Packages) error {
var errors []error
for _, p := range packages {
if err := c.ExecutePackage(outDir, p); err != nil {
errors = append(errors, err)
}
}
if len(errors) > 0 {
return fmt.Errorf("some packages had errors:\n%v\n", strings.Join(errs2strings(errors), "\n"))
}
return nil
}
type DefaultFileType struct {
Format func([]byte) ([]byte, error)
Assemble func(io.Writer, *File)
}
func (ft DefaultFileType) AssembleFile(f *File, pathname string) error {
glog.V(2).Infof("Assembling file %q", pathname)
destFile, err := os.Create(pathname)
if err != nil {
return err
}
defer destFile.Close()
b := &bytes.Buffer{}
et := NewErrorTracker(b)
ft.Assemble(et, f)
if et.Error() != nil {
return et.Error()
}
if formatted, err := ft.Format(b.Bytes()); err != nil {
err = fmt.Errorf("unable to format file %q (%v).", pathname, err)
// Write the file anyway, so they can see what's going wrong and fix the generator.
if _, err2 := destFile.Write(b.Bytes()); err2 != nil {
return err2
}
return err
} else {
_, err = destFile.Write(formatted)
return err
}
}
func (ft DefaultFileType) VerifyFile(f *File, pathname string) error {
glog.V(2).Infof("Verifying file %q", pathname)
friendlyName := filepath.Join(f.PackageName, f.Name)
b := &bytes.Buffer{}
et := NewErrorTracker(b)
ft.Assemble(et, f)
if et.Error() != nil {
return et.Error()
}
formatted, err := ft.Format(b.Bytes())
if err != nil {
return fmt.Errorf("unable to format the output for %q: %v", friendlyName, err)
}
existing, err := ioutil.ReadFile(pathname)
if err != nil {
return fmt.Errorf("unable to read file %q for comparison: %v", friendlyName, err)
}
if bytes.Compare(formatted, existing) == 0 {
return nil
}
// Be nice and find the first place where they differ
i := 0
for i < len(formatted) && i < len(existing) && formatted[i] == existing[i] {
i++
}
eDiff, fDiff := existing[i:], formatted[i:]
if len(eDiff) > 100 {
eDiff = eDiff[:100]
}
if len(fDiff) > 100 {
fDiff = fDiff[:100]
}
return fmt.Errorf("output for %q differs; first existing/expected diff: \n %q\n %q", friendlyName, string(eDiff), string(fDiff))
}
func assembleGolangFile(w io.Writer, f *File) {
w.Write(f.Header)
fmt.Fprintf(w, "package %v\n\n", f.PackageName)
if len(f.Imports) > 0 {
fmt.Fprint(w, "import (\n")
// TODO: sort imports like goimports does.
for i := range f.Imports {
if strings.Contains(i, "\"") {
// they included quotes, or are using the
// `name "path/to/pkg"` format.
fmt.Fprintf(w, "\t%s\n", i)
} else {
fmt.Fprintf(w, "\t%q\n", i)
}
}
fmt.Fprint(w, ")\n\n")
}
if f.Vars.Len() > 0 {
fmt.Fprint(w, "var (\n")
w.Write(f.Vars.Bytes())
fmt.Fprint(w, ")\n\n")
}
if f.Consts.Len() > 0 {
fmt.Fprint(w, "const (\n")
w.Write(f.Consts.Bytes())
fmt.Fprint(w, ")\n\n")
}
w.Write(f.Body.Bytes())
}
func NewGolangFile() *DefaultFileType {
return &DefaultFileType{
Format: format.Source,
Assemble: assembleGolangFile,
}
}
// format should be one line only, and not end with \n.
func addIndentHeaderComment(b *bytes.Buffer, format string, args ...interface{}) {
if b.Len() > 0 {
fmt.Fprintf(b, "\n// "+format+"\n", args...)
} else {
fmt.Fprintf(b, "// "+format+"\n", args...)
}
}
func (c *Context) filteredBy(f func(*Context, *types.Type) bool) *Context {
c2 := *c
c2.Order = []*types.Type{}
for _, t := range c.Order {
if f(c, t) {
c2.Order = append(c2.Order, t)
}
}
return &c2
}
// make a new context; inheret c.Namers, but add on 'namers'. In case of a name
// collision, the namer in 'namers' wins.
func (c *Context) addNameSystems(namers namer.NameSystems) *Context {
if namers == nil {
return c
}
c2 := *c
// Copy the existing name systems so we don't corrupt a parent context
c2.Namers = namer.NameSystems{}
for k, v := range c.Namers {
c2.Namers[k] = v
}
for name, namer := range namers {
c2.Namers[name] = namer
}
return &c2
}
// ExecutePackage executes a single package. 'outDir' is the base directory in
// which to place the package; it should be a physical path on disk, not an
// import path. e.g.: '/path/to/home/path/to/gopath/src/' The package knows its
// import path already, this will be appended to 'outDir'.
func (c *Context) ExecutePackage(outDir string, p Package) error {
path := filepath.Join(outDir, p.Path())
glog.V(2).Infof("Processing package %q, disk location %q", p.Name(), path)
// Filter out any types the *package* doesn't care about.
packageContext := c.filteredBy(p.Filter)
os.MkdirAll(path, 0755)
files := map[string]*File{}
for _, g := range p.Generators(packageContext) {
// Filter out types the *generator* doesn't care about.
genContext := packageContext.filteredBy(g.Filter)
// Now add any extra name systems defined by this generator
genContext = genContext.addNameSystems(g.Namers(genContext))
fileType := g.FileType()
if len(fileType) == 0 {
return fmt.Errorf("generator %q must specify a file type", g.Name())
}
f := files[g.Filename()]
if f == nil {
// This is the first generator to reference this file, so start it.
f = &File{
Name: g.Filename(),
FileType: fileType,
PackageName: p.Name(),
Header: p.Header(g.Filename()),
Imports: map[string]struct{}{},
}
files[f.Name] = f
} else {
if f.FileType != g.FileType() {
return fmt.Errorf("file %q already has type %q, but generator %q wants to use type %q", f.Name, f.FileType, g.Name(), g.FileType())
}
}
if vars := g.PackageVars(genContext); len(vars) > 0 {
addIndentHeaderComment(&f.Vars, "Package-wide variables from generator %q.", g.Name())
for _, v := range vars {
if _, err := fmt.Fprintf(&f.Vars, "%s\n", v); err != nil {
return err
}
}
}
if consts := g.PackageConsts(genContext); len(consts) > 0 {
addIndentHeaderComment(&f.Consts, "Package-wide consts from generator %q.", g.Name())
for _, v := range consts {
if _, err := fmt.Fprintf(&f.Consts, "%s\n", v); err != nil {
return err
}
}
}
if err := genContext.executeBody(&f.Body, g); err != nil {
return err
}
if imports := g.Imports(genContext); len(imports) > 0 {
for _, i := range imports {
f.Imports[i] = struct{}{}
}
}
}
var errors []error
for _, f := range files {
finalPath := filepath.Join(path, f.Name)
assembler, ok := c.FileTypes[f.FileType]
if !ok {
return fmt.Errorf("the file type %q registered for file %q does not exist in the context", f.FileType, f.Name)
}
var err error
if c.Verify {
err = assembler.VerifyFile(f, finalPath)
} else {
err = assembler.AssembleFile(f, finalPath)
}
if err != nil {
errors = append(errors, err)
}
}
if len(errors) > 0 {
return fmt.Errorf("errors in package %q:\n%v\n", p.Path(), strings.Join(errs2strings(errors), "\n"))
}
return nil
}
func (c *Context) executeBody(w io.Writer, generator Generator) error {
et := NewErrorTracker(w)
if err := generator.Init(c, et); err != nil {
return err
}
for _, t := range c.Order {
if err := generator.GenerateType(c, t, et); err != nil {
return err
}
}
if err := generator.Finalize(c, et); err != nil {
return err
}
return et.Error()
}

View File

@ -1,219 +0,0 @@
/*
Copyright 2015 The Kubernetes 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 generator
import (
"bytes"
"io"
"k8s.io/gengo/namer"
"k8s.io/gengo/parser"
"k8s.io/gengo/types"
)
// Package contains the contract for generating a package.
type Package interface {
// Name returns the package short name.
Name() string
// Path returns the package import path.
Path() string
// Filter should return true if this package cares about this type.
// Otherwise, this type will be omitted from the type ordering for
// this package.
Filter(*Context, *types.Type) bool
// Header should return a header for the file, including comment markers.
// Useful for copyright notices and doc strings. Include an
// autogeneration notice! Do not include the "package x" line.
Header(filename string) []byte
// Generators returns the list of generators for this package. It is
// allowed for more than one generator to write to the same file.
// A Context is passed in case the list of generators depends on the
// input types.
Generators(*Context) []Generator
}
type File struct {
Name string
FileType string
PackageName string
Header []byte
Imports map[string]struct{}
Vars bytes.Buffer
Consts bytes.Buffer
Body bytes.Buffer
}
type FileType interface {
AssembleFile(f *File, path string) error
VerifyFile(f *File, path string) error
}
// Packages is a list of packages to generate.
type Packages []Package
// Generator is the contract for anything that wants to do auto-generation.
// It's expected that the io.Writers passed to the below functions will be
// ErrorTrackers; this allows implementations to not check for io errors,
// making more readable code.
//
// The call order for the functions that take a Context is:
// 1. Filter() // Subsequent calls see only types that pass this.
// 2. Namers() // Subsequent calls see the namers provided by this.
// 3. PackageVars()
// 4. PackageConsts()
// 5. Init()
// 6. GenerateType() // Called N times, once per type in the context's Order.
// 7. Imports()
//
// You may have multiple generators for the same file.
type Generator interface {
// The name of this generator. Will be included in generated comments.
Name() string
// Filter should return true if this generator cares about this type.
// (otherwise, GenerateType will not be called.)
//
// Filter is called before any of the generator's other functions;
// subsequent calls will get a context with only the types that passed
// this filter.
Filter(*Context, *types.Type) bool
// If this generator needs special namers, return them here. These will
// override the original namers in the context if there is a collision.
// You may return nil if you don't need special names. These names will
// be available in the context passed to the rest of the generator's
// functions.
//
// A use case for this is to return a namer that tracks imports.
Namers(*Context) namer.NameSystems
// Init should write an init function, and any other content that's not
// generated per-type. (It's not intended for generator specific
// initialization! Do that when your Package constructs the
// Generators.)
Init(*Context, io.Writer) error
// Finalize should write finish up functions, and any other content that's not
// generated per-type.
Finalize(*Context, io.Writer) error
// PackageVars should emit an array of variable lines. They will be
// placed in a var ( ... ) block. There's no need to include a leading
// \t or trailing \n.
PackageVars(*Context) []string
// PackageConsts should emit an array of constant lines. They will be
// placed in a const ( ... ) block. There's no need to include a leading
// \t or trailing \n.
PackageConsts(*Context) []string
// GenerateType should emit the code for a particular type.
GenerateType(*Context, *types.Type, io.Writer) error
// Imports should return a list of necessary imports. They will be
// formatted correctly. You do not need to include quotation marks,
// return only the package name; alternatively, you can also return
// imports in the format `name "path/to/pkg"`. Imports will be called
// after Init, PackageVars, PackageConsts, and GenerateType, to allow
// you to keep track of what imports you actually need.
Imports(*Context) []string
// Preferred file name of this generator, not including a path. It is
// allowed for multiple generators to use the same filename, but it's
// up to you to make sure they don't have colliding import names.
// TODO: provide per-file import tracking, removing the requirement
// that generators coordinate..
Filename() string
// A registered file type in the context to generate this file with. If
// the FileType is not found in the context, execution will stop.
FileType() string
}
// Context is global context for individual generators to consume.
type Context struct {
// A map from the naming system to the names for that system. E.g., you
// might have public names and several private naming systems.
Namers namer.NameSystems
// All the types, in case you want to look up something.
Universe types.Universe
// All the user-specified packages. This is after recursive expansion.
Inputs []string
// The canonical ordering of the types (will be filtered by both the
// Package's and Generator's Filter methods).
Order []*types.Type
// A set of types this context can process. If this is empty or nil,
// the default "golang" filetype will be provided.
FileTypes map[string]FileType
// If true, Execute* calls will just verify that the existing output is
// correct. (You may set this after calling NewContext.)
Verify bool
// Allows generators to add packages at runtime.
builder *parser.Builder
}
// NewContext generates a context from the given builder, naming systems, and
// the naming system you wish to construct the canonical ordering from.
func NewContext(b *parser.Builder, nameSystems namer.NameSystems, canonicalOrderName string) (*Context, error) {
universe, err := b.FindTypes()
if err != nil {
return nil, err
}
c := &Context{
Namers: namer.NameSystems{},
Universe: universe,
Inputs: b.FindPackages(),
FileTypes: map[string]FileType{
GolangFileType: NewGolangFile(),
},
builder: b,
}
for name, systemNamer := range nameSystems {
c.Namers[name] = systemNamer
if name == canonicalOrderName {
orderer := namer.Orderer{Namer: systemNamer}
c.Order = orderer.OrderUniverse(universe)
}
}
return c, nil
}
// AddDir adds a Go package to the context. The specified path must be a single
// go package import path. GOPATH, GOROOT, and the location of your go binary
// (`which go`) will all be searched, in the normal Go fashion.
// Deprecated. Please use AddDirectory.
func (ctxt *Context) AddDir(path string) error {
return ctxt.builder.AddDirTo(path, &ctxt.Universe)
}
// AddDirectory adds a Go package to the context. The specified path must be a
// single go package import path. GOPATH, GOROOT, and the location of your go
// binary (`which go`) will all be searched, in the normal Go fashion.
func (ctxt *Context) AddDirectory(path string) (*types.Package, error) {
return ctxt.builder.AddDirectoryTo(path, &ctxt.Universe)
}

View File

@ -1,56 +0,0 @@
/*
Copyright 2015 The Kubernetes 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 generator
import (
"path/filepath"
"strings"
"k8s.io/gengo/namer"
"k8s.io/gengo/types"
)
func NewImportTracker(typesToAdd ...*types.Type) namer.ImportTracker {
tracker := namer.NewDefaultImportTracker(types.Name{})
tracker.IsInvalidType = func(*types.Type) bool { return false }
tracker.LocalName = func(name types.Name) string { return golangTrackerLocalName(&tracker, name) }
tracker.PrintImport = func(path, name string) string { return name + " \"" + path + "\"" }
tracker.AddTypes(typesToAdd...)
return &tracker
}
func golangTrackerLocalName(tracker namer.ImportTracker, t types.Name) string {
path := t.Package
dirs := strings.Split(path, string(filepath.Separator))
for n := len(dirs) - 1; n >= 0; n-- {
// TODO: bikeshed about whether it's more readable to have an
// _, something else, or nothing between directory names.
name := strings.Join(dirs[n:], "_")
// These characters commonly appear in import paths for go
// packages, but aren't legal go names. So we'll sanitize.
name = strings.Replace(name, ".", "_", -1)
name = strings.Replace(name, "-", "_", -1)
if _, found := tracker.PathOf(name); found {
// This name collides with some other package
continue
}
return name
}
panic("can't find import for " + path)
}

View File

@ -1,154 +0,0 @@
/*
Copyright 2015 The Kubernetes 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 generator
import (
"fmt"
"io"
"runtime"
"text/template"
)
// SnippetWriter is an attempt to make the template library usable.
// Methods are chainable, and you don't have to check Error() until you're all
// done.
type SnippetWriter struct {
w io.Writer
context *Context
// Left & right delimiters. text/template defaults to "{{" and "}}"
// which is totally unusable for go code based templates.
left, right string
funcMap template.FuncMap
err error
}
// w is the destination; left and right are the delimiters; @ and $ are both
// reasonable choices.
//
// c is used to make a function for every naming system, to which you can pass
// a type and get the corresponding name.
func NewSnippetWriter(w io.Writer, c *Context, left, right string) *SnippetWriter {
sw := &SnippetWriter{
w: w,
context: c,
left: left,
right: right,
funcMap: template.FuncMap{},
}
for name, namer := range c.Namers {
sw.funcMap[name] = namer.Name
}
return sw
}
// Do parses format and runs args through it. You can have arbitrary logic in
// the format (see the text/template documentation), but consider running many
// short templaces, with ordinary go logic in between--this may be more
// readable. Do is chainable. Any error causes every other call to do to be
// ignored, and the error will be returned by Error(). So you can check it just
// once, at the end of your function.
//
// 'args' can be quite literally anything; read the text/template documentation
// for details. Maps and structs work particularly nicely. Conveniently, the
// types package is designed to have structs that are easily referencable from
// the template language.
//
// Example:
//
// sw := generator.NewSnippetWriter(outBuffer, context, "$", "$")
// sw.Do(`The public type name is: $.type|public$`, map[string]interface{}{"type": t})
// return sw.Error()
//
// Where:
// * "$" starts a template directive
// * "." references the entire thing passed as args
// * "type" therefore sees a map and looks up the key "type"
// * "|" means "pass the thing on the left to the thing on the right"
// * "public" is the name of a naming system, so the SnippetWriter has given
// the template a function called "public" that takes a *types.Type and
// returns the naming system's name. E.g., if the type is "string" this might
// return "String".
// * the second "$" ends the template directive.
//
// The map is actually not necessary. The below does the same thing:
//
// sw.Do(`The public type name is: $.|public$`, t)
//
// You may or may not find it more readable to use the map with a descriptive
// key, but if you want to pass more than one arg, the map or a custom struct
// becomes a requirement. You can do arbitrary logic inside these templates,
// but you should consider doing the logic in go and stitching them together
// for the sake of your readers.
//
// TODO: Change Do() to optionally take a list of pairs of parameters (key, value)
// and have it construct a combined map with that and args.
func (s *SnippetWriter) Do(format string, args interface{}) *SnippetWriter {
if s.err != nil {
return s
}
// Name the template by source file:line so it can be found when
// there's an error.
_, file, line, _ := runtime.Caller(1)
tmpl, err := template.
New(fmt.Sprintf("%s:%d", file, line)).
Delims(s.left, s.right).
Funcs(s.funcMap).
Parse(format)
if err != nil {
s.err = err
return s
}
err = tmpl.Execute(s.w, args)
if err != nil {
s.err = err
}
return s
}
// Args exists to make it convenient to construct arguments for
// SnippetWriter.Do.
type Args map[interface{}]interface{}
// With makes a copy of a and adds the given key, value pair.
func (a Args) With(key, value interface{}) Args {
a2 := Args{key: value}
for k, v := range a {
a2[k] = v
}
return a2
}
// WithArgs makes a copy of a and adds the given arguments.
func (a Args) WithArgs(rhs Args) Args {
a2 := Args{}
for k, v := range rhs {
a2[k] = v
}
for k, v := range a {
a2[k] = v
}
return a2
}
func (s *SnippetWriter) Out() io.Writer {
return s.w
}
// Error returns any encountered error.
func (s *SnippetWriter) Error() error {
return s.err
}

31
vendor/k8s.io/gengo/namer/doc.go generated vendored
View File

@ -1,31 +0,0 @@
/*
Copyright 2015 The Kubernetes 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 namer has support for making different type naming systems.
//
// This is because sometimes you want to refer to the literal type, sometimes
// you want to make a name for the thing you're generating, and you want to
// make the name based on the type. For example, if you have `type foo string`,
// you want to be able to generate something like `func FooPrinter(f *foo) {
// Print(string(*f)) }`; that is, you want to refer to a public name, a literal
// name, and the underlying literal name.
//
// This package supports the idea of a "Namer" and a set of "NameSystems" to
// support these use cases.
//
// Additionally, a "RawNamer" can optionally keep track of what needs to be
// imported.
package namer // import "k8s.io/gengo/namer"

View File

@ -1,112 +0,0 @@
/*
Copyright 2015 The Kubernetes 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 namer
import (
"sort"
"k8s.io/gengo/types"
)
// ImportTracker may be passed to a namer.RawNamer, to track the imports needed
// for the types it names.
//
// TODO: pay attention to the package name (instead of renaming every package).
type DefaultImportTracker struct {
pathToName map[string]string
// forbidden names are in here. (e.g. "go" is a directory in which
// there is code, but "go" is not a legal name for a package, so we put
// it here to prevent us from naming any package "go")
nameToPath map[string]string
local types.Name
// Returns true if a given types is an invalid type and should be ignored.
IsInvalidType func(*types.Type) bool
// Returns the final local name for the given name
LocalName func(types.Name) string
// Returns the "import" line for a given (path, name).
PrintImport func(string, string) string
}
func NewDefaultImportTracker(local types.Name) DefaultImportTracker {
return DefaultImportTracker{
pathToName: map[string]string{},
nameToPath: map[string]string{},
local: local,
}
}
func (tracker *DefaultImportTracker) AddTypes(types ...*types.Type) {
for _, t := range types {
tracker.AddType(t)
}
}
func (tracker *DefaultImportTracker) AddType(t *types.Type) {
if tracker.local.Package == t.Name.Package {
return
}
if tracker.IsInvalidType(t) {
if t.Kind == types.Builtin {
return
}
if _, ok := tracker.nameToPath[t.Name.Package]; !ok {
tracker.nameToPath[t.Name.Package] = ""
}
return
}
if len(t.Name.Package) == 0 {
return
}
path := t.Name.Path
if len(path) == 0 {
path = t.Name.Package
}
if _, ok := tracker.pathToName[path]; ok {
return
}
name := tracker.LocalName(t.Name)
tracker.nameToPath[name] = path
tracker.pathToName[path] = name
}
func (tracker *DefaultImportTracker) ImportLines() []string {
importPaths := []string{}
for path := range tracker.pathToName {
importPaths = append(importPaths, path)
}
sort.Sort(sort.StringSlice(importPaths))
out := []string{}
for _, path := range importPaths {
out = append(out, tracker.PrintImport(path, tracker.pathToName[path]))
}
return out
}
// LocalNameOf returns the name you would use to refer to the package at the
// specified path within the body of a file.
func (tracker *DefaultImportTracker) LocalNameOf(path string) string {
return tracker.pathToName[path]
}
// PathOf returns the path that a given localName is referring to within the
// body of a file.
func (tracker *DefaultImportTracker) PathOf(localName string) (string, bool) {
name, ok := tracker.nameToPath[localName]
return name, ok
}

372
vendor/k8s.io/gengo/namer/namer.go generated vendored
View File

@ -1,372 +0,0 @@
/*
Copyright 2015 The Kubernetes 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 namer
import (
"path/filepath"
"strings"
"k8s.io/gengo/types"
)
// Returns whether a name is a private Go name.
func IsPrivateGoName(name string) bool {
return len(name) == 0 || strings.ToLower(name[:1]) == name[:1]
}
// NewPublicNamer is a helper function that returns a namer that makes
// CamelCase names. See the NameStrategy struct for an explanation of the
// arguments to this constructor.
func NewPublicNamer(prependPackageNames int, ignoreWords ...string) *NameStrategy {
n := &NameStrategy{
Join: Joiner(IC, IC),
IgnoreWords: map[string]bool{},
PrependPackageNames: prependPackageNames,
}
for _, w := range ignoreWords {
n.IgnoreWords[w] = true
}
return n
}
// NewPrivateNamer is a helper function that returns a namer that makes
// camelCase names. See the NameStrategy struct for an explanation of the
// arguments to this constructor.
func NewPrivateNamer(prependPackageNames int, ignoreWords ...string) *NameStrategy {
n := &NameStrategy{
Join: Joiner(IL, IC),
IgnoreWords: map[string]bool{},
PrependPackageNames: prependPackageNames,
}
for _, w := range ignoreWords {
n.IgnoreWords[w] = true
}
return n
}
// NewRawNamer will return a Namer that makes a name by which you would
// directly refer to a type, optionally keeping track of the import paths
// necessary to reference the names it provides. Tracker may be nil.
// The 'pkg' is the full package name, in which the Namer is used - all
// types from that package will be referenced by just type name without
// referencing the package.
//
// For example, if the type is map[string]int, a raw namer will literally
// return "map[string]int".
//
// Or if the type, in package foo, is "type Bar struct { ... }", then the raw
// namer will return "foo.Bar" as the name of the type, and if 'tracker' was
// not nil, will record that package foo needs to be imported.
func NewRawNamer(pkg string, tracker ImportTracker) *rawNamer {
return &rawNamer{pkg: pkg, tracker: tracker}
}
// Names is a map from Type to name, as defined by some Namer.
type Names map[*types.Type]string
// Namer takes a type, and assigns a name.
//
// The purpose of this complexity is so that you can assign coherent
// side-by-side systems of names for the types. For example, you might want a
// public interface, a private implementation struct, and also to reference
// literally the type name.
//
// Note that it is safe to call your own Name() function recursively to find
// the names of keys, elements, etc. This is because anonymous types can't have
// cycles in their names, and named types don't require the sort of recursion
// that would be problematic.
type Namer interface {
Name(*types.Type) string
}
// NameSystems is a map of a system name to a namer for that system.
type NameSystems map[string]Namer
// NameStrategy is a general Namer. The easiest way to use it is to copy the
// Public/PrivateNamer variables, and modify the members you wish to change.
//
// The Name method produces a name for the given type, of the forms:
// Anonymous types: <Prefix><Type description><Suffix>
// Named types: <Prefix><Optional Prepended Package name(s)><Original name><Suffix>
//
// In all cases, every part of the name is run through the capitalization
// functions.
//
// The IgnoreWords map can be set if you have directory names that are
// semantically meaningless for naming purposes, e.g. "proto".
//
// Prefix and Suffix can be used to disambiguate parallel systems of type
// names. For example, if you want to generate an interface and an
// implementation, you might want to suffix one with "Interface" and the other
// with "Implementation". Another common use-- if you want to generate private
// types, and one of your source types could be "string", you can't use the
// default lowercase private namer. You'll have to add a suffix or prefix.
type NameStrategy struct {
Prefix, Suffix string
Join func(pre string, parts []string, post string) string
// Add non-meaningful package directory names here (e.g. "proto") and
// they will be ignored.
IgnoreWords map[string]bool
// If > 0, prepend exactly that many package directory names (or as
// many as there are). Package names listed in "IgnoreWords" will be
// ignored.
//
// For example, if Ignore words lists "proto" and type Foo is in
// pkg/server/frobbing/proto, then a value of 1 will give a type name
// of FrobbingFoo, 2 gives ServerFrobbingFoo, etc.
PrependPackageNames int
// A cache of names thus far assigned by this namer.
Names
}
// IC ensures the first character is uppercase.
func IC(in string) string {
if in == "" {
return in
}
return strings.ToUpper(in[:1]) + in[1:]
}
// IL ensures the first character is lowercase.
func IL(in string) string {
if in == "" {
return in
}
return strings.ToLower(in[:1]) + in[1:]
}
// Joiner lets you specify functions that preprocess the various components of
// a name before joining them. You can construct e.g. camelCase or CamelCase or
// any other way of joining words. (See the IC and IL convenience functions.)
func Joiner(first, others func(string) string) func(pre string, in []string, post string) string {
return func(pre string, in []string, post string) string {
tmp := []string{others(pre)}
for i := range in {
tmp = append(tmp, others(in[i]))
}
tmp = append(tmp, others(post))
return first(strings.Join(tmp, ""))
}
}
func (ns *NameStrategy) removePrefixAndSuffix(s string) string {
// The join function may have changed capitalization.
lowerIn := strings.ToLower(s)
lowerP := strings.ToLower(ns.Prefix)
lowerS := strings.ToLower(ns.Suffix)
b, e := 0, len(s)
if strings.HasPrefix(lowerIn, lowerP) {
b = len(ns.Prefix)
}
if strings.HasSuffix(lowerIn, lowerS) {
e -= len(ns.Suffix)
}
return s[b:e]
}
var (
importPathNameSanitizer = strings.NewReplacer("-", "_", ".", "")
)
// filters out unwanted directory names and sanitizes remaining names.
func (ns *NameStrategy) filterDirs(path string) []string {
allDirs := strings.Split(path, string(filepath.Separator))
dirs := make([]string, 0, len(allDirs))
for _, p := range allDirs {
if ns.IgnoreWords == nil || !ns.IgnoreWords[p] {
dirs = append(dirs, importPathNameSanitizer.Replace(p))
}
}
return dirs
}
// See the comment on NameStrategy.
func (ns *NameStrategy) Name(t *types.Type) string {
if ns.Names == nil {
ns.Names = Names{}
}
if s, ok := ns.Names[t]; ok {
return s
}
if t.Name.Package != "" {
dirs := append(ns.filterDirs(t.Name.Package), t.Name.Name)
i := ns.PrependPackageNames + 1
dn := len(dirs)
if i > dn {
i = dn
}
name := ns.Join(ns.Prefix, dirs[dn-i:], ns.Suffix)
ns.Names[t] = name
return name
}
// Only anonymous types remain.
var name string
switch t.Kind {
case types.Builtin:
name = ns.Join(ns.Prefix, []string{t.Name.Name}, ns.Suffix)
case types.Map:
name = ns.Join(ns.Prefix, []string{
"Map",
ns.removePrefixAndSuffix(ns.Name(t.Key)),
"To",
ns.removePrefixAndSuffix(ns.Name(t.Elem)),
}, ns.Suffix)
case types.Slice:
name = ns.Join(ns.Prefix, []string{
"Slice",
ns.removePrefixAndSuffix(ns.Name(t.Elem)),
}, ns.Suffix)
case types.Pointer:
name = ns.Join(ns.Prefix, []string{
"Pointer",
ns.removePrefixAndSuffix(ns.Name(t.Elem)),
}, ns.Suffix)
case types.Struct:
names := []string{"Struct"}
for _, m := range t.Members {
names = append(names, ns.removePrefixAndSuffix(ns.Name(m.Type)))
}
name = ns.Join(ns.Prefix, names, ns.Suffix)
case types.Chan:
name = ns.Join(ns.Prefix, []string{
"Chan",
ns.removePrefixAndSuffix(ns.Name(t.Elem)),
}, ns.Suffix)
case types.Interface:
// TODO: add to name test
names := []string{"Interface"}
for _, m := range t.Methods {
// TODO: include function signature
names = append(names, m.Name.Name)
}
name = ns.Join(ns.Prefix, names, ns.Suffix)
case types.Func:
// TODO: add to name test
parts := []string{"Func"}
for _, pt := range t.Signature.Parameters {
parts = append(parts, ns.removePrefixAndSuffix(ns.Name(pt)))
}
parts = append(parts, "Returns")
for _, rt := range t.Signature.Results {
parts = append(parts, ns.removePrefixAndSuffix(ns.Name(rt)))
}
name = ns.Join(ns.Prefix, parts, ns.Suffix)
default:
name = "unnameable_" + string(t.Kind)
}
ns.Names[t] = name
return name
}
// ImportTracker allows a raw namer to keep track of the packages needed for
// import. You can implement yourself or use the one in the generation package.
type ImportTracker interface {
AddType(*types.Type)
LocalNameOf(packagePath string) string
PathOf(localName string) (string, bool)
ImportLines() []string
}
type rawNamer struct {
pkg string
tracker ImportTracker
Names
}
// Name makes a name the way you'd write it to literally refer to type t,
// making ordinary assumptions about how you've imported t's package (or using
// r.tracker to specifically track the package imports).
func (r *rawNamer) Name(t *types.Type) string {
if r.Names == nil {
r.Names = Names{}
}
if name, ok := r.Names[t]; ok {
return name
}
if t.Name.Package != "" {
var name string
if r.tracker != nil {
r.tracker.AddType(t)
if t.Name.Package == r.pkg {
name = t.Name.Name
} else {
name = r.tracker.LocalNameOf(t.Name.Package) + "." + t.Name.Name
}
} else {
if t.Name.Package == r.pkg {
name = t.Name.Name
} else {
name = filepath.Base(t.Name.Package) + "." + t.Name.Name
}
}
r.Names[t] = name
return name
}
var name string
switch t.Kind {
case types.Builtin:
name = t.Name.Name
case types.Map:
name = "map[" + r.Name(t.Key) + "]" + r.Name(t.Elem)
case types.Slice:
name = "[]" + r.Name(t.Elem)
case types.Pointer:
name = "*" + r.Name(t.Elem)
case types.Struct:
elems := []string{}
for _, m := range t.Members {
elems = append(elems, m.Name+" "+r.Name(m.Type))
}
name = "struct{" + strings.Join(elems, "; ") + "}"
case types.Chan:
// TODO: include directionality
name = "chan " + r.Name(t.Elem)
case types.Interface:
// TODO: add to name test
elems := []string{}
for _, m := range t.Methods {
// TODO: include function signature
elems = append(elems, m.Name.Name)
}
name = "interface{" + strings.Join(elems, "; ") + "}"
case types.Func:
// TODO: add to name test
params := []string{}
for _, pt := range t.Signature.Parameters {
params = append(params, r.Name(pt))
}
results := []string{}
for _, rt := range t.Signature.Results {
results = append(results, r.Name(rt))
}
name = "func(" + strings.Join(params, ",") + ")"
if len(results) == 1 {
name += " " + results[0]
} else if len(results) > 1 {
name += " (" + strings.Join(results, ",") + ")"
}
default:
name = "unnameable_" + string(t.Kind)
}
r.Names[t] = name
return name
}

69
vendor/k8s.io/gengo/namer/order.go generated vendored
View File

@ -1,69 +0,0 @@
/*
Copyright 2015 The Kubernetes 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 namer
import (
"sort"
"k8s.io/gengo/types"
)
// Orderer produces an ordering of types given a Namer.
type Orderer struct {
Namer
}
// OrderUniverse assigns a name to every type in the Universe, including Types,
// Functions and Variables, and returns a list sorted by those names.
func (o *Orderer) OrderUniverse(u types.Universe) []*types.Type {
list := tList{
namer: o.Namer,
}
for _, p := range u {
for _, t := range p.Types {
list.types = append(list.types, t)
}
for _, f := range p.Functions {
list.types = append(list.types, f)
}
for _, v := range p.Variables {
list.types = append(list.types, v)
}
}
sort.Sort(list)
return list.types
}
// OrderTypes assigns a name to every type, and returns a list sorted by those
// names.
func (o *Orderer) OrderTypes(typeList []*types.Type) []*types.Type {
list := tList{
namer: o.Namer,
types: typeList,
}
sort.Sort(list)
return list.types
}
type tList struct {
namer Namer
types []*types.Type
}
func (t tList) Len() int { return len(t.types) }
func (t tList) Less(i, j int) bool { return t.namer.Name(t.types[i]) < t.namer.Name(t.types[j]) }
func (t tList) Swap(i, j int) { t.types[i], t.types[j] = t.types[j], t.types[i] }

View File

@ -1,68 +0,0 @@
/*
Copyright 2015 The Kubernetes 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 namer
import (
"strings"
"k8s.io/gengo/types"
)
type pluralNamer struct {
// key is the case-sensitive type name, value is the case-insensitive
// intended output.
exceptions map[string]string
finalize func(string) string
}
// NewPublicPluralNamer returns a namer that returns the plural form of the input
// type's name, starting with a uppercase letter.
func NewPublicPluralNamer(exceptions map[string]string) *pluralNamer {
return &pluralNamer{exceptions, IC}
}
// NewPrivatePluralNamer returns a namer that returns the plural form of the input
// type's name, starting with a lowercase letter.
func NewPrivatePluralNamer(exceptions map[string]string) *pluralNamer {
return &pluralNamer{exceptions, IL}
}
// NewAllLowercasePluralNamer returns a namer that returns the plural form of the input
// type's name, with all letters in lowercase.
func NewAllLowercasePluralNamer(exceptions map[string]string) *pluralNamer {
return &pluralNamer{exceptions, strings.ToLower}
}
// Name returns the plural form of the type's name. If the type's name is found
// in the exceptions map, the map value is returned.
func (r *pluralNamer) Name(t *types.Type) string {
singular := t.Name.Name
var plural string
var ok bool
if plural, ok = r.exceptions[singular]; ok {
return r.finalize(plural)
}
switch string(singular[len(singular)-1]) {
case "s", "x":
plural = singular + "es"
case "y":
plural = singular[:len(singular)-1] + "ies"
default:
plural = singular + "s"
}
return r.finalize(plural)
}

19
vendor/k8s.io/gengo/parser/doc.go generated vendored
View File

@ -1,19 +0,0 @@
/*
Copyright 2015 The Kubernetes 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 parser provides code to parse go files, type-check them, extract the
// types.
package parser // import "k8s.io/gengo/parser"

812
vendor/k8s.io/gengo/parser/parse.go generated vendored
View File

@ -1,812 +0,0 @@
/*
Copyright 2015 The Kubernetes 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 parser
import (
"fmt"
"go/ast"
"go/build"
"go/parser"
"go/token"
tc "go/types"
"io/ioutil"
"os"
"os/exec"
"path/filepath"
"sort"
"strings"
"github.com/golang/glog"
"k8s.io/gengo/types"
)
// This clarifies when a pkg path has been canonicalized.
type importPathString string
// Builder lets you add all the go files in all the packages that you care
// about, then constructs the type source data.
type Builder struct {
context *build.Context
// Map of package names to more canonical information about the package.
// This might hold the same value for multiple names, e.g. if someone
// referenced ./pkg/name or in the case of vendoring, which canonicalizes
// differently that what humans would type.
buildPackages map[string]*build.Package
fset *token.FileSet
// map of package path to list of parsed files
parsed map[importPathString][]parsedFile
// map of package path to absolute path (to prevent overlap)
absPaths map[importPathString]string
// Set by typeCheckPackage(), used by importPackage() and friends.
typeCheckedPackages map[importPathString]*tc.Package
// Map of package path to whether the user requested it or it was from
// an import.
userRequested map[importPathString]bool
// All comments from everywhere in every parsed file.
endLineToCommentGroup map[fileLine]*ast.CommentGroup
// map of package to list of packages it imports.
importGraph map[importPathString]map[string]struct{}
}
// parsedFile is for tracking files with name
type parsedFile struct {
name string
file *ast.File
}
// key type for finding comments.
type fileLine struct {
file string
line int
}
// New constructs a new builder.
func New() *Builder {
c := build.Default
if c.GOROOT == "" {
if p, err := exec.Command("which", "go").CombinedOutput(); err == nil {
// The returned string will have some/path/bin/go, so remove the last two elements.
c.GOROOT = filepath.Dir(filepath.Dir(strings.Trim(string(p), "\n")))
} else {
glog.Warningf("Warning: $GOROOT not set, and unable to run `which go` to find it: %v\n", err)
}
}
// Force this to off, since we don't properly parse CGo. All symbols must
// have non-CGo equivalents.
c.CgoEnabled = false
return &Builder{
context: &c,
buildPackages: map[string]*build.Package{},
typeCheckedPackages: map[importPathString]*tc.Package{},
fset: token.NewFileSet(),
parsed: map[importPathString][]parsedFile{},
absPaths: map[importPathString]string{},
userRequested: map[importPathString]bool{},
endLineToCommentGroup: map[fileLine]*ast.CommentGroup{},
importGraph: map[importPathString]map[string]struct{}{},
}
}
// AddBuildTags adds the specified build tags to the parse context.
func (b *Builder) AddBuildTags(tags ...string) {
b.context.BuildTags = append(b.context.BuildTags, tags...)
}
// Get package information from the go/build package. Automatically excludes
// e.g. test files and files for other platforms-- there is quite a bit of
// logic of that nature in the build package.
func (b *Builder) importBuildPackage(dir string) (*build.Package, error) {
if buildPkg, ok := b.buildPackages[dir]; ok {
return buildPkg, nil
}
// This validates the `package foo // github.com/bar/foo` comments.
buildPkg, err := b.importWithMode(dir, build.ImportComment)
if err != nil {
if _, ok := err.(*build.NoGoError); !ok {
return nil, fmt.Errorf("unable to import %q: %v", dir, err)
}
}
if buildPkg == nil {
// Might be an empty directory. Try to just find the dir.
buildPkg, err = b.importWithMode(dir, build.FindOnly)
if err != nil {
return nil, err
}
}
// Remember it under the user-provided name.
glog.V(5).Infof("saving buildPackage %s", dir)
b.buildPackages[dir] = buildPkg
canonicalPackage := canonicalizeImportPath(buildPkg.ImportPath)
if dir != string(canonicalPackage) {
// Since `dir` is not the canonical name, see if we knew it under another name.
if buildPkg, ok := b.buildPackages[string(canonicalPackage)]; ok {
return buildPkg, nil
}
// Must be new, save it under the canonical name, too.
glog.V(5).Infof("saving buildPackage %s", canonicalPackage)
b.buildPackages[string(canonicalPackage)] = buildPkg
}
return buildPkg, nil
}
// AddFileForTest adds a file to the set, without verifying that the provided
// pkg actually exists on disk. The pkg must be of the form "canonical/pkg/path"
// and the path must be the absolute path to the file. Because this bypasses
// the normal recursive finding of package dependencies (on disk), test should
// sort their test files topologically first, so all deps are resolved by the
// time we need them.
func (b *Builder) AddFileForTest(pkg string, path string, src []byte) error {
if err := b.addFile(importPathString(pkg), path, src, true); err != nil {
return err
}
if _, err := b.typeCheckPackage(importPathString(pkg)); err != nil {
return err
}
return nil
}
// addFile adds a file to the set. The pkgPath must be of the form
// "canonical/pkg/path" and the path must be the absolute path to the file. A
// flag indicates whether this file was user-requested or just from following
// the import graph.
func (b *Builder) addFile(pkgPath importPathString, path string, src []byte, userRequested bool) error {
for _, p := range b.parsed[pkgPath] {
if path == p.name {
glog.V(5).Infof("addFile %s %s already parsed, skipping", pkgPath, path)
return nil
}
}
glog.V(6).Infof("addFile %s %s", pkgPath, path)
p, err := parser.ParseFile(b.fset, path, src, parser.DeclarationErrors|parser.ParseComments)
if err != nil {
return err
}
// This is redundant with addDir, but some tests call AddFileForTest, which
// call into here without calling addDir.
b.userRequested[pkgPath] = userRequested || b.userRequested[pkgPath]
b.parsed[pkgPath] = append(b.parsed[pkgPath], parsedFile{path, p})
for _, c := range p.Comments {
position := b.fset.Position(c.End())
b.endLineToCommentGroup[fileLine{position.Filename, position.Line}] = c
}
// We have to get the packages from this specific file, in case the
// user added individual files instead of entire directories.
if b.importGraph[pkgPath] == nil {
b.importGraph[pkgPath] = map[string]struct{}{}
}
for _, im := range p.Imports {
importedPath := strings.Trim(im.Path.Value, `"`)
b.importGraph[pkgPath][importedPath] = struct{}{}
}
return nil
}
// AddDir adds an entire directory, scanning it for go files. 'dir' should have
// a single go package in it. GOPATH, GOROOT, and the location of your go
// binary (`which go`) will all be searched if dir doesn't literally resolve.
func (b *Builder) AddDir(dir string) error {
_, err := b.importPackage(dir, true)
return err
}
// AddDirRecursive is just like AddDir, but it also recursively adds
// subdirectories; it returns an error only if the path couldn't be resolved;
// any directories recursed into without go source are ignored.
func (b *Builder) AddDirRecursive(dir string) error {
// Add the root.
if _, err := b.importPackage(dir, true); err != nil {
glog.Warningf("Ignoring directory %v: %v", dir, err)
}
// filepath.Walk includes the root dir, but we already did that, so we'll
// remove that prefix and rebuild a package import path.
prefix := b.buildPackages[dir].Dir
fn := func(path string, info os.FileInfo, err error) error {
if info != nil && info.IsDir() {
rel := strings.TrimPrefix(path, prefix)
if rel != "" {
// Make a pkg path.
pkg := filepath.Join(string(canonicalizeImportPath(b.buildPackages[dir].ImportPath)), rel)
// Add it.
if _, err := b.importPackage(pkg, true); err != nil {
glog.Warningf("Ignoring child directory %v: %v", pkg, err)
}
}
}
return nil
}
if err := filepath.Walk(b.buildPackages[dir].Dir, fn); err != nil {
return err
}
return nil
}
// AddDirTo adds an entire directory to a given Universe. Unlike AddDir, this
// processes the package immediately, which makes it safe to use from within a
// generator (rather than just at init time. 'dir' must be a single go package.
// GOPATH, GOROOT, and the location of your go binary (`which go`) will all be
// searched if dir doesn't literally resolve.
// Deprecated. Please use AddDirectoryTo.
func (b *Builder) AddDirTo(dir string, u *types.Universe) error {
// We want all types from this package, as if they were directly added
// by the user. They WERE added by the user, in effect.
if _, err := b.importPackage(dir, true); err != nil {
return err
}
return b.findTypesIn(canonicalizeImportPath(b.buildPackages[dir].ImportPath), u)
}
// AddDirectoryTo adds an entire directory to a given Universe. Unlike AddDir,
// this processes the package immediately, which makes it safe to use from
// within a generator (rather than just at init time. 'dir' must be a single go
// package. GOPATH, GOROOT, and the location of your go binary (`which go`)
// will all be searched if dir doesn't literally resolve.
func (b *Builder) AddDirectoryTo(dir string, u *types.Universe) (*types.Package, error) {
// We want all types from this package, as if they were directly added
// by the user. They WERE added by the user, in effect.
if _, err := b.importPackage(dir, true); err != nil {
return nil, err
}
path := canonicalizeImportPath(b.buildPackages[dir].ImportPath)
if err := b.findTypesIn(path, u); err != nil {
return nil, err
}
return u.Package(string(path)), nil
}
// The implementation of AddDir. A flag indicates whether this directory was
// user-requested or just from following the import graph.
func (b *Builder) addDir(dir string, userRequested bool) error {
glog.V(5).Infof("addDir %s", dir)
buildPkg, err := b.importBuildPackage(dir)
if err != nil {
return err
}
canonicalPackage := canonicalizeImportPath(buildPkg.ImportPath)
pkgPath := canonicalPackage
if dir != string(canonicalPackage) {
glog.V(5).Infof("addDir %s, canonical path is %s", dir, pkgPath)
}
// Sanity check the pkg dir has not changed.
if prev, found := b.absPaths[pkgPath]; found {
if buildPkg.Dir != prev {
return fmt.Errorf("package %q (%s) previously resolved to %s", pkgPath, buildPkg.Dir, prev)
}
} else {
b.absPaths[pkgPath] = buildPkg.Dir
}
for _, n := range buildPkg.GoFiles {
if !strings.HasSuffix(n, ".go") {
continue
}
absPath := filepath.Join(buildPkg.Dir, n)
data, err := ioutil.ReadFile(absPath)
if err != nil {
return fmt.Errorf("while loading %q: %v", absPath, err)
}
err = b.addFile(pkgPath, absPath, data, userRequested)
if err != nil {
return fmt.Errorf("while parsing %q: %v", absPath, err)
}
}
return nil
}
// importPackage is a function that will be called by the type check package when it
// needs to import a go package. 'path' is the import path.
func (b *Builder) importPackage(dir string, userRequested bool) (*tc.Package, error) {
glog.V(5).Infof("importPackage %s", dir)
var pkgPath = importPathString(dir)
// Get the canonical path if we can.
if buildPkg := b.buildPackages[dir]; buildPkg != nil {
canonicalPackage := canonicalizeImportPath(buildPkg.ImportPath)
glog.V(5).Infof("importPackage %s, canonical path is %s", dir, canonicalPackage)
pkgPath = canonicalPackage
}
// If we have not seen this before, process it now.
ignoreError := false
if _, found := b.parsed[pkgPath]; !found {
// Ignore errors in paths that we're importing solely because
// they're referenced by other packages.
ignoreError = true
// Add it.
if err := b.addDir(dir, userRequested); err != nil {
return nil, err
}
// Get the canonical path now that it has been added.
if buildPkg := b.buildPackages[dir]; buildPkg != nil {
canonicalPackage := canonicalizeImportPath(buildPkg.ImportPath)
glog.V(5).Infof("importPackage %s, canonical path is %s", dir, canonicalPackage)
pkgPath = canonicalPackage
}
}
// If it was previously known, just check that the user-requestedness hasn't
// changed.
b.userRequested[pkgPath] = userRequested || b.userRequested[pkgPath]
// Run the type checker. We may end up doing this to pkgs that are already
// done, or are in the queue to be done later, but it will short-circuit,
// and we can't miss pkgs that are only depended on.
pkg, err := b.typeCheckPackage(pkgPath)
if err != nil {
switch {
case ignoreError && pkg != nil:
glog.V(2).Infof("type checking encountered some issues in %q, but ignoring.\n", pkgPath)
case !ignoreError && pkg != nil:
glog.V(2).Infof("type checking encountered some errors in %q\n", pkgPath)
return nil, err
default:
return nil, err
}
}
return pkg, nil
}
type importAdapter struct {
b *Builder
}
func (a importAdapter) Import(path string) (*tc.Package, error) {
return a.b.importPackage(path, false)
}
// typeCheckPackage will attempt to return the package even if there are some
// errors, so you may check whether the package is nil or not even if you get
// an error.
func (b *Builder) typeCheckPackage(pkgPath importPathString) (*tc.Package, error) {
glog.V(5).Infof("typeCheckPackage %s", pkgPath)
if pkg, ok := b.typeCheckedPackages[pkgPath]; ok {
if pkg != nil {
glog.V(6).Infof("typeCheckPackage %s already done", pkgPath)
return pkg, nil
}
// We store a nil right before starting work on a package. So
// if we get here and it's present and nil, that means there's
// another invocation of this function on the call stack
// already processing this package.
return nil, fmt.Errorf("circular dependency for %q", pkgPath)
}
parsedFiles, ok := b.parsed[pkgPath]
if !ok {
return nil, fmt.Errorf("No files for pkg %q: %#v", pkgPath, b.parsed)
}
files := make([]*ast.File, len(parsedFiles))
for i := range parsedFiles {
files[i] = parsedFiles[i].file
}
b.typeCheckedPackages[pkgPath] = nil
c := tc.Config{
IgnoreFuncBodies: true,
// Note that importAdapter can call b.importPackage which calls this
// method. So there can't be cycles in the import graph.
Importer: importAdapter{b},
Error: func(err error) {
glog.V(2).Infof("type checker: %v\n", err)
},
}
pkg, err := c.Check(string(pkgPath), b.fset, files, nil)
b.typeCheckedPackages[pkgPath] = pkg // record the result whether or not there was an error
return pkg, err
}
// FindPackages fetches a list of the user-imported packages.
// Note that you need to call b.FindTypes() first.
func (b *Builder) FindPackages() []string {
// Iterate packages in a predictable order.
pkgPaths := []string{}
for k := range b.typeCheckedPackages {
pkgPaths = append(pkgPaths, string(k))
}
sort.Strings(pkgPaths)
result := []string{}
for _, pkgPath := range pkgPaths {
if b.userRequested[importPathString(pkgPath)] {
// Since walkType is recursive, all types that are in packages that
// were directly mentioned will be included. We don't need to
// include all types in all transitive packages, though.
result = append(result, pkgPath)
}
}
return result
}
// FindTypes finalizes the package imports, and searches through all the
// packages for types.
func (b *Builder) FindTypes() (types.Universe, error) {
// Take a snapshot of pkgs to iterate, since this will recursively mutate
// b.parsed. Iterate in a predictable order.
pkgPaths := []string{}
for pkgPath := range b.parsed {
pkgPaths = append(pkgPaths, string(pkgPath))
}
sort.Strings(pkgPaths)
u := types.Universe{}
for _, pkgPath := range pkgPaths {
if err := b.findTypesIn(importPathString(pkgPath), &u); err != nil {
return nil, err
}
}
return u, nil
}
// findTypesIn finalizes the package import and searches through the package
// for types.
func (b *Builder) findTypesIn(pkgPath importPathString, u *types.Universe) error {
glog.V(5).Infof("findTypesIn %s", pkgPath)
pkg := b.typeCheckedPackages[pkgPath]
if pkg == nil {
return fmt.Errorf("findTypesIn(%s): package is not known", pkgPath)
}
if !b.userRequested[pkgPath] {
// Since walkType is recursive, all types that the
// packages they asked for depend on will be included.
// But we don't need to include all types in all
// *packages* they depend on.
glog.V(5).Infof("findTypesIn %s: package is not user requested", pkgPath)
return nil
}
// We're keeping this package. This call will create the record.
u.Package(string(pkgPath)).Name = pkg.Name()
u.Package(string(pkgPath)).Path = pkg.Path()
u.Package(string(pkgPath)).SourcePath = b.absPaths[pkgPath]
for _, f := range b.parsed[pkgPath] {
if strings.HasSuffix(f.name, "/doc.go") {
tp := u.Package(string(pkgPath))
// findTypesIn might be called multiple times. Clean up tp.Comments
// to avoid repeatedly fill same comments to it.
tp.Comments = []string{}
for i := range f.file.Comments {
tp.Comments = append(tp.Comments, splitLines(f.file.Comments[i].Text())...)
}
if f.file.Doc != nil {
tp.DocComments = splitLines(f.file.Doc.Text())
}
}
}
s := pkg.Scope()
for _, n := range s.Names() {
obj := s.Lookup(n)
tn, ok := obj.(*tc.TypeName)
if ok {
t := b.walkType(*u, nil, tn.Type())
c1 := b.priorCommentLines(obj.Pos(), 1)
// c1.Text() is safe if c1 is nil
t.CommentLines = splitLines(c1.Text())
if c1 == nil {
t.SecondClosestCommentLines = splitLines(b.priorCommentLines(obj.Pos(), 2).Text())
} else {
t.SecondClosestCommentLines = splitLines(b.priorCommentLines(c1.List[0].Slash, 2).Text())
}
}
tf, ok := obj.(*tc.Func)
// We only care about functions, not concrete/abstract methods.
if ok && tf.Type() != nil && tf.Type().(*tc.Signature).Recv() == nil {
t := b.addFunction(*u, nil, tf)
c1 := b.priorCommentLines(obj.Pos(), 1)
// c1.Text() is safe if c1 is nil
t.CommentLines = splitLines(c1.Text())
if c1 == nil {
t.SecondClosestCommentLines = splitLines(b.priorCommentLines(obj.Pos(), 2).Text())
} else {
t.SecondClosestCommentLines = splitLines(b.priorCommentLines(c1.List[0].Slash, 2).Text())
}
}
tv, ok := obj.(*tc.Var)
if ok && !tv.IsField() {
b.addVariable(*u, nil, tv)
}
}
importedPkgs := []string{}
for k := range b.importGraph[pkgPath] {
importedPkgs = append(importedPkgs, string(k))
}
sort.Strings(importedPkgs)
for _, p := range importedPkgs {
u.AddImports(string(pkgPath), p)
}
return nil
}
func (b *Builder) importWithMode(dir string, mode build.ImportMode) (*build.Package, error) {
// This is a bit of a hack. The srcDir argument to Import() should
// properly be the dir of the file which depends on the package to be
// imported, so that vendoring can work properly and local paths can
// resolve. We assume that there is only one level of vendoring, and that
// the CWD is inside the GOPATH, so this should be safe. Nobody should be
// using local (relative) paths except on the CLI, so CWD is also
// sufficient.
cwd, err := os.Getwd()
if err != nil {
return nil, fmt.Errorf("unable to get current directory: %v", err)
}
buildPkg, err := b.context.Import(dir, cwd, mode)
if err != nil {
return nil, err
}
return buildPkg, nil
}
// if there's a comment on the line `lines` before pos, return its text, otherwise "".
func (b *Builder) priorCommentLines(pos token.Pos, lines int) *ast.CommentGroup {
position := b.fset.Position(pos)
key := fileLine{position.Filename, position.Line - lines}
return b.endLineToCommentGroup[key]
}
func splitLines(str string) []string {
return strings.Split(strings.TrimRight(str, "\n"), "\n")
}
func tcFuncNameToName(in string) types.Name {
name := strings.TrimLeft(in, "func ")
nameParts := strings.Split(name, "(")
return tcNameToName(nameParts[0])
}
func tcVarNameToName(in string) types.Name {
nameParts := strings.Split(in, " ")
// nameParts[0] is "var".
// nameParts[2:] is the type of the variable, we ignore it for now.
return tcNameToName(nameParts[1])
}
func tcNameToName(in string) types.Name {
// Detect anonymous type names. (These may have '.' characters because
// embedded types may have packages, so we detect them specially.)
if strings.HasPrefix(in, "struct{") ||
strings.HasPrefix(in, "<-chan") ||
strings.HasPrefix(in, "chan<-") ||
strings.HasPrefix(in, "chan ") ||
strings.HasPrefix(in, "func(") ||
strings.HasPrefix(in, "*") ||
strings.HasPrefix(in, "map[") ||
strings.HasPrefix(in, "[") {
return types.Name{Name: in}
}
// Otherwise, if there are '.' characters present, the name has a
// package path in front.
nameParts := strings.Split(in, ".")
name := types.Name{Name: in}
if n := len(nameParts); n >= 2 {
// The final "." is the name of the type--previous ones must
// have been in the package path.
name.Package, name.Name = strings.Join(nameParts[:n-1], "."), nameParts[n-1]
}
return name
}
func (b *Builder) convertSignature(u types.Universe, t *tc.Signature) *types.Signature {
signature := &types.Signature{}
for i := 0; i < t.Params().Len(); i++ {
signature.Parameters = append(signature.Parameters, b.walkType(u, nil, t.Params().At(i).Type()))
}
for i := 0; i < t.Results().Len(); i++ {
signature.Results = append(signature.Results, b.walkType(u, nil, t.Results().At(i).Type()))
}
if r := t.Recv(); r != nil {
signature.Receiver = b.walkType(u, nil, r.Type())
}
signature.Variadic = t.Variadic()
return signature
}
// walkType adds the type, and any necessary child types.
func (b *Builder) walkType(u types.Universe, useName *types.Name, in tc.Type) *types.Type {
// Most of the cases are underlying types of the named type.
name := tcNameToName(in.String())
if useName != nil {
name = *useName
}
switch t := in.(type) {
case *tc.Struct:
out := u.Type(name)
if out.Kind != types.Unknown {
return out
}
out.Kind = types.Struct
for i := 0; i < t.NumFields(); i++ {
f := t.Field(i)
m := types.Member{
Name: f.Name(),
Embedded: f.Anonymous(),
Tags: t.Tag(i),
Type: b.walkType(u, nil, f.Type()),
CommentLines: splitLines(b.priorCommentLines(f.Pos(), 1).Text()),
}
out.Members = append(out.Members, m)
}
return out
case *tc.Map:
out := u.Type(name)
if out.Kind != types.Unknown {
return out
}
out.Kind = types.Map
out.Elem = b.walkType(u, nil, t.Elem())
out.Key = b.walkType(u, nil, t.Key())
return out
case *tc.Pointer:
out := u.Type(name)
if out.Kind != types.Unknown {
return out
}
out.Kind = types.Pointer
out.Elem = b.walkType(u, nil, t.Elem())
return out
case *tc.Slice:
out := u.Type(name)
if out.Kind != types.Unknown {
return out
}
out.Kind = types.Slice
out.Elem = b.walkType(u, nil, t.Elem())
return out
case *tc.Array:
out := u.Type(name)
if out.Kind != types.Unknown {
return out
}
out.Kind = types.Array
out.Elem = b.walkType(u, nil, t.Elem())
// TODO: need to store array length, otherwise raw type name
// cannot be properly written.
return out
case *tc.Chan:
out := u.Type(name)
if out.Kind != types.Unknown {
return out
}
out.Kind = types.Chan
out.Elem = b.walkType(u, nil, t.Elem())
// TODO: need to store direction, otherwise raw type name
// cannot be properly written.
return out
case *tc.Basic:
out := u.Type(types.Name{
Package: "",
Name: t.Name(),
})
if out.Kind != types.Unknown {
return out
}
out.Kind = types.Unsupported
return out
case *tc.Signature:
out := u.Type(name)
if out.Kind != types.Unknown {
return out
}
out.Kind = types.Func
out.Signature = b.convertSignature(u, t)
return out
case *tc.Interface:
out := u.Type(name)
if out.Kind != types.Unknown {
return out
}
out.Kind = types.Interface
t.Complete()
for i := 0; i < t.NumMethods(); i++ {
if out.Methods == nil {
out.Methods = map[string]*types.Type{}
}
out.Methods[t.Method(i).Name()] = b.walkType(u, nil, t.Method(i).Type())
}
return out
case *tc.Named:
var out *types.Type
switch t.Underlying().(type) {
case *tc.Named, *tc.Basic, *tc.Map, *tc.Slice:
name := tcNameToName(t.String())
out = u.Type(name)
if out.Kind != types.Unknown {
return out
}
out.Kind = types.Alias
out.Underlying = b.walkType(u, nil, t.Underlying())
default:
// tc package makes everything "named" with an
// underlying anonymous type--we remove that annoying
// "feature" for users. This flattens those types
// together.
name := tcNameToName(t.String())
if out := u.Type(name); out.Kind != types.Unknown {
return out // short circuit if we've already made this.
}
out = b.walkType(u, &name, t.Underlying())
}
// If the underlying type didn't already add methods, add them.
// (Interface types will have already added methods.)
if len(out.Methods) == 0 {
for i := 0; i < t.NumMethods(); i++ {
if out.Methods == nil {
out.Methods = map[string]*types.Type{}
}
out.Methods[t.Method(i).Name()] = b.walkType(u, nil, t.Method(i).Type())
}
}
return out
default:
out := u.Type(name)
if out.Kind != types.Unknown {
return out
}
out.Kind = types.Unsupported
glog.Warningf("Making unsupported type entry %q for: %#v\n", out, t)
return out
}
}
func (b *Builder) addFunction(u types.Universe, useName *types.Name, in *tc.Func) *types.Type {
name := tcFuncNameToName(in.String())
if useName != nil {
name = *useName
}
out := u.Function(name)
out.Kind = types.DeclarationOf
out.Underlying = b.walkType(u, nil, in.Type())
return out
}
func (b *Builder) addVariable(u types.Universe, useName *types.Name, in *tc.Var) *types.Type {
name := tcVarNameToName(in.String())
if useName != nil {
name = *useName
}
out := u.Variable(name)
out.Kind = types.DeclarationOf
out.Underlying = b.walkType(u, nil, in.Type())
return out
}
// canonicalizeImportPath takes an import path and returns the actual package.
// It doesn't support nested vendoring.
func canonicalizeImportPath(importPath string) importPathString {
if !strings.Contains(importPath, "/vendor/") {
return importPathString(importPath)
}
return importPathString(importPath[strings.Index(importPath, "/vendor/")+len("/vendor/"):])
}

View File

@ -1,82 +0,0 @@
/*
Copyright 2015 The Kubernetes 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 types contains go type information, packaged in a way that makes
// auto-generation convenient, whether by template or straight go functions.
package types
import (
"fmt"
"strings"
)
// ExtractCommentTags parses comments for lines of the form:
//
// 'marker' + "key=value".
//
// Values are optional; "" is the default. A tag can be specified more than
// one time and all values are returned. If the resulting map has an entry for
// a key, the value (a slice) is guaranteed to have at least 1 element.
//
// Example: if you pass "+" for 'marker', and the following lines are in
// the comments:
// +foo=value1
// +bar
// +foo=value2
// +baz="qux"
// Then this function will return:
// map[string][]string{"foo":{"value1, "value2"}, "bar": {""}, "baz": {"qux"}}
func ExtractCommentTags(marker string, lines []string) map[string][]string {
out := map[string][]string{}
for _, line := range lines {
line = strings.Trim(line, " ")
if len(line) == 0 {
continue
}
if !strings.HasPrefix(line, marker) {
continue
}
// TODO: we could support multiple values per key if we split on spaces
kv := strings.SplitN(line[len(marker):], "=", 2)
if len(kv) == 2 {
out[kv[0]] = append(out[kv[0]], kv[1])
} else if len(kv) == 1 {
out[kv[0]] = append(out[kv[0]], "")
}
}
return out
}
// ExtractSingleBoolCommentTag parses comments for lines of the form:
//
// 'marker' + "key=value1"
//
// If the tag is not found, the default value is returned. Values are asserted
// to be boolean ("true" or "false"), and any other value will cause an error
// to be returned. If the key has multiple values, the first one will be used.
func ExtractSingleBoolCommentTag(marker string, key string, defaultVal bool, lines []string) (bool, error) {
values := ExtractCommentTags(marker, lines)[key]
if values == nil {
return defaultVal, nil
}
if values[0] == "true" {
return true, nil
}
if values[0] == "false" {
return false, nil
}
return false, fmt.Errorf("tag value for %q is not boolean: %q", key, values[0])
}

19
vendor/k8s.io/gengo/types/doc.go generated vendored
View File

@ -1,19 +0,0 @@
/*
Copyright 2015 The Kubernetes 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 types contains go type information, packaged in a way that makes
// auto-generation convenient, whether by template or straight go functions.
package types // import "k8s.io/gengo/types"

57
vendor/k8s.io/gengo/types/flatten.go generated vendored
View File

@ -1,57 +0,0 @@
/*
Copyright 2015 The Kubernetes 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 types
// FlattenMembers recursively takes any embedded members and puts them in the
// top level, correctly hiding them if the top level hides them. There must not
// be a cycle-- that implies infinite members.
//
// This is useful for e.g. computing all the valid keys in a json struct,
// properly considering any configuration of embedded structs.
func FlattenMembers(m []Member) []Member {
embedded := []Member{}
normal := []Member{}
type nameInfo struct {
top bool
i int
}
names := map[string]nameInfo{}
for i := range m {
if m[i].Embedded && m[i].Type.Kind == Struct {
embedded = append(embedded, m[i])
} else {
normal = append(normal, m[i])
names[m[i].Name] = nameInfo{true, len(normal) - 1}
}
}
for i := range embedded {
for _, e := range FlattenMembers(embedded[i].Type.Members) {
if info, found := names[e.Name]; found {
if info.top {
continue
}
if n := normal[info.i]; n.Name == e.Name && n.Type == e.Type {
continue
}
panic("conflicting members")
}
normal = append(normal, e)
names[e.Name] = nameInfo{false, len(normal) - 1}
}
}
return normal
}

499
vendor/k8s.io/gengo/types/types.go generated vendored
View File

@ -1,499 +0,0 @@
/*
Copyright 2015 The Kubernetes 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 types
import "strings"
// Ref makes a reference to the given type. It can only be used for e.g.
// passing to namers.
func Ref(packageName, typeName string) *Type {
return &Type{Name: Name{
Name: typeName,
Package: packageName,
}}
}
// A type name may have a package qualifier.
type Name struct {
// Empty if embedded or builtin. This is the package path unless Path is specified.
Package string
// The type name.
Name string
// An optional location of the type definition for languages that can have disjoint
// packages and paths.
Path string
}
// String returns the name formatted as a string.
func (n Name) String() string {
if n.Package == "" {
return n.Name
}
return n.Package + "." + n.Name
}
// ParseFullyQualifiedName parses a name like k8s.io/kubernetes/pkg/api.Pod into a Name.
func ParseFullyQualifiedName(fqn string) Name {
cs := strings.Split(fqn, ".")
pkg := ""
if len(cs) > 1 {
pkg = strings.Join(cs[0:len(cs) - 1], ".")
}
return Name{
Name: cs[len(cs) - 1],
Package: pkg,
}
}
// The possible classes of types.
type Kind string
const (
// Builtin is a primitive, like bool, string, int.
Builtin Kind = "Builtin"
Struct Kind = "Struct"
Map Kind = "Map"
Slice Kind = "Slice"
Pointer Kind = "Pointer"
// Alias is an alias of another type, e.g. in:
// type Foo string
// type Bar Foo
// Bar is an alias of Foo.
//
// In the real go type system, Foo is a "Named" string; but to simplify
// generation, this type system will just say that Foo *is* a builtin.
// We then need "Alias" as a way for us to say that Bar *is* a Foo.
Alias Kind = "Alias"
// Interface is any type that could have differing types at run time.
Interface Kind = "Interface"
// The remaining types are included for completeness, but are not well
// supported.
Array Kind = "Array" // Array is just like slice, but has a fixed length.
Chan Kind = "Chan"
Func Kind = "Func"
// DeclarationOf is different from other Kinds; it indicates that instead of
// representing an actual Type, the type is a declaration of an instance of
// a type. E.g., a top-level function, variable, or constant. See the
// comment for Type.Name for more detail.
DeclarationOf Kind = "DeclarationOf"
Unknown Kind = ""
Unsupported Kind = "Unsupported"
// Protobuf is protobuf type.
Protobuf Kind = "Protobuf"
)
// Package holds package-level information.
// Fields are public, as everything in this package, to enable consumption by
// templates (for example). But it is strongly encouraged for code to build by
// using the provided functions.
type Package struct {
// Canonical name of this package-- its path.
Path string
// The location this package was loaded from
SourcePath string
// Short name of this package; the name that appears in the
// 'package x' line.
Name string
// The comment right above the package declaration in doc.go, if any.
DocComments []string
// All comments from doc.go, if any.
// TODO: remove Comments and use DocComments everywhere.
Comments []string
// Types within this package, indexed by their name (*not* including
// package name).
Types map[string]*Type
// Functions within this package, indexed by their name (*not* including
// package name).
Functions map[string]*Type
// Global variables within this package, indexed by their name (*not* including
// package name).
Variables map[string]*Type
// Packages imported by this package, indexed by (canonicalized)
// package path.
Imports map[string]*Package
}
// Has returns true if the given name references a type known to this package.
func (p *Package) Has(name string) bool {
_, has := p.Types[name]
return has
}
// Type gets the given Type in this Package. If the Type is not already
// defined, this will add it and return the new Type value. The caller is
// expected to finish initialization.
func (p *Package) Type(typeName string) *Type {
if t, ok := p.Types[typeName]; ok {
return t
}
if p.Path == "" {
// Import the standard builtin types!
if t, ok := builtins.Types[typeName]; ok {
p.Types[typeName] = t
return t
}
}
t := &Type{Name: Name{Package: p.Path, Name: typeName}}
p.Types[typeName] = t
return t
}
// Function gets the given function Type in this Package. If the function is
// not already defined, this will add it. If a function is added, it's the
// caller's responsibility to finish construction of the function by setting
// Underlying to the correct type.
func (p *Package) Function(funcName string) *Type {
if t, ok := p.Functions[funcName]; ok {
return t
}
t := &Type{Name: Name{Package: p.Path, Name: funcName}}
t.Kind = DeclarationOf
p.Functions[funcName] = t
return t
}
// Variable gets the given variable Type in this Package. If the variable is
// not already defined, this will add it. If a variable is added, it's the caller's
// responsibility to finish construction of the variable by setting Underlying
// to the correct type.
func (p *Package) Variable(varName string) *Type {
if t, ok := p.Variables[varName]; ok {
return t
}
t := &Type{Name: Name{Package: p.Path, Name: varName}}
t.Kind = DeclarationOf
p.Variables[varName] = t
return t
}
// HasImport returns true if p imports packageName. Package names include the
// package directory.
func (p *Package) HasImport(packageName string) bool {
_, has := p.Imports[packageName]
return has
}
// Universe is a map of all packages. The key is the package name, but you
// should use Package(), Type(), Function(), or Variable() instead of direct
// access.
type Universe map[string]*Package
// Type returns the canonical type for the given fully-qualified name. Builtin
// types will always be found, even if they haven't been explicitly added to
// the map. If a non-existing type is requested, this will create (a marker for)
// it.
func (u Universe) Type(n Name) *Type {
return u.Package(n.Package).Type(n.Name)
}
// Function returns the canonical function for the given fully-qualified name.
// If a non-existing function is requested, this will create (a marker for) it.
// If a marker is created, it's the caller's responsibility to finish
// construction of the function by setting Underlying to the correct type.
func (u Universe) Function(n Name) *Type {
return u.Package(n.Package).Function(n.Name)
}
// Variable returns the canonical variable for the given fully-qualified name.
// If a non-existing variable is requested, this will create (a marker for) it.
// If a marker is created, it's the caller's responsibility to finish
// construction of the variable by setting Underlying to the correct type.
func (u Universe) Variable(n Name) *Type {
return u.Package(n.Package).Variable(n.Name)
}
// AddImports registers import lines for packageName. May be called multiple times.
// You are responsible for canonicalizing all package paths.
func (u Universe) AddImports(packagePath string, importPaths ...string) {
p := u.Package(packagePath)
for _, i := range importPaths {
p.Imports[i] = u.Package(i)
}
}
// Package returns the Package for the given path.
// If a non-existing package is requested, this will create (a marker for) it.
// If a marker is created, it's the caller's responsibility to finish
// construction of the package.
func (u Universe) Package(packagePath string) *Package {
if p, ok := u[packagePath]; ok {
return p
}
p := &Package{
Path: packagePath,
Types: map[string]*Type{},
Functions: map[string]*Type{},
Variables: map[string]*Type{},
Imports: map[string]*Package{},
}
u[packagePath] = p
return p
}
// Type represents a subset of possible go types.
type Type struct {
// There are two general categories of types, those explicitly named
// and those anonymous. Named ones will have a non-empty package in the
// name field.
//
// An exception: If Kind == DeclarationOf, then this name is the name of a
// top-level function, variable, or const, and the type can be found in Underlying.
// We do this to allow the naming system to work against these objects, even
// though they aren't strictly speaking types.
Name Name
// The general kind of this type.
Kind Kind
// If there are comment lines immediately before the type definition,
// they will be recorded here.
CommentLines []string
// If there are comment lines preceding the `CommentLines`, they will be
// recorded here. There are two cases:
// ---
// SecondClosestCommentLines
// a blank line
// CommentLines
// type definition
// ---
//
// or
// ---
// SecondClosestCommentLines
// a blank line
// type definition
// ---
SecondClosestCommentLines []string
// If Kind == Struct
Members []Member
// If Kind == Map, Slice, Pointer, or Chan
Elem *Type
// If Kind == Map, this is the map's key type.
Key *Type
// If Kind == Alias, this is the underlying type.
// If Kind == DeclarationOf, this is the type of the declaration.
Underlying *Type
// If Kind == Interface, this is the set of all required functions.
// Otherwise, if this is a named type, this is the list of methods that
// type has. (All elements will have Kind=="Func")
Methods map[string]*Type
// If Kind == func, this is the signature of the function.
Signature *Signature
// TODO: Add:
// * channel direction
// * array length
}
// String returns the name of the type.
func (t *Type) String() string {
return t.Name.String()
}
// IsPrimitive returns whether the type is a built-in type or is an alias to a
// built-in type. For example: strings and aliases of strings are primitives,
// structs are not.
func (t *Type) IsPrimitive() bool {
if t.Kind == Builtin || (t.Kind == Alias && t.Underlying.Kind == Builtin) {
return true
}
return false
}
// IsAssignable returns whether the type is deep-assignable. For example,
// slices and maps and pointers are shallow copies, but ints and strings are
// complete.
func (t *Type) IsAssignable() bool {
if t.IsPrimitive() {
return true
}
if t.Kind == Struct {
for _, m := range t.Members {
if !m.Type.IsAssignable() {
return false
}
}
return true
}
return false
}
// IsAnonymousStruct returns true if the type is an anonymous struct or an alias
// to an anonymous struct.
func (t *Type) IsAnonymousStruct() bool {
return (t.Kind == Struct && t.Name.Name == "struct{}") || (t.Kind == Alias && t.Underlying.IsAnonymousStruct())
}
// A single struct member
type Member struct {
// The name of the member.
Name string
// If the member is embedded (anonymous) this will be true, and the
// Name will be the type name.
Embedded bool
// If there are comment lines immediately before the member in the type
// definition, they will be recorded here.
CommentLines []string
// If there are tags along with this member, they will be saved here.
Tags string
// The type of this member.
Type *Type
}
// String returns the name and type of the member.
func (m Member) String() string {
return m.Name + " " + m.Type.String()
}
// Signature is a function's signature.
type Signature struct {
// TODO: store the parameter names, not just types.
// If a method of some type, this is the type it's a member of.
Receiver *Type
Parameters []*Type
Results []*Type
// True if the last in parameter is of the form ...T.
Variadic bool
// If there are comment lines immediately before this
// signature/method/function declaration, they will be recorded here.
CommentLines []string
}
// Built in types.
var (
String = &Type{
Name: Name{Name: "string"},
Kind: Builtin,
}
Int64 = &Type{
Name: Name{Name: "int64"},
Kind: Builtin,
}
Int32 = &Type{
Name: Name{Name: "int32"},
Kind: Builtin,
}
Int16 = &Type{
Name: Name{Name: "int16"},
Kind: Builtin,
}
Int = &Type{
Name: Name{Name: "int"},
Kind: Builtin,
}
Uint64 = &Type{
Name: Name{Name: "uint64"},
Kind: Builtin,
}
Uint32 = &Type{
Name: Name{Name: "uint32"},
Kind: Builtin,
}
Uint16 = &Type{
Name: Name{Name: "uint16"},
Kind: Builtin,
}
Uint = &Type{
Name: Name{Name: "uint"},
Kind: Builtin,
}
Uintptr = &Type{
Name: Name{Name: "uintptr"},
Kind: Builtin,
}
Float64 = &Type{
Name: Name{Name: "float64"},
Kind: Builtin,
}
Float32 = &Type{
Name: Name{Name: "float32"},
Kind: Builtin,
}
Float = &Type{
Name: Name{Name: "float"},
Kind: Builtin,
}
Bool = &Type{
Name: Name{Name: "bool"},
Kind: Builtin,
}
Byte = &Type{
Name: Name{Name: "byte"},
Kind: Builtin,
}
builtins = &Package{
Types: map[string]*Type{
"bool": Bool,
"string": String,
"int": Int,
"int64": Int64,
"int32": Int32,
"int16": Int16,
"int8": Byte,
"uint": Uint,
"uint64": Uint64,
"uint32": Uint32,
"uint16": Uint16,
"uint8": Byte,
"uintptr": Uintptr,
"byte": Byte,
"float": Float,
"float64": Float64,
"float32": Float32,
},
Imports: map[string]*Package{},
Path: "",
Name: "",
}
)
func IsInteger(t *Type) bool {
switch t {
case Int, Int64, Int32, Int16, Uint, Uint64, Uint32, Uint16, Byte:
return true
default:
return false
}
}