github.com/haraldrudell/parl@v0.4.176/yamlo/find-file.go (about)

     1  /*
     2  © 2020–present Harald Rudell <harald.rudell@gmail.com> (https://haraldrudell.github.io/haraldrudell/)
     3  ISC License
     4  */
     5  
     6  package yamlo
     7  
     8  /*
     9  filename: program-host.yaml program.yaml
    10  Directories: ~/apps .. /etc
    11  */
    12  
    13  import (
    14  	"errors"
    15  	"fmt"
    16  	"io/fs"
    17  	"os"
    18  	"path"
    19  	"path/filepath"
    20  
    21  	"github.com/haraldrudell/parl/perrors"
    22  	"github.com/haraldrudell/parl/pfs"
    23  	"github.com/haraldrudell/parl/pos"
    24  )
    25  
    26  const (
    27  	emptyDir = "."
    28  	appsName = "apps"
    29  	etcName  = "/etc"
    30  	yamlExt  = ".yaml"
    31  )
    32  
    33  // FindFile locates and reads the yaml file
    34  //   - if filename is empty, try dirs: [~/app, .., /etc] files: [app-host.yaml, app.yaml]
    35  //   - readFilename is absolute, cleaned filename
    36  func FindFile(filename, program string) (readFilename string, byts []byte, err error) {
    37  
    38  	// try provided filename, must exist
    39  	if filename != "" {
    40  		if filename, err = filepath.Abs(filename); perrors.IsPF(&err, "filepath.Abs %w", err) {
    41  			return // filename bad
    42  		}
    43  		if byts, _, err = readFile(filename); err == nil {
    44  			readFilename = filename
    45  		}
    46  		return // filename set return
    47  	}
    48  
    49  	// [~/app, .., /etc]
    50  	var dirs = []string{path.Join(pos.UserHomeDir(), appsName), pos.ParentDir(), pfs.Abs(etcName)}
    51  	// [app-host.yaml, app.yaml]
    52  	var filenames = []string{
    53  		fmt.Sprintf("%s-%s%s", program, pos.ShortHostname(), yamlExt),
    54  		program + yamlExt,
    55  	}
    56  	var doesNotExist bool
    57  	for _, dir := range dirs {
    58  		for _, f := range filenames {
    59  			filename = path.Join(dir, f)
    60  			if byts, doesNotExist, err = readFile(filename); err == nil {
    61  				readFilename = filename
    62  				return // successful read return
    63  			} else if !doesNotExist {
    64  				return // some error return
    65  			}
    66  			err = nil // ignore file not found error
    67  		}
    68  	}
    69  	return // no file existed return
    70  }
    71  
    72  // readFile read the contents of the file fiename
    73  //   - if err is nil, byts has content
    74  //   - if err is non-nil and doesNotExist is true, the file does not exist
    75  //   - if err is non-nil and doesNotExist is false, an error occurred
    76  func readFile(filename string) (byts []byte, doesNotExist bool, err error) {
    77  	if byts, err = os.ReadFile(filename); perrors.IsPF(&err, "os.ReadFile: %w", err) {
    78  		doesNotExist = errors.Is(err, fs.ErrNotExist)
    79  	}
    80  	return
    81  }