diff options
| author | Christine Dodrill <me@christine.website> | 2018-10-05 14:03:55 -0700 |
|---|---|---|
| committer | Christine Dodrill <me@christine.website> | 2018-10-05 14:31:22 -0700 |
| commit | c63e73391d634bdb25b3df1c582bb56b6d9a0963 (patch) | |
| tree | 81ec642a36c4ca84b3d0d4dfd8d2a91d09f762cd | |
| parent | dbeba1e5c5c0bc534a515eb298ee4f1d49df4d20 (diff) | |
| download | x-c63e73391d634bdb25b3df1c582bb56b6d9a0963.tar.xz x-c63e73391d634bdb25b3df1c582bb56b6d9a0963.zip | |
mastodon/sona-pi-toki-pona: build and deploy in go, not shell
| -rw-r--r-- | go.mod | 2 | ||||
| -rw-r--r-- | go.sum | 4 | ||||
| -rw-r--r-- | internal/greedo/doc.go | 2 | ||||
| -rw-r--r-- | internal/greedo/greedo.go | 85 | ||||
| -rw-r--r-- | internal/greedo/greedo_test.go | 11 | ||||
| -rw-r--r-- | internal/internal.go | 40 | ||||
| -rw-r--r-- | internal/minipaas/doc.go | 2 | ||||
| -rw-r--r-- | internal/minipaas/minipaas.go | 40 | ||||
| -rw-r--r-- | mastodon/sona-pi-toki-pona/build.go | 54 | ||||
| -rwxr-xr-x | mastodon/sona-pi-toki-pona/build.sh | 7 | ||||
| -rw-r--r-- | tools/appsluggr/main.go | 4 | ||||
| -rw-r--r-- | tools/minipaas/main.go | 34 | ||||
| -rw-r--r-- | vendor/github.com/kballard/go-shellquote/LICENSE | 19 | ||||
| -rw-r--r-- | vendor/github.com/kballard/go-shellquote/README | 36 | ||||
| -rw-r--r-- | vendor/github.com/kballard/go-shellquote/doc.go | 3 | ||||
| -rw-r--r-- | vendor/github.com/kballard/go-shellquote/quote.go | 102 | ||||
| -rw-r--r-- | vendor/github.com/kballard/go-shellquote/unquote.go | 156 | ||||
| -rw-r--r-- | vendor/github.com/tmc/scp/LICENSE | 14 | ||||
| -rw-r--r-- | vendor/github.com/tmc/scp/README.md | 15 | ||||
| -rw-r--r-- | vendor/github.com/tmc/scp/scp.go | 59 | ||||
| -rw-r--r-- | vendor/modules.txt | 16 |
21 files changed, 692 insertions, 13 deletions
@@ -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 @@ -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 |
