55 "fmt"
66
77 "k8s.io/apimachinery/pkg/api/meta"
8+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
89 "k8s.io/apimachinery/pkg/runtime"
910 "k8s.io/apimachinery/pkg/watch"
1011 runtimeclient "sigs.k8s.io/controller-runtime/pkg/client"
@@ -17,23 +18,52 @@ type WatchFunc func(list runtimeclient.ObjectList) error
1718// All namespaces is easy to solve but all projects would mean a goroutine/watch
1819// per project.
1920func (c * Client ) watch (ctx context.Context , list runtimeclient.ObjectList , options ... ListOpt ) error {
20- // this is a bit awkward: we need to extract some functional options. We do
21- // this by executing each opt and checking the result.
21+ // this is a bit awkward: we need to extract some functional options and
22+ // make sure we don't pass the watch option down to c.ListObjects as that
23+ // will cause infinite recursion. We do this by executing each opt and
24+ // checking the result.
25+ newOptions := []ListOpt {}
2226 var watchFunc WatchFunc
2327 var clientListOptions []runtimeclient.ListOption
2428 for _ , opt := range options {
2529 opts := & ListOpts {}
2630 opt (opts )
31+ if ! opts .watch {
32+ newOptions = append (newOptions , opt )
33+ }
2734 if opts .watchFunc != nil {
2835 watchFunc = opts .watchFunc
2936 }
3037 if opts .clientListOptions != nil {
3138 clientListOptions = opts .clientListOptions
3239 }
3340 }
41+ // do an initial list call, this is to get immediate output of the current
42+ // list if it has any items. After that updates will be streamed in by the
43+ // watch. If we would just call watch immediately, the list wouldn't be
44+ // properly formatted as the tab writer and sort logic would not have the
45+ // full list to work with.
46+ if err := c .ListObjects (ctx , list , newOptions ... ); err != nil {
47+ return err
48+ }
49+ items , err := itemsFromObjectList (list )
50+ if err != nil {
51+ return err
52+ }
53+ if items .Len () > 0 {
54+ if err := watchFunc (list ); err != nil {
55+ return err
56+ }
57+ }
3458
3559 wa , err := c .Watch (ctx , list , append (clientListOptions , & runtimeclient.ListOptions {
3660 Namespace : c .Project ,
61+ Raw : & metav1.ListOptions {
62+ // in order to get around the initial list of items, we make a
63+ // previous list call and then set the resource version of the
64+ // returned list.
65+ ResourceVersion : list .GetResourceVersion (),
66+ },
3767 })... )
3868 if err != nil {
3969 return fmt .Errorf ("watching resources: %w" , err )
0 commit comments