github.com/oam-dev/kubevela@v1.9.11/pkg/utils/file.go (about)

     1  /*
     2  Copyright 2022 The KubeVela Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8  	http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package utils
    18  
    19  import (
    20  	"context"
    21  	"fmt"
    22  	"io"
    23  	"io/fs"
    24  	"net/url"
    25  	"os"
    26  	"path/filepath"
    27  	"strings"
    28  
    29  	"github.com/pkg/errors"
    30  
    31  	"github.com/oam-dev/kubevela/pkg/utils/common"
    32  )
    33  
    34  // FileData data of a file at the path
    35  type FileData struct {
    36  	Path string
    37  	Data []byte
    38  }
    39  
    40  // LoadDataFromPath load FileData from path
    41  // If path is an url, fetch the data from the url
    42  // If path is a file, fetch the data from the file
    43  // If path is a dir, fetch the data from all the files inside the dir that passes the pathFilter
    44  func LoadDataFromPath(ctx context.Context, path string, pathFilter func(string) bool) ([]FileData, error) {
    45  	if path == "-" {
    46  		bs, err := io.ReadAll(os.Stdin)
    47  		if err != nil {
    48  			return nil, fmt.Errorf("failed to get data from stdin: %w", err)
    49  		}
    50  		return []FileData{{Path: path, Data: bs}}, nil
    51  	}
    52  
    53  	if IsValidURL(path) {
    54  		bs, err := common.HTTPGetWithOption(ctx, path, nil)
    55  		if err != nil {
    56  			return nil, fmt.Errorf("failed to get data from %s: %w", path, err)
    57  		}
    58  		return []FileData{{Path: path, Data: bs}}, nil
    59  	}
    60  	fileInfo, err := os.Stat(path)
    61  	if err != nil {
    62  		return nil, fmt.Errorf("failed to get file info for %s: %w", path, err)
    63  	}
    64  	if fileInfo.IsDir() {
    65  		var data []FileData
    66  		err = filepath.WalkDir(path, func(path string, d fs.DirEntry, err error) error {
    67  			if pathFilter == nil || pathFilter(path) {
    68  				bs, e := os.ReadFile(filepath.Clean(path))
    69  				if e != nil {
    70  					return e
    71  				}
    72  				data = append(data, FileData{Path: path, Data: bs})
    73  			}
    74  			return nil
    75  		})
    76  		if err != nil {
    77  			return nil, fmt.Errorf("failed to traverse directory %s: %w", path, err)
    78  		}
    79  		return data, nil
    80  	}
    81  	bs, e := os.ReadFile(filepath.Clean(path))
    82  	if e != nil {
    83  		return nil, fmt.Errorf("failed to read file %s: %w", path, err)
    84  	}
    85  	return []FileData{{Path: path, Data: bs}}, nil
    86  }
    87  
    88  // IsJSONYAMLorCUEFile check if the path is a json or yaml file
    89  func IsJSONYAMLorCUEFile(path string) bool {
    90  	return strings.HasSuffix(path, ".json") ||
    91  		strings.HasSuffix(path, ".yaml") ||
    92  		strings.HasSuffix(path, ".yml") ||
    93  		strings.HasSuffix(path, ".cue")
    94  }
    95  
    96  // IsCUEFile check if the path is a cue file
    97  func IsCUEFile(path string) bool {
    98  	return strings.HasSuffix(path, ".cue")
    99  }
   100  
   101  // IsEmptyDir checks if a given path is an empty directory
   102  func IsEmptyDir(path string) (bool, error) {
   103  	f, err := os.Open(filepath.Clean(path))
   104  	if err != nil {
   105  		return false, err
   106  	}
   107  	defer func(f *os.File) {
   108  		_ = f.Close()
   109  	}(f)
   110  
   111  	// Read just one file in the dir (just read names, which is faster)
   112  	_, err = f.Readdirnames(1)
   113  	// If the error is EOF, the dir is empty
   114  	if errors.Is(err, io.EOF) {
   115  		return true, nil
   116  	}
   117  
   118  	return false, err
   119  }
   120  
   121  // GetFilenameFromLocalOrRemote returns the filename of a local path or a URL.
   122  // It doesn't guarantee that the file or URL actually exists.
   123  func GetFilenameFromLocalOrRemote(path string) (string, error) {
   124  	if !IsValidURL(path) {
   125  		abs, err := filepath.Abs(path)
   126  		if err != nil {
   127  			return "", err
   128  		}
   129  		return strings.TrimSuffix(filepath.Base(abs), filepath.Ext(abs)), nil
   130  	}
   131  
   132  	u, err := url.Parse(path)
   133  	if err != nil {
   134  		return "", err
   135  	}
   136  
   137  	return strings.TrimSuffix(filepath.Base(u.Path), filepath.Ext(u.Path)), nil
   138  }