...

Source file src/helm.sh/helm/v3/internal/sympath/walk.go

Documentation: helm.sh/helm/v3/internal/sympath

     1  /*
     2  Copyright (c) for portions of walk.go are held by The Go Authors, 2009 and are
     3  provided under the BSD license.
     4  
     5  https://github.com/golang/go/blob/master/LICENSE
     6  
     7  Copyright The Helm Authors.
     8  Licensed under the Apache License, Version 2.0 (the "License");
     9  you may not use this file except in compliance with the License.
    10  You may obtain a copy of the License at
    11  
    12  http://www.apache.org/licenses/LICENSE-2.0
    13  
    14  Unless required by applicable law or agreed to in writing, software
    15  distributed under the License is distributed on an "AS IS" BASIS,
    16  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    17  See the License for the specific language governing permissions and
    18  limitations under the License.
    19  */
    20  
    21  package sympath
    22  
    23  import (
    24  	"log"
    25  	"os"
    26  	"path/filepath"
    27  	"sort"
    28  
    29  	"github.com/pkg/errors"
    30  )
    31  
    32  // Walk walks the file tree rooted at root, calling walkFn for each file or directory
    33  // in the tree, including root. All errors that arise visiting files and directories
    34  // are filtered by walkFn. The files are walked in lexical order, which makes the
    35  // output deterministic but means that for very large directories Walk can be
    36  // inefficient. Walk follows symbolic links.
    37  func Walk(root string, walkFn filepath.WalkFunc) error {
    38  	info, err := os.Lstat(root)
    39  	if err != nil {
    40  		err = walkFn(root, nil, err)
    41  	} else {
    42  		err = symwalk(root, info, walkFn)
    43  	}
    44  	if err == filepath.SkipDir {
    45  		return nil
    46  	}
    47  	return err
    48  }
    49  
    50  // readDirNames reads the directory named by dirname and returns
    51  // a sorted list of directory entries.
    52  func readDirNames(dirname string) ([]string, error) {
    53  	f, err := os.Open(dirname)
    54  	if err != nil {
    55  		return nil, err
    56  	}
    57  	names, err := f.Readdirnames(-1)
    58  	f.Close()
    59  	if err != nil {
    60  		return nil, err
    61  	}
    62  	sort.Strings(names)
    63  	return names, nil
    64  }
    65  
    66  // symwalk recursively descends path, calling walkFn.
    67  func symwalk(path string, info os.FileInfo, walkFn filepath.WalkFunc) error {
    68  	// Recursively walk symlinked directories.
    69  	if IsSymlink(info) {
    70  		resolved, err := filepath.EvalSymlinks(path)
    71  		if err != nil {
    72  			return errors.Wrapf(err, "error evaluating symlink %s", path)
    73  		}
    74  		log.Printf("found symbolic link in path: %s resolves to %s. Contents of linked file included and used", path, resolved)
    75  		if info, err = os.Lstat(resolved); err != nil {
    76  			return err
    77  		}
    78  		if err := symwalk(path, info, walkFn); err != nil && err != filepath.SkipDir {
    79  			return err
    80  		}
    81  		return nil
    82  	}
    83  
    84  	if err := walkFn(path, info, nil); err != nil {
    85  		return err
    86  	}
    87  
    88  	if !info.IsDir() {
    89  		return nil
    90  	}
    91  
    92  	names, err := readDirNames(path)
    93  	if err != nil {
    94  		return walkFn(path, info, err)
    95  	}
    96  
    97  	for _, name := range names {
    98  		filename := filepath.Join(path, name)
    99  		fileInfo, err := os.Lstat(filename)
   100  		if err != nil {
   101  			if err := walkFn(filename, fileInfo, err); err != nil && err != filepath.SkipDir {
   102  				return err
   103  			}
   104  		} else {
   105  			err = symwalk(filename, fileInfo, walkFn)
   106  			if err != nil {
   107  				if (!fileInfo.IsDir() && !IsSymlink(fileInfo)) || err != filepath.SkipDir {
   108  					return err
   109  				}
   110  			}
   111  		}
   112  	}
   113  	return nil
   114  }
   115  
   116  // IsSymlink is used to determine if the fileinfo is a symbolic link.
   117  func IsSymlink(fi os.FileInfo) bool {
   118  	return fi.Mode()&os.ModeSymlink != 0
   119  }
   120  

View as plain text