github.com/GoogleContainerTools/kpt@v1.0.0-beta.50.0.20240520170205-c25345ffcbee/internal/util/argutil/argutil.go (about)

     1  // Copyright 2019 The kpt Authors
     2  //
     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  // The argutil package contains libraries for parsing commandline args.
    16  package argutil
    17  
    18  import (
    19  	"context"
    20  	"fmt"
    21  	"os"
    22  	"path/filepath"
    23  	"strings"
    24  
    25  	"github.com/GoogleContainerTools/kpt/pkg/printer"
    26  	"sigs.k8s.io/kustomize/kyaml/errors"
    27  )
    28  
    29  var ErrMultiVersion = fmt.Errorf("at most 1 version permitted")
    30  
    31  // ParseDirVersion parses given string of the form dir@verion and returns dir
    32  // and version.
    33  func ParseDirVersion(dirVer string) (string, string, error) {
    34  	if dirVer == "" {
    35  		return "", "", nil
    36  	}
    37  	if !strings.Contains(dirVer, "@") {
    38  		return dirVer, "", nil
    39  	}
    40  	parts := strings.Split(dirVer, "@")
    41  	if len(parts) > 2 {
    42  		return "", "", ErrMultiVersion
    43  	}
    44  	return parts[0], parts[1], nil
    45  }
    46  
    47  // ParseDirVersionWithDefaults parses given string of the form dir@version and
    48  // returns dir and version with following defaults.
    49  // if dir is missing, return current working directory
    50  // if version is missing, return "master"
    51  func ParseDirVersionWithDefaults(dirVer string) (string, string, error) {
    52  	dir, version, err := ParseDirVersion(dirVer)
    53  	if err != nil {
    54  		return dir, version, err
    55  	}
    56  	if dir == "" {
    57  		dir = "./"
    58  	}
    59  	if version == "" {
    60  		version = "master"
    61  	}
    62  	return dir, version, nil
    63  }
    64  
    65  // ParseFieldPath parse a flag value into a field path
    66  // TODO(pwittrock): Extract this into lib.kpt.dev
    67  func ParseFieldPath(path string) ([]string, error) {
    68  	// fixup '\.' so we don't split on it
    69  	match := strings.ReplaceAll(path, "\\.", "$$$$")
    70  	parts := strings.Split(match, ".")
    71  	for i := range parts {
    72  		parts[i] = strings.ReplaceAll(parts[i], "$$$$", ".")
    73  	}
    74  
    75  	// split the list index from the list field
    76  	var newParts []string
    77  	for i := range parts {
    78  		if !strings.Contains(parts[i], "[") {
    79  			newParts = append(newParts, parts[i])
    80  			continue
    81  		}
    82  		p := strings.Split(parts[i], "[")
    83  		if len(p) != 2 {
    84  			return nil, errors.Errorf("unrecognized path element: %s.  "+
    85  				"Should be of the form 'list[field=value]'", parts[i])
    86  		}
    87  		p[1] = "[" + p[1]
    88  		newParts = append(newParts, p[0], p[1])
    89  	}
    90  	return newParts, nil
    91  }
    92  
    93  // ResolveSymlink returns the resolved symlink path for the input path
    94  func ResolveSymlink(ctx context.Context, path string) (string, error) {
    95  	isSymlink := false
    96  	f, err := os.Lstat(path)
    97  	if err == nil {
    98  		// this step only helps with printing WARN message by checking if the input
    99  		// path has symlink, so do not error out at this phase and let
   100  		// filepath.EvalSymlinks(path) handle the cases
   101  		if f.Mode().Type() == os.ModeSymlink {
   102  			isSymlink = true
   103  		}
   104  	}
   105  	rp, err := filepath.EvalSymlinks(path)
   106  	if err != nil {
   107  		return "", err
   108  	}
   109  	if isSymlink {
   110  		fmt.Fprintf(printer.FromContextOrDie(ctx).ErrStream(), "[WARN] resolved symlink %q to %q, please note that the symlinks within the package are ignored\n", path, rp)
   111  	}
   112  	return rp, nil
   113  }