sq/testh/proj/proj.go
Neil O'Toole 425702e7ba
The linting goes on forever (#119)
* linting

* yet more linting

* yet more linting

* yet more linting

* yet more linting

* yet more linting
2022-12-17 23:07:38 -07:00

208 lines
4.2 KiB
Go

// Package proj contains test utilities for dealing with project
// paths and the like. The sq project dir is accessed via the
// Dir function. When proj's init function returns, certain envars
// such as SQ_ROOT are guaranteed to be set. Thus the following
// will work as expected:
//
// p := proj.Expand("${SQ_ROOT}/go.mod")
package proj
import (
"bufio"
"os"
"path/filepath"
"strings"
"github.com/neilotoole/sq/libsq/core/stringz"
)
const (
// EnvRoot is the name of the envar holding the path of
// the sq project root.
EnvRoot = "SQ_ROOT"
// EnvPassw is the name of the envar holding the standard
// password used for testing.
EnvPassw = "SQ_PASSW"
// DefaultPassw is the default password used for testing.
DefaultPassw = "p_ssW0rd"
EnvLogFile = "SQ_LOGFILE"
)
var projDir string
func init() { //nolint:gochecknoinits
envar, ok := os.LookupEnv(EnvPassw)
if !ok || envar == "" {
err := os.Setenv(EnvPassw, DefaultPassw)
if err != nil {
panic(err)
}
}
var path string
envar, ok = os.LookupEnv(EnvRoot)
if !ok || envar == "" {
dir, err := os.Getwd()
if err != nil {
panic(err)
}
for {
if isProjDir(dir) {
path = dir
break
}
if os.IsPathSeparator(dir[len(dir)-1]) {
// per filepath.Dir contract, we're at the root
break
}
dir = filepath.Dir(dir)
}
if path == "" {
panic("unable to determine sq project dir")
}
// If we get here, we've found the proj dir.
// Set the env so that os.ExpandEnv etc can use the envar
err = os.Setenv(EnvRoot, path)
if err != nil {
panic(err)
}
} else {
var err error
path, err = filepath.Abs(envar)
if err != nil {
panic(err)
}
if !isProjDir(path) {
panic("envar " + EnvRoot + " does not appear to be sq project dir: " + envar)
}
}
projDir = path
}
// isProjDir returns true if dir contains a go.mod file
// containing sq's module declaration. Any io error panics.
func isProjDir(dir string) bool {
files, err := os.ReadDir(dir)
if err != nil {
panic(err)
}
var gotMatch bool
for _, fi := range files {
if fi.Name() == "go.mod" {
gotMatch = true
break
}
}
if !gotMatch {
return false
}
f, err := os.Open(filepath.Join(dir, "go.mod"))
if err != nil {
panic(err)
}
gotMatch = false // reuse var
scanner := bufio.NewScanner(f)
for scanner.Scan() {
if scanner.Text() == `module github.com/neilotoole/sq` {
gotMatch = true
break
}
}
err = f.Close()
if err != nil {
panic(err)
}
return gotMatch
}
// Dir returns the absolute path to the root of the sq project,
// as set in envar EnvRoot or determined programmatically.
func Dir() string {
return projDir
}
// Rel returns the relative path from the current
// working dir to path, where path is relative to the project dir.
// This is useful for accessing common test fixtures across
// packages.
func Rel(path string) string {
abs := filepath.Join(Dir(), path)
cwd, err := os.Getwd()
if err != nil {
panic(err)
}
relPath, err := filepath.Rel(cwd, abs)
if err != nil {
panic(err)
}
return relPath
}
// Abs returns the absolute path of projRelPath,
// where projRelPath is relative to the project dir.
func Abs(projRelPath string) string {
return filepath.Join(Dir(), projRelPath)
}
// ReadFile is a convenience function for reading
// a file under the proj dir. It's equivalent to
// os.ReadFile(proj.Abs(path)) but panics on any error.
func ReadFile(projRelPath string) []byte {
p := Abs(projRelPath)
d, err := os.ReadFile(p)
if err != nil {
panic(err)
}
return d
}
// Expand wraps os.ExpandEnv. This function is preferred
// as it ensures that envar SQ_ROOT is set (via
// proj's init function).
func Expand(s string) string {
return os.ExpandEnv(s)
}
// Passw returns the password used for testing.
func Passw() string {
return os.Getenv(EnvPassw)
}
// LogFile returns the path to sq's log file, as
// specified by EnvLogFile. If none set, the empty
// string is returned.
func LogFile() string {
return os.Getenv(EnvLogFile)
}
// BoolEnvar returns true if the environment variable e is set
// and its value is boolean true.
func BoolEnvar(envar string) bool {
s, ok := os.LookupEnv(envar)
if !ok {
return false
}
b, _ := stringz.ParseBool(strings.TrimSpace(s))
return b
}