github.com/StackExchange/blackbox/v2@v2.0.1-0.20220331193400-d84e904973ab/pkg/bbutil/filestats.go (about)

     1  package bbutil
     2  
     3  import (
     4  	"fmt"
     5  	"io/ioutil"
     6  	"os"
     7  	"path/filepath"
     8  	"sort"
     9  	"strings"
    10  	"time"
    11  )
    12  
    13  // DirExists returns true if directory exists.
    14  func DirExists(path string) (bool, error) {
    15  	stat, err := os.Stat(path)
    16  	if err == nil {
    17  		return stat.IsDir(), nil
    18  	}
    19  	if os.IsNotExist(err) {
    20  		return false, nil
    21  	}
    22  	return true, err
    23  }
    24  
    25  // FileExistsOrProblem returns true if the file exists or if we can't determine its existence.
    26  func FileExistsOrProblem(path string) bool {
    27  	_, err := os.Stat(path)
    28  	if err == nil {
    29  		return true
    30  	}
    31  	if os.IsNotExist(err) {
    32  		return false
    33  	}
    34  	return true
    35  }
    36  
    37  // Touch updates the timestamp of a file.
    38  func Touch(name string) error {
    39  	var err error
    40  	_, err = os.Stat(name)
    41  	if os.IsNotExist(err) {
    42  		file, err := os.Create(name)
    43  		if err != nil {
    44  			return fmt.Errorf("TouchFile failed: %w", err)
    45  		}
    46  		file.Close()
    47  	}
    48  
    49  	currentTime := time.Now().Local()
    50  	return os.Chtimes(name, currentTime, currentTime)
    51  }
    52  
    53  // ReadFileLines is like ioutil.ReadFile() but returns an []string.
    54  func ReadFileLines(filename string) ([]string, error) {
    55  	b, err := ioutil.ReadFile(filename)
    56  	if err != nil {
    57  		return nil, err
    58  	}
    59  	s := string(b)
    60  	s = strings.TrimSuffix(s, "\n")
    61  	if s == "" {
    62  		return []string{}, nil
    63  	}
    64  	l := strings.Split(s, "\n")
    65  	return l, nil
    66  }
    67  
    68  // AddLinesToSortedFile adds a line to a sorted file.
    69  func AddLinesToSortedFile(filename string, newlines ...string) error {
    70  	lines, err := ReadFileLines(filename)
    71  	//fmt.Printf("DEBUG: read=%q\n", lines)
    72  	if err != nil {
    73  		return fmt.Errorf("AddLinesToSortedFile can't read %q: %w", filename, err)
    74  	}
    75  	if !sort.StringsAreSorted(lines) {
    76  		return fmt.Errorf("AddLinesToSortedFile: file wasn't sorted: %v", filename)
    77  	}
    78  	lines = append(lines, newlines...)
    79  	sort.Strings(lines)
    80  	contents := strings.Join(lines, "\n") + "\n"
    81  	//fmt.Printf("DEBUG: write=%q\n", contents)
    82  	err = ioutil.WriteFile(filename, []byte(contents), 0o660)
    83  	if err != nil {
    84  		return fmt.Errorf("AddLinesToSortedFile can't write %q: %w", filename, err)
    85  	}
    86  	return nil
    87  }
    88  
    89  // AddLinesToFile adds lines to the end of a file.
    90  func AddLinesToFile(filename string, newlines ...string) error {
    91  	lines, err := ReadFileLines(filename)
    92  	if err != nil {
    93  		return fmt.Errorf("AddLinesToFile can't read %q: %w", filename, err)
    94  	}
    95  	lines = append(lines, newlines...)
    96  	contents := strings.Join(lines, "\n") + "\n"
    97  	err = ioutil.WriteFile(filename, []byte(contents), 0o660)
    98  	if err != nil {
    99  		return fmt.Errorf("AddLinesToFile can't write %q: %w", filename, err)
   100  	}
   101  	return nil
   102  }
   103  
   104  // FindDirInParent looks for target in CWD, or .., or ../.., etc.
   105  func FindDirInParent(target string) (string, error) {
   106  	// Prevent an infinite loop by only doing "cd .." this many times
   107  	maxDirLevels := 30
   108  	relpath := "."
   109  	for i := 0; i < maxDirLevels; i++ {
   110  		// Does relpath contain our target?
   111  		t := filepath.Join(relpath, target)
   112  		//logDebug.Printf("Trying %q\n", t)
   113  		_, err := os.Stat(t)
   114  		if err == nil {
   115  			return t, nil
   116  		}
   117  		if !os.IsNotExist(err) {
   118  			return "", fmt.Errorf("stat failed FindDirInParent (%q): %w", t, err)
   119  		}
   120  		// Ok, it really wasn't found.
   121  
   122  		// If we are at the root, stop.
   123  		if abs, err := filepath.Abs(relpath); err == nil && abs == "/" {
   124  			break
   125  		}
   126  		// Try one directory up
   127  		relpath = filepath.Join("..", relpath)
   128  	}
   129  	return "", fmt.Errorf("Not found")
   130  }