goutil/goutil.go
2020-05-29 10:10:30 +02:00

343 lines
6.8 KiB
Go

package goutil
import (
"bufio"
"errors"
"flag"
"fmt"
"io"
"io/ioutil"
"net/http"
"os"
"os/exec"
"os/user"
"path/filepath"
"runtime"
"strings"
)
func DecorateError(s string, err error) error {
if err != nil {
return errors.New(s + ": " + err.Error())
} else {
return nil
}
}
func WriteFile(filename string, data string) error {
return ioutil.WriteFile(filename, []byte(data), 0644)
}
func AppendToFile(filename string, data string) error {
f, err := os.OpenFile(filename, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0644)
if err != nil {
return errors.New("AppendToFile " + filename + ": " + err.Error())
}
defer f.Close()
_, err = f.WriteString(data)
return err
}
func ReadFile(filename string) (string, error) {
data, err := ioutil.ReadFile(filename)
return string(data), err
}
func TrimExt(path string) string {
extension := filepath.Ext(path)
return path[0 : len(path)-len(extension)]
}
func ListFilesExt(dir string, ext string) []string {
list := make([]string, 0)
ext = strings.ToUpper(ext)
files, err := ioutil.ReadDir(dir)
if err == nil {
for _, file := range files {
if !file.IsDir() {
if strings.ToUpper(filepath.Ext(file.Name())) == ext {
list = append(list, filepath.Join(dir, file.Name()))
}
}
}
}
return list
}
func RecListFilesExt(dir string, ext string) []string {
list := make([]string, 0)
traverse := func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if info.IsDir() {
list = append(list, ListFilesExt(path, ext)...)
}
return nil
}
filepath.Walk(dir, traverse)
return list
}
func PathExists(path string) bool {
if _, err := os.Stat(path); os.IsNotExist(err) {
return false
} else {
return true
}
}
func DirsWithPrefix(path string, prefix string) ([]string, error) {
dirs := []string{}
files, err := ioutil.ReadDir(path)
if err != nil {
return dirs, err
}
for _, file := range files {
if file.IsDir() {
if name := file.Name(); strings.HasPrefix(name, prefix) {
dirs = append(dirs, name)
}
}
}
return dirs, nil
}
func HomeDir() (string, error) {
d := ""
currentUser, err := user.Current()
if err == nil {
d = currentUser.HomeDir
}
return d, err
}
func AskFor(question string) (string, error) {
fmt.Print(question + ": ")
reader := bufio.NewReader(os.Stdin)
s, err := reader.ReadString('\n')
if err == nil {
return strings.TrimSpace(s), nil
} else {
return "", err
}
}
func OptDo(err error, f func() error) error {
if err == nil {
return f()
} else {
return err
}
}
func OptPanic(err error) {
if err != nil {
panic(err)
}
}
func IntMin(x, y int) int {
if x < y {
return x
} else {
return y
}
}
func IntMax(x, y int) int {
if x > y {
return x
} else {
return y
}
}
func StrSliceAt(sl []string, i int) string {
if i < len(sl) {
return sl[i]
} else {
return ""
}
}
func StrSlice(sl []string, start int, end int) []string {
bound := func(i int) int { return IntMin(IntMax(0, i), len(sl)) }
start = bound(start)
end = bound(end)
return sl[start:end]
}
func OpenInDefaultApp(filename string, wait bool) error {
var cmd *exec.Cmd
goos := runtime.GOOS
switch goos {
case "windows":
cmd = exec.Command(filepath.Join(os.Getenv("SYSTEMROOT"), "System32", "rundll32.exe"), "url.dll,FileProtocolHandler", filename)
case "darwin":
cmd = exec.Command("open", filename)
default:
cmd = exec.Command("xdg-open", filename)
}
if wait {
err := cmd.Run()
if goos == "windows" {
AskFor("Press Enter when you're done")
}
return err
} else {
return cmd.Start()
}
}
func OpenInEditor(filename string, wait bool) error {
var err error
goos := runtime.GOOS
if ed := os.Getenv("EDITOR"); ed != "" {
cmd := exec.Command(ed, filename)
cmd.Env = os.Environ()
if wait {
err = cmd.Run()
if goos == "windows" {
AskFor("Press Enter when you're done")
}
} else {
err = cmd.Start()
}
} else {
err = errors.New("EDITOR not set in environment")
}
return err
}
type CommandFunc func(args []string) error
type CommandFlagsInit func(s *flag.FlagSet)
type CommandInitExecFunc func() (CommandFlagsInit, CommandFunc)
type Command struct {
Cmd string
Exec CommandFunc
Desc string
Flags *flag.FlagSet
}
func NewCommandWithFlags(cmd string, f CommandInitExecFunc, desc string) Command {
flagsInit, exec := f()
var flags *flag.FlagSet
if flagsInit != nil {
flags = flag.NewFlagSet(cmd, flag.ExitOnError)
flagsInit(flags)
}
c := Command{cmd, exec, desc, flags}
return c
}
func NewCommand(cmd string, f CommandFunc, desc string) Command {
return NewCommandWithFlags(cmd, func() (CommandFlagsInit, CommandFunc) { return nil, f }, desc)
}
type commandCollection map[string]Command
func usageAndExit(cmds []Command) {
app := os.Args[0]
fmt.Println(app)
fmt.Println()
fmt.Println("Possible commands:")
for _, cmd := range cmds {
fmt.Println(" " + cmd.Cmd)
fmt.Println(" \t" + cmd.Desc)
}
fmt.Println()
fmt.Println("for detailed information type '" + app + " help COMMAND'")
os.Exit(-1)
}
func Execute(possibleCommands []Command) error {
commands := commandCollection{}
for _, c := range possibleCommands {
commands[c.Cmd] = c
}
arglen := len(os.Args)
if arglen <= 1 {
usageAndExit(possibleCommands)
}
cmdStr := os.Args[1]
if cmdStr == "help" {
if arglen == 2 {
usageAndExit(possibleCommands)
} else {
cmd, ok := commands[os.Args[2]]
if !ok {
usageAndExit(possibleCommands)
} else {
fmt.Println("Description of " + cmd.Cmd + ":")
fmt.Println(" " + cmd.Desc)
if cmd.Flags != nil {
fmt.Println("Possible flags:")
cmd.Flags.PrintDefaults()
} else {
fmt.Println("No flags")
}
return nil
}
}
}
cmd, ok := commands[cmdStr]
if !ok {
usageAndExit(possibleCommands)
}
if cmd.Flags != nil {
cmd.Flags.Parse(os.Args[2:])
return cmd.Exec(cmd.Flags.Args())
} else {
return cmd.Exec(os.Args[2:])
}
}
func Notify(head string, body string) error {
var cmd *exec.Cmd
goos := runtime.GOOS
switch goos {
case "windows":
cmd = nil
case "darwin":
cmd = exec.Command("osascript", "-e", `display notification "`+body+`" with title "`+head+`"`)
default:
cmd = exec.Command("notify-send", head, body)
}
if cmd != nil {
return cmd.Start()
}
return nil
}
func DownloadAll(url string) ([]byte, error) {
resp, err := http.Get(url)
if err != nil {
return nil, errors.New("Download: " + err.Error())
}
defer resp.Body.Close()
data, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, errors.New("Download: " + err.Error())
}
return data, err
}
func DownloadToFile(url string, dest string) error {
resp, err := http.Get(url)
if err != nil {
return errors.New("DownloadToFile: " + err.Error())
}
defer resp.Body.Close()
file, err := os.Create(dest)
if err != nil {
return errors.New("DownloadToFile: " + err.Error())
}
defer file.Close()
_, err = io.Copy(file, resp.Body)
return err
}