Added existing files

This commit is contained in:
Celestino Amoroso 2024-02-16 15:51:28 +01:00
parent 1ce95fbbab
commit 4e04fa6472
10 changed files with 1261 additions and 0 deletions

116
file-util.go Normal file
View File

@ -0,0 +1,116 @@
// file_util.go
package utils
import (
"errors"
"fmt"
"io"
"os"
"strconv"
"strings"
)
func FileSize(filePath string) (size int64) {
info, err := os.Stat(filePath)
if err == nil {
size = info.Size()
} else {
size = -1
}
return
}
func IsRegularFile(filePath string) bool {
if filePath != "" {
info, err := os.Stat(filePath)
// return (err == nil || os.IsExist(err)) && info.Mode().IsRegular()
return (err == nil || errors.Is(err, os.ErrExist)) && info.Mode().IsRegular()
}
return false
}
func IsDirectory(filePath string) bool {
if filePath != "" {
info, err := os.Stat(filePath)
return (err == nil || errors.Is(err, os.ErrExist)) && info.Mode().IsDir()
}
return false
}
func IsSymLink(filePath string) bool {
if filePath != "" {
info, err := os.Stat(filePath)
return (err == nil || errors.Is(err, os.ErrExist)) && (info.Mode()&os.ModeSymlink != 0)
}
return false
}
func IsSymLinkByDirEntry(e os.DirEntry) bool {
info, _ := e.Info()
return info.Mode()&os.ModeSymlink != 0
}
func StreamIsTerminal(fh *os.File) bool {
var isTerminal bool = false
if fh != nil {
fi, _ := fh.Stat()
isTerminal = (fi.Mode() & os.ModeCharDevice) != 0
}
return isTerminal
}
/*
* Ispirata a https://stackoverflow.com/a/50741908
*/
func MoveFile(sourcePath, destPath string) (int64, error) {
var size int64 = 0
err := os.Rename(sourcePath, destPath)
if err != nil {
inputFile, err := os.Open(sourcePath)
if err != nil {
return 0, fmt.Errorf("Couldn't open source file: %s", err)
}
outputFile, err := os.Create(destPath)
if err != nil {
inputFile.Close()
return 0, fmt.Errorf("Couldn't open dest file: %s", err)
}
defer outputFile.Close()
size, err = io.Copy(outputFile, inputFile)
inputFile.Close()
if err != nil {
return 0, fmt.Errorf("Writing to output file failed: %s", err)
}
// The copy was successful, so now delete the original file
err = os.Remove(sourcePath)
if err != nil {
return 0, fmt.Errorf("Failed removing original file: %s", err)
}
}
return size, nil
}
func ParseMemSize(s string) (size int64, err error) {
const MULTIPLES = "BKMGTP"
// s = strings.TrimSpace(s)
if len(s) != 0 {
s = strings.ToUpper(s)
s = strings.ReplaceAll(s, ".", "")
s = strings.ReplaceAll(s, ",", "")
s = strings.ReplaceAll(s, " ", "")
pos := strings.IndexAny(s, MULTIPLES)
if pos >= 0 {
size, err = strconv.ParseInt(s[0:pos], 10, 64)
mul := strings.IndexByte(MULTIPLES, s[pos])
for ; mul > 0; mul-- {
size = size * 1_000
}
} else {
size, err = strconv.ParseInt(s, 10, 64)
}
} else {
err = errors.New("Empty string")
}
return
}

6
go.mod Normal file
View File

@ -0,0 +1,6 @@
module portale-stac.it/packages/utils
go 1.21
require golang.org/x/text v0.3.7

2
go.sum Normal file
View File

@ -0,0 +1,2 @@
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=

36
gzip-util.go Normal file
View File

@ -0,0 +1,36 @@
// gzip-util.go
package utils
import (
"bufio"
"compress/gzip"
"fmt"
"io"
"strings"
)
const GZIP_SUFFIX = ".gz"
func CreateGzipReader(in io.Reader) (reader *bufio.Reader, err error) {
inflate, err := gzip.NewReader(in)
if err != nil {
fmt.Errorf("Can't inflate gzipped input stream: %v", err)
} else {
reader = bufio.NewReader(inflate)
}
return
}
func CreateGzipFile(in io.Reader, fileName string) (reader *bufio.Reader, err error) {
if len(fileName) > 0 && strings.HasSuffix(fileName, GZIP_SUFFIX) {
inflate, err := gzip.NewReader(in)
if err != nil {
fmt.Errorf("Can't inflate gzipped input stream %#v: %v", fileName, err)
} else {
reader = bufio.NewReader(inflate)
}
} else {
reader = bufio.NewReader(in)
}
return
}

154
misc-util.go Normal file
View File

@ -0,0 +1,154 @@
package utils
import (
"fmt"
"math/rand"
"os"
"strconv"
"time"
"golang.org/x/text/language"
"golang.org/x/text/message"
)
func NewEnglishPrinter() *message.Printer {
return message.NewPrinter(language.English)
}
func ExitErrorf(rc int, format string, args ...interface{}) {
fmt.Fprintf(os.Stderr, format+"\n", args...)
os.Exit(rc)
}
func ExitMessagef(rc int, format string, args ...interface{}) {
fmt.Printf(format+"\n", args...)
os.Exit(rc)
}
func OnStringIndex(index uint, values ...string) (value string) {
if index >= 0 && index < uint(len(values)) {
value = values[index]
}
return
}
func OnEmpty(s string, altValues ...string) (value string) {
if len(s) == 0 {
for _, altValue := range altValues {
if len(altValue) > 0 {
value = altValue
}
}
} else {
value = s
}
return s
}
func OnCond(cond bool, trueValue, falseValue string) string {
if cond {
return trueValue
} else {
return falseValue
}
}
func OnCondIface(cond bool, trueValue, falseValue interface{}) interface{} {
if cond {
return trueValue
} else {
return falseValue
}
}
func OnCondInt(cond bool, trueValue, falseValue int) int {
if cond {
return trueValue
} else {
return falseValue
}
}
func OnCondInt64(cond bool, trueValue, falseValue int64) int64 {
if cond {
return trueValue
} else {
return falseValue
}
}
func OnSuccess(cond bool) string {
return OnCond(cond, "SUCCEEDED", "FAILED")
}
func OnOk(cond bool) string {
return OnCond(cond, "OK", "KO")
}
func RandBool() bool {
rand.Seed(time.Now().UnixNano())
return rand.Intn(2) > 0
}
func S2Uint32(s string, defaultValue uint32) uint32 {
var res uint32
v, err := strconv.ParseUint(s, 10, 32)
if err == nil {
res = uint32(v)
} else {
res = defaultValue
}
return res
}
func S2Int32(s string, defaultValue int32) int32 {
var res int32
v, err := strconv.ParseUint(s, 10, 32)
if err == nil {
res = int32(v)
} else {
res = defaultValue
}
return res
}
func RemoveQuotes(s string) string {
l := len(s)
if l >= 2 {
if (s[0] == '"' && s[l-1] == '"') || (s[0] == '\'' && s[l-1] == '\'') {
s = s[1 : l-1]
}
}
return s
}
// Credits: https://yourbasic.org/golang/formatting-byte-size-to-human-readable-format/
func ByteCountSI(b int64) string {
const unit = 1000
if b < unit {
return fmt.Sprintf("%d B", b)
}
div, exp := int64(unit), 0
for n := b / unit; n >= unit; n /= unit {
div *= unit
exp++
}
return fmt.Sprintf("%.1f %cB",
float64(b)/float64(div), "kMGTPE"[exp])
}
// Credits: https://yourbasic.org/golang/formatting-byte-size-to-human-readable-format/
func ByteCountIEC(b int64) string {
const unit = 1024
if b < unit {
return fmt.Sprintf("%d B", b)
}
div, exp := int64(unit), 0
for n := b / unit; n >= unit; n /= unit {
div *= unit
exp++
}
return fmt.Sprintf("%.1f %ciB",
float64(b)/float64(div), "KMGTPE"[exp])
}

169
os-util.go Normal file
View File

@ -0,0 +1,169 @@
// os-util.go
package utils
import (
"fmt"
"os"
"os/user"
"path"
"path/filepath"
"strings"
)
func ExpandPath(sourcePath string) (expandedPath string, err error) {
if strings.HasPrefix(sourcePath, "~") {
var home, userName, remainder string
slashPos := strings.IndexRune(sourcePath, '/')
if slashPos > 0 {
userName = sourcePath[1:slashPos]
remainder = sourcePath[slashPos:]
} else {
userName = sourcePath[1:]
}
if len(userName) == 0 {
home, err = os.UserHomeDir()
if err != nil {
return
}
} else {
var userInfo *user.User
userInfo, err = user.Lookup(userName)
if err != nil {
return
}
home = userInfo.HomeDir
}
expandedPath = os.ExpandEnv(path.Join(home, remainder))
} else {
expandedPath = os.ExpandEnv(sourcePath)
}
return
}
func ExpandPathV(sourcePath string, maps ...map[string]string) (expandedPath string, err error) {
var normalizedPath string
if strings.HasPrefix(sourcePath, "~") {
var home, userName, remainder string
slashPos := strings.IndexRune(sourcePath, '/')
if slashPos > 0 {
userName = sourcePath[1:slashPos]
remainder = sourcePath[slashPos:]
} else {
userName = sourcePath[1:]
}
if len(userName) == 0 {
home, err = os.UserHomeDir()
if err != nil {
return
}
} else {
var userInfo *user.User
userInfo, err = user.Lookup(userName)
if err != nil {
return
}
home = userInfo.HomeDir
}
normalizedPath = path.Join(home, remainder)
} else {
normalizedPath = sourcePath
}
expandedPath = os.Expand(normalizedPath, func(name string) (value string) {
var ok bool
for _, vars := range maps {
if value, ok = vars[name]; ok {
break
}
}
if !ok {
value = os.Getenv(name)
}
return
})
return
}
func ExpandRealPath(sourcePath string) (expandedRealPath string, err error) {
var expandedPath string
if expandedPath, err = ExpandPath(sourcePath); err == nil {
if expandedPath, err = filepath.Abs(expandedPath); err == nil {
expandedRealPath, err = filepath.EvalSymlinks(expandedPath)
}
}
return
}
func GetProgramDirPath() (dir string, err error) {
var exe string
exe, err = os.Executable()
if err == nil {
exe, err = filepath.EvalSymlinks(exe)
if err == nil {
exe, err = filepath.Abs(exe)
if err == nil {
dir = filepath.Dir(exe)
}
}
}
return
}
func GetProgramPath() (exec string, err error) {
var tmpExec string
tmpExec, err = os.Executable()
if err == nil {
tmpExec, err = filepath.EvalSymlinks(tmpExec)
if err == nil {
exec, err = filepath.Abs(tmpExec)
}
}
return
}
func MakeParentDir(filePath string) (dir string, err error) {
dir = filepath.Dir(filePath)
if !IsDirectory(dir) {
if err1 := os.MkdirAll(dir, 0755); err1 != nil {
err = fmt.Errorf("Can't make parent path of %#v: %v", filePath, err1)
}
}
return
}
func ExpandFilePathAndMakeParent(specPath string) (expandedPath, expandedParent string, err error) {
expandedPath, err = ExpandPath(specPath)
if err == nil {
expandedParent, err = MakeParentDir(expandedPath)
}
return
}
func ExpandFilePathAndMakeParentV(specPath string, maps ...map[string]string) (expandedPath, expandedParent string, err error) {
expandedPath, err = ExpandPathV(specPath, maps...)
if err == nil {
expandedParent, err = MakeParentDir(expandedPath)
}
return
}
func MakeDir(dirPath string) (err error) {
if !IsDirectory(dirPath) {
if err1 := os.MkdirAll(dirPath, 0755); err1 != nil {
err = fmt.Errorf("Can't make directory path %#v: %v", dirPath, err1)
}
}
return
}
func ExpandDirPathAndMakeParent(specPath string) (expandedPath string, err error) {
expandedPath, err = ExpandPath(specPath)
if err == nil {
err = MakeDir(expandedPath)
}
return
}

222
string.go Normal file
View File

@ -0,0 +1,222 @@
// string
package utils
import (
"fmt"
"strings"
)
func PadStringRight(s string, pad string, size int, suffix string) (paddedString string) {
if len(pad) == 0 {
pad = " "
}
space := size - len(s)
if space > 0 {
paddedString = s + strings.Repeat(pad, space)
} else {
paddedString = s
}
paddedString += ": %v"
return
}
func UnescapeSpecialChars(source string, charSet, specialChars string) string {
var buf strings.Builder
var escape bool
for _, c := range source {
if c == '\\' {
if escape {
buf.WriteByte('\\')
escape = false
} else {
escape = true
}
} else {
if escape {
if index := strings.IndexRune(charSet, c); index >= 0 {
if index < len(specialChars) {
buf.WriteByte(specialChars[index])
}
}
escape = false
} else {
buf.WriteRune(c)
}
}
}
return buf.String()
}
func UnescapeBlanks(source string) string {
return UnescapeSpecialChars(source, "nrt", "\n\r\t")
}
func EscapeSpecialChars(source string, charSet string) string {
var buf strings.Builder
for _, c := range source {
if strings.IndexRune(charSet, c) >= 0 {
buf.WriteByte(92) // 92 = backslash
}
buf.WriteRune(c)
}
return buf.String()
}
func EscapeShellSpecialChars(source string) string {
return EscapeSpecialChars(source, "!`$\\()#~&*;")
}
func SplitPair(source, sep string) (left, right string) {
parts := strings.SplitN(source, sep, 2)
left = strings.TrimSpace(parts[0])
if len(parts) > 1 {
right = strings.TrimSpace(parts[1])
}
return
}
func StartsWith(s string, aliases ...string) bool {
startsWith := false
for _, alias := range aliases {
if startsWith = strings.HasPrefix(alias, s); startsWith {
break
}
}
return startsWith
}
func JoinStringMap(m map[string]string, kvSep, itemSep string) string {
var sb strings.Builder
for key, value := range m {
if sb.Len() > 0 {
sb.WriteString(itemSep)
}
sb.WriteString(key)
sb.WriteString(kvSep)
sb.WriteString(value)
}
return sb.String()
}
func JoinMap(m map[string]any, kvSep, itemSep string) string {
var sb strings.Builder
for key, value := range m {
if sb.Len() > 0 {
sb.WriteString(itemSep)
}
sb.WriteString(key)
sb.WriteString(kvSep)
if s, ok := value.(fmt.Stringer); ok {
sb.WriteString(s.String())
} else {
sb.WriteString(fmt.Sprintf("%v", value))
}
}
return sb.String()
}
func SplitByRune(s string, sep rune, maxParts int) (parts []string) {
return ScopedSplitByRune(s, sep, `'"`, `'"`, maxParts)
// var capacity int = 0
// var sb strings.Builder
// if maxParts < 0 {
// for _, b := range s {
// if b == sep {
// capacity++
// }
// }
// capacity++
// } else {
// capacity = max(1, maxParts)
// }
// parts = make([]string, 0, capacity)
// count := 0
// quote := rune(0)
// for i, r := range s {
// if r == sep && quote == rune(0) {
// if len(parts) < capacity {
// count++
// if count == maxParts {
// sb.WriteString(s[i:])
// }
// parts = append(parts, sb.String())
// sb.Reset()
// if count == maxParts {
// break
// }
// }
// } else if r == '\'' || r == '"' {
// if quote == r {
// quote = rune(0)
// } else {
// quote = r
// }
// sb.WriteRune(r)
// } else {
// sb.WriteRune(r)
// }
// }
// if maxParts < 0 {
// parts = append(parts, sb.String())
// } else {
// for ; count < maxParts; count++ {
// parts = append(parts, sb.String())
// sb.Reset()
// }
// }
// return parts
}
func ScopedSplitByRune(s string, sep rune, scopeOpeners, scopeClosers string, maxParts int) (parts []string) {
var capacity int = 0
var sb strings.Builder
if len(scopeClosers) != len(scopeOpeners) {
panic("scope openers and closers must have the same length")
}
if maxParts < 0 {
capacity = strings.Count(s, string(sep)) + 1
} else {
capacity = max(1, maxParts)
}
parts = make([]string, 0, capacity)
count := 0
scopeIndex := -1
for i, r := range s {
if r == sep && scopeIndex < 0 {
if len(parts) < capacity {
count++
if count == maxParts {
sb.WriteString(s[i:])
}
parts = append(parts, sb.String())
sb.Reset()
if count == maxParts {
break
}
}
} else {
if scopeIndex < 0 {
if quoteIndex := strings.IndexRune(scopeOpeners, r); quoteIndex >= 0 {
scopeIndex = quoteIndex
}
} else if quoteIndex := strings.IndexRune(scopeClosers, r); quoteIndex >= 0 {
scopeIndex = -1
}
sb.WriteRune(r)
}
}
if maxParts < 0 {
parts = append(parts, sb.String())
} else {
for ; count < maxParts; count++ {
parts = append(parts, sb.String())
sb.Reset()
}
}
return parts
}

283
text-util.go Normal file
View File

@ -0,0 +1,283 @@
// text-util.go
package utils
import (
"bytes"
"errors"
"fmt"
"io"
"io/ioutil"
"os"
"os/user"
"sort"
"strings"
"time"
)
type TextTemplate struct {
varMap map[string]string
UserName string
Uid string
ProgramDir string
HomeDir string
env map[string]string
}
func NewTextTemplate(args ...string) (instance *TextTemplate) {
instance = &TextTemplate{}
user, err := user.Current()
if err == nil {
instance.UserName = user.Username
instance.HomeDir = user.HomeDir
instance.Uid = user.Uid
}
instance.ProgramDir, _ = GetProgramDirPath()
instance.varMap = make(map[string]string, 5+len(args))
instance.initVarMap()
for _, arg := range args {
if len(arg) == 0 {
break
}
parts := strings.SplitN(arg, ":", 2)
if len(parts) == 2 {
instance.varMap[parts[0]] = parts[1]
} else {
instance.varMap[parts[0]] = ""
}
}
instance.env = make(map[string]string)
for _, v := range os.Environ() {
parts := strings.SplitN(v, "=", 2)
instance.env[parts[0]] = parts[1]
}
return
}
func (self *TextTemplate) initVarMap() {
self.varMap["dt"] = "Current timestamp as YYYY-MM-DD_HH-MM-SS"
self.varMap["ymd"] = "Current date as YYYY-MM-DD"
self.varMap["hm"] = "Current time as HH-MM"
self.varMap["h"] = "Current time as HH"
self.varMap["hms"] = "Current time as HH-MM-SS"
self.varMap["month"] = "Month name"
self.varMap["month-num"] = "Month as number (mm)"
self.varMap["week-day"] = "Week day name"
self.varMap["week-day-num"] = "Week day as number"
self.varMap["yesterday"] = "Yesterday date"
self.varMap["uid"] = self.Uid
self.varMap["username"] = self.UserName
self.varMap["home"] = self.HomeDir
self.varMap["progdir"] = self.ProgramDir
self.varMap["hostname"], _ = os.Hostname()
}
func (self *TextTemplate) AddVar(name, value string) {
self.varMap[name] = value
}
// func MakeVarMap() map[string]string {
// return map[string]string{
// "ymd": "Current date as YYYY-MM-DD",
// "hms": "Current time as HH-MM-SS",
// // "host": "Hostname",
// "uid": "UID",
// "username": "Username",
// "home": "Home directory",
// }
// }
func (self *TextTemplate) updateVarMap() {
var now = time.Now()
self.varMap["ymd"] = fmt.Sprintf("%04d-%02d-%02d", now.Year(), now.Month(), now.Day())
self.varMap["hms"] = fmt.Sprintf("%02d-%02d-%02d", now.Hour(), now.Minute(), now.Second())
self.varMap["hm"] = fmt.Sprintf("%02d-%02d", now.Hour(), now.Minute())
self.varMap["h"] = fmt.Sprintf("%02d", now.Hour())
self.varMap["month"] = now.Format("January")
self.varMap["month-num"] = fmt.Sprintf("%02d", now.Month())
self.varMap["week-day-num"] = fmt.Sprintf("%d", 1+now.Weekday())
self.varMap["week-day"] = now.Format("Monday")
self.varMap["dt"] = self.varMap["ymd"] + "_" + self.varMap["hms"]
yday := now.AddDate(0, 0, -1)
self.varMap["yesterday"] = fmt.Sprintf("%04d-%02d-%02d", yday.Year(), yday.Month(), yday.Day())
// self.varMap["uid"] = strconv.Itoa(int(self.Uid))
// self.varMap["uid"] = self.Uid
// self.varMap["username"] = self.UserName
// // self.varMap["host"] = self.Hostname
// self.varMap["home"] = self.HomeDir
}
func (self *TextTemplate) Expand(template string) string {
self.updateVarMap()
result := os.Expand(template, func(name string) string {
value, ok := self.varMap[name]
if ok {
return value
} else {
return ""
}
})
return result
}
func (self *TextTemplate) ExpandEnv(template string) (result string) {
if len(template) > 0 {
self.updateVarMap()
result = os.Expand(template, func(name string) string {
value, ok := self.varMap[name]
if ok {
return value
} else {
return "${" + name + "}"
}
})
// for k, v := range self.varMap {
// self.env[k] = v
// }
result = os.ExpandEnv(result)
// result = os.Expand(result, func(name string) string {
// value, ok := self.env[name]
// if ok {
// return value
// } else {
// return ""
// }
// })
}
return result
}
func (self *TextTemplate) Value(key string) (value string, ok bool) {
value, ok = self.varMap[key]
return
}
func (self *TextTemplate) String() string {
var sb strings.Builder
keys := make([]string, 0, len(self.varMap))
for k := range self.varMap {
keys = append(keys, k)
}
sort.Strings(keys)
for _, k := range keys {
sb.WriteString(fmt.Sprintf("%s=%#v\n", k, self.varMap[k]))
}
// for k, v := range self.varMap {
// sb.WriteString(fmt.Sprintf("%s=%#v\n", k, v))
// }
return sb.String()
}
func ParseParamPairsFile(sourceFile string, separator string, hook func(line int, name, value string) (err error)) (err error) {
var source io.Reader
if source, err = os.Open(sourceFile); err == nil {
err = ParseParamPairs(source, separator, hook)
}
return
}
func ParseParamPairs(source io.Reader, separator string, hook func(line int, name, value string) (err error)) (err error) {
var content, sep, name, value []byte
var sb strings.Builder
if content, err = ioutil.ReadAll(source); err != nil {
return
}
if len(separator) == 0 {
sep = []byte{' '}
} else {
sep = []byte(separator)
}
for lineCount, rawLine := range bytes.Split(content, []byte{'\n'}) {
rawLine = bytes.TrimSpace(rawLine)
if len(rawLine) == 0 || rawLine[0] == '#' {
continue
}
parts := bytes.SplitN(rawLine, sep, 2)
name = bytes.TrimSpace(parts[0])
if len(parts) > 1 {
value = bytes.TrimSpace(parts[1])
} else {
value = []byte{}
}
quoteOn := false
escMode := false
sb.Reset()
for _, c := range value {
switch c {
case '"':
if escMode {
sb.WriteByte(c)
escMode = false
} else {
quoteOn = !quoteOn
}
case '\\':
if escMode {
sb.WriteByte(c)
escMode = false
} else {
escMode = true
}
case 'n':
if escMode {
sb.WriteByte('\n')
escMode = false
} else {
sb.WriteByte(c)
}
case 'r':
if escMode {
sb.WriteByte('\r')
escMode = false
} else {
sb.WriteByte(c)
}
case 't':
if escMode {
sb.WriteByte('\t')
escMode = false
} else {
sb.WriteByte(c)
}
case '#':
if quoteOn {
sb.WriteByte(c)
} else if escMode {
sb.WriteByte(c)
escMode = false
} else {
goto endloop
}
default:
if escMode {
escMode = false
}
sb.WriteByte(c)
}
}
endloop:
if err == nil && quoteOn {
err = errors.New("unbalanced quotes")
break
}
if err == nil {
if err = hook(lineCount, string(name), sb.String()); err != nil {
break
}
}
}
return
}

69
time.go Normal file
View File

@ -0,0 +1,69 @@
package utils
import (
"fmt"
"strconv"
"strings"
"time"
)
func StringTimestamp2GoTime(s string) (ts time.Time) {
secs, err := strconv.ParseInt(s, 10, 64)
if err == nil {
ts = time.Unix(secs, 0)
}
return
}
func StringSeconds2GoDuration(s string) (secs time.Duration) {
if len(s) > 0 {
if s[len(s)-1] != 's' {
s += "s"
}
secs, _ = time.ParseDuration(s)
}
return
}
// Convert the spec string to a number of seconds.
// spec is a number, optionally followed by a time unit among 's'(seconds),
// 'm'(minutes), 'h'(hours), and 'd'(days)
// If the time unit is omitted, defaultUnit is used.
// Empty spec returns 0 seconds.
func ParseTimeInterval(spec string, defaultUnit byte) (interval int64, err error) {
var u byte
var intVal int
spec = strings.TrimSpace(spec)
if len(spec) == 0 {
//err = errors.New(iface.ErrEmptyValue)
return
}
spec = strings.ToLower(spec)
u = spec[len(spec)-1]
if u >= '0' && u <= '9' {
u = 'm'
} else {
spec = spec[0 : len(spec)-1]
}
if intVal, err = strconv.Atoi(spec); err != nil {
return
// } else if intVal <= 0 {
// err = errors.New(iface.ErrMustBePositive)
// return
}
switch u {
case 's':
interval = int64(intVal)
case 'm':
interval = int64(intVal) * 60
case 'h':
interval = int64(intVal) * 3600
case 'd':
interval = int64(intVal) * 86400
default:
err = fmt.Errorf("invalid time unit %c", u)
}
return
}

204
tty-util.go Normal file
View File

@ -0,0 +1,204 @@
package utils
import (
"os"
)
const STDIN uint = 0
const STDOUT uint = 1
const STDERR uint = 2
const (
NONE = iota
BLACK
RED
GREEN
BLUE
BROWN
// YELLOW
CYAN
MAGENTA
WHITE
)
type TTYContext struct {
isTTY [3]bool
}
func (self *TTYContext) Init() {
for i, _ := range self.isTTY {
self.isTTY[i] = StreamIsTerminal(getStream(uint(i)))
}
}
func (self *TTYContext) IsTTY(fd uint) bool {
if fd == STDERR || fd == STDOUT {
return self.isTTY[fd]
}
return false
}
func (self *TTYContext) Clean() {
for i, _ := range self.isTTY {
self.isTTY[i] = false
}
}
func (self *TTYContext) Bold(fd uint) string {
if self.isTTY[fd] {
return "\x1b[1m"
}
return ""
}
func (self *TTYContext) BoldOff(fd uint) string {
if self.isTTY[fd] {
return "\x1b[22m"
}
return ""
}
func (self *TTYContext) Underline(fd uint) string {
if self.isTTY[fd] {
return "\x1b[4m"
}
return ""
}
func (self *TTYContext) UnderlineOff(fd uint) string {
if self.isTTY[fd] {
return "\x1b[24m"
}
return ""
}
func (self *TTYContext) Italic(fd uint) string {
if self.isTTY[fd] {
return "\x1b[3m"
}
return ""
}
func (self *TTYContext) ItalicOff(fd uint) string {
if self.isTTY[fd] {
return "\x1b[23m"
}
return ""
}
func (self *TTYContext) BlackFg(fd uint) string {
if self.isTTY[fd] {
return "\x1b[30m"
}
return ""
}
func (self *TTYContext) RedFg(fd uint) string {
if self.isTTY[fd] {
return "\x1b[31m"
}
return ""
}
func (self *TTYContext) GreenFg(fd uint) string {
if self.isTTY[fd] {
return "\x1b[32m"
}
return ""
}
func (self *TTYContext) BrownFg(fd uint) string {
if self.isTTY[fd] {
return "\x1b[33m"
}
return ""
}
func (self *TTYContext) BlueFg(fd uint) string {
if self.isTTY[fd] {
return "\x1b[34m"
}
return ""
}
func (self *TTYContext) MagentaFg(fd uint) string {
if self.isTTY[fd] {
return "\x1b[35m"
}
return ""
}
func (self *TTYContext) CyanFg(fd uint) string {
if self.isTTY[fd] {
return "\x1b[36m"
}
return ""
}
func (self *TTYContext) WhiteFg(fd uint) string {
if self.isTTY[fd] {
return "\x1b[37m"
}
return ""
}
func (self *TTYContext) FgColor(fd uint, n uint) string {
var color string
switch n {
case BLACK:
color = self.BlackFg(fd)
case WHITE:
color = self.WhiteFg(fd)
case RED:
color = self.RedFg(fd)
case GREEN:
color = self.GreenFg(fd)
case BLUE:
color = self.BlueFg(fd)
case BROWN:
color = self.BrownFg(fd)
case CYAN:
color = self.CyanFg(fd)
case MAGENTA:
color = self.MagentaFg(fd)
}
return color
}
// func (self *TTYContext) BgColor(fd uint, n int) string {
// var color string
// switch n {
// case BLACK:
// color = self.BlackBg(fd)
// case WHITE:
// color = self.WhiteBg(fd)
// case RED:
// color = self.RedBg(fd)
// case GREEN:
// color = self.GreenBg(fd)
// case CYAN:
// color = self.CyanBg(fd)
// case MAGENTA:
// color = self.MagentaBg(fd)
// }
// return color
// }
func (self *TTYContext) Reset(fd uint) string {
if StreamIsTerminal(getStream(fd)) {
return "\x1b[0m"
}
return ""
}
func getStream(fd uint) *os.File {
var s *os.File = nil
switch fd {
case STDOUT:
s = os.Stdout
case STDERR:
s = os.Stderr
}
return s
}