github.com/kaisenlinux/docker.io@v0.0.0-20230510090727-ea55db55fac7/swarmkit/protobuf/plugin/storeobject/storeobject.go (about)

     1  package storeobject
     2  
     3  import (
     4  	"strings"
     5  
     6  	"github.com/docker/swarmkit/protobuf/plugin"
     7  	"github.com/gogo/protobuf/proto"
     8  	"github.com/gogo/protobuf/protoc-gen-gogo/generator"
     9  )
    10  
    11  // FIXME(aaronl): Look at fields inside the descriptor instead of
    12  // special-casing based on name.
    13  var typesWithNoSpec = map[string]struct{}{
    14  	"Task":      {},
    15  	"Resource":  {},
    16  	"Extension": {},
    17  }
    18  
    19  type storeObjectGen struct {
    20  	*generator.Generator
    21  	generator.PluginImports
    22  	eventsPkg  generator.Single
    23  	stringsPkg generator.Single
    24  }
    25  
    26  func init() {
    27  	generator.RegisterPlugin(new(storeObjectGen))
    28  }
    29  
    30  func (d *storeObjectGen) Name() string {
    31  	return "storeobject"
    32  }
    33  
    34  func (d *storeObjectGen) Init(g *generator.Generator) {
    35  	d.Generator = g
    36  }
    37  
    38  func (d *storeObjectGen) genMsgStoreObject(m *generator.Descriptor, storeObject *plugin.StoreObject) {
    39  	ccTypeName := generator.CamelCaseSlice(m.TypeName())
    40  
    41  	// Generate event types
    42  
    43  	d.P("type ", ccTypeName, "CheckFunc func(t1, t2 *", ccTypeName, ") bool")
    44  	d.P()
    45  
    46  	// generate the event object type interface for this type
    47  	// event types implement some empty interfaces, for ease of use, like such:
    48  	//
    49  	//   type EventCreate interface {
    50  	//     IsEventCreatet() bool
    51  	//   }
    52  	//
    53  	//   type EventNode interface {
    54  	//     IsEventNode() bool
    55  	//   }
    56  	//
    57  	// then, each event has the corresponding interfaces implemented for its
    58  	// type. for example:
    59  	//
    60  	//   func (e EventCreateNode) IsEventCreate() bool {
    61  	//     return true
    62  	//   }
    63  	//
    64  	//   func (e EventCreateNode) IsEventNode() bool {
    65  	//     return true
    66  	//   }
    67  	//
    68  	// this lets the user filter events based on their interface type.
    69  	// note that the event type for each object type needs to be generated for
    70  	// each object. the event change type (Create/Update/Delete) is
    71  	// hand-written in the storeobject.go file because they are only needed
    72  	// once.
    73  	d.P("type Event", ccTypeName, " interface {")
    74  	d.In()
    75  	d.P("IsEvent", ccTypeName, "() bool")
    76  	d.Out()
    77  	d.P("}")
    78  	d.P()
    79  
    80  	for _, event := range []string{"Create", "Update", "Delete"} {
    81  		d.P("type Event", event, ccTypeName, " struct {")
    82  		d.In()
    83  		d.P(ccTypeName, " *", ccTypeName)
    84  		if event == "Update" {
    85  			d.P("Old", ccTypeName, " *", ccTypeName)
    86  		}
    87  		d.P("Checks []", ccTypeName, "CheckFunc")
    88  		d.Out()
    89  		d.P("}")
    90  		d.P()
    91  		d.P("func (e Event", event, ccTypeName, ") Matches(apiEvent ", d.eventsPkg.Use(), ".Event) bool {")
    92  		d.In()
    93  		d.P("typedEvent, ok := apiEvent.(Event", event, ccTypeName, ")")
    94  		d.P("if !ok {")
    95  		d.In()
    96  		d.P("return false")
    97  		d.Out()
    98  		d.P("}")
    99  		d.P()
   100  		d.P("for _, check := range e.Checks {")
   101  		d.In()
   102  		d.P("if !check(e.", ccTypeName, ", typedEvent.", ccTypeName, ") {")
   103  		d.In()
   104  		d.P("return false")
   105  		d.Out()
   106  		d.P("}")
   107  		d.Out()
   108  		d.P("}")
   109  		d.P("return true")
   110  		d.Out()
   111  		d.P("}")
   112  		d.P()
   113  
   114  		// implement event change type interface (IsEventCreate)
   115  		d.P("func (e Event", event, ccTypeName, ") IsEvent", event, "() bool {")
   116  		d.In()
   117  		d.P("return true")
   118  		d.Out()
   119  		d.P("}")
   120  		d.P()
   121  
   122  		// implement event object type interface (IsEventNode)
   123  		d.P("func (e Event", event, ccTypeName, ") IsEvent", ccTypeName, "() bool {")
   124  		d.In()
   125  		d.P("return true")
   126  		d.Out()
   127  		d.P("}")
   128  		d.P()
   129  	}
   130  
   131  	// Generate methods for this type
   132  
   133  	d.P("func (m *", ccTypeName, ") CopyStoreObject() StoreObject {")
   134  	d.In()
   135  	d.P("return m.Copy()")
   136  	d.Out()
   137  	d.P("}")
   138  	d.P()
   139  
   140  	d.P("func (m *", ccTypeName, ") GetMeta() Meta {")
   141  	d.In()
   142  	d.P("return m.Meta")
   143  	d.Out()
   144  	d.P("}")
   145  	d.P()
   146  
   147  	d.P("func (m *", ccTypeName, ") SetMeta(meta Meta) {")
   148  	d.In()
   149  	d.P("m.Meta = meta")
   150  	d.Out()
   151  	d.P("}")
   152  	d.P()
   153  
   154  	d.P("func (m *", ccTypeName, ") GetID() string {")
   155  	d.In()
   156  	d.P("return m.ID")
   157  	d.Out()
   158  	d.P("}")
   159  	d.P()
   160  
   161  	d.P("func (m *", ccTypeName, ") EventCreate() Event {")
   162  	d.In()
   163  	d.P("return EventCreate", ccTypeName, "{", ccTypeName, ": m}")
   164  	d.Out()
   165  	d.P("}")
   166  	d.P()
   167  
   168  	d.P("func (m *", ccTypeName, ") EventUpdate(oldObject StoreObject) Event {")
   169  	d.In()
   170  	d.P("if oldObject != nil {")
   171  	d.In()
   172  	d.P("return EventUpdate", ccTypeName, "{", ccTypeName, ": m, Old", ccTypeName, ": oldObject.(*", ccTypeName, ")}")
   173  	d.Out()
   174  	d.P("} else {")
   175  	d.In()
   176  	d.P("return EventUpdate", ccTypeName, "{", ccTypeName, ": m}")
   177  	d.Out()
   178  	d.P("}")
   179  	d.Out()
   180  	d.P("}")
   181  	d.P()
   182  
   183  	d.P("func (m *", ccTypeName, ") EventDelete() Event {")
   184  	d.In()
   185  	d.P("return EventDelete", ccTypeName, "{", ccTypeName, ": m}")
   186  	d.Out()
   187  	d.P("}")
   188  	d.P()
   189  
   190  	// Generate event check functions
   191  
   192  	if storeObject.WatchSelectors.ID != nil && *storeObject.WatchSelectors.ID {
   193  		d.P("func ", ccTypeName, "CheckID(v1, v2 *", ccTypeName, ") bool {")
   194  		d.In()
   195  		d.P("return v1.ID == v2.ID")
   196  		d.Out()
   197  		d.P("}")
   198  		d.P()
   199  	}
   200  
   201  	if storeObject.WatchSelectors.IDPrefix != nil && *storeObject.WatchSelectors.IDPrefix {
   202  		d.P("func ", ccTypeName, "CheckIDPrefix(v1, v2 *", ccTypeName, ") bool {")
   203  		d.In()
   204  		d.P("return ", d.stringsPkg.Use(), ".HasPrefix(v2.ID, v1.ID)")
   205  		d.Out()
   206  		d.P("}")
   207  		d.P()
   208  	}
   209  
   210  	if storeObject.WatchSelectors.Name != nil && *storeObject.WatchSelectors.Name {
   211  		d.P("func ", ccTypeName, "CheckName(v1, v2 *", ccTypeName, ") bool {")
   212  		d.In()
   213  		// Node is a special case
   214  		if *m.Name == "Node" {
   215  			d.P("if v1.Description == nil || v2.Description == nil {")
   216  			d.In()
   217  			d.P("return false")
   218  			d.Out()
   219  			d.P("}")
   220  			d.P("return v1.Description.Hostname == v2.Description.Hostname")
   221  		} else if _, hasNoSpec := typesWithNoSpec[*m.Name]; hasNoSpec {
   222  			d.P("return v1.Annotations.Name == v2.Annotations.Name")
   223  		} else {
   224  			d.P("return v1.Spec.Annotations.Name == v2.Spec.Annotations.Name")
   225  		}
   226  		d.Out()
   227  		d.P("}")
   228  		d.P()
   229  	}
   230  
   231  	if storeObject.WatchSelectors.NamePrefix != nil && *storeObject.WatchSelectors.NamePrefix {
   232  		d.P("func ", ccTypeName, "CheckNamePrefix(v1, v2 *", ccTypeName, ") bool {")
   233  		d.In()
   234  		// Node is a special case
   235  		if *m.Name == "Node" {
   236  			d.P("if v1.Description == nil || v2.Description == nil {")
   237  			d.In()
   238  			d.P("return false")
   239  			d.Out()
   240  			d.P("}")
   241  			d.P("return ", d.stringsPkg.Use(), ".HasPrefix(v2.Description.Hostname, v1.Description.Hostname)")
   242  		} else if _, hasNoSpec := typesWithNoSpec[*m.Name]; hasNoSpec {
   243  			d.P("return ", d.stringsPkg.Use(), ".HasPrefix(v2.Annotations.Name, v1.Annotations.Name)")
   244  		} else {
   245  			d.P("return ", d.stringsPkg.Use(), ".HasPrefix(v2.Spec.Annotations.Name, v1.Spec.Annotations.Name)")
   246  		}
   247  		d.Out()
   248  		d.P("}")
   249  		d.P()
   250  	}
   251  
   252  	if storeObject.WatchSelectors.Custom != nil && *storeObject.WatchSelectors.Custom {
   253  		d.P("func ", ccTypeName, "CheckCustom(v1, v2 *", ccTypeName, ") bool {")
   254  		d.In()
   255  		// Node is a special case
   256  		if _, hasNoSpec := typesWithNoSpec[*m.Name]; hasNoSpec {
   257  			d.P("return checkCustom(v1.Annotations, v2.Annotations)")
   258  		} else {
   259  			d.P("return checkCustom(v1.Spec.Annotations, v2.Spec.Annotations)")
   260  		}
   261  		d.Out()
   262  		d.P("}")
   263  		d.P()
   264  	}
   265  
   266  	if storeObject.WatchSelectors.CustomPrefix != nil && *storeObject.WatchSelectors.CustomPrefix {
   267  		d.P("func ", ccTypeName, "CheckCustomPrefix(v1, v2 *", ccTypeName, ") bool {")
   268  		d.In()
   269  		// Node is a special case
   270  		if _, hasNoSpec := typesWithNoSpec[*m.Name]; hasNoSpec {
   271  			d.P("return checkCustomPrefix(v1.Annotations, v2.Annotations)")
   272  		} else {
   273  			d.P("return checkCustomPrefix(v1.Spec.Annotations, v2.Spec.Annotations)")
   274  		}
   275  		d.Out()
   276  		d.P("}")
   277  		d.P()
   278  	}
   279  
   280  	if storeObject.WatchSelectors.NodeID != nil && *storeObject.WatchSelectors.NodeID {
   281  		d.P("func ", ccTypeName, "CheckNodeID(v1, v2 *", ccTypeName, ") bool {")
   282  		d.In()
   283  		d.P("return v1.NodeID == v2.NodeID")
   284  		d.Out()
   285  		d.P("}")
   286  		d.P()
   287  	}
   288  
   289  	if storeObject.WatchSelectors.ServiceID != nil && *storeObject.WatchSelectors.ServiceID {
   290  		d.P("func ", ccTypeName, "CheckServiceID(v1, v2 *", ccTypeName, ") bool {")
   291  		d.In()
   292  		d.P("return v1.ServiceID == v2.ServiceID")
   293  		d.Out()
   294  		d.P("}")
   295  		d.P()
   296  	}
   297  
   298  	if storeObject.WatchSelectors.Slot != nil && *storeObject.WatchSelectors.Slot {
   299  		d.P("func ", ccTypeName, "CheckSlot(v1, v2 *", ccTypeName, ") bool {")
   300  		d.In()
   301  		d.P("return v1.Slot == v2.Slot")
   302  		d.Out()
   303  		d.P("}")
   304  		d.P()
   305  	}
   306  
   307  	if storeObject.WatchSelectors.DesiredState != nil && *storeObject.WatchSelectors.DesiredState {
   308  		d.P("func ", ccTypeName, "CheckDesiredState(v1, v2 *", ccTypeName, ") bool {")
   309  		d.In()
   310  		d.P("return v1.DesiredState == v2.DesiredState")
   311  		d.Out()
   312  		d.P("}")
   313  		d.P()
   314  	}
   315  
   316  	if storeObject.WatchSelectors.Role != nil && *storeObject.WatchSelectors.Role {
   317  		d.P("func ", ccTypeName, "CheckRole(v1, v2 *", ccTypeName, ") bool {")
   318  		d.In()
   319  		d.P("return v1.Role == v2.Role")
   320  		d.Out()
   321  		d.P("}")
   322  		d.P()
   323  	}
   324  
   325  	if storeObject.WatchSelectors.Membership != nil && *storeObject.WatchSelectors.Membership {
   326  		d.P("func ", ccTypeName, "CheckMembership(v1, v2 *", ccTypeName, ") bool {")
   327  		d.In()
   328  		d.P("return v1.Spec.Membership == v2.Spec.Membership")
   329  		d.Out()
   330  		d.P("}")
   331  		d.P()
   332  	}
   333  
   334  	if storeObject.WatchSelectors.Kind != nil && *storeObject.WatchSelectors.Kind {
   335  		d.P("func ", ccTypeName, "CheckKind(v1, v2 *", ccTypeName, ") bool {")
   336  		d.In()
   337  		d.P("return v1.Kind == v2.Kind")
   338  		d.Out()
   339  		d.P("}")
   340  		d.P()
   341  	}
   342  
   343  	// Generate Convert*Watch function, for watch API.
   344  	if ccTypeName == "Resource" {
   345  		d.P("func ConvertResourceWatch(action WatchActionKind, filters []*SelectBy, kind string) ([]Event, error) {")
   346  	} else {
   347  		d.P("func Convert", ccTypeName, "Watch(action WatchActionKind, filters []*SelectBy) ([]Event, error) {")
   348  	}
   349  	d.In()
   350  	d.P("var (")
   351  	d.In()
   352  	d.P("m ", ccTypeName)
   353  	d.P("checkFuncs []", ccTypeName, "CheckFunc")
   354  	if storeObject.WatchSelectors.DesiredState != nil && *storeObject.WatchSelectors.DesiredState {
   355  		d.P("hasDesiredState bool")
   356  	}
   357  	if storeObject.WatchSelectors.Role != nil && *storeObject.WatchSelectors.Role {
   358  		d.P("hasRole bool")
   359  	}
   360  	if storeObject.WatchSelectors.Membership != nil && *storeObject.WatchSelectors.Membership {
   361  		d.P("hasMembership bool")
   362  	}
   363  	d.Out()
   364  	d.P(")")
   365  	if ccTypeName == "Resource" {
   366  		d.P("m.Kind = kind")
   367  		d.P("checkFuncs = append(checkFuncs, ResourceCheckKind)")
   368  	}
   369  	d.P()
   370  	d.P("for _, filter := range filters {")
   371  	d.In()
   372  	d.P("switch v := filter.By.(type) {")
   373  
   374  	if storeObject.WatchSelectors.ID != nil && *storeObject.WatchSelectors.ID {
   375  		d.P("case *SelectBy_ID:")
   376  		d.In()
   377  		d.P(`if m.ID != "" {`)
   378  		d.In()
   379  		d.P("return nil, errConflictingFilters")
   380  		d.Out()
   381  		d.P("}")
   382  		d.P("m.ID = v.ID")
   383  		d.P("checkFuncs = append(checkFuncs, ", ccTypeName, "CheckID)")
   384  		d.Out()
   385  	}
   386  	if storeObject.WatchSelectors.IDPrefix != nil && *storeObject.WatchSelectors.IDPrefix {
   387  		d.P("case *SelectBy_IDPrefix:")
   388  		d.In()
   389  		d.P(`if m.ID != "" {`)
   390  		d.In()
   391  		d.P("return nil, errConflictingFilters")
   392  		d.Out()
   393  		d.P("}")
   394  		d.P("m.ID = v.IDPrefix")
   395  		d.P("checkFuncs = append(checkFuncs, ", ccTypeName, "CheckIDPrefix)")
   396  		d.Out()
   397  	}
   398  	if storeObject.WatchSelectors.Name != nil && *storeObject.WatchSelectors.Name {
   399  		d.P("case *SelectBy_Name:")
   400  		d.In()
   401  		if *m.Name == "Node" {
   402  			d.P("if m.Description != nil {")
   403  			d.In()
   404  			d.P("return nil, errConflictingFilters")
   405  			d.Out()
   406  			d.P("}")
   407  			d.P("m.Description = &NodeDescription{Hostname: v.Name}")
   408  
   409  		} else if _, hasNoSpec := typesWithNoSpec[*m.Name]; hasNoSpec {
   410  			d.P(`if m.Annotations.Name != "" {`)
   411  			d.In()
   412  			d.P("return nil, errConflictingFilters")
   413  			d.Out()
   414  			d.P("}")
   415  			d.P("m.Annotations.Name = v.Name")
   416  		} else {
   417  			d.P(`if m.Spec.Annotations.Name != "" {`)
   418  			d.In()
   419  			d.P("return nil, errConflictingFilters")
   420  			d.Out()
   421  			d.P("}")
   422  			d.P("m.Spec.Annotations.Name = v.Name")
   423  		}
   424  		d.P("checkFuncs = append(checkFuncs, ", ccTypeName, "CheckName)")
   425  		d.Out()
   426  	}
   427  	if storeObject.WatchSelectors.NamePrefix != nil && *storeObject.WatchSelectors.NamePrefix {
   428  		d.P("case *SelectBy_NamePrefix:")
   429  		d.In()
   430  		if *m.Name == "Node" {
   431  			d.P("if m.Description != nil {")
   432  			d.In()
   433  			d.P("return nil, errConflictingFilters")
   434  			d.Out()
   435  			d.P("}")
   436  			d.P("m.Description = &NodeDescription{Hostname: v.NamePrefix}")
   437  
   438  		} else if _, hasNoSpec := typesWithNoSpec[*m.Name]; hasNoSpec {
   439  			d.P(`if m.Annotations.Name != "" {`)
   440  			d.In()
   441  			d.P("return nil, errConflictingFilters")
   442  			d.Out()
   443  			d.P("}")
   444  			d.P("m.Annotations.Name = v.NamePrefix")
   445  		} else {
   446  			d.P(`if m.Spec.Annotations.Name != "" {`)
   447  			d.In()
   448  			d.P("return nil, errConflictingFilters")
   449  			d.Out()
   450  			d.P("}")
   451  			d.P("m.Spec.Annotations.Name = v.NamePrefix")
   452  		}
   453  		d.P("checkFuncs = append(checkFuncs, ", ccTypeName, "CheckNamePrefix)")
   454  		d.Out()
   455  	}
   456  	if storeObject.WatchSelectors.Custom != nil && *storeObject.WatchSelectors.Custom {
   457  		d.P("case *SelectBy_Custom:")
   458  		d.In()
   459  		if _, hasNoSpec := typesWithNoSpec[*m.Name]; hasNoSpec {
   460  			d.P(`if len(m.Annotations.Indices) != 0 {`)
   461  			d.In()
   462  			d.P("return nil, errConflictingFilters")
   463  			d.Out()
   464  			d.P("}")
   465  			d.P("m.Annotations.Indices = []IndexEntry{{Key: v.Custom.Index, Val: v.Custom.Value}}")
   466  		} else {
   467  			d.P(`if len(m.Spec.Annotations.Indices) != 0 {`)
   468  			d.In()
   469  			d.P("return nil, errConflictingFilters")
   470  			d.Out()
   471  			d.P("}")
   472  			d.P("m.Spec.Annotations.Indices = []IndexEntry{{Key: v.Custom.Index, Val: v.Custom.Value}}")
   473  		}
   474  		d.P("checkFuncs = append(checkFuncs, ", ccTypeName, "CheckCustom)")
   475  		d.Out()
   476  	}
   477  	if storeObject.WatchSelectors.CustomPrefix != nil && *storeObject.WatchSelectors.CustomPrefix {
   478  		d.P("case *SelectBy_CustomPrefix:")
   479  		d.In()
   480  		if _, hasNoSpec := typesWithNoSpec[*m.Name]; hasNoSpec {
   481  			d.P(`if len(m.Annotations.Indices) != 0 {`)
   482  			d.In()
   483  			d.P("return nil, errConflictingFilters")
   484  			d.Out()
   485  			d.P("}")
   486  			d.P("m.Annotations.Indices = []IndexEntry{{Key: v.CustomPrefix.Index, Val: v.CustomPrefix.Value}}")
   487  		} else {
   488  			d.P(`if len(m.Spec.Annotations.Indices) != 0 {`)
   489  			d.In()
   490  			d.P("return nil, errConflictingFilters")
   491  			d.Out()
   492  			d.P("}")
   493  			d.P("m.Spec.Annotations.Indices = []IndexEntry{{Key: v.CustomPrefix.Index, Val: v.CustomPrefix.Value}}")
   494  		}
   495  		d.P("checkFuncs = append(checkFuncs, ", ccTypeName, "CheckCustomPrefix)")
   496  		d.Out()
   497  	}
   498  	if storeObject.WatchSelectors.ServiceID != nil && *storeObject.WatchSelectors.ServiceID {
   499  		d.P("case *SelectBy_ServiceID:")
   500  		d.In()
   501  		d.P(`if m.ServiceID != "" {`)
   502  		d.In()
   503  		d.P("return nil, errConflictingFilters")
   504  		d.Out()
   505  		d.P("}")
   506  		d.P("m.ServiceID = v.ServiceID")
   507  		d.P("checkFuncs = append(checkFuncs, ", ccTypeName, "CheckServiceID)")
   508  		d.Out()
   509  	}
   510  	if storeObject.WatchSelectors.NodeID != nil && *storeObject.WatchSelectors.NodeID {
   511  		d.P("case *SelectBy_NodeID:")
   512  		d.In()
   513  		d.P(`if m.NodeID != "" {`)
   514  		d.In()
   515  		d.P("return nil, errConflictingFilters")
   516  		d.Out()
   517  		d.P("}")
   518  		d.P("m.NodeID = v.NodeID")
   519  		d.P("checkFuncs = append(checkFuncs, ", ccTypeName, "CheckNodeID)")
   520  		d.Out()
   521  	}
   522  	if storeObject.WatchSelectors.Slot != nil && *storeObject.WatchSelectors.Slot {
   523  		d.P("case *SelectBy_Slot:")
   524  		d.In()
   525  		d.P(`if m.Slot != 0 || m.ServiceID != "" {`)
   526  		d.In()
   527  		d.P("return nil, errConflictingFilters")
   528  		d.Out()
   529  		d.P("}")
   530  		d.P("m.ServiceID = v.Slot.ServiceID")
   531  		d.P("m.Slot = v.Slot.Slot")
   532  		d.P("checkFuncs = append(checkFuncs, ", ccTypeName, "CheckNodeID, ", ccTypeName, "CheckSlot)")
   533  		d.Out()
   534  	}
   535  	if storeObject.WatchSelectors.DesiredState != nil && *storeObject.WatchSelectors.DesiredState {
   536  		d.P("case *SelectBy_DesiredState:")
   537  		d.In()
   538  		d.P(`if hasDesiredState {`)
   539  		d.In()
   540  		d.P("return nil, errConflictingFilters")
   541  		d.Out()
   542  		d.P("}")
   543  		d.P("hasDesiredState = true")
   544  		d.P("m.DesiredState = v.DesiredState")
   545  		d.P("checkFuncs = append(checkFuncs, ", ccTypeName, "CheckDesiredState)")
   546  		d.Out()
   547  	}
   548  	if storeObject.WatchSelectors.Role != nil && *storeObject.WatchSelectors.Role {
   549  		d.P("case *SelectBy_Role:")
   550  		d.In()
   551  		d.P(`if hasRole {`)
   552  		d.In()
   553  		d.P("return nil, errConflictingFilters")
   554  		d.Out()
   555  		d.P("}")
   556  		d.P("hasRole = true")
   557  		d.P("m.Role = v.Role")
   558  		d.P("checkFuncs = append(checkFuncs, ", ccTypeName, "CheckRole)")
   559  		d.Out()
   560  	}
   561  	if storeObject.WatchSelectors.Membership != nil && *storeObject.WatchSelectors.Membership {
   562  		d.P("case *SelectBy_Membership:")
   563  		d.In()
   564  		d.P(`if hasMembership {`)
   565  		d.In()
   566  		d.P("return nil, errConflictingFilters")
   567  		d.Out()
   568  		d.P("}")
   569  		d.P("hasMembership = true")
   570  		d.P("m.Spec.Membership = v.Membership")
   571  		d.P("checkFuncs = append(checkFuncs, ", ccTypeName, "CheckMembership)")
   572  		d.Out()
   573  	}
   574  
   575  	d.P("}")
   576  	d.Out()
   577  	d.P("}")
   578  	d.P("var events []Event")
   579  	d.P("if (action & WatchActionKindCreate) != 0 {")
   580  	d.In()
   581  	d.P("events = append(events, EventCreate", ccTypeName, "{", ccTypeName, ": &m, Checks: checkFuncs})")
   582  	d.Out()
   583  	d.P("}")
   584  	d.P("if (action & WatchActionKindUpdate) != 0 {")
   585  	d.In()
   586  	d.P("events = append(events, EventUpdate", ccTypeName, "{", ccTypeName, ": &m, Checks: checkFuncs})")
   587  	d.Out()
   588  	d.P("}")
   589  	d.P("if (action & WatchActionKindRemove) != 0 {")
   590  	d.In()
   591  	d.P("events = append(events, EventDelete", ccTypeName, "{", ccTypeName, ": &m, Checks: checkFuncs})")
   592  	d.Out()
   593  	d.P("}")
   594  	d.P("if len(events) == 0 {")
   595  	d.In()
   596  	d.P("return nil, errUnrecognizedAction")
   597  	d.Out()
   598  	d.P("}")
   599  	d.P("return events, nil")
   600  	d.Out()
   601  	d.P("}")
   602  	d.P()
   603  
   604  	/*                switch v := filter.By.(type) {
   605  	default:
   606  	        return nil, status.Errorf(codes.InvalidArgument, "selector type %T is unsupported for tasks", filter.By)
   607  	}
   608  	*/
   609  
   610  	// Generate indexer by ID
   611  
   612  	d.P("type ", ccTypeName, "IndexerByID struct{}")
   613  	d.P()
   614  
   615  	d.genFromArgs(ccTypeName + "IndexerByID")
   616  	d.genPrefixFromArgs(ccTypeName + "IndexerByID")
   617  
   618  	d.P("func (indexer ", ccTypeName, "IndexerByID) FromObject(obj interface{}) (bool, []byte, error) {")
   619  	d.In()
   620  	d.P("m := obj.(*", ccTypeName, ")")
   621  	// Add the null character as a terminator
   622  	d.P(`return true, []byte(m.ID + "\x00"), nil`)
   623  	d.Out()
   624  	d.P("}")
   625  
   626  	// Generate indexer by name
   627  
   628  	d.P("type ", ccTypeName, "IndexerByName struct{}")
   629  	d.P()
   630  
   631  	d.genFromArgs(ccTypeName + "IndexerByName")
   632  	d.genPrefixFromArgs(ccTypeName + "IndexerByName")
   633  
   634  	d.P("func (indexer ", ccTypeName, "IndexerByName) FromObject(obj interface{}) (bool, []byte, error) {")
   635  	d.In()
   636  	d.P("m := obj.(*", ccTypeName, ")")
   637  	if _, hasNoSpec := typesWithNoSpec[*m.Name]; hasNoSpec {
   638  		d.P(`val := m.Annotations.Name`)
   639  	} else {
   640  		d.P(`val := m.Spec.Annotations.Name`)
   641  	}
   642  	// Add the null character as a terminator
   643  	d.P("return true, []byte(", d.stringsPkg.Use(), `.ToLower(val) + "\x00"), nil`)
   644  	d.Out()
   645  	d.P("}")
   646  
   647  	// Generate custom indexer
   648  
   649  	d.P("type ", ccTypeName, "CustomIndexer struct{}")
   650  	d.P()
   651  
   652  	d.genFromArgs(ccTypeName + "CustomIndexer")
   653  	d.genPrefixFromArgs(ccTypeName + "CustomIndexer")
   654  
   655  	d.P("func (indexer ", ccTypeName, "CustomIndexer) FromObject(obj interface{}) (bool, [][]byte, error) {")
   656  	d.In()
   657  	d.P("m := obj.(*", ccTypeName, ")")
   658  	if _, hasNoSpec := typesWithNoSpec[*m.Name]; hasNoSpec {
   659  		d.P(`return customIndexer("", &m.Annotations)`)
   660  	} else {
   661  		d.P(`return customIndexer("", &m.Spec.Annotations)`)
   662  	}
   663  	d.Out()
   664  	d.P("}")
   665  }
   666  
   667  func (d *storeObjectGen) genFromArgs(indexerName string) {
   668  	d.P("func (indexer ", indexerName, ") FromArgs(args ...interface{}) ([]byte, error) {")
   669  	d.In()
   670  	d.P("return fromArgs(args...)")
   671  	d.Out()
   672  	d.P("}")
   673  }
   674  
   675  func (d *storeObjectGen) genPrefixFromArgs(indexerName string) {
   676  	d.P("func (indexer ", indexerName, ") PrefixFromArgs(args ...interface{}) ([]byte, error) {")
   677  	d.In()
   678  	d.P("return prefixFromArgs(args...)")
   679  	d.Out()
   680  	d.P("}")
   681  
   682  }
   683  
   684  func (d *storeObjectGen) genNewStoreAction(topLevelObjs []string) {
   685  	// Generate NewStoreAction
   686  	d.P("func NewStoreAction(c Event) (StoreAction, error) {")
   687  	d.In()
   688  	d.P("var sa StoreAction")
   689  	d.P("switch v := c.(type) {")
   690  	for _, ccTypeName := range topLevelObjs {
   691  		d.P("case EventCreate", ccTypeName, ":")
   692  		d.In()
   693  		d.P("sa.Action = StoreActionKindCreate")
   694  		d.P("sa.Target = &StoreAction_", ccTypeName, "{", ccTypeName, ": v.", ccTypeName, "}")
   695  		d.Out()
   696  		d.P("case EventUpdate", ccTypeName, ":")
   697  		d.In()
   698  		d.P("sa.Action = StoreActionKindUpdate")
   699  		d.P("sa.Target = &StoreAction_", ccTypeName, "{", ccTypeName, ": v.", ccTypeName, "}")
   700  		d.Out()
   701  		d.P("case EventDelete", ccTypeName, ":")
   702  		d.In()
   703  		d.P("sa.Action = StoreActionKindRemove")
   704  		d.P("sa.Target = &StoreAction_", ccTypeName, "{", ccTypeName, ": v.", ccTypeName, "}")
   705  		d.Out()
   706  	}
   707  	d.P("default:")
   708  	d.In()
   709  	d.P("return StoreAction{}, errUnknownStoreAction")
   710  	d.Out()
   711  	d.P("}")
   712  	d.P("return sa, nil")
   713  	d.Out()
   714  	d.P("}")
   715  	d.P()
   716  }
   717  
   718  func (d *storeObjectGen) genWatchMessageEvent(topLevelObjs []string) {
   719  	// Generate WatchMessageEvent
   720  	d.P("func WatchMessageEvent(c Event) *WatchMessage_Event {")
   721  	d.In()
   722  	d.P("switch v := c.(type) {")
   723  	for _, ccTypeName := range topLevelObjs {
   724  		d.P("case EventCreate", ccTypeName, ":")
   725  		d.In()
   726  		d.P("return &WatchMessage_Event{Action: WatchActionKindCreate, Object: &Object{Object: &Object_", ccTypeName, "{", ccTypeName, ": v.", ccTypeName, "}}}")
   727  		d.Out()
   728  		d.P("case EventUpdate", ccTypeName, ":")
   729  		d.In()
   730  		d.P("if v.Old", ccTypeName, " != nil {")
   731  		d.In()
   732  		d.P("return &WatchMessage_Event{Action: WatchActionKindUpdate, Object: &Object{Object: &Object_", ccTypeName, "{", ccTypeName, ": v.", ccTypeName, "}}, OldObject: &Object{Object: &Object_", ccTypeName, "{", ccTypeName, ": v.Old", ccTypeName, "}}}")
   733  		d.Out()
   734  		d.P("} else {")
   735  		d.In()
   736  		d.P("return &WatchMessage_Event{Action: WatchActionKindUpdate, Object: &Object{Object: &Object_", ccTypeName, "{", ccTypeName, ": v.", ccTypeName, "}}}")
   737  		d.Out()
   738  		d.P("}")
   739  		d.Out()
   740  		d.P("case EventDelete", ccTypeName, ":")
   741  		d.In()
   742  		d.P("return &WatchMessage_Event{Action: WatchActionKindRemove, Object: &Object{Object: &Object_", ccTypeName, "{", ccTypeName, ": v.", ccTypeName, "}}}")
   743  		d.Out()
   744  	}
   745  	d.P("}")
   746  	d.P("return nil")
   747  	d.Out()
   748  	d.P("}")
   749  	d.P()
   750  }
   751  
   752  func (d *storeObjectGen) genEventFromStoreAction(topLevelObjs []string) {
   753  	// Generate EventFromStoreAction
   754  	d.P("func EventFromStoreAction(sa StoreAction, oldObject StoreObject) (Event, error) {")
   755  	d.In()
   756  	d.P("switch v := sa.Target.(type) {")
   757  	for _, ccTypeName := range topLevelObjs {
   758  		d.P("case *StoreAction_", ccTypeName, ":")
   759  		d.In()
   760  		d.P("switch sa.Action {")
   761  
   762  		d.P("case StoreActionKindCreate:")
   763  		d.In()
   764  		d.P("return EventCreate", ccTypeName, "{", ccTypeName, ": v.", ccTypeName, "}, nil")
   765  		d.Out()
   766  
   767  		d.P("case StoreActionKindUpdate:")
   768  		d.In()
   769  		d.P("if oldObject != nil {")
   770  		d.In()
   771  		d.P("return EventUpdate", ccTypeName, "{", ccTypeName, ": v.", ccTypeName, ", Old", ccTypeName, ": oldObject.(*", ccTypeName, ")}, nil")
   772  		d.Out()
   773  		d.P("} else {")
   774  		d.In()
   775  		d.P("return EventUpdate", ccTypeName, "{", ccTypeName, ": v.", ccTypeName, "}, nil")
   776  		d.Out()
   777  		d.P("}")
   778  		d.Out()
   779  
   780  		d.P("case StoreActionKindRemove:")
   781  		d.In()
   782  		d.P("return EventDelete", ccTypeName, "{", ccTypeName, ": v.", ccTypeName, "}, nil")
   783  		d.Out()
   784  
   785  		d.P("}")
   786  		d.Out()
   787  	}
   788  	d.P("}")
   789  	d.P("return nil, errUnknownStoreAction")
   790  	d.Out()
   791  	d.P("}")
   792  	d.P()
   793  }
   794  
   795  func (d *storeObjectGen) genConvertWatchArgs(topLevelObjs []string) {
   796  	// Generate ConvertWatchArgs
   797  	d.P("func ConvertWatchArgs(entries []*WatchRequest_WatchEntry) ([]Event, error) {")
   798  	d.In()
   799  	d.P("var events []Event")
   800  	d.P("for _, entry := range entries {")
   801  	d.In()
   802  	d.P("var newEvents []Event")
   803  	d.P("var err error")
   804  	d.P("switch entry.Kind {")
   805  	d.P(`case "":`)
   806  	d.In()
   807  	d.P("return nil, errNoKindSpecified")
   808  	d.Out()
   809  	for _, ccTypeName := range topLevelObjs {
   810  		if ccTypeName == "Resource" {
   811  			d.P("default:")
   812  			d.In()
   813  			d.P("newEvents, err = ConvertResourceWatch(entry.Action, entry.Filters, entry.Kind)")
   814  			d.Out()
   815  		} else {
   816  			d.P(`case "`, strings.ToLower(ccTypeName), `":`)
   817  			d.In()
   818  			d.P("newEvents, err = Convert", ccTypeName, "Watch(entry.Action, entry.Filters)")
   819  			d.Out()
   820  		}
   821  	}
   822  	d.P("}")
   823  	d.P("if err != nil {")
   824  	d.In()
   825  	d.P("return nil, err")
   826  	d.Out()
   827  	d.P("}")
   828  	d.P("events = append(events, newEvents...)")
   829  
   830  	d.Out()
   831  	d.P("}")
   832  	d.P("return events, nil")
   833  	d.Out()
   834  	d.P("}")
   835  	d.P()
   836  }
   837  
   838  func (d *storeObjectGen) Generate(file *generator.FileDescriptor) {
   839  	d.PluginImports = generator.NewPluginImports(d.Generator)
   840  	d.eventsPkg = d.NewImport("github.com/docker/go-events")
   841  	d.stringsPkg = d.NewImport("strings")
   842  
   843  	var topLevelObjs []string
   844  
   845  	for _, m := range file.Messages() {
   846  		if m.DescriptorProto.GetOptions().GetMapEntry() {
   847  			continue
   848  		}
   849  
   850  		if m.Options == nil {
   851  			continue
   852  		}
   853  		storeObjIntf, err := proto.GetExtension(m.Options, plugin.E_StoreObject)
   854  		if err != nil {
   855  			// no StoreObject extension
   856  			continue
   857  		}
   858  
   859  		d.genMsgStoreObject(m, storeObjIntf.(*plugin.StoreObject))
   860  
   861  		topLevelObjs = append(topLevelObjs, generator.CamelCaseSlice(m.TypeName()))
   862  	}
   863  
   864  	if len(topLevelObjs) != 0 {
   865  		d.genNewStoreAction(topLevelObjs)
   866  		d.genEventFromStoreAction(topLevelObjs)
   867  
   868  		// for watch API
   869  		d.genWatchMessageEvent(topLevelObjs)
   870  		d.genConvertWatchArgs(topLevelObjs)
   871  	}
   872  }