2022-03-19 01:24:07 +00:00
|
|
|
package saltyim
|
|
|
|
|
|
|
|
import (
|
2022-03-19 11:42:36 +00:00
|
|
|
"bytes"
|
2022-03-19 23:35:47 +00:00
|
|
|
"context"
|
2022-03-19 01:24:07 +00:00
|
|
|
"fmt"
|
|
|
|
"io"
|
|
|
|
"net/http"
|
2022-03-19 06:34:33 +00:00
|
|
|
"os"
|
2022-03-19 23:35:47 +00:00
|
|
|
"os/exec"
|
|
|
|
"syscall"
|
2022-03-20 13:54:54 +00:00
|
|
|
"text/template"
|
2022-03-19 01:24:07 +00:00
|
|
|
"time"
|
|
|
|
|
|
|
|
log "github.com/sirupsen/logrus"
|
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
|
|
|
defaultRequestTimeout = time.Second * 5
|
|
|
|
)
|
|
|
|
|
2022-03-19 11:42:36 +00:00
|
|
|
func MustRenderString(s string, ctx interface{}) string {
|
|
|
|
out, err := RenderString(s, ctx)
|
|
|
|
if err != nil {
|
|
|
|
log.WithError(err).Fatal("error rendering string template")
|
|
|
|
}
|
|
|
|
return out
|
|
|
|
}
|
|
|
|
|
|
|
|
// DirExists returns true if the given directory exists
|
|
|
|
func DirExists(name string) bool {
|
|
|
|
stat, err := os.Stat(name)
|
|
|
|
if err != nil {
|
|
|
|
if os.IsNotExist(err) {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
return stat.IsDir()
|
|
|
|
}
|
|
|
|
|
2022-03-19 06:34:33 +00:00
|
|
|
// FileExists returns true if the given file exists
|
|
|
|
func FileExists(name string) bool {
|
|
|
|
if _, err := os.Stat(name); err != nil {
|
|
|
|
if os.IsNotExist(err) {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
2022-03-19 11:42:36 +00:00
|
|
|
// RenderString renders the string `s` as a `text/template` using the provided
|
|
|
|
// context `ctx` as input into the template.
|
|
|
|
// Typically used to render the results into a Markdown document.
|
|
|
|
func RenderString(s string, ctx interface{}) (string, error) {
|
2022-03-20 13:54:54 +00:00
|
|
|
t := template.Must(template.New("s").Parse(s))
|
2022-03-19 11:42:36 +00:00
|
|
|
buf := bytes.NewBuffer([]byte{})
|
|
|
|
err := t.Execute(buf, ctx)
|
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
|
|
|
|
return buf.String(), nil
|
|
|
|
}
|
|
|
|
|
2022-03-19 01:24:07 +00:00
|
|
|
// Request is a generic request handling function for making artbitrary HTPT
|
|
|
|
// requests to Salty endpoints for looking up Salty Addresses, Configs and
|
|
|
|
// publishing encrypted messages.
|
|
|
|
func Request(method, uri string, headers http.Header, body io.Reader) (*http.Response, error) {
|
|
|
|
req, err := http.NewRequest(method, uri, body)
|
|
|
|
if err != nil {
|
2022-03-19 15:24:21 +00:00
|
|
|
return nil, fmt.Errorf("%s: http.NewRequest fail: %s", uri, err)
|
2022-03-19 01:24:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if headers == nil {
|
|
|
|
headers = make(http.Header)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Set a default User-Agent (if none set)
|
|
|
|
if headers.Get("User-Agent") == "" {
|
|
|
|
headers.Set("User-Agent", fmt.Sprintf("saltyim/%s", FullVersion()))
|
|
|
|
}
|
|
|
|
|
|
|
|
req.Header = headers
|
|
|
|
|
|
|
|
client := http.Client{
|
|
|
|
Timeout: defaultRequestTimeout,
|
|
|
|
}
|
|
|
|
|
|
|
|
res, err := client.Do(req)
|
|
|
|
if err != nil {
|
2022-03-19 15:24:21 +00:00
|
|
|
return nil, fmt.Errorf("%s: client.Do fail: %s", uri, err)
|
2022-03-19 01:24:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if res.StatusCode/100 != 2 {
|
2022-03-19 15:24:21 +00:00
|
|
|
return nil, fmt.Errorf("non-2xx response received: %s", res.Status)
|
2022-03-19 01:24:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return res, nil
|
|
|
|
}
|
2022-03-19 23:35:47 +00:00
|
|
|
|
|
|
|
// CmdExists ...
|
|
|
|
func CmdExists(cmd string) bool {
|
|
|
|
_, err := exec.LookPath(cmd)
|
|
|
|
return err == nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// RunCmd ...
|
2022-03-19 23:55:20 +00:00
|
|
|
func RunCmd(timeout time.Duration, command string, stdin io.Reader, args ...string) (string, error) {
|
2022-03-19 23:35:47 +00:00
|
|
|
var (
|
|
|
|
ctx context.Context
|
|
|
|
cancel context.CancelFunc
|
|
|
|
)
|
|
|
|
|
|
|
|
if timeout > 0 {
|
|
|
|
ctx, cancel = context.WithTimeout(context.Background(), timeout)
|
|
|
|
} else {
|
|
|
|
ctx, cancel = context.WithCancel(context.Background())
|
|
|
|
}
|
|
|
|
defer cancel()
|
|
|
|
|
|
|
|
cmd := exec.CommandContext(ctx, command, args...)
|
2022-03-19 23:55:20 +00:00
|
|
|
cmd.Stdin = stdin
|
2022-03-19 23:35:47 +00:00
|
|
|
|
|
|
|
out, err := cmd.CombinedOutput()
|
|
|
|
if err != nil {
|
|
|
|
if exitError, ok := err.(*exec.ExitError); ok {
|
|
|
|
if ws, ok := exitError.Sys().(syscall.WaitStatus); ok && ws.Signal() == syscall.SIGKILL {
|
|
|
|
err = &ErrCommandKilled{Err: err, Signal: ws.Signal()}
|
|
|
|
} else {
|
|
|
|
err = &ErrCommandFailed{Err: err, Status: exitError.ExitCode()}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-03-19 23:55:20 +00:00
|
|
|
return "", err
|
2022-03-19 23:35:47 +00:00
|
|
|
}
|
|
|
|
|
2022-03-19 23:55:20 +00:00
|
|
|
return string(out), nil
|
2022-03-19 23:35:47 +00:00
|
|
|
}
|
2022-03-20 08:16:36 +00:00
|
|
|
|
|
|
|
// SetTerminalTitle sets the Terminal/Console's title
|
|
|
|
func SetTerminalTitle(format string, args ...interface{}) {
|
|
|
|
fmt.Printf("\033]0;%s\007", fmt.Sprintf(format, args...))
|
|
|
|
}
|