Repository: kubernetes/kubernetes
File: staging/src/k8s.io/kubectl/pkg/cmd/wait/wait.go (Go)

Code before:
}

// UIDMap maps ResourceLocation with UID
type UIDMap map[ResourceLocation]types.UID

// WaitOptions is a set of options that allows you to wait.  This is the object reflects the runtime needs of a wait
// command, making the logic itself easy to unit test with our existing mocks.
type WaitOptions struct {
	ResourceFinder genericclioptions.ResourceFinder
	// UIDMap maps a resource location to a UID.  It is optional, but ConditionFuncs may choose to use it to make the result
	// more reliable.  For instance, delete can look for UID consistency during delegated calls.
	UIDMap        UIDMap
	DynamicClient dynamic.Interface
	Timeout       time.Duration
	ForCondition  string

	Printer     printers.ResourcePrinter
	ConditionFn ConditionFunc
	genericiooptions.IOStreams
}

// ConditionFunc is the interface for providing condition checks
type ConditionFunc func(ctx context.Context, info *resource.Info, o *WaitOptions) (finalObject runtime.Object, done bool, err error)

// RunWait runs the waiting logic
func (o *WaitOptions) RunWait() error {
	return o.RunWaitContext(context.Background())
}

// RunWaitContext runs the waiting logic with the provided context.
func (o *WaitOptions) RunWaitContext(ctx context.Context) error {
	ctx, cancel := watchtools.ContextWithOptionalTimeout(ctx, o.Timeout)
	defer cancel()
	if strings.ToLower(o.ForCondition) == "create" {
		// TODO(soltysh): this is not ideal solution, because we're polling every .5s,
		// and we have to use ResourceFinder, which contains the resource name.
		// In the long run, we should expose resource information from ResourceFinder,
		// or functions from ResourceBuilder for parsing those. Lastly, this poll
		// should be replaced with a ListWatch cache.
		if err := wait.PollUntilContextTimeout(ctx, 500*time.Millisecond, o.Timeout, true, func(context.Context) (done bool, err error) {
			foundResource := false
			visitErr := o.ResourceFinder.Do().Visit(func(info *resource.Info, err error) error {
				foundResource = true
				return nil
			})
			if apierrors.IsNotFound(visitErr) {
				return false, nil
			}
			if visitErr != nil {
				return false, visitErr
			}

Review comment (suggestion):
Let's deprecate this method when doing this, add:
```
// Deprecated: Use RunWaitContext instead, which allows canceling.
```


Code after:
}

// UIDMap maps ResourceLocation with UID
type UIDMap map[ResourceLocation]types.UID

// WaitOptions is a set of options that allows you to wait.  This is the object reflects the runtime needs of a wait
// command, making the logic itself easy to unit test with our existing mocks.
type WaitOptions struct {
	ResourceFinder genericclioptions.ResourceFinder
	// UIDMap maps a resource location to a UID.  It is optional, but ConditionFuncs may choose to use it to make the result
	// more reliable.  For instance, delete can look for UID consistency during delegated calls.
	UIDMap        UIDMap
	DynamicClient dynamic.Interface
	Timeout       time.Duration
	ForCondition  string

	Printer     printers.ResourcePrinter
	ConditionFn ConditionFunc
	genericiooptions.IOStreams
}

// ConditionFunc is the interface for providing condition checks
type ConditionFunc func(ctx context.Context, info *resource.Info, o *WaitOptions) (finalObject runtime.Object, done bool, err error)

// Deprecated: Use RunWaitContext instead, which allows canceling.
func (o *WaitOptions) RunWait() error {
	return o.RunWaitContext(context.Background())
}

// RunWaitContext runs the waiting logic
func (o *WaitOptions) RunWaitContext(ctx context.Context) error {
	ctx, cancel := watchtools.ContextWithOptionalTimeout(ctx, o.Timeout)
	defer cancel()
	if strings.ToLower(o.ForCondition) == "create" {
		// TODO(soltysh): this is not ideal solution, because we're polling every .5s,
		// and we have to use ResourceFinder, which contains the resource name.
		// In the long run, we should expose resource information from ResourceFinder,
		// or functions from ResourceBuilder for parsing those. Lastly, this poll
		// should be replaced with a ListWatch cache.
		if err := wait.PollUntilContextTimeout(ctx, 500*time.Millisecond, o.Timeout, true, func(context.Context) (done bool, err error) {
			foundResource := false
			visitErr := o.ResourceFinder.Do().Visit(func(info *resource.Info, err error) error {
				foundResource = true
				return nil
			})
			if apierrors.IsNotFound(visitErr) {
				return false, nil
			}
			if visitErr != nil {
				return false, visitErr
			}