Compare commits
9 Commits
b64c318a4a
...
v1.8.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
236165bec8
|
||
|
|
4cb0403e08
|
||
|
|
0318a9759b
|
||
|
|
1a93d5d9f3
|
||
|
|
5dc944cf21
|
||
|
|
77a85a4f84
|
||
|
|
43d1ddfeb8
|
||
|
|
db20c70d86
|
||
|
|
c0c924b75a
|
2
TODO
2
TODO
@@ -4,6 +4,8 @@
|
|||||||
--- https://github.com/hlandau/passlib
|
--- https://github.com/hlandau/passlib
|
||||||
-- incoprporated separately; https://git.r00t2.io/r00t2/PWGen (import r00t2.io/pwgen)
|
-- incoprporated separately; https://git.r00t2.io/r00t2/PWGen (import r00t2.io/pwgen)
|
||||||
|
|
||||||
|
- auger needs to be build-constrained to linux.
|
||||||
|
|
||||||
- unit tests
|
- unit tests
|
||||||
|
|
||||||
- constants/vars for errors
|
- constants/vars for errors
|
||||||
|
|||||||
9
auger/consts.go
Normal file
9
auger/consts.go
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
package auger
|
||||||
|
|
||||||
|
const (
|
||||||
|
augLensTpl string = "/augeas/load/%v" // A fmt.Sprintf string (single placeholder only) for Lens module roots.
|
||||||
|
augFsTree string = "/files"
|
||||||
|
augFsTpl string = augFsTree + "%v//%v" // A fmt.Sprintf string (first placeholder fspath, second placeholder includeDirective) for files to search for the includeDirective.
|
||||||
|
augInclTfm string = "incl" // The transformer keyword for Augeas includes.
|
||||||
|
augAppendSuffix string = "[last()+1]"
|
||||||
|
)
|
||||||
63
auger/funcs.go
Normal file
63
auger/funcs.go
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
package auger
|
||||||
|
|
||||||
|
import (
|
||||||
|
`io/fs`
|
||||||
|
`os`
|
||||||
|
`strings`
|
||||||
|
)
|
||||||
|
|
||||||
|
/*
|
||||||
|
AugpathToFspath returns the filesystem path from an Augeas path.
|
||||||
|
|
||||||
|
It is *required* and expected that the Augeas standard /files prefix be removed first;
|
||||||
|
if not, it is assumed to be part of the filesystem path.
|
||||||
|
|
||||||
|
If a valid path cannot be determined, fsPath will be empty.
|
||||||
|
*/
|
||||||
|
func AugpathToFspath(augPath string) (fsPath string, err error) {
|
||||||
|
|
||||||
|
var path string
|
||||||
|
var num int
|
||||||
|
var augSplit []string = strings.Split(augPath, "/")
|
||||||
|
|
||||||
|
num = len(augSplit)
|
||||||
|
|
||||||
|
for i := num - 1; i >= 0; i-- {
|
||||||
|
path = strings.Join(augSplit[:i], "/")
|
||||||
|
if !fs.ValidPath(path) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if _, err = os.Stat(path); err != nil {
|
||||||
|
if os.IsNotExist(err) {
|
||||||
|
err = nil
|
||||||
|
continue
|
||||||
|
} else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fsPath = path
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// dedupePaths is used to reduce new to only unique entries that do not exist in existing.
|
||||||
|
func dedupePaths(new, existing []string) (missing []string) {
|
||||||
|
|
||||||
|
var ok bool
|
||||||
|
var m map[string]bool = make(map[string]bool)
|
||||||
|
|
||||||
|
for _, path := range existing {
|
||||||
|
m[path] = true
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, path := range new {
|
||||||
|
if _, ok = m[path]; !ok {
|
||||||
|
missing = append(missing, path)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
294
auger/funcs_aug.go
Normal file
294
auger/funcs_aug.go
Normal file
@@ -0,0 +1,294 @@
|
|||||||
|
package auger
|
||||||
|
|
||||||
|
import (
|
||||||
|
`bufio`
|
||||||
|
`errors`
|
||||||
|
`fmt`
|
||||||
|
`io`
|
||||||
|
`os`
|
||||||
|
`path/filepath`
|
||||||
|
`strings`
|
||||||
|
|
||||||
|
`github.com/davecgh/go-spew/spew`
|
||||||
|
`github.com/google/shlex`
|
||||||
|
`honnef.co/go/augeas`
|
||||||
|
`r00t2.io/sysutils/paths`
|
||||||
|
)
|
||||||
|
|
||||||
|
// Close cleanly closes the underlying Augeas connection.
|
||||||
|
func (a *Aug) Close() {
|
||||||
|
|
||||||
|
a.aug.Close()
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Interact provides an interactive shell-like interface for debugging purposes to explore the loaded Augeas tree.
|
||||||
|
func (a *Aug) Interact() (err error) {
|
||||||
|
|
||||||
|
var input string
|
||||||
|
var lexed []string
|
||||||
|
var cmd string
|
||||||
|
var arg string
|
||||||
|
var val string
|
||||||
|
var augVal string
|
||||||
|
var augVals []string
|
||||||
|
var buf *bufio.Reader = bufio.NewReader(os.Stdin)
|
||||||
|
|
||||||
|
fmt.Fprint(os.Stderr, "INTERACTIVE MODE\nCmds: get, getall, match, set, quit\n")
|
||||||
|
breakCmd:
|
||||||
|
for {
|
||||||
|
cmd, arg, val = "", "", ""
|
||||||
|
|
||||||
|
fmt.Fprint(os.Stderr, "> ")
|
||||||
|
if input, err = buf.ReadString('\n'); err != nil {
|
||||||
|
if errors.Is(err, io.EOF) {
|
||||||
|
err = nil
|
||||||
|
break breakCmd
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if strings.TrimSpace(input) == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if lexed, err = shlex.Split(input); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if lexed == nil || len(lexed) == 0 || len(lexed) > 3 {
|
||||||
|
fmt.Fprintf(os.Stderr, "Bad command: %#v\n", lexed)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
cmd = lexed[0]
|
||||||
|
switch len(lexed) {
|
||||||
|
case 2:
|
||||||
|
arg = lexed[1]
|
||||||
|
case 3:
|
||||||
|
arg = lexed[1]
|
||||||
|
val = lexed[2]
|
||||||
|
}
|
||||||
|
switch cmd {
|
||||||
|
case "get":
|
||||||
|
if strings.TrimSpace(arg) == "" {
|
||||||
|
fmt.Fprintln(os.Stderr, "Missing argument")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if augVal, err = a.aug.Get(arg); err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "!! ERROR !!\n%v\n", spew.Sdump(err))
|
||||||
|
err = nil
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
fmt.Fprintln(os.Stderr, augVal)
|
||||||
|
case "getall":
|
||||||
|
if strings.TrimSpace(arg) == "" {
|
||||||
|
fmt.Fprintln(os.Stderr, "Missing argument")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if augVals, err = a.aug.GetAll(arg); err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "!! ERROR !!\n%v\n", spew.Sdump(err))
|
||||||
|
err = nil
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
fmt.Fprintln(os.Stderr, strings.Join(augVals, "\n"))
|
||||||
|
case "match":
|
||||||
|
if strings.TrimSpace(arg) == "" {
|
||||||
|
fmt.Fprintln(os.Stderr, "Missing argument")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if augVals, err = a.aug.Match(arg); err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "!! ERROR !!\n%v\n", spew.Sdump(err))
|
||||||
|
err = nil
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
fmt.Fprintln(os.Stderr, strings.Join(augVals, "\n"))
|
||||||
|
case "set":
|
||||||
|
if strings.TrimSpace(arg) == "" {
|
||||||
|
fmt.Fprintln(os.Stderr, "Missing argument")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if strings.TrimSpace(val) == "" {
|
||||||
|
fmt.Fprintln(os.Stderr, "Missing value")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if err = a.aug.Set(arg, val); err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "!! ERROR !!\n%v\n", spew.Sdump(err))
|
||||||
|
err = nil
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
fmt.Fprintln(os.Stderr, "Success!")
|
||||||
|
case "quit":
|
||||||
|
break breakCmd
|
||||||
|
default:
|
||||||
|
fmt.Fprintf(os.Stderr, "Unknown command: %v\n", cmd)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
RecursiveInclude parses the configuration files belonging to Augeas lens name augLens,
|
||||||
|
searching for all occurrences of includeDirective, loading those files (if they exist),
|
||||||
|
and continuing so forth recursively, loading them into the Augeas file tree.
|
||||||
|
|
||||||
|
If any relative paths are found, they will be assumed to be relative to fsRoot ("/" if empty).
|
||||||
|
For e.g. Nginx, you almost absolutely want to set this to "/etc/nginx", but you really should
|
||||||
|
use absolute paths for every include in your configs if supported by the application; it will
|
||||||
|
lead to much less guesswork and much more accurate recursing/walking.
|
||||||
|
|
||||||
|
Some lens recursively load depending on their respective include directive(s) automatically;
|
||||||
|
some (such as the Nginx lens) do not.
|
||||||
|
|
||||||
|
For example for Nginx, augLens should be "Nginx". RecursiveInclude will then iterate over
|
||||||
|
/augeas/load/Nginx/incl (/augeas/load/<augLens>/incl), parsing each file for includeDirective
|
||||||
|
(the "include" keyword, in Nginx's case), check if it is already loaded in /augeas/load/<augLens>/incl,
|
||||||
|
adding it and reloading if not, and then scanning *that* file for includeDirective, etc.
|
||||||
|
|
||||||
|
An error will be returned if augLens is a nonexistent or not-loaded Augeas lens module.
|
||||||
|
|
||||||
|
Depending on how many files there are and whether globs vs. explicit filepaths are included, this may take a while.
|
||||||
|
*/
|
||||||
|
func (a *Aug) RecursiveInclude(augLens, includeDirective, fsRoot string) (err error) {
|
||||||
|
|
||||||
|
if err = a.addIncl(includeDirective, augLens, fsRoot, nil); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
addIncl is used by RecursiveInclude.
|
||||||
|
|
||||||
|
includeDirective, augLens, and fsRoot have the same meaning as in RecursiveInclude.
|
||||||
|
|
||||||
|
newInclPaths are new filesystem paths/Augeas-compatible glob patterns to load into the filetree and recurse into.
|
||||||
|
They may be nil, especially if the first run.
|
||||||
|
*/
|
||||||
|
func (a *Aug) addIncl(includeDirective, augLens string, fsRoot string, newInclPaths []string) (err error) {
|
||||||
|
|
||||||
|
var matches []string // Passed around set of Augeas matches.
|
||||||
|
var includes []string // Filepath(s)/glob(s) from fetching includeDirective in lensInclPath. These are internal to the application but are recursed.
|
||||||
|
var lensInclPath string // The path of the included paths in the tree. These are internal to Augeas, not the application.
|
||||||
|
var appendPath string // The path for new Augeas includes.
|
||||||
|
var match []string // A placeholder for iterating when populating includes.
|
||||||
|
var fpath string // A placeholder for finding the path of a conf file that contains an includeDirective.
|
||||||
|
var lensPath string = fmt.Sprintf(augLensTpl, augLens) // The path of the lens (augLens) itself.
|
||||||
|
var augErr *augeas.Error = new(augeas.Error) // We use this to skip "nonexistent" lens.
|
||||||
|
|
||||||
|
if fsRoot == "" {
|
||||||
|
fsRoot = "/"
|
||||||
|
}
|
||||||
|
if err = paths.RealPath(&fsRoot); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for strings.HasSuffix(lensPath, "/") {
|
||||||
|
lensPath = lensPath[:len(lensPath)-1]
|
||||||
|
}
|
||||||
|
if !strings.HasSuffix(lensPath, "/"+augInclTfm) {
|
||||||
|
lensPath = strings.TrimSuffix(lensPath, "/"+augInclTfm)
|
||||||
|
}
|
||||||
|
lensInclPath = fmt.Sprintf("%v/%v", lensPath, augInclTfm)
|
||||||
|
appendPath = fmt.Sprintf("%v/%v", lensInclPath, augAppendSuffix)
|
||||||
|
|
||||||
|
// First canonize paths.
|
||||||
|
if newInclPaths != nil && len(newInclPaths) > 0 {
|
||||||
|
// Existing includes. We don't return on an empty lensInclPath because
|
||||||
|
if matches, err = a.aug.Match(lensInclPath); err != nil {
|
||||||
|
if errors.As(err, augErr) && augErr.Code == augeas.NoMatch {
|
||||||
|
err = nil
|
||||||
|
} else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for idx, m := range matches {
|
||||||
|
if matches[idx], err = a.aug.Get(m); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Normalize new include(s).
|
||||||
|
for idx, i := range newInclPaths {
|
||||||
|
if !filepath.IsAbs(i) {
|
||||||
|
newInclPaths[idx] = filepath.Join(fsRoot, i)
|
||||||
|
}
|
||||||
|
if err = paths.RealPath(&newInclPaths[idx]); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// We don't want to bother adding multiple incl's for the same path(s); it can negatively affect Augeas loads.
|
||||||
|
newInclPaths = dedupePaths(newInclPaths, matches)
|
||||||
|
|
||||||
|
// Add the new path(s) as Augeas include entries.
|
||||||
|
if newInclPaths != nil {
|
||||||
|
for _, fsPath := range newInclPaths {
|
||||||
|
if err = a.aug.Set(appendPath, fsPath); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
And then load the new files into the tree.
|
||||||
|
This is done at the end as it takes WAYYY less time to just reload the tree
|
||||||
|
as a whole once you have more than, say, 30 files added at a time.
|
||||||
|
*/
|
||||||
|
if err = a.aug.Load(); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// We now fetch all values (filepath/globs) that match the includeDirective and recurse with those as new include files.
|
||||||
|
matches = nil
|
||||||
|
if includes, err = a.aug.GetAll(lensInclPath); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for _, fsPath := range includes {
|
||||||
|
// This gets the Augeas filetree path, NOT the FS path...
|
||||||
|
if match, err = a.aug.Match(fmt.Sprintf(augFsTpl, fsPath, includeDirective)); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if match == nil || len(match) == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
For each directive match, we need to:
|
||||||
|
|
||||||
|
1.) normalize to an FS *file* path (strip augFsTree from the beginning
|
||||||
|
2.) walk backwards (via AugpathToFspath) until we find an actual file
|
||||||
|
3.) get the *dirname* of that file
|
||||||
|
4.) join the value (included file) to #3
|
||||||
|
IF
|
||||||
|
fsRoot == "/"
|
||||||
|
|
||||||
|
This very obviously breaks for applications with arbitrary roots (like Nginx including relative to /etc/nginx).
|
||||||
|
That's why we warn about it in Aug.RecursiveInclude. Caveat emptor.
|
||||||
|
*/
|
||||||
|
for idx, ftreePath := range match {
|
||||||
|
if fpath, err = a.aug.Get(ftreePath); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if fsRoot == "/" {
|
||||||
|
if ftreePath, err = AugpathToFspath(
|
||||||
|
strings.TrimSuffix(ftreePath, augFsTree),
|
||||||
|
); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if ftreePath != "" {
|
||||||
|
fpath = filepath.Join(filepath.Dir(ftreePath), fpath)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
match[idx] = fpath
|
||||||
|
}
|
||||||
|
matches = append(matches, match...)
|
||||||
|
}
|
||||||
|
|
||||||
|
if matches != nil && len(matches) != 0 {
|
||||||
|
if err = a.addIncl(includeDirective, augLens, fsRoot, matches); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
41
auger/funcs_augflags.go
Normal file
41
auger/funcs_augflags.go
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
package auger
|
||||||
|
|
||||||
|
import (
|
||||||
|
`honnef.co/go/augeas`
|
||||||
|
)
|
||||||
|
|
||||||
|
// Eval returns an evaluated set of flags.
|
||||||
|
func (a *AugFlags) Eval() (augFlags augeas.Flag) {
|
||||||
|
|
||||||
|
augFlags = augeas.None
|
||||||
|
|
||||||
|
if a.Backup != nil && *a.Backup {
|
||||||
|
augFlags |= augeas.SaveBackup
|
||||||
|
}
|
||||||
|
if a.NewFile != nil && *a.NewFile {
|
||||||
|
augFlags |= augeas.SaveNewFile
|
||||||
|
}
|
||||||
|
if a.TypeCheck != nil && *a.TypeCheck {
|
||||||
|
augFlags |= augeas.TypeCheck
|
||||||
|
}
|
||||||
|
if a.NoDfltModLoad != nil && *a.NoDfltModLoad {
|
||||||
|
augFlags |= augeas.NoModlAutoload
|
||||||
|
}
|
||||||
|
if a.DryRun != nil && *a.DryRun {
|
||||||
|
augFlags |= augeas.SaveNoop
|
||||||
|
}
|
||||||
|
if a.NoTree != nil && *a.NoTree {
|
||||||
|
augFlags |= augeas.NoLoad
|
||||||
|
}
|
||||||
|
if a.NoAutoModLoad != nil && *a.NoAutoModLoad {
|
||||||
|
augFlags |= augeas.NoModlAutoload
|
||||||
|
}
|
||||||
|
if a.EnableSpan != nil && *a.EnableSpan {
|
||||||
|
augFlags |= augeas.EnableSpan
|
||||||
|
}
|
||||||
|
if a.NoErrClose != nil && *a.NoErrClose {
|
||||||
|
augFlags |= augeas.NoErrClose
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
62
auger/types.go
Normal file
62
auger/types.go
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
package auger
|
||||||
|
|
||||||
|
import (
|
||||||
|
`honnef.co/go/augeas`
|
||||||
|
)
|
||||||
|
|
||||||
|
// Aug is a wrapper around (honnef.co/go/)augeas.Augeas. Remember to call Aug.Close().
|
||||||
|
type Aug struct {
|
||||||
|
aug augeas.Augeas
|
||||||
|
}
|
||||||
|
|
||||||
|
// AugFlags contains flags to pass to the Augeas instance.
|
||||||
|
type AugFlags struct {
|
||||||
|
/*
|
||||||
|
Backup, if true, will enable Augeas backup mode (original files are saved with a .augsave suffix).
|
||||||
|
const: augeas.SaveBackup
|
||||||
|
*/
|
||||||
|
Backup *bool `toml:"Backup,omitempty"`
|
||||||
|
/*
|
||||||
|
NewFile, if true, will create new files (.augnew suffix) instead of overwriting the original file.
|
||||||
|
const: augeas.SaveNewFile
|
||||||
|
*/
|
||||||
|
NewFile *bool `toml:"NewFile,omitempty"`
|
||||||
|
/*
|
||||||
|
TypeCheck, if true, will perform a Lens typecheck.
|
||||||
|
HIGHLY UNRECOMMENDED; WILL INDUCE A HUGE FRONTLOAD.
|
||||||
|
const: augeas.TypeCheck
|
||||||
|
*/
|
||||||
|
TypeCheck *bool `toml:"TypeCheck,omitempty"`
|
||||||
|
/*
|
||||||
|
NoDfltModLoad, if true, will suppress loading the built-in/default modules.
|
||||||
|
Highly unrecommended, as we do not have a current way in the config to define load paths (yet).
|
||||||
|
const: augeas.NoStdinc
|
||||||
|
*/
|
||||||
|
NoDfltModLoad *bool `toml:"NoDfltModLoad,omitempty"`
|
||||||
|
/*
|
||||||
|
DryRun, if true, will make all saves NO-OPs.
|
||||||
|
const: augeas.SaveNoop
|
||||||
|
*/
|
||||||
|
DryRun *bool `toml:"DryRun,omitempty"`
|
||||||
|
/*
|
||||||
|
NoTree, if true, will not load the filetree automatically. Doesn't really affect this program.
|
||||||
|
const: augeas.NoLoad
|
||||||
|
*/
|
||||||
|
NoTree *bool `toml:"NoTree,omitempty"`
|
||||||
|
/*
|
||||||
|
NoAutoModLoad, if true, will supress automatically loading modules.
|
||||||
|
const: augeas.NoModlAutoload
|
||||||
|
*/
|
||||||
|
NoAutoModLoad *bool `toml:"NoAutoModLoad,omitempty"`
|
||||||
|
/*
|
||||||
|
EnableSpan, if true, will track span in input nodes (location information, essentially).
|
||||||
|
See https://augeas.net/docs/api.html#getting-the-span-of-a-node-related-to-a-file
|
||||||
|
const: augeas.EnableSpan
|
||||||
|
*/
|
||||||
|
EnableSpan *bool `toml:"EnableSpan,omitempty"`
|
||||||
|
/*
|
||||||
|
NoErrClose, if true, will suppress automatically closing on error.
|
||||||
|
const: augeas.NoErrClose
|
||||||
|
*/
|
||||||
|
NoErrClose *bool `toml:"NoErrClose,omitempty"`
|
||||||
|
}
|
||||||
5
cryptparse/doc.go
Normal file
5
cryptparse/doc.go
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
/*
|
||||||
|
CRYPTPARSE HAS MOVED.
|
||||||
|
|
||||||
|
It is now its own module: r00t2.io/cryptparse
|
||||||
|
*/
|
||||||
@@ -17,6 +17,34 @@ import (
|
|||||||
`r00t2.io/sysutils/paths`
|
`r00t2.io/sysutils/paths`
|
||||||
)
|
)
|
||||||
|
|
||||||
|
/*
|
||||||
|
DefEnv operates like Python's .get() method on dicts (maps);
|
||||||
|
if the environment variable specified by key does not exist/is not specified,
|
||||||
|
then the value specified by fallback will be returned instead
|
||||||
|
otherwise key's value is returned.
|
||||||
|
*/
|
||||||
|
func DefEnv(key, fallback string) (value string) {
|
||||||
|
|
||||||
|
var exists bool
|
||||||
|
|
||||||
|
if value, exists = os.LookupEnv(key); !exists {
|
||||||
|
value = fallback
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// DefEnvBlank is like DefEnv but will ADDITIONALLY/ALSO apply fallback if key is *defined/exists but is an empty string*.
|
||||||
|
func DefEnvBlank(key, fallback string) (value string) {
|
||||||
|
|
||||||
|
value = DefEnv(key, fallback)
|
||||||
|
if value == "" {
|
||||||
|
value = fallback
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// GetEnvMap returns a map of all environment variables. All values are strings.
|
// GetEnvMap returns a map of all environment variables. All values are strings.
|
||||||
func GetEnvMap() (envVars map[string]string) {
|
func GetEnvMap() (envVars map[string]string) {
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,8 @@
|
|||||||
package envs
|
package envs
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"os"
|
||||||
|
|
||||||
"golang.org/x/sys/windows/registry"
|
"golang.org/x/sys/windows/registry"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
18
go.mod
18
go.mod
@@ -1,18 +1,26 @@
|
|||||||
module r00t2.io/sysutils
|
module r00t2.io/sysutils/v2
|
||||||
|
|
||||||
go 1.21
|
go 1.23.2
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
github.com/Luzifer/go-dhparam v1.2.0
|
||||||
github.com/davecgh/go-spew v1.1.1
|
github.com/davecgh/go-spew v1.1.1
|
||||||
github.com/g0rbe/go-chattr v1.0.1
|
github.com/g0rbe/go-chattr v1.0.1
|
||||||
github.com/google/uuid v1.6.0
|
github.com/go-playground/validator/v10 v10.22.0
|
||||||
|
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510
|
||||||
golang.org/x/sys v0.19.0
|
golang.org/x/sys v0.19.0
|
||||||
|
honnef.co/go/augeas v0.0.0-20161110001225-ca62e35ed6b8
|
||||||
r00t2.io/goutils v1.6.0
|
r00t2.io/goutils v1.6.0
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf // indirect
|
github.com/gabriel-vasile/mimetype v1.4.3 // indirect
|
||||||
github.com/godbus/dbus v4.1.0+incompatible // indirect
|
github.com/go-playground/locales v0.14.1 // indirect
|
||||||
|
github.com/go-playground/universal-translator v0.18.1 // indirect
|
||||||
|
github.com/leodido/go-urn v1.4.0 // indirect
|
||||||
|
golang.org/x/crypto v0.19.0 // indirect
|
||||||
|
golang.org/x/net v0.21.0 // indirect
|
||||||
|
golang.org/x/text v0.14.0 // indirect
|
||||||
)
|
)
|
||||||
|
|
||||||
// Pending https://github.com/g0rbe/go-chattr/pull/3
|
// Pending https://github.com/g0rbe/go-chattr/pull/3
|
||||||
|
|||||||
40
go.sum
40
go.sum
@@ -1,22 +1,42 @@
|
|||||||
github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf h1:iW4rZ826su+pqaw19uhpSCzhj44qo35pNgKFGqzDKkU=
|
github.com/Luzifer/go-dhparam v1.2.0 h1:YwDf15FTsVriTynCv1qF+1Inh6E8Dg1+28tPEA3pvFo=
|
||||||
|
github.com/Luzifer/go-dhparam v1.2.0/go.mod h1:hnazoxBTsXnRvGXAosio70Tb1lWowquyhVdvsXdlIPc=
|
||||||
github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/godbus/dbus v4.1.0+incompatible h1:WqqLRTsQic3apZUK9qC5sGNfXthmPXzUZ7nQPrNITa4=
|
github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0=
|
||||||
github.com/godbus/dbus v4.1.0+incompatible/go.mod h1:/YcGZj5zSblfDWMMoOzV4fas9FZnQYTkDnsGvmh2Grw=
|
github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk=
|
||||||
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
|
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
|
||||||
|
github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
|
||||||
|
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
|
||||||
|
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
|
||||||
|
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
|
||||||
|
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
|
||||||
|
github.com/go-playground/validator/v10 v10.22.0 h1:k6HsTZ0sTnROkhS//R0O+55JgM8C4Bx7ia+JlgcnOao=
|
||||||
|
github.com/go-playground/validator/v10 v10.22.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM=
|
||||||
|
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4=
|
||||||
|
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ=
|
||||||
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
|
||||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
|
||||||
github.com/johnnybubonic/go-chattr v0.0.0-20240126141003-459f46177b13 h1:tgEbuE4bNVjaCWWIB1u9lDzGqH/ZdBTg33+4vNW2rjg=
|
github.com/johnnybubonic/go-chattr v0.0.0-20240126141003-459f46177b13 h1:tgEbuE4bNVjaCWWIB1u9lDzGqH/ZdBTg33+4vNW2rjg=
|
||||||
github.com/johnnybubonic/go-chattr v0.0.0-20240126141003-459f46177b13/go.mod h1:yQc6VPJfpDDC1g+W2t47+yYmzBNioax/GLiyJ25/IOs=
|
github.com/johnnybubonic/go-chattr v0.0.0-20240126141003-459f46177b13/go.mod h1:yQc6VPJfpDDC1g+W2t47+yYmzBNioax/GLiyJ25/IOs=
|
||||||
|
github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
|
||||||
|
github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
||||||
|
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||||
|
golang.org/x/crypto v0.19.0 h1:ENy+Az/9Y1vSrlrvBSyna3PITt4tiZLf7sgCjZBX7Wo=
|
||||||
|
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
|
||||||
|
golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4=
|
||||||
|
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
|
||||||
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o=
|
golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o=
|
||||||
golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
r00t2.io/goutils v1.4.0 h1:/x/etLpMFv3+j1aPtT7KK2G0uOk+gQkGvXIYBCdjn3E=
|
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
|
||||||
r00t2.io/goutils v1.4.0/go.mod h1:9ObJI9S71wDLTOahwoOPs19DhZVYrOh4LEHmQ8SW4Lk=
|
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||||
r00t2.io/goutils v1.5.0 h1:haVk+wUK1BAk8f4UFGjy3ov3DwGMauZAOv/XYdb9isQ=
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
r00t2.io/goutils v1.5.0/go.mod h1:9ObJI9S71wDLTOahwoOPs19DhZVYrOh4LEHmQ8SW4Lk=
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
honnef.co/go/augeas v0.0.0-20161110001225-ca62e35ed6b8 h1:FW42yWB1sGClqswyHIB68wo0+oPrav1IuQ+Tdy8Qp8E=
|
||||||
|
honnef.co/go/augeas v0.0.0-20161110001225-ca62e35ed6b8/go.mod h1:44w9OfBSQ9l3o59rc2w3AnABtE44bmtNnRMNC7z+oKE=
|
||||||
r00t2.io/goutils v1.6.0 h1:oBC6PgBv0y/fdHeCmWgORHpBiU8uWw7IfFQJX5rIuzY=
|
r00t2.io/goutils v1.6.0 h1:oBC6PgBv0y/fdHeCmWgORHpBiU8uWw7IfFQJX5rIuzY=
|
||||||
r00t2.io/goutils v1.6.0/go.mod h1:9ObJI9S71wDLTOahwoOPs19DhZVYrOh4LEHmQ8SW4Lk=
|
r00t2.io/goutils v1.6.0/go.mod h1:9ObJI9S71wDLTOahwoOPs19DhZVYrOh4LEHmQ8SW4Lk=
|
||||||
r00t2.io/sysutils v1.1.1/go.mod h1:Wlfi1rrJpoKBOjWiYM9rw2FaiZqraD6VpXyiHgoDo/o=
|
r00t2.io/sysutils v1.1.1/go.mod h1:Wlfi1rrJpoKBOjWiYM9rw2FaiZqraD6VpXyiHgoDo/o=
|
||||||
|
|||||||
Reference in New Issue
Block a user