github.com/dtroyer-salad/og2/v2@v2.0.0-20240412154159-c47231610877/registry/remote/credentials/trace/trace.go (about)

     1  /*
     2  Copyright The ORAS Authors.
     3  Licensed under the Apache License, Version 2.0 (the "License");
     4  you may not use this file except in compliance with the License.
     5  You may obtain a copy of the License at
     6  
     7  http://www.apache.org/licenses/LICENSE-2.0
     8  
     9  Unless required by applicable law or agreed to in writing, software
    10  distributed under the License is distributed on an "AS IS" BASIS,
    11  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  See the License for the specific language governing permissions and
    13  limitations under the License.
    14  */
    15  
    16  package trace
    17  
    18  import "context"
    19  
    20  // executableTraceContextKey is a value key used to retrieve the ExecutableTrace
    21  // from Context.
    22  type executableTraceContextKey struct{}
    23  
    24  // ExecutableTrace is a set of hooks used to trace the execution of binary
    25  // executables. Any particular hook may be nil.
    26  type ExecutableTrace struct {
    27  	// ExecuteStart is called before the execution of the executable. The
    28  	// executableName parameter is the name of the credential helper executable
    29  	// used with NativeStore. The action parameter is one of "store", "get" and
    30  	// "erase".
    31  	//
    32  	// Reference:
    33  	//   - https://docs.docker.com/engine/reference/commandline/login#credentials-store
    34  	ExecuteStart func(executableName string, action string)
    35  
    36  	// ExecuteDone is called after the execution of an executable completes.
    37  	// The executableName parameter is the name of the credential helper
    38  	// executable used with NativeStore. The action parameter is one of "store",
    39  	// "get" and "erase". The err parameter is the error (if any) returned from
    40  	// the execution.
    41  	//
    42  	// Reference:
    43  	//   - https://docs.docker.com/engine/reference/commandline/login#credentials-store
    44  	ExecuteDone func(executableName string, action string, err error)
    45  }
    46  
    47  // ContextExecutableTrace returns the ExecutableTrace associated with the
    48  // context. If none, it returns nil.
    49  func ContextExecutableTrace(ctx context.Context) *ExecutableTrace {
    50  	trace, _ := ctx.Value(executableTraceContextKey{}).(*ExecutableTrace)
    51  	return trace
    52  }
    53  
    54  // WithExecutableTrace takes a Context and an ExecutableTrace, and returns a
    55  // Context with the ExecutableTrace added as a Value. If the Context has a
    56  // previously added trace, the hooks defined in the new trace will be added
    57  // in addition to the previous ones. The recent hooks will be called first.
    58  func WithExecutableTrace(ctx context.Context, trace *ExecutableTrace) context.Context {
    59  	if trace == nil {
    60  		return ctx
    61  	}
    62  	if oldTrace := ContextExecutableTrace(ctx); oldTrace != nil {
    63  		trace.compose(oldTrace)
    64  	}
    65  	return context.WithValue(ctx, executableTraceContextKey{}, trace)
    66  }
    67  
    68  // compose takes an oldTrace and modifies the existing trace to include
    69  // the hooks defined in the oldTrace. The hooks in the existing trace will
    70  // be called first.
    71  func (trace *ExecutableTrace) compose(oldTrace *ExecutableTrace) {
    72  	if oldStart := oldTrace.ExecuteStart; oldStart != nil {
    73  		start := trace.ExecuteStart
    74  		if start != nil {
    75  			trace.ExecuteStart = func(executableName, action string) {
    76  				start(executableName, action)
    77  				oldStart(executableName, action)
    78  			}
    79  		} else {
    80  			trace.ExecuteStart = oldStart
    81  		}
    82  	}
    83  	if oldDone := oldTrace.ExecuteDone; oldDone != nil {
    84  		done := trace.ExecuteDone
    85  		if done != nil {
    86  			trace.ExecuteDone = func(executableName, action string, err error) {
    87  				done(executableName, action, err)
    88  				oldDone(executableName, action, err)
    89  			}
    90  		} else {
    91  			trace.ExecuteDone = oldDone
    92  		}
    93  	}
    94  }