aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristine Dodrill <me@christine.website>2018-10-05 14:03:55 -0700
committerChristine Dodrill <me@christine.website>2018-10-05 14:31:22 -0700
commitc63e73391d634bdb25b3df1c582bb56b6d9a0963 (patch)
tree81ec642a36c4ca84b3d0d4dfd8d2a91d09f762cd
parentdbeba1e5c5c0bc534a515eb298ee4f1d49df4d20 (diff)
downloadx-c63e73391d634bdb25b3df1c582bb56b6d9a0963.tar.xz
x-c63e73391d634bdb25b3df1c582bb56b6d9a0963.zip
mastodon/sona-pi-toki-pona: build and deploy in go, not shell
-rw-r--r--go.mod2
-rw-r--r--go.sum4
-rw-r--r--internal/greedo/doc.go2
-rw-r--r--internal/greedo/greedo.go85
-rw-r--r--internal/greedo/greedo_test.go11
-rw-r--r--internal/internal.go40
-rw-r--r--internal/minipaas/doc.go2
-rw-r--r--internal/minipaas/minipaas.go40
-rw-r--r--mastodon/sona-pi-toki-pona/build.go54
-rwxr-xr-xmastodon/sona-pi-toki-pona/build.sh7
-rw-r--r--tools/appsluggr/main.go4
-rw-r--r--tools/minipaas/main.go34
-rw-r--r--vendor/github.com/kballard/go-shellquote/LICENSE19
-rw-r--r--vendor/github.com/kballard/go-shellquote/README36
-rw-r--r--vendor/github.com/kballard/go-shellquote/doc.go3
-rw-r--r--vendor/github.com/kballard/go-shellquote/quote.go102
-rw-r--r--vendor/github.com/kballard/go-shellquote/unquote.go156
-rw-r--r--vendor/github.com/tmc/scp/LICENSE14
-rw-r--r--vendor/github.com/tmc/scp/README.md15
-rw-r--r--vendor/github.com/tmc/scp/scp.go59
-rw-r--r--vendor/modules.txt16
21 files changed, 692 insertions, 13 deletions
diff --git a/go.mod b/go.mod
index 9a21999..ed1ff35 100644
--- a/go.mod
+++ b/go.mod
@@ -31,6 +31,7 @@ require (
github.com/joeshaw/envdecode v0.0.0-20180312135643-c9e015854467
github.com/joho/godotenv v1.3.0
github.com/kardianos/osext v0.0.0-20170510131534-ae77be60afb1 // indirect
+ github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
github.com/klauspost/cpuid v0.0.0-20180405133222-e7e905edc00e // indirect
github.com/klauspost/crc32 v0.0.0-20170628072449-bab58d77464a // indirect
github.com/klauspost/reedsolomon v0.0.0-20180704173009-925cb01d6510 // indirect
@@ -44,6 +45,7 @@ require (
github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf // indirect
github.com/streamrail/concurrent-map v0.0.0-20160823150647-8bf1e9bacbf6
github.com/technoweenie/multipartstreamer v1.0.1 // indirect
+ github.com/tmc/scp v0.0.0-20170824174625-f7b48647feef
github.com/xtaci/kcp-go v2.0.3+incompatible
github.com/xtaci/smux v1.0.7
go4.org v0.0.0-20180809161055-417644f6feb5
diff --git a/go.sum b/go.sum
index 3ec05ac..d250676 100644
--- a/go.sum
+++ b/go.sum
@@ -84,6 +84,8 @@ github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc=
github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
github.com/kardianos/osext v0.0.0-20170510131534-ae77be60afb1 h1:PJPDf8OUfOK1bb/NeTKd4f1QXZItOX389VN3B6qC8ro=
github.com/kardianos/osext v0.0.0-20170510131534-ae77be60afb1/go.mod h1:1NbS8ALrpOvjt0rHPNLyCIeMtbizbir8U//inJ+zuB8=
+github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs=
+github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/klauspost/cpuid v0.0.0-20180405133222-e7e905edc00e h1:+lIPJOWl+jSiJOc70QXJ07+2eg2Jy2EC7Mi11BWujeM=
github.com/klauspost/cpuid v0.0.0-20180405133222-e7e905edc00e/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
@@ -150,6 +152,8 @@ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXf
github.com/tarm/serial v0.0.0-20180114052751-eaafced92e96/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA=
github.com/technoweenie/multipartstreamer v1.0.1 h1:XRztA5MXiR1TIRHxH2uNxXxaIkKQDeX7m2XsSOlQEnM=
github.com/technoweenie/multipartstreamer v1.0.1/go.mod h1:jNVxdtShOxzAsukZwTSw6MDx5eUJoiEBsSvzDU9uzog=
+github.com/tmc/scp v0.0.0-20170824174625-f7b48647feef h1:7D6Nm4D6f0ci9yttWaKjM1TMAXrH5Su72dojqYGntFY=
+github.com/tmc/scp v0.0.0-20170824174625-f7b48647feef/go.mod h1:WLFStEdnJXpjK8kd4qKLwQKX/1vrDzp5BcDyiZJBHJM=
github.com/xtaci/kcp-go v2.0.3+incompatible h1:2fkFeJIk83fA0G0OfBS2XmQBPlfsfQCs0jS5Xw6EERg=
github.com/xtaci/kcp-go v2.0.3+incompatible/go.mod h1:bN6vIwHQbfHaHtFpEssmWsN45a+AZwO7eyRCmEIbtvE=
github.com/xtaci/smux v1.0.7 h1:ragFTIwevybZKibSfltLxG2biJ4Y9eFQGhcBntoEhz4=
diff --git a/internal/greedo/doc.go b/internal/greedo/doc.go
new file mode 100644
index 0000000..5684040
--- /dev/null
+++ b/internal/greedo/doc.go
@@ -0,0 +1,2 @@
+// Package greedo is a set of functions to copy files to https://xena.greedo.xeserv.us/files.
+package greedo
diff --git a/internal/greedo/greedo.go b/internal/greedo/greedo.go
new file mode 100644
index 0000000..5ec2c58
--- /dev/null
+++ b/internal/greedo/greedo.go
@@ -0,0 +1,85 @@
+package greedo
+
+import (
+ "bytes"
+ "io"
+ "io/ioutil"
+ "net"
+ "os"
+ "path/filepath"
+
+ "github.com/tmc/scp"
+ "golang.org/x/crypto/ssh"
+ "golang.org/x/crypto/ssh/agent"
+)
+
+func getAgent() (agent.Agent, error) {
+ agentConn, err := net.Dial("unix", os.Getenv("SSH_AUTH_SOCK"))
+ return agent.NewClient(agentConn), err
+}
+
+const (
+ greedoAddr = `greedo.xeserv.us:22`
+ greedoUser = `xena`
+)
+
+// Dial opens a SSH client to greedo.
+func Dial() (*ssh.Client, error) {
+ agent, err := getAgent()
+ if err != nil {
+ return nil, err
+ }
+
+ client, err := ssh.Dial("tcp", greedoAddr, &ssh.ClientConfig{
+ User: greedoUser,
+ Auth: []ssh.AuthMethod{
+ ssh.PublicKeysCallback(agent.Signers),
+ },
+ HostKeyCallback: ssh.InsecureIgnoreHostKey(),
+ })
+ if err != nil {
+ return nil, err
+ }
+
+ return client, nil
+}
+
+// Copy copies a local file reader to the remote destination path. This copies the enitre contents of contents into ram. Don't use this function if doing so is a bad idea. Only works on files less than 2 GB.
+func Copy(mode os.FileMode, fileName string, contents io.Reader, destinationPath string) error {
+ data, err := ioutil.ReadAll(contents)
+ if err != nil {
+ return err
+ }
+
+ client, err := Dial()
+ if err != nil {
+ return err
+ }
+
+ session, err := client.NewSession()
+ if err != nil {
+ return err
+ }
+
+ err = scp.Copy(int64(len(data)), mode, fileName, bytes.NewBuffer(data), destinationPath, session)
+ if err != nil {
+ return err
+ }
+
+ return nil
+}
+
+// CopyFile copies a file to Greedo's public files folder and returns its public-facing URL.
+func CopyFile(fileName string, contents io.Reader) (string, error) {
+ err := Copy(0644, fileName, contents, filepath.Join("public_html", "files", fileName))
+ if err != nil {
+ return "", err
+ }
+
+ return WebURL(fileName), nil
+}
+
+// WebURL constructs a public-facing URL for a given resource by fragment.
+func WebURL(fragment string) string {
+ return "https://xena.greedo.xeserv.us/files/" + fragment
+}
diff --git a/internal/greedo/greedo_test.go b/internal/greedo/greedo_test.go
new file mode 100644
index 0000000..4e1f857
--- /dev/null
+++ b/internal/greedo/greedo_test.go
@@ -0,0 +1,11 @@
+package greedo
+
+import "testing"
+
+func TestDial(t *testing.T) {
+ cli, err := Dial()
+ if err != nil {
+ t.Fatal(err)
+ }
+ cli.Close()
+}
diff --git a/internal/internal.go b/internal/internal.go
index f21624e..9c36aa3 100644
--- a/internal/internal.go
+++ b/internal/internal.go
@@ -1,17 +1,36 @@
package internal
import (
+ "context"
"encoding/json"
"flag"
"fmt"
"log"
"net/http"
"os"
+ "os/exec"
+ "time"
"github.com/Xe/x/tools/license/licenses"
"go4.org/legal"
)
+// current working directory and date:time tag of app boot (useful for tagging slugs)
+var (
+ WD string
+ DateTag string
+)
+
+func init() {
+ lwd, err := os.Getwd()
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ WD = lwd
+ DateTag = time.Now().Format("010220061504")
+}
+
var (
licenseShow = flag.Bool("license", false, "show software license?")
)
@@ -38,3 +57,24 @@ func HandleLicense() {
os.Exit(0)
}
}
+
+// ShouldWork explodes if the given command with the given env, working dir and context fails.
+func ShouldWork(ctx context.Context, env []string, dir string, cmdName string, args ...string) {
+ loc, err := exec.LookPath(cmdName)
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ cmd := exec.CommandContext(ctx, loc, args...)
+ cmd.Dir = dir
+ cmd.Env = env
+
+ cmd.Stdout = os.Stdout
+ cmd.Stderr = os.Stderr
+
+ log.Printf("starting process, env: %v, pwd: %s, cmd: %s, args: %v", env, dir, loc, args)
+ err = cmd.Run()
+ if err != nil {
+ log.Fatal(err)
+ }
+}
diff --git a/internal/minipaas/doc.go b/internal/minipaas/doc.go
new file mode 100644
index 0000000..659774a
--- /dev/null
+++ b/internal/minipaas/doc.go
@@ -0,0 +1,2 @@
+// Package minipaas is a set of functions for interfacing with minipaas.xeserv.us.
+package minipaas
diff --git a/internal/minipaas/minipaas.go b/internal/minipaas/minipaas.go
new file mode 100644
index 0000000..5632c3c
--- /dev/null
+++ b/internal/minipaas/minipaas.go
@@ -0,0 +1,40 @@
+package minipaas
+
+import (
+ "net"
+ "os"
+
+ "golang.org/x/crypto/ssh"
+ "golang.org/x/crypto/ssh/agent"
+)
+
+func getAgent() (agent.Agent, error) {
+ agentConn, err := net.Dial("unix", os.Getenv("SSH_AUTH_SOCK"))
+ return agent.NewClient(agentConn), err
+}
+
+const (
+ minipaasAddr = `minipaas.xeserv.us:22`
+ minipaasUser = `dokku`
+)
+
+// Dial opens a SSH client to minipaas as the dokku user.
+func Dial() (*ssh.Client, error) {
+ agent, err := getAgent()
+ if err != nil {
+ return nil, err
+ }
+
+ client, err := ssh.Dial("tcp", minipaasAddr, &ssh.ClientConfig{
+ User: minipaasUser,
+ Auth: []ssh.AuthMethod{
+ ssh.PublicKeysCallback(agent.Signers),
+ },
+ HostKeyCallback: ssh.InsecureIgnoreHostKey(),
+ })
+ if err != nil {
+ return nil, err
+ }
+
+ return client, nil
+}
diff --git a/mastodon/sona-pi-toki-pona/build.go b/mastodon/sona-pi-toki-pona/build.go
new file mode 100644
index 0000000..4c8010c
--- /dev/null
+++ b/mastodon/sona-pi-toki-pona/build.go
@@ -0,0 +1,54 @@
+//+build ignore
+
+// Builds and deploys the application to minipaas.
+package main
+
+import (
+ "context"
+ "log"
+ "os"
+
+ "github.com/Xe/x/internal"
+ "github.com/Xe/x/internal/greedo"
+ "github.com/Xe/x/internal/minipaas"
+)
+
+func main() {
+ ctx, cancel := context.WithCancel(context.Background())
+ defer cancel()
+
+ env := append(os.Environ(), []string{"CGO_ENABLED=0", "GOOS=linux"}...)
+ internal.ShouldWork(ctx, env, internal.WD, "vgo", "build", "-o=sona-pi-toki-pona")
+ internal.ShouldWork(ctx, env, internal.WD, "appsluggr", "-worker=sona-pi-toki-pona")
+ fin, err := os.Open("slug.tar.gz")
+ if err != nil {
+ log.Fatal(err)
+ }
+ defer fin.Close()
+
+ fname := "sona-pi-toki-pona-" + internal.DateTag + ".tar.gz"
+ pubURL, err := greedo.CopyFile(fname, fin)
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ mp, err := minipaas.Dial()
+ if err != nil {
+ log.Fatal(err)
+ }
+ defer mp.Close()
+
+ sess, err := mp.NewSession()
+ if err != nil {
+ log.Fatal(err)
+ }
+ defer sess.Close()
+ sess.Stdin = os.Stdin
+ sess.Stdout = os.Stdout
+ sess.Stderr = os.Stderr
+
+ err = sess.Run("tar:from sona-pi-toki-pona " + pubURL)
+ if err != nil {
+ log.Fatal(err)
+ }
+}
diff --git a/mastodon/sona-pi-toki-pona/build.sh b/mastodon/sona-pi-toki-pona/build.sh
deleted file mode 100755
index a92b6f8..0000000
--- a/mastodon/sona-pi-toki-pona/build.sh
+++ /dev/null
@@ -1,7 +0,0 @@
-#!/bin/sh
-
-CGO_ENABLED=0 GOOS=linux go build -o sona-pi-toki-pona
-appsluggr -fname sona-pi-toki-pona.tar.gz -worker sona-pi-toki-pona
-scp sona-pi-toki-pona.tar.gz xena@greedo.xeserv.us:public_html/files
-ssh dokku@minipaas.xeserv.us tar:from sona-pi-toki-pona https://xena.greedo.xeserv.us/files/sona-pi-toki-pona.tar.gz
-
diff --git a/tools/appsluggr/main.go b/tools/appsluggr/main.go
index 7b30ab1..906bbcb 100644
--- a/tools/appsluggr/main.go
+++ b/tools/appsluggr/main.go
@@ -61,6 +61,10 @@ func main() {
Copy(*worker, filepath.Join(dir, "bin", "worker"))
}
+ err = ioutil.WriteFile(filepath.Join(dir, ".buildpacks"), []byte("https://github.com/ryandotsmith/null-buildpack"), 0666)
+ if err != nil {
+ log.Fatal(err)
+ }
err = ioutil.WriteFile(filepath.Join(dir, "DOKKU_SCALE"), []byte(scalefile), 0666)
if err != nil {
log.Fatal(err)
diff --git a/tools/minipaas/main.go b/tools/minipaas/main.go
new file mode 100644
index 0000000..cebd71e
--- /dev/null
+++ b/tools/minipaas/main.go
@@ -0,0 +1,34 @@
+package main
+
+import (
+ "flag"
+ "log"
+ "os"
+ "strings"
+
+ "github.com/Xe/x/internal"
+ "github.com/Xe/x/internal/minipaas"
+)
+
+func main() {
+ flag.Parse()
+ internal.HandleLicense()
+
+ client, err := minipaas.Dial()
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ sess, err := client.NewSession()
+ if err != nil {
+ log.Fatal(err)
+ }
+ defer sess.Close()
+ sess.Stdout = os.Stdout
+ sess.Stderr = os.Stderr
+
+ err = sess.Run(strings.Join(flag.Args(), " "))
+ if err != nil {
+ log.Fatal(err)
+ }
+}
diff --git a/vendor/github.com/kballard/go-shellquote/LICENSE b/vendor/github.com/kballard/go-shellquote/LICENSE
new file mode 100644
index 0000000..a6d7731
--- /dev/null
+++ b/vendor/github.com/kballard/go-shellquote/LICENSE
@@ -0,0 +1,19 @@
+Copyright (C) 2014 Kevin Ballard
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
+OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/vendor/github.com/kballard/go-shellquote/README b/vendor/github.com/kballard/go-shellquote/README
new file mode 100644
index 0000000..4d34e87
--- /dev/null
+++ b/vendor/github.com/kballard/go-shellquote/README
@@ -0,0 +1,36 @@
+PACKAGE
+
+package shellquote
+ import "github.com/kballard/go-shellquote"
+
+ Shellquote provides utilities for joining/splitting strings using sh's
+ word-splitting rules.
+
+VARIABLES
+
+var (
+ UnterminatedSingleQuoteError = errors.New("Unterminated single-quoted string")
+ UnterminatedDoubleQuoteError = errors.New("Unterminated double-quoted string")
+ UnterminatedEscapeError = errors.New("Unterminated backslash-escape")
+)
+
+
+FUNCTIONS
+
+func Join(args ...string) string
+ Join quotes each argument and joins them with a space. If passed to
+ /bin/sh, the resulting string will be split back into the original
+ arguments.
+
+func Split(input string) (words []string, err error)
+ Split splits a string according to /bin/sh's word-splitting rules. It
+ supports backslash-escapes, single-quotes, and double-quotes. Notably it
+ does not support the $'' style of quoting. It also doesn't attempt to
+ perform any other sort of expansion, including brace expansion, shell
+ expansion, or pathname expansion.
+
+ If the given input has an unterminated quoted string or ends in a
+ backslash-escape, one of UnterminatedSingleQuoteError,
+ UnterminatedDoubleQuoteError, or UnterminatedEscapeError is returned.
+
+
diff --git a/vendor/github.com/kballard/go-shellquote/doc.go b/vendor/github.com/kballard/go-shellquote/doc.go
new file mode 100644
index 0000000..9445fa4
--- /dev/null
+++ b/vendor/github.com/kballard/go-shellquote/doc.go
@@ -0,0 +1,3 @@
+// Shellquote provides utilities for joining/splitting strings using sh's
+// word-splitting rules.
+package shellquote
diff --git a/vendor/github.com/kballard/go-shellquote/quote.go b/vendor/github.com/kballard/go-shellquote/quote.go
new file mode 100644
index 0000000..72a8cb3
--- /dev/null
+++ b/vendor/github.com/kballard/go-shellquote/quote.go
@@ -0,0 +1,102 @@
+package shellquote
+
+import (
+ "bytes"
+ "strings"
+ "unicode/utf8"
+)
+
+// Join quotes each argument and joins them with a space.
+// If passed to /bin/sh, the resulting string will be split back into the
+// original arguments.
+func Join(args ...string) string {
+ var buf bytes.Buffer
+ for i, arg := range args {
+ if i != 0 {
+ buf.WriteByte(' ')
+ }
+ quote(arg, &buf)
+ }
+ return buf.String()
+}
+
+const (
+ specialChars = "\\'\"`${[|&;<>()*?!"
+ extraSpecialChars = " \t\n"
+ prefixChars = "~"
+)
+
+func quote(word string, buf *bytes.Buffer) {
+ // We want to try to produce a "nice" output. As such, we will
+ // backslash-escape most characters, but if we encounter a space, or if we
+ // encounter an extra-special char (which doesn't work with
+ // backslash-escaping) we switch over to quoting the whole word. We do this
+ // with a space because it's typically easier for people to read multi-word
+ // arguments when quoted with a space rather than with ugly backslashes
+ // everywhere.
+ origLen := buf.Len()
+
+ if len(word) == 0 {
+ // oops, no content
+ buf.WriteString("''")
+ return
+ }
+
+ cur, prev := word, word
+ atStart := true
+ for len(cur) > 0 {
+ c, l := utf8.DecodeRuneInString(cur)
+ cur = cur[l:]
+ if strings.ContainsRune(specialChars, c) || (atStart && strings.ContainsRune(prefixChars, c)) {
+ // copy the non-special chars up to this point
+ if len(cur) < len(prev) {
+ buf.WriteString(prev[0 : len(prev)-len(cur)-l])
+ }
+ buf.WriteByte('\\')
+ buf.WriteRune(c)
+ prev = cur
+ } else if strings.ContainsRune(extraSpecialChars, c) {
+ // start over in quote mode
+ buf.Truncate(origLen)
+ goto quote
+ }
+ atStart = false
+ }
+ if len(prev) > 0 {
+ buf.WriteString(prev)
+ }
+ return
+
+quote:
+ // quote mode
+ // Use single-quotes, but if we find a single-quote in the word, we need
+ // to terminate the string, emit an escaped quote, and start the string up
+ // again
+ inQuote := false
+ for len(word) > 0 {
+ i := strings.IndexRune(word, '\'')
+ if i == -1 {
+ break
+ }
+ if i > 0 {
+ if !inQuote {
+ buf.WriteByte('\'')
+ inQuote = true
+ }
+ buf.WriteString(word[0:i])
+ }
+ word = word[i+1:]
+ if inQuote {
+ buf.WriteByte('\'')
+ inQuote = false
+ }
+ buf.WriteString("\\'")
+ }
+ if len(word) > 0 {
+ if !inQuote {
+ buf.WriteByte('\'')
+ }
+ buf.WriteString(word)
+ buf.WriteByte('\'')
+ }
+}
diff --git a/vendor/github.com/kballard/go-shellquote/unquote.go b/vendor/github.com/kballard/go-shellquote/unquote.go
new file mode 100644
index 0000000..b1b13da
--- /dev/null
+++ b/vendor/github.com/kballard/go-shellquote/unquote.go
@@ -0,0 +1,156 @@
+package shellquote
+
+import (
+ "bytes"
+ "errors"
+ "strings"
+ "unicode/utf8"
+)
+
+var (
+ UnterminatedSingleQuoteError = errors.New("Unterminated single-quoted string")
+ UnterminatedDoubleQuoteError = errors.New("Unterminated double-quoted string")
+ UnterminatedEscapeError = errors.New("Unterminated backslash-escape")
+)
+
+var (
+ splitChars = " \n\t"
+ singleChar = '\''
+ doubleChar = '"'
+ escapeChar = '\\'
+ doubleEscapeChars = "$`\"\n\\"
+)
+
+// Split splits a string according to /bin/sh's word-splitting rules. It
+// supports backslash-escapes, single-quotes, and double-quotes. Notably it does
+// not support the $'' style of quoting. It also doesn't attempt to perform any
+// other sort of expansion, including brace expansion, shell expansion, or
+// pathname expansion.
+//
+// If the given input has an unterminated quoted string or ends in a
+// backslash-escape, one of UnterminatedSingleQuoteError,
+// UnterminatedDoubleQuoteError, or UnterminatedEscapeError is returned.
+func Split(input string) (words []string, err error) {
+ var buf bytes.Buffer
+ words = make([]string, 0)
+
+ for len(input) > 0 {
+ // skip any splitChars at the start
+ c, l := utf8.DecodeRuneInString(input)
+ if strings.ContainsRune(splitChars, c) {
+ input = input[l:]
+ continue
+ } else if c == escapeChar {
+ // Look ahead for escaped newline so we can skip over it
+ next := input[l:]
+ if len(next) == 0 {
+ err = UnterminatedEscapeError
+ return
+ }
+ c2, l2 := utf8.DecodeRuneInString(next)
+ if c2 == '\n' {
+ input = next[l2:]
+ continue
+ }
+ }
+
+ var word string
+ word, input, err = splitWord(input, &buf)
+ if err != nil {
+ return
+ }
+ words = append(words, word)
+ }
+ return
+}
+
+func splitWord(input string, buf *bytes.Buffer) (word string, remainder string, err error) {
+ buf.Reset()
+
+raw:
+ {
+ cur := input
+ for len(cur) > 0 {
+ c, l := utf8.DecodeRuneInString(cur)
+ cur = cur[l:]
+ if c == singleChar {
+ buf.WriteString(input[0 : len(input)-len(cur)-l])
+ input = cur
+ goto single
+ } else if c == doubleChar {
+ buf.WriteString(input[0 : len(input)-len(cur)-l])
+ input = cur
+ goto double
+ } else if c == escapeChar {
+ buf.WriteString(input[0 : len(input)-len(cur)-l])
+ input = cur
+ goto escape
+ } else if strings.ContainsRune(splitChars, c) {
+ buf.WriteString(input[0 : len(input)-len(cur)-l])
+ return buf.String(), cur, nil
+ }
+ }
+ if len(input) > 0 {
+ buf.WriteString(input)
+ input = ""
+ }
+ goto done
+ }
+
+escape:
+ {
+ if len(input) == 0 {
+ return "", "", UnterminatedEscapeError
+ }
+ c, l := utf8.DecodeRuneInString(input)
+ if c == '\n' {
+ // a backslash-escaped newline is elided from the output entirely
+ } else {
+ buf.WriteString(input[:l])
+ }
+ input = input[l:]
+ }
+ goto raw
+
+single:
+ {
+ i := strings.IndexRune(input, singleChar)
+ if i == -1 {
+ return "", "", UnterminatedSingleQuoteError
+ }
+ buf.WriteString(input[0:i])
+ input = input[i+1:]
+ goto raw
+ }
+
+double:
+ {
+ cur := input
+ for len(cur) > 0 {
+ c, l := utf8.DecodeRuneInString(cur)
+ cur = cur[l:]
+ if c == doubleChar {
+ buf.WriteString(input[0 : len(input)-len(cur)-l])
+ input = cur
+ goto raw
+ } else if c == escapeChar {
+ // bash only supports certain escapes in double-quoted strings
+ c2, l2 := utf8.DecodeRuneInString(cur)
+ cur = cur[l2:]
+ if strings.ContainsRune(doubleEscapeChars, c2) {
+ buf.WriteString(input[0 : len(input)-len(cur)-l-l2])
+ if c2 == '\n' {
+ // newline is special, skip the backslash entirely
+ } else {
+ buf.WriteRune(c2)
+ }
+ input = cur
+ }
+ }
+ }
+ return "", "", UnterminatedDoubleQuoteError
+ }
+
+done:
+ return buf.String(), input, nil
+}
diff --git a/vendor/github.com/tmc/scp/LICENSE b/vendor/github.com/tmc/scp/LICENSE
new file mode 100644
index 0000000..a7fe777
--- /dev/null
+++ b/vendor/github.com/tmc/scp/LICENSE
@@ -0,0 +1,14 @@
+Copyright (c) 2014, Travis Cline <travis.cline@gmail.com>
+
+Permission to use, copy, modify, and/or distribute this software for any purpose
+with or without fee is hereby granted, provided that the above copyright notice
+and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
+REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
+INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
+OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
+THIS SOFTWARE.
+
diff --git a/vendor/github.com/tmc/scp/README.md b/vendor/github.com/tmc/scp/README.md
new file mode 100644
index 0000000..bdce886
--- /dev/null
+++ b/vendor/github.com/tmc/scp/README.md
@@ -0,0 +1,15 @@
+# scp
+ import "github.com/tmc/scp"
+
+Package scp provides a simple interface to copying files over a
+go.crypto/ssh session.
+
+## func Copy
+``` go
+func Copy(size int64, mode os.FileMode, fileName string, contents io.Reader, destinationPath string, session *ssh.Session) error
+```
+
+## func CopyPath
+``` go
+func CopyPath(filePath, destinationPath string, session *ssh.Session) error
+```
diff --git a/vendor/github.com/tmc/scp/scp.go b/vendor/github.com/tmc/scp/scp.go
new file mode 100644
index 0000000..7995e7f
--- /dev/null
+++ b/vendor/github.com/tmc/scp/scp.go
@@ -0,0 +1,59 @@
+// Package scp provides a simple interface to copying files over a
+// go.crypto/ssh session.
+package scp
+
+import (
+ "fmt"
+ "io"
+ "os"
+ "path"
+
+ shellquote "github.com/kballard/go-shellquote"
+
+ "golang.org/x/crypto/ssh"
+)
+
+func Copy(size int64, mode os.FileMode, fileName string, contents io.Reader, destinationPath string, session *ssh.Session) error {
+ return copy(size, mode, fileName, contents, destinationPath, session)
+}
+
+func CopyPath(filePath, destinationPath string, session *ssh.Session) error {
+ f, err := os.Open(filePath)
+ if err != nil {
+ return err
+ }
+ defer f.Close()
+ s, err := f.Stat()
+ if err != nil {
+ return err
+ }
+ return copy(s.Size(), s.Mode().Perm(), path.Base(filePath), f, destinationPath, session)
+}
+
+func copy(size int64, mode os.FileMode, fileName string, contents io.Reader, destination string, session *ssh.Session) error {
+ defer session.Close()
+ w, err := session.StdinPipe()
+
+ if err != nil {
+ return err
+ }
+
+ cmd := shellquote.Join("scp", "-t", destination)
+ if err := session.Start(cmd); err != nil {
+ w.Close()
+ return err
+ }
+
+ errors := make(chan error)
+
+ go func() {
+ errors <- session.Wait()
+ }()
+
+ fmt.Fprintf(w, "C%#o %d %s\n", mode, size, fileName)
+ io.Copy(w, contents)
+ fmt.Fprint(w, "\x00")
+ w.Close()
+
+ return <-errors
+}
diff --git a/vendor/modules.txt b/vendor/modules.txt
index cbca569..5ce1ef6 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -61,6 +61,8 @@ github.com/joho/godotenv
github.com/joho/godotenv/autoload
# github.com/kardianos/osext v0.0.0-20170510131534-ae77be60afb1
github.com/kardianos/osext
+# github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51
+github.com/kballard/go-shellquote
# github.com/klauspost/cpuid v0.0.0-20180405133222-e7e905edc00e
github.com/klauspost/cpuid
# github.com/klauspost/crc32 v0.0.0-20170628072449-bab58d77464a
@@ -91,6 +93,8 @@ github.com/ssor/bom
github.com/streamrail/concurrent-map
# github.com/technoweenie/multipartstreamer v1.0.1
github.com/technoweenie/multipartstreamer
+# github.com/tmc/scp v0.0.0-20170824174625-f7b48647feef
+github.com/tmc/scp
# github.com/xtaci/kcp-go v2.0.3+incompatible
github.com/xtaci/kcp-go
# github.com/xtaci/smux v1.0.7
@@ -101,11 +105,15 @@ go4.org/legal
golang.org/x/build/version
golang.org/x/build/envutil
# golang.org/x/crypto v0.0.0-20181001203147-e3636079e1a4
+golang.org/x/crypto/ssh
+golang.org/x/crypto/ssh/agent
golang.org/x/crypto/acme/autocert
golang.org/x/crypto/nacl/secretbox
+golang.org/x/crypto/curve25519
+golang.org/x/crypto/ed25519
+golang.org/x/crypto/internal/chacha20
+golang.org/x/crypto/poly1305
golang.org/x/crypto/acme
-golang.org/x/crypto/ssh
-golang.org/x/crypto/ssh/agent
golang.org/x/crypto/blowfish
golang.org/x/crypto/cast5
golang.org/x/crypto/pbkdf2
@@ -114,11 +122,7 @@ golang.org/x/crypto/tea
golang.org/x/crypto/twofish
golang.org/x/crypto/xtea
golang.org/x/crypto/internal/subtle
-golang.org/x/crypto/poly1305
golang.org/x/crypto/salsa20/salsa
-golang.org/x/crypto/curve25519
-golang.org/x/crypto/ed25519
-golang.org/x/crypto/internal/chacha20
golang.org/x/crypto/ed25519/internal/edwards25519
# golang.org/x/image v0.0.0-20180926015637-991ec62608f3
golang.org/x/image/math/fixed