goutil/misc/goutil.go

347 lines
6.9 KiB
Go
Raw Normal View History

package misc
2016-11-15 16:23:20 +01:00
import (
2018-07-01 16:03:26 +02:00
"bufio"
"bytes"
2018-07-01 16:03:26 +02:00
"errors"
2018-11-04 23:07:08 +01:00
"flag"
2018-07-01 16:03:26 +02:00
"fmt"
2019-02-12 00:17:21 +01:00
"io"
2016-11-15 16:23:20 +01:00
"io/ioutil"
2019-02-11 23:52:19 +01:00
"net/http"
2018-07-01 16:03:26 +02:00
"os"
2018-11-04 23:07:08 +01:00
"os/exec"
2019-01-12 22:26:31 +01:00
"os/user"
2016-11-15 16:23:20 +01:00
"path/filepath"
2018-11-04 23:07:08 +01:00
"runtime"
"strings"
2016-11-15 16:23:20 +01:00
)
2018-07-01 16:03:26 +02:00
func DecorateError(s string, err error) error {
if err != nil {
return errors.New(s + ": " + err.Error())
} else {
return nil
}
}
2016-11-15 16:23:20 +01:00
func WriteFile(filename string, data string) error {
return ioutil.WriteFile(filename, []byte(data), 0644)
}
2018-11-04 23:07:08 +01:00
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
}
2016-11-15 16:23:20 +01:00
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
}
2018-07-01 16:03:26 +02:00
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
}
2018-07-01 16:03:26 +02:00
func PathExists(path string) bool {
if _, err := os.Stat(path); os.IsNotExist(err) {
return false
} else {
return true
}
}
2018-12-23 15:51:20 +01:00
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
}
2019-01-12 22:26:31 +01:00
func HomeDir() (string, error) {
d := ""
currentUser, err := user.Current()
if err == nil {
d = currentUser.HomeDir
}
return d, err
}
2018-07-01 16:03:26 +02:00
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
}
}
2018-12-22 19:50:52 +01:00
func OptDo(err error, f func() error) error {
if err == nil {
return f()
} else {
return err
}
}
2018-12-22 20:12:34 +01:00
func OptPanic(err error) {
if err != nil {
panic(err)
}
}
2018-07-01 16:03:26 +02:00
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]
}
2018-11-04 23:07:08 +01:00
func OpenInDefaultApp(filename string, wait bool) error {
var cmd *exec.Cmd
goos := runtime.GOOS
switch goos {
2018-11-04 23:07:08 +01:00
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
2018-11-04 23:07:08 +01:00
} else {
return cmd.Start()
}
}
2018-12-10 17:16:26 +01:00
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
}
2018-11-04 23:07:08 +01:00
type CommandFunc func(args []string) error
type CommandFlagsInit func(s *flag.FlagSet)
type CommandInitExecFunc func() (CommandFlagsInit, CommandFunc)
type Command struct {
2020-05-29 10:10:30 +02:00
Cmd string
Exec CommandFunc
Desc string
Flags *flag.FlagSet
2018-11-04 23:07:08 +01:00
}
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
2018-12-09 18:14:38 +01:00
func usageAndExit(cmds []Command) {
2018-12-09 23:57:43 +01:00
app := os.Args[0]
fmt.Println(app)
2018-12-09 10:06:27 +01:00
fmt.Println()
2018-11-04 23:07:08 +01:00
fmt.Println("Possible commands:")
for _, cmd := range cmds {
2020-05-29 10:10:30 +02:00
fmt.Println(" " + cmd.Cmd)
fmt.Println(" \t" + cmd.Desc)
2018-11-04 23:07:08 +01:00
}
fmt.Println()
2018-12-09 23:57:43 +01:00
fmt.Println("for detailed information type '" + app + " help COMMAND'")
2018-11-04 23:07:08 +01:00
os.Exit(-1)
}
func Execute(possibleCommands []Command) error {
commands := commandCollection{}
for _, c := range possibleCommands {
2020-05-29 10:10:30 +02:00
commands[c.Cmd] = c
2018-11-04 23:07:08 +01:00
}
arglen := len(os.Args)
if arglen <= 1 {
2018-12-09 18:14:38 +01:00
usageAndExit(possibleCommands)
2018-11-04 23:07:08 +01:00
}
cmdStr := os.Args[1]
if cmdStr == "help" {
if arglen == 2 {
2018-12-09 18:14:38 +01:00
usageAndExit(possibleCommands)
2018-11-04 23:07:08 +01:00
} else {
cmd, ok := commands[os.Args[2]]
if !ok {
2018-12-09 18:14:38 +01:00
usageAndExit(possibleCommands)
2018-11-04 23:07:08 +01:00
} else {
2020-05-29 10:10:30 +02:00
fmt.Println("Description of " + cmd.Cmd + ":")
fmt.Println(" " + cmd.Desc)
if cmd.Flags != nil {
2018-11-04 23:07:08 +01:00
fmt.Println("Possible flags:")
2020-05-29 10:10:30 +02:00
cmd.Flags.PrintDefaults()
2018-11-04 23:07:08 +01:00
} else {
fmt.Println("No flags")
}
return nil
}
}
}
cmd, ok := commands[cmdStr]
if !ok {
2018-12-09 18:14:38 +01:00
usageAndExit(possibleCommands)
2018-11-04 23:07:08 +01:00
}
2020-05-29 10:10:30 +02:00
if cmd.Flags != nil {
cmd.Flags.Parse(os.Args[2:])
return cmd.Exec(cmd.Flags.Args())
2018-11-04 23:07:08 +01:00
} else {
2020-05-29 10:10:30 +02:00
return cmd.Exec(os.Args[2:])
2018-11-04 23:07:08 +01:00
}
}
2019-01-13 10:24:46 +01:00
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
}
2019-02-11 23:52:19 +01:00
func DownloadAll(url string, limit int64) ([]byte, error) {
var buf bytes.Buffer
err := download(url, &buf, limit)
return buf.Bytes(), err
}
func DownloadToFile(url string, dest string, limit int64) error {
file, err := os.Create(dest)
2019-02-11 23:52:19 +01:00
if err != nil {
return errors.New("DownloadToFile: " + err.Error())
2019-02-11 23:52:19 +01:00
}
defer file.Close()
return download(url, file, limit)
2019-02-11 23:52:19 +01:00
}
2019-02-12 00:17:21 +01:00
func download(url string, dest io.Writer, limit int64) error {
2019-02-12 00:17:21 +01:00
resp, err := http.Get(url)
if err != nil {
return errors.New("download: " + err.Error())
2019-02-12 00:17:21 +01:00
}
defer resp.Body.Close()
var reader io.Reader
if limit > 0 {
reader = io.LimitReader(resp.Body, limit)
} else {
reader = resp.Body
2019-02-12 00:17:21 +01:00
}
_, err = io.Copy(dest, reader)
2019-02-12 00:17:21 +01:00
return err
}