update some stuff for paths, add env mappings
This commit is contained in:
		
							parent
							
								
									c1fc07de50
								
							
						
					
					
						commit
						3e51ac58db
					
				
							
								
								
									
										208
									
								
								funcs.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										208
									
								
								funcs.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,208 @@ | ||||
| package sysutils | ||||
| 
 | ||||
| import ( | ||||
| 	`os` | ||||
| 	`runtime` | ||||
| 	`strconv` | ||||
| 	`strings` | ||||
| ) | ||||
| 
 | ||||
| /* | ||||
| 	EnvMapper contains the environment variables as grouped by their basic type. | ||||
| 	If a variable's type cannot be determined, it's placed in Strings. | ||||
| 	If a variable's type is a list, it will be an []interface{} as each item may be a different variable type. | ||||
| 	It essentially is the same as EnvMap except with the types split out for convenience. | ||||
| */ | ||||
| type EnvMapper struct { | ||||
| 	Booleans map[string]bool          `json:"bools"` | ||||
| 	Numbers  map[string]int           `json:"nums"` | ||||
| 	Strings  map[string]string        `json:"strings"` | ||||
| 	Lists    map[string][]interface{} `json:"lists"` | ||||
| } | ||||
| 
 | ||||
| // GetEnvMapper returns a pointer to a populated EnvMapper. | ||||
| func GetEnvMapper() (e *EnvMapper, err error) { | ||||
| 
 | ||||
| 	var em map[string]interface{} | ||||
| 	var env EnvMapper | ||||
| 
 | ||||
| 	env = EnvMapper{ | ||||
| 		Booleans: nil, | ||||
| 		Numbers:  nil, | ||||
| 		Strings:  nil, | ||||
| 		Lists:    nil, | ||||
| 	} | ||||
| 
 | ||||
| 	for k, v := range em { | ||||
| 
 | ||||
| 		switch t := v.(type) { | ||||
| 		case bool: | ||||
| 			if env.Booleans == nil { | ||||
| 				env.Booleans = make(map[string]bool, 0) | ||||
| 			} | ||||
| 			env.Booleans[k] = t | ||||
| 			continue | ||||
| 		case int: | ||||
| 			if env.Numbers == nil { | ||||
| 				env.Numbers = make(map[string]int, 0) | ||||
| 			} | ||||
| 			env.Numbers[k] = t | ||||
| 			continue | ||||
| 		case []interface{}: | ||||
| 			if env.Lists == nil { | ||||
| 				env.Lists = make(map[string][]interface{}, 0) | ||||
| 			} | ||||
| 			env.Lists[k] = t | ||||
| 		case string: // the "default" since everything could probably be typeswitched to a string otherwise. | ||||
| 			if env.Strings == nil { | ||||
| 				env.Strings = make(map[string]string, 0) | ||||
| 			} | ||||
| 			env.Strings[k] = t | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	*e = env | ||||
| 
 | ||||
| 	return | ||||
| } | ||||
| 
 | ||||
| /* | ||||
| 	EnvMap returns a map of environment variables. | ||||
| 	The variable is an interface due to it attempting to use a variable's value to its "true" native type. | ||||
| 	If a type cannot be determined, it will be treated a string. | ||||
| */ | ||||
| func EnvMap() (envs map[string]interface{}, err error) { | ||||
| 
 | ||||
| 	var ems map[string]string | ||||
| 
 | ||||
| 	if ems, err = EnvMapString(); err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	for k, v := range ems { | ||||
| 
 | ||||
| 		// Is int? | ||||
| 		if i, ok := getNum(v); ok { | ||||
| 			envs[k] = i | ||||
| 			continue | ||||
| 		} | ||||
| 
 | ||||
| 		// Is bool? | ||||
| 		if b, ok := getBool(v); ok { | ||||
| 			envs[k] = b | ||||
| 			continue | ||||
| 		} | ||||
| 
 | ||||
| 		// Is array? | ||||
| 		if a, ok := getArr(v); ok { | ||||
| 			envs[k] = a | ||||
| 			continue | ||||
| 		} | ||||
| 
 | ||||
| 		// It's a string (probably). | ||||
| 		envs[k] = v | ||||
| 	} | ||||
| 
 | ||||
| 	return | ||||
| } | ||||
| 
 | ||||
| // EnvMapString is like EnvMap, but all values are treated as strings. | ||||
| func EnvMapString() (envs map[string]string, err error) { | ||||
| 
 | ||||
| 	var envArray []string | ||||
| 
 | ||||
| 	envs = make(map[string]string, 0) | ||||
| 
 | ||||
| 	envArray = os.Environ() | ||||
| 
 | ||||
| 	for _, e := range envArray { | ||||
| 		var k, v string | ||||
| 		var kv []string | ||||
| 
 | ||||
| 		kv = strings.SplitN(e, "=", 2) | ||||
| 		k = kv[0] | ||||
| 		if len(kv) == 2 { | ||||
| 			v = kv[1] | ||||
| 		} else { | ||||
| 			v = "" | ||||
| 		} | ||||
| 		envs[k] = v | ||||
| 	} | ||||
| 
 | ||||
| 	return | ||||
| } | ||||
| 
 | ||||
| // UTILITY FUNCS | ||||
| 
 | ||||
| // getBool attempts to convert a string value to a boolean. | ||||
| func getBool(s string) (b bool, ok bool) { | ||||
| 
 | ||||
| 	switch s2 := strings.ToLower(strings.TrimSpace(s)); s2 { | ||||
| 	case "true", "yes", "y": | ||||
| 		b = true | ||||
| 		ok = true | ||||
| 	case "false", "no", "n": | ||||
| 		b = false | ||||
| 		ok = true | ||||
| 	} | ||||
| 
 | ||||
| 	return | ||||
| } | ||||
| 
 | ||||
| // getNum attempts to convert a string value to an int. | ||||
| func getNum(s string) (n int, ok bool) { | ||||
| 
 | ||||
| 	var err error | ||||
| 
 | ||||
| 	if n, err = strconv.Atoi(s); err == nil { | ||||
| 		ok = true | ||||
| 	} | ||||
| 
 | ||||
| 	return | ||||
| } | ||||
| 
 | ||||
| // getArr attempts to convert a string value to an array of interface{}. | ||||
| func getArr(s string) (a []interface{}, ok bool) { | ||||
| 
 | ||||
| 	var arrS []string | ||||
| 
 | ||||
| 	if arrS, ok = getArrStr(s); !ok { | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	a = make([]interface{}, len(arrS)) | ||||
| 
 | ||||
| 	for idx, i := range arrS { | ||||
| 		if b, ok := getBool(i); ok { | ||||
| 			a[idx] = b | ||||
| 		} else if n, ok := getNum(i); ok { | ||||
| 			a[idx] = n | ||||
| 		} else if l, ok := getArr(i); ok { | ||||
| 			a[idx] = l | ||||
| 		} else { | ||||
| 			a[idx] = i | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return | ||||
| } | ||||
| 
 | ||||
| // getArrStr attempts to convert a string value to an array of strings. | ||||
| func getArrStr(s string) (a []string, ok bool) { | ||||
| 
 | ||||
| 	var sep string = ":" | ||||
| 
 | ||||
| 	if runtime.GOOS == "windows" { | ||||
| 		sep = ";" | ||||
| 	} | ||||
| 
 | ||||
| 	a = strings.Split(s, sep) | ||||
| 	l := len(s) | ||||
| 	if l <= 1 { | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	ok = true | ||||
| 
 | ||||
| 	return | ||||
| } | ||||
| @ -63,7 +63,7 @@ func main() { | ||||
| 		"\tService: %v\n" + | ||||
| 		"\tDesc: %v\n" + | ||||
| 		"\tReserved?: %v\n", | ||||
| 		p.Number, p.Proto.Name, p.ServiceName, p.Description, p.Reserved) | ||||
| 		p.Number, p.Protocol.Name, p.ServiceName, p.Description, p.Reserved) | ||||
| } | ||||
| ---- | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										149
									
								
								paths/func.go
									
									
									
									
									
								
							
							
						
						
									
										149
									
								
								paths/func.go
									
									
									
									
									
								
							| @ -20,108 +20,155 @@ package paths | ||||
| 
 | ||||
| import ( | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	`fmt` | ||||
| 	"os" | ||||
| 	"os/user" | ||||
| 	"path/filepath" | ||||
| 	`runtime` | ||||
| 	// "strconv" | ||||
| 	"strings" | ||||
| 
 | ||||
| 	// "syscall" | ||||
| ) | ||||
| 
 | ||||
| var err error | ||||
| /* | ||||
| 	ExpandHome will take a tilde(~)-prefixed path and resolve it to the actual path in-place. | ||||
| 	Note that it only works for current user; the syntax ~someotheruser/foo/bar is currently unsupported. | ||||
| */ | ||||
| func ExpandHome(path *string) (err error) { | ||||
| 
 | ||||
| 	var usr *user.User | ||||
| 
 | ||||
| func ExpandHome(path *string) error { | ||||
| 	// Props to this guy. | ||||
| 	// https://stackoverflow.com/a/43578461/733214 | ||||
| 	if len(*path) == 0 { | ||||
| 		return errors.New("empty path") | ||||
| 		err = errors.New("empty path") | ||||
| 		return | ||||
| 	} else if (*path)[0] != '~' { | ||||
| 		return nil | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	// E(ffective)UID (e.g. chown'd user for SUID) | ||||
| 	/* | ||||
| 		uid := strconv.Itoa(syscall.Geteuid()) | ||||
| 		usr, err := user.LookupId(euid) | ||||
| 	*/ | ||||
| 	// R(real)UID (invoking user) | ||||
| 	usr, err := user.Current() | ||||
| 	if err != nil { | ||||
| 	// (Real)UID (invoking user) | ||||
| 	if usr, err = user.Current(); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	*path = filepath.Join(usr.HomeDir, (*path)[1:]) | ||||
| 	return nil | ||||
| 
 | ||||
| 	return | ||||
| } | ||||
| 
 | ||||
| func GetPathEnv() ([]string, error) { | ||||
| 	paths := []string{} | ||||
| 	for _, p := range strings.Split(os.Getenv("PATH"), ":") { | ||||
| // GetPathEnv returns a slice of the PATH variable's items. | ||||
| func GetPathEnv() (paths []string, err error) { | ||||
| 
 | ||||
| 	var pathVar string = "PATH" | ||||
| 	var sep string = ":" | ||||
| 
 | ||||
| 	paths = make([]string, 0) | ||||
| 
 | ||||
| 	if runtime.GOOS == "windows" { | ||||
| 		pathVar = "Path" | ||||
| 		sep = ";" | ||||
| 	} | ||||
| 
 | ||||
| 	for _, p := range strings.Split(os.Getenv(pathVar), sep) { | ||||
| 		if err = RealPath(&p); err != nil { | ||||
| 			return nil, err | ||||
| 			return | ||||
| 		} | ||||
| 		paths = append(paths, p) | ||||
| 	} | ||||
| 	return paths, nil | ||||
| 	return | ||||
| } | ||||
| 
 | ||||
| func MakeDirIfNotExist(path *string) error { | ||||
| 	exists, stat, err := RealPathExistsStat(path) | ||||
| 	if err != nil { | ||||
| // MakeDirIfNotExist will create a directory at a given path if it doesn't exist. | ||||
| func MakeDirIfNotExist(path string) (err error) { | ||||
| 
 | ||||
| 	var stat os.FileInfo | ||||
| 	var exists bool | ||||
| 	var locPath string = path | ||||
| 
 | ||||
| 	if exists, stat, err = RealPathExistsStat(&locPath); err != nil { | ||||
| 		if !exists { | ||||
| 			// This, at least as of golang 1.15, uses the user's umask. | ||||
| 			// It does not actually create a dir with 0777. | ||||
| 			// It's up to the caller to do an os.Chmod() on the path after, if desired. | ||||
| 			os.MkdirAll(*path, 0777) | ||||
| 			return nil | ||||
| 			if err = os.MkdirAll(locPath, 0777); err != nil { | ||||
| 				return | ||||
| 			} | ||||
| 			err = nil | ||||
| 			return | ||||
| 		} else { | ||||
| 			return err | ||||
| 			return | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	// So it exists, but it probably isn't a dir. | ||||
| 	if !stat.Mode().IsDir() { | ||||
| 		return errors.New(fmt.Sprintf("path %v exists but is not a directory", *path)) | ||||
| 		err = errors.New(fmt.Sprintf("path %v exists but is not a directory", locPath)) | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	// This should probably never happen. Probably. | ||||
| 	return errors.New("undefined behaviour") | ||||
| 	err = errors.New("undefined") | ||||
| 	return | ||||
| } | ||||
| 
 | ||||
| func RealPath(path *string) error { | ||||
| 	err := ExpandHome(path) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| // RealPath will transform a given path into the very best guess for an absolute path in-place. | ||||
| func RealPath(path *string) (err error) { | ||||
| 
 | ||||
| 	if err = ExpandHome(path); err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	*path, err = filepath.Abs(*path) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 
 | ||||
| 	if *path, err = filepath.Abs(*path); err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	return nil | ||||
| 
 | ||||
| 	return | ||||
| } | ||||
| 
 | ||||
| func RealPathExists(path *string) (bool, error) { | ||||
| 	// I know it's hacky, but we use the bool as a sort of proto-state-machine thing. | ||||
| 	// If err != nil and bool is true, the error occurred during path absolution. | ||||
| 	// If err != nil and bool is false, the path does not exist. | ||||
| 	err := RealPath(path) | ||||
| 	if err != nil { | ||||
| 		return true, err | ||||
| /* | ||||
| 	RealPathExists is like RealPath, but will also return a boolean as to whether the path | ||||
| 	actually exists or not. | ||||
| 
 | ||||
| 	It's hacky, but the "exists" bool along with err is a sort of proto-state-machine. | ||||
| 	If err != nil and bool is true, the error occurred during path absolution. | ||||
| 	If err != nil and bool is false, the path does not exist. | ||||
| */ | ||||
| func RealPathExists(path *string) (exists bool, err error) { | ||||
| 
 | ||||
| 	if err = RealPath(path); err != nil { | ||||
| 		exists = true | ||||
| 		return | ||||
| 	} | ||||
| 	if _, err := os.Stat(*path); err != nil { | ||||
| 		return false, err | ||||
| 
 | ||||
| 	if _, err = os.Stat(*path); err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	return true, nil | ||||
| 
 | ||||
| 	exists = true | ||||
| 
 | ||||
| 	return | ||||
| } | ||||
| 
 | ||||
| func RealPathExistsStat(path *string) (bool, os.FileInfo, error) { | ||||
| 	// Same deal as RealPathExists. | ||||
| 	// If err != nil and bool is true, the error occurred during path absolution. | ||||
| 	// If err != nil and bool is false, the path does not exist. | ||||
| 	err := RealPath(path) | ||||
| 	if err != nil { | ||||
| 		return true, nil, err | ||||
| // RealPathExistsStat is like RealPathExists except it will also return the os.FileInfo for the path (assuming it exists). | ||||
| func RealPathExistsStat(path *string) (exists bool, stat os.FileInfo, err error) { | ||||
| 
 | ||||
| 	// See the comments for RealPathExists for details on this. | ||||
| 	if err = RealPath(path); err != nil { | ||||
| 		exists = true | ||||
| 		return | ||||
| 	} | ||||
| 	stat, err := os.Stat(*path) | ||||
| 	if err != nil { | ||||
| 		return false, nil, err | ||||
| 
 | ||||
| 	if stat, err = os.Stat(*path); err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	return true, stat, nil | ||||
| 
 | ||||
| 	exists = true | ||||
| 
 | ||||
| 	return | ||||
| } | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user