cmd/construct: start work on eclier frontend

This commit is contained in:
Cadey Ratio 2018-01-21 20:26:17 -08:00
parent a6fce981ef
commit 18a2049013
415 changed files with 88902 additions and 56 deletions

204
Gopkg.lock generated
View File

@ -1,6 +1,18 @@
# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
[[projects]]
branch = "master"
name = "github.com/ThomasRooney/gexpect"
packages = ["."]
revision = "5482f03509440585d13d8f648989e05903001842"
[[projects]]
branch = "master"
name = "github.com/Xe/eclier"
packages = ["."]
revision = "b586327df9d5a5e5023fa1338f44941745136d68"
[[projects]]
branch = "master"
name = "github.com/Xe/gopreload"
@ -22,6 +34,15 @@
packages = ["."]
revision = "62b230097e9c9534ca2074782b25d738c4b68964"
[[projects]]
branch = "master"
name = "github.com/Xe/x"
packages = [
"tools/glue/libs/gluaexpect",
"tools/glue/libs/gluasimplebox"
]
revision = "860ea0dedb8beb93b60717510eabca2ef5ffe150"
[[projects]]
branch = "master"
name = "github.com/aclements/go-moremath"
@ -43,6 +64,12 @@
revision = "5f10fee965225ac1eecdc234c09daf5cd9e7f7b6"
version = "v1.2.1"
[[projects]]
branch = "master"
name = "github.com/ailncode/gluaxmlpath"
packages = ["."]
revision = "6ce478ecb4a60c4fc8929838e0b21b7fb7ca7440"
[[projects]]
branch = "master"
name = "github.com/alecthomas/template"
@ -160,6 +187,18 @@
revision = "7cd7992b3bc86f920394f8de92c13900da1a46b7"
version = "v3.2.0"
[[projects]]
branch = "master"
name = "github.com/cjoudrey/gluahttp"
packages = ["."]
revision = "b4bfe0c50fea948dcbf3966e120996d6607bbd89"
[[projects]]
branch = "master"
name = "github.com/cjoudrey/gluaurl"
packages = ["."]
revision = "31cbb9bef199454415879f2e6d609d1136d60cad"
[[projects]]
name = "github.com/coreos/bbolt"
packages = ["."]
@ -354,6 +393,12 @@
packages = ["."]
revision = "683f49123a33db61abfb241b7ac5e4af4dc54d55"
[[projects]]
branch = "master"
name = "github.com/howeyc/gopass"
packages = ["."]
revision = "bf9dde6d0d2c004a008c27aaee91170c786f6db8"
[[projects]]
name = "github.com/jmespath/go-jmespath"
packages = ["."]
@ -380,6 +425,12 @@
packages = ["."]
revision = "ae77be60afb1dcacde03767a8c37337fad28ac14"
[[projects]]
branch = "master"
name = "github.com/kballard/go-shellquote"
packages = ["."]
revision = "cd60e84ee657ff3dc51de0b4f55dd299a3e136f2"
[[projects]]
name = "github.com/klauspost/cpuid"
packages = ["."]
@ -392,27 +443,66 @@
revision = "6bb6130ff6a76a904c1841707d65603aec9cc288"
version = "v1.6"
[[projects]]
branch = "master"
name = "github.com/kohkimakimoto/gluaenv"
packages = ["."]
revision = "2888db6bbe38923d59c42e443895875cc8ce0820"
[[projects]]
branch = "master"
name = "github.com/kohkimakimoto/gluafs"
packages = ["."]
revision = "01391ed2d7ab89dc80157605b073403f960aa223"
[[projects]]
branch = "master"
name = "github.com/kohkimakimoto/gluaquestion"
packages = ["."]
revision = "311437c29ba54d027ad2af383661725ae2bfdcdc"
[[projects]]
branch = "master"
name = "github.com/kohkimakimoto/gluassh"
packages = ["."]
revision = "2a7bd48d7568de8230c87ac1ef4a4c481e45814d"
[[projects]]
branch = "master"
name = "github.com/kohkimakimoto/gluatemplate"
packages = ["."]
revision = "d9e2c9d6b00f069a9da377a9ac529c827c1c7d71"
[[projects]]
branch = "master"
name = "github.com/kohkimakimoto/gluayaml"
packages = ["."]
revision = "6fe413d49d73d785510ecf1529991ab0573e96c7"
[[projects]]
branch = "master"
name = "github.com/kr/fs"
packages = ["."]
revision = "2788f0dbd16903de03cb8186e5c7d97b69ad387b"
[[projects]]
branch = "master"
name = "github.com/kr/pretty"
packages = ["."]
revision = "cfb55aafdaf3ec08f0db22699ab822c50091b1c4"
[[projects]]
name = "github.com/kr/pty"
packages = ["."]
revision = "282ce0e5322c82529687d609ee670fac7c7d917c"
version = "v1.1.1"
[[projects]]
branch = "master"
name = "github.com/kr/text"
packages = ["."]
revision = "7cafcd837844e784b526369c9bce262804aebc60"
[[projects]]
branch = "master"
name = "github.com/lib/pq"
packages = [
".",
"oid"
]
revision = "27ea5d92de30060e7121ddd543fe14e9a327e0cc"
[[projects]]
branch = "master"
name = "github.com/lucas-clemente/aes12"
@ -463,18 +553,6 @@
revision = "ab3ca2f6f85577d7ec82e0a6df721147a2e737f9"
version = "v2.0.1"
[[projects]]
name = "github.com/mattes/migrate"
packages = [
".",
"database",
"database/postgres",
"source",
"source/go-bindata"
]
revision = "035c07716cd373d88456ec4d701402df52584cb4"
version = "v3.0.1"
[[projects]]
name = "github.com/mattn/go-isatty"
packages = ["."]
@ -559,12 +637,30 @@
packages = ["."]
revision = "96aac992fc8b1a4c83841a6c3e7178d20d989625"
[[projects]]
branch = "master"
name = "github.com/otm/gluaflag"
packages = ["."]
revision = "078088de689148194436293886e8e39809167332"
[[projects]]
branch = "master"
name = "github.com/otm/gluash"
packages = ["."]
revision = "e145c563986f0b91f740a758a84bca46c163aec7"
[[projects]]
name = "github.com/pkg/errors"
packages = ["."]
revision = "645ef00459ed84a119197bfb8d8205042c6df63d"
version = "v0.8.0"
[[projects]]
name = "github.com/pkg/sftp"
packages = ["."]
revision = "f6a9258a0f570c3a76681b897b6ded57cb0dfa88"
version = "1.2.0"
[[projects]]
name = "github.com/posener/complete"
packages = [
@ -639,6 +735,35 @@
revision = "ebec7ef2574b42a7088cd7751176483e0a27d458"
version = "v1.0.6"
[[projects]]
branch = "master"
name = "github.com/yookoala/realpath"
packages = ["."]
revision = "d19ef9c409d9817c1e685775e53d361b03eabbc8"
[[projects]]
branch = "master"
name = "github.com/yuin/gluamapper"
packages = ["."]
revision = "d836955830e75240d46ce9f0e6d148d94f2e1d3a"
[[projects]]
branch = "master"
name = "github.com/yuin/gluare"
packages = ["."]
revision = "d7c94f1a80ede93a621ed100866e6d4745ca8c22"
[[projects]]
branch = "master"
name = "github.com/yuin/gopher-lua"
packages = [
".",
"ast",
"parse",
"pm"
]
revision = "7d7bc8747e3f614c5c587729a341fe7d8903cdb8"
[[projects]]
branch = "master"
name = "github.com/zclconf/go-cty"
@ -669,7 +794,10 @@
"blowfish",
"cast5",
"curve25519",
"ed25519",
"ed25519/internal/edwards25519",
"hkdf",
"internal/chacha20",
"nacl/secretbox",
"openpgp",
"openpgp/armor",
@ -681,6 +809,9 @@
"poly1305",
"salsa20",
"salsa20/salsa",
"ssh",
"ssh/agent",
"ssh/terminal",
"tea",
"twofish",
"xtea"
@ -710,7 +841,10 @@
[[projects]]
branch = "master"
name = "golang.org/x/sys"
packages = ["unix"]
packages = [
"unix",
"windows"
]
revision = "2c42eef0765b9837fbdab12011af7830f55f88f0"
[[projects]]
@ -777,9 +911,33 @@
revision = "947dcec5ba9c011838740e680966fd7087a71d0d"
version = "v2.2.6"
[[projects]]
branch = "v2"
name = "gopkg.in/xmlpath.v2"
packages = ["."]
revision = "860cbeca3ebcc600db0b213c0e83ad6ce91f5739"
[[projects]]
branch = "v2"
name = "gopkg.in/yaml.v2"
packages = ["."]
revision = "d670f9405373e636a5a2765eea47fac0c9bc91a4"
[[projects]]
branch = "master"
name = "layeh.com/gopher-json"
packages = ["."]
revision = "1aab82196e3b418b56866938f28b6a693f2c6b18"
[[projects]]
name = "layeh.com/gopher-luar"
packages = ["."]
revision = "7b2b96926970546e504881ee7364c1127508eb4e"
version = "v1.0.2"
[solve-meta]
analyzer-name = "dep"
analyzer-version = 1
inputs-digest = "8cd1d7d7f5e846cb0b8d6bf78e6a7ecd32c6e24dd18c886ac99eaeb1b3109aff"
inputs-digest = "e0d2f0d7da737ab5517f0ff1c22588a2f835a8f37ef6b67e491ffd6e1e0defc3"
solver-name = "gps-cdcl"
solver-version = 1

104
cmd/construct/main.go Normal file
View File

@ -0,0 +1,104 @@
package main
import (
"context"
"flag"
"log"
"net/http"
"os"
"path/filepath"
"github.com/Xe/eclier"
"github.com/Xe/x/tools/glue/libs/gluaexpect"
"github.com/Xe/x/tools/glue/libs/gluasimplebox"
"github.com/ailncode/gluaxmlpath"
"github.com/cjoudrey/gluahttp"
"github.com/cjoudrey/gluaurl"
"github.com/kohkimakimoto/gluaenv"
"github.com/kohkimakimoto/gluafs"
"github.com/kohkimakimoto/gluaquestion"
"github.com/kohkimakimoto/gluassh"
"github.com/kohkimakimoto/gluatemplate"
"github.com/kohkimakimoto/gluayaml"
homedir "github.com/mitchellh/go-homedir"
"github.com/otm/gluaflag"
"github.com/otm/gluash"
"github.com/yuin/gluare"
lua "github.com/yuin/gopher-lua"
json "layeh.com/gopher-json"
)
var hDir string
var cfgHome *string
var netrcFile *string
func init() {
dir, err := homedir.Dir()
if err != nil {
log.Fatal(err)
}
hDir = dir
cfgHome = flag.String("home", filepath.Join(hDir, ".construct"), "construct's home directory")
netrcFile = flag.String("netrc", filepath.Join(hDir, ".netrc"), "location of netrc file to use for authentication")
}
func main() {
flag.Parse()
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
pluginLoc := filepath.Join(*cfgHome, "plugins")
scriptsLoc := filepath.Join(*cfgHome, "local", "scripts")
os.MkdirAll(pluginLoc, 0755)
os.MkdirAll(scriptsLoc, 0755)
fout, err := os.Create(*netrcFile)
if err != nil {
log.Fatal(err)
}
fout.Close()
opts := []eclier.RouterOption{
eclier.WithGluaCreationHook(preload),
eclier.WithScriptHome(scriptsLoc),
}
err = filepath.Walk(pluginLoc, func(path string, info os.FileInfo, err error) error {
if info.IsDir() {
opts = append(opts, eclier.WithScriptHome(info.Name()))
}
return nil
})
if err != nil {
log.Fatal(err)
}
r, err := eclier.NewRouter(opts...)
if err != nil {
log.Fatal(err)
}
r.Run(ctx, flag.Args())
}
func preload(L *lua.LState) {
L.PreloadModule("re", gluare.Loader)
L.PreloadModule("sh", gluash.Loader)
L.PreloadModule("fs", gluafs.Loader)
L.PreloadModule("env", gluaenv.Loader)
L.PreloadModule("yaml", gluayaml.Loader)
L.PreloadModule("question", gluaquestion.Loader)
L.PreloadModule("ssh", gluassh.Loader)
L.PreloadModule("http", gluahttp.NewHttpModule(&http.Client{}).Loader)
L.PreloadModule("flag", gluaflag.Loader)
L.PreloadModule("template", gluatemplate.Loader)
L.PreloadModule("url", gluaurl.Loader)
gluaexpect.Preload(L)
gluasimplebox.Preload(L)
gluaxmlpath.Preload(L)
json.Preload(L)
}

54
mage.go
View File

@ -14,11 +14,8 @@ import (
"github.com/magefile/mage/mg"
)
var (
wd string
arches []string
bins []string
)
var wd string
var arches []string
func init() {
lwd, err := os.Getwd()
@ -26,15 +23,7 @@ func init() {
wd = lwd
arches = []string{"amd64", "ppc64le", "arm64"}
bins = []string{
"mage",
"route-httpagent",
"route-cli",
"routed",
"route-runmigrations",
"terraform-provider-route",
}
arches = []string{"amd64", "ppc64", "386", "arm", "arm64"}
}
const pkgBase = "git.xeserv.us/xena/route/"
@ -47,7 +36,7 @@ func buildBins(goos, goarch string) {
os.MkdirAll(filepath.Join(d, goos, goarch), 0777)
for _, pkg := range bins {
for _, pkg := range []string{"route-httpagent", "route-cli", "routed", "terraform-provider-route"} {
env := []string{"GOOS=" + goos, "GOARCH=" + goarch}
goBuild(ctx, env, filepath.Join(d, goos, goarch), "cmd/"+pkg)
goInstall(ctx, env, "cmd/"+pkg)
@ -73,12 +62,9 @@ func Docker() {
ver, err := gitTag()
qod.ANE(err)
shouldWork(ctx, nil, wd, "docker", "build", "-t", "xena/route-core", ".")
run := filepath.Join(wd, "run")
shouldWork(ctx, nil, run, "docker", "build", "-t", "xena/routed:"+ver, "-f", "Dockerfile.routed", ".")
shouldWork(ctx, nil, run, "docker", "build", "-t", "xena/route-httpagent:"+ver, "-f", "Dockerfile.agent", ".")
shouldWork(ctx, nil, wd, "docker", "build", "-t", "xena/route-core", "-f", "Dockerfile.core", ".")
shouldWork(ctx, nil, wd, "docker", "build", "-t", "xena/routed:"+ver, "-f", "Dockerfile.routed", ".")
shouldWork(ctx, nil, wd, "docker", "build", "-t", "xena/route-httpagent:"+ver, "-f", "Dockerfile.agent", ".")
}
// Linux builds binaries for linux
@ -102,6 +88,10 @@ func Darwin() {
// Build builds the binaries for route and routed.
func Build() {
buildBins(runtime.GOOS, runtime.GOARCH)
if runtime.GOOS == "linux" {
Plugin()
}
}
// Plugin builds all of the plugins for programs wanting to augment themselves with route.
@ -154,6 +144,13 @@ func Package() {
}
}
// Version is the version as git reports.
func Version() {
ver, err := gitTag()
qod.ANE(err)
qod.Printlnf("route-%s", ver)
}
// Test runs all of the functional and unit tests for the project.
func Test() {
ctx, cancel := context.WithCancel(context.Background())
@ -168,7 +165,7 @@ func Tools(ctx context.Context) {
"github.com/golang/dep/cmd/dep",
"github.com/golang/protobuf/protoc-gen-go",
"github.com/twitchtv/twirp/protoc-gen-twirp",
"github.com/jteeuwen/go-bindata/go-bindata",
"github.com/Xe/twirp-codegens/cmd/protoc-gen-twirp_eclier",
}
for _, t := range tools {
@ -178,26 +175,17 @@ func Tools(ctx context.Context) {
// Generate runs code generators and the like.
func Generate(ctx context.Context) {
protoDir := filepath.Join(wd, "proto")
databaseDir := filepath.Join(wd, "internal", "database", "migrations")
os.Mkdir(filepath.Join(databaseDir, "dmigrations"), 0777)
dir := filepath.Join(wd, "proto")
Tools(ctx)
shouldWork(ctx, nil, protoDir, "sh", "./regen.sh")
shouldWork(ctx, nil, databaseDir, "go-bindata", "-pkg", "dmigrations", "-o", "../dmigrations/bindata.go", ".")
shouldWork(ctx, nil, dir, "sh", "./regen.sh")
}
// Vars shows the various variables that this magefile uses.
func Vars() {
ver, err := gitTag()
qod.ANE(err)
qod.Printlnf("arches:\t%v", arches)
qod.Printlnf("bins:\t%v", bins)
qod.Printlnf("goarch:\t%s", runtime.GOARCH)
qod.Printlnf("goos:\t%s", runtime.GOOS)
qod.Printlnf("wd:\t%s", wd)
qod.Printlnf("ver:\t%s", ver)
}

View File

@ -0,0 +1,31 @@
-- Code generated by protoc-gen-twirp_eclier v5.0.0DO NOT EDIT
-- source: route.proto
script.verb = "backends:kill"
script.help = "Executes method kill on service backends for twirp package xeserv.us.route.backends"
script.author = "machine-generated"
script.version = "v5.0.0"
script.usage = ""
local flag = require "flag"
local svc = require "svc"
local fs = flag.new()
-- flags for BackendId
fs:string("id", "", "value for message arg id")
script.usage = fs:usage()
function run(arg)
if arg[1] == "-help" or arg[1] == "--help" then
print(fs:usage())
return
end
arg[0] = script.verb
local flags = fs:parse(arg)
local resp = svc.backends.kill(flags)
end

View File

@ -0,0 +1,34 @@
-- Code generated by protoc-gen-twirp_eclier v5.0.0DO NOT EDIT
-- source: route.proto
script.verb = "backends:list"
script.help = "Executes method list on service backends for twirp package xeserv.us.route.backends"
script.author = "machine-generated"
script.version = "v5.0.0"
script.usage = ""
local flag = require "flag"
local svc = require "svc"
local fs = flag.new()
-- flags for BackendSelector
fs:string("domain", "", "value for message arg domain")
fs:string("user", "", "value for message arg user")
script.usage = fs:usage()
function run(arg)
if arg[1] == "-help" or arg[1] == "--help" then
print(fs:usage())
return
end
arg[0] = script.verb
local flags = fs:parse(arg)
local resp = svc.backends.list(flags)
print("bs:\t\t" .. tostring(resp.bs))
print("backends:\t\t" .. tostring(resp.backends))
end

View File

@ -0,0 +1,33 @@
-- Code generated by protoc-gen-twirp_eclier v5.0.0DO NOT EDIT
-- source: route.proto
script.verb = "routes:delete"
script.help = "Executes method delete on service routes for twirp package xeserv.us.route.routes"
script.author = "machine-generated"
script.version = "v5.0.0"
script.usage = ""
local flag = require "flag"
local svc = require "svc"
local fs = flag.new()
-- flags for Route
fs:string("id", "", "value for message arg id")
fs:string("creator", "", "value for message arg creator")
fs:string("host", "", "value for message arg host")
script.usage = fs:usage()
function run(arg)
if arg[1] == "-help" or arg[1] == "--help" then
print(fs:usage())
return
end
arg[0] = script.verb
local flags = fs:parse(arg)
local resp = svc.routes.delete(flags)
end

View File

@ -0,0 +1,35 @@
-- Code generated by protoc-gen-twirp_eclier v5.0.0DO NOT EDIT
-- source: route.proto
script.verb = "routes:get"
script.help = "Executes method get on service routes for twirp package xeserv.us.route.routes"
script.author = "machine-generated"
script.version = "v5.0.0"
script.usage = ""
local flag = require "flag"
local svc = require "svc"
local fs = flag.new()
-- flags for GetRouteRequest
fs:string("unused", "", "value for message arg unused")
fs:string("id", "", "value for message arg id")
script.usage = fs:usage()
function run(arg)
if arg[1] == "-help" or arg[1] == "--help" then
print(fs:usage())
return
end
arg[0] = script.verb
local flags = fs:parse(arg)
local resp = svc.routes.get(flags)
print("id:\t\t" .. tostring(resp.id))
print("creator:\t\t" .. tostring(resp.creator))
print("host:\t\t" .. tostring(resp.host))
end

View File

@ -0,0 +1,31 @@
-- Code generated by protoc-gen-twirp_eclier v5.0.0DO NOT EDIT
-- source: route.proto
script.verb = "routes:get_all"
script.help = "Executes method get_all on service routes for twirp package xeserv.us.route.routes"
script.author = "machine-generated"
script.version = "v5.0.0"
script.usage = ""
local flag = require "flag"
local svc = require "svc"
local fs = flag.new()
-- flags for Nil
script.usage = fs:usage()
function run(arg)
if arg[1] == "-help" or arg[1] == "--help" then
print(fs:usage())
return
end
arg[0] = script.verb
local flags = fs:parse(arg)
local resp = svc.routes.get_all(flags)
print("routes:\t\t" .. tostring(resp.routes))
end

View File

@ -0,0 +1,36 @@
-- Code generated by protoc-gen-twirp_eclier v5.0.0DO NOT EDIT
-- source: route.proto
script.verb = "routes:put"
script.help = "Executes method put on service routes for twirp package xeserv.us.route.routes"
script.author = "machine-generated"
script.version = "v5.0.0"
script.usage = ""
local flag = require "flag"
local svc = require "svc"
local fs = flag.new()
-- flags for Route
fs:string("id", "", "value for message arg id")
fs:string("creator", "", "value for message arg creator")
fs:string("host", "", "value for message arg host")
script.usage = fs:usage()
function run(arg)
if arg[1] == "-help" or arg[1] == "--help" then
print(fs:usage())
return
end
arg[0] = script.verb
local flags = fs:parse(arg)
local resp = svc.routes.put(flags)
print("id:\t\t" .. tostring(resp.id))
print("creator:\t\t" .. tostring(resp.creator))
print("host:\t\t" .. tostring(resp.host))
end

View File

@ -0,0 +1,34 @@
-- Code generated by protoc-gen-twirp_eclier v5.0.0DO NOT EDIT
-- source: route.proto
script.verb = "tokens:deactivate"
script.help = "Executes method deactivate on service tokens for twirp package xeserv.us.route.tokens"
script.author = "machine-generated"
script.version = "v5.0.0"
script.usage = ""
local flag = require "flag"
local svc = require "svc"
local fs = flag.new()
-- flags for Token
fs:string("id", "", "value for message arg id")
fs:string("body", "", "value for message arg body")
fs:strings("scopes", "", "value for message arg scopes")
fs:bool("active", "", "value for message arg active")
script.usage = fs:usage()
function run(arg)
if arg[1] == "-help" or arg[1] == "--help" then
print(fs:usage())
return
end
arg[0] = script.verb
local flags = fs:parse(arg)
local resp = svc.tokens.deactivate(flags)
end

View File

@ -0,0 +1,34 @@
-- Code generated by protoc-gen-twirp_eclier v5.0.0DO NOT EDIT
-- source: route.proto
script.verb = "tokens:delete"
script.help = "Executes method delete on service tokens for twirp package xeserv.us.route.tokens"
script.author = "machine-generated"
script.version = "v5.0.0"
script.usage = ""
local flag = require "flag"
local svc = require "svc"
local fs = flag.new()
-- flags for Token
fs:string("id", "", "value for message arg id")
fs:string("body", "", "value for message arg body")
fs:strings("scopes", "", "value for message arg scopes")
fs:bool("active", "", "value for message arg active")
script.usage = fs:usage()
function run(arg)
if arg[1] == "-help" or arg[1] == "--help" then
print(fs:usage())
return
end
arg[0] = script.verb
local flags = fs:parse(arg)
local resp = svc.tokens.delete(flags)
end

View File

@ -0,0 +1,36 @@
-- Code generated by protoc-gen-twirp_eclier v5.0.0DO NOT EDIT
-- source: route.proto
script.verb = "tokens:get"
script.help = "Executes method get on service tokens for twirp package xeserv.us.route.tokens"
script.author = "machine-generated"
script.version = "v5.0.0"
script.usage = ""
local flag = require "flag"
local svc = require "svc"
local fs = flag.new()
-- flags for GetTokenRequest
fs:string("token", "", "value for message arg token")
fs:string("id", "", "value for message arg id")
script.usage = fs:usage()
function run(arg)
if arg[1] == "-help" or arg[1] == "--help" then
print(fs:usage())
return
end
arg[0] = script.verb
local flags = fs:parse(arg)
local resp = svc.tokens.get(flags)
print("id:\t\t" .. tostring(resp.id))
print("body:\t\t" .. tostring(resp.body))
print("scopes:\t\t" .. tostring(resp.scopes))
print("active:\t\t" .. tostring(resp.active))
end

View File

@ -0,0 +1,31 @@
-- Code generated by protoc-gen-twirp_eclier v5.0.0DO NOT EDIT
-- source: route.proto
script.verb = "tokens:get_all"
script.help = "Executes method get_all on service tokens for twirp package xeserv.us.route.tokens"
script.author = "machine-generated"
script.version = "v5.0.0"
script.usage = ""
local flag = require "flag"
local svc = require "svc"
local fs = flag.new()
-- flags for Nil
script.usage = fs:usage()
function run(arg)
if arg[1] == "-help" or arg[1] == "--help" then
print(fs:usage())
return
end
arg[0] = script.verb
local flags = fs:parse(arg)
local resp = svc.tokens.get_all(flags)
print("tokens:\t\t" .. tostring(resp.tokens))
end

View File

@ -0,0 +1,38 @@
-- Code generated by protoc-gen-twirp_eclier v5.0.0DO NOT EDIT
-- source: route.proto
script.verb = "tokens:put"
script.help = "Executes method put on service tokens for twirp package xeserv.us.route.tokens"
script.author = "machine-generated"
script.version = "v5.0.0"
script.usage = ""
local flag = require "flag"
local svc = require "svc"
local fs = flag.new()
-- flags for Token
fs:string("id", "", "value for message arg id")
fs:string("body", "", "value for message arg body")
fs:strings("scopes", "", "value for message arg scopes")
fs:bool("active", "", "value for message arg active")
script.usage = fs:usage()
function run(arg)
if arg[1] == "-help" or arg[1] == "--help" then
print(fs:usage())
return
end
arg[0] = script.verb
local flags = fs:parse(arg)
local resp = svc.tokens.put(flags)
print("id:\t\t" .. tostring(resp.id))
print("body:\t\t" .. tostring(resp.body))
print("scopes:\t\t" .. tostring(resp.scopes))
print("active:\t\t" .. tostring(resp.active))
end

View File

@ -3,4 +3,5 @@
protoc -I. \
--go_out=:. \
--twirp_out=. \
--twirp_eclier_out=./eclier \
route.proto

7
vendor/github.com/ThomasRooney/gexpect/LICENCE generated vendored Normal file
View File

@ -0,0 +1,7 @@
Copyright (C) 2014 Thomas Rooney
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.

64
vendor/github.com/ThomasRooney/gexpect/README.md generated vendored Normal file
View File

@ -0,0 +1,64 @@
# Gexpect
Gexpect is a pure golang expect-like module.
It makes it simpler to create and control other terminal applications.
child, err := gexpect.Spawn("python")
if err != nil {
panic(err)
}
child.Expect(">>>")
child.SendLine("print 'Hello World'")
child.Interact()
child.Close()
## Examples
`Spawn` handles the argument parsing from a string
child.Spawn("/bin/sh -c 'echo \"my complicated command\" | tee log | cat > log2'")
child.ReadLine() // ReadLine() (string, error)
child.ReadUntil(' ') // ReadUntil(delim byte) ([]byte, error)
`ReadLine`, `ReadUntil` and `SendLine` send strings from/to `stdout/stdin` respectively
child, _ := gexpect.Spawn("cat")
child.SendLine("echoing process_stdin") // SendLine(command string) (error)
msg, _ := child.ReadLine() // msg = echoing process_stdin
`Wait` and `Close` allow for graceful and ungraceful termination.
child.Wait() // Waits until the child terminates naturally.
child.Close() // Sends a kill command
`AsyncInteractChannels` spawns two go routines to pipe into and from `stdout`/`stdin`, allowing for some usecases to be a little simpler.
child, _ := gexpect.Spawn("sh")
sender, receiver := child.AsyncInteractChannels()
sender <- "echo Hello World\n" // Send to stdin
line, open := <- receiver // Recieve a line from stdout/stderr
// When the subprocess stops (e.g. with child.Close()) , receiver is closed
if open {
fmt.Printf("Received %s", line)
}
`ExpectRegex` uses golang's internal regex engine to wait until a match from the process with the given regular expression (or an error on process termination with no match).
child, _ := gexpect.Spawn("echo accb")
match, _ := child.ExpectRegex("a..b")
// (match=true)
`ExpectRegexFind` allows for groups to be extracted from process stdout. The first element is an array of containing the total matched text, followed by each subexpression group match.
child, _ := gexpect.Spawn("echo 123 456 789")
result, _ := child.ExpectRegexFind("\d+ (\d+) (\d+)")
// result = []string{"123 456 789", "456", "789"}
See `gexpect_test.go` and the `examples` folder for full syntax
## Credits
github.com/kballard/go-shellquote
github.com/kr/pty
KMP Algorithm: "http://blog.databigbang.com/searching-for-substrings-in-streams-a-slight-modification-of-the-knuth-morris-pratt-algorithm-in-haxe/"

449
vendor/github.com/ThomasRooney/gexpect/gexpect.go generated vendored Normal file
View File

@ -0,0 +1,449 @@
// +build !windows
package gexpect
import (
"bytes"
"errors"
"fmt"
"io"
"os"
"os/exec"
"regexp"
"time"
"unicode/utf8"
shell "github.com/kballard/go-shellquote"
"github.com/kr/pty"
)
var (
ErrEmptySearch = errors.New("empty search string")
)
type ExpectSubprocess struct {
Cmd *exec.Cmd
buf *buffer
outputBuffer []byte
}
type buffer struct {
f *os.File
b bytes.Buffer
collect bool
collection bytes.Buffer
}
func (buf *buffer) StartCollecting() {
buf.collect = true
}
func (buf *buffer) StopCollecting() (result string) {
result = string(buf.collection.Bytes())
buf.collect = false
buf.collection.Reset()
return result
}
func (buf *buffer) Read(chunk []byte) (int, error) {
nread := 0
if buf.b.Len() > 0 {
n, err := buf.b.Read(chunk)
if err != nil {
return n, err
}
if n == len(chunk) {
return n, nil
}
nread = n
}
fn, err := buf.f.Read(chunk[nread:])
return fn + nread, err
}
func (buf *buffer) ReadRune() (r rune, size int, err error) {
l := buf.b.Len()
chunk := make([]byte, utf8.UTFMax)
if l > 0 {
n, err := buf.b.Read(chunk)
if err != nil {
return 0, 0, err
}
if utf8.FullRune(chunk[:n]) {
r, rL := utf8.DecodeRune(chunk)
if n > rL {
buf.PutBack(chunk[rL:n])
}
if buf.collect {
buf.collection.WriteRune(r)
}
return r, rL, nil
}
}
// else add bytes from the file, then try that
for l < utf8.UTFMax {
fn, err := buf.f.Read(chunk[l : l+1])
if err != nil {
return 0, 0, err
}
l = l + fn
if utf8.FullRune(chunk[:l]) {
r, rL := utf8.DecodeRune(chunk)
if buf.collect {
buf.collection.WriteRune(r)
}
return r, rL, nil
}
}
return 0, 0, errors.New("File is not a valid UTF=8 encoding")
}
func (buf *buffer) PutBack(chunk []byte) {
if len(chunk) == 0 {
return
}
if buf.b.Len() == 0 {
buf.b.Write(chunk)
return
}
d := make([]byte, 0, len(chunk)+buf.b.Len())
d = append(d, chunk...)
d = append(d, buf.b.Bytes()...)
buf.b.Reset()
buf.b.Write(d)
}
func SpawnAtDirectory(command string, directory string) (*ExpectSubprocess, error) {
expect, err := _spawn(command)
if err != nil {
return nil, err
}
expect.Cmd.Dir = directory
return _start(expect)
}
func Command(command string) (*ExpectSubprocess, error) {
expect, err := _spawn(command)
if err != nil {
return nil, err
}
return expect, nil
}
func (expect *ExpectSubprocess) Start() error {
_, err := _start(expect)
return err
}
func Spawn(command string) (*ExpectSubprocess, error) {
expect, err := _spawn(command)
if err != nil {
return nil, err
}
return _start(expect)
}
func (expect *ExpectSubprocess) Close() error {
if err := expect.Cmd.Process.Kill(); err != nil {
return err
}
if err := expect.buf.f.Close(); err != nil {
return err
}
return nil
}
func (expect *ExpectSubprocess) AsyncInteractChannels() (send chan string, receive chan string) {
receive = make(chan string)
send = make(chan string)
go func() {
for {
str, err := expect.ReadLine()
if err != nil {
close(receive)
return
}
receive <- str
}
}()
go func() {
for {
select {
case sendCommand, exists := <-send:
{
if !exists {
return
}
err := expect.Send(sendCommand)
if err != nil {
receive <- "gexpect Error: " + err.Error()
return
}
}
}
}
}()
return
}
func (expect *ExpectSubprocess) ExpectRegex(regex string) (bool, error) {
return regexp.MatchReader(regex, expect.buf)
}
func (expect *ExpectSubprocess) expectRegexFind(regex string, output bool) ([]string, string, error) {
re, err := regexp.Compile(regex)
if err != nil {
return nil, "", err
}
expect.buf.StartCollecting()
pairs := re.FindReaderSubmatchIndex(expect.buf)
stringIndexedInto := expect.buf.StopCollecting()
l := len(pairs)
numPairs := l / 2
result := make([]string, numPairs)
for i := 0; i < numPairs; i += 1 {
result[i] = stringIndexedInto[pairs[i*2]:pairs[i*2+1]]
}
// convert indexes to strings
if len(result) == 0 {
err = fmt.Errorf("ExpectRegex didn't find regex '%v'.", regex)
} else {
// The number in pairs[1] is an index of a first
// character outside the whole match
putBackIdx := pairs[1]
if len(stringIndexedInto) > putBackIdx {
stringToPutBack := stringIndexedInto[putBackIdx:]
stringIndexedInto = stringIndexedInto[:putBackIdx]
expect.buf.PutBack([]byte(stringToPutBack))
}
}
return result, stringIndexedInto, err
}
func (expect *ExpectSubprocess) expectTimeoutRegexFind(regex string, timeout time.Duration) (result []string, out string, err error) {
t := make(chan bool)
go func() {
result, out, err = expect.ExpectRegexFindWithOutput(regex)
t <- false
}()
go func() {
time.Sleep(timeout)
err = fmt.Errorf("ExpectRegex timed out after %v finding '%v'.\nOutput:\n%s", timeout, regex, expect.Collect())
t <- true
}()
<-t
return result, out, err
}
func (expect *ExpectSubprocess) ExpectRegexFind(regex string) ([]string, error) {
result, _, err := expect.expectRegexFind(regex, false)
return result, err
}
func (expect *ExpectSubprocess) ExpectTimeoutRegexFind(regex string, timeout time.Duration) ([]string, error) {
result, _, err := expect.expectTimeoutRegexFind(regex, timeout)
return result, err
}
func (expect *ExpectSubprocess) ExpectRegexFindWithOutput(regex string) ([]string, string, error) {
return expect.expectRegexFind(regex, true)
}
func (expect *ExpectSubprocess) ExpectTimeoutRegexFindWithOutput(regex string, timeout time.Duration) ([]string, string, error) {
return expect.expectTimeoutRegexFind(regex, timeout)
}
func buildKMPTable(searchString string) []int {
pos := 2
cnd := 0
length := len(searchString)
var table []int
if length < 2 {
length = 2
}
table = make([]int, length)
table[0] = -1
table[1] = 0
for pos < len(searchString) {
if searchString[pos-1] == searchString[cnd] {
cnd += 1
table[pos] = cnd
pos += 1
} else if cnd > 0 {
cnd = table[cnd]
} else {
table[pos] = 0
pos += 1
}
}
return table
}
func (expect *ExpectSubprocess) ExpectTimeout(searchString string, timeout time.Duration) (e error) {
result := make(chan error)
go func() {
result <- expect.Expect(searchString)
}()
select {
case e = <-result:
case <-time.After(timeout):
e = fmt.Errorf("Expect timed out after %v waiting for '%v'.\nOutput:\n%s", timeout, searchString, expect.Collect())
}
return e
}
func (expect *ExpectSubprocess) Expect(searchString string) (e error) {
target := len(searchString)
if target < 1 {
return ErrEmptySearch
}
chunk := make([]byte, target*2)
if expect.outputBuffer != nil {
expect.outputBuffer = expect.outputBuffer[0:]
}
m := 0
i := 0
// Build KMP Table
table := buildKMPTable(searchString)
for {
n, err := expect.buf.Read(chunk)
if n == 0 && err != nil {
return err
}
if expect.outputBuffer != nil {
expect.outputBuffer = append(expect.outputBuffer, chunk[:n]...)
}
offset := m + i
for m+i-offset < n {
if searchString[i] == chunk[m+i-offset] {
i += 1
if i == target {
unreadIndex := m + i - offset
if len(chunk) > unreadIndex {
expect.buf.PutBack(chunk[unreadIndex:n])
}
return nil
}
} else {
m += i - table[i]
if table[i] > -1 {
i = table[i]
} else {
i = 0
}
}
}
}
}
func (expect *ExpectSubprocess) Send(command string) error {
_, err := io.WriteString(expect.buf.f, command)
return err
}
func (expect *ExpectSubprocess) Capture() {
if expect.outputBuffer == nil {
expect.outputBuffer = make([]byte, 0)
}
}
func (expect *ExpectSubprocess) Collect() []byte {
collectOutput := make([]byte, len(expect.outputBuffer))
copy(collectOutput, expect.outputBuffer)
expect.outputBuffer = nil
return collectOutput
}
func (expect *ExpectSubprocess) SendLine(command string) error {
_, err := io.WriteString(expect.buf.f, command+"\r\n")
return err
}
func (expect *ExpectSubprocess) Interact() {
defer expect.Cmd.Wait()
io.Copy(os.Stdout, &expect.buf.b)
go io.Copy(os.Stdout, expect.buf.f)
go io.Copy(expect.buf.f, os.Stdin)
}
func (expect *ExpectSubprocess) ReadUntil(delim byte) ([]byte, error) {
join := make([]byte, 0, 512)
chunk := make([]byte, 255)
for {
n, err := expect.buf.Read(chunk)
for i := 0; i < n; i++ {
if chunk[i] == delim {
if len(chunk) > i+1 {
expect.buf.PutBack(chunk[i+1:n])
}
return join, nil
} else {
join = append(join, chunk[i])
}
}
if err != nil {
return join, err
}
}
}
func (expect *ExpectSubprocess) Wait() error {
return expect.Cmd.Wait()
}
func (expect *ExpectSubprocess) ReadLine() (string, error) {
str, err := expect.ReadUntil('\n')
return string(str), err
}
func _start(expect *ExpectSubprocess) (*ExpectSubprocess, error) {
f, err := pty.Start(expect.Cmd)
if err != nil {
return nil, err
}
expect.buf.f = f
return expect, nil
}
func _spawn(command string) (*ExpectSubprocess, error) {
wrapper := new(ExpectSubprocess)
wrapper.outputBuffer = nil
splitArgs, err := shell.Split(command)
if err != nil {
return nil, err
}
numArguments := len(splitArgs) - 1
if numArguments < 0 {
return nil, errors.New("gexpect: No command given to spawn")
}
path, err := exec.LookPath(splitArgs[0])
if err != nil {
return nil, err
}
if numArguments >= 1 {
wrapper.Cmd = exec.Command(path, splitArgs[1:]...)
} else {
wrapper.Cmd = exec.Command(path)
}
wrapper.buf = new(buffer)
return wrapper, nil
}

419
vendor/github.com/ThomasRooney/gexpect/gexpect_test.go generated vendored Normal file
View File

@ -0,0 +1,419 @@
// +build !windows
package gexpect
import (
"bytes"
"fmt"
"io/ioutil"
"strings"
"testing"
"time"
)
func TestEmptySearchString(t *testing.T) {
t.Logf("Testing empty search string...")
child, err := Spawn("echo Hello World")
if err != nil {
t.Fatal(err)
}
err = child.Expect("")
if err != ErrEmptySearch {
t.Fatalf("Expected empty search error, got %v", err)
}
}
func TestHelloWorld(t *testing.T) {
t.Logf("Testing Hello World... ")
child, err := Spawn("echo \"Hello World\"")
if err != nil {
t.Fatal(err)
}
err = child.Expect("Hello World")
if err != nil {
t.Fatal(err)
}
}
func TestDoubleHelloWorld(t *testing.T) {
t.Logf("Testing Double Hello World... ")
child, err := Spawn(`sh -c "echo Hello World ; echo Hello ; echo Hi"`)
if err != nil {
t.Fatal(err)
}
err = child.Expect("Hello World")
if err != nil {
t.Fatal(err)
}
err = child.Expect("Hello")
if err != nil {
t.Fatal(err)
}
err = child.Expect("Hi")
if err != nil {
t.Fatal(err)
}
}
func TestHelloWorldFailureCase(t *testing.T) {
t.Logf("Testing Hello World Failure case... ")
child, err := Spawn("echo \"Hello World\"")
if err != nil {
t.Fatal(err)
}
err = child.Expect("YOU WILL NEVER FIND ME")
if err != nil {
return
}
t.Fatal("Expected an error for TestHelloWorldFailureCase")
}
func TestBiChannel(t *testing.T) {
t.Logf("Testing BiChannel screen... ")
child, err := Spawn("cat")
if err != nil {
t.Fatal(err)
}
sender, receiver := child.AsyncInteractChannels()
wait := func(str string) {
for {
msg, open := <-receiver
if !open {
return
}
if strings.Contains(msg, str) {
return
}
}
}
endlChar := fmt.Sprintln("")
sender <- fmt.Sprintf("echo%v", endlChar)
wait("echo")
sender <- fmt.Sprintf("echo2%v", endlChar)
wait("echo2")
child.Close()
child.Wait()
}
func TestCommandStart(t *testing.T) {
t.Logf("Testing Command... ")
// Doing this allows you to modify the cmd struct prior to execution, for example to add environment variables
child, err := Command("echo 'Hello World'")
if err != nil {
t.Fatal(err)
}
child.Start()
child.Expect("Hello World")
}
var regexMatchTests = []struct {
re string
good string
bad string
}{
{`a`, `a`, `b`},
{`.b`, `ab`, `ac`},
{`a+hello`, `aaaahello`, `bhello`},
{`(hello|world)`, `hello`, `unknown`},
{`(hello|world)`, `world`, `unknown`},
{"\u00a9", "\u00a9", `unknown`}, // 2 bytes long unicode character "copyright sign"
}
func TestRegexMatch(t *testing.T) {
t.Logf("Testing Regular Expression Matching... ")
for _, tt := range regexMatchTests {
runTest := func(input string) bool {
var match bool
child, err := Spawn("echo \"" + input + "\"")
if err != nil {
t.Fatal(err)
}
match, err = child.ExpectRegex(tt.re)
if err != nil {
t.Fatal(err)
}
return match
}
if !runTest(tt.good) {
t.Errorf("Regex Not matching [%#q] with pattern [%#q]", tt.good, tt.re)
}
if runTest(tt.bad) {
t.Errorf("Regex Matching [%#q] with pattern [%#q]", tt.bad, tt.re)
}
}
}
var regexFindTests = []struct {
re string
input string
matches []string
}{
{`he(l)lo wo(r)ld`, `hello world`, []string{"hello world", "l", "r"}},
{`(a)`, `a`, []string{"a", "a"}},
{`so.. (hello|world)`, `so.. hello`, []string{"so.. hello", "hello"}},
{`(a+)hello`, `aaaahello`, []string{"aaaahello", "aaaa"}},
{`\d+ (\d+) (\d+)`, `123 456 789`, []string{"123 456 789", "456", "789"}},
{`\d+ (\d+) (\d+)`, "\u00a9 123 456 789 \u00a9", []string{"123 456 789", "456", "789"}}, // check unicode characters
}
func TestRegexFind(t *testing.T) {
t.Logf("Testing Regular Expression Search... ")
for _, tt := range regexFindTests {
runTest := func(input string) []string {
child, err := Spawn("echo \"" + input + "\"")
if err != nil {
t.Fatal(err)
}
matches, err := child.ExpectRegexFind(tt.re)
if err != nil {
t.Fatal(err)
}
return matches
}
matches := runTest(tt.input)
if len(matches) != len(tt.matches) {
t.Fatalf("Regex not producing the expected number of patterns.. got[%d] ([%s]) expected[%d] ([%s])",
len(matches), strings.Join(matches, ","),
len(tt.matches), strings.Join(tt.matches, ","))
}
for i, _ := range matches {
if matches[i] != tt.matches[i] {
t.Errorf("Regex Expected group [%s] and got group [%s] with pattern [%#q] and input [%s]",
tt.matches[i], matches[i], tt.re, tt.input)
}
}
}
}
func TestReadLine(t *testing.T) {
t.Logf("Testing ReadLine...")
child, err := Spawn("echo \"foo\nbar\"")
if err != nil {
t.Fatal(err)
}
s, err := child.ReadLine()
if err != nil {
t.Fatal(err)
}
if s != "foo\r" {
t.Fatalf("expected 'foo\\r', got '%s'", s)
}
s, err = child.ReadLine()
if err != nil {
t.Fatal(err)
}
if s != "bar\r" {
t.Fatalf("expected 'bar\\r', got '%s'", s)
}
}
func TestRegexWithOutput(t *testing.T) {
t.Logf("Testing Regular Expression search with output...")
s := "You will not find me"
p, err := Spawn("echo -n " + s)
if err != nil {
t.Fatalf("Cannot exec rkt: %v", err)
}
searchPattern := `I should not find you`
result, out, err := p.ExpectRegexFindWithOutput(searchPattern)
if err == nil {
t.Fatalf("Shouldn't have found `%v` in `%v`", searchPattern, out)
}
if s != out {
t.Fatalf("Child output didn't match: %s", out)
}
err = p.Wait()
if err != nil {
t.Fatalf("Child didn't terminate correctly: %v", err)
}
p, err = Spawn("echo You will find me")
if err != nil {
t.Fatalf("Cannot exec rkt: %v", err)
}
searchPattern = `.*(You will).*`
result, out, err = p.ExpectRegexFindWithOutput(searchPattern)
if err != nil || result[1] != "You will" {
t.Fatalf("Did not find pattern `%v` in `%v'\n", searchPattern, out)
}
err = p.Wait()
if err != nil {
t.Fatalf("Child didn't terminate correctly: %v", err)
}
}
func TestRegexTimeoutWithOutput(t *testing.T) {
t.Logf("Testing Regular Expression search with timeout and output...")
seconds := 2
timeout := time.Duration(seconds-1) * time.Second
p, err := Spawn(fmt.Sprintf("sh -c 'sleep %d && echo You find me'", seconds))
if err != nil {
t.Fatalf("Cannot exec rkt: %v", err)
}
searchPattern := `find me`
result, out, err := p.ExpectTimeoutRegexFindWithOutput(searchPattern, timeout)
if err == nil {
t.Fatalf("Shouldn't have finished call with result: %v", result)
}
seconds = 2
timeout = time.Duration(seconds+1) * time.Second
p, err = Spawn(fmt.Sprintf("sh -c 'sleep %d && echo You find me'", seconds))
if err != nil {
t.Fatalf("Cannot exec rkt: %v", err)
}
searchPattern = `find me`
result, out, err = p.ExpectTimeoutRegexFindWithOutput(searchPattern, timeout)
if err != nil {
t.Fatalf("Didn't find %v in output: %v", searchPattern, out)
}
}
func TestRegexFindNoExcessBytes(t *testing.T) {
t.Logf("Testing Regular Expressions returning output with no excess strings")
repeats := 50
tests := []struct {
desc string
loopBody string
searchPattern string
expectFullTmpl string
unmatchedData string
}{
{
desc: `matching lines line by line with $ at the end of the regexp`,
loopBody: `echo "prefix: ${i} line"`,
searchPattern: `(?m)^prefix:\s+(\d+) line\s??$`,
expectFullTmpl: `prefix: %d line`,
unmatchedData: "\n",
// the "$" char at the end of regexp does not
// match the \n, so it is left as an unmatched
// data
},
{
desc: `matching lines line by line with \n at the end of the regexp`,
loopBody: `echo "prefix: ${i} line"`,
searchPattern: `(?m)^prefix:\s+(\d+) line\s??\n`,
expectFullTmpl: `prefix: %d line`,
unmatchedData: "",
},
{
desc: `matching chunks in single line chunk by chunk`,
loopBody: `printf "a ${i} b"`,
searchPattern: `a\s+(\d+)\s+b`,
expectFullTmpl: `a %d b`,
unmatchedData: "",
},
}
seqCmd := fmt.Sprintf("`seq 1 %d`", repeats)
shCmdTmpl := fmt.Sprintf(`sh -c 'for i in %s; do %%s; done'`, seqCmd)
for _, tt := range tests {
t.Logf("Test: %s", tt.desc)
shCmd := fmt.Sprintf(shCmdTmpl, tt.loopBody)
t.Logf("Running command: %s", shCmd)
p, err := Spawn(shCmd)
if err != nil {
t.Fatalf("Cannot exec shell script: %v", err)
}
defer func() {
if err := p.Wait(); err != nil {
t.Fatalf("shell script didn't terminate correctly: %v", err)
}
}()
for i := 1; i <= repeats; i++ {
matches, output, err := p.ExpectRegexFindWithOutput(tt.searchPattern)
if err != nil {
t.Fatalf("Failed to get the match number %d: %v", i, err)
}
if len(matches) != 2 {
t.Fatalf("Expected only 2 matches, got %d", len(matches))
}
full := strings.TrimSpace(matches[0])
expFull := fmt.Sprintf(tt.expectFullTmpl, i)
partial := matches[1]
expPartial := fmt.Sprintf("%d", i)
if full != expFull {
t.Fatalf("Did not the expected full match %q, got %q", expFull, full)
}
if partial != expPartial {
t.Fatalf("Did not the expected partial match %q, got %q", expPartial, partial)
}
// The output variable usually contains the
// unmatched data followed by the whole match.
// The first line is special as it has no data
// preceding it.
var expectedOutput string
if i == 1 || tt.unmatchedData == "" {
expectedOutput = matches[0]
} else {
expectedOutput = fmt.Sprintf("%s%s", tt.unmatchedData, matches[0])
}
if output != expectedOutput {
t.Fatalf("The collected output %q should be the same as the whole match %q", output, expectedOutput)
}
}
}
}
func TestBufferReadRune(t *testing.T) {
tests := []struct {
bufferContent []byte
fileContent []byte
expectedRune rune
}{
// unicode "copyright char" is \u00a9 is encoded as two bytes in utf8 0xc2 0xa9
{[]byte{0xc2, 0xa9}, []byte{}, '\u00a9'}, // whole rune is already in buffer.b
{[]byte{0xc2}, []byte{0xa9}, '\u00a9'}, // half of is in the buffer.b and another half still in buffer.f (file)
{[]byte{}, []byte{0xc2, 0xa9}, '\u00a9'}, // whole rune is the file
// some random noise in the end of file
{[]byte{0xc2, 0xa9}, []byte{0x20, 0x20, 0x20, 0x20}, '\u00a9'},
{[]byte{0xc2}, []byte{0xa9, 0x20, 0x20, 0x20, 0x20}, '\u00a9'},
{[]byte{}, []byte{0xc2, 0xa9, 0x20, 0x20, 0x20, 0x20}, '\u00a9'},
}
for i, tt := range tests {
// prepare tmp file with fileContent
f, err := ioutil.TempFile("", "")
if err != nil {
t.Fatal(err)
}
n, err := f.Write(tt.fileContent)
if err != nil {
t.Fatal(err)
}
if n != len(tt.fileContent) {
t.Fatal("expected fileContent written to temp file")
}
_, err = f.Seek(0, 0)
if err != nil {
t.Fatal(err)
}
// new buffer
buf := buffer{f: f, b: *bytes.NewBuffer(tt.bufferContent)}
// call ReadRune
r, size, err := buf.ReadRune()
if r != tt.expectedRune {
t.Fatalf("#%d: expected rune %+q but go is %+q", i, tt.expectedRune, r)
}
if size != len(string(tt.expectedRune)) {
t.Fatalf("#%d: expected rune %d bytes long but got just %d bytes long", i, len(string(tt.expectedRune)), size)
}
}
}

2
vendor/github.com/Xe/eclier/.gitignore generated vendored Normal file
View File

@ -0,0 +1,2 @@
.DS_Store
doc

223
vendor/github.com/Xe/eclier/Gopkg.lock generated vendored Normal file
View File

@ -0,0 +1,223 @@
memo = "b40e77e679fec09015bfda27b7d1fc37f4ba6240cbe95cf9fb88b5c56e40ebdf"
[[projects]]
branch = "master"
name = "github.com/ThomasRooney/gexpect"
packages = ["."]
revision = "5482f03509440585d13d8f648989e05903001842"
[[projects]]
branch = "master"
name = "github.com/Xe/x"
packages = ["tools/glue/libs/gluaexpect","tools/glue/libs/gluasimplebox"]
revision = "d0ebe3970f361daa31a135f1e0c7304eb1442f61"
[[projects]]
branch = "master"
name = "github.com/ailncode/gluaxmlpath"
packages = ["."]
revision = "6ce478ecb4a60c4fc8929838e0b21b7fb7ca7440"
[[projects]]
branch = "master"
name = "github.com/brandur/simplebox"
packages = ["."]
revision = "84e9865bb03ad38c464043bf5382ce8c68ca5f0c"
[[projects]]
branch = "master"
name = "github.com/cjoudrey/gluahttp"
packages = ["."]
revision = "b4bfe0c50fea948dcbf3966e120996d6607bbd89"
[[projects]]
branch = "master"
name = "github.com/cjoudrey/gluaurl"
packages = ["."]
revision = "31cbb9bef199454415879f2e6d609d1136d60cad"
[[projects]]
branch = "master"
name = "github.com/cyberdelia/heroku-go"
packages = ["v3"]
revision = "bb8b6b1e9656ec0728638961f8e8b4211fee735d"
[[projects]]
branch = "master"
name = "github.com/dickeyxxx/netrc"
packages = ["."]
revision = "3acf1b3de25d89c7688c63bb45f6b07f566555ec"
[[projects]]
branch = "master"
name = "github.com/google/go-querystring"
packages = ["query"]
revision = "53e6ce116135b80d037921a7fdd5138cf32d7a8a"
[[projects]]
branch = "master"
name = "github.com/howeyc/gopass"
packages = ["."]
revision = "bf9dde6d0d2c004a008c27aaee91170c786f6db8"
[[projects]]
branch = "master"
name = "github.com/kballard/go-shellquote"
packages = ["."]
revision = "d8ec1a69a250a17bb0e419c386eac1f3711dc142"
[[projects]]
branch = "master"
name = "github.com/kohkimakimoto/gluaenv"
packages = ["."]
revision = "2888db6bbe38923d59c42e443895875cc8ce0820"
[[projects]]
branch = "master"
name = "github.com/kohkimakimoto/gluafs"
packages = ["."]
revision = "01391ed2d7ab89dc80157605b073403f960aa223"
[[projects]]
branch = "master"
name = "github.com/kohkimakimoto/gluaquestion"
packages = ["."]
revision = "311437c29ba54d027ad2af383661725ae2bfdcdc"
[[projects]]
branch = "master"
name = "github.com/kohkimakimoto/gluassh"
packages = ["."]
revision = "2a7bd48d7568de8230c87ac1ef4a4c481e45814d"
[[projects]]
branch = "master"
name = "github.com/kohkimakimoto/gluatemplate"
packages = ["."]
revision = "d9e2c9d6b00f069a9da377a9ac529c827c1c7d71"
[[projects]]
branch = "master"
name = "github.com/kohkimakimoto/gluayaml"
packages = ["."]
revision = "6fe413d49d73d785510ecf1529991ab0573e96c7"
[[projects]]
branch = "master"
name = "github.com/kr/fs"
packages = ["."]
revision = "2788f0dbd16903de03cb8186e5c7d97b69ad387b"
[[projects]]
branch = "master"
name = "github.com/kr/pty"
packages = ["."]
revision = "ce7fa45920dc37a92de8377972e52bc55ffa8d57"
[[projects]]
branch = "master"
name = "github.com/mattn/go-runewidth"
packages = ["."]
revision = "737072b4e32b7a5018b4a7125da8d12de90e8045"
[[projects]]
branch = "master"
name = "github.com/mitchellh/mapstructure"
packages = ["."]
revision = "cc8532a8e9a55ea36402aa21efdf403a60d34096"
[[projects]]
branch = "master"
name = "github.com/olekukonko/tablewriter"
packages = ["."]
revision = "44e365d423f4f06769182abfeeae2b91be9d529b"
[[projects]]
branch = "master"
name = "github.com/otm/gluaflag"
packages = ["."]
revision = "078088de689148194436293886e8e39809167332"
[[projects]]
branch = "master"
name = "github.com/otm/gluash"
packages = ["."]
revision = "e145c563986f0b91f740a758a84bca46c163aec7"
[[projects]]
name = "github.com/pborman/uuid"
packages = ["."]
revision = "e790cca94e6cc75c7064b1332e63811d4aae1a53"
version = "v1.1"
[[projects]]
branch = "master"
name = "github.com/pkg/sftp"
packages = ["."]
revision = "e84cc8c755ca39b7b64f510fe1fffc1b51f210a5"
[[projects]]
branch = "master"
name = "github.com/yookoala/realpath"
packages = ["."]
revision = "c416d99ab5ed256fa30c1f3bab73152deb59bb69"
[[projects]]
branch = "master"
name = "github.com/yuin/gluamapper"
packages = ["."]
revision = "d836955830e75240d46ce9f0e6d148d94f2e1d3a"
[[projects]]
branch = "master"
name = "github.com/yuin/gluare"
packages = ["."]
revision = "8e2742cd1bf2b904720ac66eca3c2091b2ea0720"
[[projects]]
branch = "master"
name = "github.com/yuin/gopher-lua"
packages = [".","ast","parse","pm"]
revision = "33ebc07735566cd0c3c4b69e2839d522cc389852"
[[projects]]
branch = "master"
name = "golang.org/x/crypto"
packages = ["curve25519","ed25519","ed25519/internal/edwards25519","nacl/secretbox","poly1305","salsa20/salsa","ssh","ssh/agent","ssh/terminal"]
revision = "dd85ac7e6a88fc6ca420478e934de5f1a42dd3c6"
[[projects]]
branch = "master"
name = "golang.org/x/net"
packages = ["html","html/atom"]
revision = "66aacef3dd8a676686c7ae3716979581e8b03c47"
[[projects]]
branch = "master"
name = "golang.org/x/sys"
packages = ["unix"]
revision = "9ccfe848b9db8435a24c424abbc07a921adf1df5"
[[projects]]
branch = "v2"
name = "gopkg.in/xmlpath.v2"
packages = ["."]
revision = "860cbeca3ebcc600db0b213c0e83ad6ce91f5739"
[[projects]]
branch = "master"
name = "gopkg.in/yaml.v2"
packages = ["."]
revision = "cd8b52f8269e0feb286dfeef29f8fe4d5b397e0b"
[[projects]]
branch = "master"
name = "layeh.com/gopher-json"
packages = ["."]
revision = "c128cc74278be889c4381681712931976fe0d88b"
[[projects]]
branch = "master"
name = "layeh.com/gopher-luar"
packages = ["."]
revision = "80196fe2abc5682963fc7a5261f5a5d77509938b"

72
vendor/github.com/Xe/eclier/Gopkg.toml generated vendored Normal file
View File

@ -0,0 +1,72 @@
[[dependencies]]
branch = "master"
name = "github.com/Xe/x"
[[dependencies]]
branch = "master"
name = "github.com/ailncode/gluaxmlpath"
[[dependencies]]
branch = "master"
name = "github.com/cjoudrey/gluahttp"
[[dependencies]]
branch = "master"
name = "github.com/cjoudrey/gluaurl"
[[dependencies]]
branch = "master"
name = "github.com/dickeyxxx/netrc"
[[dependencies]]
branch = "master"
name = "github.com/kohkimakimoto/gluaenv"
[[dependencies]]
branch = "master"
name = "github.com/kohkimakimoto/gluafs"
[[dependencies]]
branch = "master"
name = "github.com/kohkimakimoto/gluaquestion"
[[dependencies]]
branch = "master"
name = "github.com/kohkimakimoto/gluassh"
[[dependencies]]
branch = "master"
name = "github.com/kohkimakimoto/gluatemplate"
[[dependencies]]
branch = "master"
name = "github.com/kohkimakimoto/gluayaml"
[[dependencies]]
branch = "master"
name = "github.com/olekukonko/tablewriter"
[[dependencies]]
branch = "master"
name = "github.com/otm/gluaflag"
[[dependencies]]
branch = "master"
name = "github.com/otm/gluash"
[[dependencies]]
branch = "master"
name = "github.com/yuin/gluare"
[[dependencies]]
branch = "master"
name = "github.com/yuin/gopher-lua"
[[dependencies]]
branch = "master"
name = "layeh.com/gopher-json"
[[dependencies]]
branch = "master"
name = "layeh.com/gopher-luar"

121
vendor/github.com/Xe/eclier/LICENSE generated vendored Normal file
View File

@ -0,0 +1,121 @@
Creative Commons Legal Code
CC0 1.0 Universal
CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE
LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN
ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS
INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES
REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS
PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM
THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED
HEREUNDER.
Statement of Purpose
The laws of most jurisdictions throughout the world automatically confer
exclusive Copyright and Related Rights (defined below) upon the creator
and subsequent owner(s) (each and all, an "owner") of an original work of
authorship and/or a database (each, a "Work").
Certain owners wish to permanently relinquish those rights to a Work for
the purpose of contributing to a commons of creative, cultural and
scientific works ("Commons") that the public can reliably and without fear
of later claims of infringement build upon, modify, incorporate in other
works, reuse and redistribute as freely as possible in any form whatsoever
and for any purposes, including without limitation commercial purposes.
These owners may contribute to the Commons to promote the ideal of a free
culture and the further production of creative, cultural and scientific
works, or to gain reputation or greater distribution for their Work in
part through the use and efforts of others.
For these and/or other purposes and motivations, and without any
expectation of additional consideration or compensation, the person
associating CC0 with a Work (the "Affirmer"), to the extent that he or she
is an owner of Copyright and Related Rights in the Work, voluntarily
elects to apply CC0 to the Work and publicly distribute the Work under its
terms, with knowledge of his or her Copyright and Related Rights in the
Work and the meaning and intended legal effect of CC0 on those rights.
1. Copyright and Related Rights. A Work made available under CC0 may be
protected by copyright and related or neighboring rights ("Copyright and
Related Rights"). Copyright and Related Rights include, but are not
limited to, the following:
i. the right to reproduce, adapt, distribute, perform, display,
communicate, and translate a Work;
ii. moral rights retained by the original author(s) and/or performer(s);
iii. publicity and privacy rights pertaining to a person's image or
likeness depicted in a Work;
iv. rights protecting against unfair competition in regards to a Work,
subject to the limitations in paragraph 4(a), below;
v. rights protecting the extraction, dissemination, use and reuse of data
in a Work;
vi. database rights (such as those arising under Directive 96/9/EC of the
European Parliament and of the Council of 11 March 1996 on the legal
protection of databases, and under any national implementation
thereof, including any amended or successor version of such
directive); and
vii. other similar, equivalent or corresponding rights throughout the
world based on applicable law or treaty, and any national
implementations thereof.
2. Waiver. To the greatest extent permitted by, but not in contravention
of, applicable law, Affirmer hereby overtly, fully, permanently,
irrevocably and unconditionally waives, abandons, and surrenders all of
Affirmer's Copyright and Related Rights and associated claims and causes
of action, whether now known or unknown (including existing as well as
future claims and causes of action), in the Work (i) in all territories
worldwide, (ii) for the maximum duration provided by applicable law or
treaty (including future time extensions), (iii) in any current or future
medium and for any number of copies, and (iv) for any purpose whatsoever,
including without limitation commercial, advertising or promotional
purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each
member of the public at large and to the detriment of Affirmer's heirs and
successors, fully intending that such Waiver shall not be subject to
revocation, rescission, cancellation, termination, or any other legal or
equitable action to disrupt the quiet enjoyment of the Work by the public
as contemplated by Affirmer's express Statement of Purpose.
3. Public License Fallback. Should any part of the Waiver for any reason
be judged legally invalid or ineffective under applicable law, then the
Waiver shall be preserved to the maximum extent permitted taking into
account Affirmer's express Statement of Purpose. In addition, to the
extent the Waiver is so judged Affirmer hereby grants to each affected
person a royalty-free, non transferable, non sublicensable, non exclusive,
irrevocable and unconditional license to exercise Affirmer's Copyright and
Related Rights in the Work (i) in all territories worldwide, (ii) for the
maximum duration provided by applicable law or treaty (including future
time extensions), (iii) in any current or future medium and for any number
of copies, and (iv) for any purpose whatsoever, including without
limitation commercial, advertising or promotional purposes (the
"License"). The License shall be deemed effective as of the date CC0 was
applied by Affirmer to the Work. Should any part of the License for any
reason be judged legally invalid or ineffective under applicable law, such
partial invalidity or ineffectiveness shall not invalidate the remainder
of the License, and in such case Affirmer hereby affirms that he or she
will not (i) exercise any of his or her remaining Copyright and Related
Rights in the Work or (ii) assert any associated claims and causes of
action with respect to the Work, in either case contrary to Affirmer's
express Statement of Purpose.
4. Limitations and Disclaimers.
a. No trademark or patent rights held by Affirmer are waived, abandoned,
surrendered, licensed or otherwise affected by this document.
b. Affirmer offers the Work as-is and makes no representations or
warranties of any kind concerning the Work, express, implied,
statutory or otherwise, including without limitation warranties of
title, merchantability, fitness for a particular purpose, non
infringement, or the absence of latent or other defects, accuracy, or
the present or absence of errors, whether or not discoverable, all to
the greatest extent permissible under applicable law.
c. Affirmer disclaims responsibility for clearing rights of other persons
that may apply to the Work or any use thereof, including without
limitation any person's Copyright and Related Rights in the Work.
Further, Affirmer disclaims responsibility for obtaining any necessary
consents, permissions or other rights required for any use of the
Work.
d. Affirmer understands and acknowledges that Creative Commons is not a
party to this document and has no duty or obligation with respect to
this CC0 or use of the Work.

38
vendor/github.com/Xe/eclier/README.md generated vendored Normal file
View File

@ -0,0 +1,38 @@
# eclier
Pronounced like eclair
The core of a command line application allowing for trivial user extension.
Every command and subcommand is its own `.lua` file that is either shipped as
part of the built-in cartridge of commands or a plugin that the user installs.
The core contains the following:
- A module loading system for preparing different commands for use
- The core subcommand router
## How to write plugins
Create a new file in the script home named after the plugin subcommand, for
example: `scripts/hello.lua`:
```lua
script.verb = "hello"
script.help = "prints everyone's favorite hello world message"
script.author = "Xe" -- put your github username here
script.version = "1.0"
script.usage = ""
function(run)
print "Hello, world!"
end
```
And then run it using the example shell cli:
```console
~/go/src/github.com/Xe/eclier:master λ go run ./example/main.go hello
Hello, world!
```

113
vendor/github.com/Xe/eclier/builtin.go generated vendored Normal file
View File

@ -0,0 +1,113 @@
package eclier
import (
"context"
"flag"
"fmt"
)
// Constants for built-in commands.
const (
BuiltinScriptPath = "<built-in>"
BuiltinAuthor = "<built-in>"
BuiltinVersion = "<built-in>"
)
type pluginCommand struct {
r *Router
fs *flag.FlagSet
dontShowBuiltin *bool
}
// Close is a no-op.
func (p *pluginCommand) Close() error { return nil }
// Init sets up the flags for this command.
func (p *pluginCommand) Init() {
p.fs = flag.NewFlagSet(p.Verb(), flag.ExitOnError)
p.dontShowBuiltin = p.fs.Bool("no-builtin", false, "if set, don't show built-in commands")
}
// ScriptPath returns the built-in script path.
func (p *pluginCommand) ScriptPath() string { return BuiltinScriptPath }
// Verb returns the command verb.
func (p *pluginCommand) Verb() string { return "plugins" }
// Help returns the command help
func (p *pluginCommand) Help() string {
return `plugin lists all of the loaded commands and their script paths.`
}
func (p *pluginCommand) Usage() string {
return ` -no-builtin
if set, don't show built-in commands`
}
func (p *pluginCommand) Author() string { return BuiltinAuthor }
func (p *pluginCommand) Version() string { return BuiltinVersion }
// Run executes the command.
func (p *pluginCommand) Run(ctx context.Context, arg []string) error {
p.fs.Parse(arg)
for _, c := range p.r.cmds {
if c.ScriptPath() == BuiltinScriptPath && *p.dontShowBuiltin {
continue
}
fmt.Printf("%s\t%s\n", c.Verb(), c.ScriptPath())
}
return nil
}
// NewBuiltinCommand makes it easier to write core commands for eclier.
func NewBuiltinCommand(verb, help, usage string, doer func(context.Context, []string) error) Command {
return &commandFunc{
verb: verb,
help: help,
usage: usage,
doer: doer,
}
}
// commandFunc is a simple alias for creating builtin commands.
type commandFunc struct {
verb string
help string
usage string
doer func(context.Context, []string) error
}
// Close deallocates resources set up by the initialization of the command.
func (c *commandFunc) Close() error { return nil }
// Init is a no-op.
func (c *commandFunc) Init() {}
// ScriptPath returns the built-in script path.
func (c *commandFunc) ScriptPath() string { return BuiltinScriptPath }
// Verb returns the command verb.
func (c *commandFunc) Verb() string { return c.verb }
// Help returns the command help.
func (c *commandFunc) Help() string { return c.help }
// Usage returns the command usage.
func (c *commandFunc) Usage() string { return c.usage }
// Author returns the built-in author.
func (c *commandFunc) Author() string { return BuiltinAuthor }
// Version returns the built-in version.
func (c *commandFunc) Version() string { return BuiltinVersion }
// Run runs the command handler.
func (c *commandFunc) Run(ctx context.Context, arg []string) error {
return c.doer(ctx, arg)
}

18
vendor/github.com/Xe/eclier/command.go generated vendored Normal file
View File

@ -0,0 +1,18 @@
package eclier
import (
"context"
)
// Command is an individual subcommand.
type Command interface {
Close() error
Init()
ScriptPath() string
Verb() string
Help() string
Usage() string
Author() string
Version() string
Run(ctx context.Context, arg []string) error
}

8
vendor/github.com/Xe/eclier/config.ld generated vendored Normal file
View File

@ -0,0 +1,8 @@
file = {
"./internal/gluanetrc/netrc.lua",
"./internal/gluaheroku/heroku.lua",
}
title = "eclier lua libraries"
project = "eclier"
description = "The lua libraries created for eclier demos and common utility."

140
vendor/github.com/Xe/eclier/router.go generated vendored Normal file
View File

@ -0,0 +1,140 @@
package eclier
import (
"context"
"fmt"
"log"
"os"
"path/filepath"
"strings"
"sync"
"github.com/olekukonko/tablewriter"
lua "github.com/yuin/gopher-lua"
)
// Router is the main subcommand router for eclier. At a high level what this is
// doing is similar to http.ServeMux, but for CLI commands instead of HTTP handlers.
type Router struct {
lock sync.Mutex
cmds map[string]Command
// configured data
gluaCreationHook func(*lua.LState)
scriptHomes []string
cartridge map[string]string
}
// NewRouter creates a new instance of Router and sets it up for use.
func NewRouter(opts ...RouterOption) (*Router, error) {
r := &Router{
cmds: map[string]Command{},
cartridge: map[string]string{},
}
for _, opt := range opts {
opt(r)
}
// scan r.scriptHome for lua scripts, load them into their own lua states and
// make a wrapper around them for the Command type.
for _, home := range r.scriptHomes {
err := filepath.Walk(home, func(path string, info os.FileInfo, err error) error {
if err != nil {
log.Printf("error in arg: %v", err)
return err
}
if strings.HasSuffix(info.Name(), ".lua") {
fname := filepath.Join(home, info.Name())
fin, err := os.Open(fname)
if err != nil {
return err
}
defer fin.Close()
c := newGluaCommand(r.gluaCreationHook, fname, fin)
r.cmds[c.Verb()] = c
}
return nil
})
if err != nil {
return nil, err
}
}
var helpCommand Command = NewBuiltinCommand("help", "shows help for subcommands", "[subcommand]", func(ctx context.Context, arg []string) error {
if len(arg) == 0 {
table := tablewriter.NewWriter(os.Stdout)
table.SetHeader([]string{"Verb", "Author", "Version", "Help"})
for _, cmd := range r.cmds {
table.Append([]string{cmd.Verb(), cmd.Author(), cmd.Version(), cmd.Help()})
}
table.Render()
return nil
}
cmd, ok := r.cmds[arg[0]]
if !ok {
fmt.Printf("can't find help for %s", arg[0])
os.Exit(2)
}
fmt.Printf("Verb: %s\nAuthor: %s\nVersion: %s\nHelp: %s\nUsage: %s %s\n", cmd.Verb(), cmd.Author(), cmd.Version(), cmd.Help(), cmd.Verb(), cmd.Usage())
return nil
})
r.cmds["plugins"] = &pluginCommand{r: r}
r.cmds["help"] = helpCommand
return r, nil
}
// Run executes a single command given in slot 0 of the argument array.
func (r *Router) Run(ctx context.Context, arg []string) error {
r.lock.Lock()
defer r.lock.Unlock()
if len(arg) == 0 {
fmt.Printf("please specify a subcommand, such as `%s help`\n", filepath.Base(os.Args[0]))
os.Exit(2)
}
cmd := arg[0]
arg = arg[1:]
ci, ok := r.cmds[cmd]
if !ok {
fmt.Printf("No such command %s could be run.\n", cmd)
os.Exit(2)
}
ci.Init()
return ci.Run(ctx, arg)
}
// RouterOption is a functional option for Router.
type RouterOption func(*Router)
// WithScriptHome sets the router's script home to the given directory. This is
// where lua files will be walked and parsed.
func WithScriptHome(dir string) RouterOption {
return func(r *Router) {
r.scriptHomes = append(r.scriptHomes, dir)
}
}
// WithGluaCreationHook adds a custom bit of code that runs every time a new
// gopher-lua LState is created. This allows users of this library to register
// custom libraries to the pile of states.
func WithGluaCreationHook(hook func(*lua.LState)) RouterOption {
return func(r *Router) {
r.gluaCreationHook = hook
}
}

92
vendor/github.com/Xe/eclier/script.go generated vendored Normal file
View File

@ -0,0 +1,92 @@
package eclier
import (
"context"
"errors"
"io"
"io/ioutil"
"sync"
lua "github.com/yuin/gopher-lua"
luar "layeh.com/gopher-luar"
)
type Script struct {
Verb string
Help string
Usage string
Author string
Version string
}
type gluaCommand struct {
sync.Mutex
script *Script
L *lua.LState
filename string
}
func newGluaCommand(preload func(*lua.LState), filename string, r io.Reader) Command {
L := lua.NewState()
preload(L)
script := &Script{}
L.SetGlobal("script", luar.New(L, script))
data, err := ioutil.ReadAll(r)
if err != nil {
panic(err)
}
err = L.DoString(string(data))
if err != nil {
panic(err)
}
return &gluaCommand{script: script, L: L, filename: filename}
}
func (g *gluaCommand) Close() error {
g.L.Close()
return nil
}
func (g *gluaCommand) Init() {}
func (g *gluaCommand) ScriptPath() string { return g.filename }
func (g *gluaCommand) Verb() string { return g.script.Verb }
func (g *gluaCommand) Help() string { return g.script.Help }
func (g *gluaCommand) Usage() string { return g.script.Usage }
func (g *gluaCommand) Author() string { return g.script.Author }
func (g *gluaCommand) Version() string { return g.script.Version }
func (g *gluaCommand) Run(ctx context.Context, arg []string) error {
runf := g.L.GetGlobal("run")
if runf.Type() == lua.LTNil {
return errors.New("no global function run in this script")
}
tab := g.L.NewTable()
for _, a := range arg {
tab.Append(lua.LString(a))
}
err := g.L.CallByParam(lua.P{
Fn: runf,
NRet: 0,
Protect: false,
}, tab)
if err != nil {
panic(err)
}
return nil
}

661
vendor/github.com/Xe/x/tools/glue/CHEATSHEET.md generated vendored Normal file
View File

@ -0,0 +1,661 @@
## `json`
```lua
local json = require "json"
```
Json encoder/decoder
The following functions are exposed by the library:
decode(string): Decodes a JSON string. Returns nil and an error string if
the string could not be decoded.
encode(value): Encodes a value into a JSON string. Returns nil and an error
string if the value could not be encoded.
## `xmlpath`
```lua
local xmlpath = require "xmlpath"
```
XMLPath style iteration
xml ="<bookist><book>x1</book><book>x2</book><book>x3</book></booklist>"
local xmlpath = require("xmlpath")
node,err = xmlpath.loadxml(xml)
path,err = xmlpath.compile("//book")
it = path:iter(node)
for k,v in pairs(it) do
print(k,v:string())
end
## `http`
```lua
local http = require("http")
```
HTTP client library
### API
- [`http.delete(url [, options])`](#httpdeleteurl--options)
- [`http.get(url [, options])`](#httpgeturl--options)
- [`http.head(url [, options])`](#httpheadurl--options)
- [`http.patch(url [, options])`](#httppatchurl--options)
- [`http.post(url [, options])`](#httpposturl--options)
- [`http.put(url [, options])`](#httpputurl--options)
- [`http.request(method, url [, options])`](#httprequestmethod-url--options)
- [`http.request_batch(requests)`](#httprequest_batchrequests)
- [`http.response`](#httpresponse)
#### http.delete(url [, options])
**Attributes**
| Name | Type | Description |
| ------- | ------ | ----------- |
| url | String | URL of the resource to load |
| options | Table | Additional options |
**Options**
| Name | Type | Description |
| ------- | ------ | ----------- |
| query | String | URL encoded query params |
| cookies | Table | Additional cookies to send with the request |
| headers | Table | Additional headers to send with the request |
**Returns**
[http.response](#httpresponse) or (nil, error message)
#### http.get(url [, options])
**Attributes**
| Name | Type | Description |
| ------- | ------ | ----------- |
| url | String | URL of the resource to load |
| options | Table | Additional options |
**Options**
| Name | Type | Description |
| ------- | ------ | ----------- |
| query | String | URL encoded query params |
| cookies | Table | Additional cookies to send with the request |
| headers | Table | Additional headers to send with the request |
**Returns**
[http.response](#httpresponse) or (nil, error message)
#### http.head(url [, options])
**Attributes**
| Name | Type | Description |
| ------- | ------ | ----------- |
| url | String | URL of the resource to load |
| options | Table | Additional options |
**Options**
| Name | Type | Description |
| ------- | ------ | ----------- |
| query | String | URL encoded query params |
| cookies | Table | Additional cookies to send with the request |
| headers | Table | Additional headers to send with the request |
**Returns**
[http.response](#httpresponse) or (nil, error message)
#### http.patch(url [, options])
**Attributes**
| Name | Type | Description |
| ------- | ------ | ----------- |
| url | String | URL of the resource to load |
| options | Table | Additional options |
**Options**
| Name | Type | Description |
| ------- | ------ | ----------- |
| query | String | URL encoded query params |
| cookies | Table | Additional cookies to send with the request |
| body | String | Request body. |
| form | String | Deprecated. URL encoded request body. This will also set the `Content-Type` header to `application/x-www-form-urlencoded` |
| headers | Table | Additional headers to send with the request |
**Returns**
[http.response](#httpresponse) or (nil, error message)
#### http.post(url [, options])
**Attributes**
| Name | Type | Description |
| ------- | ------ | ----------- |
| url | String | URL of the resource to load |
| options | Table | Additional options |
**Options**
| Name | Type | Description |
| ------- | ------ | ----------- |
| query | String | URL encoded query params |
| cookies | Table | Additional cookies to send with the request |
| body | String | Request body. |
| form | String | Deprecated. URL encoded request body. This will also set the `Content-Type` header to `application/x-www-form-urlencoded` |
| headers | Table | Additional headers to send with the request |
**Returns**
[http.response](#httpresponse) or (nil, error message)
#### http.put(url [, options])
**Attributes**
| Name | Type | Description |
| ------- | ------ | ----------- |
| url | String | URL of the resource to load |
| options | Table | Additional options |
**Options**
| Name | Type | Description |
| ------- | ------ | ----------- |
| query | String | URL encoded query params |
| cookies | Table | Additional cookies to send with the request |
| body | String | Request body. |
| form | String | Deprecated. URL encoded request body. This will also set the `Content-Type` header to `application/x-www-form-urlencoded` |
| headers | Table | Additional headers to send with the request |
**Returns**
[http.response](#httpresponse) or (nil, error message)
#### http.request(method, url [, options])
**Attributes**
| Name | Type | Description |
| ------- | ------ | ----------- |
| method | String | The HTTP request method |
| url | String | URL of the resource to load |
| options | Table | Additional options |
**Options**
| Name | Type | Description |
| ------- | ------ | ----------- |
| query | String | URL encoded query params |
| cookies | Table | Additional cookies to send with the request |
| body | String | Request body. |
| form | String | Deprecated. URL encoded request body. This will also set the `Content-Type` header to `application/x-www-form-urlencoded` |
| headers | Table | Additional headers to send with the request |
**Returns**
[http.response](#httpresponse) or (nil, error message)
#### http.request_batch(requests)
**Attributes**
| Name | Type | Description |
| -------- | ----- | ----------- |
| requests | Table | A table of requests to send. Each request item is by itself a table containing [http.request](#httprequestmethod-url--options) parameters for the request |
**Returns**
[[http.response](#httpresponse)] or ([[http.response](#httpresponse)], [error message])
#### http.response
The `http.response` table contains information about a completed HTTP request.
**Attributes**
| Name | Type | Description |
| ----------- | ------ | ----------- |
| body | String | The HTTP response body |
| body_size | Number | The size of the HTTP reponse body in bytes |
| headers | Table | The HTTP response headers |
| cookies | Table | The cookies sent by the server in the HTTP response |
| status_code | Number | The HTTP response status code |
| url | String | The final URL the request ended pointing to after redirects |
## `url`
```lua
local url = require "url"
```
URL parsing library
### API
- [`url.parse(url)`](#urlparseurl)
- [`url.build(options)`](#urlbuildoptions)
- [`url.build_query_string(query_params)`](#urlbuild_query_stringquery_params)
- [`url.resolve(from, to)`](#urlresolvefrom-to)
#### url.parse(url)
Parse URL into a table of key/value components.
**Attributes**
| Name | Type | Description |
| ------- | ------ | ----------- |
| url | String | URL to parsed |
**Returns**
Table with parsed URL or (nil, error message)
| Name | Type | Description |
| -------- | ------ | ----------- |
| scheme | String | Scheme of the URL |
| username | String | Username |
| password | String | Password |
| host | String | Host and port of the URL |
| path | String | Path |
| query | String | Query string |
| fragment | String | Fragment |
#### url.build(options)
Assemble a URL string from a table of URL components.
**Attributes**
| Name | Type | Description |
| ------- | ----- | ----------- |
| options | Table | Table with URL components, see [`url.parse`](#urlparseurl) for list of valid components |
**Returns**
String
#### url.build_query_string(query_params)
Assemble table of query string parameters into a string.
**Attributes**
| Name | Type | Description |
| ------------ | ----- | ----------- |
| query_params | Table | Table with query parameters |
**Returns**
String
#### url.resolve(from, to)
Take a base URL, and a href URL, and resolve them as a browser would for an anchor tag.
| Name | Type | Description |
| ---- | ------ | ----------- |
| from | String | base URL |
| to | String | href URL |
**Returns**
String or (nil, error message)
## `env`
```lua
local env = require "env"
```
Environment manipulation
### API
#### `env.set(key, value)`
Same `os.setenv`
#### `env.get(key)`
Same `os.getenv`
#### `env.loadfile(file)`
Loads environment variables from a file. The file is as the following:
```
AAA=BBB
CCC=DDD
```
If this function fails, it returns `nil`, plus a string describing the error.
## `fs`
```lua
local fs = require "fs"
```
Filesystem manipulation
### API
#### `fs.exists(file)`
Returns true if the file exists.
#### `fs.read(file)`
Reads file content and return it. If this function fails, it returns `nil`, plus a string describing the error.
#### `fs.write(file, content, [mode])`
Writes content to the file. If this function fails, it returns `nil`, plus a string describing the error.
#### `fs.mkdir(path, [mode, recursive])`
Create directory. If this function fails, it returns `nil`, plus a string describing the error.
#### `fs.remove(path, [recursive])`
Remove path. If this function fails, it returns `nil`, plus a string describing the error.
#### `fs.symlink(target, link)`
Create symbolic link. If this function fails, it returns `nil`, plus a string describing the error.
#### `fs.dirname(path)`
Returns all but the last element of path.
#### `fs.basename(path)`
Returns the last element of path.
#### `fs.realpath(path)`
Returns the real path of a given path in the os. If this function fails, it returns `nil`, plus a string describing the error.
#### `fs.getcwd()`
Returns the current working directory. If this function fails, it returns `nil`, plus a string describing the error.
#### `fs.chdir(path)`
Changes the current working directory. If this function fails, it returns `nil`, plus a string describing the error.
#### `fs.file()`
Returns the script file path. If this function fails, it returns `nil`, plus a string describing the error.
#### `fs.dir()`
Returns the directory path that is parent of the script file. If this function fails, it returns `nil`, plus a string describing the error.
#### `fs.glob(pattern, function)`
Run the callback function with the files matching pattern. See below example:
```lua
local fs = require("fs")
local ret, err = fs.glob("/tmp/*", function(file)
print(file.path)
print(file.realpath)
end)
```
## `markdown`
```lua
local markdown = require "markdown"
```
Markdown -> HTML for string and file
### API
#### `markdown.dostring(text)`
Returns HTML string generated from the markdown text.
#### `markdown.dofile(file)`
Returns HTML string generated from the markdown text file. If this function fails, it returns `nil`, plus a string describing the error.
## `question`
```lua
local question = require "question"
```
Prompt library
### API
* `question.ask(text)`
* `question.secret(text)`
## `ssh`
```lua
local ssh = require "ssh"
```
SSH client library
https://github.com/kohkimakimoto/gluassh/blob/master/gluassh_test.go
## `template`
```lua
local template = require "template"
```
Go text templates
### API
#### `template.dostring(text, table)`
Returns string generated by text template with the table values. If this function fails, it returns `nil`, plus a string describing the error.
#### `template.dofile(file, table)`
Returns string generated by file template with the table values. If this function fails, it returns `nil`, plus a string describing the error.
## `yaml`
```lua
local yaml = require "yaml"
```
Yaml -> table parser
### API
#### `yaml.parse(string)`
Parses yaml formatted string and returns a table. If this function fails, it returns `nil`, plus a string describing the error.
## `flag`
```lua
local flag = require "flag"
```
Command line flag parsing.
See the tests here: https://github.com/otm/gluaflag
```lua
local flag = require "flag"
fs = flag.new()
fs:string("name", "foo", "String help string")
fs:intArg("title", 1, "Title")
fs:numberArg("title", 1, "Title")
flags = fs:parse(arg) -- arg is the remaining command line arguments
assert(flags.title == 2, "expected title to be 2")
assert(flags.title == 2.32, "expected title to be 2.32")
```
## `sh`
```lua
local sh = require "sh"
```
gluash is a interface to call any program as it were a function. Programs are executed asynchronously to enable streaming of data in pipes.
In all discussions bellow the imported module will be referred to as `sh`.
Commands are called just like functions, executed on the sh module.
```lua
sh.ls("/")
```
For commands that have exotic names, names that are reserved words, or to execute absolute or relative paths call the sh module directly.
```lua
sh("/bin/ls", "/")
```
#### Multiple Arguments
Commands with multiple arguments have to be invoked with a separate string for each argument.
```lua
-- this works
sh.ls("-la", "/")
-- this does not work
sh.ls("-la /")
```
#### Piping
Piping in sh is done almost like piping in the shell. Just call next command as a method on the previous command.
```lua
sh.du("-sb"):sort("-rn"):print()
```
If the command has a exotic name, or a reserved word, call the command through `cmd(path, ...args)`. The first argument in `cmd` is the path.
```lua
sh.du("-sb"):cmd("sort", "-rn"):print()
```
### Waiting for Processes
All commands are executed by default in the background, so one have to explicitly wait for a process to finish. There are several ways to wait for the command to finish.
* `print()` - write stdout and stderr to stdout.
* `ok()` - aborts execution if the command's exit code is not zero
* `success()` - returns true of the commands exit code is zero
* `exitcode()` - returns the exit code of the command
### Abort by Default
It is possible to set the module to abort on errors without checking. It can be practical in some occasions, however performance will be degraded. When global exit code checks are done the commands are run in series, even in pipes, and output is saved in memory buffers.
To enable global exit code settings call the sh module with an table with the key `abort` set to true.
```lua
sh{abort=true}
```
To read current settings in the module call the module with an empty table.
```lua
configuration = sh{}
print("abort:", configuration.abort)
```
### Analyzing Output
There are several options to analyze the output of a command.
#### lines()
An iterator is accessible by calling the method `lines()` on the command.
```lua
for line in sh.cat("/etc/hosts"):lines() do
print(line)
end
```
#### stdout([filename]), stderr([filename]), combinedOutput([filename])
`stdout()`, `stderr()`, and `combinedOutput()` all returns the output of the command as a string. An optional `filename` can be given to the method, in that case the output is also written to the file. The file will be truncated.
```lua
-- print output of command
output = sh.echo("hello world"):combinedOutput("/tmp/output")
print(output)
```
In the example above will print `hello world` and it will write it to `/tmp/output`
### Glob Expansion
There is no glob expansion done on arguments, however there is a glob functionality in sh.
```lua
sh.ls(sh.glob("*.go"))
```
## `re`
```lua
local re = require "re"
```
Regular Expressions
### API
re.find , re.gsub, re.match, re.gmatch are available. These functions have the same API as Lua pattern match.
gluare uses the Go regexp package, so you can use regular expressions that are supported in the Go regexp package.
In addition, the following functions are defined:
```
gluare.quote(s string) -> string
Arguments:
s string: a string value to escape meta characters
Returns:
string: escaped string
gluare.quote returns a string that quotes all regular expression metacharacters inside the given text.
```
## `simplebox`
```lua
local simplebox = require "simplebox"
```
Simple encryption
### API
#### Create a new instance of simplebox with a newly generated key
```lua
local simplebox = require "simplebox"
local key = simplebox.genkey()
print("key is: " .. key)
local sb = simplebox.new()
```

4
vendor/github.com/Xe/x/tools/glue/Dockerfile generated vendored Normal file
View File

@ -0,0 +1,4 @@
FROM busybox
ADD glue /glue
CMD /glue

181
vendor/github.com/Xe/x/tools/glue/Gopkg.lock generated vendored Normal file
View File

@ -0,0 +1,181 @@
memo = ""
[[projects]]
branch = "master"
name = "github.com/ThomasRooney/gexpect"
packages = ["."]
revision = "5482f03509440585d13d8f648989e05903001842"
[[projects]]
branch = "master"
name = "github.com/ailncode/gluaxmlpath"
packages = ["."]
revision = "6ce478ecb4a60c4fc8929838e0b21b7fb7ca7440"
[[projects]]
branch = "master"
name = "github.com/brandur/simplebox"
packages = ["."]
revision = "84e9865bb03ad38c464043bf5382ce8c68ca5f0c"
[[projects]]
branch = "master"
name = "github.com/cjoudrey/gluahttp"
packages = ["."]
revision = "b4bfe0c50fea948dcbf3966e120996d6607bbd89"
[[projects]]
branch = "master"
name = "github.com/cjoudrey/gluaurl"
packages = ["."]
revision = "31cbb9bef199454415879f2e6d609d1136d60cad"
[[projects]]
branch = "master"
name = "github.com/howeyc/gopass"
packages = ["."]
revision = "bf9dde6d0d2c004a008c27aaee91170c786f6db8"
[[projects]]
branch = "master"
name = "github.com/kballard/go-shellquote"
packages = ["."]
revision = "d8ec1a69a250a17bb0e419c386eac1f3711dc142"
[[projects]]
branch = "master"
name = "github.com/kohkimakimoto/gluaenv"
packages = ["."]
revision = "2888db6bbe38923d59c42e443895875cc8ce0820"
[[projects]]
branch = "master"
name = "github.com/kohkimakimoto/gluafs"
packages = ["."]
revision = "01391ed2d7ab89dc80157605b073403f960aa223"
[[projects]]
branch = "master"
name = "github.com/kohkimakimoto/gluaquestion"
packages = ["."]
revision = "311437c29ba54d027ad2af383661725ae2bfdcdc"
[[projects]]
branch = "master"
name = "github.com/kohkimakimoto/gluassh"
packages = ["."]
revision = "2a7bd48d7568de8230c87ac1ef4a4c481e45814d"
[[projects]]
branch = "master"
name = "github.com/kohkimakimoto/gluatemplate"
packages = ["."]
revision = "d9e2c9d6b00f069a9da377a9ac529c827c1c7d71"
[[projects]]
branch = "master"
name = "github.com/kohkimakimoto/gluayaml"
packages = ["."]
revision = "6fe413d49d73d785510ecf1529991ab0573e96c7"
[[projects]]
branch = "master"
name = "github.com/kr/fs"
packages = ["."]
revision = "2788f0dbd16903de03cb8186e5c7d97b69ad387b"
[[projects]]
branch = "master"
name = "github.com/kr/pty"
packages = ["."]
revision = "ce7fa45920dc37a92de8377972e52bc55ffa8d57"
[[projects]]
branch = "master"
name = "github.com/mitchellh/mapstructure"
packages = ["."]
revision = "cc8532a8e9a55ea36402aa21efdf403a60d34096"
[[projects]]
branch = "master"
name = "github.com/otm/gluaflag"
packages = ["."]
revision = "078088de689148194436293886e8e39809167332"
[[projects]]
branch = "master"
name = "github.com/otm/gluash"
packages = ["."]
revision = "e145c563986f0b91f740a758a84bca46c163aec7"
[[projects]]
branch = "master"
name = "github.com/pkg/sftp"
packages = ["."]
revision = "e84cc8c755ca39b7b64f510fe1fffc1b51f210a5"
[[projects]]
branch = "master"
name = "github.com/yookoala/realpath"
packages = ["."]
revision = "c416d99ab5ed256fa30c1f3bab73152deb59bb69"
[[projects]]
branch = "master"
name = "github.com/yuin/gluamapper"
packages = ["."]
revision = "d836955830e75240d46ce9f0e6d148d94f2e1d3a"
[[projects]]
branch = "master"
name = "github.com/yuin/gluare"
packages = ["."]
revision = "8e2742cd1bf2b904720ac66eca3c2091b2ea0720"
[[projects]]
branch = "master"
name = "github.com/yuin/gopher-lua"
packages = [".","parse"]
revision = "33ebc07735566cd0c3c4b69e2839d522cc389852"
[[projects]]
branch = "master"
name = "golang.org/x/crypto"
packages = ["nacl/secretbox","ssh/terminal","ssh","ssh/agent"]
revision = "dd85ac7e6a88fc6ca420478e934de5f1a42dd3c6"
[[projects]]
branch = "master"
name = "golang.org/x/net"
packages = ["html"]
revision = "66aacef3dd8a676686c7ae3716979581e8b03c47"
[[projects]]
branch = "master"
name = "golang.org/x/sys"
packages = ["unix"]
revision = "9ccfe848b9db8435a24c424abbc07a921adf1df5"
[[projects]]
branch = "v2"
name = "gopkg.in/xmlpath.v2"
packages = ["."]
revision = "860cbeca3ebcc600db0b213c0e83ad6ce91f5739"
[[projects]]
branch = "master"
name = "gopkg.in/yaml.v2"
packages = ["."]
revision = "cd8b52f8269e0feb286dfeef29f8fe4d5b397e0b"
[[projects]]
branch = "master"
name = "layeh.com/gopher-json"
packages = ["."]
revision = "c128cc74278be889c4381681712931976fe0d88b"
[[projects]]
branch = "master"
name = "layeh.com/gopher-luar"
packages = ["."]
revision = "80196fe2abc5682963fc7a5261f5a5d77509938b"

68
vendor/github.com/Xe/x/tools/glue/Gopkg.toml generated vendored Normal file
View File

@ -0,0 +1,68 @@
[[dependencies]]
branch = "master"
name = "github.com/ThomasRooney/gexpect"
[[dependencies]]
branch = "master"
name = "github.com/ailncode/gluaxmlpath"
[[dependencies]]
branch = "master"
name = "github.com/brandur/simplebox"
[[dependencies]]
branch = "master"
name = "github.com/cjoudrey/gluahttp"
[[dependencies]]
branch = "master"
name = "github.com/cjoudrey/gluaurl"
[[dependencies]]
branch = "master"
name = "github.com/kohkimakimoto/gluaenv"
[[dependencies]]
branch = "master"
name = "github.com/kohkimakimoto/gluafs"
[[dependencies]]
branch = "master"
name = "github.com/kohkimakimoto/gluaquestion"
[[dependencies]]
branch = "master"
name = "github.com/kohkimakimoto/gluassh"
[[dependencies]]
branch = "master"
name = "github.com/kohkimakimoto/gluatemplate"
[[dependencies]]
branch = "master"
name = "github.com/kohkimakimoto/gluayaml"
[[dependencies]]
branch = "master"
name = "github.com/otm/gluaflag"
[[dependencies]]
branch = "master"
name = "github.com/otm/gluash"
[[dependencies]]
branch = "master"
name = "github.com/yuin/gluare"
[[dependencies]]
branch = "master"
name = "github.com/yuin/gopher-lua"
[[dependencies]]
branch = "master"
name = "layeh.com/gopher-json"
[[dependencies]]
branch = "master"
name = "layeh.com/gopher-luar"

18
vendor/github.com/Xe/x/tools/glue/README.md generated vendored Normal file
View File

@ -0,0 +1,18 @@
glue
====
Basically gopher-lua's cmd/glua with the following modules imported:
- https://godoc.org/layeh.com/gopher-json
- https://github.com/ailncode/gluaxmlpath
- https://github.com/cjoudrey/gluahttp
- https://github.com/cjoudrey/gluaurl
- https://github.com/kohkimakimoto/gluaenv
- https://github.com/kohkimakimoto/gluafs
- https://github.com/kohkimakimoto/gluamarkdown
- https://github.com/kohkimakimoto/gluaquestion
- https://github.com/kohkimakimoto/gluassh
- https://github.com/kohkimakimoto/gluatemplate
- https://github.com/kohkimakimoto/gluayaml
- https://github.com/otm/gluaflag
- https://github.com/otm/gluash
- https://github.com/yuin/gluare

6
vendor/github.com/Xe/x/tools/glue/box.rb generated vendored Normal file
View File

@ -0,0 +1,6 @@
from "alpine:edge"
copy "glue", "/glue"
cmd "/glue"
flatten
tag "xena/glue"

20
vendor/github.com/Xe/x/tools/glue/build.lua generated vendored Normal file
View File

@ -0,0 +1,20 @@
-- expects glue, $ go get -u github.com/Xe/tools/glue
local sh = require "sh"
sh { abort = true }
if os.getenv("CGO_ENABLED") ~= "0" then
error("CGO_ENABLED must be set to 1")
end
print "building glue..."
sh.go("build"):print()
sh.upx("--ultra-brute", "glue"):print()
sh.box("box.rb"):print()
print "releasing to docker hub"
sh.docker("push", "xena/glue"):print()
print "moving glue binary to $GOPATH/bin"
sh.mv("glue", (os.getenv("GOPATH") .. "/bin/glue"))
print "build/release complete"

BIN
vendor/github.com/Xe/x/tools/glue/glue generated vendored Executable file

Binary file not shown.

213
vendor/github.com/Xe/x/tools/glue/glue.go generated vendored Normal file
View File

@ -0,0 +1,213 @@
package main
import (
"bufio"
"flag"
"fmt"
"net/http"
"os"
"runtime/pprof"
"github.com/Xe/x/tools/glue/libs/gluaexpect"
"github.com/Xe/x/tools/glue/libs/gluasimplebox"
"github.com/ailncode/gluaxmlpath"
"github.com/cjoudrey/gluahttp"
"github.com/cjoudrey/gluaurl"
"github.com/kohkimakimoto/gluaenv"
"github.com/kohkimakimoto/gluafs"
"github.com/kohkimakimoto/gluaquestion"
"github.com/kohkimakimoto/gluassh"
"github.com/kohkimakimoto/gluatemplate"
"github.com/kohkimakimoto/gluayaml"
"github.com/otm/gluaflag"
"github.com/otm/gluash"
"github.com/yuin/gluare"
"github.com/yuin/gopher-lua"
"github.com/yuin/gopher-lua/parse"
json "layeh.com/gopher-json"
)
func main() {
os.Exit(mainAux())
}
func mainAux() int {
var opt_e, opt_l, opt_p string
var opt_i, opt_v, opt_dt, opt_dc bool
var opt_m int
flag.StringVar(&opt_e, "e", "", "")
flag.StringVar(&opt_l, "l", "", "")
flag.StringVar(&opt_p, "p", "", "")
flag.IntVar(&opt_m, "mx", 0, "")
flag.BoolVar(&opt_i, "i", false, "")
flag.BoolVar(&opt_v, "v", false, "")
flag.BoolVar(&opt_dt, "dt", false, "")
flag.BoolVar(&opt_dc, "dc", false, "")
flag.Usage = func() {
fmt.Println(`Usage: glue [options] [script [args]].
Available options are:
-e stat execute string 'stat'
-l name require library 'name'
-mx MB memory limit(default: unlimited)
-dt dump AST trees
-dc dump VM codes
-i enter interactive mode after executing 'script'
-p file write cpu profiles to the file
-v show version information
`)
}
flag.Parse()
if len(opt_p) != 0 {
f, err := os.Create(opt_p)
if err != nil {
fmt.Println(err.Error())
os.Exit(1)
}
pprof.StartCPUProfile(f)
defer pprof.StopCPUProfile()
}
if len(opt_e) == 0 && !opt_i && !opt_v && flag.NArg() == 0 {
opt_i = true
}
status := 0
L := lua.NewState()
defer L.Close()
if opt_m > 0 {
L.SetMx(opt_m)
}
preload(L)
if opt_v || opt_i {
fmt.Println(lua.PackageCopyRight)
}
if len(opt_l) > 0 {
if err := L.DoFile(opt_l); err != nil {
fmt.Println(err.Error())
}
}
if nargs := flag.NArg(); nargs > 0 {
script := flag.Arg(0)
argtb := L.NewTable()
for i := 1; i < nargs; i++ {
L.RawSet(argtb, lua.LNumber(i), lua.LString(flag.Arg(i)))
}
L.SetGlobal("arg", argtb)
if opt_dt || opt_dc {
file, err := os.Open(script)
if err != nil {
fmt.Println(err.Error())
return 1
}
chunk, err2 := parse.Parse(file, script)
if err2 != nil {
fmt.Println(err2.Error())
return 1
}
if opt_dt {
fmt.Println(parse.Dump(chunk))
}
if opt_dc {
proto, err3 := lua.Compile(chunk, script)
if err3 != nil {
fmt.Println(err3.Error())
return 1
}
fmt.Println(proto.String())
}
}
if err := L.DoFile(script); err != nil {
fmt.Println(err.Error())
status = 1
}
}
if len(opt_e) > 0 {
if err := L.DoString(opt_e); err != nil {
fmt.Println(err.Error())
status = 1
}
}
if opt_i {
doREPL(L)
}
return status
}
func preload(L *lua.LState) {
L.PreloadModule("re", gluare.Loader)
L.PreloadModule("sh", gluash.Loader)
L.PreloadModule("fs", gluafs.Loader)
L.PreloadModule("env", gluaenv.Loader)
L.PreloadModule("yaml", gluayaml.Loader)
L.PreloadModule("question", gluaquestion.Loader)
L.PreloadModule("ssh", gluassh.Loader)
L.PreloadModule("http", gluahttp.NewHttpModule(&http.Client{}).Loader)
L.PreloadModule("flag", gluaflag.Loader)
L.PreloadModule("template", gluatemplate.Loader)
L.PreloadModule("url", gluaurl.Loader)
gluaexpect.Preload(L)
gluasimplebox.Preload(L)
gluaxmlpath.Preload(L)
json.Preload(L)
}
// do read/eval/print/loop
func doREPL(L *lua.LState) {
reader := bufio.NewReader(os.Stdin)
for {
if str, err := loadline(reader, L); err == nil {
if err := L.DoString(str); err != nil {
fmt.Println(err)
}
} else { // error on loadline
fmt.Println(err)
return
}
}
}
func incomplete(err error) bool {
if lerr, ok := err.(*lua.ApiError); ok {
if perr, ok := lerr.Cause.(*parse.Error); ok {
return perr.Pos.Line == parse.EOF
}
}
return false
}
func loadline(reader *bufio.Reader, L *lua.LState) (string, error) {
fmt.Print("> ")
if line, err := reader.ReadString('\n'); err == nil {
if _, err := L.LoadString("return " + line); err == nil { // try add return <...> then compile
return line, nil
} else {
return multiline(line, reader, L)
}
} else {
return "", err
}
}
func multiline(ml string, reader *bufio.Reader, L *lua.LState) (string, error) {
for {
if _, err := L.LoadString(ml); err == nil { // try compile
return ml, nil
} else if !incomplete(err) { // syntax error , but not EOF
return ml, nil
} else {
fmt.Print(">> ")
if line, err := reader.ReadString('\n'); err == nil {
ml = ml + "\n" + line
} else {
return "", err
}
}
}
}

View File

@ -0,0 +1,35 @@
package gluaexpect
import (
"github.com/ThomasRooney/gexpect"
lua "github.com/yuin/gopher-lua"
luar "layeh.com/gopher-luar"
)
func Preload(L *lua.LState) {
L.PreloadModule("expect", Loader)
}
// Loader is the module loader function.
func Loader(L *lua.LState) int {
mod := L.SetFuncs(L.NewTable(), api)
L.Push(mod)
return 1
}
var api = map[string]lua.LGFunction{
"spawn": spawn,
}
func spawn(L *lua.LState) int {
cmd := L.CheckString(1)
child, err := gexpect.Spawn(cmd)
if err != nil {
L.Push(lua.LNil)
L.Push(lua.LString(err.Error()))
return 2
}
L.Push(luar.New(L, child))
return 1
}

View File

@ -0,0 +1,100 @@
package gluasimplebox
import (
"crypto/rand"
"encoding/base64"
"encoding/hex"
"errors"
"github.com/brandur/simplebox"
lua "github.com/yuin/gopher-lua"
luar "layeh.com/gopher-luar"
)
func Preload(L *lua.LState) {
L.PreloadModule("simplebox", Loader)
}
// Loader is the module loader function.
func Loader(L *lua.LState) int {
mod := L.SetFuncs(L.NewTable(), api)
L.Push(mod)
return 1
}
var api = map[string]lua.LGFunction{
"new": newSecretBox,
"genkey": genKey,
}
func newSecretBox(L *lua.LState) int {
key := L.CheckString(1)
k, err := parseKey(key)
if err != nil {
L.Push(lua.LNil)
L.Push(lua.LString(err.Error()))
return 2
}
sb := simplebox.NewFromSecretKey(k)
L.Push(luar.New(L, &box{sb: sb}))
return 1
}
func genKey(L *lua.LState) int {
key, err := generateKey()
if err != nil {
L.Push(lua.LNil)
L.Push(lua.LString(err.Error()))
return 2
}
L.Push(lua.LString(base64.URLEncoding.EncodeToString(key[:])))
return 1
}
func generateKey() (*[32]byte, error) {
var k [32]byte
_, err := rand.Read(k[:])
if err != nil {
return nil, err
}
return &k, nil
}
func parseKey(s string) (*[32]byte, error) {
k := &[32]byte{}
raw, err := base64.URLEncoding.DecodeString(s)
if err != nil {
return nil, err
}
if n := copy(k[:], raw); n < len(k) {
return nil, errors.New("not valid")
}
return k, nil
}
type box struct {
sb *simplebox.SimpleBox
}
func (b *box) Encrypt(data string) string {
result := b.sb.Encrypt([]byte(data))
return hex.EncodeToString(result)
}
func (b *box) Decrypt(data string) (string, error) {
d, err := hex.DecodeString(data)
if err != nil {
return "", err
}
plain, err := b.sb.Decrypt([]byte(d))
if err != nil {
return "", err
}
return string(plain), nil
}

40
vendor/github.com/ailncode/gluaxmlpath/README.md generated vendored Normal file
View File

@ -0,0 +1,40 @@
# gluaxmlpath
gluaxmlpath provides an easy way to use [xmlpath](https://github.com/go-xmlpath/xmlpath) from within [GopherLua](https://github.com/yuin/gopher-lua).
## Installation
```
go get github.com/ailncode/gluaxmlpath
```
## Usage
```go
package main
import (
"github.com/ailncode/gluaxmlpath"
"github.com/yuin/gopher-lua"
)
func main() {
L := lua.NewState()
defer L.Close()
gluaxmlpath.Preload(L)
if err := L.DoString(`
xml ="<bookist><book>x1</book><book>x2</book><book>x3</book></booklist>"
local xmlpath = require("xmlpath")
node,err = xmlpath.loadxml(xml)
path,err = xmlpath.compile("//book")
it = path:iter(node)
for k,v in pairs(it) do
print(k,v:string())
end
`); err != nil {
panic(err)
}
}
```

37
vendor/github.com/ailncode/gluaxmlpath/api.go generated vendored Normal file
View File

@ -0,0 +1,37 @@
package gluaxmlpath
import (
"bytes"
"github.com/yuin/gopher-lua"
xmlpath "gopkg.in/xmlpath.v2"
)
var api = map[string]lua.LGFunction{
"loadxml": loadXml,
"compile": compile,
}
func loadXml(L *lua.LState) int {
xmlStr := L.CheckString(1)
r := bytes.NewReader([]byte(xmlStr))
node, err := xmlpath.ParseHTML(r)
if err != nil {
L.Push(lua.LNil)
L.Push(lua.LString(err.Error()))
return 2
}
L.Push(newNode(L, node))
return 1
}
func compile(L *lua.LState) int {
xpathStr := L.CheckString(1)
path, err := xmlpath.Compile(xpathStr)
if err != nil {
L.Push(lua.LNil)
L.Push(lua.LString(err.Error()))
return 2
}
L.Push(newPath(L, path))
return 1
}

21
vendor/github.com/ailncode/gluaxmlpath/xmlpath.go generated vendored Normal file
View File

@ -0,0 +1,21 @@
package gluaxmlpath
import (
"github.com/yuin/gopher-lua"
)
// Preload adds xmlpath to the given Lua state's package.preload table. After it
// has been preloaded, it can be loaded using require:
//
// local xmlpath = require("xmlpath")
func Preload(L *lua.LState) {
L.PreloadModule("xmlpath", Loader)
}
// Loader is the module loader function.
func Loader(L *lua.LState) int {
mod := L.SetFuncs(L.NewTable(), api)
registerType(L, mod)
L.Push(mod)
return 1
}

135
vendor/github.com/ailncode/gluaxmlpath/xmlpathtype.go generated vendored Normal file
View File

@ -0,0 +1,135 @@
package gluaxmlpath
import (
"github.com/yuin/gopher-lua"
xmlpath "gopkg.in/xmlpath.v2"
)
type Node struct {
base *xmlpath.Node
}
type Path struct {
base *xmlpath.Path
}
type Iter struct {
base *xmlpath.Iter
}
const luaNodeTypeName = "xmlpath.node"
const luaPathTypeName = "xmlpath.path"
const luaIterTypeName = "xmlpath.iter"
func registerType(L *lua.LState, module *lua.LTable) {
//reg node
nodemt := L.NewTypeMetatable(luaNodeTypeName)
L.SetField(module, "node", nodemt)
L.SetField(nodemt, "__index", L.SetFuncs(L.NewTable(), map[string]lua.LGFunction{
"string": nodeString,
}))
//reg path
pathmt := L.NewTypeMetatable(luaPathTypeName)
L.SetField(module, "path", pathmt)
L.SetField(pathmt, "__index", L.SetFuncs(L.NewTable(), map[string]lua.LGFunction{
"iter": iter,
}))
//reg iter
itermt := L.NewTypeMetatable(luaIterTypeName)
L.SetField(module, "iter", itermt)
L.SetField(itermt, "__index", L.SetFuncs(L.NewTable(), map[string]lua.LGFunction{
//"next": next,
"node": node,
}))
}
func newNode(L *lua.LState, n *xmlpath.Node) *lua.LUserData {
ud := L.NewUserData()
ud.Value = &Node{
n,
}
L.SetMetatable(ud, L.GetTypeMetatable(luaNodeTypeName))
return ud
}
func checkNode(L *lua.LState) *Node {
ud := L.CheckUserData(1)
if v, ok := ud.Value.(*Node); ok {
return v
}
L.ArgError(1, "node expected")
return nil
}
func newPath(L *lua.LState, p *xmlpath.Path) *lua.LUserData {
ud := L.NewUserData()
ud.Value = &Path{
p,
}
L.SetMetatable(ud, L.GetTypeMetatable(luaPathTypeName))
return ud
}
func checkPath(L *lua.LState) *Path {
ud := L.CheckUserData(1)
if v, ok := ud.Value.(*Path); ok {
return v
}
L.ArgError(1, "path expected")
return nil
}
func newIter(L *lua.LState, i *xmlpath.Iter) *lua.LUserData {
ud := L.NewUserData()
ud.Value = &Iter{
i,
}
L.SetMetatable(ud, L.GetTypeMetatable(luaIterTypeName))
return ud
}
func checkIter(L *lua.LState) *Iter {
ud := L.CheckUserData(1)
if v, ok := ud.Value.(*Iter); ok {
return v
}
L.ArgError(1, "iter expected")
return nil
}
//iter := path.iter(node)
func iter(L *lua.LState) int {
path := checkPath(L)
if L.GetTop() == 2 {
ut := L.CheckUserData(2)
if node, ok := ut.Value.(*Node); ok {
it := path.base.Iter(node.base)
ltab := L.NewTable()
i := 1
for it.Next() {
L.RawSetInt(ltab, i, newNode(L, it.Node()))
i++
}
L.Push(ltab)
//L.Push(newIter(L, it))
return 1
}
}
L.ArgError(1, "node expected")
return 0
}
//support lua standard iterator
//hasNext := iter.next()
// func next(L *lua.LState) int {
// iter := checkIter(L)
// L.Push(lua.LBool(iter.base.Next()))
// return 1
// }
//node := iter.node()
func node(L *lua.LState) int {
iter := checkIter(L)
L.Push(newNode(L, iter.base.Node()))
return 1
}
//string := node.string()
func nodeString(L *lua.LState) int {
node := checkNode(L)
L.Push(lua.LString(node.base.String()))
return 1
}

24
vendor/github.com/cjoudrey/gluahttp/.gitignore generated vendored Normal file
View File

@ -0,0 +1,24 @@
# Compiled Object files, Static and Dynamic libs (Shared Objects)
*.o
*.a
*.so
# Folders
_obj
_test
# Architecture specific extensions/prefixes
*.[568vq]
[568vq].out
*.cgo1.go
*.cgo2.c
_cgo_defun.c
_cgo_gotypes.go
_cgo_export.*
_testmain.go
*.exe
*.test
*.prof

15
vendor/github.com/cjoudrey/gluahttp/.travis.yml generated vendored Normal file
View File

@ -0,0 +1,15 @@
language: go
go:
- 1.4
- 1.5
- 1.6
install:
- go get github.com/yuin/gopher-lua
script:
- go test -v
notifications:
email: false

22
vendor/github.com/cjoudrey/gluahttp/LICENSE generated vendored Normal file
View File

@ -0,0 +1,22 @@
The MIT License (MIT)
Copyright (c) 2015 Christian Joudrey
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.

235
vendor/github.com/cjoudrey/gluahttp/README.md generated vendored Normal file
View File

@ -0,0 +1,235 @@
# gluahttp
[![](https://travis-ci.org/cjoudrey/gluahttp.svg)](https://travis-ci.org/cjoudrey/gluahttp)
gluahttp provides an easy way to make HTTP requests from within [GopherLua](https://github.com/yuin/gopher-lua).
## Installation
```
go get github.com/cjoudrey/gluahttp
```
## Usage
```go
import "github.com/yuin/gopher-lua"
import "github.com/cjoudrey/gluahttp"
func main() {
L := lua.NewState()
defer L.Close()
L.PreloadModule("http", NewHttpModule(&http.Client{}).Loader)
if err := L.DoString(`
local http = require("http")
response, error_message = http.request("GET", "http://example.com", {
query="page=1"
headers={
Accept="*/*"
}
})
`); err != nil {
panic(err)
}
}
```
## API
- [`http.delete(url [, options])`](#httpdeleteurl--options)
- [`http.get(url [, options])`](#httpgeturl--options)
- [`http.head(url [, options])`](#httpheadurl--options)
- [`http.patch(url [, options])`](#httppatchurl--options)
- [`http.post(url [, options])`](#httpposturl--options)
- [`http.put(url [, options])`](#httpputurl--options)
- [`http.request(method, url [, options])`](#httprequestmethod-url--options)
- [`http.request_batch(requests)`](#httprequest_batchrequests)
- [`http.response`](#httpresponse)
### http.delete(url [, options])
**Attributes**
| Name | Type | Description |
| ------- | ------ | ----------- |
| url | String | URL of the resource to load |
| options | Table | Additional options |
**Options**
| Name | Type | Description |
| ------- | ------ | ----------- |
| query | String | URL encoded query params |
| cookies | Table | Additional cookies to send with the request |
| headers | Table | Additional headers to send with the request |
**Returns**
[http.response](#httpresponse) or (nil, error message)
### http.get(url [, options])
**Attributes**
| Name | Type | Description |
| ------- | ------ | ----------- |
| url | String | URL of the resource to load |
| options | Table | Additional options |
**Options**
| Name | Type | Description |
| ------- | ------ | ----------- |
| query | String | URL encoded query params |
| cookies | Table | Additional cookies to send with the request |
| headers | Table | Additional headers to send with the request |
**Returns**
[http.response](#httpresponse) or (nil, error message)
### http.head(url [, options])
**Attributes**
| Name | Type | Description |
| ------- | ------ | ----------- |
| url | String | URL of the resource to load |
| options | Table | Additional options |
**Options**
| Name | Type | Description |
| ------- | ------ | ----------- |
| query | String | URL encoded query params |
| cookies | Table | Additional cookies to send with the request |
| headers | Table | Additional headers to send with the request |
**Returns**
[http.response](#httpresponse) or (nil, error message)
### http.patch(url [, options])
**Attributes**
| Name | Type | Description |
| ------- | ------ | ----------- |
| url | String | URL of the resource to load |
| options | Table | Additional options |
**Options**
| Name | Type | Description |
| ------- | ------ | ----------- |
| query | String | URL encoded query params |
| cookies | Table | Additional cookies to send with the request |
| body | String | Request body. |
| form | String | Deprecated. URL encoded request body. This will also set the `Content-Type` header to `application/x-www-form-urlencoded` |
| headers | Table | Additional headers to send with the request |
**Returns**
[http.response](#httpresponse) or (nil, error message)
### http.post(url [, options])
**Attributes**
| Name | Type | Description |
| ------- | ------ | ----------- |
| url | String | URL of the resource to load |
| options | Table | Additional options |
**Options**
| Name | Type | Description |
| ------- | ------ | ----------- |
| query | String | URL encoded query params |
| cookies | Table | Additional cookies to send with the request |
| body | String | Request body. |
| form | String | Deprecated. URL encoded request body. This will also set the `Content-Type` header to `application/x-www-form-urlencoded` |
| headers | Table | Additional headers to send with the request |
**Returns**
[http.response](#httpresponse) or (nil, error message)
### http.put(url [, options])
**Attributes**
| Name | Type | Description |
| ------- | ------ | ----------- |
| url | String | URL of the resource to load |
| options | Table | Additional options |
**Options**
| Name | Type | Description |
| ------- | ------ | ----------- |
| query | String | URL encoded query params |
| cookies | Table | Additional cookies to send with the request |
| body | String | Request body. |
| form | String | Deprecated. URL encoded request body. This will also set the `Content-Type` header to `application/x-www-form-urlencoded` |
| headers | Table | Additional headers to send with the request |
**Returns**
[http.response](#httpresponse) or (nil, error message)
### http.request(method, url [, options])
**Attributes**
| Name | Type | Description |
| ------- | ------ | ----------- |
| method | String | The HTTP request method |
| url | String | URL of the resource to load |
| options | Table | Additional options |
**Options**
| Name | Type | Description |
| ------- | ------ | ----------- |
| query | String | URL encoded query params |
| cookies | Table | Additional cookies to send with the request |
| body | String | Request body. |
| form | String | Deprecated. URL encoded request body. This will also set the `Content-Type` header to `application/x-www-form-urlencoded` |
| headers | Table | Additional headers to send with the request |
**Returns**
[http.response](#httpresponse) or (nil, error message)
### http.request_batch(requests)
**Attributes**
| Name | Type | Description |
| -------- | ----- | ----------- |
| requests | Table | A table of requests to send. Each request item is by itself a table containing [http.request](#httprequestmethod-url--options) parameters for the request |
**Returns**
[[http.response](#httpresponse)] or ([[http.response](#httpresponse)], [error message])
### http.response
The `http.response` table contains information about a completed HTTP request.
**Attributes**
| Name | Type | Description |
| ----------- | ------ | ----------- |
| body | String | The HTTP response body |
| body_size | Number | The size of the HTTP reponse body in bytes |
| headers | Table | The HTTP response headers |
| cookies | Table | The cookies sent by the server in the HTTP response |
| status_code | Number | The HTTP response status code |
| url | String | The final URL the request ended pointing to after redirects |

212
vendor/github.com/cjoudrey/gluahttp/gluahttp.go generated vendored Normal file
View File

@ -0,0 +1,212 @@
package gluahttp
import "github.com/yuin/gopher-lua"
import "net/http"
import "fmt"
import "errors"
import "io/ioutil"
import "strings"
type httpModule struct {
client *http.Client
}
type empty struct{}
func NewHttpModule(client *http.Client) *httpModule {
return &httpModule{
client: client,
}
}
func (h *httpModule) Loader(L *lua.LState) int {
mod := L.SetFuncs(L.NewTable(), map[string]lua.LGFunction{
"get": h.get,
"delete": h.delete,
"head": h.head,
"patch": h.patch,
"post": h.post,
"put": h.put,
"request": h.request,
"request_batch": h.requestBatch,
})
registerHttpResponseType(mod, L)
L.Push(mod)
return 1
}
func (h *httpModule) get(L *lua.LState) int {
return h.doRequestAndPush(L, "get", L.ToString(1), L.ToTable(2))
}
func (h *httpModule) delete(L *lua.LState) int {
return h.doRequestAndPush(L, "delete", L.ToString(1), L.ToTable(2))
}
func (h *httpModule) head(L *lua.LState) int {
return h.doRequestAndPush(L, "head", L.ToString(1), L.ToTable(2))
}
func (h *httpModule) patch(L *lua.LState) int {
return h.doRequestAndPush(L, "patch", L.ToString(1), L.ToTable(2))
}
func (h *httpModule) post(L *lua.LState) int {
return h.doRequestAndPush(L, "post", L.ToString(1), L.ToTable(2))
}
func (h *httpModule) put(L *lua.LState) int {
return h.doRequestAndPush(L, "put", L.ToString(1), L.ToTable(2))
}
func (h *httpModule) request(L *lua.LState) int {
return h.doRequestAndPush(L, L.ToString(1), L.ToString(2), L.ToTable(3))
}
func (h *httpModule) requestBatch(L *lua.LState) int {
requests := L.ToTable(1)
amountRequests := requests.Len()
errs := make([]error, amountRequests)
responses := make([]*lua.LUserData, amountRequests)
sem := make(chan empty, amountRequests)
i := 0
requests.ForEach(func(_ lua.LValue, value lua.LValue) {
requestTable := toTable(value)
if requestTable != nil {
method := requestTable.RawGet(lua.LNumber(1)).String()
url := requestTable.RawGet(lua.LNumber(2)).String()
options := toTable(requestTable.RawGet(lua.LNumber(3)))
go func(i int, L *lua.LState, method string, url string, options *lua.LTable) {
response, err := h.doRequest(L, method, url, options)
if err == nil {
errs[i] = nil
responses[i] = response
} else {
errs[i] = err
responses[i] = nil
}
sem <- empty{}
}(i, L, method, url, options)
} else {
errs[i] = errors.New("Request must be a table")
responses[i] = nil
sem <- empty{}
}
i = i + 1
})
for i = 0; i < amountRequests; i++ {
<-sem
}
hasErrors := false
errorsTable := L.NewTable()
responsesTable := L.NewTable()
for i = 0; i < amountRequests; i++ {
if errs[i] == nil {
responsesTable.Append(responses[i])
errorsTable.Append(lua.LNil)
} else {
responsesTable.Append(lua.LNil)
errorsTable.Append(lua.LString(fmt.Sprintf("%s", errs[i])))
hasErrors = true
}
}
if hasErrors {
L.Push(responsesTable)
L.Push(errorsTable)
return 2
} else {
L.Push(responsesTable)
return 1
}
}
func (h *httpModule) doRequest(L *lua.LState, method string, url string, options *lua.LTable) (*lua.LUserData, error) {
req, err := http.NewRequest(strings.ToUpper(method), url, nil)
if err != nil {
return nil, err
}
if options != nil {
if reqCookies, ok := options.RawGet(lua.LString("cookies")).(*lua.LTable); ok {
reqCookies.ForEach(func(key lua.LValue, value lua.LValue) {
req.AddCookie(&http.Cookie{Name: key.String(), Value: value.String()})
})
}
switch reqQuery := options.RawGet(lua.LString("query")).(type) {
case lua.LString:
req.URL.RawQuery = reqQuery.String()
}
body := options.RawGet(lua.LString("body"))
if _, ok := body.(lua.LString); !ok {
// "form" is deprecated.
body = options.RawGet(lua.LString("form"))
// Only set the Content-Type to application/x-www-form-urlencoded
// when someone uses "form", not for "body".
if _, ok := body.(lua.LString); ok {
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
}
}
switch reqBody := body.(type) {
case lua.LString:
body := reqBody.String()
req.ContentLength = int64(len(body))
req.Body = ioutil.NopCloser(strings.NewReader(body))
}
// Set these last. That way the code above doesn't overwrite them.
if reqHeaders, ok := options.RawGet(lua.LString("headers")).(*lua.LTable); ok {
reqHeaders.ForEach(func(key lua.LValue, value lua.LValue) {
req.Header.Set(key.String(), value.String())
})
}
}
res, err := h.client.Do(req)
if err != nil {
return nil, err
}
defer res.Body.Close()
body, err := ioutil.ReadAll(res.Body)
if err != nil {
return nil, err
}
return newHttpResponse(res, &body, len(body), L), nil
}
func (h *httpModule) doRequestAndPush(L *lua.LState, method string, url string, options *lua.LTable) int {
response, err := h.doRequest(L, method, url, options)
if err != nil {
L.Push(lua.LNil)
L.Push(lua.LString(fmt.Sprintf("%s", err)))
return 2
}
L.Push(response)
return 1
}
func toTable(v lua.LValue) *lua.LTable {
if lv, ok := v.(*lua.LTable); ok {
return lv
}
return nil
}

433
vendor/github.com/cjoudrey/gluahttp/gluahttp_test.go generated vendored Normal file
View File

@ -0,0 +1,433 @@
package gluahttp
import "github.com/yuin/gopher-lua"
import "testing"
import "io/ioutil"
import "net/http"
import "net"
import "fmt"
import "net/http/cookiejar"
import "strings"
func TestRequestNoMethod(t *testing.T) {
if err := evalLua(t, `
local http = require("http")
response, error = http.request()
assert_equal(nil, response)
assert_contains('unsupported protocol scheme ""', error)
`); err != nil {
t.Errorf("Failed to evaluate script: %s", err)
}
}
func TestRequestNoUrl(t *testing.T) {
if err := evalLua(t, `
local http = require("http")
response, error = http.request("get")
assert_equal(nil, response)
assert_contains('unsupported protocol scheme ""', error)
`); err != nil {
t.Errorf("Failed to evaluate script: %s", err)
}
}
func TestRequestBatch(t *testing.T) {
listener, _ := net.Listen("tcp", "127.0.0.1:0")
setupServer(listener)
if err := evalLua(t, `
local http = require("http")
responses, errors = http.request_batch({
{"get", "http://`+listener.Addr().String()+`", {query="page=1"}},
{"post", "http://`+listener.Addr().String()+`/set_cookie"},
{"post", ""},
1
})
assert_equal(nil, errors[1])
assert_equal(nil, errors[2])
assert_contains('unsupported protocol scheme ""', errors[3])
assert_equal('Request must be a table', errors[4])
assert_equal('Requested GET / with query "page=1"', responses[1]["body"])
assert_equal('Cookie set!', responses[2]["body"])
assert_equal('12345', responses[2]["cookies"]["session_id"])
assert_equal(nil, responses[3])
assert_equal(nil, responses[4])
responses, errors = http.request_batch({
{"get", "http://`+listener.Addr().String()+`/get_cookie"}
})
assert_equal(nil, errors)
assert_equal("session_id=12345", responses[1]["body"])
`); err != nil {
t.Errorf("Failed to evaluate script: %s", err)
}
}
func TestRequestGet(t *testing.T) {
listener, _ := net.Listen("tcp", "127.0.0.1:0")
setupServer(listener)
if err := evalLua(t, `
local http = require("http")
response, error = http.request("get", "http://`+listener.Addr().String()+`")
assert_equal('Requested GET / with query ""', response['body'])
assert_equal(200, response['status_code'])
assert_equal('29', response['headers']['Content-Length'])
assert_equal('text/plain; charset=utf-8', response['headers']['Content-Type'])
`); err != nil {
t.Errorf("Failed to evaluate script: %s", err)
}
}
func TestRequestGetWithRedirect(t *testing.T) {
listener, _ := net.Listen("tcp", "127.0.0.1:0")
setupServer(listener)
if err := evalLua(t, `
local http = require("http")
response, error = http.request("get", "http://`+listener.Addr().String()+`/redirect")
assert_equal('Requested GET / with query ""', response['body'])
assert_equal(200, response['status_code'])
assert_equal('http://`+listener.Addr().String()+`/', response['url'])
`); err != nil {
t.Errorf("Failed to evaluate script: %s", err)
}
}
func TestRequestPostForm(t *testing.T) {
listener, _ := net.Listen("tcp", "127.0.0.1:0")
setupServer(listener)
if err := evalLua(t, `
local http = require("http")
response, error = http.request("post", "http://`+listener.Addr().String()+`", {
form="username=bob&password=secret"
})
assert_equal(
'Requested POST / with query ""' ..
'Content-Type: application/x-www-form-urlencoded' ..
'Content-Length: 28' ..
'Body: username=bob&password=secret', response['body'])
`); err != nil {
t.Errorf("Failed to evaluate script: %s", err)
}
}
func TestRequestHeaders(t *testing.T) {
listener, _ := net.Listen("tcp", "127.0.0.1:0")
setupServer(listener)
if err := evalLua(t, `
local http = require("http")
response, error = http.request("post", "http://`+listener.Addr().String()+`", {
headers={
["Content-Type"]="application/json"
}
})
assert_equal(
'Requested POST / with query ""' ..
'Content-Type: application/json' ..
'Content-Length: 0' ..
'Body: ', response['body'])
`); err != nil {
t.Errorf("Failed to evaluate script: %s", err)
}
}
func TestRequestQuery(t *testing.T) {
listener, _ := net.Listen("tcp", "127.0.0.1:0")
setupServer(listener)
if err := evalLua(t, `
local http = require("http")
response, error = http.request("get", "http://`+listener.Addr().String()+`", {
query="page=2"
})
assert_equal('Requested GET / with query "page=2"', response['body'])
`); err != nil {
t.Errorf("Failed to evaluate script: %s", err)
}
}
func TestGet(t *testing.T) {
listener, _ := net.Listen("tcp", "127.0.0.1:0")
setupServer(listener)
if err := evalLua(t, `
local http = require("http")
response, error = http.get("http://`+listener.Addr().String()+`", {
query="page=1"
})
assert_equal('Requested GET / with query "page=1"', response['body'])
assert_equal(200, response['status_code'])
assert_equal('35', response['headers']['Content-Length'])
assert_equal('text/plain; charset=utf-8', response['headers']['Content-Type'])
`); err != nil {
t.Errorf("Failed to evaluate script: %s", err)
}
}
func TestDelete(t *testing.T) {
listener, _ := net.Listen("tcp", "127.0.0.1:0")
setupServer(listener)
if err := evalLua(t, `
local http = require("http")
response, error = http.delete("http://`+listener.Addr().String()+`", {
query="page=1"
})
assert_equal('Requested DELETE / with query "page=1"', response['body'])
assert_equal(200, response['status_code'])
assert_equal('38', response['headers']['Content-Length'])
assert_equal('text/plain; charset=utf-8', response['headers']['Content-Type'])
`); err != nil {
t.Errorf("Failed to evaluate script: %s", err)
}
}
func TestHead(t *testing.T) {
listener, _ := net.Listen("tcp", "127.0.0.1:0")
setupServer(listener)
if err := evalLua(t, `
local http = require("http")
response, error = http.head("http://`+listener.Addr().String()+`/head", {
query="page=1"
})
assert_equal(200, response['status_code'])
assert_equal("/head?page=1", response['headers']['X-Request-Uri'])
`); err != nil {
t.Errorf("Failed to evaluate script: %s", err)
}
}
func TestPost(t *testing.T) {
listener, _ := net.Listen("tcp", "127.0.0.1:0")
setupServer(listener)
if err := evalLua(t, `
local http = require("http")
response, error = http.post("http://`+listener.Addr().String()+`", {
body="username=bob&password=secret"
})
assert_equal(
'Requested POST / with query ""' ..
'Content-Type: ' ..
'Content-Length: 28' ..
'Body: username=bob&password=secret', response['body'])
`); err != nil {
t.Errorf("Failed to evaluate script: %s", err)
}
}
func TestPatch(t *testing.T) {
listener, _ := net.Listen("tcp", "127.0.0.1:0")
setupServer(listener)
if err := evalLua(t, `
local http = require("http")
response, error = http.patch("http://`+listener.Addr().String()+`", {
body='{"username":"bob"}',
headers={
["Content-Type"]="application/json"
}
})
assert_equal(
'Requested PATCH / with query ""' ..
'Content-Type: application/json' ..
'Content-Length: 18' ..
'Body: {"username":"bob"}', response['body'])
`); err != nil {
t.Errorf("Failed to evaluate script: %s", err)
}
}
func TestPut(t *testing.T) {
listener, _ := net.Listen("tcp", "127.0.0.1:0")
setupServer(listener)
if err := evalLua(t, `
local http = require("http")
response, error = http.put("http://`+listener.Addr().String()+`", {
body="username=bob&password=secret",
headers={
["Content-Type"]="application/x-www-form-urlencoded"
}
})
assert_equal(
'Requested PUT / with query ""' ..
'Content-Type: application/x-www-form-urlencoded' ..
'Content-Length: 28' ..
'Body: username=bob&password=secret', response['body'])
`); err != nil {
t.Errorf("Failed to evaluate script: %s", err)
}
}
func TestResponseCookies(t *testing.T) {
listener, _ := net.Listen("tcp", "127.0.0.1:0")
setupServer(listener)
if err := evalLua(t, `
local http = require("http")
response, error = http.get("http://`+listener.Addr().String()+`/set_cookie")
assert_equal('Cookie set!', response["body"])
assert_equal('12345', response["cookies"]["session_id"])
`); err != nil {
t.Errorf("Failed to evaluate script: %s", err)
}
}
func TestRequestCookies(t *testing.T) {
listener, _ := net.Listen("tcp", "127.0.0.1:0")
setupServer(listener)
if err := evalLua(t, `
local http = require("http")
response, error = http.get("http://`+listener.Addr().String()+`/get_cookie", {
cookies={
["session_id"]="test"
}
})
assert_equal('session_id=test', response["body"])
assert_equal(15, response["body_size"])
`); err != nil {
t.Errorf("Failed to evaluate script: %s", err)
}
}
func TestResponseBodySize(t *testing.T) {
listener, _ := net.Listen("tcp", "127.0.0.1:0")
setupServer(listener)
if err := evalLua(t, `
local http = require("http")
response, error = http.get("http://`+listener.Addr().String()+`/")
assert_equal(29, response["body_size"])
`); err != nil {
t.Errorf("Failed to evaluate script: %s", err)
}
}
func TestResponseBody(t *testing.T) {
listener, _ := net.Listen("tcp", "127.0.0.1:0")
setupServer(listener)
if err := evalLua(t, `
local http = require("http")
response, error = http.get("http://`+listener.Addr().String()+`/")
assert_equal("Requested XXX / with query \"\"", string.gsub(response.body, "GET", "XXX"))
`); err != nil {
t.Errorf("Failed to evaluate script: %s", err)
}
}
func TestResponseUrl(t *testing.T) {
listener, _ := net.Listen("tcp", "127.0.0.1:0")
setupServer(listener)
if err := evalLua(t, `
local http = require("http")
response, error = http.get("http://`+listener.Addr().String()+`/redirect")
assert_equal("http://`+listener.Addr().String()+`/", response["url"])
response, error = http.get("http://`+listener.Addr().String()+`/get_cookie")
assert_equal("http://`+listener.Addr().String()+`/get_cookie", response["url"])
`); err != nil {
t.Errorf("Failed to evaluate script: %s", err)
}
}
func evalLua(t *testing.T, script string) error {
L := lua.NewState()
defer L.Close()
cookieJar, _ := cookiejar.New(nil)
L.PreloadModule("http", NewHttpModule(&http.Client{
Jar: cookieJar,
},
).Loader)
L.SetGlobal("assert_equal", L.NewFunction(func(L *lua.LState) int {
expected := L.Get(1)
actual := L.Get(2)
if expected.Type() != actual.Type() || expected.String() != actual.String() {
t.Errorf("Expected %s %q, got %s %q", expected.Type(), expected, actual.Type(), actual)
}
return 0
}))
L.SetGlobal("assert_contains", L.NewFunction(func(L *lua.LState) int {
contains := L.Get(1)
actual := L.Get(2)
if !strings.Contains(actual.String(), contains.String()) {
t.Errorf("Expected %s %q contains %s %q", actual.Type(), actual, contains.Type(), contains)
}
return 0
}))
return L.DoString(script)
}
func setupServer(listener net.Listener) {
mux := http.NewServeMux()
mux.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
fmt.Fprintf(w, "Requested %s / with query %q", req.Method, req.URL.RawQuery)
if req.Method == "POST" || req.Method == "PATCH" || req.Method == "PUT" {
body, _ := ioutil.ReadAll(req.Body)
fmt.Fprintf(w, "Content-Type: %s", req.Header.Get("Content-Type"))
fmt.Fprintf(w, "Content-Length: %s", req.Header.Get("Content-Length"))
fmt.Fprintf(w, "Body: %s", body)
}
})
mux.HandleFunc("/head", func(w http.ResponseWriter, req *http.Request) {
if req.Method == "HEAD" {
w.Header().Set("X-Request-Uri", req.URL.String())
w.WriteHeader(http.StatusOK)
} else {
w.WriteHeader(http.StatusNotFound)
}
})
mux.HandleFunc("/set_cookie", func(w http.ResponseWriter, req *http.Request) {
http.SetCookie(w, &http.Cookie{Name: "session_id", Value: "12345"})
fmt.Fprint(w, "Cookie set!")
})
mux.HandleFunc("/get_cookie", func(w http.ResponseWriter, req *http.Request) {
session_id, _ := req.Cookie("session_id")
fmt.Fprint(w, session_id)
})
mux.HandleFunc("/redirect", func(w http.ResponseWriter, req *http.Request) {
http.Redirect(w, req, "/", http.StatusFound)
})
s := &http.Server{
Handler: mux,
}
go s.Serve(listener)
}

View File

@ -0,0 +1,98 @@
package gluahttp
import "github.com/yuin/gopher-lua"
import "net/http"
const luaHttpResponseTypeName = "http.response"
type luaHttpResponse struct {
res *http.Response
body lua.LString
bodySize int
}
func registerHttpResponseType(module *lua.LTable, L *lua.LState) {
mt := L.NewTypeMetatable(luaHttpResponseTypeName)
L.SetField(mt, "__index", L.NewFunction(httpResponseIndex))
L.SetField(module, "response", mt)
}
func newHttpResponse(res *http.Response, body *[]byte, bodySize int, L *lua.LState) *lua.LUserData {
ud := L.NewUserData()
ud.Value = &luaHttpResponse{
res: res,
body: lua.LString(*body),
bodySize: bodySize,
}
L.SetMetatable(ud, L.GetTypeMetatable(luaHttpResponseTypeName))
return ud
}
func checkHttpResponse(L *lua.LState) *luaHttpResponse {
ud := L.CheckUserData(1)
if v, ok := ud.Value.(*luaHttpResponse); ok {
return v
}
L.ArgError(1, "http.response expected")
return nil
}
func httpResponseIndex(L *lua.LState) int {
res := checkHttpResponse(L)
switch L.CheckString(2) {
case "headers":
return httpResponseHeaders(res, L)
case "cookies":
return httpResponseCookies(res, L)
case "status_code":
return httpResponseStatusCode(res, L)
case "url":
return httpResponseUrl(res, L)
case "body":
return httpResponseBody(res, L)
case "body_size":
return httpResponseBodySize(res, L)
}
return 0
}
func httpResponseHeaders(res *luaHttpResponse, L *lua.LState) int {
headers := L.NewTable()
for key, _ := range res.res.Header {
headers.RawSetString(key, lua.LString(res.res.Header.Get(key)))
}
L.Push(headers)
return 1
}
func httpResponseCookies(res *luaHttpResponse, L *lua.LState) int {
cookies := L.NewTable()
for _, cookie := range res.res.Cookies() {
cookies.RawSetString(cookie.Name, lua.LString(cookie.Value))
}
L.Push(cookies)
return 1
}
func httpResponseStatusCode(res *luaHttpResponse, L *lua.LState) int {
L.Push(lua.LNumber(res.res.StatusCode))
return 1
}
func httpResponseUrl(res *luaHttpResponse, L *lua.LState) int {
L.Push(lua.LString(res.res.Request.URL.String()))
return 1
}
func httpResponseBody(res *luaHttpResponse, L *lua.LState) int {
L.Push(res.body)
return 1
}
func httpResponseBodySize(res *luaHttpResponse, L *lua.LState) int {
L.Push(lua.LNumber(res.bodySize))
return 1
}

24
vendor/github.com/cjoudrey/gluaurl/.gitignore generated vendored Normal file
View File

@ -0,0 +1,24 @@
# Compiled Object files, Static and Dynamic libs (Shared Objects)
*.o
*.a
*.so
# Folders
_obj
_test
# Architecture specific extensions/prefixes
*.[568vq]
[568vq].out
*.cgo1.go
*.cgo2.c
_cgo_defun.c
_cgo_gotypes.go
_cgo_export.*
_testmain.go
*.exe
*.test
*.prof

14
vendor/github.com/cjoudrey/gluaurl/.travis.yml generated vendored Normal file
View File

@ -0,0 +1,14 @@
language: go
go:
- 1.3
- 1.4
install:
- go get github.com/yuin/gopher-lua
script:
- go test -v
notifications:
email: false

22
vendor/github.com/cjoudrey/gluaurl/LICENSE generated vendored Normal file
View File

@ -0,0 +1,22 @@
The MIT License (MIT)
Copyright (c) 2015 Christian Joudrey
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.

109
vendor/github.com/cjoudrey/gluaurl/README.md generated vendored Normal file
View File

@ -0,0 +1,109 @@
# gluaurl
[![](https://travis-ci.org/cjoudrey/gluaurl.svg)](https://travis-ci.org/cjoudrey/gluaurl)
gluahttp provides an easy way to parse and build URLs from within [GopherLua](https://github.com/yuin/gopher-lua).
## Installation
```
go get github.com/cjoudrey/gluaurl
```
## Usage
```go
import "github.com/yuin/gopher-lua"
import "github.com/cjoudrey/gluaurl"
func main() {
L := lua.NewState()
defer L.Close()
L.PreloadModule("url", gluaurl.Loader)
if err := L.DoString(`
local url = require("url")
parsed_url = url.parse("http://example.com/")
print(parsed_url.host)
`); err != nil {
panic(err)
}
}
```
## API
- [`url.parse(url)`](#urlparseurl)
- [`url.build(options)`](#urlbuildoptions)
- [`url.build_query_string(query_params)`](#urlbuild_query_stringquery_params)
- [`url.resolve(from, to)`](#urlresolvefrom-to)
### url.parse(url)
Parse URL into a table of key/value components.
**Attributes**
| Name | Type | Description |
| ------- | ------ | ----------- |
| url | String | URL to parsed |
**Returns**
Table with parsed URL or (nil, error message)
| Name | Type | Description |
| -------- | ------ | ----------- |
| scheme | String | Scheme of the URL |
| username | String | Username |
| password | String | Password |
| host | String | Host and port of the URL |
| path | String | Path |
| query | String | Query string |
| fragment | String | Fragment |
### url.build(options)
Assemble a URL string from a table of URL components.
**Attributes**
| Name | Type | Description |
| ------- | ----- | ----------- |
| options | Table | Table with URL components, see [`url.parse`](#urlparseurl) for list of valid components |
**Returns**
String
### url.build_query_string(query_params)
Assemble table of query string parameters into a string.
**Attributes**
| Name | Type | Description |
| ------------ | ----- | ----------- |
| query_params | Table | Table with query parameters |
**Returns**
String
### url.resolve(from, to)
Take a base URL, and a href URL, and resolve them as a browser would for an anchor tag.
| Name | Type | Description |
| ---- | ------ | ----------- |
| from | String | base URL |
| to | String | href URL |
**Returns**
String or (nil, error message)

178
vendor/github.com/cjoudrey/gluaurl/gluaurl.go generated vendored Normal file
View File

@ -0,0 +1,178 @@
package gluaurl
import "github.com/yuin/gopher-lua"
import "net/url"
import "strings"
import "fmt"
import "sort"
import "regexp"
var rBracket = regexp.MustCompile("\\[\\]$")
func Loader(L *lua.LState) int {
mod := L.SetFuncs(L.NewTable(), map[string]lua.LGFunction{
"parse": parse,
"build": build,
"build_query_string": buildQueryString,
"resolve": resolve,
})
L.Push(mod)
return 1
}
func parse(L *lua.LState) int {
parsed := L.NewTable()
url, err := url.Parse(L.CheckString(1))
if err != nil {
L.Push(lua.LNil)
L.Push(lua.LString(fmt.Sprintf("%s", err)))
return 2
}
parsed.RawSetString("scheme", lua.LString(url.Scheme))
if url.User != nil {
parsed.RawSetString("username", lua.LString(url.User.Username()))
if password, hasPassword := url.User.Password(); hasPassword {
parsed.RawSetString("password", lua.LString(password))
} else {
parsed.RawSetString("password", lua.LNil)
}
} else {
parsed.RawSetString("username", lua.LNil)
parsed.RawSetString("password", lua.LNil)
}
parsed.RawSetString("host", lua.LString(url.Host))
parsed.RawSetString("path", lua.LString(url.Path))
parsed.RawSetString("query", lua.LString(url.RawQuery))
parsed.RawSetString("fragment", lua.LString(url.Fragment))
L.Push(parsed)
return 1
}
func build(L *lua.LState) int {
options := L.CheckTable(1)
buildUrl := url.URL{}
if scheme := options.RawGetString("scheme"); scheme != lua.LNil {
buildUrl.Scheme = scheme.String()
}
if username := options.RawGetString("username"); username != lua.LNil {
if password := options.RawGetString("password"); password != lua.LNil {
buildUrl.User = url.UserPassword(username.String(), password.String())
} else {
buildUrl.User = url.User(username.String())
}
}
if host := options.RawGetString("host"); host != lua.LNil {
buildUrl.Host = host.String()
}
if path := options.RawGetString("path"); path != lua.LNil {
buildUrl.Path = path.String()
}
if query := options.RawGetString("query"); query != lua.LNil {
buildUrl.RawQuery = query.String()
}
if fragment := options.RawGetString("fragment"); fragment != lua.LNil {
buildUrl.Fragment = fragment.String()
}
L.Push(lua.LString(buildUrl.String()))
return 1
}
func buildQueryString(L *lua.LState) int {
options := L.CheckTable(1)
ret := make([]string, 0)
options.ForEach(func(key, value lua.LValue) {
toQueryString(key.String(), value, &ret)
})
sort.Strings(ret)
L.Push(lua.LString(strings.Join(ret, "&")))
return 1
}
func toQueryString(prefix string, lv lua.LValue, ret *[]string) {
switch v := lv.(type) {
case lua.LBool:
*ret = append(*ret, url.QueryEscape(prefix)+"="+v.String())
break
case lua.LNumber:
*ret = append(*ret, url.QueryEscape(prefix)+"="+v.String())
break
case lua.LString:
*ret = append(*ret, url.QueryEscape(prefix)+"="+url.QueryEscape(v.String()))
break
case *lua.LTable:
maxn := v.MaxN()
if maxn == 0 {
ret2 := make([]string, 0)
v.ForEach(func(key lua.LValue, value lua.LValue) {
toQueryString(prefix+"["+key.String()+"]", value, &ret2)
})
sort.Strings(ret2)
*ret = append(*ret, strings.Join(ret2, "&"))
} else {
ret2 := make([]string, 0)
for i := 1; i <= maxn; i++ {
vi := v.RawGetInt(i)
if rBracket.MatchString(prefix) {
ret2 = append(ret2, url.QueryEscape(prefix)+"="+vi.String())
} else {
if vi.Type() == lua.LTTable {
toQueryString(fmt.Sprintf("%s[%d]", prefix, i-1), vi, &ret2)
} else {
toQueryString(prefix+"[]", vi, &ret2)
}
}
}
*ret = append(*ret, strings.Join(ret2, "&"))
}
break
}
}
func resolve(L *lua.LState) int {
from := L.CheckString(1)
to := L.CheckString(2)
fromUrl, err := url.Parse(from)
if err != nil {
L.Push(lua.LNil)
L.Push(lua.LString(fmt.Sprintf("%s", err)))
return 2
}
toUrl, err := url.Parse(to)
if err != nil {
L.Push(lua.LNil)
L.Push(lua.LString(fmt.Sprintf("%s", err)))
return 2
}
resolvedUrl := fromUrl.ResolveReference(toUrl).String()
L.Push(lua.LString(resolvedUrl))
return 1
}

250
vendor/github.com/cjoudrey/gluaurl/gluaurl_test.go generated vendored Normal file
View File

@ -0,0 +1,250 @@
package gluaurl
import "github.com/yuin/gopher-lua"
import "testing"
import "os"
import "bytes"
import "io"
import "strings"
func TestParse(t *testing.T) {
output, err := evalScript(`
local url = require("url")
parsed = url.parse("http://bob:secret@example.com:8080/products?page=2#something")
print(parsed.scheme)
print(parsed.username)
print(parsed.password)
print(parsed.host)
print(parsed.path)
print(parsed.query)
print(parsed.fragment)
`)
if err != nil {
t.Errorf("Failed to evaluate script: %s", err)
} else {
if expected := `http
bob
secret
example.com:8080
/products
page=2
something
`; expected != output {
t.Errorf("Expected output does not match actual output\nExpected: %s\nActual: %s", expected, output)
}
}
}
func TestParseOnlyHost(t *testing.T) {
output, err := evalScript(`
local url = require("url")
parsed = url.parse("https://example.com")
print(parsed.scheme)
print(parsed.username)
print(parsed.password)
print(parsed.host)
print(parsed.path)
print(parsed.query)
print(parsed.fragment)
`)
if err != nil {
t.Errorf("Failed to evaluate script: %s", err)
} else {
if expected := `https
nil
nil
example.com
`; expected != output {
t.Errorf("Expected output does not match actual output\nExpected: %s\nActual: %s", expected, output)
}
}
}
func TestBuild(t *testing.T) {
output, err := evalScript(`
local url = require("url")
built = url.build({
scheme="https",
username="bob",
password="secret",
host="example.com:8080",
path="/products",
query="page=2",
fragment="something"
})
print(built)
`)
if err != nil {
t.Errorf("Failed to evaluate script: %s", err)
} else {
if expected := `https://bob:secret@example.com:8080/products?page=2#something
`; expected != output {
t.Errorf("Expected output does not match actual output\nExpected: %s\nActual: %s", expected, output)
}
}
}
func TestBuildEmpty(t *testing.T) {
output, err := evalScript(`
local url = require("url")
built = url.build({})
print(built)
`)
if err != nil {
t.Errorf("Failed to evaluate script: %s", err)
} else {
if expected := `
`; expected != output {
t.Errorf("Expected output does not match actual output\nExpected: %s\nActual: %s", expected, output)
}
}
}
func TestBuildQueryString(t *testing.T) {
output, err := evalScript(`
local url = require("url")
function assert_query_string(options, expected, message)
actual = url.build_query_string(options)
if expected ~= actual then
print("Failed to build '" .. message .. "'")
print("Expected:")
print(expected)
print("Actual:")
print(actual)
end
end
assert_query_string(
{foo="bar", baz=42, quux="All your base are belong to us"},
"baz=42&foo=bar&quux=All+your+base+are+belong+to+us",
"simple"
)
assert_query_string(
{someName={1, 2, 3}, regularThing="blah"},
"regularThing=blah&someName%5B%5D=1&someName%5B%5D=2&someName%5B%5D=3",
"with array"
)
assert_query_string(
{foo={"a", "b", "c"}},
"foo%5B%5D=a&foo%5B%5D=b&foo%5B%5D=c",
"with array of strings"
)
assert_query_string(
{foo={"baz", 42, "All your base are belong to us"}},
"foo%5B%5D=baz&foo%5B%5D=42&foo%5B%5D=All+your+base+are+belong+to+us",
"more array"
)
assert_query_string(
{foo={bar="baz", beep=42, quux="All your base are belong to us"}},
"foo%5Bbar%5D=baz&foo%5Bbeep%5D=42&foo%5Bquux%5D=All+your+base+are+belong+to+us",
"even more arrays"
)
assert_query_string(
{a={1,2}, b={c=3, d={4,5}, e={ x={6}, y=7, z={8,9} }, f=true, g=false, h=""}, i={10,11}, j=true, k=false, l={"",0}, m="cowboy hat?" },
"a%5B%5D=1&a%5B%5D=2&b%5Bc%5D=3&b%5Bd%5D%5B%5D=4&b%5Bd%5D%5B%5D=5&b%5Be%5D%5Bx%5D%5B%5D=6&b%5Be%5D%5By%5D=7&b%5Be%5D%5Bz%5D%5B%5D=8&b%5Be%5D%5Bz%5D%5B%5D=9&b%5Bf%5D=true&b%5Bg%5D=false&b%5Bh%5D=&i%5B%5D=10&i%5B%5D=11&j=true&k=false&l%5B%5D=&l%5B%5D=0&m=cowboy+hat%3F",
"huge structure"
)
assert_query_string(
{ a={0, { 1, 2 }, { 3, { 4, 5 }, { 6 } }, { b= { 7, { 8, 9 }, { { c=10, d=11 } }, { { 12 } }, { { { 13 } } }, { e= { f= { g={ 14, { 15 } } } } }, 16 } }, 17 } },
"a%5B%5D=0&a%5B1%5D%5B%5D=1&a%5B1%5D%5B%5D=2&a%5B2%5D%5B%5D=3&a%5B2%5D%5B1%5D%5B%5D=4&a%5B2%5D%5B1%5D%5B%5D=5&a%5B2%5D%5B2%5D%5B%5D=6&a%5B3%5D%5Bb%5D%5B%5D=7&a%5B3%5D%5Bb%5D%5B1%5D%5B%5D=8&a%5B3%5D%5Bb%5D%5B1%5D%5B%5D=9&a%5B3%5D%5Bb%5D%5B2%5D%5B0%5D%5Bc%5D=10&a%5B3%5D%5Bb%5D%5B2%5D%5B0%5D%5Bd%5D=11&a%5B3%5D%5Bb%5D%5B3%5D%5B0%5D%5B%5D=12&a%5B3%5D%5Bb%5D%5B4%5D%5B0%5D%5B0%5D%5B%5D=13&a%5B3%5D%5Bb%5D%5B5%5D%5Be%5D%5Bf%5D%5Bg%5D%5B%5D=14&a%5B3%5D%5Bb%5D%5B5%5D%5Be%5D%5Bf%5D%5Bg%5D%5B1%5D%5B%5D=15&a%5B3%5D%5Bb%5D%5B%5D=16&a%5B%5D=17",
"nested arrays"
)
assert_query_string(
{ a= {1,2,3}, ["b[]"]= {4,5,6}, ["c[d]"]= {7,8,9}, e= { f= {10}, g= {11,12}, h= 13 } },
"a%5B%5D=1&a%5B%5D=2&a%5B%5D=3&b%5B%5D=4&b%5B%5D=5&b%5B%5D=6&c%5Bd%5D%5B%5D=7&c%5Bd%5D%5B%5D=8&c%5Bd%5D%5B%5D=9&e%5Bf%5D%5B%5D=10&e%5Bg%5D%5B%5D=11&e%5Bg%5D%5B%5D=12&e%5Bh%5D=13",
"make sure params are not double-encoded"
)
`)
if err != nil {
t.Errorf("Failed to evaluate script: %s", err)
} else {
if expected := ``; expected != output {
t.Error(output)
}
}
}
func TestResolve(t *testing.T) {
output, err := evalScript(`
local url = require("url")
print(url.resolve('/one/two/three', 'four'))
print(url.resolve('http://example.com/', '/one'))
print(url.resolve('http://example.com/one', '/two'))
print(url.resolve('https://example.com/one', '//example2.com'))
`)
if err != nil {
t.Errorf("Failed to evaluate script: %s", err)
} else {
if expected := `/one/two/four
http://example.com/one
http://example.com/two
https://example2.com
`; expected != output {
t.Errorf("Expected output does not match actual output\nExpected: %s\nActual: %s", expected, output)
}
}
}
func evalScript(script string) (string, error) {
L := lua.NewState()
defer L.Close()
L.PreloadModule("url", Loader)
var err error
out := captureStdout(func() {
err = L.DoString(script)
})
return out, err
}
func captureStdout(inner func()) string {
oldStdout := os.Stdout
r, w, _ := os.Pipe()
os.Stdout = w
outC := make(chan string)
go func() {
var buf bytes.Buffer
io.Copy(&buf, r)
outC <- buf.String()
}()
inner()
w.Close()
os.Stdout = oldStdout
out := strings.Replace(<-outC, "\r", "", -1)
return out
}

11
vendor/github.com/howeyc/gopass/.travis.yml generated vendored Normal file
View File

@ -0,0 +1,11 @@
language: go
os:
- linux
- osx
go:
- 1.3
- 1.4
- 1.5
- tip

15
vendor/github.com/howeyc/gopass/LICENSE.txt generated vendored Normal file
View File

@ -0,0 +1,15 @@
ISC License
Copyright (c) 2012 Chris Howey
Permission to use, copy, modify, and 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.

384
vendor/github.com/howeyc/gopass/OPENSOLARIS.LICENSE generated vendored Normal file
View File

@ -0,0 +1,384 @@
Unless otherwise noted, all files in this distribution are released
under the Common Development and Distribution License (CDDL).
Exceptions are noted within the associated source files.
--------------------------------------------------------------------
COMMON DEVELOPMENT AND DISTRIBUTION LICENSE Version 1.0
1. Definitions.
1.1. "Contributor" means each individual or entity that creates
or contributes to the creation of Modifications.
1.2. "Contributor Version" means the combination of the Original
Software, prior Modifications used by a Contributor (if any),
and the Modifications made by that particular Contributor.
1.3. "Covered Software" means (a) the Original Software, or (b)
Modifications, or (c) the combination of files containing
Original Software with files containing Modifications, in
each case including portions thereof.
1.4. "Executable" means the Covered Software in any form other
than Source Code.
1.5. "Initial Developer" means the individual or entity that first
makes Original Software available under this License.
1.6. "Larger Work" means a work which combines Covered Software or
portions thereof with code not governed by the terms of this
License.
1.7. "License" means this document.
1.8. "Licensable" means having the right to grant, to the maximum
extent possible, whether at the time of the initial grant or
subsequently acquired, any and all of the rights conveyed
herein.
1.9. "Modifications" means the Source Code and Executable form of
any of the following:
A. Any file that results from an addition to, deletion from or
modification of the contents of a file containing Original
Software or previous Modifications;
B. Any new file that contains any part of the Original
Software or previous Modifications; or
C. Any new file that is contributed or otherwise made
available under the terms of this License.
1.10. "Original Software" means the Source Code and Executable
form of computer software code that is originally released
under this License.
1.11. "Patent Claims" means any patent claim(s), now owned or
hereafter acquired, including without limitation, method,
process, and apparatus claims, in any patent Licensable by
grantor.
1.12. "Source Code" means (a) the common form of computer software
code in which modifications are made and (b) associated
documentation included in or with such code.
1.13. "You" (or "Your") means an individual or a legal entity
exercising rights under, and complying with all of the terms
of, this License. For legal entities, "You" includes any
entity which controls, is controlled by, or is under common
control with You. For purposes of this definition,
"control" means (a) the power, direct or indirect, to cause
the direction or management of such entity, whether by
contract or otherwise, or (b) ownership of more than fifty
percent (50%) of the outstanding shares or beneficial
ownership of such entity.
2. License Grants.
2.1. The Initial Developer Grant.
Conditioned upon Your compliance with Section 3.1 below and
subject to third party intellectual property claims, the Initial
Developer hereby grants You a world-wide, royalty-free,
non-exclusive license:
(a) under intellectual property rights (other than patent or
trademark) Licensable by Initial Developer, to use,
reproduce, modify, display, perform, sublicense and
distribute the Original Software (or portions thereof),
with or without Modifications, and/or as part of a Larger
Work; and
(b) under Patent Claims infringed by the making, using or
selling of Original Software, to make, have made, use,
practice, sell, and offer for sale, and/or otherwise
dispose of the Original Software (or portions thereof).
(c) The licenses granted in Sections 2.1(a) and (b) are
effective on the date Initial Developer first distributes
or otherwise makes the Original Software available to a
third party under the terms of this License.
(d) Notwithstanding Section 2.1(b) above, no patent license is
granted: (1) for code that You delete from the Original
Software, or (2) for infringements caused by: (i) the
modification of the Original Software, or (ii) the
combination of the Original Software with other software
or devices.
2.2. Contributor Grant.
Conditioned upon Your compliance with Section 3.1 below and
subject to third party intellectual property claims, each
Contributor hereby grants You a world-wide, royalty-free,
non-exclusive license:
(a) under intellectual property rights (other than patent or
trademark) Licensable by Contributor to use, reproduce,
modify, display, perform, sublicense and distribute the
Modifications created by such Contributor (or portions
thereof), either on an unmodified basis, with other
Modifications, as Covered Software and/or as part of a
Larger Work; and
(b) under Patent Claims infringed by the making, using, or
selling of Modifications made by that Contributor either
alone and/or in combination with its Contributor Version
(or portions of such combination), to make, use, sell,
offer for sale, have made, and/or otherwise dispose of:
(1) Modifications made by that Contributor (or portions
thereof); and (2) the combination of Modifications made by
that Contributor with its Contributor Version (or portions
of such combination).
(c) The licenses granted in Sections 2.2(a) and 2.2(b) are
effective on the date Contributor first distributes or
otherwise makes the Modifications available to a third
party.
(d) Notwithstanding Section 2.2(b) above, no patent license is
granted: (1) for any code that Contributor has deleted
from the Contributor Version; (2) for infringements caused
by: (i) third party modifications of Contributor Version,
or (ii) the combination of Modifications made by that
Contributor with other software (except as part of the
Contributor Version) or other devices; or (3) under Patent
Claims infringed by Covered Software in the absence of
Modifications made by that Contributor.
3. Distribution Obligations.
3.1. Availability of Source Code.
Any Covered Software that You distribute or otherwise make
available in Executable form must also be made available in Source
Code form and that Source Code form must be distributed only under
the terms of this License. You must include a copy of this
License with every copy of the Source Code form of the Covered
Software You distribute or otherwise make available. You must
inform recipients of any such Covered Software in Executable form
as to how they can obtain such Covered Software in Source Code
form in a reasonable manner on or through a medium customarily
used for software exchange.
3.2. Modifications.
The Modifications that You create or to which You contribute are
governed by the terms of this License. You represent that You
believe Your Modifications are Your original creation(s) and/or
You have sufficient rights to grant the rights conveyed by this
License.
3.3. Required Notices.
You must include a notice in each of Your Modifications that
identifies You as the Contributor of the Modification. You may
not remove or alter any copyright, patent or trademark notices
contained within the Covered Software, or any notices of licensing
or any descriptive text giving attribution to any Contributor or
the Initial Developer.
3.4. Application of Additional Terms.
You may not offer or impose any terms on any Covered Software in
Source Code form that alters or restricts the applicable version
of this License or the recipients' rights hereunder. You may
choose to offer, and to charge a fee for, warranty, support,
indemnity or liability obligations to one or more recipients of
Covered Software. However, you may do so only on Your own behalf,
and not on behalf of the Initial Developer or any Contributor.
You must make it absolutely clear that any such warranty, support,
indemnity or liability obligation is offered by You alone, and You
hereby agree to indemnify the Initial Developer and every
Contributor for any liability incurred by the Initial Developer or
such Contributor as a result of warranty, support, indemnity or
liability terms You offer.
3.5. Distribution of Executable Versions.
You may distribute the Executable form of the Covered Software
under the terms of this License or under the terms of a license of
Your choice, which may contain terms different from this License,
provided that You are in compliance with the terms of this License
and that the license for the Executable form does not attempt to
limit or alter the recipient's rights in the Source Code form from
the rights set forth in this License. If You distribute the
Covered Software in Executable form under a different license, You
must make it absolutely clear that any terms which differ from
this License are offered by You alone, not by the Initial
Developer or Contributor. You hereby agree to indemnify the
Initial Developer and every Contributor for any liability incurred
by the Initial Developer or such Contributor as a result of any
such terms You offer.
3.6. Larger Works.
You may create a Larger Work by combining Covered Software with
other code not governed by the terms of this License and
distribute the Larger Work as a single product. In such a case,
You must make sure the requirements of this License are fulfilled
for the Covered Software.
4. Versions of the License.
4.1. New Versions.
Sun Microsystems, Inc. is the initial license steward and may
publish revised and/or new versions of this License from time to
time. Each version will be given a distinguishing version number.
Except as provided in Section 4.3, no one other than the license
steward has the right to modify this License.
4.2. Effect of New Versions.
You may always continue to use, distribute or otherwise make the
Covered Software available under the terms of the version of the
License under which You originally received the Covered Software.
If the Initial Developer includes a notice in the Original
Software prohibiting it from being distributed or otherwise made
available under any subsequent version of the License, You must
distribute and make the Covered Software available under the terms
of the version of the License under which You originally received
the Covered Software. Otherwise, You may also choose to use,
distribute or otherwise make the Covered Software available under
the terms of any subsequent version of the License published by
the license steward.
4.3. Modified Versions.
When You are an Initial Developer and You want to create a new
license for Your Original Software, You may create and use a
modified version of this License if You: (a) rename the license
and remove any references to the name of the license steward
(except to note that the license differs from this License); and
(b) otherwise make it clear that the license contains terms which
differ from this License.
5. DISCLAIMER OF WARRANTY.
COVERED SOFTWARE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS"
BASIS, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED,
INCLUDING, WITHOUT LIMITATION, WARRANTIES THAT THE COVERED
SOFTWARE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR
PURPOSE OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND
PERFORMANCE OF THE COVERED SOFTWARE IS WITH YOU. SHOULD ANY
COVERED SOFTWARE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT THE
INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY
NECESSARY SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF
WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. NO USE OF
ANY COVERED SOFTWARE IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS
DISCLAIMER.
6. TERMINATION.
6.1. This License and the rights granted hereunder will terminate
automatically if You fail to comply with terms herein and fail to
cure such breach within 30 days of becoming aware of the breach.
Provisions which, by their nature, must remain in effect beyond
the termination of this License shall survive.
6.2. If You assert a patent infringement claim (excluding
declaratory judgment actions) against Initial Developer or a
Contributor (the Initial Developer or Contributor against whom You
assert such claim is referred to as "Participant") alleging that
the Participant Software (meaning the Contributor Version where
the Participant is a Contributor or the Original Software where
the Participant is the Initial Developer) directly or indirectly
infringes any patent, then any and all rights granted directly or
indirectly to You by such Participant, the Initial Developer (if
the Initial Developer is not the Participant) and all Contributors
under Sections 2.1 and/or 2.2 of this License shall, upon 60 days
notice from Participant terminate prospectively and automatically
at the expiration of such 60 day notice period, unless if within
such 60 day period You withdraw Your claim with respect to the
Participant Software against such Participant either unilaterally
or pursuant to a written agreement with Participant.
6.3. In the event of termination under Sections 6.1 or 6.2 above,
all end user licenses that have been validly granted by You or any
distributor hereunder prior to termination (excluding licenses
granted to You by any distributor) shall survive termination.
7. LIMITATION OF LIABILITY.
UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, WHETHER TORT
(INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE, SHALL YOU, THE
INITIAL DEVELOPER, ANY OTHER CONTRIBUTOR, OR ANY DISTRIBUTOR OF
COVERED SOFTWARE, OR ANY SUPPLIER OF ANY OF SUCH PARTIES, BE
LIABLE TO ANY PERSON FOR ANY INDIRECT, SPECIAL, INCIDENTAL, OR
CONSEQUENTIAL DAMAGES OF ANY CHARACTER INCLUDING, WITHOUT
LIMITATION, DAMAGES FOR LOST PROFITS, LOSS OF GOODWILL, WORK
STOPPAGE, COMPUTER FAILURE OR MALFUNCTION, OR ANY AND ALL OTHER
COMMERCIAL DAMAGES OR LOSSES, EVEN IF SUCH PARTY SHALL HAVE BEEN
INFORMED OF THE POSSIBILITY OF SUCH DAMAGES. THIS LIMITATION OF
LIABILITY SHALL NOT APPLY TO LIABILITY FOR DEATH OR PERSONAL
INJURY RESULTING FROM SUCH PARTY'S NEGLIGENCE TO THE EXTENT
APPLICABLE LAW PROHIBITS SUCH LIMITATION. SOME JURISDICTIONS DO
NOT ALLOW THE EXCLUSION OR LIMITATION OF INCIDENTAL OR
CONSEQUENTIAL DAMAGES, SO THIS EXCLUSION AND LIMITATION MAY NOT
APPLY TO YOU.
8. U.S. GOVERNMENT END USERS.
The Covered Software is a "commercial item," as that term is
defined in 48 C.F.R. 2.101 (Oct. 1995), consisting of "commercial
computer software" (as that term is defined at 48
C.F.R. 252.227-7014(a)(1)) and "commercial computer software
documentation" as such terms are used in 48 C.F.R. 12.212
(Sept. 1995). Consistent with 48 C.F.R. 12.212 and 48
C.F.R. 227.7202-1 through 227.7202-4 (June 1995), all
U.S. Government End Users acquire Covered Software with only those
rights set forth herein. This U.S. Government Rights clause is in
lieu of, and supersedes, any other FAR, DFAR, or other clause or
provision that addresses Government rights in computer software
under this License.
9. MISCELLANEOUS.
This License represents the complete agreement concerning subject
matter hereof. If any provision of this License is held to be
unenforceable, such provision shall be reformed only to the extent
necessary to make it enforceable. This License shall be governed
by the law of the jurisdiction specified in a notice contained
within the Original Software (except to the extent applicable law,
if any, provides otherwise), excluding such jurisdiction's
conflict-of-law provisions. Any litigation relating to this
License shall be subject to the jurisdiction of the courts located
in the jurisdiction and venue specified in a notice contained
within the Original Software, with the losing party responsible
for costs, including, without limitation, court costs and
reasonable attorneys' fees and expenses. The application of the
United Nations Convention on Contracts for the International Sale
of Goods is expressly excluded. Any law or regulation which
provides that the language of a contract shall be construed
against the drafter shall not apply to this License. You agree
that You alone are responsible for compliance with the United
States export administration regulations (and the export control
laws and regulation of any other countries) when You use,
distribute or otherwise make available any Covered Software.
10. RESPONSIBILITY FOR CLAIMS.
As between Initial Developer and the Contributors, each party is
responsible for claims and damages arising, directly or
indirectly, out of its utilization of rights under this License
and You agree to work with Initial Developer and Contributors to
distribute such responsibility on an equitable basis. Nothing
herein is intended or shall be deemed to constitute any admission
of liability.
--------------------------------------------------------------------
NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND
DISTRIBUTION LICENSE (CDDL)
For Covered Software in this distribution, this License shall
be governed by the laws of the State of California (excluding
conflict-of-law provisions).
Any litigation relating to this License shall be subject to the
jurisdiction of the Federal Courts of the Northern District of
California and the state courts of the State of California, with
venue lying in Santa Clara County, California.

27
vendor/github.com/howeyc/gopass/README.md generated vendored Normal file
View File

@ -0,0 +1,27 @@
# getpasswd in Go [![GoDoc](https://godoc.org/github.com/howeyc/gopass?status.svg)](https://godoc.org/github.com/howeyc/gopass) [![Build Status](https://secure.travis-ci.org/howeyc/gopass.png?branch=master)](http://travis-ci.org/howeyc/gopass)
Retrieve password from user terminal or piped input without echo.
Verified on BSD, Linux, and Windows.
Example:
```go
package main
import "fmt"
import "github.com/howeyc/gopass"
func main() {
fmt.Printf("Password: ")
// Silent. For printing *'s use gopass.GetPasswdMasked()
pass, err := gopass.GetPasswd()
if err != nil {
// Handle gopass.ErrInterrupted or getch() read error
}
// Do something with pass
}
```
Caution: Multi-byte characters not supported!

110
vendor/github.com/howeyc/gopass/pass.go generated vendored Normal file
View File

@ -0,0 +1,110 @@
package gopass
import (
"errors"
"fmt"
"io"
"os"
)
type FdReader interface {
io.Reader
Fd() uintptr
}
var defaultGetCh = func(r io.Reader) (byte, error) {
buf := make([]byte, 1)
if n, err := r.Read(buf); n == 0 || err != nil {
if err != nil {
return 0, err
}
return 0, io.EOF
}
return buf[0], nil
}
var (
maxLength = 512
ErrInterrupted = errors.New("interrupted")
ErrMaxLengthExceeded = fmt.Errorf("maximum byte limit (%v) exceeded", maxLength)
// Provide variable so that tests can provide a mock implementation.
getch = defaultGetCh
)
// getPasswd returns the input read from terminal.
// If prompt is not empty, it will be output as a prompt to the user
// If masked is true, typing will be matched by asterisks on the screen.
// Otherwise, typing will echo nothing.
func getPasswd(prompt string, masked bool, r FdReader, w io.Writer) ([]byte, error) {
var err error
var pass, bs, mask []byte
if masked {
bs = []byte("\b \b")
mask = []byte("*")
}
if isTerminal(r.Fd()) {
if oldState, err := makeRaw(r.Fd()); err != nil {
return pass, err
} else {
defer func() {
restore(r.Fd(), oldState)
fmt.Fprintln(w)
}()
}
}
if prompt != "" {
fmt.Fprint(w, prompt)
}
// Track total bytes read, not just bytes in the password. This ensures any
// errors that might flood the console with nil or -1 bytes infinitely are
// capped.
var counter int
for counter = 0; counter <= maxLength; counter++ {
if v, e := getch(r); e != nil {
err = e
break
} else if v == 127 || v == 8 {
if l := len(pass); l > 0 {
pass = pass[:l-1]
fmt.Fprint(w, string(bs))
}
} else if v == 13 || v == 10 {
break
} else if v == 3 {
err = ErrInterrupted
break
} else if v != 0 {
pass = append(pass, v)
fmt.Fprint(w, string(mask))
}
}
if counter > maxLength {
err = ErrMaxLengthExceeded
}
return pass, err
}
// GetPasswd returns the password read from the terminal without echoing input.
// The returned byte array does not include end-of-line characters.
func GetPasswd() ([]byte, error) {
return getPasswd("", false, os.Stdin, os.Stdout)
}
// GetPasswdMasked returns the password read from the terminal, echoing asterisks.
// The returned byte array does not include end-of-line characters.
func GetPasswdMasked() ([]byte, error) {
return getPasswd("", true, os.Stdin, os.Stdout)
}
// GetPasswdPrompt prompts the user and returns the password read from the terminal.
// If mask is true, then asterisks are echoed.
// The returned byte array does not include end-of-line characters.
func GetPasswdPrompt(prompt string, mask bool, r FdReader, w io.Writer) ([]byte, error) {
return getPasswd(prompt, mask, r, w)
}

225
vendor/github.com/howeyc/gopass/pass_test.go generated vendored Normal file
View File

@ -0,0 +1,225 @@
package gopass
import (
"bufio"
"bytes"
"fmt"
"io"
"io/ioutil"
"os"
"testing"
"time"
)
// TestGetPasswd tests the password creation and output based on a byte buffer
// as input to mock the underlying getch() methods.
func TestGetPasswd(t *testing.T) {
type testData struct {
input []byte
// Due to how backspaces are written, it is easier to manually write
// each expected output for the masked cases.
masked string
password string
byesLeft int
reason string
}
ds := []testData{
testData{[]byte("abc\n"), "***", "abc", 0, "Password parsing should stop at \\n"},
testData{[]byte("abc\r"), "***", "abc", 0, "Password parsing should stop at \\r"},
testData{[]byte("a\nbc\n"), "*", "a", 3, "Password parsing should stop at \\n"},
testData{[]byte("*!]|\n"), "****", "*!]|", 0, "Special characters shouldn't affect the password."},
testData{[]byte("abc\r\n"), "***", "abc", 1,
"Password parsing should stop at \\r; Windows LINE_MODE should be unset so \\r is not converted to \\r\\n."},
testData{[]byte{'a', 'b', 'c', 8, '\n'}, "***\b \b", "ab", 0, "Backspace byte should remove the last read byte."},
testData{[]byte{'a', 'b', 127, 'c', '\n'}, "**\b \b*", "ac", 0, "Delete byte should remove the last read byte."},
testData{[]byte{'a', 'b', 127, 'c', 8, 127, '\n'}, "**\b \b*\b \b\b \b", "", 0, "Successive deletes continue to delete."},
testData{[]byte{8, 8, 8, '\n'}, "", "", 0, "Deletes before characters are noops."},
testData{[]byte{8, 8, 8, 'a', 'b', 'c', '\n'}, "***", "abc", 0, "Deletes before characters are noops."},
testData{[]byte{'a', 'b', 0, 'c', '\n'}, "***", "abc", 0,
"Nil byte should be ignored due; may get unintended nil bytes from syscalls on Windows."},
}
// Redirecting output for tests as they print to os.Stdout but we want to
// capture and test the output.
for _, masked := range []bool{true, false} {
for _, d := range ds {
pipeBytesToStdin(d.input)
r, w, err := os.Pipe()
if err != nil {
t.Fatal(err.Error())
}
result, err := getPasswd("", masked, os.Stdin, w)
if err != nil {
t.Errorf("Error getting password: %s", err.Error())
}
leftOnBuffer := flushStdin()
// Test output (masked and unmasked). Delete/backspace actually
// deletes, overwrites and deletes again. As a result, we need to
// remove those from the pipe afterwards to mimic the console's
// interpretation of those bytes.
w.Close()
output, err := ioutil.ReadAll(r)
if err != nil {
t.Fatal(err.Error())
}
var expectedOutput []byte
if masked {
expectedOutput = []byte(d.masked)
} else {
expectedOutput = []byte("")
}
if bytes.Compare(expectedOutput, output) != 0 {
t.Errorf("Expected output to equal %v (%q) but got %v (%q) instead when masked=%v. %s", expectedOutput, string(expectedOutput), output, string(output), masked, d.reason)
}
if string(result) != d.password {
t.Errorf("Expected %q but got %q instead when masked=%v. %s", d.password, result, masked, d.reason)
}
if leftOnBuffer != d.byesLeft {
t.Errorf("Expected %v bytes left on buffer but instead got %v when masked=%v. %s", d.byesLeft, leftOnBuffer, masked, d.reason)
}
}
}
}
// TestPipe ensures we get our expected pipe behavior.
func TestPipe(t *testing.T) {
type testData struct {
input string
password string
expError error
}
ds := []testData{
testData{"abc", "abc", io.EOF},
testData{"abc\n", "abc", nil},
testData{"abc\r", "abc", nil},
testData{"abc\r\n", "abc", nil},
}
for _, d := range ds {
_, err := pipeToStdin(d.input)
if err != nil {
t.Log("Error writing input to stdin:", err)
t.FailNow()
}
pass, err := GetPasswd()
if string(pass) != d.password {
t.Errorf("Expected %q but got %q instead.", d.password, string(pass))
}
if err != d.expError {
t.Errorf("Expected %v but got %q instead.", d.expError, err)
}
}
}
// flushStdin reads from stdin for .5 seconds to ensure no bytes are left on
// the buffer. Returns the number of bytes read.
func flushStdin() int {
ch := make(chan byte)
go func(ch chan byte) {
reader := bufio.NewReader(os.Stdin)
for {
b, err := reader.ReadByte()
if err != nil { // Maybe log non io.EOF errors, if you want
close(ch)
return
}
ch <- b
}
close(ch)
}(ch)
numBytes := 0
for {
select {
case _, ok := <-ch:
if !ok {
return numBytes
}
numBytes++
case <-time.After(500 * time.Millisecond):
return numBytes
}
}
return numBytes
}
// pipeToStdin pipes the given string onto os.Stdin by replacing it with an
// os.Pipe. The write end of the pipe is closed so that EOF is read after the
// final byte.
func pipeToStdin(s string) (int, error) {
pipeReader, pipeWriter, err := os.Pipe()
if err != nil {
fmt.Println("Error getting os pipes:", err)
os.Exit(1)
}
os.Stdin = pipeReader
w, err := pipeWriter.WriteString(s)
pipeWriter.Close()
return w, err
}
func pipeBytesToStdin(b []byte) (int, error) {
return pipeToStdin(string(b))
}
// TestGetPasswd_Err tests errors are properly handled from getch()
func TestGetPasswd_Err(t *testing.T) {
var inBuffer *bytes.Buffer
getch = func(io.Reader) (byte, error) {
b, err := inBuffer.ReadByte()
if err != nil {
return 13, err
}
if b == 'z' {
return 'z', fmt.Errorf("Forced error; byte returned should not be considered accurate.")
}
return b, nil
}
defer func() { getch = defaultGetCh }()
for input, expectedPassword := range map[string]string{"abc": "abc", "abzc": "ab"} {
inBuffer = bytes.NewBufferString(input)
p, err := GetPasswdMasked()
if string(p) != expectedPassword {
t.Errorf("Expected %q but got %q instead.", expectedPassword, p)
}
if err == nil {
t.Errorf("Expected error to be returned.")
}
}
}
func TestMaxPasswordLength(t *testing.T) {
type testData struct {
input []byte
expectedErr error
// Helper field to output in case of failure; rather than hundreds of
// bytes.
inputDesc string
}
ds := []testData{
testData{append(bytes.Repeat([]byte{'a'}, maxLength), '\n'), nil, fmt.Sprintf("%v 'a' bytes followed by a newline", maxLength)},
testData{append(bytes.Repeat([]byte{'a'}, maxLength+1), '\n'), ErrMaxLengthExceeded, fmt.Sprintf("%v 'a' bytes followed by a newline", maxLength+1)},
testData{append(bytes.Repeat([]byte{0x00}, maxLength+1), '\n'), ErrMaxLengthExceeded, fmt.Sprintf("%v 0x00 bytes followed by a newline", maxLength+1)},
}
for _, d := range ds {
pipeBytesToStdin(d.input)
_, err := GetPasswd()
if err != d.expectedErr {
t.Errorf("Expected error to be %v; isntead got %v from %v", d.expectedErr, err, d.inputDesc)
}
}
}

25
vendor/github.com/howeyc/gopass/terminal.go generated vendored Normal file
View File

@ -0,0 +1,25 @@
// +build !solaris
package gopass
import "golang.org/x/crypto/ssh/terminal"
type terminalState struct {
state *terminal.State
}
func isTerminal(fd uintptr) bool {
return terminal.IsTerminal(int(fd))
}
func makeRaw(fd uintptr) (*terminalState, error) {
state, err := terminal.MakeRaw(int(fd))
return &terminalState{
state: state,
}, err
}
func restore(fd uintptr, oldState *terminalState) error {
return terminal.Restore(int(fd), oldState.state)
}

69
vendor/github.com/howeyc/gopass/terminal_solaris.go generated vendored Normal file
View File

@ -0,0 +1,69 @@
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
// Below is derived from Solaris source, so CDDL license is included.
package gopass
import (
"syscall"
"golang.org/x/sys/unix"
)
type terminalState struct {
state *unix.Termios
}
// isTerminal returns true if there is a terminal attached to the given
// file descriptor.
// Source: http://src.illumos.org/source/xref/illumos-gate/usr/src/lib/libbc/libc/gen/common/isatty.c
func isTerminal(fd uintptr) bool {
var termio unix.Termio
err := unix.IoctlSetTermio(int(fd), unix.TCGETA, &termio)
return err == nil
}
// makeRaw puts the terminal connected to the given file descriptor into raw
// mode and returns the previous state of the terminal so that it can be
// restored.
// Source: http://src.illumos.org/source/xref/illumos-gate/usr/src/lib/libast/common/uwin/getpass.c
func makeRaw(fd uintptr) (*terminalState, error) {
oldTermiosPtr, err := unix.IoctlGetTermios(int(fd), unix.TCGETS)
if err != nil {
return nil, err
}
oldTermios := *oldTermiosPtr
newTermios := oldTermios
newTermios.Lflag &^= syscall.ECHO | syscall.ECHOE | syscall.ECHOK | syscall.ECHONL
if err := unix.IoctlSetTermios(int(fd), unix.TCSETS, &newTermios); err != nil {
return nil, err
}
return &terminalState{
state: oldTermiosPtr,
}, nil
}
func restore(fd uintptr, oldState *terminalState) error {
return unix.IoctlSetTermios(int(fd), unix.TCSETS, oldState.state)
}

19
vendor/github.com/kballard/go-shellquote/LICENSE generated vendored Normal file
View File

@ -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.

36
vendor/github.com/kballard/go-shellquote/README generated vendored Normal file
View File

@ -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.

29
vendor/github.com/kballard/go-shellquote/both_test.go generated vendored Normal file
View File

@ -0,0 +1,29 @@
package shellquote
import (
"reflect"
"testing"
"testing/quick"
)
// this is called bothtest because it tests Split and Join together
func TestJoinSplit(t *testing.T) {
f := func(strs []string) bool {
// Join, then split, the input
combined := Join(strs...)
split, err := Split(combined)
if err != nil {
t.Logf("Error splitting %#v: %v", combined, err)
return false
}
if !reflect.DeepEqual(strs, split) {
t.Logf("Input %q did not match output %q", strs, split)
return false
}
return true
}
if err := quick.Check(f, nil); err != nil {
t.Error(err)
}
}

3
vendor/github.com/kballard/go-shellquote/doc.go generated vendored Normal file
View File

@ -0,0 +1,3 @@
// Shellquote provides utilities for joining/splitting strings using sh's
// word-splitting rules.
package shellquote

102
vendor/github.com/kballard/go-shellquote/quote.go generated vendored Normal file
View File

@ -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('\'')
}
}

31
vendor/github.com/kballard/go-shellquote/quote_test.go generated vendored Normal file
View File

@ -0,0 +1,31 @@
package shellquote
import (
"testing"
)
func TestSimpleJoin(t *testing.T) {
for _, elem := range simpleJoinTest {
output := Join(elem.input...)
if output != elem.output {
t.Errorf("Input %q, got %q, expected %q", elem.input, output, elem.output)
}
}
}
var simpleJoinTest = []struct {
input []string
output string
}{
{[]string{"test"}, "test"},
{[]string{"hello goodbye"}, "'hello goodbye'"},
{[]string{"hello", "goodbye"}, "hello goodbye"},
{[]string{"don't you know the dewey decimal system?"}, "'don'\\''t you know the dewey decimal system?'"},
{[]string{"don't", "you", "know", "the", "dewey", "decimal", "system?"}, "don\\'t you know the dewey decimal system\\?"},
{[]string{"~user", "u~ser", " ~user", "!~user"}, "\\~user u~ser ' ~user' \\!~user"},
{[]string{"foo*", "M{ovies,usic}", "ab[cd]", "%3"}, "foo\\* M\\{ovies,usic} ab\\[cd] %3"},
{[]string{"one", "", "three"}, "one '' three"},
{[]string{"some(parentheses)"}, "some\\(parentheses\\)"},
{[]string{"$some_ot~her_)spe!cial_*_characters"}, "\\$some_ot~her_\\)spe\\!cial_\\*_characters"},
{[]string{"' "}, "\\'' '"},
}

144
vendor/github.com/kballard/go-shellquote/unquote.go generated vendored Normal file
View File

@ -0,0 +1,144 @@
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
}
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
}

View File

@ -0,0 +1,53 @@
package shellquote
import (
"reflect"
"testing"
)
func TestSimpleSplit(t *testing.T) {
for _, elem := range simpleSplitTest {
output, err := Split(elem.input)
if err != nil {
t.Errorf("Input %q, got error %#v", elem.input, err)
} else if !reflect.DeepEqual(output, elem.output) {
t.Errorf("Input %q, got %q, expected %q", elem.input, output, elem.output)
}
}
}
func TestErrorSplit(t *testing.T) {
for _, elem := range errorSplitTest {
_, err := Split(elem.input)
if err != elem.error {
t.Errorf("Input %q, got error %#v, expected error %#v", elem.input, err, elem.error)
}
}
}
var simpleSplitTest = []struct {
input string
output []string
}{
{"hello", []string{"hello"}},
{"hello goodbye", []string{"hello", "goodbye"}},
{"hello goodbye", []string{"hello", "goodbye"}},
{"glob* test?", []string{"glob*", "test?"}},
{"don\\'t you know the dewey decimal system\\?", []string{"don't", "you", "know", "the", "dewey", "decimal", "system?"}},
{"'don'\\''t you know the dewey decimal system?'", []string{"don't you know the dewey decimal system?"}},
{"one '' two", []string{"one", "", "two"}},
{"text with\\\na backslash-escaped newline", []string{"text", "witha", "backslash-escaped", "newline"}},
{"text \"with\na\" quoted newline", []string{"text", "with\na", "quoted", "newline"}},
{"\"quoted\\d\\\\\\\" text with\\\na backslash-escaped newline\"", []string{"quoted\\d\\\" text witha backslash-escaped newline"}},
{"foo\"bar\"baz", []string{"foobarbaz"}},
}
var errorSplitTest = []struct {
input string
error error
}{
{"don't worry", UnterminatedSingleQuoteError},
{"'test'\\''ing", UnterminatedSingleQuoteError},
{"\"foo'bar", UnterminatedDoubleQuoteError},
{"foo\\", UnterminatedEscapeError},
}

8
vendor/github.com/kohkimakimoto/gluaenv/.gitignore generated vendored Normal file
View File

@ -0,0 +1,8 @@
.DS_Store
Thumbs.db
.tags*
._*
.vagrant
*.iml
!.gitkeep

20
vendor/github.com/kohkimakimoto/gluaenv/LICENSE generated vendored Normal file
View File

@ -0,0 +1,20 @@
The MIT License (MIT)
Copyright (c) 2016 Kohki Makimoto
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.

75
vendor/github.com/kohkimakimoto/gluaenv/README.md generated vendored Normal file
View File

@ -0,0 +1,75 @@
# gluaenv
Utility package for manipulating environment variables for [gopher-lua](https://github.com/yuin/gopher-lua)
## Installation
```
go get github.com/kohkimakimoto/gluaenv
```
## API
### `env.set(key, value)`
Same `os.setenv`
### `env.get(key)`
Same `os.getenv`
### `env.loadfile(file)`
Loads environment variables from a file. The file is as the following:
```
AAA=BBB
CCC=DDD
```
If this function fails, it returns `nil`, plus a string describing the error.
## Usage
```go
package main
import (
"github.com/yuin/gopher-lua"
"github.com/kohkimakimoto/gluaenv"
)
func main() {
L := lua.NewState()
defer L.Close()
L.PreloadModule("env", gluaenv.Loader)
if err := L.DoString(`
local env = require("env")
-- set a environment variable
env.set("HOGE_KEY", "HOGE_VALUE")
-- get a environment variable
local v = env.get("HOGE_KEY")
-- load envrironment variables from a file.
env.loadfile("path/to/.env")
-- file example
-- AAA=BBB
-- CCC=DDD
`); err != nil {
panic(err)
}
}
```
## Author
Kohki Makimoto <kohki.makimoto@gmail.com>
## License
MIT license.

193
vendor/github.com/kohkimakimoto/gluaenv/gluaenv.go generated vendored Normal file
View File

@ -0,0 +1,193 @@
package gluaenv
import (
"github.com/yuin/gopher-lua"
"os"
"bufio"
"strings"
"errors"
)
func Loader(L *lua.LState) int {
tb := L.NewTable()
L.SetFuncs(tb, map[string]lua.LGFunction{
"set": envSet,
"get": envGet,
"loadfile": envLoadFile,
})
L.Push(tb)
return 1
}
func envSet(L *lua.LState) int {
// same github.com/yuin/gopher-lua/oslib.go
err := os.Setenv(L.CheckString(1), L.CheckString(2))
if err != nil {
L.Push(lua.LNil)
L.Push(lua.LString(err.Error()))
return 2
} else {
L.Push(lua.LTrue)
return 1
}
}
func envGet(L *lua.LState) int {
// same github.com/yuin/gopher-lua/oslib.go
v := os.Getenv(L.CheckString(1))
if len(v) == 0 {
L.Push(lua.LNil)
} else {
L.Push(lua.LString(v))
}
return 1
}
func envLoadFile(L *lua.LState) int {
if err := loadFile(L.CheckString(1)); err != nil {
L.Push(lua.LNil)
L.Push(lua.LString(err.Error()))
return 2
} else {
L.Push(lua.LTrue)
return 1
}
}
// loadFile' s code is highly inspired by https://github.com/joho/godotenv/blob/master/godotenv.go
//Copyright (c) 2013 John Barton
//
//MIT License
//
//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.
func loadFile(filename string) error {
envMap, err := readFile(filename)
if err != nil {
return err
}
for key, value := range envMap {
os.Setenv(key, value)
}
return nil
}
func readFile(filename string) (envMap map[string]string, err error) {
file, err := os.Open(filename)
if err != nil {
return
}
defer file.Close()
envMap = make(map[string]string)
var lines []string
scanner := bufio.NewScanner(file)
for scanner.Scan() {
lines = append(lines, scanner.Text())
}
for _, fullLine := range lines {
if !isIgnoredLine(fullLine) {
key, value, err := parseLine(fullLine)
if err == nil {
envMap[key] = value
}
}
}
return
}
func parseLine(line string) (key string, value string, err error) {
if len(line) == 0 {
err = errors.New("zero length string")
return
}
// ditch the comments (but keep quoted hashes)
if strings.Contains(line, "#") {
segmentsBetweenHashes := strings.Split(line, "#")
quotesAreOpen := false
var segmentsToKeep []string
for _, segment := range segmentsBetweenHashes {
if strings.Count(segment, "\"") == 1 || strings.Count(segment, "'") == 1 {
if quotesAreOpen {
quotesAreOpen = false
segmentsToKeep = append(segmentsToKeep, segment)
} else {
quotesAreOpen = true
}
}
if len(segmentsToKeep) == 0 || quotesAreOpen {
segmentsToKeep = append(segmentsToKeep, segment)
}
}
line = strings.Join(segmentsToKeep, "#")
}
// now split key from value
splitString := strings.SplitN(line, "=", 2)
if len(splitString) != 2 {
// try yaml mode!
splitString = strings.SplitN(line, ":", 2)
}
if len(splitString) != 2 {
err = errors.New("Can't separate key from value")
return
}
// Parse the key
key = splitString[0]
if strings.HasPrefix(key, "export") {
key = strings.TrimPrefix(key, "export")
}
key = strings.Trim(key, " ")
// Parse the value
value = splitString[1]
// trim
value = strings.Trim(value, " ")
// check if we've got quoted values
if strings.Count(value, "\"") == 2 || strings.Count(value, "'") == 2 {
// pull the quotes off the edges
value = strings.Trim(value, "\"'")
// expand quotes
value = strings.Replace(value, "\\\"", "\"", -1)
// expand newlines
value = strings.Replace(value, "\\n", "\n", -1)
}
return
}
func isIgnoredLine(line string) bool {
trimmedLine := strings.Trim(line, " \n\t")
return len(trimmedLine) == 0 || strings.HasPrefix(trimmedLine, "#")
}

View File

@ -0,0 +1,70 @@
package gluaenv
import (
"github.com/yuin/gopher-lua"
"testing"
"io/ioutil"
"os"
)
func TestSetAndGet(t *testing.T) {
L := lua.NewState()
defer L.Close()
L.PreloadModule("env", Loader)
if err := L.DoString(`
local env = require("env")
env.set("HOGE_KEY", "HOGE_VALUE")
local v = env.get("HOGE_KEY")
assert(v == "HOGE_VALUE")
`); err != nil {
t.Error(err)
}
}
var sampleFile = `
AAA=hogehoge
BBB=bbbbbbbb
# CCC=eeeeee
DDD=ddddddd
`
func TestLoadfile(t *testing.T) {
tmpFile, err := ioutil.TempFile("", "")
if err != nil {
t.Errorf("should not raise error: %v", err)
}
if err = ioutil.WriteFile(tmpFile.Name(), []byte(sampleFile), 0644); err != nil {
t.Errorf("should not raise error: %v", err)
}
defer func() {
tmpFile.Close()
os.Remove(tmpFile.Name())
}()
L := lua.NewState()
defer L.Close()
L.PreloadModule("env", Loader)
if err := L.DoString(`
local env = require("env")
env.loadfile("` + tmpFile.Name() + `")
assert(env.get("AAA") == "hogehoge")
assert(env.get("BBB") == "bbbbbbbb")
assert(env.get("CCC") == nil)
assert(env.get("DDD") == "ddddddd")
r1, r2 = env.loadfile("` + tmpFile.Name() + `.notfound_file")
assert(r1 == nil)
`); err != nil {
t.Error(err)
}
}

5
vendor/github.com/kohkimakimoto/gluafs/.gitignore generated vendored Normal file
View File

@ -0,0 +1,5 @@
.DS_Store
Thumbs.db
.tags*
._*
*.iml

108
vendor/github.com/kohkimakimoto/gluafs/README.md generated vendored Normal file
View File

@ -0,0 +1,108 @@
# gluafs
filesystem utility for [gopher-lua](https://github.com/yuin/gopher-lua). This project is inspired by [layeh/gopher-lfs](https://github.com/layeh/gopher-lfs).
## Installation
```
go get github.com/kohkimakimoto/gluafs
```
## API
### `fs.exists(file)`
Returns true if the file exists.
### `fs.read(file)`
Reads file content and return it. If this function fails, it returns `nil`, plus a string describing the error.
### `fs.write(file, content, [mode])`
Writes content to the file. If this function fails, it returns `nil`, plus a string describing the error.
### `fs.mkdir(path, [mode, recursive])`
Create directory. If this function fails, it returns `nil`, plus a string describing the error.
### `fs.remove(path, [recursive])`
Remove path. If this function fails, it returns `nil`, plus a string describing the error.
### `fs.symlink(target, link)`
Create symbolic link. If this function fails, it returns `nil`, plus a string describing the error.
### `fs.dirname(path)`
Returns all but the last element of path.
### `fs.basename(path)`
Returns the last element of path.
### `fs.realpath(path)`
Returns the real path of a given path in the os. If this function fails, it returns `nil`, plus a string describing the error.
### `fs.getcwd()`
Returns the current working directory. If this function fails, it returns `nil`, plus a string describing the error.
### `fs.chdir(path)`
Changes the current working directory. If this function fails, it returns `nil`, plus a string describing the error.
### `fs.file()`
Returns the script file path. If this function fails, it returns `nil`, plus a string describing the error.
### `fs.dir()`
Returns the directory path that is parent of the script file. If this function fails, it returns `nil`, plus a string describing the error.
### `fs.glob(pattern, function)`
Run the callback function with the files matching pattern. See below example:
```lua
local fs = require("fs")
local ret, err = fs.glob("/tmp/*", function(file)
print(file.path)
print(file.realpath)
end)
```
## Usage
```go
package main
import (
"github.com/yuin/gopher-lua"
"github.com/kohkimakimoto/gluafs"
)
func main() {
L := lua.NewState()
defer L.Close()
L.PreloadModule("fs", gluafs.Loader)
if err := L.DoString(`
local fs = require("fs")
local ret = fs.exists("path/to/file")
`); err != nil {
panic(err)
}
}
```
## Author
Kohki Makimoto <kohki.makimoto@gmail.com>
## License
MIT license.

327
vendor/github.com/kohkimakimoto/gluafs/fs.go generated vendored Normal file
View File

@ -0,0 +1,327 @@
package gluafs
import (
"fmt"
"github.com/yookoala/realpath"
"github.com/yuin/gopher-lua"
"io/ioutil"
"os"
"path/filepath"
"strconv"
)
func Loader(L *lua.LState) int {
tb := L.NewTable()
L.SetFuncs(tb, map[string]lua.LGFunction{
"exists": exists,
"read": read,
"write": write,
"mkdir": mkdir,
"remove": remove,
"symlink": symlink,
"dirname": dirname,
"basename": basename,
"realpath": fnRealpath,
"getcwd": getcwd,
"chdir": chdir,
"file": file,
"dir": dir,
"glob": glob,
})
L.Push(tb)
return 1
}
func exists(L *lua.LState) int {
var ret bool
path := L.CheckString(1)
if _, err := os.Stat(path); os.IsNotExist(err) {
ret = false
} else {
ret = true
}
L.Push(lua.LBool(ret))
return 1
}
func read(L *lua.LState) int {
path := L.CheckString(1)
if _, err := os.Stat(path); os.IsNotExist(err) {
L.Push(lua.LNil)
L.Push(lua.LString(err.Error()))
return 2
}
content, err := ioutil.ReadFile(path)
if err != nil {
L.Push(lua.LNil)
L.Push(lua.LString(err.Error()))
return 2
}
L.Push(lua.LString(string(content)))
return 1
}
func write(L *lua.LState) int {
p := L.CheckString(1)
content := []byte(L.CheckString(2))
var mode os.FileMode = 0666
top := L.GetTop()
if top == 3 {
m, err := oct2decimal(L.CheckInt(3))
if err != nil {
L.Push(lua.LNil)
L.Push(lua.LString(err.Error()))
return 2
}
mode = os.FileMode(m)
}
err := ioutil.WriteFile(p, content, mode)
if err != nil {
L.Push(lua.LNil)
L.Push(lua.LString(err.Error()))
return 2
}
L.Push(lua.LTrue)
return 1
}
func mkdir(L *lua.LState) int {
dir := L.CheckString(1)
var mode os.FileMode = 0777
top := L.GetTop()
if top >= 2 {
m, err := oct2decimal(L.CheckInt(2))
if err != nil {
L.Push(lua.LNil)
L.Push(lua.LString(err.Error()))
return 2
}
mode = os.FileMode(m)
}
recursive := false
if top >= 3 {
recursive = L.ToBool(3)
}
var err error
if recursive {
err = os.MkdirAll(dir, mode)
} else {
err = os.Mkdir(dir, mode)
}
if err != nil {
L.Push(lua.LNil)
L.Push(lua.LString(err.Error()))
return 2
}
L.Push(lua.LTrue)
return 1
}
func remove(L *lua.LState) int {
p := L.CheckString(1)
recursive := false
if L.GetTop() >= 2 {
recursive = L.ToBool(2)
}
var err error
if recursive {
err = os.Remove(p)
} else {
err = os.RemoveAll(p)
}
if err != nil {
L.Push(lua.LNil)
L.Push(lua.LString(err.Error()))
return 2
}
L.Push(lua.LTrue)
return 1
}
func symlink(L *lua.LState) int {
target := L.CheckString(1)
link := L.CheckString(2)
err := os.Symlink(target, link)
if err != nil {
L.Push(lua.LNil)
L.Push(lua.LString(err.Error()))
return 2
}
L.Push(lua.LTrue)
return 1
}
func dirname(L *lua.LState) int {
filep := L.CheckString(1)
dirna := filepath.Dir(filep)
L.Push(lua.LString(dirna))
return 1
}
func basename(L *lua.LState) int {
filep := L.CheckString(1)
dirna := filepath.Base(filep)
L.Push(lua.LString(dirna))
return 1
}
func fnRealpath(L *lua.LState) int {
filep := L.CheckString(1)
real, err := realpath.Realpath(filep)
if err != nil {
L.Push(lua.LNil)
L.Push(lua.LString(err.Error()))
return 2
}
L.Push(lua.LString(real))
return 1
}
func getcwd(L *lua.LState) int {
dir, err := os.Getwd()
if err != nil {
L.Push(lua.LNil)
L.Push(lua.LString(err.Error()))
return 2
}
L.Push(lua.LString(dir))
return 1
}
func chdir(L *lua.LState) int {
dir := L.CheckString(1)
err := os.Chdir(dir)
if err != nil {
L.Push(lua.LNil)
L.Push(lua.LString(err.Error()))
return 2
}
L.Push(lua.LTrue)
return 1
}
func file(L *lua.LState) int {
// same: debug.getinfo(2,'S').source
var dbg *lua.Debug
var err error
var ok bool
dbg, ok = L.GetStack(1)
if !ok {
L.Push(lua.LNil)
L.Push(lua.LString(fmt.Sprint(dbg)))
return 2
}
_, err = L.GetInfo("S", dbg, lua.LNil)
if err != nil {
L.Push(lua.LNil)
L.Push(lua.LString(err.Error()))
return 2
}
L.Push(lua.LString(dbg.Source))
return 1
}
func dir(L *lua.LState) int {
// same: debug.getinfo(2,'S').source
var dbg *lua.Debug
var err error
var ok bool
dbg, ok = L.GetStack(1)
if !ok {
L.Push(lua.LNil)
L.Push(lua.LString(fmt.Sprint(dbg)))
return 2
}
_, err = L.GetInfo("S", dbg, lua.LNil)
if err != nil {
L.Push(lua.LNil)
L.Push(lua.LString(err.Error()))
return 2
}
dirname := filepath.Dir(dbg.Source)
L.Push(lua.LString(dirname))
return 1
}
func glob(L *lua.LState) int {
ptn := L.CheckString(1)
fn := L.CheckFunction(2)
files, err := filepath.Glob(ptn)
if err != nil {
L.Push(lua.LNil)
L.Push(lua.LString(err.Error()))
return 2
}
for _, f := range files {
tb := L.NewTable()
tb.RawSetString("path", lua.LString(f))
abspath, err := filepath.Abs(f)
if err != nil {
L.Push(lua.LNil)
L.Push(lua.LString(err.Error()))
return 2
}
tb.RawSetString("realpath", lua.LString(abspath))
err = L.CallByParam(lua.P{
Fn: fn,
NRet: 0,
Protect: true,
}, tb)
if err != nil {
L.Push(lua.LNil)
L.Push(lua.LString(err.Error()))
return 2
}
}
L.Push(lua.LTrue)
return 1
}
func isDir(path string) (ret bool) {
fi, err := os.Stat(path)
if err != nil {
return false
}
return fi.IsDir()
}
func oct2decimal(oct int) (uint64, error) {
return strconv.ParseUint(fmt.Sprintf("%d", oct), 8, 32)
}

148
vendor/github.com/kohkimakimoto/gluafs/fs_test.go generated vendored Normal file
View File

@ -0,0 +1,148 @@
package gluafs
import (
"github.com/yuin/gopher-lua"
"io/ioutil"
"os"
"testing"
)
func TestExists(t *testing.T) {
L := lua.NewState()
defer L.Close()
L.PreloadModule("fs", Loader)
if err := L.DoString(`
local fs = require("fs")
assert(fs.exists(".") == true)
`); err != nil {
t.Error(err)
}
}
var tmpFileContent = "aaaaaaaabbbbbbbb"
func TestRead(t *testing.T) {
tmpFile, err := ioutil.TempFile("", "")
if err != nil {
t.Errorf("should not raise error: %v", err)
}
if err = ioutil.WriteFile(tmpFile.Name(), []byte(tmpFileContent), 0644); err != nil {
t.Errorf("should not raise error: %v", err)
}
defer func() {
tmpFile.Close()
os.Remove(tmpFile.Name())
}()
L := lua.NewState()
defer L.Close()
L.PreloadModule("fs", Loader)
if err := L.DoString(`
local fs = require("fs")
local content = fs.read("` + tmpFile.Name() + `")
assert(content == "aaaaaaaabbbbbbbb")
local content2, err = fs.read("` + tmpFile.Name() + `.hoge")
assert(content2 == nil)
`); err != nil {
t.Error(err)
}
}
func TestWrite(t *testing.T) {
tmpDir, err := ioutil.TempDir("", "")
if err != nil {
t.Errorf("should not raise error: %v", err)
}
defer func() {
os.RemoveAll(tmpDir)
}()
L := lua.NewState()
defer L.Close()
L.PreloadModule("fs", Loader)
if err := L.DoString(`
local fs = require("fs")
local ret, err = fs.write("` + tmpDir + `/hoge", "aaaaaaaabbbbbbbb", 755)
local content = fs.read("` + tmpDir + `/hoge")
assert(content == "aaaaaaaabbbbbbbb")
ret, err = fs.write("` + tmpDir + `/hoge/aaaa", "aaaaaaaabbbbbbbb")
assert(ret == nil)
`); err != nil {
t.Error(err)
}
}
func TestMkdir(t *testing.T) {
tmpDir, err := ioutil.TempDir("", "")
if err != nil {
t.Errorf("should not raise error: %v", err)
}
defer func() {
os.RemoveAll(tmpDir)
}()
L := lua.NewState()
defer L.Close()
L.PreloadModule("fs", Loader)
if err := L.DoString(`
local fs = require("fs")
local ret, err = fs.mkdir("` + tmpDir + `/hoge")
assert(ret == true)
local ret, err = fs.mkdir("` + tmpDir + `/hoge/aaa/bbb", 0777, true)
assert(ret == true)
local ret, err = fs.mkdir("` + tmpDir + `/hoge/bbb/eeee", 0777)
assert(ret == nil)
-- print(err)
`); err != nil {
t.Error(err)
}
}
func TestGlob(t *testing.T) {
tmpDir, err := ioutil.TempDir("", "")
if err != nil {
t.Errorf("should not raise error: %v", err)
}
defer func() {
os.RemoveAll(tmpDir)
}()
L := lua.NewState()
defer L.Close()
L.PreloadModule("fs", Loader)
if err := L.DoString(`
local fs = require("fs")
fs.mkdir("` + tmpDir + `/dir01")
fs.mkdir("` + tmpDir + `/dir02")
fs.mkdir("` + tmpDir + `/dir03")
fs.write("` + tmpDir + `/file01", "aaaaaaa")
fs.write("` + tmpDir + `/file02", "bbbbbbb")
local ret, err = fs.glob("` + tmpDir + `/*", function(file)
print(file.path)
print(file.realpath)
end)
assert(ret == true)
assert(err == nil)
`); err != nil {
t.Error(err)
}
}

View File

@ -0,0 +1,6 @@
.DS_Store
Thumbs.db
.tags*
._*
*.iml
.vagrant

20
vendor/github.com/kohkimakimoto/gluaquestion/LICENSE generated vendored Normal file
View File

@ -0,0 +1,20 @@
The MIT License (MIT)
Copyright (c) 2016 Kohki Makimoto
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.

44
vendor/github.com/kohkimakimoto/gluaquestion/README.md generated vendored Normal file
View File

@ -0,0 +1,44 @@
# gluaquestion
A library of [gopher-lua](https://github.com/yuin/gopher-lua) to prompt the user for input.
## Installation
```
go get github.com/kohkimakimoto/gluaquestion
```
## API
* `question.ask(text)`
* `question.secret(text)`
## Usage
```go
package main
import (
"github.com/yuin/gopher-lua"
"github.com/kohkimakimoto/gluaquestion"
)
func main() {
L := lua.NewState()
defer L.Close()
L.PreloadModule("question", gluaquestion.Loader)
if err := L.DoString(`
local question = require("question")
local name = question.ask("What's your name: ")
print("hello " .. name)
-- What's your name: kohki
-- hello kohki
`); err != nil {
panic(err)
}
}
```

View File

@ -0,0 +1,45 @@
package gluaquestion
import (
"bufio"
"fmt"
"os"
"strings"
"github.com/howeyc/gopass"
"github.com/yuin/gopher-lua"
)
// Loader is glua module loader.
func Loader(L *lua.LState) int {
tb := L.NewTable()
L.SetFuncs(tb, map[string]lua.LGFunction{
"ask": ask,
"secret": secret,
})
L.Push(tb)
return 1
}
func ask(L *lua.LState) int {
msg := L.CheckString(1)
fmt.Printf(msg)
reader := bufio.NewReader(os.Stdin)
str, _ := reader.ReadString('\n')
str = strings.TrimRight(str, "\r\n")
L.Push(lua.LString(str))
return 1
}
func secret(L *lua.LState) int {
msg := L.CheckString(1)
fmt.Printf(msg)
pass, _ := gopass.GetPasswd()
L.Push(lua.LString(pass))
return 1
}

6
vendor/github.com/kohkimakimoto/gluassh/.gitignore generated vendored Normal file
View File

@ -0,0 +1,6 @@
.DS_Store
Thumbs.db
.tags*
._*
*.iml
.vagrant

20
vendor/github.com/kohkimakimoto/gluassh/LICENSE generated vendored Normal file
View File

@ -0,0 +1,20 @@
The MIT License (MIT)
Copyright (c) 2016 Kohki Makimoto
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.

10
vendor/github.com/kohkimakimoto/gluassh/Makefile generated vendored Normal file
View File

@ -0,0 +1,10 @@
.PHONY: build dep install test
test_setup:
cd _tests && vagrant up && cd -
test:
go test ./... -cover
testverbose:
go test ./... -v -cover

4
vendor/github.com/kohkimakimoto/gluassh/README.md generated vendored Normal file
View File

@ -0,0 +1,4 @@
# gluassh
SSH library for [gopher-lua](https://github.com/yuin/gopher-lua) to run commands on remote severs.

380
vendor/github.com/kohkimakimoto/gluassh/communicator.go generated vendored Normal file
View File

@ -0,0 +1,380 @@
package gluassh
import (
"bytes"
"crypto/x509"
"encoding/pem"
"errors"
"fmt"
"github.com/pkg/sftp"
"golang.org/x/crypto/ssh"
"golang.org/x/crypto/ssh/agent"
"io"
"io/ioutil"
"net"
"os"
"github.com/yuin/gopher-lua"
)
//
// Refers to
//
// https://github.com/markpeek/packer/blob/53446bf713ed2866b451aa1d00813a90308ee9e9/communicator/ssh/communicator.go
// https://github.com/rapidloop/rtop
// https://github.com/rapidloop/rtop/blob/ba5b35e964135d50e0babedf0bd69b2fcb5dbcb4/src/sshhelper.go#L185
// https://gist.github.com/zxvdr/8229523
//
// SSH communicator
type Communicator struct {
Config *Config
Agent agent.Agent
Auths []ssh.AuthMethod
ClientConfig *ssh.ClientConfig
UpstreamConfig *Config
client *ssh.Client
clientConns []interface {
Close() error
}
OriginalConfig *Config
}
func NewComm(config *Config) (*Communicator, error) {
// Has a proxy?
originalConfig := config
var upstreamConfig *Config = nil
proxy := config.PopProxyConfig()
if proxy != nil {
upstreamConfig = config
config = proxy
}
comm := &Communicator{
Config: config,
UpstreamConfig: upstreamConfig,
clientConns: make([]interface {
Close() error
}, 0),
OriginalConfig: originalConfig,
}
// construct auths
auths := []ssh.AuthMethod{}
if config.UseAgent {
// use ssh-agent
if sock := os.Getenv("SSH_AUTH_SOCK"); len(sock) > 0 {
agconn, err := net.Dial("unix", sock)
if err != nil {
return nil, err
}
ag := agent.NewClient(agconn)
auth := ssh.PublicKeysCallback(ag.Signers)
auths = append(auths, auth)
comm.Agent = ag
} else {
return nil, errors.New("Could not get a socket from SSH_AUTH_SOCK")
}
} else {
// use key file
pemBytes, err := ioutil.ReadFile(config.KeyOrDefault())
if err != nil {
return nil, err
}
block, _ := pem.Decode(pemBytes)
if block == nil {
return nil, errors.New("no key found in " + config.KeyOrDefault())
}
// handle plain and encrypted keyfile
if x509.IsEncryptedPEMBlock(block) {
if config.KeyPassphrase == "" {
return nil, errors.New("You have to set a key_passphrase for the encryped keyfile '" + config.KeyOrDefault() + "'")
}
block.Bytes, err = x509.DecryptPEMBlock(block, []byte(config.KeyPassphrase))
if err != nil {
return nil, err
}
key, err := parsePemBlock(block)
if err != nil {
return nil, err
}
signer, err := ssh.NewSignerFromKey(key)
if err != nil {
return nil, err
}
auths = append(auths, ssh.PublicKeys(signer))
} else {
signer, err := ssh.ParsePrivateKey(pemBytes)
if err != nil {
return nil, err
}
auths = append(auths, ssh.PublicKeys(signer))
}
}
if config.Password != "" {
// Use password
auths = append(auths, ssh.Password(config.Password))
}
comm.Auths = auths
// ssh client config
comm.ClientConfig = &ssh.ClientConfig{
User: config.UserOrDefault(),
Auth: auths,
}
return comm, nil
}
// Exec runs command on remote server.
// It is a low-layer method to be used Run, Script and others method.
func (c *Communicator) Exec(cmd string, opt *Option, L *lua.LState) (*Result, error) {
// get a client
client, err := c.Client()
if err != nil {
return nil, err
}
// get a session
sess, err := client.NewSession()
if err != nil {
return nil, err
}
defer sess.Close()
// RequestAgentForwarding
if c.Config.ForwardAgent && c.Agent != nil {
agent.ForwardToAgent(client, c.Agent)
if err = agent.RequestAgentForwarding(sess); err != nil {
return nil, err
}
}
// Request a PTY
if c.Config.Pty {
// refers to https://github.com/markpeek/packer/blob/53446bf713ed2866b451aa1d00813a90308ee9e9/communicator/ssh/communicator.go
termModes := ssh.TerminalModes{
ssh.ECHO: 0, // do not echo
ssh.TTY_OP_ISPEED: 14400, // input speed = 14.4kbaud
ssh.TTY_OP_OSPEED: 14400, // output speed = 14.4kbaud
}
err = sess.RequestPty("xterm", 80, 40, termModes)
if err != nil {
return nil, err
}
}
// Compose sudo command line.
if opt.Sudo {
if opt.User != "" {
cmd = "sudo -Sku " + opt.User + " /bin/sh -l -c '" + cmd + "'"
} else {
cmd = "sudo -Sk /bin/sh -l -c '" + cmd + "'"
}
}
// apply io
var outWriter io.Writer
var errWriter io.Writer
var inReader io.Reader
// buffer
var outBuffer = new(bytes.Buffer)
var errBuffer = new(bytes.Buffer)
var inBuffer = new(bytes.Buffer)
// append stdio to buffer
if opt.UseStdout {
if opt.OutputFunc != nil {
outWriter = io.MultiWriter(os.Stdout, outBuffer, NewLFuncWriter(1, opt.OutputFunc, L))
} else {
outWriter = io.MultiWriter(os.Stdout, outBuffer)
}
} else {
outWriter = io.MultiWriter(outBuffer)
}
if opt.UseStderr {
if opt.OutputFunc != nil {
errWriter = io.MultiWriter(os.Stderr, errBuffer, NewLFuncWriter(2, opt.OutputFunc, L))
} else {
errWriter = io.MultiWriter(os.Stderr, errBuffer)
}
} else {
errWriter = io.MultiWriter(errBuffer)
}
inReader = io.MultiReader(inBuffer, os.Stdin)
sess.Stdin = inReader
sess.Stdout = outWriter
sess.Stderr = errWriter
// write sudo password
if opt.Password != "" {
// If it try to use sudo password, write password to input buffer
fmt.Fprintln(inBuffer, opt.Password)
}
err = sess.Run(cmd)
if err != nil {
if exitErr, ok := err.(*ssh.ExitError); ok {
return NewResult(outBuffer, errBuffer, exitErr.ExitStatus()), err
} else {
return NewResult(outBuffer, errBuffer, 1), err
}
}
return NewResult(outBuffer, errBuffer, 0), nil
}
func (c *Communicator) Run(cmd string, opt *Option, L *lua.LState) (*Result, error) {
return c.Exec(cmd, opt, L)
}
func (c *Communicator) Get(remote string, local string) error {
client, err := c.Client()
if err != nil {
return err
}
sc, err := sftp.NewClient(client)
if err != nil {
return err
}
defer sc.Close()
fi, err := sc.Open(remote)
if err != nil {
return err
}
defer fi.Close()
fo, err := os.Create(local)
if err != nil {
return err
}
defer fo.Close()
_, err = io.Copy(fo, fi)
if err != nil {
return err
}
return nil
}
func (c *Communicator) Put(local string, remote string) error {
client, err := c.Client()
if err != nil {
return err
}
sc, err := sftp.NewClient(client)
if err != nil {
return err
}
defer sc.Close()
b, err := ioutil.ReadFile(local)
if err != nil {
return err
}
fo, err := sc.Create(remote)
if err != nil {
return err
}
defer fo.Close()
_, err = fo.Write(b)
if err != nil {
return err
}
return nil
}
func (c *Communicator) Client() (*ssh.Client, error) {
if c.client != nil {
return c.client, nil
}
// create ssh client.
client, err := ssh.Dial("tcp", c.Config.HostOrDefault()+":"+c.Config.PortOrDefault(), c.ClientConfig)
if err != nil {
return nil, err
}
c.clientConns = append(c.clientConns, client)
// If it has a upstream server?
for c.UpstreamConfig != nil {
// It is next server config to connect.
var config *Config = nil
// Does the upstream server need proxy to connet?
proxy := c.UpstreamConfig.PopProxyConfig()
if proxy != nil {
config = proxy
} else {
config = c.UpstreamConfig
c.UpstreamConfig = nil
}
// dial to ssh proxy
connection, err := client.Dial("tcp", config.HostOrDefault()+":"+config.PortOrDefault())
if err != nil {
return nil, err
}
c.clientConns = append(c.clientConns, connection)
conn, chans, reqs, err := ssh.NewClientConn(connection, config.HostOrDefault()+":"+config.PortOrDefault(), c.ClientConfig)
if err != nil {
return nil, err
}
client = ssh.NewClient(conn, chans, reqs)
c.clientConns = append(c.clientConns, client)
if err != nil {
return nil, err
}
}
c.client = client
return c.client, nil
}
func (c *Communicator) Close() error {
for _, conn := range c.clientConns {
err := conn.Close()
if err != nil {
return err
}
}
return nil
}
// ref golang.org/x/crypto/ssh/keys.go#ParseRawPrivateKey.
func parsePemBlock(block *pem.Block) (interface{}, error) {
switch block.Type {
case "RSA PRIVATE KEY":
return x509.ParsePKCS1PrivateKey(block.Bytes)
case "EC PRIVATE KEY":
return x509.ParseECPrivateKey(block.Bytes)
case "DSA PRIVATE KEY":
return ssh.ParseDSAPrivateKey(block.Bytes)
default:
return nil, fmt.Errorf("rtop: unsupported key type %q", block.Type)
}
}

106
vendor/github.com/kohkimakimoto/gluassh/config.go generated vendored Normal file
View File

@ -0,0 +1,106 @@
package gluassh
import (
"encoding/json"
"os"
"os/user"
"path/filepath"
)
// SSH connection config.
type Config struct {
Host string `json:"host"`
Port string `json:"port"`
User string `json:"user"`
Key string `json:"key"`
KeyPassphrase string `json:"key_passphrase"`
UseAgent bool `json:"use_agent"`
ForwardAgent bool `json:"forward_agent"`
Pty bool `json:"pty"`
Password string `json:"password"`
Proxy *Config `json:"proxy"`
}
// NewConfig creates new config instance.
func NewConfig() *Config {
c := &Config{}
return c
}
// Pop the last proxy server
func (c *Config) PopProxyConfig() *Config {
proxy := c.Proxy
if proxy == nil {
return nil
}
if proxy.Proxy != nil {
return proxy.PopProxyConfig()
}
c.Proxy = nil
return proxy
}
func (c *Config) UpdateWithJSON(data []byte) error {
err := json.Unmarshal(data, c)
if err != nil {
return err
}
return nil
}
func (c *Config) ConfigsChain() []*Config {
var configs []*Config
configs = append(configs, c)
if c.Proxy != nil {
proxyConfigs := c.Proxy.ConfigsChain()
configs = append(proxyConfigs, configs...)
}
return configs
}
func (c *Config) HostOrDefault() string {
if c.Host == "" {
return "localhost"
} else {
return c.Host
}
}
func (c *Config) PortOrDefault() string {
if c.Port == "" {
return "22"
} else {
return c.Port
}
}
func (c *Config) KeyOrDefault() string {
if c.Key == "" {
home := os.Getenv("HOME")
if home == "" {
home = os.Getenv("USERPROFILE")
}
return filepath.Join(home, ".ssh/id_rsa")
}
return c.Key
}
func (c *Config) UserOrDefault() string {
if c.User == "" {
u, err := user.Current()
if err == nil {
return u.Username
}
}
return c.User
}

232
vendor/github.com/kohkimakimoto/gluassh/gluassh.go generated vendored Normal file
View File

@ -0,0 +1,232 @@
package gluassh
import (
"github.com/yuin/gluamapper"
"github.com/yuin/gopher-lua"
"errors"
)
const LConnectionClass = "SSHConnectionClass*"
type Connection struct {
}
// Loader is glua module loader.
func Loader(L *lua.LState) int {
// register ssh connection class
registerConnectionClass(L)
// load module
tb := L.NewTable()
L.SetFuncs(tb, map[string]lua.LGFunction{
"run": run,
"get": get,
"put": put,
})
// set up meta table
mt := L.NewTable()
L.SetField(mt, "__call",L.NewFunction(call))
L.SetMetatable(tb, mt)
L.Push(tb)
return 1
}
func registerConnectionClass(L *lua.LState) {
mt := L.NewTypeMetatable(LConnectionClass)
// methods
L.SetField(mt, "__index", L.SetFuncs(L.NewTable(), map[string]lua.LGFunction{
// "run": connRun,
// "get": connGet,
// "put": connPut,
}))
}
func call(L *lua.LState) int {
// TODO: implements
if L.GetTop() != 2 {
L.RaiseError("calling ssh requires 1 argment that is a server config.")
}
// tb := L.Get(1)
return 0
}
func newConnection(L *lua.LState) int {
connection := &Connection{}
ud := L.NewUserData()
ud.Value = connection
L.SetMetatable(ud, L.GetTypeMetatable(LConnectionClass))
L.Push(ud)
return 1
}
// This is a Lua module function.
// run execute command on a remote host via SSH.
func run(L *lua.LState) int {
// communicator
comm, err := commFromLTable(L.CheckTable(1))
if err != nil {
panic(err)
}
defer comm.Close()
// option and command
option := NewOption()
cmd := ""
if L.GetTop() == 4 {
if err := gluamapper.Map(L.CheckTable(2), option); err != nil {
panic(err)
}
cmds, err := toStrings(L.Get(3))
if err != nil {
panic(err)
}
cmd = concatCommandLines(cmds)
fn := L.CheckFunction(4)
option.OutputFunc = fn
} else if L.GetTop() == 3 {
if err := gluamapper.Map(L.CheckTable(2), option); err != nil {
panic(err)
}
cmds, err := toStrings(L.Get(3))
if err != nil {
panic(err)
}
cmd = concatCommandLines(cmds)
} else if L.GetTop() == 2 {
cmds, err := toStrings(L.Get(2))
if err != nil {
panic(err)
}
cmd = concatCommandLines(cmds)
} else {
L.RaiseError("run method requires 2 arugments at least.")
}
// run
ret, err := comm.Run(cmd, option, L)
if err != nil {
L.RaiseError("ssh error: %s", err)
}
tb := updateLTableByRunResult(L.NewTable(), ret)
L.Push(tb)
return 1
}
// This is a Lua module function.
func get(L *lua.LState) int {
// communicator
comm, err := commFromLTable(L.CheckTable(1))
if err != nil {
panic(err)
}
defer comm.Close()
remote := L.ToString(2)
local := L.ToString(3)
err = comm.Get(remote, local)
if err != nil {
panic(err)
}
return 0
}
// This is a Lua module function.
func put(L *lua.LState) int {
// communicator
comm, err := commFromLTable(L.CheckTable(1))
if err != nil {
panic(err)
}
defer comm.Close()
local := L.ToString(2)
remote := L.ToString(3)
err = comm.Put(local, remote)
if err != nil {
panic(err)
}
return 0
}
func commFromLTable(table *lua.LTable) (*Communicator, error) {
// config
cfg := NewConfig()
// update config by passed table.
if err := gluamapper.Map(table, cfg); err != nil {
return nil, err
}
// communicator
comm, err := NewComm(cfg)
if err != nil {
return nil, err
}
return comm, nil
}
func toStrings(v lua.LValue) ([]string, error) {
var ret []string
if lv, ok := v.(*lua.LTable); ok {
lv.ForEach(func(tk lua.LValue, tv lua.LValue) {
if ls, ok := tv.(lua.LString); ok {
ret = append(ret, string(ls))
}
})
} else {
if ls, ok := v.(lua.LString); ok {
ret = append(ret, string(ls))
} else {
return ret, errors.New("Could not transfer lua value to string slice")
}
}
return ret, nil
}
func concatCommandLines(cmdlines []string) string {
cmdline := ""
for i, v := range cmdlines {
if i == 0 {
cmdline = v
} else {
cmdline = cmdline + " && " + v
}
}
return cmdline
}
func updateLTableByRunResult(tb *lua.LTable, ret *Result) *lua.LTable {
if ret != nil {
tb.RawSetString("out", lua.LString(ret.Out.String()))
tb.RawSetString("err", lua.LString(ret.Err.String()))
tb.RawSetString("status", lua.LNumber(ret.Status))
tb.RawSetString("successful", lua.LBool(ret.Successful()))
tb.RawSetString("failed", lua.LBool(ret.Failed()))
} else {
tb.RawSetString("out", lua.LNil)
tb.RawSetString("err", lua.LNil)
tb.RawSetString("status", lua.LNil)
tb.RawSetString("successful", lua.LBool(false))
tb.RawSetString("failed", lua.LBool(true))
}
return tb
}

120
vendor/github.com/kohkimakimoto/gluassh/gluassh_test.go generated vendored Normal file
View File

@ -0,0 +1,120 @@
package gluassh
import(
"testing"
"github.com/yuin/gopher-lua"
"os"
"path/filepath"
)
var keynopass string
var keypass string
func TestRunWithKeynopass(t *testing.T) {
L := lua.NewState()
defer L.Close()
L.PreloadModule("ssh", Loader)
if err := L.DoString(`
local ssh = require "ssh"
conn_user_keynopass = {
host = "192.168.56.81",
port = "22",
user = "user_keynopass",
key = "` + keynopass + `",
}
local ret = ssh.run(conn_user_keynopass, "hostname")
assert(ret.out == "gluassh-test-server\n")
`); err != nil {
t.Error(err)
}
}
func TestRunWithKeynopassSudo(t *testing.T) {
L := lua.NewState()
defer L.Close()
L.PreloadModule("ssh", Loader)
if err := L.DoString(`
local ssh = require "ssh"
conn_user_keynopass = {
host = "192.168.56.81",
port = "22",
user = "user_keynopass",
key = "` + keynopass + `",
}
ret = ssh.run(conn_user_keynopass, {sudo = true}, "whoami")
assert(ret.out == "root\n")
`); err != nil {
t.Error(err)
}
}
func TestRunWithKeypass(t *testing.T) {
L := lua.NewState()
defer L.Close()
L.PreloadModule("ssh", Loader)
if err := L.DoString(`
local ssh = require "ssh"
conn_user_keypass = {
host = "192.168.56.81",
port = "22",
user = "user_keypass",
key = "` + keypass + `",
key_passphrase = "hogehoge",
}
local ret = ssh.run(conn_user_keypass, "hostname")
assert(ret.out == "gluassh-test-server\n")
`); err != nil {
t.Error(err)
}
}
func TestRunWithKeynopassFunc(t *testing.T) {
L := lua.NewState()
defer L.Close()
L.PreloadModule("ssh", Loader)
if err := L.DoString(`
local ssh = require "ssh"
conn_user_keynopass = {
host = "192.168.56.81",
port = "22",
user = "user_keynopass",
key = "` + keynopass + `",
}
local ret = ssh.run(conn_user_keynopass, {}, "hostname", function(stdout, stderr)
print(stdout)
end)
`); err != nil {
t.Error(err)
}
}
func init() {
wd, err := os.Getwd()
if err != nil {
panic(err)
}
keynopass = filepath.Join(wd, "_tests", "keys", "id_rsa.nopass")
keypass = filepath.Join(wd, "_tests", "keys", "id_rsa.pass")
}

70
vendor/github.com/kohkimakimoto/gluassh/option.go generated vendored Normal file
View File

@ -0,0 +1,70 @@
package gluassh
import (
"github.com/yuin/gopher-lua"
)
// SSH run option
type Option struct {
// Use sudo
Sudo bool
// sudo user
User string
// sudo password
Password string
// Use stdout
UseStdout bool
// Use stderr
UseStderr bool
// function receives output.
OutputFunc *lua.LFunction
}
func NewOption() *Option {
opt := &Option{
Sudo: false,
UseStdout: true,
UseStderr: true,
}
return opt
}
type LFuncWriter struct {
outType int
fn *lua.LFunction
L *lua.LState
}
func NewLFuncWriter(outType int, fn *lua.LFunction, L *lua.LState) *LFuncWriter {
return &LFuncWriter{
L: L,
outType: outType,
fn: fn,
}
}
func (w *LFuncWriter) Write(data []byte) (int, error) {
if w.outType == 1 {
err := w.L.CallByParam(lua.P{
Fn: w.fn,
NRet: 0,
Protect: true,
}, lua.LString(string(data)))
if err != nil {
return len(data), err
}
} else {
err := w.L.CallByParam(lua.P{
Fn: w.fn,
NRet: 0,
Protect: true,
}, lua.LString(string(data)))
if err != nil {
return len(data), err
}
}
return len(data), nil
}

31
vendor/github.com/kohkimakimoto/gluassh/result.go generated vendored Normal file
View File

@ -0,0 +1,31 @@
package gluassh
import (
"bytes"
)
type Result struct {
Out *bytes.Buffer
Err *bytes.Buffer
Status int
}
func NewResult(outbuf *bytes.Buffer, errbuf *bytes.Buffer, status int) *Result {
return &Result{
Out: outbuf,
Err: errbuf,
Status: status,
}
}
func (r *Result) Successful() bool {
if r.Status == 0 {
return true
} else {
return false
}
}
func (r *Result) Failed() bool {
return !r.Successful()
}

View File

@ -0,0 +1,6 @@
.DS_Store
Thumbs.db
/.tags*
._*
*.iml
/_vendor

20
vendor/github.com/kohkimakimoto/gluatemplate/LICENSE generated vendored Normal file
View File

@ -0,0 +1,20 @@
The MIT License (MIT)
Copyright (c) 2015 Kohki Makimoto
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.

67
vendor/github.com/kohkimakimoto/gluatemplate/README.md generated vendored Normal file
View File

@ -0,0 +1,67 @@
# gluatemplate
Text template for [gopher-lua](https://github.com/yuin/gopher-lua)
This product is based on [Go Text Template](https://golang.org/pkg/text/template/).
If you are not familiar with the syntax, please read the documentation.
## Installation
```
go get github.com/kohkimakimoto/gluatemplate
```
## API
### `template.dostring(text, table)`
Returns string generated by text template with the table values. If this function fails, it returns `nil`, plus a string describing the error.
### `template.dofile(file, table)`
Returns string generated by file template with the table values. If this function fails, it returns `nil`, plus a string describing the error.
## Usage
```go
package main
import (
"github.com/yuin/gopher-lua"
"github.com/kohkimakimoto/gluatemplate"
)
func main() {
L := lua.NewState()
defer L.Close()
L.PreloadModule("template", gluatemplate.Loader)
if err := L.DoString(`
local template = require("template")
local text = template.dostring([[
This is a text template library.
Created by {{.first_name}} {{.last_name}}
]], {
first_name = "kohki",
last_name = "makimoto",
})
print(text)
--
-- This is a text template library.
-- Created by kohki makimoto
--
`); err != nil {
panic(err)
}
}
```
## Author
Kohki Makimoto <kohki.makimoto@gmail.com>
## License
MIT license.

View File

@ -0,0 +1,106 @@
package gluatemplate
import (
"bytes"
"fmt"
"github.com/yuin/gopher-lua"
"text/template"
)
func Loader(L *lua.LState) int {
tb := L.NewTable()
L.SetFuncs(tb, map[string]lua.LGFunction{
"dostring": doString,
"dofile": doFile,
})
L.Push(tb)
return 1
}
// render
func doString(L *lua.LState) int {
tmplcontent := L.CheckString(1)
var dict interface{}
tmpl, err := template.New("T").Parse(tmplcontent)
if err != nil {
L.Push(lua.LNil)
L.Push(lua.LString(err.Error()))
return 2
}
if L.GetTop() >= 2 {
dict = toGoValue(L.CheckTable(2))
}
var b bytes.Buffer
if err := tmpl.Execute(&b, dict); err != nil {
L.Push(lua.LNil)
L.Push(lua.LString(err.Error()))
return 2
}
s := b.String()
L.Push(lua.LString(s))
return 1
}
func doFile(L *lua.LState) int {
tmplfile := L.CheckString(1)
var dict interface{}
tmpl, err := template.ParseFiles(tmplfile)
if err != nil {
L.Push(lua.LNil)
L.Push(lua.LString(err.Error()))
return 2
}
if L.GetTop() >= 2 {
dict = toGoValue(L.CheckTable(2))
}
var b bytes.Buffer
if err := tmpl.Execute(&b, dict); err != nil {
L.Push(lua.LNil)
L.Push(lua.LString(err.Error()))
return 2
}
s := b.String()
L.Push(lua.LString(s))
return 1
}
// This code refers to https://github.com/yuin/gluamapper/blob/master/gluamapper.go
func toGoValue(lv lua.LValue) interface{} {
switch v := lv.(type) {
case *lua.LNilType:
return nil
case lua.LBool:
return bool(v)
case lua.LString:
return string(v)
case lua.LNumber:
return float64(v)
case *lua.LTable:
maxn := v.MaxN()
if maxn == 0 { // table
ret := make(map[interface{}]interface{})
v.ForEach(func(key, value lua.LValue) {
keystr := fmt.Sprint(toGoValue(key))
ret[keystr] = toGoValue(value)
})
return ret
} else { // array
ret := make([]interface{}, 0, maxn)
for i := 1; i <= maxn; i++ {
ret = append(ret, toGoValue(v.RawGetInt(i)))
}
return ret
}
default:
return v
}
}

Some files were not shown because too many files have changed in this diff Show More