github.com/bazelbuild/remote-apis-sdks@v0.0.0-20240425170053-8a36686a6350/go/pkg/symlinkopts/opts.go (about)

     1  // Package symlinkopts provides an efficient interface to create unambiguous symlink options.
     2  package symlinkopts
     3  
     4  import (
     5  	"fmt"
     6  	"strings"
     7  )
     8  
     9  // Options represents a set of options for handling symlinks. The zero value is equivalent to skipping all symlinks.
    10  type Options struct {
    11  	preserve        bool
    12  	noDangling      bool
    13  	includeTarget   bool
    14  	resolve         bool
    15  	resolveExternal bool
    16  }
    17  
    18  // String returns a string representation of the options.
    19  //
    20  // The string has at most five letters:
    21  //
    22  //	P for Preserve
    23  //	N for No Dangling
    24  //	I for Include Target
    25  //	R for Replace
    26  //	E for Replace External
    27  func (o Options) String() string {
    28  	var b strings.Builder
    29  	if o.preserve {
    30  		fmt.Fprint(&b, "P")
    31  	}
    32  	if o.noDangling {
    33  		fmt.Fprint(&b, "N")
    34  	}
    35  	if o.includeTarget {
    36  		fmt.Fprint(&b, "I")
    37  	}
    38  	if o.resolve {
    39  		fmt.Fprint(&b, "R")
    40  	}
    41  	if o.resolveExternal {
    42  		fmt.Fprint(&b, "E")
    43  	}
    44  	return b.String()
    45  }
    46  
    47  // Preserve returns true if the options include the corresponding property.
    48  func (o Options) Preserve() bool {
    49  	return o.preserve
    50  }
    51  
    52  // NoDangling returns true if the options include the corresponding property.
    53  func (o Options) NoDangling() bool {
    54  	return o.noDangling
    55  }
    56  
    57  // IncludeTarget returns true if the options include the corresponding property.
    58  func (o Options) IncludeTarget() bool {
    59  	return o.includeTarget
    60  }
    61  
    62  // Resolve returns true if the options include the corresponding property.
    63  func (o Options) Resolve() bool {
    64  	return o.resolve
    65  }
    66  
    67  // ResolveExternal returns true if the options include the corresponding property.
    68  func (o Options) ResolveExternal() bool {
    69  	return o.resolveExternal
    70  }
    71  
    72  // Skip returns true if the options indicate that symlinks should be skipped.
    73  func (o Options) Skip() bool {
    74  	return !o.preserve && !o.noDangling && !o.includeTarget && !o.resolve && !o.resolveExternal
    75  }
    76  
    77  // ResolveAlways return the correct set of options to always resolve symlinks.
    78  //
    79  // This implies that symlinks are followed and no dangling symlinks are allowed.
    80  // Every symlink will be replaced by its target. For example, if foo/bar was a symlink
    81  // to the regular file baz, then foo/bar will become a regular file with the content of baz.
    82  func ResolveAlways() Options {
    83  	return Options{
    84  		resolve:         true,
    85  		resolveExternal: true,
    86  		includeTarget:   true,
    87  		noDangling:      true,
    88  	}
    89  }
    90  
    91  // ResolveExternalOnly returns the correct set of options to only resolve symlinks
    92  // if the target is outside the root directory. Otherwise, the symlink is preserved.
    93  //
    94  // This implies that all symlinks are followed, therefore, no dangling links are allowed.
    95  // Otherwise, it's not possible to guarantee that all required files are under the root.
    96  // Targets of non-external symlinks are not included.
    97  func ResolveExternalOnly() Options {
    98  	return Options{
    99  		preserve:        true,
   100  		resolveExternal: true,
   101  		noDangling:      true,
   102  	}
   103  }
   104  
   105  // ResolveExternalOnlyWithTarget is like ResolveExternalOnly but targets of non-external symlinks are included.
   106  func ResolveExternalOnlyWithTarget() Options {
   107  	return Options{
   108  		preserve:        true,
   109  		resolveExternal: true,
   110  		includeTarget:   true,
   111  		noDangling:      true,
   112  	}
   113  }
   114  
   115  // PreserveWithTarget returns the correct set of options to preserve all symlinks and include the targets.
   116  //
   117  // This implies that dangling links are not allowed.
   118  func PreserveWithTarget() Options {
   119  	return Options{
   120  		preserve:      true,
   121  		includeTarget: true,
   122  		noDangling:    true,
   123  	}
   124  }
   125  
   126  // PreserveNoDangling returns the correct set of options to preserve all symlinks without targets.
   127  //
   128  // Targets need to be explicitly included.
   129  // Dangling links are not allowed.
   130  func PreserveNoDangling() Options {
   131  	return Options{
   132  		preserve:   true,
   133  		noDangling: true,
   134  	}
   135  }
   136  
   137  // PreserveAllowDangling returns the correct set of options to preserve all symlinks without targets.
   138  //
   139  // Targets need to be explicitly included.
   140  // Dangling links are allowed.
   141  func PreserveAllowDangling() Options {
   142  	return Options{preserve: true}
   143  }
   144  
   145  // Skip is the zero value for Options which is equivalent to skipping all symlinks (as if they did not exist).
   146  func Skip() Options {
   147  	return Options{}
   148  }