mirror of
https://github.com/woodpecker-ci/woodpecker.git
synced 2024-11-26 20:01:02 +00:00
Merge pull request #1517 from bradrydzewski/master
remove vexp from vendoring process [CI SKIP]
This commit is contained in:
commit
671461dc00
648 changed files with 76035 additions and 167838 deletions
|
@ -38,14 +38,14 @@ func Run(client dockerclient.Client, conf *dockerclient.ContainerConfig, name st
|
|||
func RunDaemon(client dockerclient.Client, conf *dockerclient.ContainerConfig, name string) (*dockerclient.ContainerInfo, error) {
|
||||
|
||||
// attempts to create the contianer
|
||||
id, err := client.CreateContainer(conf, name)
|
||||
id, err := client.CreateContainer(conf, name, nil)
|
||||
if err != nil {
|
||||
// and pull the image and re-create if that fails
|
||||
err = client.PullImage(conf.Image, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
id, err = client.CreateContainer(conf, name)
|
||||
id, err = client.CreateContainer(conf, name, nil)
|
||||
if err != nil {
|
||||
client.RemoveContainer(id, true, true)
|
||||
return nil, err
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
Copyright (c) 2013 Apollic Software, LLC. All rights reserved.
|
||||
Copyright (c) 2015 Functional Software, Inc. All rights reserved.
|
||||
Copyright (c) 2009 The Go Authors. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
|
@ -11,7 +10,7 @@ notice, this list of conditions and the following disclaimer.
|
|||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
* Neither the name of Apollic Software, LLC nor the names of its
|
||||
* Neither the name of Google Inc. nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
22
vendor/code.google.com/p/go.crypto/PATENTS
generated
vendored
Normal file
22
vendor/code.google.com/p/go.crypto/PATENTS
generated
vendored
Normal file
|
@ -0,0 +1,22 @@
|
|||
Additional IP Rights Grant (Patents)
|
||||
|
||||
"This implementation" means the copyrightable works distributed by
|
||||
Google as part of the Go project.
|
||||
|
||||
Google hereby grants to You a perpetual, worldwide, non-exclusive,
|
||||
no-charge, royalty-free, irrevocable (except as stated in this section)
|
||||
patent license to make, have made, use, offer to sell, sell, import,
|
||||
transfer and otherwise run, modify and propagate the contents of this
|
||||
implementation of Go, where such license applies only to those patent
|
||||
claims, both currently owned or controlled by Google and acquired in
|
||||
the future, licensable by Google that are necessarily infringed by this
|
||||
implementation of Go. This grant does not include claims that would be
|
||||
infringed only as a consequence of further modification of this
|
||||
implementation. If you or your agent or exclusive licensee institute or
|
||||
order or agree to the institution of patent litigation against any
|
||||
entity (including a cross-claim or counterclaim in a lawsuit) alleging
|
||||
that this implementation of Go or any code incorporated within this
|
||||
implementation of Go constitutes direct or contributory patent
|
||||
infringement, or inducement of patent infringement, then any patent
|
||||
rights granted to you under this License for this implementation of Go
|
||||
shall terminate as of the date such litigation is filed.
|
87
vendor/code.google.com/p/go.crypto/ssh/buffer_test.go
generated
vendored
87
vendor/code.google.com/p/go.crypto/ssh/buffer_test.go
generated
vendored
|
@ -1,87 +0,0 @@
|
|||
// Copyright 2011 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package ssh
|
||||
|
||||
import (
|
||||
"io"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var BYTES = []byte("abcdefghijklmnopqrstuvwxyz")
|
||||
|
||||
func TestBufferReadwrite(t *testing.T) {
|
||||
b := newBuffer()
|
||||
b.write(BYTES[:10])
|
||||
r, _ := b.Read(make([]byte, 10))
|
||||
if r != 10 {
|
||||
t.Fatalf("Expected written == read == 10, written: 10, read %d", r)
|
||||
}
|
||||
|
||||
b = newBuffer()
|
||||
b.write(BYTES[:5])
|
||||
r, _ = b.Read(make([]byte, 10))
|
||||
if r != 5 {
|
||||
t.Fatalf("Expected written == read == 5, written: 5, read %d", r)
|
||||
}
|
||||
|
||||
b = newBuffer()
|
||||
b.write(BYTES[:10])
|
||||
r, _ = b.Read(make([]byte, 5))
|
||||
if r != 5 {
|
||||
t.Fatalf("Expected written == 10, read == 5, written: 10, read %d", r)
|
||||
}
|
||||
|
||||
b = newBuffer()
|
||||
b.write(BYTES[:5])
|
||||
b.write(BYTES[5:15])
|
||||
r, _ = b.Read(make([]byte, 10))
|
||||
r2, _ := b.Read(make([]byte, 10))
|
||||
if r != 10 || r2 != 5 || 15 != r+r2 {
|
||||
t.Fatal("Expected written == read == 15")
|
||||
}
|
||||
}
|
||||
|
||||
func TestBufferClose(t *testing.T) {
|
||||
b := newBuffer()
|
||||
b.write(BYTES[:10])
|
||||
b.eof()
|
||||
_, err := b.Read(make([]byte, 5))
|
||||
if err != nil {
|
||||
t.Fatal("expected read of 5 to not return EOF")
|
||||
}
|
||||
b = newBuffer()
|
||||
b.write(BYTES[:10])
|
||||
b.eof()
|
||||
r, err := b.Read(make([]byte, 5))
|
||||
r2, err2 := b.Read(make([]byte, 10))
|
||||
if r != 5 || r2 != 5 || err != nil || err2 != nil {
|
||||
t.Fatal("expected reads of 5 and 5")
|
||||
}
|
||||
|
||||
b = newBuffer()
|
||||
b.write(BYTES[:10])
|
||||
b.eof()
|
||||
r, err = b.Read(make([]byte, 5))
|
||||
r2, err2 = b.Read(make([]byte, 10))
|
||||
r3, err3 := b.Read(make([]byte, 10))
|
||||
if r != 5 || r2 != 5 || r3 != 0 || err != nil || err2 != nil || err3 != io.EOF {
|
||||
t.Fatal("expected reads of 5 and 5 and 0, with EOF")
|
||||
}
|
||||
|
||||
b = newBuffer()
|
||||
b.write(make([]byte, 5))
|
||||
b.write(make([]byte, 10))
|
||||
b.eof()
|
||||
r, err = b.Read(make([]byte, 9))
|
||||
r2, err2 = b.Read(make([]byte, 3))
|
||||
r3, err3 = b.Read(make([]byte, 3))
|
||||
r4, err4 := b.Read(make([]byte, 10))
|
||||
if err != nil || err2 != nil || err3 != nil || err4 != io.EOF {
|
||||
t.Fatalf("Expected EOF on forth read only, err=%v, err2=%v, err3=%v, err4=%v", err, err2, err3, err4)
|
||||
}
|
||||
if r != 9 || r2 != 3 || r3 != 3 || r4 != 0 {
|
||||
t.Fatal("Expected written == read == 15", r, r2, r3, r4)
|
||||
}
|
||||
}
|
55
vendor/code.google.com/p/go.crypto/ssh/certs_test.go
generated
vendored
55
vendor/code.google.com/p/go.crypto/ssh/certs_test.go
generated
vendored
|
@ -1,55 +0,0 @@
|
|||
// Copyright 2013 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package ssh
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// Cert generated by ssh-keygen 6.0p1 Debian-4.
|
||||
// % ssh-keygen -s ca-key -I test user-key
|
||||
var exampleSSHCert = `ssh-rsa-cert-v01@openssh.com AAAAHHNzaC1yc2EtY2VydC12MDFAb3BlbnNzaC5jb20AAAAgb1srW/W3ZDjYAO45xLYAwzHBDLsJ4Ux6ICFIkTjb1LEAAAADAQABAAAAYQCkoR51poH0wE8w72cqSB8Sszx+vAhzcMdCO0wqHTj7UNENHWEXGrU0E0UQekD7U+yhkhtoyjbPOVIP7hNa6aRk/ezdh/iUnCIt4Jt1v3Z1h1P+hA4QuYFMHNB+rmjPwAcAAAAAAAAAAAAAAAEAAAAEdGVzdAAAAAAAAAAAAAAAAP//////////AAAAAAAAAIIAAAAVcGVybWl0LVgxMS1mb3J3YXJkaW5nAAAAAAAAABdwZXJtaXQtYWdlbnQtZm9yd2FyZGluZwAAAAAAAAAWcGVybWl0LXBvcnQtZm9yd2FyZGluZwAAAAAAAAAKcGVybWl0LXB0eQAAAAAAAAAOcGVybWl0LXVzZXItcmMAAAAAAAAAAAAAAHcAAAAHc3NoLXJzYQAAAAMBAAEAAABhANFS2kaktpSGc+CcmEKPyw9mJC4nZKxHKTgLVZeaGbFZOvJTNzBspQHdy7Q1uKSfktxpgjZnksiu/tFF9ngyY2KFoc+U88ya95IZUycBGCUbBQ8+bhDtw/icdDGQD5WnUwAAAG8AAAAHc3NoLXJzYQAAAGC8Y9Z2LQKhIhxf52773XaWrXdxP0t3GBVo4A10vUWiYoAGepr6rQIoGGXFxT4B9Gp+nEBJjOwKDXPrAevow0T9ca8gZN+0ykbhSrXLE5Ao48rqr3zP4O1/9P7e6gp0gw8=`
|
||||
|
||||
func TestParseCert(t *testing.T) {
|
||||
authKeyBytes := []byte(exampleSSHCert)
|
||||
|
||||
key, _, _, rest, ok := ParseAuthorizedKey(authKeyBytes)
|
||||
if !ok {
|
||||
t.Fatalf("could not parse certificate")
|
||||
}
|
||||
if len(rest) > 0 {
|
||||
t.Errorf("rest: got %q, want empty", rest)
|
||||
}
|
||||
|
||||
if _, ok = key.(*OpenSSHCertV01); !ok {
|
||||
t.Fatalf("got %#v, want *OpenSSHCertV01", key)
|
||||
}
|
||||
|
||||
marshaled := MarshalAuthorizedKey(key)
|
||||
// Before comparison, remove the trailing newline that
|
||||
// MarshalAuthorizedKey adds.
|
||||
marshaled = marshaled[:len(marshaled)-1]
|
||||
if !bytes.Equal(authKeyBytes, marshaled) {
|
||||
t.Errorf("marshaled certificate does not match original: got %q, want %q", marshaled, authKeyBytes)
|
||||
}
|
||||
}
|
||||
|
||||
func TestVerifyCert(t *testing.T) {
|
||||
key, _, _, _, _ := ParseAuthorizedKey([]byte(exampleSSHCert))
|
||||
validCert := key.(*OpenSSHCertV01)
|
||||
if ok := validateOpenSSHCertV01Signature(validCert); !ok {
|
||||
t.Error("Unable to validate certificate!")
|
||||
}
|
||||
|
||||
invalidCert := &OpenSSHCertV01{
|
||||
Key: rsaKey.PublicKey(),
|
||||
SignatureKey: ecdsaKey.PublicKey(),
|
||||
Signature: &signature{},
|
||||
}
|
||||
if ok := validateOpenSSHCertV01Signature(invalidCert); ok {
|
||||
t.Error("Invalid cert signature passed validation!")
|
||||
}
|
||||
}
|
62
vendor/code.google.com/p/go.crypto/ssh/cipher_test.go
generated
vendored
62
vendor/code.google.com/p/go.crypto/ssh/cipher_test.go
generated
vendored
|
@ -1,62 +0,0 @@
|
|||
// Copyright 2011 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package ssh
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// TestCipherReversal tests that each cipher factory produces ciphers that can
|
||||
// encrypt and decrypt some data successfully.
|
||||
func TestCipherReversal(t *testing.T) {
|
||||
testData := []byte("abcdefghijklmnopqrstuvwxyz012345")
|
||||
testKey := []byte("AbCdEfGhIjKlMnOpQrStUvWxYz012345")
|
||||
testIv := []byte("sdflkjhsadflkjhasdflkjhsadfklhsa")
|
||||
|
||||
cryptBuffer := make([]byte, 32)
|
||||
|
||||
for name, cipherMode := range cipherModes {
|
||||
encrypter, err := cipherMode.createCipher(testKey, testIv)
|
||||
if err != nil {
|
||||
t.Errorf("failed to create encrypter for %q: %s", name, err)
|
||||
continue
|
||||
}
|
||||
decrypter, err := cipherMode.createCipher(testKey, testIv)
|
||||
if err != nil {
|
||||
t.Errorf("failed to create decrypter for %q: %s", name, err)
|
||||
continue
|
||||
}
|
||||
|
||||
copy(cryptBuffer, testData)
|
||||
|
||||
encrypter.XORKeyStream(cryptBuffer, cryptBuffer)
|
||||
if name == "none" {
|
||||
if !bytes.Equal(cryptBuffer, testData) {
|
||||
t.Errorf("encryption made change with 'none' cipher")
|
||||
continue
|
||||
}
|
||||
} else {
|
||||
if bytes.Equal(cryptBuffer, testData) {
|
||||
t.Errorf("encryption made no change with %q", name)
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
decrypter.XORKeyStream(cryptBuffer, cryptBuffer)
|
||||
if !bytes.Equal(cryptBuffer, testData) {
|
||||
t.Errorf("decrypted bytes not equal to input with %q", name)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestDefaultCiphersExist(t *testing.T) {
|
||||
for _, cipherAlgo := range DefaultCipherOrder {
|
||||
if _, ok := cipherModes[cipherAlgo]; !ok {
|
||||
t.Errorf("default cipher %q is unknown", cipherAlgo)
|
||||
}
|
||||
}
|
||||
}
|
368
vendor/code.google.com/p/go.crypto/ssh/client_auth_test.go
generated
vendored
368
vendor/code.google.com/p/go.crypto/ssh/client_auth_test.go
generated
vendored
|
@ -1,368 +0,0 @@
|
|||
// Copyright 2011 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package ssh
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/dsa"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"math/big"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
_ "crypto/sha1"
|
||||
)
|
||||
|
||||
// private key for mock server
|
||||
const testServerPrivateKey = `-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEpAIBAAKCAQEA19lGVsTqIT5iiNYRgnoY1CwkbETW5cq+Rzk5v/kTlf31XpSU
|
||||
70HVWkbTERECjaYdXM2gGcbb+sxpq6GtXf1M3kVomycqhxwhPv4Cr6Xp4WT/jkFx
|
||||
9z+FFzpeodGJWjOH6L2H5uX1Cvr9EDdQp9t9/J32/qBFntY8GwoUI/y/1MSTmMiF
|
||||
tupdMODN064vd3gyMKTwrlQ8tZM6aYuyOPsutLlUY7M5x5FwMDYvnPDSeyT/Iw0z
|
||||
s3B+NCyqeeMd2T7YzQFnRATj0M7rM5LoSs7DVqVriOEABssFyLj31PboaoLhOKgc
|
||||
qoM9khkNzr7FHVvi+DhYM2jD0DwvqZLN6NmnLwIDAQABAoIBAQCGVj+kuSFOV1lT
|
||||
+IclQYA6bM6uY5mroqcSBNegVxCNhWU03BxlW//BE9tA/+kq53vWylMeN9mpGZea
|
||||
riEMIh25KFGWXqXlOOioH8bkMsqA8S7sBmc7jljyv+0toQ9vCCtJ+sueNPhxQQxH
|
||||
D2YvUjfzBQ04I9+wn30BByDJ1QA/FoPsunxIOUCcRBE/7jxuLYcpR+JvEF68yYIh
|
||||
atXRld4W4in7T65YDR8jK1Uj9XAcNeDYNpT/M6oFLx1aPIlkG86aCWRO19S1jLPT
|
||||
b1ZAKHHxPMCVkSYW0RqvIgLXQOR62D0Zne6/2wtzJkk5UCjkSQ2z7ZzJpMkWgDgN
|
||||
ifCULFPBAoGBAPoMZ5q1w+zB+knXUD33n1J+niN6TZHJulpf2w5zsW+m2K6Zn62M
|
||||
MXndXlVAHtk6p02q9kxHdgov34Uo8VpuNjbS1+abGFTI8NZgFo+bsDxJdItemwC4
|
||||
KJ7L1iz39hRN/ZylMRLz5uTYRGddCkeIHhiG2h7zohH/MaYzUacXEEy3AoGBANz8
|
||||
e/msleB+iXC0cXKwds26N4hyMdAFE5qAqJXvV3S2W8JZnmU+sS7vPAWMYPlERPk1
|
||||
D8Q2eXqdPIkAWBhrx4RxD7rNc5qFNcQWEhCIxC9fccluH1y5g2M+4jpMX2CT8Uv+
|
||||
3z+NoJ5uDTXZTnLCfoZzgZ4nCZVZ+6iU5U1+YXFJAoGBANLPpIV920n/nJmmquMj
|
||||
orI1R/QXR9Cy56cMC65agezlGOfTYxk5Cfl5Ve+/2IJCfgzwJyjWUsFx7RviEeGw
|
||||
64o7JoUom1HX+5xxdHPsyZ96OoTJ5RqtKKoApnhRMamau0fWydH1yeOEJd+TRHhc
|
||||
XStGfhz8QNa1dVFvENczja1vAoGABGWhsd4VPVpHMc7lUvrf4kgKQtTC2PjA4xoc
|
||||
QJ96hf/642sVE76jl+N6tkGMzGjnVm4P2j+bOy1VvwQavKGoXqJBRd5Apppv727g
|
||||
/SM7hBXKFc/zH80xKBBgP/i1DR7kdjakCoeu4ngeGywvu2jTS6mQsqzkK+yWbUxJ
|
||||
I7mYBsECgYB/KNXlTEpXtz/kwWCHFSYA8U74l7zZbVD8ul0e56JDK+lLcJ0tJffk
|
||||
gqnBycHj6AhEycjda75cs+0zybZvN4x65KZHOGW/O/7OAWEcZP5TPb3zf9ned3Hl
|
||||
NsZoFj52ponUM6+99A2CmezFCN16c4mbA//luWF+k3VVqR6BpkrhKw==
|
||||
-----END RSA PRIVATE KEY-----`
|
||||
|
||||
const testClientPrivateKey = `-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIBOwIBAAJBALdGZxkXDAjsYk10ihwU6Id2KeILz1TAJuoq4tOgDWxEEGeTrcld
|
||||
r/ZwVaFzjWzxaf6zQIJbfaSEAhqD5yo72+sCAwEAAQJBAK8PEVU23Wj8mV0QjwcJ
|
||||
tZ4GcTUYQL7cF4+ezTCE9a1NrGnCP2RuQkHEKxuTVrxXt+6OF15/1/fuXnxKjmJC
|
||||
nxkCIQDaXvPPBi0c7vAxGwNY9726x01/dNbHCE0CBtcotobxpwIhANbbQbh3JHVW
|
||||
2haQh4fAG5mhesZKAGcxTyv4mQ7uMSQdAiAj+4dzMpJWdSzQ+qGHlHMIBvVHLkqB
|
||||
y2VdEyF7DPCZewIhAI7GOI/6LDIFOvtPo6Bj2nNmyQ1HU6k/LRtNIXi4c9NJAiAr
|
||||
rrxx26itVhJmcvoUhOjwuzSlP2bE5VHAvkGB352YBg==
|
||||
-----END RSA PRIVATE KEY-----`
|
||||
|
||||
// keychain implements the ClientKeyring interface
|
||||
type keychain struct {
|
||||
keys []Signer
|
||||
}
|
||||
|
||||
func (k *keychain) Key(i int) (PublicKey, error) {
|
||||
if i < 0 || i >= len(k.keys) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
return k.keys[i].PublicKey(), nil
|
||||
}
|
||||
|
||||
func (k *keychain) Sign(i int, rand io.Reader, data []byte) (sig []byte, err error) {
|
||||
return k.keys[i].Sign(rand, data)
|
||||
}
|
||||
|
||||
func (k *keychain) add(key Signer) {
|
||||
k.keys = append(k.keys, key)
|
||||
}
|
||||
|
||||
func (k *keychain) loadPEM(file string) error {
|
||||
buf, err := ioutil.ReadFile(file)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
key, err := ParsePrivateKey(buf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
k.add(key)
|
||||
return nil
|
||||
}
|
||||
|
||||
// password implements the ClientPassword interface
|
||||
type password string
|
||||
|
||||
func (p password) Password(user string) (string, error) {
|
||||
return string(p), nil
|
||||
}
|
||||
|
||||
type keyboardInteractive map[string]string
|
||||
|
||||
func (cr *keyboardInteractive) Challenge(user string, instruction string, questions []string, echos []bool) ([]string, error) {
|
||||
var answers []string
|
||||
for _, q := range questions {
|
||||
answers = append(answers, (*cr)[q])
|
||||
}
|
||||
return answers, nil
|
||||
}
|
||||
|
||||
// reused internally by tests
|
||||
var (
|
||||
rsaKey Signer
|
||||
dsaKey Signer
|
||||
clientKeychain = new(keychain)
|
||||
clientPassword = password("tiger")
|
||||
serverConfig = &ServerConfig{
|
||||
PasswordCallback: func(conn *ServerConn, user, pass string) bool {
|
||||
return user == "testuser" && pass == string(clientPassword)
|
||||
},
|
||||
PublicKeyCallback: func(conn *ServerConn, user, algo string, pubkey []byte) bool {
|
||||
key, _ := clientKeychain.Key(0)
|
||||
expected := MarshalPublicKey(key)
|
||||
algoname := key.PublicKeyAlgo()
|
||||
return user == "testuser" && algo == algoname && bytes.Equal(pubkey, expected)
|
||||
},
|
||||
KeyboardInteractiveCallback: func(conn *ServerConn, user string, client ClientKeyboardInteractive) bool {
|
||||
ans, err := client.Challenge("user",
|
||||
"instruction",
|
||||
[]string{"question1", "question2"},
|
||||
[]bool{true, true})
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
ok := user == "testuser" && ans[0] == "answer1" && ans[1] == "answer2"
|
||||
client.Challenge("user", "motd", nil, nil)
|
||||
return ok
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
func init() {
|
||||
var err error
|
||||
rsaKey, err = ParsePrivateKey([]byte(testServerPrivateKey))
|
||||
if err != nil {
|
||||
panic("unable to set private key: " + err.Error())
|
||||
}
|
||||
rawDSAKey := new(dsa.PrivateKey)
|
||||
|
||||
// taken from crypto/dsa/dsa_test.go
|
||||
rawDSAKey.P, _ = new(big.Int).SetString("A9B5B793FB4785793D246BAE77E8FF63CA52F442DA763C440259919FE1BC1D6065A9350637A04F75A2F039401D49F08E066C4D275A5A65DA5684BC563C14289D7AB8A67163BFBF79D85972619AD2CFF55AB0EE77A9002B0EF96293BDD0F42685EBB2C66C327079F6C98000FBCB79AACDE1BC6F9D5C7B1A97E3D9D54ED7951FEF", 16)
|
||||
rawDSAKey.Q, _ = new(big.Int).SetString("E1D3391245933D68A0714ED34BBCB7A1F422B9C1", 16)
|
||||
rawDSAKey.G, _ = new(big.Int).SetString("634364FC25248933D01D1993ECABD0657CC0CB2CEED7ED2E3E8AECDFCDC4A25C3B15E9E3B163ACA2984B5539181F3EFF1A5E8903D71D5B95DA4F27202B77D2C44B430BB53741A8D59A8F86887525C9F2A6A5980A195EAA7F2FF910064301DEF89D3AA213E1FAC7768D89365318E370AF54A112EFBA9246D9158386BA1B4EEFDA", 16)
|
||||
rawDSAKey.Y, _ = new(big.Int).SetString("32969E5780CFE1C849A1C276D7AEB4F38A23B591739AA2FE197349AEEBD31366AEE5EB7E6C6DDB7C57D02432B30DB5AA66D9884299FAA72568944E4EEDC92EA3FBC6F39F53412FBCC563208F7C15B737AC8910DBC2D9C9B8C001E72FDC40EB694AB1F06A5A2DBD18D9E36C66F31F566742F11EC0A52E9F7B89355C02FB5D32D2", 16)
|
||||
rawDSAKey.X, _ = new(big.Int).SetString("5078D4D29795CBE76D3AACFE48C9AF0BCDBEE91A", 16)
|
||||
|
||||
dsaKey, err = NewSignerFromKey(rawDSAKey)
|
||||
if err != nil {
|
||||
panic("NewSignerFromKey: " + err.Error())
|
||||
}
|
||||
clientKeychain.add(rsaKey)
|
||||
serverConfig.AddHostKey(rsaKey)
|
||||
}
|
||||
|
||||
// newMockAuthServer creates a new Server bound to
|
||||
// the loopback interface. The server exits after
|
||||
// processing one handshake.
|
||||
func newMockAuthServer(t *testing.T) string {
|
||||
l, err := Listen("tcp", "127.0.0.1:0", serverConfig)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to newMockAuthServer: %s", err)
|
||||
}
|
||||
go func() {
|
||||
defer l.Close()
|
||||
c, err := l.Accept()
|
||||
if err != nil {
|
||||
t.Errorf("Unable to accept incoming connection: %v", err)
|
||||
return
|
||||
}
|
||||
if err := c.Handshake(); err != nil {
|
||||
// not Errorf because this is expected to
|
||||
// fail for some tests.
|
||||
t.Logf("Handshaking error: %v", err)
|
||||
return
|
||||
}
|
||||
defer c.Close()
|
||||
}()
|
||||
return l.Addr().String()
|
||||
}
|
||||
|
||||
func TestClientAuthPublicKey(t *testing.T) {
|
||||
config := &ClientConfig{
|
||||
User: "testuser",
|
||||
Auth: []ClientAuth{
|
||||
ClientAuthKeyring(clientKeychain),
|
||||
},
|
||||
}
|
||||
c, err := Dial("tcp", newMockAuthServer(t), config)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to dial remote side: %s", err)
|
||||
}
|
||||
c.Close()
|
||||
}
|
||||
|
||||
func TestClientAuthPassword(t *testing.T) {
|
||||
config := &ClientConfig{
|
||||
User: "testuser",
|
||||
Auth: []ClientAuth{
|
||||
ClientAuthPassword(clientPassword),
|
||||
},
|
||||
}
|
||||
|
||||
c, err := Dial("tcp", newMockAuthServer(t), config)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to dial remote side: %s", err)
|
||||
}
|
||||
c.Close()
|
||||
}
|
||||
|
||||
func TestClientAuthWrongPassword(t *testing.T) {
|
||||
wrongPw := password("wrong")
|
||||
config := &ClientConfig{
|
||||
User: "testuser",
|
||||
Auth: []ClientAuth{
|
||||
ClientAuthPassword(wrongPw),
|
||||
ClientAuthKeyring(clientKeychain),
|
||||
},
|
||||
}
|
||||
|
||||
c, err := Dial("tcp", newMockAuthServer(t), config)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to dial remote side: %s", err)
|
||||
}
|
||||
c.Close()
|
||||
}
|
||||
|
||||
func TestClientAuthKeyboardInteractive(t *testing.T) {
|
||||
answers := keyboardInteractive(map[string]string{
|
||||
"question1": "answer1",
|
||||
"question2": "answer2",
|
||||
})
|
||||
config := &ClientConfig{
|
||||
User: "testuser",
|
||||
Auth: []ClientAuth{
|
||||
ClientAuthKeyboardInteractive(&answers),
|
||||
},
|
||||
}
|
||||
|
||||
c, err := Dial("tcp", newMockAuthServer(t), config)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to dial remote side: %s", err)
|
||||
}
|
||||
c.Close()
|
||||
}
|
||||
|
||||
func TestClientAuthWrongKeyboardInteractive(t *testing.T) {
|
||||
answers := keyboardInteractive(map[string]string{
|
||||
"question1": "answer1",
|
||||
"question2": "WRONG",
|
||||
})
|
||||
config := &ClientConfig{
|
||||
User: "testuser",
|
||||
Auth: []ClientAuth{
|
||||
ClientAuthKeyboardInteractive(&answers),
|
||||
},
|
||||
}
|
||||
|
||||
c, err := Dial("tcp", newMockAuthServer(t), config)
|
||||
if err == nil {
|
||||
c.Close()
|
||||
t.Fatalf("wrong answers should not have authenticated with KeyboardInteractive")
|
||||
}
|
||||
}
|
||||
|
||||
// the mock server will only authenticate ssh-rsa keys
|
||||
func TestClientAuthInvalidPublicKey(t *testing.T) {
|
||||
kc := new(keychain)
|
||||
|
||||
kc.add(dsaKey)
|
||||
config := &ClientConfig{
|
||||
User: "testuser",
|
||||
Auth: []ClientAuth{
|
||||
ClientAuthKeyring(kc),
|
||||
},
|
||||
}
|
||||
|
||||
c, err := Dial("tcp", newMockAuthServer(t), config)
|
||||
if err == nil {
|
||||
c.Close()
|
||||
t.Fatalf("dsa private key should not have authenticated with rsa public key")
|
||||
}
|
||||
}
|
||||
|
||||
// the client should authenticate with the second key
|
||||
func TestClientAuthRSAandDSA(t *testing.T) {
|
||||
kc := new(keychain)
|
||||
kc.add(dsaKey)
|
||||
kc.add(rsaKey)
|
||||
config := &ClientConfig{
|
||||
User: "testuser",
|
||||
Auth: []ClientAuth{
|
||||
ClientAuthKeyring(kc),
|
||||
},
|
||||
}
|
||||
c, err := Dial("tcp", newMockAuthServer(t), config)
|
||||
if err != nil {
|
||||
t.Fatalf("client could not authenticate with rsa key: %v", err)
|
||||
}
|
||||
c.Close()
|
||||
}
|
||||
|
||||
func TestClientHMAC(t *testing.T) {
|
||||
kc := new(keychain)
|
||||
kc.add(rsaKey)
|
||||
for _, mac := range DefaultMACOrder {
|
||||
config := &ClientConfig{
|
||||
User: "testuser",
|
||||
Auth: []ClientAuth{
|
||||
ClientAuthKeyring(kc),
|
||||
},
|
||||
Crypto: CryptoConfig{
|
||||
MACs: []string{mac},
|
||||
},
|
||||
}
|
||||
c, err := Dial("tcp", newMockAuthServer(t), config)
|
||||
if err != nil {
|
||||
t.Fatalf("client could not authenticate with mac algo %s: %v", mac, err)
|
||||
}
|
||||
c.Close()
|
||||
}
|
||||
}
|
||||
|
||||
// issue 4285.
|
||||
func TestClientUnsupportedCipher(t *testing.T) {
|
||||
kc := new(keychain)
|
||||
config := &ClientConfig{
|
||||
User: "testuser",
|
||||
Auth: []ClientAuth{
|
||||
ClientAuthKeyring(kc),
|
||||
},
|
||||
Crypto: CryptoConfig{
|
||||
Ciphers: []string{"aes128-cbc"}, // not currently supported
|
||||
},
|
||||
}
|
||||
c, err := Dial("tcp", newMockAuthServer(t), config)
|
||||
if err == nil {
|
||||
t.Errorf("expected no ciphers in common")
|
||||
c.Close()
|
||||
}
|
||||
}
|
||||
|
||||
func TestClientUnsupportedKex(t *testing.T) {
|
||||
kc := new(keychain)
|
||||
config := &ClientConfig{
|
||||
User: "testuser",
|
||||
Auth: []ClientAuth{
|
||||
ClientAuthKeyring(kc),
|
||||
},
|
||||
Crypto: CryptoConfig{
|
||||
KeyExchanges: []string{"diffie-hellman-group-exchange-sha256"}, // not currently supported
|
||||
},
|
||||
}
|
||||
c, err := Dial("tcp", newMockAuthServer(t), config)
|
||||
if err == nil || !strings.Contains(err.Error(), "no common algorithms") {
|
||||
t.Errorf("got %v, expected 'no common algorithms'", err)
|
||||
}
|
||||
if c != nil {
|
||||
c.Close()
|
||||
}
|
||||
}
|
34
vendor/code.google.com/p/go.crypto/ssh/client_test.go
generated
vendored
34
vendor/code.google.com/p/go.crypto/ssh/client_test.go
generated
vendored
|
@ -1,34 +0,0 @@
|
|||
package ssh
|
||||
|
||||
import (
|
||||
"net"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func testClientVersion(t *testing.T, config *ClientConfig, expected string) {
|
||||
clientConn, serverConn := net.Pipe()
|
||||
receivedVersion := make(chan string, 1)
|
||||
go func() {
|
||||
version, err := readVersion(serverConn)
|
||||
if err != nil {
|
||||
receivedVersion <- ""
|
||||
} else {
|
||||
receivedVersion <- string(version)
|
||||
}
|
||||
serverConn.Close()
|
||||
}()
|
||||
Client(clientConn, config)
|
||||
actual := <-receivedVersion
|
||||
if actual != expected {
|
||||
t.Fatalf("got %s; want %s", actual, expected)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCustomClientVersion(t *testing.T) {
|
||||
version := "Test-Client-Version-0.0"
|
||||
testClientVersion(t, &ClientConfig{ClientVersion: version}, version)
|
||||
}
|
||||
|
||||
func TestDefaultClientVersion(t *testing.T) {
|
||||
testClientVersion(t, &ClientConfig{}, packageVersion)
|
||||
}
|
57
vendor/code.google.com/p/go.crypto/ssh/common_test.go
generated
vendored
57
vendor/code.google.com/p/go.crypto/ssh/common_test.go
generated
vendored
|
@ -1,57 +0,0 @@
|
|||
// Copyright 2011 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package ssh
|
||||
|
||||
import (
|
||||
"io"
|
||||
"net"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestSafeString(t *testing.T) {
|
||||
strings := map[string]string{
|
||||
"\x20\x0d\x0a": "\x20\x0d\x0a",
|
||||
"flibble": "flibble",
|
||||
"new\x20line": "new\x20line",
|
||||
"123456\x07789": "123456 789",
|
||||
"\t\t\x10\r\n": "\t\t \r\n",
|
||||
}
|
||||
|
||||
for s, expected := range strings {
|
||||
actual := safeString(s)
|
||||
if expected != actual {
|
||||
t.Errorf("expected: %v, actual: %v", []byte(expected), []byte(actual))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure Read/Write are not exposed.
|
||||
func TestConnHideRWMethods(t *testing.T) {
|
||||
for _, c := range []interface{}{new(ServerConn), new(ClientConn)} {
|
||||
if _, ok := c.(io.Reader); ok {
|
||||
t.Errorf("%T implements io.Reader", c)
|
||||
}
|
||||
if _, ok := c.(io.Writer); ok {
|
||||
t.Errorf("%T implements io.Writer", c)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestConnSupportsLocalRemoteMethods(t *testing.T) {
|
||||
type LocalAddr interface {
|
||||
LocalAddr() net.Addr
|
||||
}
|
||||
type RemoteAddr interface {
|
||||
RemoteAddr() net.Addr
|
||||
}
|
||||
for _, c := range []interface{}{new(ServerConn), new(ClientConn)} {
|
||||
if _, ok := c.(LocalAddr); !ok {
|
||||
t.Errorf("%T does not implement LocalAddr", c)
|
||||
}
|
||||
if _, ok := c.(RemoteAddr); !ok {
|
||||
t.Errorf("%T does not implement RemoteAddr", c)
|
||||
}
|
||||
}
|
||||
}
|
191
vendor/code.google.com/p/go.crypto/ssh/example_test.go
generated
vendored
191
vendor/code.google.com/p/go.crypto/ssh/example_test.go
generated
vendored
|
@ -1,191 +0,0 @@
|
|||
// Copyright 2011 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package ssh
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net/http"
|
||||
|
||||
"code.google.com/p/go.crypto/ssh/terminal"
|
||||
)
|
||||
|
||||
func ExampleListen() {
|
||||
// An SSH server is represented by a ServerConfig, which holds
|
||||
// certificate details and handles authentication of ServerConns.
|
||||
config := &ServerConfig{
|
||||
PasswordCallback: func(conn *ServerConn, user, pass string) bool {
|
||||
return user == "testuser" && pass == "tiger"
|
||||
},
|
||||
}
|
||||
|
||||
privateBytes, err := ioutil.ReadFile("id_rsa")
|
||||
if err != nil {
|
||||
panic("Failed to load private key")
|
||||
}
|
||||
|
||||
private, err := ParsePrivateKey(privateBytes)
|
||||
if err != nil {
|
||||
panic("Failed to parse private key")
|
||||
}
|
||||
|
||||
config.AddHostKey(private)
|
||||
|
||||
// Once a ServerConfig has been configured, connections can be
|
||||
// accepted.
|
||||
listener, err := Listen("tcp", "0.0.0.0:2022", config)
|
||||
if err != nil {
|
||||
panic("failed to listen for connection")
|
||||
}
|
||||
sConn, err := listener.Accept()
|
||||
if err != nil {
|
||||
panic("failed to accept incoming connection")
|
||||
}
|
||||
if err := sConn.Handshake(); err != nil {
|
||||
panic("failed to handshake")
|
||||
}
|
||||
|
||||
// A ServerConn multiplexes several channels, which must
|
||||
// themselves be Accepted.
|
||||
for {
|
||||
// Accept reads from the connection, demultiplexes packets
|
||||
// to their corresponding channels and returns when a new
|
||||
// channel request is seen. Some goroutine must always be
|
||||
// calling Accept; otherwise no messages will be forwarded
|
||||
// to the channels.
|
||||
channel, err := sConn.Accept()
|
||||
if err != nil {
|
||||
panic("error from Accept")
|
||||
}
|
||||
|
||||
// Channels have a type, depending on the application level
|
||||
// protocol intended. In the case of a shell, the type is
|
||||
// "session" and ServerShell may be used to present a simple
|
||||
// terminal interface.
|
||||
if channel.ChannelType() != "session" {
|
||||
channel.Reject(UnknownChannelType, "unknown channel type")
|
||||
continue
|
||||
}
|
||||
channel.Accept()
|
||||
|
||||
term := terminal.NewTerminal(channel, "> ")
|
||||
serverTerm := &ServerTerminal{
|
||||
Term: term,
|
||||
Channel: channel,
|
||||
}
|
||||
go func() {
|
||||
defer channel.Close()
|
||||
for {
|
||||
line, err := serverTerm.ReadLine()
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
fmt.Println(line)
|
||||
}
|
||||
}()
|
||||
}
|
||||
}
|
||||
|
||||
func ExampleDial() {
|
||||
// An SSH client is represented with a ClientConn. Currently only
|
||||
// the "password" authentication method is supported.
|
||||
//
|
||||
// To authenticate with the remote server you must pass at least one
|
||||
// implementation of ClientAuth via the Auth field in ClientConfig.
|
||||
config := &ClientConfig{
|
||||
User: "username",
|
||||
Auth: []ClientAuth{
|
||||
// ClientAuthPassword wraps a ClientPassword implementation
|
||||
// in a type that implements ClientAuth.
|
||||
ClientAuthPassword(password("yourpassword")),
|
||||
},
|
||||
}
|
||||
client, err := Dial("tcp", "yourserver.com:22", config)
|
||||
if err != nil {
|
||||
panic("Failed to dial: " + err.Error())
|
||||
}
|
||||
|
||||
// Each ClientConn can support multiple interactive sessions,
|
||||
// represented by a Session.
|
||||
session, err := client.NewSession()
|
||||
if err != nil {
|
||||
panic("Failed to create session: " + err.Error())
|
||||
}
|
||||
defer session.Close()
|
||||
|
||||
// Once a Session is created, you can execute a single command on
|
||||
// the remote side using the Run method.
|
||||
var b bytes.Buffer
|
||||
session.Stdout = &b
|
||||
if err := session.Run("/usr/bin/whoami"); err != nil {
|
||||
panic("Failed to run: " + err.Error())
|
||||
}
|
||||
fmt.Println(b.String())
|
||||
}
|
||||
|
||||
func ExampleClientConn_Listen() {
|
||||
config := &ClientConfig{
|
||||
User: "username",
|
||||
Auth: []ClientAuth{
|
||||
ClientAuthPassword(password("password")),
|
||||
},
|
||||
}
|
||||
// Dial your ssh server.
|
||||
conn, err := Dial("tcp", "localhost:22", config)
|
||||
if err != nil {
|
||||
log.Fatalf("unable to connect: %s", err)
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
// Request the remote side to open port 8080 on all interfaces.
|
||||
l, err := conn.Listen("tcp", "0.0.0.0:8080")
|
||||
if err != nil {
|
||||
log.Fatalf("unable to register tcp forward: %v", err)
|
||||
}
|
||||
defer l.Close()
|
||||
|
||||
// Serve HTTP with your SSH server acting as a reverse proxy.
|
||||
http.Serve(l, http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) {
|
||||
fmt.Fprintf(resp, "Hello world!\n")
|
||||
}))
|
||||
}
|
||||
|
||||
func ExampleSession_RequestPty() {
|
||||
// Create client config
|
||||
config := &ClientConfig{
|
||||
User: "username",
|
||||
Auth: []ClientAuth{
|
||||
ClientAuthPassword(password("password")),
|
||||
},
|
||||
}
|
||||
// Connect to ssh server
|
||||
conn, err := Dial("tcp", "localhost:22", config)
|
||||
if err != nil {
|
||||
log.Fatalf("unable to connect: %s", err)
|
||||
}
|
||||
defer conn.Close()
|
||||
// Create a session
|
||||
session, err := conn.NewSession()
|
||||
if err != nil {
|
||||
log.Fatalf("unable to create session: %s", err)
|
||||
}
|
||||
defer session.Close()
|
||||
// Set up terminal modes
|
||||
modes := TerminalModes{
|
||||
ECHO: 0, // disable echoing
|
||||
TTY_OP_ISPEED: 14400, // input speed = 14.4kbaud
|
||||
TTY_OP_OSPEED: 14400, // output speed = 14.4kbaud
|
||||
}
|
||||
// Request pseudo terminal
|
||||
if err := session.RequestPty("xterm", 80, 40, modes); err != nil {
|
||||
log.Fatalf("request for pseudo terminal failed: %s", err)
|
||||
}
|
||||
// Start remote shell
|
||||
if err := session.Shell(); err != nil {
|
||||
log.Fatalf("failed to start shell: %s", err)
|
||||
}
|
||||
}
|
48
vendor/code.google.com/p/go.crypto/ssh/kex_test.go
generated
vendored
48
vendor/code.google.com/p/go.crypto/ssh/kex_test.go
generated
vendored
|
@ -1,48 +0,0 @@
|
|||
// Copyright 2013 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package ssh
|
||||
|
||||
// Key exchange tests.
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestKexes(t *testing.T) {
|
||||
type kexResultErr struct {
|
||||
result *kexResult
|
||||
err error
|
||||
}
|
||||
|
||||
for name, kex := range kexAlgoMap {
|
||||
a, b := memPipe()
|
||||
|
||||
s := make(chan kexResultErr, 1)
|
||||
c := make(chan kexResultErr, 1)
|
||||
var magics handshakeMagics
|
||||
go func() {
|
||||
r, e := kex.Client(a, rand.Reader, &magics)
|
||||
c <- kexResultErr{r, e}
|
||||
}()
|
||||
go func() {
|
||||
r, e := kex.Server(b, rand.Reader, &magics, ecdsaKey)
|
||||
s <- kexResultErr{r, e}
|
||||
}()
|
||||
|
||||
clientRes := <-c
|
||||
serverRes := <-s
|
||||
if clientRes.err != nil {
|
||||
t.Errorf("client: %v", clientRes.err)
|
||||
}
|
||||
if serverRes.err != nil {
|
||||
t.Errorf("server: %v", serverRes.err)
|
||||
}
|
||||
if !reflect.DeepEqual(clientRes.result, serverRes.result) {
|
||||
t.Errorf("kex %q: mismatch %#v, %#v", name, clientRes.result, serverRes.result)
|
||||
}
|
||||
}
|
||||
}
|
214
vendor/code.google.com/p/go.crypto/ssh/keys_test.go
generated
vendored
214
vendor/code.google.com/p/go.crypto/ssh/keys_test.go
generated
vendored
|
@ -1,214 +0,0 @@
|
|||
package ssh
|
||||
|
||||
import (
|
||||
"crypto/dsa"
|
||||
"crypto/ecdsa"
|
||||
"crypto/elliptic"
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var (
|
||||
ecdsaKey Signer
|
||||
ecdsa384Key Signer
|
||||
ecdsa521Key Signer
|
||||
testCertKey Signer
|
||||
)
|
||||
|
||||
type testSigner struct {
|
||||
Signer
|
||||
pub PublicKey
|
||||
}
|
||||
|
||||
func (ts *testSigner) PublicKey() PublicKey {
|
||||
if ts.pub != nil {
|
||||
return ts.pub
|
||||
}
|
||||
return ts.Signer.PublicKey()
|
||||
}
|
||||
|
||||
func init() {
|
||||
raw256, _ := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
|
||||
ecdsaKey, _ = NewSignerFromKey(raw256)
|
||||
|
||||
raw384, _ := ecdsa.GenerateKey(elliptic.P384(), rand.Reader)
|
||||
ecdsa384Key, _ = NewSignerFromKey(raw384)
|
||||
|
||||
raw521, _ := ecdsa.GenerateKey(elliptic.P521(), rand.Reader)
|
||||
ecdsa521Key, _ = NewSignerFromKey(raw521)
|
||||
|
||||
// Create a cert and sign it for use in tests.
|
||||
testCert := &OpenSSHCertV01{
|
||||
Nonce: []byte{}, // To pass reflect.DeepEqual after marshal & parse, this must be non-nil
|
||||
Key: ecdsaKey.PublicKey(),
|
||||
ValidPrincipals: []string{"gopher1", "gopher2"}, // increases test coverage
|
||||
ValidAfter: 0, // unix epoch
|
||||
ValidBefore: maxUint64, // The end of currently representable time.
|
||||
Reserved: []byte{}, // To pass reflect.DeepEqual after marshal & parse, this must be non-nil
|
||||
SignatureKey: rsaKey.PublicKey(),
|
||||
}
|
||||
sigBytes, _ := rsaKey.Sign(rand.Reader, testCert.BytesForSigning())
|
||||
testCert.Signature = &signature{
|
||||
Format: testCert.SignatureKey.PublicKeyAlgo(),
|
||||
Blob: sigBytes,
|
||||
}
|
||||
testCertKey = &testSigner{
|
||||
Signer: ecdsaKey,
|
||||
pub: testCert,
|
||||
}
|
||||
}
|
||||
|
||||
func rawKey(pub PublicKey) interface{} {
|
||||
switch k := pub.(type) {
|
||||
case *rsaPublicKey:
|
||||
return (*rsa.PublicKey)(k)
|
||||
case *dsaPublicKey:
|
||||
return (*dsa.PublicKey)(k)
|
||||
case *ecdsaPublicKey:
|
||||
return (*ecdsa.PublicKey)(k)
|
||||
case *OpenSSHCertV01:
|
||||
return k
|
||||
}
|
||||
panic("unknown key type")
|
||||
}
|
||||
|
||||
func TestKeyMarshalParse(t *testing.T) {
|
||||
keys := []Signer{rsaKey, dsaKey, ecdsaKey, ecdsa384Key, ecdsa521Key, testCertKey}
|
||||
for _, priv := range keys {
|
||||
pub := priv.PublicKey()
|
||||
roundtrip, rest, ok := ParsePublicKey(MarshalPublicKey(pub))
|
||||
if !ok {
|
||||
t.Errorf("ParsePublicKey(%T) failed", pub)
|
||||
}
|
||||
|
||||
if len(rest) > 0 {
|
||||
t.Errorf("ParsePublicKey(%T): trailing junk", pub)
|
||||
}
|
||||
|
||||
k1 := rawKey(pub)
|
||||
k2 := rawKey(roundtrip)
|
||||
|
||||
if !reflect.DeepEqual(k1, k2) {
|
||||
t.Errorf("got %#v in roundtrip, want %#v", k2, k1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnsupportedCurves(t *testing.T) {
|
||||
raw, err := ecdsa.GenerateKey(elliptic.P224(), rand.Reader)
|
||||
if err != nil {
|
||||
t.Fatalf("GenerateKey: %v", err)
|
||||
}
|
||||
|
||||
if _, err = NewSignerFromKey(raw); err == nil || !strings.Contains(err.Error(), "only P256") {
|
||||
t.Fatalf("NewPrivateKey should not succeed with P224, got: %v", err)
|
||||
}
|
||||
|
||||
if _, err = NewPublicKey(&raw.PublicKey); err == nil || !strings.Contains(err.Error(), "only P256") {
|
||||
t.Fatalf("NewPublicKey should not succeed with P224, got: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewPublicKey(t *testing.T) {
|
||||
keys := []Signer{rsaKey, dsaKey, ecdsaKey}
|
||||
for _, k := range keys {
|
||||
raw := rawKey(k.PublicKey())
|
||||
pub, err := NewPublicKey(raw)
|
||||
if err != nil {
|
||||
t.Errorf("NewPublicKey(%#v): %v", raw, err)
|
||||
}
|
||||
if !reflect.DeepEqual(k.PublicKey(), pub) {
|
||||
t.Errorf("NewPublicKey(%#v) = %#v, want %#v", raw, pub, k.PublicKey())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestKeySignVerify(t *testing.T) {
|
||||
keys := []Signer{rsaKey, dsaKey, ecdsaKey, testCertKey}
|
||||
for _, priv := range keys {
|
||||
pub := priv.PublicKey()
|
||||
|
||||
data := []byte("sign me")
|
||||
sig, err := priv.Sign(rand.Reader, data)
|
||||
if err != nil {
|
||||
t.Fatalf("Sign(%T): %v", priv, err)
|
||||
}
|
||||
|
||||
if !pub.Verify(data, sig) {
|
||||
t.Errorf("publicKey.Verify(%T) failed", priv)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseRSAPrivateKey(t *testing.T) {
|
||||
key, err := ParsePrivateKey([]byte(testServerPrivateKey))
|
||||
if err != nil {
|
||||
t.Fatalf("ParsePrivateKey: %v", err)
|
||||
}
|
||||
|
||||
rsa, ok := key.(*rsaPrivateKey)
|
||||
if !ok {
|
||||
t.Fatalf("got %T, want *rsa.PrivateKey", rsa)
|
||||
}
|
||||
|
||||
if err := rsa.Validate(); err != nil {
|
||||
t.Errorf("Validate: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseECPrivateKey(t *testing.T) {
|
||||
// Taken from the data in test/ .
|
||||
pem := []byte(`-----BEGIN EC PRIVATE KEY-----
|
||||
MHcCAQEEINGWx0zo6fhJ/0EAfrPzVFyFC9s18lBt3cRoEDhS3ARooAoGCCqGSM49
|
||||
AwEHoUQDQgAEi9Hdw6KvZcWxfg2IDhA7UkpDtzzt6ZqJXSsFdLd+Kx4S3Sx4cVO+
|
||||
6/ZOXRnPmNAlLUqjShUsUBBngG0u2fqEqA==
|
||||
-----END EC PRIVATE KEY-----`)
|
||||
|
||||
key, err := ParsePrivateKey(pem)
|
||||
if err != nil {
|
||||
t.Fatalf("ParsePrivateKey: %v", err)
|
||||
}
|
||||
|
||||
ecKey, ok := key.(*ecdsaPrivateKey)
|
||||
if !ok {
|
||||
t.Fatalf("got %T, want *ecdsaPrivateKey", ecKey)
|
||||
}
|
||||
|
||||
if !validateECPublicKey(ecKey.Curve, ecKey.X, ecKey.Y) {
|
||||
t.Fatalf("public key does not validate.")
|
||||
}
|
||||
}
|
||||
|
||||
// ssh-keygen -t dsa -f /tmp/idsa.pem
|
||||
var dsaPEM = `-----BEGIN DSA PRIVATE KEY-----
|
||||
MIIBuwIBAAKBgQD6PDSEyXiI9jfNs97WuM46MSDCYlOqWw80ajN16AohtBncs1YB
|
||||
lHk//dQOvCYOsYaE+gNix2jtoRjwXhDsc25/IqQbU1ahb7mB8/rsaILRGIbA5WH3
|
||||
EgFtJmXFovDz3if6F6TzvhFpHgJRmLYVR8cqsezL3hEZOvvs2iH7MorkxwIVAJHD
|
||||
nD82+lxh2fb4PMsIiaXudAsBAoGAQRf7Q/iaPRn43ZquUhd6WwvirqUj+tkIu6eV
|
||||
2nZWYmXLlqFQKEy4Tejl7Wkyzr2OSYvbXLzo7TNxLKoWor6ips0phYPPMyXld14r
|
||||
juhT24CrhOzuLMhDduMDi032wDIZG4Y+K7ElU8Oufn8Sj5Wge8r6ANmmVgmFfynr
|
||||
FhdYCngCgYEA3ucGJ93/Mx4q4eKRDxcWD3QzWyqpbRVRRV1Vmih9Ha/qC994nJFz
|
||||
DQIdjxDIT2Rk2AGzMqFEB68Zc3O+Wcsmz5eWWzEwFxaTwOGWTyDqsDRLm3fD+QYj
|
||||
nOwuxb0Kce+gWI8voWcqC9cyRm09jGzu2Ab3Bhtpg8JJ8L7gS3MRZK4CFEx4UAfY
|
||||
Fmsr0W6fHB9nhS4/UXM8
|
||||
-----END DSA PRIVATE KEY-----`
|
||||
|
||||
func TestParseDSA(t *testing.T) {
|
||||
s, err := ParsePrivateKey([]byte(dsaPEM))
|
||||
if err != nil {
|
||||
t.Fatalf("ParsePrivateKey returned error: %s", err)
|
||||
}
|
||||
|
||||
data := []byte("sign me")
|
||||
sig, err := s.Sign(rand.Reader, data)
|
||||
if err != nil {
|
||||
t.Fatalf("dsa.Sign: %v", err)
|
||||
}
|
||||
|
||||
if !s.PublicKey().Verify(data, sig) {
|
||||
t.Error("Verify failed.")
|
||||
}
|
||||
}
|
102
vendor/code.google.com/p/go.crypto/ssh/mempipe_test.go
generated
vendored
102
vendor/code.google.com/p/go.crypto/ssh/mempipe_test.go
generated
vendored
|
@ -1,102 +0,0 @@
|
|||
// Copyright 2013 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package ssh
|
||||
|
||||
import (
|
||||
"io"
|
||||
"sync"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// An in-memory packetConn. It is safe to call Close and writePacket
|
||||
// from different goroutines.
|
||||
type memTransport struct {
|
||||
eof bool
|
||||
pending [][]byte
|
||||
write *memTransport
|
||||
sync.Mutex
|
||||
*sync.Cond
|
||||
}
|
||||
|
||||
func (t *memTransport) readPacket() ([]byte, error) {
|
||||
t.Lock()
|
||||
defer t.Unlock()
|
||||
for {
|
||||
if len(t.pending) > 0 {
|
||||
r := t.pending[0]
|
||||
t.pending = t.pending[1:]
|
||||
return r, nil
|
||||
}
|
||||
if t.eof {
|
||||
return nil, io.EOF
|
||||
}
|
||||
t.Cond.Wait()
|
||||
}
|
||||
}
|
||||
|
||||
func (t *memTransport) Close() error {
|
||||
t.write.Lock()
|
||||
defer t.write.Unlock()
|
||||
if t.write.eof {
|
||||
return io.EOF
|
||||
}
|
||||
t.write.eof = true
|
||||
t.write.Cond.Broadcast()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *memTransport) writePacket(p []byte) error {
|
||||
t.write.Lock()
|
||||
defer t.write.Unlock()
|
||||
if t.write.eof {
|
||||
return io.EOF
|
||||
}
|
||||
t.write.pending = append(t.write.pending, p)
|
||||
t.write.Cond.Signal()
|
||||
return nil
|
||||
}
|
||||
|
||||
func memPipe() (a, b packetConn) {
|
||||
t1 := memTransport{}
|
||||
t2 := memTransport{}
|
||||
t1.write = &t2
|
||||
t2.write = &t1
|
||||
t1.Cond = sync.NewCond(&t1.Mutex)
|
||||
t2.Cond = sync.NewCond(&t2.Mutex)
|
||||
return &t1, &t2
|
||||
}
|
||||
|
||||
func TestmemPipe(t *testing.T) {
|
||||
a, b := memPipe()
|
||||
if err := a.writePacket([]byte{42}); err != nil {
|
||||
t.Fatalf("writePacket: %v", err)
|
||||
}
|
||||
if err := a.Close(); err != nil {
|
||||
t.Fatal("Close: ", err)
|
||||
}
|
||||
p, err := b.readPacket()
|
||||
if err != nil {
|
||||
t.Fatal("readPacket: ", err)
|
||||
}
|
||||
if len(p) != 1 || p[0] != 42 {
|
||||
t.Fatalf("got %v, want {42}", p)
|
||||
}
|
||||
p, err = b.readPacket()
|
||||
if err != io.EOF {
|
||||
t.Fatalf("got %v, %v, want EOF", p, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDoubleClose(t *testing.T) {
|
||||
a, _ := memPipe()
|
||||
err := a.Close()
|
||||
if err != nil {
|
||||
t.Errorf("Close: %v", err)
|
||||
}
|
||||
err = a.Close()
|
||||
if err != io.EOF {
|
||||
t.Errorf("expect EOF on double close.")
|
||||
}
|
||||
}
|
232
vendor/code.google.com/p/go.crypto/ssh/messages_test.go
generated
vendored
232
vendor/code.google.com/p/go.crypto/ssh/messages_test.go
generated
vendored
|
@ -1,232 +0,0 @@
|
|||
// Copyright 2011 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package ssh
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
"math/rand"
|
||||
"reflect"
|
||||
"testing"
|
||||
"testing/quick"
|
||||
)
|
||||
|
||||
var intLengthTests = []struct {
|
||||
val, length int
|
||||
}{
|
||||
{0, 4 + 0},
|
||||
{1, 4 + 1},
|
||||
{127, 4 + 1},
|
||||
{128, 4 + 2},
|
||||
{-1, 4 + 1},
|
||||
}
|
||||
|
||||
func TestIntLength(t *testing.T) {
|
||||
for _, test := range intLengthTests {
|
||||
v := new(big.Int).SetInt64(int64(test.val))
|
||||
length := intLength(v)
|
||||
if length != test.length {
|
||||
t.Errorf("For %d, got length %d but expected %d", test.val, length, test.length)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var messageTypes = []interface{}{
|
||||
&kexInitMsg{},
|
||||
&kexDHInitMsg{},
|
||||
&serviceRequestMsg{},
|
||||
&serviceAcceptMsg{},
|
||||
&userAuthRequestMsg{},
|
||||
&channelOpenMsg{},
|
||||
&channelOpenConfirmMsg{},
|
||||
&channelOpenFailureMsg{},
|
||||
&channelRequestMsg{},
|
||||
&channelRequestSuccessMsg{},
|
||||
}
|
||||
|
||||
func TestMarshalUnmarshal(t *testing.T) {
|
||||
rand := rand.New(rand.NewSource(0))
|
||||
for i, iface := range messageTypes {
|
||||
ty := reflect.ValueOf(iface).Type()
|
||||
|
||||
n := 100
|
||||
if testing.Short() {
|
||||
n = 5
|
||||
}
|
||||
for j := 0; j < n; j++ {
|
||||
v, ok := quick.Value(ty, rand)
|
||||
if !ok {
|
||||
t.Errorf("#%d: failed to create value", i)
|
||||
break
|
||||
}
|
||||
|
||||
m1 := v.Elem().Interface()
|
||||
m2 := iface
|
||||
|
||||
marshaled := marshal(msgIgnore, m1)
|
||||
if err := unmarshal(m2, marshaled, msgIgnore); err != nil {
|
||||
t.Errorf("#%d failed to unmarshal %#v: %s", i, m1, err)
|
||||
break
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(v.Interface(), m2) {
|
||||
t.Errorf("#%d\ngot: %#v\nwant:%#v\n%x", i, m2, m1, marshaled)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnmarshalEmptyPacket(t *testing.T) {
|
||||
var b []byte
|
||||
var m channelRequestSuccessMsg
|
||||
err := unmarshal(&m, b, msgChannelRequest)
|
||||
want := ParseError{msgChannelRequest}
|
||||
if _, ok := err.(ParseError); !ok {
|
||||
t.Fatalf("got %T, want %T", err, want)
|
||||
}
|
||||
if got := err.(ParseError); want != got {
|
||||
t.Fatal("got %#v, want %#v", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnmarshalUnexpectedPacket(t *testing.T) {
|
||||
type S struct {
|
||||
I uint32
|
||||
S string
|
||||
B bool
|
||||
}
|
||||
|
||||
s := S{42, "hello", true}
|
||||
packet := marshal(42, s)
|
||||
roundtrip := S{}
|
||||
err := unmarshal(&roundtrip, packet, 43)
|
||||
if err == nil {
|
||||
t.Fatal("expected error, not nil")
|
||||
}
|
||||
want := UnexpectedMessageError{43, 42}
|
||||
if got, ok := err.(UnexpectedMessageError); !ok || want != got {
|
||||
t.Fatal("expected %q, got %q", want, got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBareMarshalUnmarshal(t *testing.T) {
|
||||
type S struct {
|
||||
I uint32
|
||||
S string
|
||||
B bool
|
||||
}
|
||||
|
||||
s := S{42, "hello", true}
|
||||
packet := marshal(0, s)
|
||||
roundtrip := S{}
|
||||
unmarshal(&roundtrip, packet, 0)
|
||||
|
||||
if !reflect.DeepEqual(s, roundtrip) {
|
||||
t.Errorf("got %#v, want %#v", roundtrip, s)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBareMarshal(t *testing.T) {
|
||||
type S2 struct {
|
||||
I uint32
|
||||
}
|
||||
s := S2{42}
|
||||
packet := marshal(0, s)
|
||||
i, rest, ok := parseUint32(packet)
|
||||
if len(rest) > 0 || !ok {
|
||||
t.Errorf("parseInt(%q): parse error", packet)
|
||||
}
|
||||
if i != s.I {
|
||||
t.Errorf("got %d, want %d", i, s.I)
|
||||
}
|
||||
}
|
||||
|
||||
func randomBytes(out []byte, rand *rand.Rand) {
|
||||
for i := 0; i < len(out); i++ {
|
||||
out[i] = byte(rand.Int31())
|
||||
}
|
||||
}
|
||||
|
||||
func randomNameList(rand *rand.Rand) []string {
|
||||
ret := make([]string, rand.Int31()&15)
|
||||
for i := range ret {
|
||||
s := make([]byte, 1+(rand.Int31()&15))
|
||||
for j := range s {
|
||||
s[j] = 'a' + uint8(rand.Int31()&15)
|
||||
}
|
||||
ret[i] = string(s)
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func randomInt(rand *rand.Rand) *big.Int {
|
||||
return new(big.Int).SetInt64(int64(int32(rand.Uint32())))
|
||||
}
|
||||
|
||||
func (*kexInitMsg) Generate(rand *rand.Rand, size int) reflect.Value {
|
||||
ki := &kexInitMsg{}
|
||||
randomBytes(ki.Cookie[:], rand)
|
||||
ki.KexAlgos = randomNameList(rand)
|
||||
ki.ServerHostKeyAlgos = randomNameList(rand)
|
||||
ki.CiphersClientServer = randomNameList(rand)
|
||||
ki.CiphersServerClient = randomNameList(rand)
|
||||
ki.MACsClientServer = randomNameList(rand)
|
||||
ki.MACsServerClient = randomNameList(rand)
|
||||
ki.CompressionClientServer = randomNameList(rand)
|
||||
ki.CompressionServerClient = randomNameList(rand)
|
||||
ki.LanguagesClientServer = randomNameList(rand)
|
||||
ki.LanguagesServerClient = randomNameList(rand)
|
||||
if rand.Int31()&1 == 1 {
|
||||
ki.FirstKexFollows = true
|
||||
}
|
||||
return reflect.ValueOf(ki)
|
||||
}
|
||||
|
||||
func (*kexDHInitMsg) Generate(rand *rand.Rand, size int) reflect.Value {
|
||||
dhi := &kexDHInitMsg{}
|
||||
dhi.X = randomInt(rand)
|
||||
return reflect.ValueOf(dhi)
|
||||
}
|
||||
|
||||
// TODO(dfc) maybe this can be removed in the future if testing/quick can handle
|
||||
// derived basic types.
|
||||
func (RejectionReason) Generate(rand *rand.Rand, size int) reflect.Value {
|
||||
m := RejectionReason(Prohibited)
|
||||
return reflect.ValueOf(m)
|
||||
}
|
||||
|
||||
var (
|
||||
_kexInitMsg = new(kexInitMsg).Generate(rand.New(rand.NewSource(0)), 10).Elem().Interface()
|
||||
_kexDHInitMsg = new(kexDHInitMsg).Generate(rand.New(rand.NewSource(0)), 10).Elem().Interface()
|
||||
|
||||
_kexInit = marshal(msgKexInit, _kexInitMsg)
|
||||
_kexDHInit = marshal(msgKexDHInit, _kexDHInitMsg)
|
||||
)
|
||||
|
||||
func BenchmarkMarshalKexInitMsg(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
marshal(msgKexInit, _kexInitMsg)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkUnmarshalKexInitMsg(b *testing.B) {
|
||||
m := new(kexInitMsg)
|
||||
for i := 0; i < b.N; i++ {
|
||||
unmarshal(m, _kexInit, msgKexInit)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkMarshalKexDHInitMsg(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
marshal(msgKexDHInit, _kexDHInitMsg)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkUnmarshalKexDHInitMsg(b *testing.B) {
|
||||
m := new(kexDHInitMsg)
|
||||
for i := 0; i < b.N; i++ {
|
||||
unmarshal(m, _kexDHInit, msgKexDHInit)
|
||||
}
|
||||
}
|
789
vendor/code.google.com/p/go.crypto/ssh/session_test.go
generated
vendored
789
vendor/code.google.com/p/go.crypto/ssh/session_test.go
generated
vendored
|
@ -1,789 +0,0 @@
|
|||
// Copyright 2011 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package ssh
|
||||
|
||||
// Session tests.
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
crypto_rand "crypto/rand"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"math/rand"
|
||||
"net"
|
||||
"testing"
|
||||
|
||||
"code.google.com/p/go.crypto/ssh/terminal"
|
||||
)
|
||||
|
||||
type serverType func(*serverChan, *testing.T)
|
||||
|
||||
// dial constructs a new test server and returns a *ClientConn.
|
||||
func dial(handler serverType, t *testing.T) *ClientConn {
|
||||
l, err := Listen("tcp", "127.0.0.1:0", serverConfig)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to listen: %v", err)
|
||||
}
|
||||
go func() {
|
||||
defer l.Close()
|
||||
conn, err := l.Accept()
|
||||
if err != nil {
|
||||
t.Errorf("Unable to accept: %v", err)
|
||||
return
|
||||
}
|
||||
defer conn.Close()
|
||||
if err := conn.Handshake(); err != nil {
|
||||
t.Errorf("Unable to handshake: %v", err)
|
||||
return
|
||||
}
|
||||
done := make(chan struct{})
|
||||
for {
|
||||
ch, err := conn.Accept()
|
||||
if err == io.EOF || err == io.ErrUnexpectedEOF {
|
||||
return
|
||||
}
|
||||
// We sometimes get ECONNRESET rather than EOF.
|
||||
if _, ok := err.(*net.OpError); ok {
|
||||
return
|
||||
}
|
||||
if err != nil {
|
||||
t.Errorf("Unable to accept incoming channel request: %v", err)
|
||||
return
|
||||
}
|
||||
if ch.ChannelType() != "session" {
|
||||
ch.Reject(UnknownChannelType, "unknown channel type")
|
||||
continue
|
||||
}
|
||||
ch.Accept()
|
||||
go func() {
|
||||
defer close(done)
|
||||
handler(ch.(*serverChan), t)
|
||||
}()
|
||||
}
|
||||
<-done
|
||||
}()
|
||||
|
||||
config := &ClientConfig{
|
||||
User: "testuser",
|
||||
Auth: []ClientAuth{
|
||||
ClientAuthPassword(clientPassword),
|
||||
},
|
||||
}
|
||||
|
||||
c, err := Dial("tcp", l.Addr().String(), config)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to dial remote side: %v", err)
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
// Test a simple string is returned to session.Stdout.
|
||||
func TestSessionShell(t *testing.T) {
|
||||
conn := dial(shellHandler, t)
|
||||
defer conn.Close()
|
||||
session, err := conn.NewSession()
|
||||
if err != nil {
|
||||
t.Fatalf("Unable to request new session: %v", err)
|
||||
}
|
||||
defer session.Close()
|
||||
stdout := new(bytes.Buffer)
|
||||
session.Stdout = stdout
|
||||
if err := session.Shell(); err != nil {
|
||||
t.Fatalf("Unable to execute command: %s", err)
|
||||
}
|
||||
if err := session.Wait(); err != nil {
|
||||
t.Fatalf("Remote command did not exit cleanly: %v", err)
|
||||
}
|
||||
actual := stdout.String()
|
||||
if actual != "golang" {
|
||||
t.Fatalf("Remote shell did not return expected string: expected=golang, actual=%s", actual)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(dfc) add support for Std{in,err}Pipe when the Server supports it.
|
||||
|
||||
// Test a simple string is returned via StdoutPipe.
|
||||
func TestSessionStdoutPipe(t *testing.T) {
|
||||
conn := dial(shellHandler, t)
|
||||
defer conn.Close()
|
||||
session, err := conn.NewSession()
|
||||
if err != nil {
|
||||
t.Fatalf("Unable to request new session: %v", err)
|
||||
}
|
||||
defer session.Close()
|
||||
stdout, err := session.StdoutPipe()
|
||||
if err != nil {
|
||||
t.Fatalf("Unable to request StdoutPipe(): %v", err)
|
||||
}
|
||||
var buf bytes.Buffer
|
||||
if err := session.Shell(); err != nil {
|
||||
t.Fatalf("Unable to execute command: %v", err)
|
||||
}
|
||||
done := make(chan bool, 1)
|
||||
go func() {
|
||||
if _, err := io.Copy(&buf, stdout); err != nil {
|
||||
t.Errorf("Copy of stdout failed: %v", err)
|
||||
}
|
||||
done <- true
|
||||
}()
|
||||
if err := session.Wait(); err != nil {
|
||||
t.Fatalf("Remote command did not exit cleanly: %v", err)
|
||||
}
|
||||
<-done
|
||||
actual := buf.String()
|
||||
if actual != "golang" {
|
||||
t.Fatalf("Remote shell did not return expected string: expected=golang, actual=%s", actual)
|
||||
}
|
||||
}
|
||||
|
||||
// Test that a simple string is returned via the Output helper,
|
||||
// and that stderr is discarded.
|
||||
func TestSessionOutput(t *testing.T) {
|
||||
conn := dial(fixedOutputHandler, t)
|
||||
defer conn.Close()
|
||||
session, err := conn.NewSession()
|
||||
if err != nil {
|
||||
t.Fatalf("Unable to request new session: %v", err)
|
||||
}
|
||||
defer session.Close()
|
||||
|
||||
buf, err := session.Output("") // cmd is ignored by fixedOutputHandler
|
||||
if err != nil {
|
||||
t.Error("Remote command did not exit cleanly:", err)
|
||||
}
|
||||
w := "this-is-stdout."
|
||||
g := string(buf)
|
||||
if g != w {
|
||||
t.Error("Remote command did not return expected string:")
|
||||
t.Logf("want %q", w)
|
||||
t.Logf("got %q", g)
|
||||
}
|
||||
}
|
||||
|
||||
// Test that both stdout and stderr are returned
|
||||
// via the CombinedOutput helper.
|
||||
func TestSessionCombinedOutput(t *testing.T) {
|
||||
conn := dial(fixedOutputHandler, t)
|
||||
defer conn.Close()
|
||||
session, err := conn.NewSession()
|
||||
if err != nil {
|
||||
t.Fatalf("Unable to request new session: %v", err)
|
||||
}
|
||||
defer session.Close()
|
||||
|
||||
buf, err := session.CombinedOutput("") // cmd is ignored by fixedOutputHandler
|
||||
if err != nil {
|
||||
t.Error("Remote command did not exit cleanly:", err)
|
||||
}
|
||||
const stdout = "this-is-stdout."
|
||||
const stderr = "this-is-stderr."
|
||||
g := string(buf)
|
||||
if g != stdout+stderr && g != stderr+stdout {
|
||||
t.Error("Remote command did not return expected string:")
|
||||
t.Logf("want %q, or %q", stdout+stderr, stderr+stdout)
|
||||
t.Logf("got %q", g)
|
||||
}
|
||||
}
|
||||
|
||||
// Test non-0 exit status is returned correctly.
|
||||
func TestExitStatusNonZero(t *testing.T) {
|
||||
conn := dial(exitStatusNonZeroHandler, t)
|
||||
defer conn.Close()
|
||||
session, err := conn.NewSession()
|
||||
if err != nil {
|
||||
t.Fatalf("Unable to request new session: %v", err)
|
||||
}
|
||||
defer session.Close()
|
||||
if err := session.Shell(); err != nil {
|
||||
t.Fatalf("Unable to execute command: %v", err)
|
||||
}
|
||||
err = session.Wait()
|
||||
if err == nil {
|
||||
t.Fatalf("expected command to fail but it didn't")
|
||||
}
|
||||
e, ok := err.(*ExitError)
|
||||
if !ok {
|
||||
t.Fatalf("expected *ExitError but got %T", err)
|
||||
}
|
||||
if e.ExitStatus() != 15 {
|
||||
t.Fatalf("expected command to exit with 15 but got %v", e.ExitStatus())
|
||||
}
|
||||
}
|
||||
|
||||
// Test 0 exit status is returned correctly.
|
||||
func TestExitStatusZero(t *testing.T) {
|
||||
conn := dial(exitStatusZeroHandler, t)
|
||||
defer conn.Close()
|
||||
session, err := conn.NewSession()
|
||||
if err != nil {
|
||||
t.Fatalf("Unable to request new session: %v", err)
|
||||
}
|
||||
defer session.Close()
|
||||
|
||||
if err := session.Shell(); err != nil {
|
||||
t.Fatalf("Unable to execute command: %v", err)
|
||||
}
|
||||
err = session.Wait()
|
||||
if err != nil {
|
||||
t.Fatalf("expected nil but got %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Test exit signal and status are both returned correctly.
|
||||
func TestExitSignalAndStatus(t *testing.T) {
|
||||
conn := dial(exitSignalAndStatusHandler, t)
|
||||
defer conn.Close()
|
||||
session, err := conn.NewSession()
|
||||
if err != nil {
|
||||
t.Fatalf("Unable to request new session: %v", err)
|
||||
}
|
||||
defer session.Close()
|
||||
if err := session.Shell(); err != nil {
|
||||
t.Fatalf("Unable to execute command: %v", err)
|
||||
}
|
||||
err = session.Wait()
|
||||
if err == nil {
|
||||
t.Fatalf("expected command to fail but it didn't")
|
||||
}
|
||||
e, ok := err.(*ExitError)
|
||||
if !ok {
|
||||
t.Fatalf("expected *ExitError but got %T", err)
|
||||
}
|
||||
if e.Signal() != "TERM" || e.ExitStatus() != 15 {
|
||||
t.Fatalf("expected command to exit with signal TERM and status 15 but got signal %s and status %v", e.Signal(), e.ExitStatus())
|
||||
}
|
||||
}
|
||||
|
||||
// Test exit signal and status are both returned correctly.
|
||||
func TestKnownExitSignalOnly(t *testing.T) {
|
||||
conn := dial(exitSignalHandler, t)
|
||||
defer conn.Close()
|
||||
session, err := conn.NewSession()
|
||||
if err != nil {
|
||||
t.Fatalf("Unable to request new session: %v", err)
|
||||
}
|
||||
defer session.Close()
|
||||
if err := session.Shell(); err != nil {
|
||||
t.Fatalf("Unable to execute command: %v", err)
|
||||
}
|
||||
err = session.Wait()
|
||||
if err == nil {
|
||||
t.Fatalf("expected command to fail but it didn't")
|
||||
}
|
||||
e, ok := err.(*ExitError)
|
||||
if !ok {
|
||||
t.Fatalf("expected *ExitError but got %T", err)
|
||||
}
|
||||
if e.Signal() != "TERM" || e.ExitStatus() != 143 {
|
||||
t.Fatalf("expected command to exit with signal TERM and status 143 but got signal %s and status %v", e.Signal(), e.ExitStatus())
|
||||
}
|
||||
}
|
||||
|
||||
// Test exit signal and status are both returned correctly.
|
||||
func TestUnknownExitSignal(t *testing.T) {
|
||||
conn := dial(exitSignalUnknownHandler, t)
|
||||
defer conn.Close()
|
||||
session, err := conn.NewSession()
|
||||
if err != nil {
|
||||
t.Fatalf("Unable to request new session: %v", err)
|
||||
}
|
||||
defer session.Close()
|
||||
if err := session.Shell(); err != nil {
|
||||
t.Fatalf("Unable to execute command: %v", err)
|
||||
}
|
||||
err = session.Wait()
|
||||
if err == nil {
|
||||
t.Fatalf("expected command to fail but it didn't")
|
||||
}
|
||||
e, ok := err.(*ExitError)
|
||||
if !ok {
|
||||
t.Fatalf("expected *ExitError but got %T", err)
|
||||
}
|
||||
if e.Signal() != "SYS" || e.ExitStatus() != 128 {
|
||||
t.Fatalf("expected command to exit with signal SYS and status 128 but got signal %s and status %v", e.Signal(), e.ExitStatus())
|
||||
}
|
||||
}
|
||||
|
||||
// Test WaitMsg is not returned if the channel closes abruptly.
|
||||
func TestExitWithoutStatusOrSignal(t *testing.T) {
|
||||
conn := dial(exitWithoutSignalOrStatus, t)
|
||||
defer conn.Close()
|
||||
session, err := conn.NewSession()
|
||||
if err != nil {
|
||||
t.Fatalf("Unable to request new session: %v", err)
|
||||
}
|
||||
defer session.Close()
|
||||
if err := session.Shell(); err != nil {
|
||||
t.Fatalf("Unable to execute command: %v", err)
|
||||
}
|
||||
err = session.Wait()
|
||||
if err == nil {
|
||||
t.Fatalf("expected command to fail but it didn't")
|
||||
}
|
||||
_, ok := err.(*ExitError)
|
||||
if ok {
|
||||
// you can't actually test for errors.errorString
|
||||
// because it's not exported.
|
||||
t.Fatalf("expected *errorString but got %T", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestInvalidServerMessage(t *testing.T) {
|
||||
conn := dial(sendInvalidRecord, t)
|
||||
defer conn.Close()
|
||||
session, err := conn.NewSession()
|
||||
if err != nil {
|
||||
t.Fatalf("Unable to request new session: %v", err)
|
||||
}
|
||||
// Make sure that we closed all the clientChans when the connection
|
||||
// failed.
|
||||
session.wait()
|
||||
|
||||
defer session.Close()
|
||||
}
|
||||
|
||||
// In the wild some clients (and servers) send zero sized window updates.
|
||||
// Test that the client can continue after receiving a zero sized update.
|
||||
func TestClientZeroWindowAdjust(t *testing.T) {
|
||||
conn := dial(sendZeroWindowAdjust, t)
|
||||
defer conn.Close()
|
||||
session, err := conn.NewSession()
|
||||
if err != nil {
|
||||
t.Fatalf("Unable to request new session: %v", err)
|
||||
}
|
||||
defer session.Close()
|
||||
|
||||
if err := session.Shell(); err != nil {
|
||||
t.Fatalf("Unable to execute command: %v", err)
|
||||
}
|
||||
err = session.Wait()
|
||||
if err != nil {
|
||||
t.Fatalf("expected nil but got %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// In the wild some clients (and servers) send zero sized window updates.
|
||||
// Test that the server can continue after receiving a zero size update.
|
||||
func TestServerZeroWindowAdjust(t *testing.T) {
|
||||
conn := dial(exitStatusZeroHandler, t)
|
||||
defer conn.Close()
|
||||
session, err := conn.NewSession()
|
||||
if err != nil {
|
||||
t.Fatalf("Unable to request new session: %v", err)
|
||||
}
|
||||
defer session.Close()
|
||||
|
||||
if err := session.Shell(); err != nil {
|
||||
t.Fatalf("Unable to execute command: %v", err)
|
||||
}
|
||||
|
||||
// send a bogus zero sized window update
|
||||
session.clientChan.sendWindowAdj(0)
|
||||
|
||||
err = session.Wait()
|
||||
if err != nil {
|
||||
t.Fatalf("expected nil but got %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Verify that the client never sends a packet larger than maxpacket.
|
||||
func TestClientStdinRespectsMaxPacketSize(t *testing.T) {
|
||||
conn := dial(discardHandler, t)
|
||||
defer conn.Close()
|
||||
session, err := conn.NewSession()
|
||||
if err != nil {
|
||||
t.Fatalf("failed to request new session: %v", err)
|
||||
}
|
||||
defer session.Close()
|
||||
stdin, err := session.StdinPipe()
|
||||
if err != nil {
|
||||
t.Fatalf("failed to obtain stdinpipe: %v", err)
|
||||
}
|
||||
const size = 100 * 1000
|
||||
for i := 0; i < 10; i++ {
|
||||
n, err := stdin.Write(make([]byte, size))
|
||||
if n != size || err != nil {
|
||||
t.Fatalf("failed to write: %d, %v", n, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Verify that the client never accepts a packet larger than maxpacket.
|
||||
func TestServerStdoutRespectsMaxPacketSize(t *testing.T) {
|
||||
conn := dial(largeSendHandler, t)
|
||||
defer conn.Close()
|
||||
session, err := conn.NewSession()
|
||||
if err != nil {
|
||||
t.Fatalf("Unable to request new session: %v", err)
|
||||
}
|
||||
defer session.Close()
|
||||
out, err := session.StdoutPipe()
|
||||
if err != nil {
|
||||
t.Fatalf("Unable to connect to Stdout: %v", err)
|
||||
}
|
||||
if err := session.Shell(); err != nil {
|
||||
t.Fatalf("Unable to execute command: %v", err)
|
||||
}
|
||||
if _, err := ioutil.ReadAll(out); err != nil {
|
||||
t.Fatalf("failed to read: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestClientCannotSendAfterEOF(t *testing.T) {
|
||||
conn := dial(exitWithoutSignalOrStatus, t)
|
||||
defer conn.Close()
|
||||
session, err := conn.NewSession()
|
||||
if err != nil {
|
||||
t.Fatalf("Unable to request new session: %v", err)
|
||||
}
|
||||
defer session.Close()
|
||||
in, err := session.StdinPipe()
|
||||
if err != nil {
|
||||
t.Fatalf("Unable to connect channel stdin: %v", err)
|
||||
}
|
||||
if err := session.Shell(); err != nil {
|
||||
t.Fatalf("Unable to execute command: %v", err)
|
||||
}
|
||||
if err := in.Close(); err != nil {
|
||||
t.Fatalf("Unable to close stdin: %v", err)
|
||||
}
|
||||
if _, err := in.Write([]byte("foo")); err == nil {
|
||||
t.Fatalf("Session write should fail")
|
||||
}
|
||||
}
|
||||
|
||||
func TestClientCannotSendAfterClose(t *testing.T) {
|
||||
conn := dial(exitWithoutSignalOrStatus, t)
|
||||
defer conn.Close()
|
||||
session, err := conn.NewSession()
|
||||
if err != nil {
|
||||
t.Fatalf("Unable to request new session: %v", err)
|
||||
}
|
||||
defer session.Close()
|
||||
in, err := session.StdinPipe()
|
||||
if err != nil {
|
||||
t.Fatalf("Unable to connect channel stdin: %v", err)
|
||||
}
|
||||
if err := session.Shell(); err != nil {
|
||||
t.Fatalf("Unable to execute command: %v", err)
|
||||
}
|
||||
// close underlying channel
|
||||
if err := session.channel.Close(); err != nil {
|
||||
t.Fatalf("Unable to close session: %v", err)
|
||||
}
|
||||
if _, err := in.Write([]byte("foo")); err == nil {
|
||||
t.Fatalf("Session write should fail")
|
||||
}
|
||||
}
|
||||
|
||||
func TestClientCannotSendHugePacket(t *testing.T) {
|
||||
// client and server use the same transport write code so this
|
||||
// test suffices for both.
|
||||
conn := dial(shellHandler, t)
|
||||
defer conn.Close()
|
||||
if err := conn.transport.writePacket(make([]byte, maxPacket*2)); err == nil {
|
||||
t.Fatalf("huge packet write should fail")
|
||||
}
|
||||
}
|
||||
|
||||
// windowTestBytes is the number of bytes that we'll send to the SSH server.
|
||||
const windowTestBytes = 16000 * 200
|
||||
|
||||
// TestServerWindow writes random data to the server. The server is expected to echo
|
||||
// the same data back, which is compared against the original.
|
||||
func TestServerWindow(t *testing.T) {
|
||||
origBuf := bytes.NewBuffer(make([]byte, 0, windowTestBytes))
|
||||
io.CopyN(origBuf, crypto_rand.Reader, windowTestBytes)
|
||||
origBytes := origBuf.Bytes()
|
||||
|
||||
conn := dial(echoHandler, t)
|
||||
defer conn.Close()
|
||||
session, err := conn.NewSession()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer session.Close()
|
||||
result := make(chan []byte)
|
||||
|
||||
go func() {
|
||||
defer close(result)
|
||||
echoedBuf := bytes.NewBuffer(make([]byte, 0, windowTestBytes))
|
||||
serverStdout, err := session.StdoutPipe()
|
||||
if err != nil {
|
||||
t.Errorf("StdoutPipe failed: %v", err)
|
||||
return
|
||||
}
|
||||
n, err := copyNRandomly("stdout", echoedBuf, serverStdout, windowTestBytes)
|
||||
if err != nil && err != io.EOF {
|
||||
t.Errorf("Read only %d bytes from server, expected %d: %v", n, windowTestBytes, err)
|
||||
}
|
||||
result <- echoedBuf.Bytes()
|
||||
}()
|
||||
|
||||
serverStdin, err := session.StdinPipe()
|
||||
if err != nil {
|
||||
t.Fatalf("StdinPipe failed: %v", err)
|
||||
}
|
||||
written, err := copyNRandomly("stdin", serverStdin, origBuf, windowTestBytes)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to copy origBuf to serverStdin: %v", err)
|
||||
}
|
||||
if written != windowTestBytes {
|
||||
t.Fatalf("Wrote only %d of %d bytes to server", written, windowTestBytes)
|
||||
}
|
||||
|
||||
echoedBytes := <-result
|
||||
|
||||
if !bytes.Equal(origBytes, echoedBytes) {
|
||||
t.Fatalf("Echoed buffer differed from original, orig %d, echoed %d", len(origBytes), len(echoedBytes))
|
||||
}
|
||||
}
|
||||
|
||||
// Verify the client can handle a keepalive packet from the server.
|
||||
func TestClientHandlesKeepalives(t *testing.T) {
|
||||
conn := dial(channelKeepaliveSender, t)
|
||||
defer conn.Close()
|
||||
session, err := conn.NewSession()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer session.Close()
|
||||
if err := session.Shell(); err != nil {
|
||||
t.Fatalf("Unable to execute command: %v", err)
|
||||
}
|
||||
err = session.Wait()
|
||||
if err != nil {
|
||||
t.Fatalf("expected nil but got: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
type exitStatusMsg struct {
|
||||
PeersId uint32
|
||||
Request string
|
||||
WantReply bool
|
||||
Status uint32
|
||||
}
|
||||
|
||||
type exitSignalMsg struct {
|
||||
PeersId uint32
|
||||
Request string
|
||||
WantReply bool
|
||||
Signal string
|
||||
CoreDumped bool
|
||||
Errmsg string
|
||||
Lang string
|
||||
}
|
||||
|
||||
func newServerShell(ch *serverChan, prompt string) *ServerTerminal {
|
||||
term := terminal.NewTerminal(ch, prompt)
|
||||
return &ServerTerminal{
|
||||
Term: term,
|
||||
Channel: ch,
|
||||
}
|
||||
}
|
||||
|
||||
func exitStatusZeroHandler(ch *serverChan, t *testing.T) {
|
||||
defer ch.Close()
|
||||
// this string is returned to stdout
|
||||
shell := newServerShell(ch, "> ")
|
||||
readLine(shell, t)
|
||||
sendStatus(0, ch, t)
|
||||
}
|
||||
|
||||
func exitStatusNonZeroHandler(ch *serverChan, t *testing.T) {
|
||||
defer ch.Close()
|
||||
shell := newServerShell(ch, "> ")
|
||||
readLine(shell, t)
|
||||
sendStatus(15, ch, t)
|
||||
}
|
||||
|
||||
func exitSignalAndStatusHandler(ch *serverChan, t *testing.T) {
|
||||
defer ch.Close()
|
||||
shell := newServerShell(ch, "> ")
|
||||
readLine(shell, t)
|
||||
sendStatus(15, ch, t)
|
||||
sendSignal("TERM", ch, t)
|
||||
}
|
||||
|
||||
func exitSignalHandler(ch *serverChan, t *testing.T) {
|
||||
defer ch.Close()
|
||||
shell := newServerShell(ch, "> ")
|
||||
readLine(shell, t)
|
||||
sendSignal("TERM", ch, t)
|
||||
}
|
||||
|
||||
func exitSignalUnknownHandler(ch *serverChan, t *testing.T) {
|
||||
defer ch.Close()
|
||||
shell := newServerShell(ch, "> ")
|
||||
readLine(shell, t)
|
||||
sendSignal("SYS", ch, t)
|
||||
}
|
||||
|
||||
func exitWithoutSignalOrStatus(ch *serverChan, t *testing.T) {
|
||||
defer ch.Close()
|
||||
shell := newServerShell(ch, "> ")
|
||||
readLine(shell, t)
|
||||
}
|
||||
|
||||
func shellHandler(ch *serverChan, t *testing.T) {
|
||||
defer ch.Close()
|
||||
// this string is returned to stdout
|
||||
shell := newServerShell(ch, "golang")
|
||||
readLine(shell, t)
|
||||
sendStatus(0, ch, t)
|
||||
}
|
||||
|
||||
// Ignores the command, writes fixed strings to stderr and stdout.
|
||||
// Strings are "this-is-stdout." and "this-is-stderr.".
|
||||
func fixedOutputHandler(ch *serverChan, t *testing.T) {
|
||||
defer ch.Close()
|
||||
|
||||
_, err := ch.Read(make([]byte, 0))
|
||||
if _, ok := err.(ChannelRequest); !ok {
|
||||
t.Fatalf("error: expected channel request, got: %#v", err)
|
||||
return
|
||||
}
|
||||
// ignore request, always send some text
|
||||
ch.AckRequest(true)
|
||||
|
||||
_, err = io.WriteString(ch, "this-is-stdout.")
|
||||
if err != nil {
|
||||
t.Fatalf("error writing on server: %v", err)
|
||||
}
|
||||
_, err = io.WriteString(ch.Stderr(), "this-is-stderr.")
|
||||
if err != nil {
|
||||
t.Fatalf("error writing on server: %v", err)
|
||||
}
|
||||
sendStatus(0, ch, t)
|
||||
}
|
||||
|
||||
func readLine(shell *ServerTerminal, t *testing.T) {
|
||||
if _, err := shell.ReadLine(); err != nil && err != io.EOF {
|
||||
t.Errorf("unable to read line: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func sendStatus(status uint32, ch *serverChan, t *testing.T) {
|
||||
msg := exitStatusMsg{
|
||||
PeersId: ch.remoteId,
|
||||
Request: "exit-status",
|
||||
WantReply: false,
|
||||
Status: status,
|
||||
}
|
||||
if err := ch.writePacket(marshal(msgChannelRequest, msg)); err != nil {
|
||||
t.Errorf("unable to send status: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func sendSignal(signal string, ch *serverChan, t *testing.T) {
|
||||
sig := exitSignalMsg{
|
||||
PeersId: ch.remoteId,
|
||||
Request: "exit-signal",
|
||||
WantReply: false,
|
||||
Signal: signal,
|
||||
CoreDumped: false,
|
||||
Errmsg: "Process terminated",
|
||||
Lang: "en-GB-oed",
|
||||
}
|
||||
if err := ch.writePacket(marshal(msgChannelRequest, sig)); err != nil {
|
||||
t.Errorf("unable to send signal: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func sendInvalidRecord(ch *serverChan, t *testing.T) {
|
||||
defer ch.Close()
|
||||
packet := make([]byte, 1+4+4+1)
|
||||
packet[0] = msgChannelData
|
||||
marshalUint32(packet[1:], 29348723 /* invalid channel id */)
|
||||
marshalUint32(packet[5:], 1)
|
||||
packet[9] = 42
|
||||
|
||||
if err := ch.writePacket(packet); err != nil {
|
||||
t.Errorf("unable send invalid record: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func sendZeroWindowAdjust(ch *serverChan, t *testing.T) {
|
||||
defer ch.Close()
|
||||
// send a bogus zero sized window update
|
||||
ch.sendWindowAdj(0)
|
||||
shell := newServerShell(ch, "> ")
|
||||
readLine(shell, t)
|
||||
sendStatus(0, ch, t)
|
||||
}
|
||||
|
||||
func discardHandler(ch *serverChan, t *testing.T) {
|
||||
defer ch.Close()
|
||||
// grow the window to avoid being fooled by
|
||||
// the initial 1 << 14 window.
|
||||
ch.sendWindowAdj(1024 * 1024)
|
||||
io.Copy(ioutil.Discard, ch)
|
||||
}
|
||||
|
||||
func largeSendHandler(ch *serverChan, t *testing.T) {
|
||||
defer ch.Close()
|
||||
// grow the window to avoid being fooled by
|
||||
// the initial 1 << 14 window.
|
||||
ch.sendWindowAdj(1024 * 1024)
|
||||
shell := newServerShell(ch, "> ")
|
||||
readLine(shell, t)
|
||||
// try to send more than the 32k window
|
||||
// will allow
|
||||
if err := ch.writePacket(make([]byte, 128*1024)); err == nil {
|
||||
t.Errorf("wrote packet larger than 32k")
|
||||
}
|
||||
}
|
||||
|
||||
func echoHandler(ch *serverChan, t *testing.T) {
|
||||
defer ch.Close()
|
||||
if n, err := copyNRandomly("echohandler", ch, ch, windowTestBytes); err != nil {
|
||||
t.Errorf("short write, wrote %d, expected %d: %v ", n, windowTestBytes, err)
|
||||
}
|
||||
}
|
||||
|
||||
// copyNRandomly copies n bytes from src to dst. It uses a variable, and random,
|
||||
// buffer size to exercise more code paths.
|
||||
func copyNRandomly(title string, dst io.Writer, src io.Reader, n int) (int, error) {
|
||||
var (
|
||||
buf = make([]byte, 32*1024)
|
||||
written int
|
||||
remaining = n
|
||||
)
|
||||
for remaining > 0 {
|
||||
l := rand.Intn(1 << 15)
|
||||
if remaining < l {
|
||||
l = remaining
|
||||
}
|
||||
nr, er := src.Read(buf[:l])
|
||||
nw, ew := dst.Write(buf[:nr])
|
||||
remaining -= nw
|
||||
written += nw
|
||||
if ew != nil {
|
||||
return written, ew
|
||||
}
|
||||
if nr != nw {
|
||||
return written, io.ErrShortWrite
|
||||
}
|
||||
if er != nil && er != io.EOF {
|
||||
return written, er
|
||||
}
|
||||
}
|
||||
return written, nil
|
||||
}
|
||||
|
||||
func channelKeepaliveSender(ch *serverChan, t *testing.T) {
|
||||
defer ch.Close()
|
||||
shell := newServerShell(ch, "> ")
|
||||
readLine(shell, t)
|
||||
msg := channelRequestMsg{
|
||||
PeersId: ch.remoteId,
|
||||
Request: "keepalive@openssh.com",
|
||||
WantReply: true,
|
||||
}
|
||||
if err := ch.writePacket(marshal(msgChannelRequest, msg)); err != nil {
|
||||
t.Errorf("unable to send channel keepalive request: %v", err)
|
||||
}
|
||||
sendStatus(0, ch, t)
|
||||
}
|
16
vendor/code.google.com/p/go.crypto/ssh/tcpip_test.go
generated
vendored
16
vendor/code.google.com/p/go.crypto/ssh/tcpip_test.go
generated
vendored
|
@ -1,16 +0,0 @@
|
|||
package ssh
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestAutoPortListenBroken(t *testing.T) {
|
||||
broken := "SSH-2.0-OpenSSH_5.9hh11"
|
||||
works := "SSH-2.0-OpenSSH_6.1"
|
||||
if !isBrokenOpenSSHVersion(broken) {
|
||||
t.Errorf("version %q not marked as broken", broken)
|
||||
}
|
||||
if isBrokenOpenSSHVersion(works) {
|
||||
t.Errorf("version %q marked as broken", works)
|
||||
}
|
||||
}
|
699
vendor/code.google.com/p/go.crypto/ssh/terminal/terminal.go
generated
vendored
699
vendor/code.google.com/p/go.crypto/ssh/terminal/terminal.go
generated
vendored
|
@ -1,699 +0,0 @@
|
|||
// Copyright 2011 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package terminal
|
||||
|
||||
import (
|
||||
"io"
|
||||
"sync"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
// EscapeCodes contains escape sequences that can be written to the terminal in
|
||||
// order to achieve different styles of text.
|
||||
type EscapeCodes struct {
|
||||
// Foreground colors
|
||||
Black, Red, Green, Yellow, Blue, Magenta, Cyan, White []byte
|
||||
|
||||
// Reset all attributes
|
||||
Reset []byte
|
||||
}
|
||||
|
||||
var vt100EscapeCodes = EscapeCodes{
|
||||
Black: []byte{keyEscape, '[', '3', '0', 'm'},
|
||||
Red: []byte{keyEscape, '[', '3', '1', 'm'},
|
||||
Green: []byte{keyEscape, '[', '3', '2', 'm'},
|
||||
Yellow: []byte{keyEscape, '[', '3', '3', 'm'},
|
||||
Blue: []byte{keyEscape, '[', '3', '4', 'm'},
|
||||
Magenta: []byte{keyEscape, '[', '3', '5', 'm'},
|
||||
Cyan: []byte{keyEscape, '[', '3', '6', 'm'},
|
||||
White: []byte{keyEscape, '[', '3', '7', 'm'},
|
||||
|
||||
Reset: []byte{keyEscape, '[', '0', 'm'},
|
||||
}
|
||||
|
||||
// Terminal contains the state for running a VT100 terminal that is capable of
|
||||
// reading lines of input.
|
||||
type Terminal struct {
|
||||
// AutoCompleteCallback, if non-null, is called for each keypress with
|
||||
// the full input line and the current position of the cursor (in
|
||||
// bytes, as an index into |line|). If it returns ok=false, the key
|
||||
// press is processed normally. Otherwise it returns a replacement line
|
||||
// and the new cursor position.
|
||||
AutoCompleteCallback func(line string, pos int, key rune) (newLine string, newPos int, ok bool)
|
||||
|
||||
// Escape contains a pointer to the escape codes for this terminal.
|
||||
// It's always a valid pointer, although the escape codes themselves
|
||||
// may be empty if the terminal doesn't support them.
|
||||
Escape *EscapeCodes
|
||||
|
||||
// lock protects the terminal and the state in this object from
|
||||
// concurrent processing of a key press and a Write() call.
|
||||
lock sync.Mutex
|
||||
|
||||
c io.ReadWriter
|
||||
prompt string
|
||||
|
||||
// line is the current line being entered.
|
||||
line []rune
|
||||
// pos is the logical position of the cursor in line
|
||||
pos int
|
||||
// echo is true if local echo is enabled
|
||||
echo bool
|
||||
|
||||
// cursorX contains the current X value of the cursor where the left
|
||||
// edge is 0. cursorY contains the row number where the first row of
|
||||
// the current line is 0.
|
||||
cursorX, cursorY int
|
||||
// maxLine is the greatest value of cursorY so far.
|
||||
maxLine int
|
||||
|
||||
termWidth, termHeight int
|
||||
|
||||
// outBuf contains the terminal data to be sent.
|
||||
outBuf []byte
|
||||
// remainder contains the remainder of any partial key sequences after
|
||||
// a read. It aliases into inBuf.
|
||||
remainder []byte
|
||||
inBuf [256]byte
|
||||
|
||||
// history contains previously entered commands so that they can be
|
||||
// accessed with the up and down keys.
|
||||
history stRingBuffer
|
||||
// historyIndex stores the currently accessed history entry, where zero
|
||||
// means the immediately previous entry.
|
||||
historyIndex int
|
||||
// When navigating up and down the history it's possible to return to
|
||||
// the incomplete, initial line. That value is stored in
|
||||
// historyPending.
|
||||
historyPending string
|
||||
}
|
||||
|
||||
// NewTerminal runs a VT100 terminal on the given ReadWriter. If the ReadWriter is
|
||||
// a local terminal, that terminal must first have been put into raw mode.
|
||||
// prompt is a string that is written at the start of each input line (i.e.
|
||||
// "> ").
|
||||
func NewTerminal(c io.ReadWriter, prompt string) *Terminal {
|
||||
return &Terminal{
|
||||
Escape: &vt100EscapeCodes,
|
||||
c: c,
|
||||
prompt: prompt,
|
||||
termWidth: 80,
|
||||
termHeight: 24,
|
||||
echo: true,
|
||||
historyIndex: -1,
|
||||
}
|
||||
}
|
||||
|
||||
const (
|
||||
keyCtrlD = 4
|
||||
keyEnter = '\r'
|
||||
keyEscape = 27
|
||||
keyBackspace = 127
|
||||
keyUnknown = 0xd800 /* UTF-16 surrogate area */ + iota
|
||||
keyUp
|
||||
keyDown
|
||||
keyLeft
|
||||
keyRight
|
||||
keyAltLeft
|
||||
keyAltRight
|
||||
keyHome
|
||||
keyEnd
|
||||
keyDeleteWord
|
||||
keyDeleteLine
|
||||
)
|
||||
|
||||
// bytesToKey tries to parse a key sequence from b. If successful, it returns
|
||||
// the key and the remainder of the input. Otherwise it returns utf8.RuneError.
|
||||
func bytesToKey(b []byte) (rune, []byte) {
|
||||
if len(b) == 0 {
|
||||
return utf8.RuneError, nil
|
||||
}
|
||||
|
||||
switch b[0] {
|
||||
case 1: // ^A
|
||||
return keyHome, b[1:]
|
||||
case 5: // ^E
|
||||
return keyEnd, b[1:]
|
||||
case 8: // ^H
|
||||
return keyBackspace, b[1:]
|
||||
case 11: // ^K
|
||||
return keyDeleteLine, b[1:]
|
||||
case 23: // ^W
|
||||
return keyDeleteWord, b[1:]
|
||||
}
|
||||
|
||||
if b[0] != keyEscape {
|
||||
if !utf8.FullRune(b) {
|
||||
return utf8.RuneError, b
|
||||
}
|
||||
r, l := utf8.DecodeRune(b)
|
||||
return r, b[l:]
|
||||
}
|
||||
|
||||
if len(b) >= 3 && b[0] == keyEscape && b[1] == '[' {
|
||||
switch b[2] {
|
||||
case 'A':
|
||||
return keyUp, b[3:]
|
||||
case 'B':
|
||||
return keyDown, b[3:]
|
||||
case 'C':
|
||||
return keyRight, b[3:]
|
||||
case 'D':
|
||||
return keyLeft, b[3:]
|
||||
}
|
||||
}
|
||||
|
||||
if len(b) >= 3 && b[0] == keyEscape && b[1] == 'O' {
|
||||
switch b[2] {
|
||||
case 'H':
|
||||
return keyHome, b[3:]
|
||||
case 'F':
|
||||
return keyEnd, b[3:]
|
||||
}
|
||||
}
|
||||
|
||||
if len(b) >= 6 && b[0] == keyEscape && b[1] == '[' && b[2] == '1' && b[3] == ';' && b[4] == '3' {
|
||||
switch b[5] {
|
||||
case 'C':
|
||||
return keyAltRight, b[6:]
|
||||
case 'D':
|
||||
return keyAltLeft, b[6:]
|
||||
}
|
||||
}
|
||||
|
||||
// If we get here then we have a key that we don't recognise, or a
|
||||
// partial sequence. It's not clear how one should find the end of a
|
||||
// sequence without knowing them all, but it seems that [a-zA-Z] only
|
||||
// appears at the end of a sequence.
|
||||
for i, c := range b[0:] {
|
||||
if c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z' {
|
||||
return keyUnknown, b[i+1:]
|
||||
}
|
||||
}
|
||||
|
||||
return utf8.RuneError, b
|
||||
}
|
||||
|
||||
// queue appends data to the end of t.outBuf
|
||||
func (t *Terminal) queue(data []rune) {
|
||||
t.outBuf = append(t.outBuf, []byte(string(data))...)
|
||||
}
|
||||
|
||||
var eraseUnderCursor = []rune{' ', keyEscape, '[', 'D'}
|
||||
var space = []rune{' '}
|
||||
|
||||
func isPrintable(key rune) bool {
|
||||
isInSurrogateArea := key >= 0xd800 && key <= 0xdbff
|
||||
return key >= 32 && !isInSurrogateArea
|
||||
}
|
||||
|
||||
// moveCursorToPos appends data to t.outBuf which will move the cursor to the
|
||||
// given, logical position in the text.
|
||||
func (t *Terminal) moveCursorToPos(pos int) {
|
||||
if !t.echo {
|
||||
return
|
||||
}
|
||||
|
||||
x := len(t.prompt) + pos
|
||||
y := x / t.termWidth
|
||||
x = x % t.termWidth
|
||||
|
||||
up := 0
|
||||
if y < t.cursorY {
|
||||
up = t.cursorY - y
|
||||
}
|
||||
|
||||
down := 0
|
||||
if y > t.cursorY {
|
||||
down = y - t.cursorY
|
||||
}
|
||||
|
||||
left := 0
|
||||
if x < t.cursorX {
|
||||
left = t.cursorX - x
|
||||
}
|
||||
|
||||
right := 0
|
||||
if x > t.cursorX {
|
||||
right = x - t.cursorX
|
||||
}
|
||||
|
||||
t.cursorX = x
|
||||
t.cursorY = y
|
||||
t.move(up, down, left, right)
|
||||
}
|
||||
|
||||
func (t *Terminal) move(up, down, left, right int) {
|
||||
movement := make([]rune, 3*(up+down+left+right))
|
||||
m := movement
|
||||
for i := 0; i < up; i++ {
|
||||
m[0] = keyEscape
|
||||
m[1] = '['
|
||||
m[2] = 'A'
|
||||
m = m[3:]
|
||||
}
|
||||
for i := 0; i < down; i++ {
|
||||
m[0] = keyEscape
|
||||
m[1] = '['
|
||||
m[2] = 'B'
|
||||
m = m[3:]
|
||||
}
|
||||
for i := 0; i < left; i++ {
|
||||
m[0] = keyEscape
|
||||
m[1] = '['
|
||||
m[2] = 'D'
|
||||
m = m[3:]
|
||||
}
|
||||
for i := 0; i < right; i++ {
|
||||
m[0] = keyEscape
|
||||
m[1] = '['
|
||||
m[2] = 'C'
|
||||
m = m[3:]
|
||||
}
|
||||
|
||||
t.queue(movement)
|
||||
}
|
||||
|
||||
func (t *Terminal) clearLineToRight() {
|
||||
op := []rune{keyEscape, '[', 'K'}
|
||||
t.queue(op)
|
||||
}
|
||||
|
||||
const maxLineLength = 4096
|
||||
|
||||
func (t *Terminal) setLine(newLine []rune, newPos int) {
|
||||
if t.echo {
|
||||
t.moveCursorToPos(0)
|
||||
t.writeLine(newLine)
|
||||
for i := len(newLine); i < len(t.line); i++ {
|
||||
t.writeLine(space)
|
||||
}
|
||||
t.moveCursorToPos(newPos)
|
||||
}
|
||||
t.line = newLine
|
||||
t.pos = newPos
|
||||
}
|
||||
|
||||
func (t *Terminal) eraseNPreviousChars(n int) {
|
||||
if n == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
if t.pos < n {
|
||||
n = t.pos
|
||||
}
|
||||
t.pos -= n
|
||||
t.moveCursorToPos(t.pos)
|
||||
|
||||
copy(t.line[t.pos:], t.line[n+t.pos:])
|
||||
t.line = t.line[:len(t.line)-n]
|
||||
if t.echo {
|
||||
t.writeLine(t.line[t.pos:])
|
||||
for i := 0; i < n; i++ {
|
||||
t.queue(space)
|
||||
}
|
||||
t.cursorX += n
|
||||
t.moveCursorToPos(t.pos)
|
||||
}
|
||||
}
|
||||
|
||||
// countToLeftWord returns then number of characters from the cursor to the
|
||||
// start of the previous word.
|
||||
func (t *Terminal) countToLeftWord() int {
|
||||
if t.pos == 0 {
|
||||
return 0
|
||||
}
|
||||
|
||||
pos := t.pos - 1
|
||||
for pos > 0 {
|
||||
if t.line[pos] != ' ' {
|
||||
break
|
||||
}
|
||||
pos--
|
||||
}
|
||||
for pos > 0 {
|
||||
if t.line[pos] == ' ' {
|
||||
pos++
|
||||
break
|
||||
}
|
||||
pos--
|
||||
}
|
||||
|
||||
return t.pos - pos
|
||||
}
|
||||
|
||||
// countToRightWord returns then number of characters from the cursor to the
|
||||
// start of the next word.
|
||||
func (t *Terminal) countToRightWord() int {
|
||||
pos := t.pos
|
||||
for pos < len(t.line) {
|
||||
if t.line[pos] == ' ' {
|
||||
break
|
||||
}
|
||||
pos++
|
||||
}
|
||||
for pos < len(t.line) {
|
||||
if t.line[pos] != ' ' {
|
||||
break
|
||||
}
|
||||
pos++
|
||||
}
|
||||
return pos - t.pos
|
||||
}
|
||||
|
||||
// handleKey processes the given key and, optionally, returns a line of text
|
||||
// that the user has entered.
|
||||
func (t *Terminal) handleKey(key rune) (line string, ok bool) {
|
||||
switch key {
|
||||
case keyBackspace:
|
||||
if t.pos == 0 {
|
||||
return
|
||||
}
|
||||
t.eraseNPreviousChars(1)
|
||||
case keyAltLeft:
|
||||
// move left by a word.
|
||||
t.pos -= t.countToLeftWord()
|
||||
t.moveCursorToPos(t.pos)
|
||||
case keyAltRight:
|
||||
// move right by a word.
|
||||
t.pos += t.countToRightWord()
|
||||
t.moveCursorToPos(t.pos)
|
||||
case keyLeft:
|
||||
if t.pos == 0 {
|
||||
return
|
||||
}
|
||||
t.pos--
|
||||
t.moveCursorToPos(t.pos)
|
||||
case keyRight:
|
||||
if t.pos == len(t.line) {
|
||||
return
|
||||
}
|
||||
t.pos++
|
||||
t.moveCursorToPos(t.pos)
|
||||
case keyHome:
|
||||
if t.pos == 0 {
|
||||
return
|
||||
}
|
||||
t.pos = 0
|
||||
t.moveCursorToPos(t.pos)
|
||||
case keyEnd:
|
||||
if t.pos == len(t.line) {
|
||||
return
|
||||
}
|
||||
t.pos = len(t.line)
|
||||
t.moveCursorToPos(t.pos)
|
||||
case keyUp:
|
||||
entry, ok := t.history.NthPreviousEntry(t.historyIndex + 1)
|
||||
if !ok {
|
||||
return "", false
|
||||
}
|
||||
if t.historyIndex == -1 {
|
||||
t.historyPending = string(t.line)
|
||||
}
|
||||
t.historyIndex++
|
||||
runes := []rune(entry)
|
||||
t.setLine(runes, len(runes))
|
||||
case keyDown:
|
||||
switch t.historyIndex {
|
||||
case -1:
|
||||
return
|
||||
case 0:
|
||||
runes := []rune(t.historyPending)
|
||||
t.setLine(runes, len(runes))
|
||||
t.historyIndex--
|
||||
default:
|
||||
entry, ok := t.history.NthPreviousEntry(t.historyIndex - 1)
|
||||
if ok {
|
||||
t.historyIndex--
|
||||
runes := []rune(entry)
|
||||
t.setLine(runes, len(runes))
|
||||
}
|
||||
}
|
||||
case keyEnter:
|
||||
t.moveCursorToPos(len(t.line))
|
||||
t.queue([]rune("\r\n"))
|
||||
line = string(t.line)
|
||||
ok = true
|
||||
t.line = t.line[:0]
|
||||
t.pos = 0
|
||||
t.cursorX = 0
|
||||
t.cursorY = 0
|
||||
t.maxLine = 0
|
||||
case keyDeleteWord:
|
||||
// Delete zero or more spaces and then one or more characters.
|
||||
t.eraseNPreviousChars(t.countToLeftWord())
|
||||
case keyDeleteLine:
|
||||
// Delete everything from the current cursor position to the
|
||||
// end of line.
|
||||
for i := t.pos; i < len(t.line); i++ {
|
||||
t.queue(space)
|
||||
t.cursorX++
|
||||
}
|
||||
t.line = t.line[:t.pos]
|
||||
t.moveCursorToPos(t.pos)
|
||||
default:
|
||||
if t.AutoCompleteCallback != nil {
|
||||
prefix := string(t.line[:t.pos])
|
||||
suffix := string(t.line[t.pos:])
|
||||
|
||||
t.lock.Unlock()
|
||||
newLine, newPos, completeOk := t.AutoCompleteCallback(prefix+suffix, len(prefix), key)
|
||||
t.lock.Lock()
|
||||
|
||||
if completeOk {
|
||||
t.setLine([]rune(newLine), utf8.RuneCount([]byte(newLine)[:newPos]))
|
||||
return
|
||||
}
|
||||
}
|
||||
if !isPrintable(key) {
|
||||
return
|
||||
}
|
||||
if len(t.line) == maxLineLength {
|
||||
return
|
||||
}
|
||||
if len(t.line) == cap(t.line) {
|
||||
newLine := make([]rune, len(t.line), 2*(1+len(t.line)))
|
||||
copy(newLine, t.line)
|
||||
t.line = newLine
|
||||
}
|
||||
t.line = t.line[:len(t.line)+1]
|
||||
copy(t.line[t.pos+1:], t.line[t.pos:])
|
||||
t.line[t.pos] = key
|
||||
if t.echo {
|
||||
t.writeLine(t.line[t.pos:])
|
||||
}
|
||||
t.pos++
|
||||
t.moveCursorToPos(t.pos)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (t *Terminal) writeLine(line []rune) {
|
||||
for len(line) != 0 {
|
||||
remainingOnLine := t.termWidth - t.cursorX
|
||||
todo := len(line)
|
||||
if todo > remainingOnLine {
|
||||
todo = remainingOnLine
|
||||
}
|
||||
t.queue(line[:todo])
|
||||
t.cursorX += todo
|
||||
line = line[todo:]
|
||||
|
||||
if t.cursorX == t.termWidth {
|
||||
t.cursorX = 0
|
||||
t.cursorY++
|
||||
if t.cursorY > t.maxLine {
|
||||
t.maxLine = t.cursorY
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (t *Terminal) Write(buf []byte) (n int, err error) {
|
||||
t.lock.Lock()
|
||||
defer t.lock.Unlock()
|
||||
|
||||
if t.cursorX == 0 && t.cursorY == 0 {
|
||||
// This is the easy case: there's nothing on the screen that we
|
||||
// have to move out of the way.
|
||||
return t.c.Write(buf)
|
||||
}
|
||||
|
||||
// We have a prompt and possibly user input on the screen. We
|
||||
// have to clear it first.
|
||||
t.move(0 /* up */, 0 /* down */, t.cursorX /* left */, 0 /* right */)
|
||||
t.cursorX = 0
|
||||
t.clearLineToRight()
|
||||
|
||||
for t.cursorY > 0 {
|
||||
t.move(1 /* up */, 0, 0, 0)
|
||||
t.cursorY--
|
||||
t.clearLineToRight()
|
||||
}
|
||||
|
||||
if _, err = t.c.Write(t.outBuf); err != nil {
|
||||
return
|
||||
}
|
||||
t.outBuf = t.outBuf[:0]
|
||||
|
||||
if n, err = t.c.Write(buf); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
t.queue([]rune(t.prompt))
|
||||
chars := len(t.prompt)
|
||||
if t.echo {
|
||||
t.queue(t.line)
|
||||
chars += len(t.line)
|
||||
}
|
||||
t.cursorX = chars % t.termWidth
|
||||
t.cursorY = chars / t.termWidth
|
||||
t.moveCursorToPos(t.pos)
|
||||
|
||||
if _, err = t.c.Write(t.outBuf); err != nil {
|
||||
return
|
||||
}
|
||||
t.outBuf = t.outBuf[:0]
|
||||
return
|
||||
}
|
||||
|
||||
// ReadPassword temporarily changes the prompt and reads a password, without
|
||||
// echo, from the terminal.
|
||||
func (t *Terminal) ReadPassword(prompt string) (line string, err error) {
|
||||
t.lock.Lock()
|
||||
defer t.lock.Unlock()
|
||||
|
||||
oldPrompt := t.prompt
|
||||
t.prompt = prompt
|
||||
t.echo = false
|
||||
|
||||
line, err = t.readLine()
|
||||
|
||||
t.prompt = oldPrompt
|
||||
t.echo = true
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// ReadLine returns a line of input from the terminal.
|
||||
func (t *Terminal) ReadLine() (line string, err error) {
|
||||
t.lock.Lock()
|
||||
defer t.lock.Unlock()
|
||||
|
||||
return t.readLine()
|
||||
}
|
||||
|
||||
func (t *Terminal) readLine() (line string, err error) {
|
||||
// t.lock must be held at this point
|
||||
|
||||
if t.cursorX == 0 && t.cursorY == 0 {
|
||||
t.writeLine([]rune(t.prompt))
|
||||
t.c.Write(t.outBuf)
|
||||
t.outBuf = t.outBuf[:0]
|
||||
}
|
||||
|
||||
for {
|
||||
rest := t.remainder
|
||||
lineOk := false
|
||||
for !lineOk {
|
||||
var key rune
|
||||
key, rest = bytesToKey(rest)
|
||||
if key == utf8.RuneError {
|
||||
break
|
||||
}
|
||||
if key == keyCtrlD {
|
||||
return "", io.EOF
|
||||
}
|
||||
line, lineOk = t.handleKey(key)
|
||||
}
|
||||
if len(rest) > 0 {
|
||||
n := copy(t.inBuf[:], rest)
|
||||
t.remainder = t.inBuf[:n]
|
||||
} else {
|
||||
t.remainder = nil
|
||||
}
|
||||
t.c.Write(t.outBuf)
|
||||
t.outBuf = t.outBuf[:0]
|
||||
if lineOk {
|
||||
if t.echo {
|
||||
t.historyIndex = -1
|
||||
t.history.Add(line)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// t.remainder is a slice at the beginning of t.inBuf
|
||||
// containing a partial key sequence
|
||||
readBuf := t.inBuf[len(t.remainder):]
|
||||
var n int
|
||||
|
||||
t.lock.Unlock()
|
||||
n, err = t.c.Read(readBuf)
|
||||
t.lock.Lock()
|
||||
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
t.remainder = t.inBuf[:n+len(t.remainder)]
|
||||
}
|
||||
|
||||
panic("unreachable") // for Go 1.0.
|
||||
}
|
||||
|
||||
// SetPrompt sets the prompt to be used when reading subsequent lines.
|
||||
func (t *Terminal) SetPrompt(prompt string) {
|
||||
t.lock.Lock()
|
||||
defer t.lock.Unlock()
|
||||
|
||||
t.prompt = prompt
|
||||
}
|
||||
|
||||
func (t *Terminal) SetSize(width, height int) {
|
||||
t.lock.Lock()
|
||||
defer t.lock.Unlock()
|
||||
|
||||
t.termWidth, t.termHeight = width, height
|
||||
}
|
||||
|
||||
// stRingBuffer is a ring buffer of strings.
|
||||
type stRingBuffer struct {
|
||||
// entries contains max elements.
|
||||
entries []string
|
||||
max int
|
||||
// head contains the index of the element most recently added to the ring.
|
||||
head int
|
||||
// size contains the number of elements in the ring.
|
||||
size int
|
||||
}
|
||||
|
||||
func (s *stRingBuffer) Add(a string) {
|
||||
if s.entries == nil {
|
||||
const defaultNumEntries = 100
|
||||
s.entries = make([]string, defaultNumEntries)
|
||||
s.max = defaultNumEntries
|
||||
}
|
||||
|
||||
s.head = (s.head + 1) % s.max
|
||||
s.entries[s.head] = a
|
||||
if s.size < s.max {
|
||||
s.size++
|
||||
}
|
||||
}
|
||||
|
||||
// NthPreviousEntry returns the value passed to the nth previous call to Add.
|
||||
// If n is zero then the immediately prior value is returned, if one, then the
|
||||
// next most recent, and so on. If such an element doesn't exist then ok is
|
||||
// false.
|
||||
func (s *stRingBuffer) NthPreviousEntry(n int) (value string, ok bool) {
|
||||
if n >= s.size {
|
||||
return "", false
|
||||
}
|
||||
index := s.head - n
|
||||
if index < 0 {
|
||||
index += s.max
|
||||
}
|
||||
return s.entries[index], true
|
||||
}
|
209
vendor/code.google.com/p/go.crypto/ssh/terminal/terminal_test.go
generated
vendored
209
vendor/code.google.com/p/go.crypto/ssh/terminal/terminal_test.go
generated
vendored
|
@ -1,209 +0,0 @@
|
|||
// Copyright 2011 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package terminal
|
||||
|
||||
import (
|
||||
"io"
|
||||
"testing"
|
||||
)
|
||||
|
||||
type MockTerminal struct {
|
||||
toSend []byte
|
||||
bytesPerRead int
|
||||
received []byte
|
||||
}
|
||||
|
||||
func (c *MockTerminal) Read(data []byte) (n int, err error) {
|
||||
n = len(data)
|
||||
if n == 0 {
|
||||
return
|
||||
}
|
||||
if n > len(c.toSend) {
|
||||
n = len(c.toSend)
|
||||
}
|
||||
if n == 0 {
|
||||
return 0, io.EOF
|
||||
}
|
||||
if c.bytesPerRead > 0 && n > c.bytesPerRead {
|
||||
n = c.bytesPerRead
|
||||
}
|
||||
copy(data, c.toSend[:n])
|
||||
c.toSend = c.toSend[n:]
|
||||
return
|
||||
}
|
||||
|
||||
func (c *MockTerminal) Write(data []byte) (n int, err error) {
|
||||
c.received = append(c.received, data...)
|
||||
return len(data), nil
|
||||
}
|
||||
|
||||
func TestClose(t *testing.T) {
|
||||
c := &MockTerminal{}
|
||||
ss := NewTerminal(c, "> ")
|
||||
line, err := ss.ReadLine()
|
||||
if line != "" {
|
||||
t.Errorf("Expected empty line but got: %s", line)
|
||||
}
|
||||
if err != io.EOF {
|
||||
t.Errorf("Error should have been EOF but got: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
var keyPressTests = []struct {
|
||||
in string
|
||||
line string
|
||||
err error
|
||||
throwAwayLines int
|
||||
}{
|
||||
{
|
||||
err: io.EOF,
|
||||
},
|
||||
{
|
||||
in: "\r",
|
||||
line: "",
|
||||
},
|
||||
{
|
||||
in: "foo\r",
|
||||
line: "foo",
|
||||
},
|
||||
{
|
||||
in: "a\x1b[Cb\r", // right
|
||||
line: "ab",
|
||||
},
|
||||
{
|
||||
in: "a\x1b[Db\r", // left
|
||||
line: "ba",
|
||||
},
|
||||
{
|
||||
in: "a\177b\r", // backspace
|
||||
line: "b",
|
||||
},
|
||||
{
|
||||
in: "\x1b[A\r", // up
|
||||
},
|
||||
{
|
||||
in: "\x1b[B\r", // down
|
||||
},
|
||||
{
|
||||
in: "line\x1b[A\x1b[B\r", // up then down
|
||||
line: "line",
|
||||
},
|
||||
{
|
||||
in: "line1\rline2\x1b[A\r", // recall previous line.
|
||||
line: "line1",
|
||||
throwAwayLines: 1,
|
||||
},
|
||||
{
|
||||
// recall two previous lines and append.
|
||||
in: "line1\rline2\rline3\x1b[A\x1b[Axxx\r",
|
||||
line: "line1xxx",
|
||||
throwAwayLines: 2,
|
||||
},
|
||||
{
|
||||
// Ctrl-A to move to beginning of line followed by ^K to kill
|
||||
// line.
|
||||
in: "a b \001\013\r",
|
||||
line: "",
|
||||
},
|
||||
{
|
||||
// Ctrl-A to move to beginning of line, Ctrl-E to move to end,
|
||||
// finally ^K to kill nothing.
|
||||
in: "a b \001\005\013\r",
|
||||
line: "a b ",
|
||||
},
|
||||
{
|
||||
in: "\027\r",
|
||||
line: "",
|
||||
},
|
||||
{
|
||||
in: "a\027\r",
|
||||
line: "",
|
||||
},
|
||||
{
|
||||
in: "a \027\r",
|
||||
line: "",
|
||||
},
|
||||
{
|
||||
in: "a b\027\r",
|
||||
line: "a ",
|
||||
},
|
||||
{
|
||||
in: "a b \027\r",
|
||||
line: "a ",
|
||||
},
|
||||
{
|
||||
in: "one two thr\x1b[D\027\r",
|
||||
line: "one two r",
|
||||
},
|
||||
{
|
||||
in: "\013\r",
|
||||
line: "",
|
||||
},
|
||||
{
|
||||
in: "a\013\r",
|
||||
line: "a",
|
||||
},
|
||||
{
|
||||
in: "ab\x1b[D\013\r",
|
||||
line: "a",
|
||||
},
|
||||
{
|
||||
in: "Ξεσκεπάζω\r",
|
||||
line: "Ξεσκεπάζω",
|
||||
},
|
||||
{
|
||||
in: "£\r\x1b[A\177\r", // non-ASCII char, enter, up, backspace.
|
||||
line: "",
|
||||
throwAwayLines: 1,
|
||||
},
|
||||
{
|
||||
in: "£\r££\x1b[A\x1b[B\177\r", // non-ASCII char, enter, 2x non-ASCII, up, down, backspace, enter.
|
||||
line: "£",
|
||||
throwAwayLines: 1,
|
||||
},
|
||||
}
|
||||
|
||||
func TestKeyPresses(t *testing.T) {
|
||||
for i, test := range keyPressTests {
|
||||
for j := 1; j < len(test.in); j++ {
|
||||
c := &MockTerminal{
|
||||
toSend: []byte(test.in),
|
||||
bytesPerRead: j,
|
||||
}
|
||||
ss := NewTerminal(c, "> ")
|
||||
for k := 0; k < test.throwAwayLines; k++ {
|
||||
_, err := ss.ReadLine()
|
||||
if err != nil {
|
||||
t.Errorf("Throwaway line %d from test %d resulted in error: %s", k, i, err)
|
||||
}
|
||||
}
|
||||
line, err := ss.ReadLine()
|
||||
if line != test.line {
|
||||
t.Errorf("Line resulting from test %d (%d bytes per read) was '%s', expected '%s'", i, j, line, test.line)
|
||||
break
|
||||
}
|
||||
if err != test.err {
|
||||
t.Errorf("Error resulting from test %d (%d bytes per read) was '%v', expected '%v'", i, j, err, test.err)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestPasswordNotSaved(t *testing.T) {
|
||||
c := &MockTerminal{
|
||||
toSend: []byte("password\r\x1b[A\r"),
|
||||
bytesPerRead: 1,
|
||||
}
|
||||
ss := NewTerminal(c, "> ")
|
||||
pw, _ := ss.ReadPassword("> ")
|
||||
if pw != "password" {
|
||||
t.Fatalf("failed to read password, got %s", pw)
|
||||
}
|
||||
line, _ := ss.ReadLine()
|
||||
if len(line) > 0 {
|
||||
t.Fatalf("password was saved in history")
|
||||
}
|
||||
}
|
128
vendor/code.google.com/p/go.crypto/ssh/terminal/util.go
generated
vendored
128
vendor/code.google.com/p/go.crypto/ssh/terminal/util.go
generated
vendored
|
@ -1,128 +0,0 @@
|
|||
// Copyright 2011 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build linux,!appengine darwin
|
||||
|
||||
// Package terminal provides support functions for dealing with terminals, as
|
||||
// commonly found on UNIX systems.
|
||||
//
|
||||
// Putting a terminal into raw mode is the most common requirement:
|
||||
//
|
||||
// oldState, err := terminal.MakeRaw(0)
|
||||
// if err != nil {
|
||||
// panic(err)
|
||||
// }
|
||||
// defer terminal.Restore(0, oldState)
|
||||
package terminal
|
||||
|
||||
import (
|
||||
"io"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// State contains the state of a terminal.
|
||||
type State struct {
|
||||
termios syscall.Termios
|
||||
}
|
||||
|
||||
// IsTerminal returns true if the given file descriptor is a terminal.
|
||||
func IsTerminal(fd int) bool {
|
||||
var termios syscall.Termios
|
||||
_, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlReadTermios, uintptr(unsafe.Pointer(&termios)), 0, 0, 0)
|
||||
return err == 0
|
||||
}
|
||||
|
||||
// MakeRaw put 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.
|
||||
func MakeRaw(fd int) (*State, error) {
|
||||
var oldState State
|
||||
if _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlReadTermios, uintptr(unsafe.Pointer(&oldState.termios)), 0, 0, 0); err != 0 {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
newState := oldState.termios
|
||||
newState.Iflag &^= syscall.ISTRIP | syscall.INLCR | syscall.ICRNL | syscall.IGNCR | syscall.IXON | syscall.IXOFF
|
||||
newState.Lflag &^= syscall.ECHO | syscall.ICANON | syscall.ISIG
|
||||
if _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlWriteTermios, uintptr(unsafe.Pointer(&newState)), 0, 0, 0); err != 0 {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &oldState, nil
|
||||
}
|
||||
|
||||
// GetState returns the current state of a terminal which may be useful to
|
||||
// restore the terminal after a signal.
|
||||
func GetState(fd int) (*State, error) {
|
||||
var oldState State
|
||||
if _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlReadTermios, uintptr(unsafe.Pointer(&oldState.termios)), 0, 0, 0); err != 0 {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &oldState, nil
|
||||
}
|
||||
|
||||
// Restore restores the terminal connected to the given file descriptor to a
|
||||
// previous state.
|
||||
func Restore(fd int, state *State) error {
|
||||
_, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlWriteTermios, uintptr(unsafe.Pointer(&state.termios)), 0, 0, 0)
|
||||
return err
|
||||
}
|
||||
|
||||
// GetSize returns the dimensions of the given terminal.
|
||||
func GetSize(fd int) (width, height int, err error) {
|
||||
var dimensions [4]uint16
|
||||
|
||||
if _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), uintptr(syscall.TIOCGWINSZ), uintptr(unsafe.Pointer(&dimensions)), 0, 0, 0); err != 0 {
|
||||
return -1, -1, err
|
||||
}
|
||||
return int(dimensions[1]), int(dimensions[0]), nil
|
||||
}
|
||||
|
||||
// ReadPassword reads a line of input from a terminal without local echo. This
|
||||
// is commonly used for inputting passwords and other sensitive data. The slice
|
||||
// returned does not include the \n.
|
||||
func ReadPassword(fd int) ([]byte, error) {
|
||||
var oldState syscall.Termios
|
||||
if _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlReadTermios, uintptr(unsafe.Pointer(&oldState)), 0, 0, 0); err != 0 {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
newState := oldState
|
||||
newState.Lflag &^= syscall.ECHO
|
||||
newState.Lflag |= syscall.ICANON | syscall.ISIG
|
||||
newState.Iflag |= syscall.ICRNL
|
||||
if _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlWriteTermios, uintptr(unsafe.Pointer(&newState)), 0, 0, 0); err != 0 {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
defer func() {
|
||||
syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlWriteTermios, uintptr(unsafe.Pointer(&oldState)), 0, 0, 0)
|
||||
}()
|
||||
|
||||
var buf [16]byte
|
||||
var ret []byte
|
||||
for {
|
||||
n, err := syscall.Read(fd, buf[:])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if n == 0 {
|
||||
if len(ret) == 0 {
|
||||
return nil, io.EOF
|
||||
}
|
||||
break
|
||||
}
|
||||
if buf[n-1] == '\n' {
|
||||
n--
|
||||
}
|
||||
ret = append(ret, buf[:n]...)
|
||||
if n < len(buf) {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return ret, nil
|
||||
}
|
12
vendor/code.google.com/p/go.crypto/ssh/terminal/util_bsd.go
generated
vendored
12
vendor/code.google.com/p/go.crypto/ssh/terminal/util_bsd.go
generated
vendored
|
@ -1,12 +0,0 @@
|
|||
// Copyright 2013 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build darwin
|
||||
|
||||
package terminal
|
||||
|
||||
import "syscall"
|
||||
|
||||
const ioctlReadTermios = syscall.TIOCGETA
|
||||
const ioctlWriteTermios = syscall.TIOCSETA
|
12
vendor/code.google.com/p/go.crypto/ssh/terminal/util_linux.go
generated
vendored
12
vendor/code.google.com/p/go.crypto/ssh/terminal/util_linux.go
generated
vendored
|
@ -1,12 +0,0 @@
|
|||
// Copyright 2013 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build linux
|
||||
|
||||
package terminal
|
||||
|
||||
import "syscall"
|
||||
|
||||
const ioctlReadTermios = syscall.TCGETS
|
||||
const ioctlWriteTermios = syscall.TCSETS
|
7
vendor/code.google.com/p/go.crypto/ssh/test/doc.go
generated
vendored
7
vendor/code.google.com/p/go.crypto/ssh/test/doc.go
generated
vendored
|
@ -1,7 +0,0 @@
|
|||
// Copyright 2012 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// This package contains integration tests for the
|
||||
// code.google.com/p/go.crypto/ssh package.
|
||||
package test
|
160
vendor/code.google.com/p/go.crypto/ssh/test/forward_unix_test.go
generated
vendored
160
vendor/code.google.com/p/go.crypto/ssh/test/forward_unix_test.go
generated
vendored
|
@ -1,160 +0,0 @@
|
|||
// Copyright 2012 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build darwin freebsd linux netbsd openbsd plan9
|
||||
|
||||
package test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"math/rand"
|
||||
"net"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestPortForward(t *testing.T) {
|
||||
server := newServer(t)
|
||||
defer server.Shutdown()
|
||||
conn := server.Dial(clientConfig())
|
||||
defer conn.Close()
|
||||
|
||||
sshListener, err := conn.Listen("tcp", "localhost:0")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
go func() {
|
||||
sshConn, err := sshListener.Accept()
|
||||
if err != nil {
|
||||
t.Fatalf("listen.Accept failed: %v", err)
|
||||
}
|
||||
|
||||
_, err = io.Copy(sshConn, sshConn)
|
||||
if err != nil && err != io.EOF {
|
||||
t.Fatalf("ssh client copy: %v", err)
|
||||
}
|
||||
sshConn.Close()
|
||||
}()
|
||||
|
||||
forwardedAddr := sshListener.Addr().String()
|
||||
tcpConn, err := net.Dial("tcp", forwardedAddr)
|
||||
if err != nil {
|
||||
t.Fatalf("TCP dial failed: %v", err)
|
||||
}
|
||||
|
||||
readChan := make(chan []byte)
|
||||
go func() {
|
||||
data, _ := ioutil.ReadAll(tcpConn)
|
||||
readChan <- data
|
||||
}()
|
||||
|
||||
// Invent some data.
|
||||
data := make([]byte, 100*1000)
|
||||
for i := range data {
|
||||
data[i] = byte(i % 255)
|
||||
}
|
||||
|
||||
var sent []byte
|
||||
for len(sent) < 1000*1000 {
|
||||
// Send random sized chunks
|
||||
m := rand.Intn(len(data))
|
||||
n, err := tcpConn.Write(data[:m])
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
sent = append(sent, data[:n]...)
|
||||
}
|
||||
if err := tcpConn.(*net.TCPConn).CloseWrite(); err != nil {
|
||||
t.Errorf("tcpConn.CloseWrite: %v", err)
|
||||
}
|
||||
|
||||
read := <-readChan
|
||||
|
||||
if len(sent) != len(read) {
|
||||
t.Fatalf("got %d bytes, want %d", len(read), len(sent))
|
||||
}
|
||||
if bytes.Compare(sent, read) != 0 {
|
||||
t.Fatalf("read back data does not match")
|
||||
}
|
||||
|
||||
if err := sshListener.Close(); err != nil {
|
||||
t.Fatalf("sshListener.Close: %v", err)
|
||||
}
|
||||
|
||||
// Check that the forward disappeared.
|
||||
tcpConn, err = net.Dial("tcp", forwardedAddr)
|
||||
if err == nil {
|
||||
tcpConn.Close()
|
||||
t.Errorf("still listening to %s after closing", forwardedAddr)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAcceptClose(t *testing.T) {
|
||||
server := newServer(t)
|
||||
defer server.Shutdown()
|
||||
conn := server.Dial(clientConfig())
|
||||
|
||||
sshListener, err := conn.Listen("tcp", "localhost:0")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
quit := make(chan error, 1)
|
||||
go func() {
|
||||
for {
|
||||
c, err := sshListener.Accept()
|
||||
if err != nil {
|
||||
quit <- err
|
||||
break
|
||||
}
|
||||
c.Close()
|
||||
}
|
||||
}()
|
||||
sshListener.Close()
|
||||
|
||||
select {
|
||||
case <-time.After(1 * time.Second):
|
||||
t.Errorf("timeout: listener did not close.")
|
||||
case err := <-quit:
|
||||
t.Logf("quit as expected (error %v)", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Check that listeners exit if the underlying client transport dies.
|
||||
func TestPortForwardConnectionClose(t *testing.T) {
|
||||
server := newServer(t)
|
||||
defer server.Shutdown()
|
||||
conn := server.Dial(clientConfig())
|
||||
|
||||
sshListener, err := conn.Listen("tcp", "localhost:0")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
quit := make(chan error, 1)
|
||||
go func() {
|
||||
for {
|
||||
c, err := sshListener.Accept()
|
||||
if err != nil {
|
||||
quit <- err
|
||||
break
|
||||
}
|
||||
c.Close()
|
||||
}
|
||||
}()
|
||||
|
||||
// It would be even nicer if we closed the server side, but it
|
||||
// is more involved as the fd for that side is dup()ed.
|
||||
server.clientConn.Close()
|
||||
|
||||
select {
|
||||
case <-time.After(1 * time.Second):
|
||||
t.Errorf("timeout: listener did not close.")
|
||||
case err := <-quit:
|
||||
t.Logf("quit as expected (error %v)", err)
|
||||
}
|
||||
}
|
246
vendor/code.google.com/p/go.crypto/ssh/test/keys_test.go
generated
vendored
246
vendor/code.google.com/p/go.crypto/ssh/test/keys_test.go
generated
vendored
|
@ -1,246 +0,0 @@
|
|||
package test
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"code.google.com/p/go.crypto/ssh"
|
||||
)
|
||||
|
||||
var (
|
||||
validKey = `AAAAB3NzaC1yc2EAAAADAQABAAABAQDEX/dPu4PmtvgK3La9zioCEDrJ` +
|
||||
`yUr6xEIK7Pr+rLgydcqWTU/kt7w7gKjOw4vvzgHfjKl09CWyvgb+y5dCiTk` +
|
||||
`9MxI+erGNhs3pwaoS+EavAbawB7iEqYyTep3YaJK+4RJ4OX7ZlXMAIMrTL+` +
|
||||
`UVrK89t56hCkFYaAgo3VY+z6rb/b3bDBYtE1Y2tS7C3au73aDgeb9psIrSV` +
|
||||
`86ucKBTl5X62FnYiyGd++xCnLB6uLximM5OKXfLzJQNS/QyZyk12g3D8y69` +
|
||||
`Xw1GzCSKX1u1+MQboyf0HJcG2ryUCLHdcDVppApyHx2OLq53hlkQ/yxdflD` +
|
||||
`qCqAE4j+doagSsIfC1T2T`
|
||||
|
||||
authWithOptions = []string{
|
||||
`# comments to ignore before any keys...`,
|
||||
``,
|
||||
`env="HOME=/home/root",no-port-forwarding ssh-rsa ` + validKey + ` user@host`,
|
||||
`# comments to ignore, along with a blank line`,
|
||||
``,
|
||||
`env="HOME=/home/root2" ssh-rsa ` + validKey + ` user2@host2`,
|
||||
``,
|
||||
`# more comments, plus a invalid entry`,
|
||||
`ssh-rsa data-that-will-not-parse user@host3`,
|
||||
}
|
||||
|
||||
authOptions = strings.Join(authWithOptions, "\n")
|
||||
authWithCRLF = strings.Join(authWithOptions, "\r\n")
|
||||
authInvalid = []byte(`ssh-rsa`)
|
||||
authWithQuotedCommaInEnv = []byte(`env="HOME=/home/root,dir",no-port-forwarding ssh-rsa ` + validKey + ` user@host`)
|
||||
authWithQuotedSpaceInEnv = []byte(`env="HOME=/home/root dir",no-port-forwarding ssh-rsa ` + validKey + ` user@host`)
|
||||
authWithQuotedQuoteInEnv = []byte(`env="HOME=/home/\"root dir",no-port-forwarding` + "\t" + `ssh-rsa` + "\t" + validKey + ` user@host`)
|
||||
|
||||
authWithDoubleQuotedQuote = []byte(`no-port-forwarding,env="HOME=/home/ \"root dir\"" ssh-rsa ` + validKey + "\t" + `user@host`)
|
||||
authWithInvalidSpace = []byte(`env="HOME=/home/root dir", no-port-forwarding ssh-rsa ` + validKey + ` user@host
|
||||
#more to follow but still no valid keys`)
|
||||
authWithMissingQuote = []byte(`env="HOME=/home/root,no-port-forwarding ssh-rsa ` + validKey + ` user@host
|
||||
env="HOME=/home/root",shared-control ssh-rsa ` + validKey + ` user@host`)
|
||||
|
||||
testClientPrivateKey = `-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEowIBAAKCAQEAxF/3T7uD5rb4Cty2vc4qAhA6yclK+sRCCuz6/qy4MnXKlk1P
|
||||
5Le8O4CozsOL784B34ypdPQlsr4G/suXQok5PTMSPnqxjYbN6cGqEvhGrwG2sAe4
|
||||
hKmMk3qd2GiSvuESeDl+2ZVzACDK0y/lFayvPbeeoQpBWGgIKN1WPs+q2/292wwW
|
||||
LRNWNrUuwt2ru92g4Hm/abCK0lfOrnCgU5eV+thZ2IshnfvsQpyweri8YpjOTil3
|
||||
y8yUDUv0MmcpNdoNw/MuvV8NRswkil9btfjEG6Mn9ByXBtq8lAix3XA1aaQKch8d
|
||||
ji6ud4ZZEP8sXX5Q6gqgBOI/naGoErCHwtU9kwIDAQABAoIBAFJRKAp0QEZmTHPB
|
||||
MZk+4r0asIoFpziXLFgIHu7C2DPOzK1Umzj1DCKlPB3wOqi7Ym2jOSWdcnAK2EPW
|
||||
dAGgJC5TSkKGjAcXixmB5RkumfKidUI0+lQh/puTurcMnvcEwglDkLkEvMBA/sSo
|
||||
Pw9m486rOgOnmNzGPyViItURmD2+0yDdLl/vOsO/L1p76GCd0q0J3LqnmsQmawi7
|
||||
Zwj2Stm6BIrggG5GsF204Iet5219TYLo4g1Qb2AlJ9C8P1FtAWhMwJalDxH9Os2/
|
||||
KCDjnaq5n3bXbIU+3QjskjeVXL/Fnbhjnh4zs1EA7eHzl9dCGbcZ2LOimo2PRo8q
|
||||
wVQmz4ECgYEA9dhiu74TxRVoaO5N2X+FsMzRO8gZdP3Z9IrV4jVN8WT4Vdp0snoF
|
||||
gkVkqqbQUNKUb5K6B3Js/qNKfcjLbCNq9fewTcT6WsHQdtPbX/QA6Pa2Z29wrlA2
|
||||
wrIYaAkmVaHny7wsOmgX01aOnuf2MlUnksK43sjZHdIo/m+sDKwwY1cCgYEAzHx4
|
||||
mwUDMdRF4qpDKJhthraBNejRextNQQYsHVnNaMwZ4aeQcH5l85Cgjm7VpGlbVyBQ
|
||||
h4zwFvllImp3D2U3mjVkV8Tm9ID98eWvw2YDzBnS3P3SysajD23Z+BXSG9GNv/8k
|
||||
oAm+bVlvnJy4haK2AcIMk1YFuDuAOmy73abk7iUCgYEAj4qVM1sq/eKfAM1LJRfg
|
||||
/jbIX+hYfMePD8pUUWygIra6jJ4tjtvSBZrwyPb3IImjY3W/KoP0AcVjxAeORohz
|
||||
dkP1a6L8LiuFxSuzpdW5BkyuebxGhXCOWKVVvMDC4jLTPVCUXlHSv3GFemCjjgXM
|
||||
QlNxT5rjsha4Gr8nLIsJAacCgYA4VA1Q/pd7sXKy1p37X8nD8yAyvnh+Be5I/C9I
|
||||
woUP2jFC9MqYAmmJJ4ziz2swiAkuPeuQ+2Tjnz2ZtmQnrIUdiJmkh8vrDGFnshKx
|
||||
q7deELsCPzVCwGcIiAUkDra7DQWUHu9y2lxHePyC0rUNst2aLF8UcvzOXC2danhx
|
||||
vViQtQKBgCmZ7YavE/GNWww8N3xHBJ6UPmUuhQlnAbgNCcdyz30MevBg/JbyUTs2
|
||||
slftTH15QusJ1UoITnnZuFJ40LqDvh8UhiK09ffM/IbUx839/m2vUOdFZB/WNn9g
|
||||
Cy0LzddU4KE8JZ/tlk68+hM5fjLLA0aqSunaql5CKfplwLu8x1hL
|
||||
-----END RSA PRIVATE KEY-----
|
||||
`
|
||||
keys = map[string]string{
|
||||
"ssh_host_dsa_key": `-----BEGIN DSA PRIVATE KEY-----
|
||||
MIIBugIBAAKBgQDe2SIKvZdBp+InawtSXH0NotiMPhm3udyu4hh/E+icMz264kDX
|
||||
v+sV7ddnSQGQWZ/eVU7Jtx29dCMD1VlFpEd7yGKzmdwJIeA+YquNWoqBRQEJsWWS
|
||||
7Fsfvv83dA/DTNIQfOY3+TIs6Mb9vagbgQMU3JUWEhbLE9LCEU6UwwRlpQIVAL4p
|
||||
JF83SwpE8Jx6KnDpR89npkl/AoGAAy00TdDnAXvStwrZiAFbjZi8xDmPa9WwpfhJ
|
||||
Rkno45TthDLrS+WmqY8/LTwlqZdOBtoBAynMJfKkUiZM21lWWpL1hRKYdwBlIBy5
|
||||
XdR2/6wcPSuZ0tCQhDBTstX0Q3P1j198KGKvzy7q9vILKQwtSRqLS1y4JJERafdO
|
||||
E+9CnGwCgYBz0WwBe2EZtGhGhBdnelTIBeo7PIsr0PzqxQj+dc8PBl8K9FfhRyOp
|
||||
U39stUvoUxE9vaIFrY1P5xENjLFnPf+hlcuf40GUWEssW9YWPOaBp8afa9hY5Sxs
|
||||
pvNR6eZFEFOJnx/ZgcA4g+vbrgGi5cM0W470mbGw2CkfJQUafdoIgAIUF+2I9kZe
|
||||
2FTBuC9uacqczDlc+0k=
|
||||
-----END DSA PRIVATE KEY-----`,
|
||||
"ssh_host_rsa_key": `-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEowIBAAKCAQEAuf76Ue2Wtae9oDtaS6rIJgO7iCFTsZUTW9LBsvx/2nli6jKU
|
||||
d9tUbBRzgdbnRLJ32UljXhERuB/axlrX8/lBzUZ+oYiM0KkEEOXY1z/bcMxdRxGF
|
||||
XHuf4uXvyC2XyA4+ZvBeS4j1QFyIHZ62o7gAlKMTjiek3B4AQEJAlCLmhH3jB8wc
|
||||
K/IYXAOlNGM5G44/ZLQpTi8diOV6DLs7tJ7rtEQedOEJfZng5rwp0USFkqcbfDbe
|
||||
9/hk0J32jZvOtZNBokYtBb4YEdIiWBzzNtHzU3Dzw61+TKVXaH5HaIvzL9iMrw9f
|
||||
kJbJyogfZk9BJfemEN+xqP72jlhE8LXNhpTxFQIDAQABAoIBAHbdf+Y5+5XuNF6h
|
||||
b8xpwW2h9whBnDYiOnP1VfroKWFbMB7R4lZS4joMO+FfkP8zOyqvHwTvza4pFWys
|
||||
g9SUmDvy8FyVYsC7MzEFYzX0xm3o/Te898ip7P1Zy4rXsGeWysSImwqU5X+TYx3i
|
||||
33/zyNM1APtZVJ+jwK9QZ+sD/uPuZK2yS03HGSMZq6ebdoOSaYhluKrxXllSLO1J
|
||||
KJxDiDdy2lEFw0W8HcI3ly1lg6OI+TRqqaCcLVNF4fNJmYIFM+2VEI9BdgynIh0Q
|
||||
pMZlJKgaEBcSqCymnTK81ohYD1cV4st2B0km3Sw35Rl04Ij5ITeiya3hp8VfE6UY
|
||||
PljkA6UCgYEA4811FTFj+kzNZ86C4OW1T5sM4NZt8gcz6CSvVnl+bDzbEOMMyzP7
|
||||
2I9zKsR5ApdodH2m8d+RUw1Oe0bNGW5xig/DH/hn9lLQaO52JAi0we8A94dUUMSq
|
||||
fUk9jKZEXpP/MlfTdJaPos9mxT7z8jREQxIiqH9AV0rLVDOCfDbSWj8CgYEA0QTE
|
||||
IAUuki3UUqYKzLQrh/QmhY5KTx5amNW9XZ2VGtJvDPJrtBSBZlPEuXZAc4eBWEc7
|
||||
U3Y9QwsalzupU6Yi6+gmofaXs8xJnj+jKth1DnJvrbLLGlSmf2Ijnwt22TyFUOtt
|
||||
UAknpjHutDjQPf7pUGWaCPgwwKFsdB8EBjpJF6sCgYAfXesBQAvEK08dPBJJZVfR
|
||||
3kenrd71tIgxLtv1zETcIoUHjjv0vvOunhH9kZAYC0EWyTZzl5UrGmn0D4uuNMbt
|
||||
e74iaNHn2P9Zc3xQ+eHp0j8P1lKFzI6tMaiH9Vz0qOw6wl0bcJ/WizhbcI+migvc
|
||||
MGMVUHBLlMDqly0gbWwJgQKBgQCgtb9ut01FjANSwORQ3L8Tu3/a9Lrh9n7GQKFn
|
||||
V4CLrP1BwStavOF5ojMCPo/zxF6JV8ufsqwL3n/FhFP/QyBarpb1tTqTPiHkkR2O
|
||||
Ffx67TY9IdnUFv4lt3mYEiKBiW0f+MSF42Qe/wmAfKZw5IzUCirTdrFVi0huSGK5
|
||||
vxrwHQKBgHZ7RoC3I2f6F5fflA2ZAe9oJYC7XT624rY7VeOBwK0W0F47iV3euPi/
|
||||
pKvLIBLcWL1Lboo+girnmSZtIYg2iLS3b4T9VFcKWg0y4AVwmhMWe9jWIltfWAAX
|
||||
9l0lNikMRGAx3eXudKXEtbGt3/cUzPVaQUHy5LiBxkxnFxgaJPXs
|
||||
-----END RSA PRIVATE KEY-----`,
|
||||
"ssh_host_ecdsa_key": `-----BEGIN EC PRIVATE KEY-----
|
||||
MHcCAQEEINGWx0zo6fhJ/0EAfrPzVFyFC9s18lBt3cRoEDhS3ARooAoGCCqGSM49
|
||||
AwEHoUQDQgAEi9Hdw6KvZcWxfg2IDhA7UkpDtzzt6ZqJXSsFdLd+Kx4S3Sx4cVO+
|
||||
6/ZOXRnPmNAlLUqjShUsUBBngG0u2fqEqA==
|
||||
-----END EC PRIVATE KEY-----`,
|
||||
"authorized_keys": `ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDEX/dPu4PmtvgK3La9zioCEDrJyUr6xEIK7Pr+rLgydcqWTU/kt7w7gKjOw4vvzgHfjKl09CWyvgb+y5dCiTk9MxI+erGNhs3pwaoS+EavAbawB7iEqYyTep3YaJK+4RJ4OX7ZlXMAIMrTL+UVrK89t56hCkFYaAgo3VY+z6rb/b3bDBYtE1Y2tS7C3au73aDgeb9psIrSV86ucKBTl5X62FnYiyGd++xCnLB6uLximM5OKXfLzJQNS/QyZyk12g3D8y69Xw1GzCSKX1u1+MQboyf0HJcG2ryUCLHdcDVppApyHx2OLq53hlkQ/yxdflDqCqAE4j+doagSsIfC1T2T user@host`,
|
||||
}
|
||||
)
|
||||
|
||||
func TestMarshalParsePublicKey(t *testing.T) {
|
||||
pub := getTestPublicKey(t)
|
||||
|
||||
authKeys := ssh.MarshalAuthorizedKey(pub)
|
||||
actualFields := strings.Fields(string(authKeys))
|
||||
if len(actualFields) == 0 {
|
||||
t.Fatalf("failed authKeys: %v", authKeys)
|
||||
}
|
||||
|
||||
// drop the comment
|
||||
expectedFields := strings.Fields(keys["authorized_keys"])[0:2]
|
||||
|
||||
if !reflect.DeepEqual(actualFields, expectedFields) {
|
||||
t.Errorf("got %v, expected %v", actualFields, expectedFields)
|
||||
}
|
||||
|
||||
actPub, _, _, _, ok := ssh.ParseAuthorizedKey([]byte(keys["authorized_keys"]))
|
||||
if !ok {
|
||||
t.Fatalf("cannot parse %v", keys["authorized_keys"])
|
||||
}
|
||||
if !reflect.DeepEqual(actPub, pub) {
|
||||
t.Errorf("got %v, expected %v", actPub, pub)
|
||||
}
|
||||
}
|
||||
|
||||
type authResult struct {
|
||||
pubKey interface{} //*rsa.PublicKey
|
||||
options []string
|
||||
comments string
|
||||
rest string
|
||||
ok bool
|
||||
}
|
||||
|
||||
func testAuthorizedKeys(t *testing.T, authKeys []byte, expected []authResult) {
|
||||
rest := authKeys
|
||||
var values []authResult
|
||||
for len(rest) > 0 {
|
||||
var r authResult
|
||||
r.pubKey, r.comments, r.options, rest, r.ok = ssh.ParseAuthorizedKey(rest)
|
||||
r.rest = string(rest)
|
||||
values = append(values, r)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(values, expected) {
|
||||
t.Errorf("got %q, expected %q", values, expected)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func getTestPublicKey(t *testing.T) ssh.PublicKey {
|
||||
priv, err := ssh.ParsePrivateKey([]byte(testClientPrivateKey))
|
||||
if err != nil {
|
||||
t.Fatalf("ParsePrivateKey: %v", err)
|
||||
}
|
||||
|
||||
return priv.PublicKey()
|
||||
}
|
||||
|
||||
func TestAuth(t *testing.T) {
|
||||
pub := getTestPublicKey(t)
|
||||
rest2 := strings.Join(authWithOptions[3:], "\n")
|
||||
rest3 := strings.Join(authWithOptions[6:], "\n")
|
||||
testAuthorizedKeys(t, []byte(authOptions), []authResult{
|
||||
{pub, []string{`env="HOME=/home/root"`, "no-port-forwarding"}, "user@host", rest2, true},
|
||||
{pub, []string{`env="HOME=/home/root2"`}, "user2@host2", rest3, true},
|
||||
{nil, nil, "", "", false},
|
||||
})
|
||||
}
|
||||
|
||||
func TestAuthWithCRLF(t *testing.T) {
|
||||
pub := getTestPublicKey(t)
|
||||
rest2 := strings.Join(authWithOptions[3:], "\r\n")
|
||||
rest3 := strings.Join(authWithOptions[6:], "\r\n")
|
||||
testAuthorizedKeys(t, []byte(authWithCRLF), []authResult{
|
||||
{pub, []string{`env="HOME=/home/root"`, "no-port-forwarding"}, "user@host", rest2, true},
|
||||
{pub, []string{`env="HOME=/home/root2"`}, "user2@host2", rest3, true},
|
||||
{nil, nil, "", "", false},
|
||||
})
|
||||
}
|
||||
|
||||
func TestAuthWithQuotedSpaceInEnv(t *testing.T) {
|
||||
pub := getTestPublicKey(t)
|
||||
testAuthorizedKeys(t, []byte(authWithQuotedSpaceInEnv), []authResult{
|
||||
{pub, []string{`env="HOME=/home/root dir"`, "no-port-forwarding"}, "user@host", "", true},
|
||||
})
|
||||
}
|
||||
|
||||
func TestAuthWithQuotedCommaInEnv(t *testing.T) {
|
||||
pub := getTestPublicKey(t)
|
||||
testAuthorizedKeys(t, []byte(authWithQuotedCommaInEnv), []authResult{
|
||||
{pub, []string{`env="HOME=/home/root,dir"`, "no-port-forwarding"}, "user@host", "", true},
|
||||
})
|
||||
}
|
||||
|
||||
func TestAuthWithQuotedQuoteInEnv(t *testing.T) {
|
||||
pub := getTestPublicKey(t)
|
||||
testAuthorizedKeys(t, []byte(authWithQuotedQuoteInEnv), []authResult{
|
||||
{pub, []string{`env="HOME=/home/\"root dir"`, "no-port-forwarding"}, "user@host", "", true},
|
||||
})
|
||||
|
||||
testAuthorizedKeys(t, []byte(authWithDoubleQuotedQuote), []authResult{
|
||||
{pub, []string{"no-port-forwarding", `env="HOME=/home/ \"root dir\""`}, "user@host", "", true},
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
func TestAuthWithInvalidSpace(t *testing.T) {
|
||||
testAuthorizedKeys(t, []byte(authWithInvalidSpace), []authResult{
|
||||
{nil, nil, "", "", false},
|
||||
})
|
||||
}
|
||||
|
||||
func TestAuthWithMissingQuote(t *testing.T) {
|
||||
pub := getTestPublicKey(t)
|
||||
testAuthorizedKeys(t, []byte(authWithMissingQuote), []authResult{
|
||||
{pub, []string{`env="HOME=/home/root"`, `shared-control`}, "user@host", "", true},
|
||||
})
|
||||
}
|
||||
|
||||
func TestInvalidEntry(t *testing.T) {
|
||||
_, _, _, _, ok := ssh.ParseAuthorizedKey(authInvalid)
|
||||
if ok {
|
||||
t.Errorf("Expected invalid entry, returned valid entry")
|
||||
}
|
||||
}
|
185
vendor/code.google.com/p/go.crypto/ssh/test/session_test.go
generated
vendored
185
vendor/code.google.com/p/go.crypto/ssh/test/session_test.go
generated
vendored
|
@ -1,185 +0,0 @@
|
|||
// Copyright 2012 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build !windows
|
||||
|
||||
package test
|
||||
|
||||
// Session functional tests.
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"code.google.com/p/go.crypto/ssh"
|
||||
"io"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestRunCommandSuccess(t *testing.T) {
|
||||
server := newServer(t)
|
||||
defer server.Shutdown()
|
||||
conn := server.Dial(clientConfig())
|
||||
defer conn.Close()
|
||||
|
||||
session, err := conn.NewSession()
|
||||
if err != nil {
|
||||
t.Fatalf("session failed: %v", err)
|
||||
}
|
||||
defer session.Close()
|
||||
err = session.Run("true")
|
||||
if err != nil {
|
||||
t.Fatalf("session failed: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestHostKeyCheck(t *testing.T) {
|
||||
server := newServer(t)
|
||||
defer server.Shutdown()
|
||||
|
||||
conf := clientConfig()
|
||||
k := conf.HostKeyChecker.(*storedHostKey)
|
||||
|
||||
// change the keys.
|
||||
k.keys[ssh.KeyAlgoRSA][25]++
|
||||
k.keys[ssh.KeyAlgoDSA][25]++
|
||||
k.keys[ssh.KeyAlgoECDSA256][25]++
|
||||
|
||||
conn, err := server.TryDial(conf)
|
||||
if err == nil {
|
||||
conn.Close()
|
||||
t.Fatalf("dial should have failed.")
|
||||
} else if !strings.Contains(err.Error(), "host key mismatch") {
|
||||
t.Fatalf("'host key mismatch' not found in %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRunCommandFailed(t *testing.T) {
|
||||
server := newServer(t)
|
||||
defer server.Shutdown()
|
||||
conn := server.Dial(clientConfig())
|
||||
defer conn.Close()
|
||||
|
||||
session, err := conn.NewSession()
|
||||
if err != nil {
|
||||
t.Fatalf("session failed: %v", err)
|
||||
}
|
||||
defer session.Close()
|
||||
err = session.Run(`bash -c "kill -9 $$"`)
|
||||
if err == nil {
|
||||
t.Fatalf("session succeeded: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRunCommandWeClosed(t *testing.T) {
|
||||
server := newServer(t)
|
||||
defer server.Shutdown()
|
||||
conn := server.Dial(clientConfig())
|
||||
defer conn.Close()
|
||||
|
||||
session, err := conn.NewSession()
|
||||
if err != nil {
|
||||
t.Fatalf("session failed: %v", err)
|
||||
}
|
||||
err = session.Shell()
|
||||
if err != nil {
|
||||
t.Fatalf("shell failed: %v", err)
|
||||
}
|
||||
err = session.Close()
|
||||
if err != nil {
|
||||
t.Fatalf("shell failed: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFuncLargeRead(t *testing.T) {
|
||||
server := newServer(t)
|
||||
defer server.Shutdown()
|
||||
conn := server.Dial(clientConfig())
|
||||
defer conn.Close()
|
||||
|
||||
session, err := conn.NewSession()
|
||||
if err != nil {
|
||||
t.Fatalf("unable to create new session: %s", err)
|
||||
}
|
||||
|
||||
stdout, err := session.StdoutPipe()
|
||||
if err != nil {
|
||||
t.Fatalf("unable to acquire stdout pipe: %s", err)
|
||||
}
|
||||
|
||||
err = session.Start("dd if=/dev/urandom bs=2048 count=1")
|
||||
if err != nil {
|
||||
t.Fatalf("unable to execute remote command: %s", err)
|
||||
}
|
||||
|
||||
buf := new(bytes.Buffer)
|
||||
n, err := io.Copy(buf, stdout)
|
||||
if err != nil {
|
||||
t.Fatalf("error reading from remote stdout: %s", err)
|
||||
}
|
||||
|
||||
if n != 2048 {
|
||||
t.Fatalf("Expected %d bytes but read only %d from remote command", 2048, n)
|
||||
}
|
||||
}
|
||||
|
||||
func TestInvalidTerminalMode(t *testing.T) {
|
||||
server := newServer(t)
|
||||
defer server.Shutdown()
|
||||
conn := server.Dial(clientConfig())
|
||||
defer conn.Close()
|
||||
|
||||
session, err := conn.NewSession()
|
||||
if err != nil {
|
||||
t.Fatalf("session failed: %v", err)
|
||||
}
|
||||
defer session.Close()
|
||||
|
||||
if err = session.RequestPty("vt100", 80, 40, ssh.TerminalModes{255: 1984}); err == nil {
|
||||
t.Fatalf("req-pty failed: successful request with invalid mode")
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidTerminalMode(t *testing.T) {
|
||||
server := newServer(t)
|
||||
defer server.Shutdown()
|
||||
conn := server.Dial(clientConfig())
|
||||
defer conn.Close()
|
||||
|
||||
session, err := conn.NewSession()
|
||||
if err != nil {
|
||||
t.Fatalf("session failed: %v", err)
|
||||
}
|
||||
defer session.Close()
|
||||
|
||||
stdout, err := session.StdoutPipe()
|
||||
if err != nil {
|
||||
t.Fatalf("unable to acquire stdout pipe: %s", err)
|
||||
}
|
||||
|
||||
stdin, err := session.StdinPipe()
|
||||
if err != nil {
|
||||
t.Fatalf("unable to acquire stdin pipe: %s", err)
|
||||
}
|
||||
|
||||
tm := ssh.TerminalModes{ssh.ECHO: 0}
|
||||
if err = session.RequestPty("xterm", 80, 40, tm); err != nil {
|
||||
t.Fatalf("req-pty failed: %s", err)
|
||||
}
|
||||
|
||||
err = session.Shell()
|
||||
if err != nil {
|
||||
t.Fatalf("session failed: %s", err)
|
||||
}
|
||||
|
||||
stdin.Write([]byte("stty -a && exit\n"))
|
||||
|
||||
var buf bytes.Buffer
|
||||
if _, err := io.Copy(&buf, stdout); err != nil {
|
||||
t.Fatalf("reading failed: %s", err)
|
||||
}
|
||||
|
||||
if sttyOutput := buf.String(); !strings.Contains(sttyOutput, "-echo ") {
|
||||
t.Fatalf("terminal mode failure: expected -echo in stty output, got %s", sttyOutput)
|
||||
}
|
||||
}
|
47
vendor/code.google.com/p/go.crypto/ssh/test/tcpip_test.go
generated
vendored
47
vendor/code.google.com/p/go.crypto/ssh/test/tcpip_test.go
generated
vendored
|
@ -1,47 +0,0 @@
|
|||
// Copyright 2012 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build !windows
|
||||
|
||||
package test
|
||||
|
||||
// direct-tcpip functional tests
|
||||
|
||||
import (
|
||||
"net"
|
||||
"net/http"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestTCPIPHTTP(t *testing.T) {
|
||||
// google.com will generate at least one redirect, possibly three
|
||||
// depending on your location.
|
||||
doTest(t, "http://google.com")
|
||||
}
|
||||
|
||||
func TestTCPIPHTTPS(t *testing.T) {
|
||||
doTest(t, "https://encrypted.google.com/")
|
||||
}
|
||||
|
||||
func doTest(t *testing.T, url string) {
|
||||
server := newServer(t)
|
||||
defer server.Shutdown()
|
||||
conn := server.Dial(clientConfig())
|
||||
defer conn.Close()
|
||||
|
||||
tr := &http.Transport{
|
||||
Dial: func(n, addr string) (net.Conn, error) {
|
||||
return conn.Dial(n, addr)
|
||||
},
|
||||
}
|
||||
client := &http.Client{
|
||||
Transport: tr,
|
||||
}
|
||||
resp, err := client.Get(url)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to proxy: %s", err)
|
||||
}
|
||||
// got a body without error
|
||||
t.Log(resp)
|
||||
}
|
296
vendor/code.google.com/p/go.crypto/ssh/test/test_unix_test.go
generated
vendored
296
vendor/code.google.com/p/go.crypto/ssh/test/test_unix_test.go
generated
vendored
|
@ -1,296 +0,0 @@
|
|||
// Copyright 2012 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build darwin freebsd linux netbsd openbsd plan9
|
||||
|
||||
package test
|
||||
|
||||
// functional test harness for unix.
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net"
|
||||
"os"
|
||||
"os/exec"
|
||||
"os/user"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
"text/template"
|
||||
|
||||
"code.google.com/p/go.crypto/ssh"
|
||||
)
|
||||
|
||||
const sshd_config = `
|
||||
Protocol 2
|
||||
HostKey {{.Dir}}/ssh_host_rsa_key
|
||||
HostKey {{.Dir}}/ssh_host_dsa_key
|
||||
HostKey {{.Dir}}/ssh_host_ecdsa_key
|
||||
Pidfile {{.Dir}}/sshd.pid
|
||||
#UsePrivilegeSeparation no
|
||||
KeyRegenerationInterval 3600
|
||||
ServerKeyBits 768
|
||||
SyslogFacility AUTH
|
||||
LogLevel DEBUG2
|
||||
LoginGraceTime 120
|
||||
PermitRootLogin no
|
||||
StrictModes no
|
||||
RSAAuthentication yes
|
||||
PubkeyAuthentication yes
|
||||
AuthorizedKeysFile {{.Dir}}/authorized_keys
|
||||
IgnoreRhosts yes
|
||||
RhostsRSAAuthentication no
|
||||
HostbasedAuthentication no
|
||||
`
|
||||
|
||||
var (
|
||||
configTmpl template.Template
|
||||
privateKey ssh.Signer
|
||||
hostKeyRSA ssh.Signer
|
||||
hostKeyECDSA ssh.Signer
|
||||
hostKeyDSA ssh.Signer
|
||||
)
|
||||
|
||||
func init() {
|
||||
template.Must(configTmpl.Parse(sshd_config))
|
||||
|
||||
for n, k := range map[string]*ssh.Signer{
|
||||
"ssh_host_ecdsa_key": &hostKeyECDSA,
|
||||
"ssh_host_rsa_key": &hostKeyRSA,
|
||||
"ssh_host_dsa_key": &hostKeyDSA,
|
||||
} {
|
||||
var err error
|
||||
*k, err = ssh.ParsePrivateKey([]byte(keys[n]))
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("ParsePrivateKey(%q): %v", n, err))
|
||||
}
|
||||
}
|
||||
|
||||
var err error
|
||||
privateKey, err = ssh.ParsePrivateKey([]byte(testClientPrivateKey))
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("ParsePrivateKey: %v", err))
|
||||
}
|
||||
}
|
||||
|
||||
type server struct {
|
||||
t *testing.T
|
||||
cleanup func() // executed during Shutdown
|
||||
configfile string
|
||||
cmd *exec.Cmd
|
||||
output bytes.Buffer // holds stderr from sshd process
|
||||
|
||||
// Client half of the network connection.
|
||||
clientConn net.Conn
|
||||
}
|
||||
|
||||
func username() string {
|
||||
var username string
|
||||
if user, err := user.Current(); err == nil {
|
||||
username = user.Username
|
||||
} else {
|
||||
// user.Current() currently requires cgo. If an error is
|
||||
// returned attempt to get the username from the environment.
|
||||
log.Printf("user.Current: %v; falling back on $USER", err)
|
||||
username = os.Getenv("USER")
|
||||
}
|
||||
if username == "" {
|
||||
panic("Unable to get username")
|
||||
}
|
||||
return username
|
||||
}
|
||||
|
||||
type storedHostKey struct {
|
||||
// keys map from an algorithm string to binary key data.
|
||||
keys map[string][]byte
|
||||
}
|
||||
|
||||
func (k *storedHostKey) Add(key ssh.PublicKey) {
|
||||
if k.keys == nil {
|
||||
k.keys = map[string][]byte{}
|
||||
}
|
||||
k.keys[key.PublicKeyAlgo()] = ssh.MarshalPublicKey(key)
|
||||
}
|
||||
|
||||
func (k *storedHostKey) Check(addr string, remote net.Addr, algo string, key []byte) error {
|
||||
if k.keys == nil || bytes.Compare(key, k.keys[algo]) != 0 {
|
||||
return fmt.Errorf("host key mismatch. Got %q, want %q", key, k.keys[algo])
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func clientConfig() *ssh.ClientConfig {
|
||||
keyChecker := storedHostKey{}
|
||||
keyChecker.Add(hostKeyECDSA.PublicKey())
|
||||
keyChecker.Add(hostKeyRSA.PublicKey())
|
||||
keyChecker.Add(hostKeyDSA.PublicKey())
|
||||
|
||||
kc := new(keychain)
|
||||
kc.keys = append(kc.keys, privateKey)
|
||||
config := &ssh.ClientConfig{
|
||||
User: username(),
|
||||
Auth: []ssh.ClientAuth{
|
||||
ssh.ClientAuthKeyring(kc),
|
||||
},
|
||||
HostKeyChecker: &keyChecker,
|
||||
}
|
||||
return config
|
||||
}
|
||||
|
||||
// unixConnection creates two halves of a connected net.UnixConn. It
|
||||
// is used for connecting the Go SSH client with sshd without opening
|
||||
// ports.
|
||||
func unixConnection() (*net.UnixConn, *net.UnixConn, error) {
|
||||
dir, err := ioutil.TempDir("", "unixConnection")
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
defer os.Remove(dir)
|
||||
|
||||
addr := filepath.Join(dir, "ssh")
|
||||
listener, err := net.Listen("unix", addr)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
defer listener.Close()
|
||||
c1, err := net.Dial("unix", addr)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
c2, err := listener.Accept()
|
||||
if err != nil {
|
||||
c1.Close()
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
return c1.(*net.UnixConn), c2.(*net.UnixConn), nil
|
||||
}
|
||||
|
||||
func (s *server) TryDial(config *ssh.ClientConfig) (*ssh.ClientConn, error) {
|
||||
sshd, err := exec.LookPath("sshd")
|
||||
if err != nil {
|
||||
s.t.Skipf("skipping test: %v", err)
|
||||
}
|
||||
|
||||
c1, c2, err := unixConnection()
|
||||
if err != nil {
|
||||
s.t.Fatalf("unixConnection: %v", err)
|
||||
}
|
||||
|
||||
s.cmd = exec.Command(sshd, "-f", s.configfile, "-i", "-e")
|
||||
f, err := c2.File()
|
||||
if err != nil {
|
||||
s.t.Fatalf("UnixConn.File: %v", err)
|
||||
}
|
||||
defer f.Close()
|
||||
s.cmd.Stdin = f
|
||||
s.cmd.Stdout = f
|
||||
s.cmd.Stderr = &s.output
|
||||
if err := s.cmd.Start(); err != nil {
|
||||
s.t.Fail()
|
||||
s.Shutdown()
|
||||
s.t.Fatalf("s.cmd.Start: %v", err)
|
||||
}
|
||||
s.clientConn = c1
|
||||
return ssh.Client(c1, config)
|
||||
}
|
||||
|
||||
func (s *server) Dial(config *ssh.ClientConfig) *ssh.ClientConn {
|
||||
conn, err := s.TryDial(config)
|
||||
if err != nil {
|
||||
s.t.Fail()
|
||||
s.Shutdown()
|
||||
s.t.Fatalf("ssh.Client: %v", err)
|
||||
}
|
||||
return conn
|
||||
}
|
||||
|
||||
func (s *server) Shutdown() {
|
||||
if s.cmd != nil && s.cmd.Process != nil {
|
||||
// Don't check for errors; if it fails it's most
|
||||
// likely "os: process already finished", and we don't
|
||||
// care about that. Use os.Interrupt, so child
|
||||
// processes are killed too.
|
||||
s.cmd.Process.Signal(os.Interrupt)
|
||||
s.cmd.Wait()
|
||||
}
|
||||
if s.t.Failed() {
|
||||
// log any output from sshd process
|
||||
s.t.Logf("sshd: %s", s.output.String())
|
||||
}
|
||||
s.cleanup()
|
||||
}
|
||||
|
||||
// newServer returns a new mock ssh server.
|
||||
func newServer(t *testing.T) *server {
|
||||
dir, err := ioutil.TempDir("", "sshtest")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
f, err := os.Create(filepath.Join(dir, "sshd_config"))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
err = configTmpl.Execute(f, map[string]string{
|
||||
"Dir": dir,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
f.Close()
|
||||
|
||||
for k, v := range keys {
|
||||
f, err := os.OpenFile(filepath.Join(dir, k), os.O_WRONLY|os.O_TRUNC|os.O_CREATE, 0600)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, err := f.Write([]byte(v)); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
f.Close()
|
||||
}
|
||||
|
||||
return &server{
|
||||
t: t,
|
||||
configfile: f.Name(),
|
||||
cleanup: func() {
|
||||
if err := os.RemoveAll(dir); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// keychain implements the ClientKeyring interface.
|
||||
type keychain struct {
|
||||
keys []ssh.Signer
|
||||
}
|
||||
|
||||
func (k *keychain) Key(i int) (ssh.PublicKey, error) {
|
||||
if i < 0 || i >= len(k.keys) {
|
||||
return nil, nil
|
||||
}
|
||||
return k.keys[i].PublicKey(), nil
|
||||
}
|
||||
|
||||
func (k *keychain) Sign(i int, rand io.Reader, data []byte) (sig []byte, err error) {
|
||||
return k.keys[i].Sign(rand, data)
|
||||
}
|
||||
|
||||
func (k *keychain) loadPEM(file string) error {
|
||||
buf, err := ioutil.ReadFile(file)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
key, err := ssh.ParsePrivateKey(buf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
k.keys = append(k.keys, key)
|
||||
return nil
|
||||
}
|
69
vendor/code.google.com/p/go.crypto/ssh/transport_test.go
generated
vendored
69
vendor/code.google.com/p/go.crypto/ssh/transport_test.go
generated
vendored
|
@ -1,69 +0,0 @@
|
|||
// Copyright 2011 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package ssh
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestReadVersion(t *testing.T) {
|
||||
longversion := strings.Repeat("SSH-2.0-bla", 50)[:253]
|
||||
cases := map[string]string{
|
||||
"SSH-2.0-bla\r\n": "SSH-2.0-bla",
|
||||
"SSH-2.0-bla\n": "SSH-2.0-bla",
|
||||
longversion + "\r\n": longversion,
|
||||
}
|
||||
|
||||
for in, want := range cases {
|
||||
result, err := readVersion(bytes.NewBufferString(in))
|
||||
if err != nil {
|
||||
t.Errorf("readVersion(%q): %s", in, err)
|
||||
}
|
||||
got := string(result)
|
||||
if got != want {
|
||||
t.Errorf("got %q, want %q", got, want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestReadVersionError(t *testing.T) {
|
||||
longversion := strings.Repeat("SSH-2.0-bla", 50)[:253]
|
||||
cases := []string{
|
||||
longversion + "too-long\r\n",
|
||||
}
|
||||
for _, in := range cases {
|
||||
if _, err := readVersion(bytes.NewBufferString(in)); err == nil {
|
||||
t.Errorf("readVersion(%q) should have failed", in)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestExchangeVersionsBasic(t *testing.T) {
|
||||
v := "SSH-2.0-bla"
|
||||
buf := bytes.NewBufferString(v + "\r\n")
|
||||
them, err := exchangeVersions(buf, []byte("xyz"))
|
||||
if err != nil {
|
||||
t.Errorf("exchangeVersions: %v", err)
|
||||
}
|
||||
|
||||
if want := "SSH-2.0-bla"; string(them) != want {
|
||||
t.Errorf("got %q want %q for our version", them, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestExchangeVersions(t *testing.T) {
|
||||
cases := []string{
|
||||
"not\x000allowed",
|
||||
"not allowed\n",
|
||||
}
|
||||
for _, c := range cases {
|
||||
buf := bytes.NewBufferString("SSH-2.0-bla\r\n")
|
||||
if _, err := exchangeVersions(buf, []byte(c)); err == nil {
|
||||
t.Errorf("exchangeVersions(%q): should have failed", c)
|
||||
}
|
||||
}
|
||||
}
|
8
vendor/github.com/Bugagazavr/go-gitlab-client/Makefile
generated
vendored
8
vendor/github.com/Bugagazavr/go-gitlab-client/Makefile
generated
vendored
|
@ -1,8 +0,0 @@
|
|||
all:deps test
|
||||
|
||||
deps:
|
||||
go get github.com/stretchr/testify
|
||||
go get ./...
|
||||
|
||||
test:
|
||||
go test -cover -short ./...
|
81
vendor/github.com/Bugagazavr/go-gitlab-client/README.md
generated
vendored
81
vendor/github.com/Bugagazavr/go-gitlab-client/README.md
generated
vendored
|
@ -1,81 +0,0 @@
|
|||
go-gitlab-client
|
||||
================
|
||||
|
||||
This is a fork of project https://github.com/plouc/go-gitlab-client
|
||||
|
||||
go-gitlab-client is a simple client written in golang to consume gitlab API.
|
||||
|
||||
[![Build Status](https://travis-ci.org/Bugagazavr/go-gitlab-client.svg?branch=master)](https://travis-ci.org/Bugagazavr/go-gitlab-client)
|
||||
|
||||
|
||||
##features
|
||||
|
||||
*
|
||||
###Session [gitlab api doc](http://doc.gitlab.com/ce/api/session.html)
|
||||
* get session
|
||||
|
||||
*
|
||||
###Projects [gitlab api doc](http://doc.gitlab.com/ce/api/projects.html)
|
||||
* list projects
|
||||
* get single project
|
||||
* list project merge requests
|
||||
* list notes on merge requests
|
||||
* add comments to merge requests
|
||||
|
||||
*
|
||||
###Repositories [gitlab api doc](http://doc.gitlab.com/ce/api/repositories.html)
|
||||
* list repository branches
|
||||
* get single repository branch
|
||||
* list project repository tags
|
||||
* list repository commits
|
||||
* list project hooks
|
||||
* add/get/edit/rm project hook
|
||||
|
||||
*
|
||||
###Users [gitlab api doc](http://doc.gitlab.com/ce/api/users.html)
|
||||
* get single user
|
||||
* manage user keys
|
||||
|
||||
*
|
||||
###Deploy Keys [gitlab api doc](http://doc.gitlab.com/ce/api/deploy_keys.html)
|
||||
* list project deploy keys
|
||||
* add/get/rm project deploy key
|
||||
|
||||
|
||||
|
||||
|
||||
##Installation
|
||||
|
||||
To install go-gitlab-client, use `go get`:
|
||||
|
||||
go get github.com/bugagazavr/go-gitlab-client
|
||||
|
||||
Import the `go-gitlab-client` package into your code:
|
||||
|
||||
```go
|
||||
package whatever
|
||||
|
||||
import (
|
||||
"github.com/bugagazavr/go-gitlab-client"
|
||||
)
|
||||
```
|
||||
|
||||
|
||||
##Update
|
||||
|
||||
To update `go-gitlab-client`, use `go get -u`:
|
||||
|
||||
go get -u github.com/bugagazavr/go-gitlab-client
|
||||
|
||||
|
||||
##Documentation
|
||||
|
||||
Visit the docs at http://godoc.org/github.com/Bugagazavr/go-gitlab-client
|
||||
|
||||
|
||||
## Examples
|
||||
|
||||
You can play with the examples located in the `examples` directory
|
||||
|
||||
* [projects](https://github.com/Bugagazavr/go-gitlab-client/tree/master/examples/projects)
|
||||
* [repositories](https://github.com/Bugagazavr/go-gitlab-client/tree/master/examples/repositories)
|
118
vendor/github.com/Bugagazavr/go-gitlab-client/deploy_keys.go
generated
vendored
118
vendor/github.com/Bugagazavr/go-gitlab-client/deploy_keys.go
generated
vendored
|
@ -1,118 +0,0 @@
|
|||
package gogitlab
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/url"
|
||||
)
|
||||
|
||||
const (
|
||||
// ID
|
||||
project_url_deploy_keys = "/projects/:id/keys" // Get list of project deploy keys
|
||||
// PROJECT ID AND KEY ID
|
||||
project_url_deploy_key = "/projects/:id/keys/:key_id" // Get single project deploy key
|
||||
)
|
||||
|
||||
/*
|
||||
Get list of project deploy keys.
|
||||
|
||||
GET /projects/:id/keys
|
||||
|
||||
Parameters:
|
||||
|
||||
id The ID of a project
|
||||
|
||||
*/
|
||||
func (g *Gitlab) ProjectDeployKeys(id string) ([]*PublicKey, error) {
|
||||
|
||||
url, opaque := g.ResourceUrlRaw(project_url_deploy_keys, map[string]string{":id": id})
|
||||
|
||||
var deployKeys []*PublicKey
|
||||
|
||||
contents, err := g.buildAndExecRequestRaw("GET", url, opaque, nil)
|
||||
if err == nil {
|
||||
err = json.Unmarshal(contents, &deployKeys)
|
||||
}
|
||||
|
||||
return deployKeys, err
|
||||
}
|
||||
|
||||
/*
|
||||
Get single project deploy key.
|
||||
|
||||
GET /projects/:id/keys/:key_id
|
||||
|
||||
Parameters:
|
||||
|
||||
id The ID of a project
|
||||
key_id The ID of a key
|
||||
|
||||
*/
|
||||
func (g *Gitlab) ProjectDeployKey(id, key_id string) (*PublicKey, error) {
|
||||
|
||||
url, opaque := g.ResourceUrlRaw(project_url_deploy_key, map[string]string{
|
||||
":id": id,
|
||||
":key_id": key_id,
|
||||
})
|
||||
|
||||
var deployKey *PublicKey
|
||||
|
||||
contents, err := g.buildAndExecRequestRaw("GET", url, opaque, nil)
|
||||
if err == nil {
|
||||
err = json.Unmarshal(contents, &deployKey)
|
||||
}
|
||||
|
||||
return deployKey, err
|
||||
}
|
||||
|
||||
/*
|
||||
Add deploy key to project.
|
||||
|
||||
POST /projects/:id/keys
|
||||
|
||||
Parameters:
|
||||
|
||||
id The ID of a project
|
||||
title The key title
|
||||
key The key value
|
||||
|
||||
*/
|
||||
func (g *Gitlab) AddProjectDeployKey(id, title, key string) error {
|
||||
var err error
|
||||
|
||||
path, opaque := g.ResourceUrlRaw(project_url_deploy_keys, map[string]string{":id": id})
|
||||
|
||||
v := url.Values{}
|
||||
v.Set("title", title)
|
||||
v.Set("key", key)
|
||||
|
||||
body := v.Encode()
|
||||
|
||||
_, err = g.buildAndExecRequestRaw("POST", path, opaque, []byte(body))
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
/*
|
||||
Remove deploy key from project
|
||||
|
||||
DELETE /projects/:id/keys/:key_id
|
||||
|
||||
Parameters:
|
||||
|
||||
id The ID of a project
|
||||
key_id The ID of a key
|
||||
|
||||
*/
|
||||
func (g *Gitlab) RemoveProjectDeployKey(id, key_id string) error {
|
||||
|
||||
url, opaque := g.ResourceUrlRaw(project_url_deploy_key, map[string]string{
|
||||
":id": id,
|
||||
":key_id": key_id,
|
||||
})
|
||||
|
||||
var err error
|
||||
|
||||
_, err = g.buildAndExecRequestRaw("DELETE", url, opaque, nil)
|
||||
|
||||
return err
|
||||
}
|
72
vendor/github.com/Bugagazavr/go-gitlab-client/events.go
generated
vendored
72
vendor/github.com/Bugagazavr/go-gitlab-client/events.go
generated
vendored
|
@ -1,72 +0,0 @@
|
|||
package gogitlab
|
||||
|
||||
import (
|
||||
"encoding/xml"
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Person struct {
|
||||
Name string `xml:"name"json:"name"`
|
||||
Email string `xml:"email"json:"email"`
|
||||
}
|
||||
|
||||
type Link struct {
|
||||
Rel string `xml:"rel,attr,omitempty"json:"rel"`
|
||||
Href string `xml:"href,attr"json:"href"`
|
||||
}
|
||||
|
||||
type ActivityFeed struct {
|
||||
Title string `xml:"title"json:"title"`
|
||||
Id string `xml:"id"json:"id"`
|
||||
Link []Link `xml:"link"json:"link"`
|
||||
Updated time.Time `xml:"updated,attr"json:"updated"`
|
||||
Entries []*FeedCommit `xml:"entry"json:"entries"`
|
||||
}
|
||||
|
||||
type FeedCommit struct {
|
||||
Id string `xml:"id"json:"id"`
|
||||
Title string `xml:"title"json:"title"`
|
||||
Link []Link `xml:"link"json:"link"`
|
||||
Updated time.Time `xml:"updated"json:"updated"`
|
||||
Author Person `xml:"author"json:"author"`
|
||||
Summary string `xml:"summary"json:"summary"`
|
||||
//<media:thumbnail width="40" height="40" url="https://secure.gravatar.com/avatar/7070eab7c6206530d3b7820362227fec?s=40&d=mm"/>
|
||||
}
|
||||
|
||||
func (g *Gitlab) Activity() (ActivityFeed, error) {
|
||||
|
||||
url := g.BaseUrl + dasboard_feed_path + "?private_token=" + g.Token
|
||||
fmt.Println(url)
|
||||
|
||||
contents, err := g.buildAndExecRequest("GET", url, nil)
|
||||
if err != nil {
|
||||
fmt.Println("%s", err)
|
||||
}
|
||||
|
||||
var activity ActivityFeed
|
||||
err = xml.Unmarshal(contents, &activity)
|
||||
if err != nil {
|
||||
fmt.Println("%s", err)
|
||||
}
|
||||
|
||||
return activity, err
|
||||
}
|
||||
|
||||
func (g *Gitlab) RepoActivityFeed(feedPath string) ActivityFeed {
|
||||
|
||||
url := g.BaseUrl + g.RepoFeedPath + "?private_token=" + g.Token
|
||||
|
||||
contents, err := g.buildAndExecRequest("GET", url, nil)
|
||||
if err != nil {
|
||||
fmt.Println("%s", err)
|
||||
}
|
||||
|
||||
var activity ActivityFeed
|
||||
err = xml.Unmarshal(contents, &activity)
|
||||
if err != nil {
|
||||
fmt.Println("%s", err)
|
||||
}
|
||||
|
||||
return activity
|
||||
}
|
5
vendor/github.com/Bugagazavr/go-gitlab-client/examples/config.json.sample
generated
vendored
5
vendor/github.com/Bugagazavr/go-gitlab-client/examples/config.json.sample
generated
vendored
|
@ -1,5 +0,0 @@
|
|||
{
|
||||
"host": "https://gitlab.domain.com",
|
||||
"api_path": "/api/v3",
|
||||
"token": "TOKEN"
|
||||
}
|
246
vendor/github.com/Bugagazavr/go-gitlab-client/examples/projects/main.go
generated
vendored
246
vendor/github.com/Bugagazavr/go-gitlab-client/examples/projects/main.go
generated
vendored
|
@ -1,246 +0,0 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"flag"
|
||||
"fmt"
|
||||
"github.com/bugagazavr/go-gitlab-client"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
Host string `json:"host"`
|
||||
ApiPath string `json:"api_path"`
|
||||
Token string `json:"token"`
|
||||
}
|
||||
|
||||
func main() {
|
||||
help := flag.Bool("help", false, "Show usage")
|
||||
|
||||
file, e := ioutil.ReadFile("../config.json")
|
||||
if e != nil {
|
||||
fmt.Printf("Config file error: %v\n", e)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
var config Config
|
||||
json.Unmarshal(file, &config)
|
||||
fmt.Printf("Results: %+v\n", config)
|
||||
|
||||
var gitlab *gogitlab.Gitlab
|
||||
|
||||
gitlab = gogitlab.NewGitlab(config.Host, config.ApiPath, config.Token)
|
||||
|
||||
var method string
|
||||
flag.StringVar(&method, "m", "", "Specify method to retrieve projects infos, available methods:\n"+
|
||||
" > -m projects\n"+
|
||||
" > -m project -id PROJECT_ID\n"+
|
||||
" > -m hooks -id PROJECT_ID\n"+
|
||||
" > -m branches -id PROJECT_ID\n"+
|
||||
" > -m merge_requests -id PROJECT_ID\n"+
|
||||
" > -m merge_request_notes -id PROJECT_ID -merge_id MERGE_REQUEST_ID\n"+
|
||||
" > -m merge_request_comment -id PROJECT_ID -merge_id MERGE_REQUEST_ID -comment COMMENT_BODY\n"+
|
||||
" > -m team -id PROJECT_ID")
|
||||
|
||||
var id string
|
||||
flag.StringVar(&id, "id", "", "Specify repository id")
|
||||
|
||||
var merge_id string
|
||||
flag.StringVar(&merge_id, "merge_id", "", "Specify merge request id")
|
||||
|
||||
var comment string
|
||||
flag.StringVar(&comment, "comment", "", "The body of the new comment")
|
||||
|
||||
flag.Usage = func() {
|
||||
fmt.Printf("Usage:\n")
|
||||
flag.PrintDefaults()
|
||||
}
|
||||
flag.Parse()
|
||||
|
||||
if *help == true || method == "" {
|
||||
flag.Usage()
|
||||
return
|
||||
}
|
||||
|
||||
startedAt := time.Now()
|
||||
defer func() {
|
||||
fmt.Printf("processed in %v\n", time.Now().Sub(startedAt))
|
||||
}()
|
||||
|
||||
switch method {
|
||||
case "projects":
|
||||
fmt.Println("Fetching projects…")
|
||||
|
||||
projects, err := gitlab.Projects(1, 100)
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
for _, project := range projects {
|
||||
fmt.Printf("> %6d | %s\n", project.Id, project.Name)
|
||||
}
|
||||
|
||||
case "project":
|
||||
fmt.Println("Fetching project…")
|
||||
|
||||
if id == "" {
|
||||
flag.Usage()
|
||||
return
|
||||
}
|
||||
|
||||
project, err := gitlab.Project(id)
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
format := "> %-23s: %s\n"
|
||||
|
||||
fmt.Printf("%s\n", project.Name)
|
||||
fmt.Printf(format, "id", strconv.Itoa(project.Id))
|
||||
fmt.Printf(format, "name", project.Name)
|
||||
fmt.Printf(format, "description", project.Description)
|
||||
fmt.Printf(format, "default branch", project.DefaultBranch)
|
||||
if project.Owner != nil {
|
||||
fmt.Printf(format, "owner.name", project.Owner.Username)
|
||||
}
|
||||
fmt.Printf(format, "public", strconv.FormatBool(project.Public))
|
||||
fmt.Printf(format, "path", project.Path)
|
||||
fmt.Printf(format, "path with namespace", project.PathWithNamespace)
|
||||
fmt.Printf(format, "issues enabled", strconv.FormatBool(project.IssuesEnabled))
|
||||
fmt.Printf(format, "merge requests enabled", strconv.FormatBool(project.MergeRequestsEnabled))
|
||||
fmt.Printf(format, "wall enabled", strconv.FormatBool(project.WallEnabled))
|
||||
fmt.Printf(format, "wiki enabled", strconv.FormatBool(project.WikiEnabled))
|
||||
fmt.Printf(format, "created at", project.CreatedAtRaw)
|
||||
//fmt.Printf(format, "namespace", project.Namespace)
|
||||
|
||||
case "branches":
|
||||
fmt.Println("Fetching project branches…")
|
||||
|
||||
if id == "" {
|
||||
flag.Usage()
|
||||
return
|
||||
}
|
||||
|
||||
branches, err := gitlab.ProjectBranches(id)
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
for _, branch := range branches {
|
||||
fmt.Printf("> %s\n", branch.Name)
|
||||
}
|
||||
|
||||
case "merge_requests":
|
||||
fmt.Println("Fetching project merge_requests…")
|
||||
|
||||
if id == "" {
|
||||
flag.Usage()
|
||||
return
|
||||
}
|
||||
|
||||
mrs, err := gitlab.ProjectMergeRequests(id, 0, 30, "opened")
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
for _, mr := range mrs {
|
||||
author := ""
|
||||
if mr.Author != nil {
|
||||
author = mr.Author.Username
|
||||
}
|
||||
assignee := ""
|
||||
if mr.Assignee != nil {
|
||||
assignee = mr.Assignee.Username
|
||||
}
|
||||
fmt.Printf(" (#%d) %s -> %s [%s] author[%s] assignee[%s]\n",
|
||||
mr.Id, mr.SourceBranch, mr.TargetBranch, mr.State,
|
||||
author, assignee)
|
||||
}
|
||||
|
||||
case "merge_request_notes":
|
||||
fmt.Println("Fetching merge_request notes…")
|
||||
|
||||
if id == "" {
|
||||
flag.Usage()
|
||||
return
|
||||
}
|
||||
|
||||
notes, err := gitlab.MergeRequestNotes(id, merge_id, 0, 30)
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
for _, note := range notes {
|
||||
author := ""
|
||||
if note.Author != nil {
|
||||
author = note.Author.Username
|
||||
}
|
||||
fmt.Printf(" [%d] author: %s <%s> %s\n",
|
||||
note.Id, author, note.CreatedAt, note.Body)
|
||||
}
|
||||
|
||||
case "merge_request_comment":
|
||||
fmt.Println("Sending new merge_request comment…")
|
||||
|
||||
if id == "" {
|
||||
flag.Usage()
|
||||
return
|
||||
}
|
||||
|
||||
note, err := gitlab.SendMergeRequestComment(id, merge_id, comment)
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
return
|
||||
}
|
||||
author := ""
|
||||
if note.Author != nil {
|
||||
author = note.Author.Username
|
||||
}
|
||||
fmt.Printf(" [%d] author: %s <%s> %s\n",
|
||||
note.Id, author, note.CreatedAt, note.Body)
|
||||
|
||||
case "hooks":
|
||||
fmt.Println("Fetching project hooks…")
|
||||
|
||||
if id == "" {
|
||||
flag.Usage()
|
||||
return
|
||||
}
|
||||
|
||||
hooks, err := gitlab.ProjectHooks(id)
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
for _, hook := range hooks {
|
||||
fmt.Printf("> [%d] %s, created on %s\n", hook.Id, hook.Url, hook.CreatedAtRaw)
|
||||
}
|
||||
|
||||
case "team":
|
||||
fmt.Println("Fetching project team members…")
|
||||
|
||||
if id == "" {
|
||||
flag.Usage()
|
||||
return
|
||||
}
|
||||
|
||||
members, err := gitlab.ProjectMembers(id)
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
for _, member := range members {
|
||||
fmt.Printf("> [%d] %s (%s) since %s\n", member.Id, member.Username, member.Name, member.CreatedAt)
|
||||
}
|
||||
}
|
||||
}
|
124
vendor/github.com/Bugagazavr/go-gitlab-client/examples/repositories/main.go
generated
vendored
124
vendor/github.com/Bugagazavr/go-gitlab-client/examples/repositories/main.go
generated
vendored
|
@ -1,124 +0,0 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"flag"
|
||||
"fmt"
|
||||
"github.com/bugagazavr/go-gitlab-client"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
Host string `json:"host"`
|
||||
ApiPath string `json:"api_path"`
|
||||
Token string `json:"token"`
|
||||
}
|
||||
|
||||
func main() {
|
||||
help := flag.Bool("help", false, "Show usage")
|
||||
|
||||
file, e := ioutil.ReadFile("../config.json")
|
||||
if e != nil {
|
||||
fmt.Printf("Config file error: %v\n", e)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
var config Config
|
||||
json.Unmarshal(file, &config)
|
||||
fmt.Printf("Results: %+v\n", config)
|
||||
|
||||
gitlab := gogitlab.NewGitlab(config.Host, config.ApiPath, config.Token)
|
||||
|
||||
var method string
|
||||
flag.StringVar(&method, "m", "", "Specify method to retrieve repositories, available methods:\n"+
|
||||
" > branches\n"+
|
||||
" > branch\n"+
|
||||
" > tags\n"+
|
||||
" > commits\n"+
|
||||
" > commit_comments -sha COMMIT_SHA\n"+
|
||||
" > comment_a_commit -sha COMMIT_SHA -comment COMMENT_BODY")
|
||||
|
||||
var id string
|
||||
flag.StringVar(&id, "id", "", "Specify repository id")
|
||||
|
||||
var sha string
|
||||
flag.StringVar(&sha, "sha", "", "Specify commit sha")
|
||||
|
||||
var comment string
|
||||
flag.StringVar(&comment, "comment", "", "The body of the new comment")
|
||||
|
||||
flag.Usage = func() {
|
||||
fmt.Printf("Usage:\n")
|
||||
flag.PrintDefaults()
|
||||
}
|
||||
flag.Parse()
|
||||
|
||||
if *help == true || method == "" || id == "" {
|
||||
flag.Usage()
|
||||
return
|
||||
}
|
||||
|
||||
startedAt := time.Now()
|
||||
defer func() {
|
||||
fmt.Printf("processed in %v\n", time.Now().Sub(startedAt))
|
||||
}()
|
||||
|
||||
switch method {
|
||||
case "branches":
|
||||
fmt.Println("Fetching repository branches…")
|
||||
|
||||
branches, err := gitlab.RepoBranches(id)
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
}
|
||||
|
||||
for _, branch := range branches {
|
||||
fmt.Printf("> %s\n", branch.Name)
|
||||
}
|
||||
case "branch":
|
||||
case "tags":
|
||||
fmt.Println("Fetching repository tags…")
|
||||
|
||||
tags, err := gitlab.RepoTags(id)
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
}
|
||||
|
||||
for _, tag := range tags {
|
||||
fmt.Printf("> %s\n", tag.Name)
|
||||
}
|
||||
case "commits":
|
||||
fmt.Println("Fetching repository commits…")
|
||||
|
||||
commits, err := gitlab.RepoCommits(id)
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
}
|
||||
|
||||
for _, commit := range commits {
|
||||
fmt.Printf("(%s) %s > [%s] %s\n", commit.Id, commit.CreatedAt.Format("Mon 02 Jan 15:04"), commit.Author_Name, commit.Title)
|
||||
}
|
||||
case "commit_comments":
|
||||
fmt.Println("Fetching comments on a repository commit…")
|
||||
|
||||
comments, err := gitlab.RepoCommitComments(id, sha)
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
}
|
||||
|
||||
for _, c := range comments {
|
||||
fmt.Printf("[%s] %s\n", c.Author.Username, c.Note)
|
||||
}
|
||||
case "comment_a_commit":
|
||||
fmt.Println("Sending a new comment on a repository commit…")
|
||||
|
||||
c, err := gitlab.SendRepoCommitComment(id, sha, comment)
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
}
|
||||
|
||||
fmt.Printf("[%s] %s\n", c.Author.Username, c.Note)
|
||||
}
|
||||
}
|
220
vendor/github.com/Bugagazavr/go-gitlab-client/gitlab.go
generated
vendored
220
vendor/github.com/Bugagazavr/go-gitlab-client/gitlab.go
generated
vendored
|
@ -1,220 +0,0 @@
|
|||
// Package github implements a simple client to consume gitlab API.
|
||||
package gogitlab
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/tls"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
dasboard_feed_path = "/dashboard.atom"
|
||||
)
|
||||
|
||||
type Gitlab struct {
|
||||
BaseUrl string
|
||||
ApiPath string
|
||||
RepoFeedPath string
|
||||
Token string
|
||||
Bearer bool
|
||||
Client *http.Client
|
||||
}
|
||||
|
||||
const (
|
||||
dateLayout = "2006-01-02T15:04:05-07:00"
|
||||
)
|
||||
|
||||
var (
|
||||
skipCertVerify = flag.Bool("gitlab.skip-cert-check", false,
|
||||
`If set to true, gitlab client will skip certificate checking for https, possibly exposing your system to MITM attack.`)
|
||||
)
|
||||
|
||||
func NewGitlab(baseUrl, apiPath, token string) *Gitlab {
|
||||
return NewGitlabCert(baseUrl, apiPath, token, *skipCertVerify)
|
||||
}
|
||||
|
||||
func NewGitlabCert(baseUrl, apiPath, token string, skipVerify bool) *Gitlab {
|
||||
config := &tls.Config{InsecureSkipVerify: skipVerify}
|
||||
tr := &http.Transport{
|
||||
Proxy: http.ProxyFromEnvironment,
|
||||
TLSClientConfig: config,
|
||||
}
|
||||
client := &http.Client{Transport: tr}
|
||||
|
||||
return &Gitlab{
|
||||
BaseUrl: baseUrl,
|
||||
ApiPath: apiPath,
|
||||
Token: token,
|
||||
Client: client,
|
||||
}
|
||||
}
|
||||
|
||||
func (g *Gitlab) ResourceUrl(url string, params map[string]string) string {
|
||||
|
||||
if params != nil {
|
||||
for key, val := range params {
|
||||
url = strings.Replace(url, key, encodeParameter(val), -1)
|
||||
}
|
||||
}
|
||||
|
||||
url = g.BaseUrl + g.ApiPath + url
|
||||
if !g.Bearer {
|
||||
url = url + "?private_token=" + g.Token
|
||||
}
|
||||
return url
|
||||
}
|
||||
|
||||
func (g *Gitlab) buildAndExecRequest(method, url string, body []byte) ([]byte, error) {
|
||||
|
||||
var req *http.Request
|
||||
var err error
|
||||
|
||||
if body != nil {
|
||||
reader := bytes.NewReader(body)
|
||||
req, err = http.NewRequest(method, url, reader)
|
||||
} else {
|
||||
req, err = http.NewRequest(method, url, nil)
|
||||
}
|
||||
if err != nil {
|
||||
panic("Error while building gitlab request")
|
||||
}
|
||||
|
||||
if g.Bearer {
|
||||
req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", g.Token))
|
||||
}
|
||||
|
||||
resp, err := g.Client.Do(req)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Client.Do error: %q", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
contents, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
fmt.Printf("%s", err)
|
||||
}
|
||||
|
||||
if resp.StatusCode >= 400 {
|
||||
err = fmt.Errorf("*Gitlab.buildAndExecRequest failed: <%d> %s", resp.StatusCode, req.URL)
|
||||
}
|
||||
|
||||
return contents, err
|
||||
}
|
||||
|
||||
func (g *Gitlab) ResourceUrlQuery(u string, params, query map[string]string) string {
|
||||
if params != nil {
|
||||
for key, val := range params {
|
||||
u = strings.Replace(u, key, encodeParameter(val), -1)
|
||||
}
|
||||
}
|
||||
|
||||
query_params := url.Values{}
|
||||
if !g.Bearer {
|
||||
query_params.Add("private_token", g.Token)
|
||||
}
|
||||
|
||||
if query != nil {
|
||||
for key, val := range query {
|
||||
query_params.Set(key, val)
|
||||
}
|
||||
}
|
||||
|
||||
u = g.BaseUrl + g.ApiPath + u + "?" + query_params.Encode()
|
||||
return u
|
||||
|
||||
}
|
||||
|
||||
func (g *Gitlab) ResourceUrlQueryRaw(u string, params, query map[string]string) (string, string) {
|
||||
if params != nil {
|
||||
for key, val := range params {
|
||||
u = strings.Replace(u, key, encodeParameter(val), -1)
|
||||
}
|
||||
}
|
||||
|
||||
query_params := url.Values{}
|
||||
if !g.Bearer {
|
||||
query_params.Add("private_token", g.Token)
|
||||
}
|
||||
|
||||
if query != nil {
|
||||
for key, val := range query {
|
||||
query_params.Set(key, val)
|
||||
}
|
||||
}
|
||||
|
||||
u = g.BaseUrl + g.ApiPath + u + "?" + query_params.Encode()
|
||||
p, err := url.Parse(u)
|
||||
if err != nil {
|
||||
return u, ""
|
||||
}
|
||||
|
||||
opaque := "//" + p.Host + p.Path
|
||||
return u, opaque
|
||||
|
||||
}
|
||||
|
||||
func (g *Gitlab) ResourceUrlRaw(u string, params map[string]string) (string, string) {
|
||||
|
||||
if params != nil {
|
||||
for key, val := range params {
|
||||
u = strings.Replace(u, key, encodeParameter(val), -1)
|
||||
}
|
||||
}
|
||||
|
||||
path := u
|
||||
u = g.BaseUrl + g.ApiPath + path
|
||||
if !g.Bearer {
|
||||
u = u + "?private_token=" + g.Token
|
||||
}
|
||||
|
||||
p, err := url.Parse(u)
|
||||
if err != nil {
|
||||
return u, ""
|
||||
}
|
||||
opaque := "//" + p.Host + p.Path
|
||||
return u, opaque
|
||||
}
|
||||
|
||||
func (g *Gitlab) buildAndExecRequestRaw(method, url, opaque string, body []byte) ([]byte, error) {
|
||||
|
||||
var req *http.Request
|
||||
var err error
|
||||
|
||||
if body != nil {
|
||||
reader := bytes.NewReader(body)
|
||||
req, err = http.NewRequest(method, url, reader)
|
||||
} else {
|
||||
req, err = http.NewRequest(method, url, nil)
|
||||
}
|
||||
if err != nil {
|
||||
panic("Error while building gitlab request")
|
||||
}
|
||||
|
||||
if g.Bearer {
|
||||
req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", g.Token))
|
||||
}
|
||||
|
||||
if len(opaque) > 0 {
|
||||
req.URL.Opaque = opaque
|
||||
}
|
||||
|
||||
resp, err := g.Client.Do(req)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Client.Do error: %q", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
contents, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
fmt.Printf("%s", err)
|
||||
}
|
||||
|
||||
if resp.StatusCode >= 400 {
|
||||
err = fmt.Errorf("*Gitlab.buildAndExecRequestRaw failed: <%d> %s", resp.StatusCode, req.URL)
|
||||
}
|
||||
|
||||
return contents, err
|
||||
}
|
13
vendor/github.com/Bugagazavr/go-gitlab-client/gitlab_test.go
generated
vendored
13
vendor/github.com/Bugagazavr/go-gitlab-client/gitlab_test.go
generated
vendored
|
@ -1,13 +0,0 @@
|
|||
package gogitlab
|
||||
|
||||
import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestResourceUrl(t *testing.T) {
|
||||
gitlab := NewGitlab("http://base_url/", "api_path", "token")
|
||||
|
||||
assert.Equal(t, gitlab.ResourceUrl(projects_url, nil), "http://base_url/api_path/projects?private_token=token")
|
||||
assert.Equal(t, gitlab.ResourceUrl(project_url, map[string]string{":id": "123"}), "http://base_url/api_path/projects/123?private_token=token")
|
||||
}
|
16
vendor/github.com/Bugagazavr/go-gitlab-client/helper_test.go
generated
vendored
16
vendor/github.com/Bugagazavr/go-gitlab-client/helper_test.go
generated
vendored
|
@ -1,16 +0,0 @@
|
|||
package gogitlab
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
)
|
||||
|
||||
func Stub(filename string) (*httptest.Server, *Gitlab) {
|
||||
stub, _ := ioutil.ReadFile(filename)
|
||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Write([]byte(stub))
|
||||
}))
|
||||
gitlab := NewGitlab(ts.URL, "", "")
|
||||
return ts, gitlab
|
||||
}
|
156
vendor/github.com/Bugagazavr/go-gitlab-client/hook_payload.go
generated
vendored
156
vendor/github.com/Bugagazavr/go-gitlab-client/hook_payload.go
generated
vendored
|
@ -1,156 +0,0 @@
|
|||
package gogitlab
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type HookObjAttr struct {
|
||||
Id int `json:"id,omitempty"`
|
||||
Title string `json:"title,omitempty"`
|
||||
AssigneeId int `json:"assignee_id,omitempty"`
|
||||
AuthorId int `json:"author_id,omitempty"`
|
||||
ProjectId int `json:"project_id,omitempty"`
|
||||
CreatedAt string `json:"created_at,omitempty"`
|
||||
UpdatedAt string `json:"updated_at,omitempty"`
|
||||
Position int `json:"position,omitempty"`
|
||||
BranchName string `json:"branch_name,omitempty"`
|
||||
Description string `json:"description,omitempty"`
|
||||
MilestoneId int `json:"milestone_id,omitempty"`
|
||||
State string `json:"state,omitempty"`
|
||||
IId int `json:"iid,omitempty"`
|
||||
TargetBranch string `json:"target_branch,omitempty"`
|
||||
SourceBranch string `json:"source_branch,omitempty"`
|
||||
SourceProjectId int `json:"source_project_id,omitempty"`
|
||||
StCommits string `json:"st_commits,omitempty"`
|
||||
StDiffs string `json:"st_diffs,omitempty"`
|
||||
MergeStatus string `json:"merge_status,omitempty"`
|
||||
TargetProjectId int `json:"target_project_id,omitempty"`
|
||||
Url string `json:"url,omiyempty"`
|
||||
Source *hProject `json:"source,omitempty"`
|
||||
Target *hProject `json:"target,omitempty"`
|
||||
LastCommit *hCommit `json:"last_commit,omitempty"`
|
||||
}
|
||||
|
||||
type hProject struct {
|
||||
Name string `json:"name"`
|
||||
SshUrl string `json:"ssh_url"`
|
||||
HttpUrl string `json:"http_url"`
|
||||
VisibilityLevel int `json:"visibility_level"`
|
||||
WebUrl string `json:"web_url"`
|
||||
Namespace string `json:"namespace"`
|
||||
}
|
||||
|
||||
type hRepository struct {
|
||||
Name string `json:"name,omitempty"`
|
||||
URL string `json:"url,omitempty"`
|
||||
Description string `json:"description,omitempty"`
|
||||
Homepage string `json:"homepage,omitempty"`
|
||||
GitHttpUrl string `json:"git_http_url,omitempty"`
|
||||
GitSshUrl string `json:"git_ssh_url,omitempty"`
|
||||
VisibilityLevel int `json:"visibility_level,omitempty"`
|
||||
}
|
||||
|
||||
type hCommit struct {
|
||||
Id string `json:"id,omitempty"`
|
||||
Message string `json:"message,omitempty"`
|
||||
Timestamp string `json:"timestamp,omitempty"`
|
||||
URL string `json:"url,omitempty"`
|
||||
Author *Person `json:"author,omitempty"`
|
||||
}
|
||||
|
||||
type HookPayload struct {
|
||||
Before string `json:"before,omitempty"`
|
||||
After string `json:"after,omitempty"`
|
||||
Ref string `json:"ref,omitempty"`
|
||||
UserId int `json:"user_id,omitempty"`
|
||||
UserName string `json:"user_name,omitempty"`
|
||||
ProjectId int `json:"project_id,omitempty"`
|
||||
Repository *hRepository `json:"repository,omitempty"`
|
||||
Commits []hCommit `json:"commits,omitempty"`
|
||||
TotalCommitsCount int `json:"total_commits_count,omitempty"`
|
||||
ObjectKind string `json:"object_kind,omitempty"`
|
||||
ObjectAttributes *HookObjAttr `json:"object_attributes,omitempty"`
|
||||
}
|
||||
|
||||
// ParseHook parses hook payload from GitLab
|
||||
func ParseHook(payload []byte) (*HookPayload, error) {
|
||||
hp := HookPayload{}
|
||||
if err := json.Unmarshal(payload, &hp); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Basic sanity check
|
||||
switch {
|
||||
case len(hp.ObjectKind) == 0:
|
||||
// Assume this is a post-receive within repository
|
||||
if len(hp.After) == 0 {
|
||||
return nil, fmt.Errorf("Invalid hook received, commit hash not found.")
|
||||
}
|
||||
case hp.ObjectKind == "push":
|
||||
if hp.Repository == nil {
|
||||
return nil, fmt.Errorf("Invalid push hook received, attributes not found")
|
||||
}
|
||||
case hp.ObjectKind == "tag_push":
|
||||
if hp.Repository == nil {
|
||||
return nil, fmt.Errorf("Invalid tag push hook received, attributes not found")
|
||||
}
|
||||
case hp.ObjectKind == "issue":
|
||||
fallthrough
|
||||
case hp.ObjectKind == "merge_request":
|
||||
if hp.ObjectAttributes == nil {
|
||||
return nil, fmt.Errorf("Invalid hook received, attributes not found.")
|
||||
}
|
||||
default:
|
||||
return nil, fmt.Errorf("Invalid hook received, payload format not recognized.")
|
||||
}
|
||||
|
||||
return &hp, nil
|
||||
}
|
||||
|
||||
// Type return current event type
|
||||
// This function returns "unknown" type if event not supported
|
||||
func (h *HookPayload) Type() string {
|
||||
switch {
|
||||
case strings.HasPrefix(h.Ref, "refs/heads/") && len(h.After) == 0:
|
||||
return "branch_deleted"
|
||||
case strings.HasPrefix(h.Ref, "refs/heads/") && len(h.Before) == 0:
|
||||
return "branch"
|
||||
case strings.HasPrefix(h.Ref, "refs/heads/"):
|
||||
return "commit"
|
||||
case strings.HasPrefix(h.Ref, "refs/tags/") && len(h.After) == 0:
|
||||
return "tag_deleted"
|
||||
case strings.HasPrefix(h.Ref, "refs/tags/"):
|
||||
return "tag"
|
||||
case h.ObjectKind == "issue":
|
||||
return "issue"
|
||||
case h.ObjectKind == "merge_request":
|
||||
return "merge_request"
|
||||
default:
|
||||
return "unknown"
|
||||
}
|
||||
}
|
||||
|
||||
// Tag returns current tag for push event hook payload
|
||||
// This function returns empty string for any other events
|
||||
func (h *HookPayload) Tag() string {
|
||||
return strings.TrimPrefix(h.Ref, "refs/tags/")
|
||||
}
|
||||
|
||||
// Branch returns current branch for push event hook payload
|
||||
// This function returns empty string for any other events
|
||||
func (h *HookPayload) Branch() string {
|
||||
return strings.TrimPrefix(h.Ref, "refs/heads/")
|
||||
}
|
||||
|
||||
// Head returns the latest changeset for push event hook payload
|
||||
func (h *HookPayload) Head() hCommit {
|
||||
c := hCommit{}
|
||||
for _, cm := range h.Commits {
|
||||
if h.After == cm.Id {
|
||||
return cm
|
||||
}
|
||||
}
|
||||
return c
|
||||
}
|
45
vendor/github.com/Bugagazavr/go-gitlab-client/hook_payload_test.go
generated
vendored
45
vendor/github.com/Bugagazavr/go-gitlab-client/hook_payload_test.go
generated
vendored
|
@ -1,45 +0,0 @@
|
|||
package gogitlab
|
||||
|
||||
import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
"io/ioutil"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestParsePushHook(t *testing.T) {
|
||||
stub, _ := ioutil.ReadFile("stubs/hook_payloads/push.json")
|
||||
p, err := ParseHook([]byte(stub))
|
||||
|
||||
assert.Equal(t, err, nil)
|
||||
assert.Equal(t, p.ObjectKind, "push")
|
||||
assert.IsType(t, new(HookPayload), p)
|
||||
assert.Equal(t, p.After, "da1560886d4f094c3e6c9ef40349f7d38b5d27d7")
|
||||
assert.Equal(t, p.Repository.URL, "git@example.com:mike/diasporadiaspora.git")
|
||||
assert.Equal(t, p.Repository.GitHttpUrl, "http://example.com/mike/diaspora.git")
|
||||
assert.Equal(t, p.Repository.GitSshUrl, "git@example.com:mike/diaspora.git")
|
||||
assert.Equal(t, p.Repository.VisibilityLevel, 0)
|
||||
assert.Equal(t, len(p.Commits), 2)
|
||||
assert.Equal(t, p.Commits[0].Author.Email, "jordi@softcatala.org")
|
||||
assert.Equal(t, p.Commits[1].Id, "da1560886d4f094c3e6c9ef40349f7d38b5d27d7")
|
||||
assert.Equal(t, p.Branch(), "master")
|
||||
assert.Equal(t, p.Head().Message, "fixed readme")
|
||||
}
|
||||
|
||||
func TestParseIssueHook(t *testing.T) {
|
||||
stub, _ := ioutil.ReadFile("stubs/hook_payloads/issue.json")
|
||||
p, err := ParseHook([]byte(stub))
|
||||
|
||||
assert.Equal(t, err, nil)
|
||||
assert.Equal(t, p.ObjectKind, "issue")
|
||||
assert.Equal(t, p.ObjectAttributes.Id, 301)
|
||||
}
|
||||
|
||||
func TestParseMergeRequestHook(t *testing.T) {
|
||||
stub, _ := ioutil.ReadFile("stubs/hook_payloads/merge_request.json")
|
||||
p, err := ParseHook([]byte(stub))
|
||||
|
||||
assert.Equal(t, err, nil)
|
||||
assert.Equal(t, p.ObjectKind, "merge_request")
|
||||
assert.Equal(t, p.ObjectAttributes.TargetBranch, "master")
|
||||
assert.Equal(t, p.ObjectAttributes.SourceProjectId, p.ObjectAttributes.TargetProjectId)
|
||||
}
|
187
vendor/github.com/Bugagazavr/go-gitlab-client/hooks.go
generated
vendored
187
vendor/github.com/Bugagazavr/go-gitlab-client/hooks.go
generated
vendored
|
@ -1,187 +0,0 @@
|
|||
package gogitlab
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/url"
|
||||
)
|
||||
|
||||
const (
|
||||
project_url_hooks = "/projects/:id/hooks" // Get list of project hooks
|
||||
project_url_hook = "/projects/:id/hooks/:hook_id" // Get single project hook
|
||||
)
|
||||
|
||||
type Hook struct {
|
||||
Id int `json:"id,omitempty"`
|
||||
Url string `json:"url,omitempty"`
|
||||
CreatedAtRaw string `json:"created_at,omitempty"`
|
||||
}
|
||||
|
||||
/*
|
||||
Get list of project hooks.
|
||||
|
||||
GET /projects/:id/hooks
|
||||
|
||||
Parameters:
|
||||
|
||||
id The ID of a project
|
||||
|
||||
*/
|
||||
func (g *Gitlab) ProjectHooks(id string) ([]*Hook, error) {
|
||||
|
||||
url, opaque := g.ResourceUrlRaw(project_url_hooks, map[string]string{":id": id})
|
||||
|
||||
var err error
|
||||
var hooks []*Hook
|
||||
|
||||
contents, err := g.buildAndExecRequestRaw("GET", url, opaque, nil)
|
||||
if err != nil {
|
||||
return hooks, err
|
||||
}
|
||||
|
||||
err = json.Unmarshal(contents, &hooks)
|
||||
|
||||
return hooks, err
|
||||
}
|
||||
|
||||
/*
|
||||
Get single project hook.
|
||||
|
||||
GET /projects/:id/hooks/:hook_id
|
||||
|
||||
Parameters:
|
||||
|
||||
id The ID of a project
|
||||
hook_id The ID of a hook
|
||||
|
||||
*/
|
||||
func (g *Gitlab) ProjectHook(id, hook_id string) (*Hook, error) {
|
||||
|
||||
url, opaque := g.ResourceUrlRaw(project_url_hook, map[string]string{
|
||||
":id": id,
|
||||
":hook_id": hook_id,
|
||||
})
|
||||
|
||||
var err error
|
||||
hook := new(Hook)
|
||||
|
||||
contents, err := g.buildAndExecRequestRaw("GET", url, opaque, nil)
|
||||
if err != nil {
|
||||
return hook, err
|
||||
}
|
||||
|
||||
err = json.Unmarshal(contents, &hook)
|
||||
|
||||
return hook, err
|
||||
}
|
||||
|
||||
/*
|
||||
Add new project hook.
|
||||
|
||||
POST /projects/:id/hooks
|
||||
|
||||
Parameters:
|
||||
|
||||
id The ID or NAMESPACE/PROJECT_NAME of a project
|
||||
hook_url The hook URL
|
||||
push_events Trigger hook on push events
|
||||
issues_events Trigger hook on issues events
|
||||
merge_requests_events Trigger hook on merge_requests events
|
||||
|
||||
*/
|
||||
func (g *Gitlab) AddProjectHook(id, hook_url string, push_events, issues_events, merge_requests_events, tag_events bool) error {
|
||||
|
||||
url, opaque := g.ResourceUrlRaw(project_url_hooks, map[string]string{":id": id})
|
||||
|
||||
var err error
|
||||
|
||||
body := buildHookQuery(hook_url, push_events, issues_events, merge_requests_events, tag_events)
|
||||
_, err = g.buildAndExecRequestRaw("POST", url, opaque, []byte(body))
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
/*
|
||||
Edit existing project hook.
|
||||
|
||||
PUT /projects/:id/hooks/:hook_id
|
||||
|
||||
Parameters:
|
||||
|
||||
id The ID or NAMESPACE/PROJECT_NAME of a project
|
||||
hook_id The ID of a project hook
|
||||
hook_url The hook URL
|
||||
push_events Trigger hook on push events
|
||||
issues_events Trigger hook on issues events
|
||||
merge_requests_events Trigger hook on merge_requests events
|
||||
|
||||
*/
|
||||
func (g *Gitlab) EditProjectHook(id, hook_id, hook_url string, push_events, issues_events, merge_requests_events, tag_events bool) error {
|
||||
|
||||
url, opaque := g.ResourceUrlRaw(project_url_hook, map[string]string{
|
||||
":id": id,
|
||||
":hook_id": hook_id,
|
||||
})
|
||||
|
||||
var err error
|
||||
|
||||
body := buildHookQuery(hook_url, push_events, issues_events, merge_requests_events, tag_events)
|
||||
_, err = g.buildAndExecRequestRaw("PUT", url, opaque, []byte(body))
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
/*
|
||||
Remove hook from project.
|
||||
|
||||
DELETE /projects/:id/hooks/:hook_id
|
||||
|
||||
Parameters:
|
||||
|
||||
id The ID or NAMESPACE/PROJECT_NAME of a project
|
||||
hook_id The ID of hook to delete
|
||||
|
||||
*/
|
||||
func (g *Gitlab) RemoveProjectHook(id, hook_id string) error {
|
||||
|
||||
url, opaque := g.ResourceUrlRaw(project_url_hook, map[string]string{
|
||||
":id": id,
|
||||
":hook_id": hook_id,
|
||||
})
|
||||
|
||||
var err error
|
||||
|
||||
_, err = g.buildAndExecRequestRaw("DELETE", url, opaque, nil)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
/*
|
||||
Build HTTP query to add or edit hook
|
||||
*/
|
||||
func buildHookQuery(hook_url string, push_events, issues_events, merge_requests_events, tag_events bool) string {
|
||||
|
||||
v := url.Values{}
|
||||
v.Set("url", hook_url)
|
||||
|
||||
if push_events {
|
||||
v.Set("push_events", "true")
|
||||
} else {
|
||||
v.Set("push_events", "false")
|
||||
}
|
||||
if issues_events {
|
||||
v.Set("issues_events", "true")
|
||||
} else {
|
||||
v.Set("issues_events", "false")
|
||||
}
|
||||
if merge_requests_events {
|
||||
v.Set("merge_requests_events", "true")
|
||||
} else {
|
||||
v.Set("merge_requests_events", "false")
|
||||
}
|
||||
if tag_events {
|
||||
v.Set("tag_push_events", "true")
|
||||
} else {
|
||||
v.Set("tag_push_events", "false")
|
||||
}
|
||||
return v.Encode()
|
||||
}
|
16
vendor/github.com/Bugagazavr/go-gitlab-client/hooks_test.go
generated
vendored
16
vendor/github.com/Bugagazavr/go-gitlab-client/hooks_test.go
generated
vendored
|
@ -1,16 +0,0 @@
|
|||
package gogitlab
|
||||
|
||||
import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestHook(t *testing.T) {
|
||||
ts, gitlab := Stub("stubs/hooks/show.json")
|
||||
hook, err := gitlab.ProjectHook("1", "2")
|
||||
|
||||
assert.Equal(t, err, nil)
|
||||
assert.IsType(t, new(Hook), hook)
|
||||
assert.Equal(t, hook.Url, "http://example.com/hook")
|
||||
defer ts.Close()
|
||||
}
|
292
vendor/github.com/Bugagazavr/go-gitlab-client/projects.go
generated
vendored
292
vendor/github.com/Bugagazavr/go-gitlab-client/projects.go
generated
vendored
|
@ -1,292 +0,0 @@
|
|||
package gogitlab
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
projects_url = "/projects" // Get a list of projects owned by the authenticated user
|
||||
projects_search_url = "/projects/search/:query" // Search for projects by name
|
||||
project_url = "/projects/:id" // Get a specific project, identified by project ID or NAME
|
||||
project_url_events = "/projects/:id/events" // Get project events
|
||||
project_url_branches = "/projects/:id/repository/branches" // Lists all branches of a project
|
||||
project_url_members = "/projects/:id/members" // List project team members
|
||||
project_url_member = "/projects/:id/members/:user_id" // Get project team member
|
||||
project_url_merge_requests = "/projects/:id/merge_requests" // List all merge requests of a project
|
||||
merge_request_url_notes = "/projects/:id/merge_requests/:merge_request_id/notes" // Manage comments for a given merge request
|
||||
)
|
||||
|
||||
type Member struct {
|
||||
Id int
|
||||
Username string
|
||||
Email string
|
||||
Name string
|
||||
State string
|
||||
CreatedAt string `json:"created_at,omitempty"`
|
||||
// AccessLevel int
|
||||
}
|
||||
|
||||
type Namespace struct {
|
||||
Id int
|
||||
Name string
|
||||
Path string
|
||||
Description string
|
||||
Owner_Id int
|
||||
Created_At string
|
||||
Updated_At string
|
||||
}
|
||||
|
||||
type ProjectAccess struct {
|
||||
AccessLevel int `json:"access_level,omitempty"`
|
||||
NotificationLevel int `json:"notification_level,omitempty"`
|
||||
}
|
||||
|
||||
type GroupAccess struct {
|
||||
AccessLevel int `json:"access_level,omitempty"`
|
||||
NotificationLevel int `json:"notification_level,omitempty"`
|
||||
}
|
||||
|
||||
type Permissions struct {
|
||||
ProjectAccess *ProjectAccess `json:"project_access,omitempty"`
|
||||
GroupAccess *GroupAccess `json:"group_access,omitempty"`
|
||||
}
|
||||
|
||||
// A gitlab project
|
||||
type Project struct {
|
||||
Id int `json:"id,omitempty"`
|
||||
Name string `json:"name,omitempty"`
|
||||
Description string `json:"description,omitempty"`
|
||||
DefaultBranch string `json:"default_branch,omitempty"`
|
||||
Owner *Member `json:"owner,omitempty"`
|
||||
Public bool `json:"public,omitempty"`
|
||||
Path string `json:"path,omitempty"`
|
||||
PathWithNamespace string `json:"path_with_namespace,omitempty"`
|
||||
IssuesEnabled bool `json:"issues_enabled,omitempty"`
|
||||
MergeRequestsEnabled bool `json:"merge_requests_enabled,omitempty"`
|
||||
WallEnabled bool `json:"wall_enabled,omitempty"`
|
||||
WikiEnabled bool `json:"wiki_enabled,omitempty"`
|
||||
CreatedAtRaw string `json:"created_at,omitempty"`
|
||||
Namespace *Namespace `json:"namespace,omitempty"`
|
||||
SshRepoUrl string `json:"ssh_url_to_repo"`
|
||||
HttpRepoUrl string `json:"http_url_to_repo"`
|
||||
Url string `json:"web_url"`
|
||||
Permissions *Permissions `json:"permissions,omitempty"`
|
||||
}
|
||||
|
||||
type MergeRequest struct {
|
||||
Id int `json:"id,omitempty"`
|
||||
// IId
|
||||
TargetBranch string `json:"target_branch,omitempty"`
|
||||
SourceBranch string `json:"source_branch,omitempty"`
|
||||
ProjectId int `json:"project_id,omitempty"`
|
||||
Title string `json:"title,omitempty"`
|
||||
State string `json:"state,omitempty"`
|
||||
Upvotes int `json:"upvotes,omitempty"`
|
||||
Downvotes int `json:"downvotes,omitempty"`
|
||||
Author *Member `json:"author,omitempty"`
|
||||
Assignee *Member `json:"assignee,omitempty"`
|
||||
Description string `json:"description,omitempty"`
|
||||
}
|
||||
|
||||
type MergeRequestNote struct {
|
||||
Attachment interface{} `json:"attachment"`
|
||||
Body string `json:"body"`
|
||||
CreatedAt string `json:"created_at"`
|
||||
Id int `json:"id"`
|
||||
Author *Member `json:"author"`
|
||||
}
|
||||
|
||||
/*
|
||||
Get a list of all projects owned by the authenticated user.
|
||||
*/
|
||||
func (g *Gitlab) AllProjects() ([]*Project, error) {
|
||||
var per_page = 100
|
||||
var projects []*Project
|
||||
|
||||
for i := 1; true; i++ {
|
||||
contents, err := g.Projects(i, per_page)
|
||||
if err != nil {
|
||||
return projects, err
|
||||
}
|
||||
|
||||
for _, value := range contents {
|
||||
projects = append(projects, value)
|
||||
}
|
||||
|
||||
if len(projects) == 0 {
|
||||
break
|
||||
}
|
||||
|
||||
if len(projects)/i < per_page {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return projects, nil
|
||||
}
|
||||
|
||||
/*
|
||||
Get a list of projects owned by the authenticated user.
|
||||
*/
|
||||
func (g *Gitlab) Projects(page int, per_page int) ([]*Project, error) {
|
||||
|
||||
url := g.ResourceUrlQuery(projects_url, nil, map[string]string{"page": strconv.Itoa(page), "per_page": strconv.Itoa(per_page)})
|
||||
|
||||
var projects []*Project
|
||||
|
||||
contents, err := g.buildAndExecRequest("GET", url, nil)
|
||||
if err == nil {
|
||||
err = json.Unmarshal(contents, &projects)
|
||||
}
|
||||
|
||||
return projects, err
|
||||
}
|
||||
|
||||
/*
|
||||
Get a specific project, identified by project ID or NAME,
|
||||
which is owned by the authentication user.
|
||||
Namespaced project may be retrieved by specifying the namespace
|
||||
and its project name like this:
|
||||
|
||||
`namespace%2Fproject-name`
|
||||
|
||||
*/
|
||||
func (g *Gitlab) Project(id string) (*Project, error) {
|
||||
|
||||
url, opaque := g.ResourceUrlRaw(project_url, map[string]string{":id": id})
|
||||
|
||||
var project *Project
|
||||
|
||||
contents, err := g.buildAndExecRequestRaw("GET", url, opaque, nil)
|
||||
if err == nil {
|
||||
err = json.Unmarshal(contents, &project)
|
||||
}
|
||||
|
||||
return project, err
|
||||
}
|
||||
|
||||
/*
|
||||
Lists all branches of a project.
|
||||
*/
|
||||
func (g *Gitlab) ProjectBranches(id string) ([]*Branch, error) {
|
||||
|
||||
url, opaque := g.ResourceUrlRaw(project_url_branches, map[string]string{":id": id})
|
||||
|
||||
var branches []*Branch
|
||||
|
||||
contents, err := g.buildAndExecRequestRaw("GET", url, opaque, nil)
|
||||
if err == nil {
|
||||
err = json.Unmarshal(contents, &branches)
|
||||
}
|
||||
|
||||
return branches, err
|
||||
}
|
||||
|
||||
func (g *Gitlab) ProjectMembers(id string) ([]*Member, error) {
|
||||
url, opaque := g.ResourceUrlRaw(project_url_members, map[string]string{":id": id})
|
||||
|
||||
var members []*Member
|
||||
|
||||
contents, err := g.buildAndExecRequestRaw("GET", url, opaque, nil)
|
||||
if err == nil {
|
||||
err = json.Unmarshal(contents, &members)
|
||||
}
|
||||
|
||||
return members, err
|
||||
}
|
||||
|
||||
/*
|
||||
Lists all merge requests of a project.
|
||||
*/
|
||||
func (g *Gitlab) ProjectMergeRequests(id string, page int, per_page int, state string) ([]*MergeRequest, error) {
|
||||
par := map[string]string{":id": id}
|
||||
qry := map[string]string{
|
||||
"state": state,
|
||||
"page": strconv.Itoa(page),
|
||||
"per_page": strconv.Itoa(per_page)}
|
||||
url := g.ResourceUrlQuery(project_url_merge_requests, par, qry)
|
||||
|
||||
var mr []*MergeRequest
|
||||
|
||||
contents, err := g.buildAndExecRequest("GET", url, nil)
|
||||
if err == nil {
|
||||
err = json.Unmarshal(contents, &mr)
|
||||
}
|
||||
|
||||
return mr, err
|
||||
}
|
||||
|
||||
/*
|
||||
Lists all comments on merge request.
|
||||
*/
|
||||
func (g *Gitlab) MergeRequestNotes(id string, merge_request_id string, page int, per_page int) ([]*MergeRequestNote, error) {
|
||||
par := map[string]string{":id": id, ":merge_request_id": merge_request_id}
|
||||
qry := map[string]string{
|
||||
"page": strconv.Itoa(page),
|
||||
"per_page": strconv.Itoa(per_page)}
|
||||
url := g.ResourceUrlQuery(merge_request_url_notes, par, qry)
|
||||
|
||||
var mr []*MergeRequestNote
|
||||
|
||||
contents, err := g.buildAndExecRequest("GET", url, nil)
|
||||
if err == nil {
|
||||
err = json.Unmarshal(contents, &mr)
|
||||
}
|
||||
|
||||
return mr, err
|
||||
}
|
||||
|
||||
/*
|
||||
Creates a new comment on a merge request.
|
||||
*/
|
||||
func (g *Gitlab) SendMergeRequestComment(id string, merge_request_id string, comment string) (*MergeRequestNote, error) {
|
||||
par := map[string]string{":id": id, ":merge_request_id": merge_request_id}
|
||||
url := g.ResourceUrlQuery(merge_request_url_notes, par, map[string]string{})
|
||||
|
||||
var mr *MergeRequestNote
|
||||
|
||||
contents, err := g.buildAndExecRequest("POST", url, []byte(fmt.Sprintf("body=%s", comment)))
|
||||
if err == nil {
|
||||
err = json.Unmarshal(contents, &mr)
|
||||
}
|
||||
|
||||
return mr, err
|
||||
}
|
||||
|
||||
/*
|
||||
Get single project id.
|
||||
|
||||
GET /projects/search/:query
|
||||
|
||||
Parameters:
|
||||
|
||||
namespace The namespace of a project
|
||||
name The id of a project
|
||||
|
||||
*/
|
||||
func (g *Gitlab) SearchProjectId(namespace string, name string) (id int, err error) {
|
||||
|
||||
url, opaque := g.ResourceUrlRaw(projects_search_url, map[string]string{
|
||||
":query": strings.ToLower(name),
|
||||
})
|
||||
|
||||
var projects []*Project
|
||||
|
||||
contents, err := g.buildAndExecRequestRaw("GET", url, opaque, nil)
|
||||
if err == nil {
|
||||
err = json.Unmarshal(contents, &projects)
|
||||
} else {
|
||||
return id, err
|
||||
}
|
||||
|
||||
for _, project := range projects {
|
||||
if project.Namespace.Name == namespace && strings.ToLower(project.Name) == strings.ToLower(name) {
|
||||
id = project.Id
|
||||
}
|
||||
}
|
||||
|
||||
return id, err
|
||||
}
|
85
vendor/github.com/Bugagazavr/go-gitlab-client/projects_test.go
generated
vendored
85
vendor/github.com/Bugagazavr/go-gitlab-client/projects_test.go
generated
vendored
|
@ -1,85 +0,0 @@
|
|||
package gogitlab
|
||||
|
||||
import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestALlProjects(t *testing.T) {
|
||||
ts, gitlab := Stub("stubs/projects/index.json")
|
||||
projects, err := gitlab.AllProjects()
|
||||
|
||||
assert.Equal(t, err, nil)
|
||||
assert.Equal(t, len(projects), 2)
|
||||
defer ts.Close()
|
||||
}
|
||||
|
||||
func TestProjects(t *testing.T) {
|
||||
ts, gitlab := Stub("stubs/projects/index.json")
|
||||
projects, err := gitlab.Projects(1, 100)
|
||||
|
||||
assert.Equal(t, err, nil)
|
||||
assert.Equal(t, len(projects), 2)
|
||||
defer ts.Close()
|
||||
}
|
||||
|
||||
func TestProject(t *testing.T) {
|
||||
ts, gitlab := Stub("stubs/projects/show.json")
|
||||
project, err := gitlab.Project("1")
|
||||
|
||||
assert.Equal(t, err, nil)
|
||||
assert.IsType(t, new(Project), project)
|
||||
assert.Equal(t, project.SshRepoUrl, "git@example.com:diaspora/diaspora-project-site.git")
|
||||
assert.Equal(t, project.HttpRepoUrl, "http://example.com/diaspora/diaspora-project-site.git")
|
||||
defer ts.Close()
|
||||
}
|
||||
|
||||
func TestProjectBranches(t *testing.T) {
|
||||
ts, gitlab := Stub("stubs/projects/branches/index.json")
|
||||
branches, err := gitlab.ProjectBranches("1")
|
||||
|
||||
assert.Equal(t, err, nil)
|
||||
assert.Equal(t, len(branches), 2)
|
||||
defer ts.Close()
|
||||
}
|
||||
|
||||
func TestProjectMergeRequests(t *testing.T) {
|
||||
ts, gitlab := Stub("stubs/projects/merge_requests/index.json")
|
||||
defer ts.Close()
|
||||
mr, err := gitlab.ProjectMergeRequests("1", 0, 30, "all")
|
||||
|
||||
assert.Equal(t, err, nil)
|
||||
assert.Equal(t, len(mr), 1)
|
||||
|
||||
if len(mr) > 0 {
|
||||
assert.Equal(t, mr[0].TargetBranch, "master")
|
||||
assert.Equal(t, mr[0].SourceBranch, "test1")
|
||||
}
|
||||
}
|
||||
|
||||
func TestMergeRequestNotes(t *testing.T) {
|
||||
ts, gitlab := Stub("stubs/projects/merge_requests/notes/index.json")
|
||||
defer ts.Close()
|
||||
notes, err := gitlab.MergeRequestNotes("1", "1", 0, 30)
|
||||
|
||||
assert.Equal(t, err, nil)
|
||||
assert.Equal(t, len(notes), 1)
|
||||
|
||||
if len(notes) > 0 {
|
||||
assert.Equal(t, notes[0].Id, 301)
|
||||
assert.Equal(t, notes[0].Body, "Comment for MR")
|
||||
assert.Equal(t, notes[0].Author.Username, "pipin")
|
||||
}
|
||||
}
|
||||
|
||||
func TestSearchProjectId(t *testing.T) {
|
||||
ts, gitlab := Stub("stubs/projects/index.json")
|
||||
|
||||
namespace := "Brightbox"
|
||||
name := "Puppet"
|
||||
id, err := gitlab.SearchProjectId(namespace, name)
|
||||
|
||||
assert.Equal(t, err, nil)
|
||||
assert.Equal(t, id, 6)
|
||||
defer ts.Close()
|
||||
}
|
69
vendor/github.com/Bugagazavr/go-gitlab-client/public_keys.go
generated
vendored
69
vendor/github.com/Bugagazavr/go-gitlab-client/public_keys.go
generated
vendored
|
@ -1,69 +0,0 @@
|
|||
package gogitlab
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/url"
|
||||
)
|
||||
|
||||
const (
|
||||
// ID
|
||||
user_keys = "/user/keys" // Get current user keys
|
||||
user_key = "/user/keys/:id" // Get user key by id
|
||||
custom_user_keys = "/user/:id/keys" // Create key for user with :id
|
||||
)
|
||||
|
||||
type PublicKey struct {
|
||||
Id int `json:"id,omitempty"`
|
||||
Title string `json:"title,omitempty"`
|
||||
Key string `json:"key,omitempty"`
|
||||
CreatedAtRaw string `json:"created_at,omitempty"`
|
||||
}
|
||||
|
||||
func (g *Gitlab) UserKeys() ([]*PublicKey, error) {
|
||||
url := g.ResourceUrl(user_keys, nil)
|
||||
var keys []*PublicKey
|
||||
contents, err := g.buildAndExecRequest("GET", url, nil)
|
||||
if err == nil {
|
||||
err = json.Unmarshal(contents, &keys)
|
||||
}
|
||||
return keys, err
|
||||
}
|
||||
|
||||
func (g *Gitlab) UserKey(id string) (*PublicKey, error) {
|
||||
url := g.ResourceUrl(user_key, map[string]string{":id": id})
|
||||
var key *PublicKey
|
||||
contents, err := g.buildAndExecRequest("GET", url, nil)
|
||||
if err == nil {
|
||||
err = json.Unmarshal(contents, &key)
|
||||
}
|
||||
return key, err
|
||||
}
|
||||
|
||||
func (g *Gitlab) AddKey(title, key string) error {
|
||||
path := g.ResourceUrl(user_keys, nil)
|
||||
var err error
|
||||
v := url.Values{}
|
||||
v.Set("title", title)
|
||||
v.Set("key", key)
|
||||
body := v.Encode()
|
||||
_, err = g.buildAndExecRequest("POST", path, []byte(body))
|
||||
return err
|
||||
}
|
||||
|
||||
func (g *Gitlab) AddUserKey(id, title, key string) error {
|
||||
path := g.ResourceUrl(user_keys, map[string]string{":id": id})
|
||||
var err error
|
||||
v := url.Values{}
|
||||
v.Set("title", title)
|
||||
v.Set("key", key)
|
||||
body := v.Encode()
|
||||
_, err = g.buildAndExecRequest("POST", path, []byte(body))
|
||||
return err
|
||||
}
|
||||
|
||||
func (g *Gitlab) DeleteKey(id string) error {
|
||||
url := g.ResourceUrl(user_key, map[string]string{":id": id})
|
||||
var err error
|
||||
_, err = g.buildAndExecRequest("DELETE", url, nil)
|
||||
return err
|
||||
}
|
50
vendor/github.com/Bugagazavr/go-gitlab-client/public_keys_test.go
generated
vendored
50
vendor/github.com/Bugagazavr/go-gitlab-client/public_keys_test.go
generated
vendored
|
@ -1,50 +0,0 @@
|
|||
package gogitlab
|
||||
|
||||
import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestGetUserKeys(t *testing.T) {
|
||||
ts, gitlab := Stub("stubs/public_keys/index.json")
|
||||
keys, err := gitlab.UserKeys()
|
||||
|
||||
assert.Equal(t, err, nil)
|
||||
assert.Equal(t, len(keys), 2)
|
||||
defer ts.Close()
|
||||
}
|
||||
|
||||
func TestGetUserKey(t *testing.T) {
|
||||
ts, gitlab := Stub("stubs/public_keys/show.json")
|
||||
key, err := gitlab.UserKey("1")
|
||||
|
||||
assert.Equal(t, err, nil)
|
||||
assert.IsType(t, new(PublicKey), key)
|
||||
assert.Equal(t, key.Title, "Public key")
|
||||
assert.Equal(t, key.Key, "ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAIEAiPWx6WM4lhHNedGfBpPJNPpZ7yKu+dnn1SJejgt4596k6YjzGGphH2TUxwKzxcKDKKezwkpfnxPkSMkuEspGRt/aZZ9wa++Oi7Qkr8prgHc4soW6NUlfDzpvZK2H5E7eQaSeP3SAwGmQKUFHCddNaP0L+hM7zhFNzjFvpaMgJw0=")
|
||||
defer ts.Close()
|
||||
}
|
||||
|
||||
func TestAddKey(t *testing.T) {
|
||||
ts, gitlab := Stub("")
|
||||
err := gitlab.AddKey("Public key", "stubbed key")
|
||||
|
||||
assert.Equal(t, err, nil)
|
||||
defer ts.Close()
|
||||
}
|
||||
|
||||
func TestAddUserKey(t *testing.T) {
|
||||
ts, gitlab := Stub("")
|
||||
err := gitlab.AddUserKey("1", "Public key", "stubbed key")
|
||||
|
||||
assert.Equal(t, err, nil)
|
||||
defer ts.Close()
|
||||
}
|
||||
|
||||
func TestDeleteKey(t *testing.T) {
|
||||
ts, gitlab := Stub("")
|
||||
err := gitlab.DeleteKey("1")
|
||||
|
||||
assert.Equal(t, err, nil)
|
||||
defer ts.Close()
|
||||
}
|
323
vendor/github.com/Bugagazavr/go-gitlab-client/repositories.go
generated
vendored
323
vendor/github.com/Bugagazavr/go-gitlab-client/repositories.go
generated
vendored
|
@ -1,323 +0,0 @@
|
|||
package gogitlab
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
repo_url_branches = "/projects/:id/repository/branches" // List repository branches
|
||||
repo_url_branch = "/projects/:id/repository/branches/:branch" // Get a specific branch of a project.
|
||||
repo_url_tags = "/projects/:id/repository/tags" // List project repository tags
|
||||
repo_url_commits = "/projects/:id/repository/commits" // List repository commits
|
||||
repo_url_commit_comments = "/projects/:id/repository/commits/:sha/comments" // New comment or list of commit comments
|
||||
repo_url_tree = "/projects/:id/repository/tree" // List repository tree
|
||||
repo_url_raw_file = "/projects/:id/repository/blobs/:sha" // Get raw file content for specific commit/branch
|
||||
)
|
||||
|
||||
type BranchCommit struct {
|
||||
Id string `json:"id,omitempty"`
|
||||
Tree string `json:"tree,omitempty"`
|
||||
AuthoredDateRaw string `json:"authored_date,omitempty"`
|
||||
CommittedDateRaw string `json:"committed_date,omitempty"`
|
||||
Message string `json:"message,omitempty"`
|
||||
Author *Person `json:"author,omitempty"`
|
||||
Committer *Person `json:"committer,omitempty"`
|
||||
/*
|
||||
"parents": [
|
||||
{"id": "9b0c4b08e7890337fc8111e66f809c8bbec467a9"},
|
||||
{"id": "3ac634dca850cab70ab14b43ad6073d1e0a7827f"}
|
||||
]
|
||||
*/
|
||||
}
|
||||
|
||||
type Branch struct {
|
||||
Name string `json:"name,omitempty"`
|
||||
Protected bool `json:"protected,omitempty"`
|
||||
Commit *BranchCommit `json:"commit,omitempty"`
|
||||
}
|
||||
|
||||
type Tag struct {
|
||||
Name string `json:"name,omitempty"`
|
||||
Protected bool `json:"protected,omitempty"`
|
||||
Commit *BranchCommit `json:"commit,omitempty"`
|
||||
}
|
||||
|
||||
type Commit struct {
|
||||
Id string
|
||||
Short_Id string
|
||||
Title string
|
||||
Author_Name string
|
||||
Author_Email string
|
||||
Created_At string
|
||||
CreatedAt time.Time
|
||||
}
|
||||
|
||||
type File struct {
|
||||
Id string `json:"id,omitempty"`
|
||||
Name string `json:"name,omitempty"`
|
||||
Type string `json:"type,omitempty"`
|
||||
Mode string `json:"mode,omitempty"`
|
||||
|
||||
Children []*File
|
||||
}
|
||||
|
||||
type CommitComment struct {
|
||||
Author *Member `json:"author,omitempty"`
|
||||
Line int `json:"line,omitempty"`
|
||||
LineType string `json:"line_type,omitempty"`
|
||||
Note string `json:"note,omitempty"`
|
||||
Path string `json:"path,omitempty"`
|
||||
}
|
||||
|
||||
/*
|
||||
Get a list of repository branches from a project, sorted by name alphabetically.
|
||||
|
||||
GET /projects/:id/repository/branches
|
||||
|
||||
Parameters:
|
||||
|
||||
id The ID of a project
|
||||
|
||||
Usage:
|
||||
|
||||
branches, err := gitlab.RepoBranches("your_projet_id")
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
}
|
||||
for _, branch := range branches {
|
||||
fmt.Printf("%+v\n", branch)
|
||||
}
|
||||
*/
|
||||
func (g *Gitlab) RepoBranches(id string) ([]*Branch, error) {
|
||||
|
||||
url, opaque := g.ResourceUrlRaw(repo_url_branches, map[string]string{":id": id})
|
||||
|
||||
var branches []*Branch
|
||||
|
||||
contents, err := g.buildAndExecRequestRaw("GET", url, opaque, nil)
|
||||
if err == nil {
|
||||
err = json.Unmarshal(contents, &branches)
|
||||
}
|
||||
|
||||
return branches, err
|
||||
}
|
||||
|
||||
/*
|
||||
Get a single project repository branch.
|
||||
|
||||
GET /projects/:id/repository/branches/:branch
|
||||
|
||||
Parameters:
|
||||
|
||||
id The ID of a project
|
||||
branch The name of the branch
|
||||
|
||||
*/
|
||||
func (g *Gitlab) RepoBranch(id, refName string) (*Branch, error) {
|
||||
|
||||
url, opaque := g.ResourceUrlRaw(repo_url_branch, map[string]string{
|
||||
":id": id,
|
||||
":branch": refName,
|
||||
})
|
||||
|
||||
branch := new(Branch)
|
||||
|
||||
contents, err := g.buildAndExecRequestRaw("GET", url, opaque, nil)
|
||||
if err == nil {
|
||||
err = json.Unmarshal(contents, &branch)
|
||||
}
|
||||
return branch, err
|
||||
}
|
||||
|
||||
/*
|
||||
Get a list of repository tags from a project, sorted by name in reverse alphabetical order.
|
||||
|
||||
GET /projects/:id/repository/tags
|
||||
|
||||
Parameters:
|
||||
|
||||
id The ID of a project
|
||||
|
||||
Usage:
|
||||
|
||||
tags, err := gitlab.RepoTags("your_projet_id")
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
}
|
||||
for _, tag := range tags {
|
||||
fmt.Printf("%+v\n", tag)
|
||||
}
|
||||
*/
|
||||
func (g *Gitlab) RepoTags(id string) ([]*Tag, error) {
|
||||
|
||||
url, opaque := g.ResourceUrlRaw(repo_url_tags, map[string]string{":id": id})
|
||||
|
||||
var tags []*Tag
|
||||
|
||||
contents, err := g.buildAndExecRequestRaw("GET", url, opaque, nil)
|
||||
if err == nil {
|
||||
err = json.Unmarshal(contents, &tags)
|
||||
}
|
||||
|
||||
return tags, err
|
||||
}
|
||||
|
||||
/*
|
||||
Get a list of repository commits in a project.
|
||||
|
||||
GET /projects/:id/repository/commits
|
||||
|
||||
Parameters:
|
||||
|
||||
id The ID of a project
|
||||
refName The name of a repository branch or tag or if not given the default branch
|
||||
|
||||
Usage:
|
||||
|
||||
commits, err := gitlab.RepoCommits("your_projet_id")
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
}
|
||||
for _, commit := range commits {
|
||||
fmt.Printf("%+v\n", commit)
|
||||
}
|
||||
*/
|
||||
func (g *Gitlab) RepoCommits(id string) ([]*Commit, error) {
|
||||
|
||||
url, opaque := g.ResourceUrlRaw(repo_url_commits, map[string]string{":id": id})
|
||||
|
||||
var commits []*Commit
|
||||
|
||||
contents, err := g.buildAndExecRequestRaw("GET", url, opaque, nil)
|
||||
if err == nil {
|
||||
err = json.Unmarshal(contents, &commits)
|
||||
if err == nil {
|
||||
for _, commit := range commits {
|
||||
t, _ := time.Parse(dateLayout, commit.Created_At)
|
||||
commit.CreatedAt = t
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return commits, err
|
||||
}
|
||||
|
||||
/*
|
||||
Get a list of comments in a repository commit.
|
||||
|
||||
GET /projects/:id/repository/commits/:sha/comments
|
||||
|
||||
Parameters:
|
||||
|
||||
id The ID of a project
|
||||
sha The sha of the commit
|
||||
|
||||
Usage:
|
||||
|
||||
comments, err := gitlab.RepoCommitComments("your_projet_id", "commit_sha")
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
}
|
||||
for _, comment := range comments {
|
||||
fmt.Printf("%+v\n", comment)
|
||||
}
|
||||
*/
|
||||
func (g *Gitlab) RepoCommitComments(id string, sha string) ([]*CommitComment, error) {
|
||||
|
||||
url, opaque := g.ResourceUrlRaw(repo_url_commit_comments, map[string]string{":id": id, ":sha": sha})
|
||||
|
||||
var comments []*CommitComment
|
||||
|
||||
contents, err := g.buildAndExecRequestRaw("GET", url, opaque, nil)
|
||||
if err == nil {
|
||||
err = json.Unmarshal(contents, &comments)
|
||||
}
|
||||
|
||||
return comments, err
|
||||
}
|
||||
|
||||
/*
|
||||
Create a comment in a repository commit.
|
||||
|
||||
POST /projects/:id/repository/commits/:sha/comments
|
||||
|
||||
Parameters:
|
||||
|
||||
id The ID of a project
|
||||
sha The sha of the commit
|
||||
body The body of the comment
|
||||
|
||||
Usage:
|
||||
|
||||
comment, err := gitlab.SendRepoCommitComment("your_projet_id", "commit_sha", "your comment goes here")
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
}
|
||||
fmt.Printf("%+v\n", comment)
|
||||
*/
|
||||
func (g *Gitlab) SendRepoCommitComment(id string, sha string, body string) (*CommitComment, error) {
|
||||
|
||||
url, opaque := g.ResourceUrlRaw(repo_url_commit_comments, map[string]string{":id": id, ":sha": sha})
|
||||
|
||||
var comment *CommitComment
|
||||
|
||||
contents, err := g.buildAndExecRequestRaw("POST", url, opaque, []byte(fmt.Sprintf("note=%s", body)))
|
||||
if err == nil {
|
||||
err = json.Unmarshal(contents, &comment)
|
||||
}
|
||||
|
||||
return comment, err
|
||||
}
|
||||
|
||||
/*
|
||||
Get Raw file content
|
||||
*/
|
||||
func (g *Gitlab) RepoRawFile(id, sha, filepath string) ([]byte, error) {
|
||||
url_ := g.ResourceUrlQuery(repo_url_raw_file, map[string]string{
|
||||
":id": id,
|
||||
":sha": sha,
|
||||
}, map[string]string{
|
||||
"filepath": filepath,
|
||||
})
|
||||
|
||||
p, err := url.Parse(url_)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
opaque := "//" + p.Host + p.Path
|
||||
contents, err := g.buildAndExecRequestRaw("GET", url_, opaque, nil)
|
||||
|
||||
return contents, err
|
||||
}
|
||||
|
||||
/*
|
||||
Get Raw file content
|
||||
*/
|
||||
func (g *Gitlab) RepoTree(id, ref, path string) ([]*File, error) {
|
||||
|
||||
url := g.ResourceUrlQuery(repo_url_tree, map[string]string{
|
||||
":id": id,
|
||||
}, map[string]string{
|
||||
"ref": ref,
|
||||
"path": path,
|
||||
})
|
||||
|
||||
var files []*File
|
||||
|
||||
contents, err := g.buildAndExecRequest("GET", url, nil)
|
||||
if err == nil {
|
||||
err = json.Unmarshal(contents, &files)
|
||||
}
|
||||
|
||||
for _, f := range files {
|
||||
if f.Type == "tree" {
|
||||
f.Children, err = g.RepoTree(id, ref, path+"/"+f.Name)
|
||||
}
|
||||
}
|
||||
|
||||
return files, err
|
||||
}
|
52
vendor/github.com/Bugagazavr/go-gitlab-client/repositories_test.go
generated
vendored
52
vendor/github.com/Bugagazavr/go-gitlab-client/repositories_test.go
generated
vendored
|
@ -1,52 +0,0 @@
|
|||
package gogitlab
|
||||
|
||||
import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestRepoBranches(t *testing.T) {
|
||||
ts, gitlab := Stub("stubs/branches/index.json")
|
||||
branches, err := gitlab.RepoBranches("1")
|
||||
|
||||
assert.Equal(t, err, nil)
|
||||
assert.Equal(t, len(branches), 1)
|
||||
defer ts.Close()
|
||||
}
|
||||
|
||||
func TestRepoBranch(t *testing.T) {
|
||||
ts, gitlab := Stub("stubs/branches/show.json")
|
||||
branch, err := gitlab.RepoBranch("1", "master")
|
||||
|
||||
assert.Equal(t, err, nil)
|
||||
assert.IsType(t, new(Branch), branch)
|
||||
assert.Equal(t, branch.Name, "master")
|
||||
defer ts.Close()
|
||||
}
|
||||
|
||||
func TestRepoTags(t *testing.T) {
|
||||
ts, gitlab := Stub("stubs/tags/index.json")
|
||||
tags, err := gitlab.RepoTags("1")
|
||||
|
||||
assert.Equal(t, err, nil)
|
||||
assert.Equal(t, len(tags), 1)
|
||||
defer ts.Close()
|
||||
}
|
||||
|
||||
func TestRepoCommits(t *testing.T) {
|
||||
ts, gitlab := Stub("stubs/commits/index.json")
|
||||
commits, err := gitlab.RepoCommits("1")
|
||||
|
||||
assert.Equal(t, err, nil)
|
||||
assert.Equal(t, len(commits), 2)
|
||||
defer ts.Close()
|
||||
}
|
||||
|
||||
func TestRepoCommitComments(t *testing.T) {
|
||||
ts, gitlab := Stub("stubs/commits/comments/index.json")
|
||||
comments, err := gitlab.RepoCommitComments("1", "a9e6a5io4e695923c995ed2e836789b50oi77e0b")
|
||||
|
||||
assert.Equal(t, err, nil)
|
||||
assert.Equal(t, len(comments), 1)
|
||||
defer ts.Close()
|
||||
}
|
19
vendor/github.com/Bugagazavr/go-gitlab-client/services.go
generated
vendored
19
vendor/github.com/Bugagazavr/go-gitlab-client/services.go
generated
vendored
|
@ -1,19 +0,0 @@
|
|||
package gogitlab
|
||||
|
||||
const (
|
||||
drone_service_url = "/projects/:id/services/drone-ci"
|
||||
)
|
||||
|
||||
func (g *Gitlab) AddDroneService(id string, params map[string]string) error {
|
||||
url, opaque := g.ResourceUrlQueryRaw(drone_service_url, map[string]string{":id": id}, params)
|
||||
|
||||
_, err := g.buildAndExecRequestRaw("PUT", url, opaque, nil)
|
||||
return err
|
||||
}
|
||||
|
||||
func (g *Gitlab) DeleteDroneService(id string) error {
|
||||
url, opaque := g.ResourceUrlQueryRaw(drone_service_url, map[string]string{":id": id}, nil)
|
||||
|
||||
_, err := g.buildAndExecRequestRaw("DELETE", url, opaque, nil)
|
||||
return err
|
||||
}
|
54
vendor/github.com/Bugagazavr/go-gitlab-client/session.go
generated
vendored
54
vendor/github.com/Bugagazavr/go-gitlab-client/session.go
generated
vendored
|
@ -1,54 +0,0 @@
|
|||
package gogitlab
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/url"
|
||||
)
|
||||
|
||||
const (
|
||||
session_path = "/session"
|
||||
)
|
||||
|
||||
type Session struct {
|
||||
Id int `json:"id"`
|
||||
UserName string `json:"username"`
|
||||
Name string `json:"name"`
|
||||
Blocked bool `json:"blocked"`
|
||||
State string `json:"state"`
|
||||
AvatarURL string `json:"avatar_url",omitempty`
|
||||
IsAdmin bool `json:"is_admin"`
|
||||
Bio string `json:"bio",omitempty`
|
||||
Email string `json:"email"`
|
||||
ThemeId int `json:"theme_id",omitempty`
|
||||
ColorSchemeId int `json:"color_scheme_id",omitempty`
|
||||
ExternUid string `json:"extern_uid",omitempty`
|
||||
Provider string `json:"provider",omitempty`
|
||||
CanCreateGroup bool `json:"can_create_group"`
|
||||
CanCreateProject bool `json:"can_create_project"`
|
||||
Skype string `json:"skype",omitempty`
|
||||
Twitter string `json:"twitter",omitempty`
|
||||
LinkedIn string `json:"linkedin",omitempty`
|
||||
WebsiteURL string `json:"website_url",omitempty`
|
||||
PrivateToken string `json:"private_token"`
|
||||
}
|
||||
|
||||
func (g *Gitlab) GetSession(email string, password string) (*Session, error) {
|
||||
session_url := g.ResourceUrl(session_path, map[string]string{})
|
||||
|
||||
var session *Session
|
||||
|
||||
v := url.Values{}
|
||||
v.Set("email", email)
|
||||
v.Set("password", password)
|
||||
|
||||
body := v.Encode()
|
||||
|
||||
contents, err := g.buildAndExecRequest("POST", session_url, []byte(body))
|
||||
if err != nil {
|
||||
return session, err
|
||||
}
|
||||
|
||||
err = json.Unmarshal(contents, &session)
|
||||
|
||||
return session, err
|
||||
}
|
33
vendor/github.com/Bugagazavr/go-gitlab-client/session_test.go
generated
vendored
33
vendor/github.com/Bugagazavr/go-gitlab-client/session_test.go
generated
vendored
|
@ -1,33 +0,0 @@
|
|||
package gogitlab
|
||||
|
||||
import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestGetSesison(t *testing.T) {
|
||||
ts, gitlab := Stub("stubs/session/index.json")
|
||||
session, err := gitlab.GetSession("john@example.com", "samplepassword")
|
||||
|
||||
assert.Equal(t, err, nil)
|
||||
assert.Equal(t, session.Id, 1)
|
||||
assert.Equal(t, session.UserName, "john_smith")
|
||||
assert.Equal(t, session.Name, "John Smith")
|
||||
assert.Equal(t, session.State, "active")
|
||||
assert.Equal(t, session.AvatarURL, "http://someurl.com/avatar.png")
|
||||
assert.Equal(t, session.IsAdmin, false)
|
||||
assert.Equal(t, session.Bio, "somebio")
|
||||
assert.Equal(t, session.Skype, "someskype")
|
||||
assert.Equal(t, session.LinkedIn, "somelinkedin")
|
||||
assert.Equal(t, session.Twitter, "sometwitter")
|
||||
assert.Equal(t, session.WebsiteURL, "http://example.com")
|
||||
assert.Equal(t, session.Email, "john@example.com")
|
||||
assert.Equal(t, session.ThemeId, 1)
|
||||
assert.Equal(t, session.ColorSchemeId, 1)
|
||||
assert.Equal(t, session.ExternUid, "someuid")
|
||||
assert.Equal(t, session.Provider, "github.com")
|
||||
assert.Equal(t, session.CanCreateGroup, true)
|
||||
assert.Equal(t, session.CanCreateProject, true)
|
||||
assert.Equal(t, session.PrivateToken, "dd34asd13as")
|
||||
defer ts.Close()
|
||||
}
|
26
vendor/github.com/Bugagazavr/go-gitlab-client/stubs/branches/index.json
generated
vendored
26
vendor/github.com/Bugagazavr/go-gitlab-client/stubs/branches/index.json
generated
vendored
|
@ -1,26 +0,0 @@
|
|||
[
|
||||
{
|
||||
"name": "master",
|
||||
"commit": {
|
||||
"id": "7b5c3cc8be40ee161ae89a06bba6229da1032a0c",
|
||||
"parents": [
|
||||
{
|
||||
"id": "4ad91d3c1144c406e50c7b33bae684bd6837faf8"
|
||||
}
|
||||
],
|
||||
"tree": "46e82de44b1061621357f24c05515327f2795a95",
|
||||
"message": "add projects API",
|
||||
"author": {
|
||||
"name": "John Smith",
|
||||
"email": "john@example.com"
|
||||
},
|
||||
"committer": {
|
||||
"name": "John Smith",
|
||||
"email": "john@example.com"
|
||||
},
|
||||
"authored_date": "2012-06-27T05:51:39-07:00",
|
||||
"committed_date": "2012-06-28T03:44:20-07:00"
|
||||
},
|
||||
"protected": true
|
||||
}
|
||||
]
|
24
vendor/github.com/Bugagazavr/go-gitlab-client/stubs/branches/show.json
generated
vendored
24
vendor/github.com/Bugagazavr/go-gitlab-client/stubs/branches/show.json
generated
vendored
|
@ -1,24 +0,0 @@
|
|||
{
|
||||
"name": "master",
|
||||
"commit": {
|
||||
"id": "7b5c3cc8be40ee161ae89a06bba6229da1032a0c",
|
||||
"parents": [
|
||||
{
|
||||
"id": "4ad91d3c1144c406e50c7b33bae684bd6837faf8"
|
||||
}
|
||||
],
|
||||
"tree": "46e82de44b1061621357f24c05515327f2795a95",
|
||||
"message": "add projects API",
|
||||
"author": {
|
||||
"name": "John Smith",
|
||||
"email": "john@example.com"
|
||||
},
|
||||
"committer": {
|
||||
"name": "John Smith",
|
||||
"email": "john@example.com"
|
||||
},
|
||||
"authored_date": "2012-06-27T05:51:39-07:00",
|
||||
"committed_date": "2012-06-28T03:44:20-07:00"
|
||||
},
|
||||
"protected": true
|
||||
}
|
16
vendor/github.com/Bugagazavr/go-gitlab-client/stubs/commits/comments/index.json
generated
vendored
16
vendor/github.com/Bugagazavr/go-gitlab-client/stubs/commits/comments/index.json
generated
vendored
|
@ -1,16 +0,0 @@
|
|||
[
|
||||
{
|
||||
"author": {
|
||||
"id": 1,
|
||||
"username": "admin",
|
||||
"email": "admin@local.host",
|
||||
"name": "Administrator",
|
||||
"blocked": false,
|
||||
"created_at": "2012-04-29T08:46:00Z"
|
||||
},
|
||||
"note": "text1",
|
||||
"path": "example.rb",
|
||||
"line": 5,
|
||||
"line_type": "new"
|
||||
}
|
||||
]
|
18
vendor/github.com/Bugagazavr/go-gitlab-client/stubs/commits/index.json
generated
vendored
18
vendor/github.com/Bugagazavr/go-gitlab-client/stubs/commits/index.json
generated
vendored
|
@ -1,18 +0,0 @@
|
|||
[
|
||||
{
|
||||
"id": "ed899a2f4b50b4370feeea94676502b42383c746",
|
||||
"short_id": "ed899a2f4b5",
|
||||
"title": "Replace sanitize with escape once",
|
||||
"author_name": "Dmitriy Zaporozhets",
|
||||
"author_email": "dzaporozhets@sphereconsultinginc.com",
|
||||
"created_at": "2012-09-20T11:50:22+03:00"
|
||||
},
|
||||
{
|
||||
"id": "6104942438c14ec7bd21c6cd5bd995272b3faff6",
|
||||
"short_id": "6104942438c",
|
||||
"title": "Sanitize for network graph",
|
||||
"author_name": "randx",
|
||||
"author_email": "dmitriy.zaporozhets@gmail.com",
|
||||
"created_at": "2012-09-20T09:06:12+03:00"
|
||||
}
|
||||
]
|
18
vendor/github.com/Bugagazavr/go-gitlab-client/stubs/hook_payloads/issue.json
generated
vendored
18
vendor/github.com/Bugagazavr/go-gitlab-client/stubs/hook_payloads/issue.json
generated
vendored
|
@ -1,18 +0,0 @@
|
|||
{
|
||||
"object_kind": "issue",
|
||||
"object_attributes": {
|
||||
"id": 301,
|
||||
"title": "New API: create/update/delete file",
|
||||
"assignee_id": 51,
|
||||
"author_id": 51,
|
||||
"project_id": 14,
|
||||
"created_at": "2013-12-03T17:15:43Z",
|
||||
"updated_at": "2013-12-03T17:15:43Z",
|
||||
"position": 0,
|
||||
"branch_name": null,
|
||||
"description": "Create new API for manipulations with repository",
|
||||
"milestone_id": null,
|
||||
"state": "opened",
|
||||
"iid": 23
|
||||
}
|
||||
}
|
22
vendor/github.com/Bugagazavr/go-gitlab-client/stubs/hook_payloads/merge_request.json
generated
vendored
22
vendor/github.com/Bugagazavr/go-gitlab-client/stubs/hook_payloads/merge_request.json
generated
vendored
|
@ -1,22 +0,0 @@
|
|||
{
|
||||
"object_kind": "merge_request",
|
||||
"object_attributes": {
|
||||
"id": 99,
|
||||
"target_branch": "master",
|
||||
"source_branch": "ms-viewport",
|
||||
"source_project_id": 14,
|
||||
"author_id": 51,
|
||||
"assignee_id": 6,
|
||||
"title": "MS-Viewport",
|
||||
"created_at": "2013-12-03T17:23:34Z",
|
||||
"updated_at": "2013-12-03T17:23:34Z",
|
||||
"st_commits": null,
|
||||
"st_diffs": null,
|
||||
"milestone_id": null,
|
||||
"state": "opened",
|
||||
"merge_status": "unchecked",
|
||||
"target_project_id": 14,
|
||||
"iid": 1,
|
||||
"description": ""
|
||||
}
|
||||
}
|
42
vendor/github.com/Bugagazavr/go-gitlab-client/stubs/hook_payloads/push.json
generated
vendored
42
vendor/github.com/Bugagazavr/go-gitlab-client/stubs/hook_payloads/push.json
generated
vendored
|
@ -1,42 +0,0 @@
|
|||
{
|
||||
"object_kind": "push",
|
||||
"before": "95790bf891e76fee5e1747ab589903a6a1f80f22",
|
||||
"after": "da1560886d4f094c3e6c9ef40349f7d38b5d27d7",
|
||||
"ref": "refs/heads/master",
|
||||
"user_id": 4,
|
||||
"user_name": "John Smith",
|
||||
"user_email": "john@example.com",
|
||||
"project_id": 15,
|
||||
"repository": {
|
||||
"name": "Diaspora",
|
||||
"url": "git@example.com:mike/diasporadiaspora.git",
|
||||
"description": "",
|
||||
"homepage": "http://example.com/mike/diaspora",
|
||||
"git_http_url":"http://example.com/mike/diaspora.git",
|
||||
"git_ssh_url":"git@example.com:mike/diaspora.git",
|
||||
"visibility_level":0
|
||||
},
|
||||
"commits": [
|
||||
{
|
||||
"id": "b6568db1bc1dcd7f8b4d5a946b0b91f9dacd7327",
|
||||
"message": "Update Catalan translation to e38cb41.",
|
||||
"timestamp": "2011-12-12T14:27:31+02:00",
|
||||
"url": "http://example.com/mike/diaspora/commit/b6568db1bc1dcd7f8b4d5a946b0b91f9dacd7327",
|
||||
"author": {
|
||||
"name": "Jordi Mallach",
|
||||
"email": "jordi@softcatala.org"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "da1560886d4f094c3e6c9ef40349f7d38b5d27d7",
|
||||
"message": "fixed readme",
|
||||
"timestamp": "2012-01-03T23:36:29+02:00",
|
||||
"url": "http://example.com/mike/diaspora/commit/da1560886d4f094c3e6c9ef40349f7d38b5d27d7",
|
||||
"author": {
|
||||
"name": "GitLab dev user",
|
||||
"email": "gitlabdev@dv6700.(none)"
|
||||
}
|
||||
}
|
||||
],
|
||||
"total_commits_count": 4
|
||||
}
|
9
vendor/github.com/Bugagazavr/go-gitlab-client/stubs/hooks/show.json
generated
vendored
9
vendor/github.com/Bugagazavr/go-gitlab-client/stubs/hooks/show.json
generated
vendored
|
@ -1,9 +0,0 @@
|
|||
{
|
||||
"id": 1,
|
||||
"url": "http://example.com/hook",
|
||||
"project_id": 3,
|
||||
"push_events": "true",
|
||||
"issues_events": "true",
|
||||
"merge_requests_events": "true",
|
||||
"created_at": "2012-10-12T17:04:47Z"
|
||||
}
|
50
vendor/github.com/Bugagazavr/go-gitlab-client/stubs/projects/branches/index.json
generated
vendored
50
vendor/github.com/Bugagazavr/go-gitlab-client/stubs/projects/branches/index.json
generated
vendored
|
@ -1,50 +0,0 @@
|
|||
[
|
||||
{
|
||||
"name": "async",
|
||||
"commit": {
|
||||
"id": "a2b702edecdf41f07b42653eb1abe30ce98b9fca",
|
||||
"parents": [
|
||||
{
|
||||
"id": "3f94fc7c85061973edc9906ae170cc269b07ca55"
|
||||
}
|
||||
],
|
||||
"tree": "c68537c6534a02cc2b176ca1549f4ffa190b58ee",
|
||||
"message": "give caolan credit where it's due (up top)",
|
||||
"author": {
|
||||
"name": "Jeremy Ashkenas",
|
||||
"email": "jashkenas@example.com"
|
||||
},
|
||||
"committer": {
|
||||
"name": "Jeremy Ashkenas",
|
||||
"email": "jashkenas@example.com"
|
||||
},
|
||||
"authored_date": "2010-12-08T21:28:50+00:00",
|
||||
"committed_date": "2010-12-08T21:28:50+00:00"
|
||||
},
|
||||
"protected": false
|
||||
},
|
||||
{
|
||||
"name": "gh-pages",
|
||||
"commit": {
|
||||
"id": "101c10a60019fe870d21868835f65c25d64968fc",
|
||||
"parents": [
|
||||
{
|
||||
"id": "9c15d2e26945a665131af5d7b6d30a06ba338aaa"
|
||||
}
|
||||
],
|
||||
"tree": "fb5cc9d45da3014b17a876ad539976a0fb9b352a",
|
||||
"message": "Underscore.js 1.5.2",
|
||||
"author": {
|
||||
"name": "Jeremy Ashkenas",
|
||||
"email": "jashkenas@example.com"
|
||||
},
|
||||
"committer": {
|
||||
"name": "Jeremy Ashkenas",
|
||||
"email": "jashkenas@example.com"
|
||||
},
|
||||
"authored_date": "2013-09-07T12: 58: 21+00: 00",
|
||||
"committed_date": "2013-09-07T12: 58: 21+00: 00"
|
||||
},
|
||||
"protected": false
|
||||
}
|
||||
]
|
72
vendor/github.com/Bugagazavr/go-gitlab-client/stubs/projects/index.json
generated
vendored
72
vendor/github.com/Bugagazavr/go-gitlab-client/stubs/projects/index.json
generated
vendored
|
@ -1,72 +0,0 @@
|
|||
[
|
||||
{
|
||||
"id": 4,
|
||||
"description": null,
|
||||
"default_branch": "master",
|
||||
"public": false,
|
||||
"visibility_level": 0,
|
||||
"ssh_url_to_repo": "git@example.com:diaspora/diaspora-client.git",
|
||||
"http_url_to_repo": "http://example.com/diaspora/diaspora-client.git",
|
||||
"web_url": "http://example.com/diaspora/diaspora-client",
|
||||
"owner": {
|
||||
"id": 3,
|
||||
"name": "Diaspora",
|
||||
"created_at": "2013-09-30T13: 46: 02Z"
|
||||
},
|
||||
"name": "Diaspora Client",
|
||||
"name_with_namespace": "Diaspora / Diaspora Client",
|
||||
"path": "diaspora-client",
|
||||
"path_with_namespace": "diaspora/diaspora-client",
|
||||
"issues_enabled": true,
|
||||
"merge_requests_enabled": true,
|
||||
"wall_enabled": false,
|
||||
"wiki_enabled": true,
|
||||
"snippets_enabled": false,
|
||||
"created_at": "2013-09-30T13: 46: 02Z",
|
||||
"last_activity_at": "2013-09-30T13: 46: 02Z",
|
||||
"namespace": {
|
||||
"created_at": "2013-09-30T13: 46: 02Z",
|
||||
"description": "",
|
||||
"id": 3,
|
||||
"name": "Diaspora",
|
||||
"owner_id": 1,
|
||||
"path": "diaspora",
|
||||
"updated_at": "2013-09-30T13: 46: 02Z"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 6,
|
||||
"description": null,
|
||||
"default_branch": "master",
|
||||
"public": false,
|
||||
"visibility_level": 0,
|
||||
"ssh_url_to_repo": "git@example.com:brightbox/puppet.git",
|
||||
"http_url_to_repo": "http://example.com/brightbox/puppet.git",
|
||||
"web_url": "http://example.com/brightbox/puppet",
|
||||
"owner": {
|
||||
"id": 4,
|
||||
"name": "Brightbox",
|
||||
"created_at": "2013-09-30T13:46:02Z"
|
||||
},
|
||||
"name": "Puppet",
|
||||
"name_with_namespace": "Brightbox / Puppet",
|
||||
"path": "puppet",
|
||||
"path_with_namespace": "brightbox/puppet",
|
||||
"issues_enabled": true,
|
||||
"merge_requests_enabled": true,
|
||||
"wall_enabled": false,
|
||||
"wiki_enabled": true,
|
||||
"snippets_enabled": false,
|
||||
"created_at": "2013-09-30T13:46:02Z",
|
||||
"last_activity_at": "2013-09-30T13:46:02Z",
|
||||
"namespace": {
|
||||
"created_at": "2013-09-30T13:46:02Z",
|
||||
"description": "",
|
||||
"id": 4,
|
||||
"name": "Brightbox",
|
||||
"owner_id": 1,
|
||||
"path": "brightbox",
|
||||
"updated_at": "2013-09-30T13:46:02Z"
|
||||
}
|
||||
}
|
||||
]
|
30
vendor/github.com/Bugagazavr/go-gitlab-client/stubs/projects/merge_requests/index.json
generated
vendored
30
vendor/github.com/Bugagazavr/go-gitlab-client/stubs/projects/merge_requests/index.json
generated
vendored
|
@ -1,30 +0,0 @@
|
|||
[
|
||||
{
|
||||
"id": 1,
|
||||
"iid": 1,
|
||||
"target_branch": "master",
|
||||
"source_branch": "test1",
|
||||
"project_id": 3,
|
||||
"title": "test1",
|
||||
"state": "opened",
|
||||
"upvotes": 0,
|
||||
"downvotes": 0,
|
||||
"author": {
|
||||
"id": 1,
|
||||
"username": "admin",
|
||||
"email": "admin@example.com",
|
||||
"name": "Administrator",
|
||||
"state": "active",
|
||||
"created_at": "2012-04-29T08:46:00Z"
|
||||
},
|
||||
"assignee": {
|
||||
"id": 1,
|
||||
"username": "admin",
|
||||
"email": "admin@example.com",
|
||||
"name": "Administrator",
|
||||
"state": "active",
|
||||
"created_at": "2012-04-29T08:46:00Z"
|
||||
},
|
||||
"description":"fixed login page css paddings"
|
||||
}
|
||||
]
|
|
@ -1,16 +0,0 @@
|
|||
[
|
||||
{
|
||||
"id": 301,
|
||||
"body": "Comment for MR",
|
||||
"attachment": null,
|
||||
"author": {
|
||||
"id": 1,
|
||||
"username": "pipin",
|
||||
"email": "admin@example.com",
|
||||
"name": "Pip",
|
||||
"state": "active",
|
||||
"created_at": "2013-09-30T13:46:01Z"
|
||||
},
|
||||
"created_at": "2013-10-02T08:57:14Z"
|
||||
}
|
||||
]
|
45
vendor/github.com/Bugagazavr/go-gitlab-client/stubs/projects/show.json
generated
vendored
45
vendor/github.com/Bugagazavr/go-gitlab-client/stubs/projects/show.json
generated
vendored
|
@ -1,45 +0,0 @@
|
|||
{
|
||||
"id": 3,
|
||||
"description": null,
|
||||
"default_branch": "master",
|
||||
"public": false,
|
||||
"visibility_level": 0,
|
||||
"ssh_url_to_repo": "git@example.com:diaspora/diaspora-project-site.git",
|
||||
"http_url_to_repo": "http://example.com/diaspora/diaspora-project-site.git",
|
||||
"web_url": "http://example.com/diaspora/diaspora-project-site",
|
||||
"owner": {
|
||||
"id": 3,
|
||||
"name": "Diaspora",
|
||||
"created_at": "2013-09-30T13: 46: 02Z"
|
||||
},
|
||||
"name": "Diaspora Project Site",
|
||||
"name_with_namespace": "Diaspora / Diaspora Project Site",
|
||||
"path": "diaspora-project-site",
|
||||
"path_with_namespace": "diaspora/diaspora-project-site",
|
||||
"issues_enabled": true,
|
||||
"merge_requests_enabled": true,
|
||||
"wall_enabled": false,
|
||||
"wiki_enabled": true,
|
||||
"snippets_enabled": false,
|
||||
"created_at": "2013-09-30T13: 46: 02Z",
|
||||
"last_activity_at": "2013-09-30T13: 46: 02Z",
|
||||
"namespace": {
|
||||
"created_at": "2013-09-30T13: 46: 02Z",
|
||||
"description": "",
|
||||
"id": 3,
|
||||
"name": "Diaspora",
|
||||
"owner_id": 1,
|
||||
"path": "diaspora",
|
||||
"updated_at": "2013-09-30T13: 46: 02Z"
|
||||
},
|
||||
"permissions": {
|
||||
"project_access": {
|
||||
"access_level": 10,
|
||||
"notification_level": 3
|
||||
},
|
||||
"group_access": {
|
||||
"access_level": 50,
|
||||
"notification_level": 3
|
||||
}
|
||||
}
|
||||
}
|
12
vendor/github.com/Bugagazavr/go-gitlab-client/stubs/public_keys/index.json
generated
vendored
12
vendor/github.com/Bugagazavr/go-gitlab-client/stubs/public_keys/index.json
generated
vendored
|
@ -1,12 +0,0 @@
|
|||
[
|
||||
{
|
||||
"id": 1,
|
||||
"title": "Public key",
|
||||
"key": "ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAIEAiPWx6WM4lhHNedGfBpPJNPpZ7yKu+dnn1SJejgt4596k6YjzGGphH2TUxwKzxcKDKKezwkpfnxPkSMkuEspGRt/aZZ9wa++Oi7Qkr8prgHc4soW6NUlfDzpvZK2H5E7eQaSeP3SAwGmQKUFHCddNaP0L+hM7zhFNzjFvpaMgJw0="
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"title": "Another Public key",
|
||||
"key": "ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAIEAiPWx6WM4lhHNedGfBpPJNPpZ7yKu+dnn1SJejgt4596k6YjzGGphH2TUxwKzxcKDKKezwkpfnxPkSMkuEspGRt/aZZ9wa++Oi7Qkr8prgHc4soW6NUlfDzpvZK2H5E7eQaSeP3SAwGmQKUFHCddNaP0L+hM7zhFNzjFvpaMgJw0="
|
||||
}
|
||||
]
|
5
vendor/github.com/Bugagazavr/go-gitlab-client/stubs/public_keys/show.json
generated
vendored
5
vendor/github.com/Bugagazavr/go-gitlab-client/stubs/public_keys/show.json
generated
vendored
|
@ -1,5 +0,0 @@
|
|||
{
|
||||
"id": 1,
|
||||
"title": "Public key",
|
||||
"key": "ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAIEAiPWx6WM4lhHNedGfBpPJNPpZ7yKu+dnn1SJejgt4596k6YjzGGphH2TUxwKzxcKDKKezwkpfnxPkSMkuEspGRt/aZZ9wa++Oi7Qkr8prgHc4soW6NUlfDzpvZK2H5E7eQaSeP3SAwGmQKUFHCddNaP0L+hM7zhFNzjFvpaMgJw0="
|
||||
}
|
23
vendor/github.com/Bugagazavr/go-gitlab-client/stubs/session/index.json
generated
vendored
23
vendor/github.com/Bugagazavr/go-gitlab-client/stubs/session/index.json
generated
vendored
|
@ -1,23 +0,0 @@
|
|||
{
|
||||
"id": 1,
|
||||
"username": "john_smith",
|
||||
"email": "john@example.com",
|
||||
"name": "John Smith",
|
||||
"avatar_url": "http://someurl.com/avatar.png",
|
||||
"state": "active",
|
||||
"created_at": "2012-05-23T08:00:58Z",
|
||||
"bio": "somebio",
|
||||
"skype": "someskype",
|
||||
"linkedin": "somelinkedin",
|
||||
"twitter": "sometwitter",
|
||||
"website_url": "http://example.com",
|
||||
"theme_id": 1,
|
||||
"color_scheme_id": 1,
|
||||
"extern_uid": "someuid",
|
||||
"provider": "github.com",
|
||||
"is_admin": false,
|
||||
"can_create_group": true,
|
||||
"can_create_team": true,
|
||||
"can_create_project": true,
|
||||
"private_token": "dd34asd13as"
|
||||
}
|
22
vendor/github.com/Bugagazavr/go-gitlab-client/stubs/tags/index.json
generated
vendored
22
vendor/github.com/Bugagazavr/go-gitlab-client/stubs/tags/index.json
generated
vendored
|
@ -1,22 +0,0 @@
|
|||
[
|
||||
{
|
||||
"name": "v1.0.0",
|
||||
"commit": {
|
||||
"id": "2695effb5807a22ff3d138d593fd856244e155e7",
|
||||
"parents": [],
|
||||
"tree": "38017f2f189336fe4497e9d230c5bb1bf873f08d",
|
||||
"message": "Initial commit",
|
||||
"author": {
|
||||
"name": "John Smith",
|
||||
"email": "john@example.com"
|
||||
},
|
||||
"committer": {
|
||||
"name": "Jack Smith",
|
||||
"email": "jack@example.com"
|
||||
},
|
||||
"authored_date": "2012-05-28T04:42:42-07:00",
|
||||
"committed_date": "2012-05-28T04:42:42-07:00"
|
||||
},
|
||||
"protected": null
|
||||
}
|
||||
]
|
19
vendor/github.com/Bugagazavr/go-gitlab-client/stubs/users/current.json
generated
vendored
19
vendor/github.com/Bugagazavr/go-gitlab-client/stubs/users/current.json
generated
vendored
|
@ -1,19 +0,0 @@
|
|||
{
|
||||
"id": 1,
|
||||
"username": "john_smith",
|
||||
"email": "john@example.com",
|
||||
"name": "John Smith",
|
||||
"private_token": "dd34asd13as",
|
||||
"state": "active",
|
||||
"created_at": "2012-05-23T08:00:58Z",
|
||||
"bio": null,
|
||||
"skype": "",
|
||||
"linkedin": "",
|
||||
"twitter": "",
|
||||
"website_url": "",
|
||||
"theme_id": 1,
|
||||
"color_scheme_id": 2,
|
||||
"is_admin": false,
|
||||
"can_create_group": true,
|
||||
"can_create_project": true
|
||||
}
|
41
vendor/github.com/Bugagazavr/go-gitlab-client/stubs/users/index.json
generated
vendored
41
vendor/github.com/Bugagazavr/go-gitlab-client/stubs/users/index.json
generated
vendored
|
@ -1,41 +0,0 @@
|
|||
[
|
||||
{
|
||||
"id": 1,
|
||||
"username": "john_smith",
|
||||
"email": "john@example.com",
|
||||
"name": "John Smith",
|
||||
"state": "active",
|
||||
"created_at": "2012-05-23T08:00:58Z",
|
||||
"bio": null,
|
||||
"skype": "",
|
||||
"linkedin": "",
|
||||
"twitter": "",
|
||||
"website_url": "",
|
||||
"extern_uid": "john.smith",
|
||||
"provider": "provider_name",
|
||||
"theme_id": 1,
|
||||
"color_scheme_id": 2,
|
||||
"is_admin": false,
|
||||
"can_create_group": true
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"username": "jack_smith",
|
||||
"email": "jack@example.com",
|
||||
"name": "Jack Smith",
|
||||
"state": "blocked",
|
||||
"created_at": "2012-05-23T08:01:01Z",
|
||||
"bio": null,
|
||||
"skype": "",
|
||||
"linkedin": "",
|
||||
"twitter": "",
|
||||
"website_url": "",
|
||||
"extern_uid": "jack.smith",
|
||||
"provider": "provider_name",
|
||||
"theme_id": 1,
|
||||
"color_scheme_id": 3,
|
||||
"is_admin": false,
|
||||
"can_create_group": true,
|
||||
"can_create_project": true
|
||||
}
|
||||
]
|
15
vendor/github.com/Bugagazavr/go-gitlab-client/stubs/users/show.json
generated
vendored
15
vendor/github.com/Bugagazavr/go-gitlab-client/stubs/users/show.json
generated
vendored
|
@ -1,15 +0,0 @@
|
|||
{
|
||||
"id": 6,
|
||||
"username": "plouc",
|
||||
"email": "plouc@plouc.com",
|
||||
"name": "Raphaël Benitte",
|
||||
"bio": null,
|
||||
"skype": "",
|
||||
"linkedin": "",
|
||||
"twitter": "",
|
||||
"theme_id": 2,
|
||||
"state": "active",
|
||||
"created_at": "2001-01-01T00:00:00Z",
|
||||
"extern_uid": "uid=plouc",
|
||||
"provider": "ldap"
|
||||
}
|
97
vendor/github.com/Bugagazavr/go-gitlab-client/users.go
generated
vendored
97
vendor/github.com/Bugagazavr/go-gitlab-client/users.go
generated
vendored
|
@ -1,97 +0,0 @@
|
|||
package gogitlab
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
const (
|
||||
users_url = "/users" // Get users list
|
||||
user_url = "/users/:id" // Get a single user.
|
||||
current_user_url = "/user" // Get current user
|
||||
)
|
||||
|
||||
type User struct {
|
||||
Id int `json:"id,omitempty"`
|
||||
Username string `json:"username,omitempty"`
|
||||
Email string `json:"email,omitempty"`
|
||||
AvatarUrl string `json:"avatar_url,omitempty"`
|
||||
Name string `json:"name,omitempty"`
|
||||
State string `json:"state,omitempty"`
|
||||
CreatedAt string `json:"created_at,omitempty"`
|
||||
Bio string `json:"bio,omitempty"`
|
||||
Skype string `json:"skype,omitempty"`
|
||||
LinkedIn string `json:"linkedin,omitempty"`
|
||||
Twitter string `json:"twitter,omitempty"`
|
||||
ExternUid string `json:"extern_uid,omitempty"`
|
||||
Provider string `json:"provider,omitempty"`
|
||||
ThemeId int `json:"theme_id,omitempty"`
|
||||
ColorSchemeId int `json:"color_scheme_id,color_scheme_id"`
|
||||
}
|
||||
|
||||
func (g *Gitlab) Users(page int, per_page int) ([]*User, error) {
|
||||
|
||||
qry := map[string]string{
|
||||
"page": strconv.Itoa(page),
|
||||
"per_page": strconv.Itoa(per_page)}
|
||||
url := g.ResourceUrlQuery(users_url, nil, qry)
|
||||
|
||||
var users []*User
|
||||
|
||||
contents, err := g.buildAndExecRequest("GET", url, nil)
|
||||
if err == nil {
|
||||
err = json.Unmarshal(contents, &users)
|
||||
}
|
||||
|
||||
return users, err
|
||||
}
|
||||
|
||||
/*
|
||||
Get a single user.
|
||||
|
||||
GET /users/:id
|
||||
|
||||
Parameters:
|
||||
|
||||
id The ID of a user
|
||||
|
||||
Usage:
|
||||
|
||||
user, err := gitlab.User("your_user_id")
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
}
|
||||
fmt.Printf("%+v\n", user)
|
||||
*/
|
||||
func (g *Gitlab) User(id string) (*User, error) {
|
||||
|
||||
url := g.ResourceUrl(user_url, map[string]string{":id": id})
|
||||
|
||||
user := new(User)
|
||||
|
||||
contents, err := g.buildAndExecRequest("GET", url, nil)
|
||||
if err == nil {
|
||||
err = json.Unmarshal(contents, &user)
|
||||
}
|
||||
|
||||
return user, err
|
||||
}
|
||||
|
||||
func (g *Gitlab) DeleteUser(id string) error {
|
||||
url := g.ResourceUrl(user_url, map[string]string{":id": id})
|
||||
var err error
|
||||
_, err = g.buildAndExecRequest("DELETE", url, nil)
|
||||
return err
|
||||
}
|
||||
|
||||
func (g *Gitlab) CurrentUser() (User, error) {
|
||||
url := g.ResourceUrl(current_user_url, nil)
|
||||
var user User
|
||||
|
||||
contents, err := g.buildAndExecRequest("GET", url, nil)
|
||||
if err == nil {
|
||||
err = json.Unmarshal(contents, &user)
|
||||
}
|
||||
|
||||
return user, err
|
||||
}
|
53
vendor/github.com/Bugagazavr/go-gitlab-client/users_test.go
generated
vendored
53
vendor/github.com/Bugagazavr/go-gitlab-client/users_test.go
generated
vendored
|
@ -1,53 +0,0 @@
|
|||
package gogitlab
|
||||
|
||||
import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestUsers(t *testing.T) {
|
||||
ts, gitlab := Stub("stubs/users/index.json")
|
||||
users, err := gitlab.Users(0, 100)
|
||||
|
||||
assert.Equal(t, err, nil)
|
||||
assert.Equal(t, len(users), 2)
|
||||
defer ts.Close()
|
||||
}
|
||||
|
||||
func TestUser(t *testing.T) {
|
||||
ts, gitlab := Stub("stubs/users/show.json")
|
||||
user, err := gitlab.User("plouc")
|
||||
|
||||
assert.Equal(t, err, nil)
|
||||
assert.IsType(t, new(User), user)
|
||||
assert.Equal(t, user.Id, 6)
|
||||
assert.Equal(t, user.Username, "plouc")
|
||||
assert.Equal(t, user.Name, "Raphaël Benitte")
|
||||
assert.Equal(t, user.Bio, "")
|
||||
assert.Equal(t, user.Skype, "")
|
||||
assert.Equal(t, user.LinkedIn, "")
|
||||
assert.Equal(t, user.Twitter, "")
|
||||
assert.Equal(t, user.ThemeId, 2)
|
||||
assert.Equal(t, user.State, "active")
|
||||
assert.Equal(t, user.CreatedAt, "2001-01-01T00:00:00Z")
|
||||
assert.Equal(t, user.ExternUid, "uid=plouc")
|
||||
assert.Equal(t, user.Provider, "ldap")
|
||||
defer ts.Close()
|
||||
}
|
||||
|
||||
func TestDeleteUser(t *testing.T) {
|
||||
ts, gitlab := Stub("")
|
||||
err := gitlab.DeleteUser("1")
|
||||
|
||||
assert.Equal(t, err, nil)
|
||||
defer ts.Close()
|
||||
}
|
||||
|
||||
func TestCurrentUser(t *testing.T) {
|
||||
ts, gitlab := Stub("stubs/users/current.json")
|
||||
user, err := gitlab.CurrentUser()
|
||||
|
||||
assert.Equal(t, err, nil)
|
||||
assert.Equal(t, user.Username, "john_smith")
|
||||
defer ts.Close()
|
||||
}
|
10
vendor/github.com/Bugagazavr/go-gitlab-client/util.go
generated
vendored
10
vendor/github.com/Bugagazavr/go-gitlab-client/util.go
generated
vendored
|
@ -1,10 +0,0 @@
|
|||
package gogitlab
|
||||
|
||||
import (
|
||||
"net/url"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func encodeParameter(value string) string {
|
||||
return strings.Replace(url.QueryEscape(value), "/", "%2F", 0)
|
||||
}
|
11
vendor/github.com/Bugagazavr/go-gitlab-client/util_test.go
generated
vendored
11
vendor/github.com/Bugagazavr/go-gitlab-client/util_test.go
generated
vendored
|
@ -1,11 +0,0 @@
|
|||
package gogitlab
|
||||
|
||||
import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestParameterEncoding(t *testing.T) {
|
||||
assert.Equal(t, encodeParameter("namespace/project"), "namespace%2Fproject")
|
||||
assert.Equal(t, encodeParameter("14"), "14")
|
||||
}
|
53
vendor/github.com/Sirupsen/logrus/entry_test.go
generated
vendored
53
vendor/github.com/Sirupsen/logrus/entry_test.go
generated
vendored
|
@ -1,53 +0,0 @@
|
|||
package logrus
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestEntryPanicln(t *testing.T) {
|
||||
errBoom := fmt.Errorf("boom time")
|
||||
|
||||
defer func() {
|
||||
p := recover()
|
||||
assert.NotNil(t, p)
|
||||
|
||||
switch pVal := p.(type) {
|
||||
case *Entry:
|
||||
assert.Equal(t, "kaboom", pVal.Message)
|
||||
assert.Equal(t, errBoom, pVal.Data["err"])
|
||||
default:
|
||||
t.Fatalf("want type *Entry, got %T: %#v", pVal, pVal)
|
||||
}
|
||||
}()
|
||||
|
||||
logger := New()
|
||||
logger.Out = &bytes.Buffer{}
|
||||
entry := NewEntry(logger)
|
||||
entry.WithField("err", errBoom).Panicln("kaboom")
|
||||
}
|
||||
|
||||
func TestEntryPanicf(t *testing.T) {
|
||||
errBoom := fmt.Errorf("boom again")
|
||||
|
||||
defer func() {
|
||||
p := recover()
|
||||
assert.NotNil(t, p)
|
||||
|
||||
switch pVal := p.(type) {
|
||||
case *Entry:
|
||||
assert.Equal(t, "kaboom true", pVal.Message)
|
||||
assert.Equal(t, errBoom, pVal.Data["err"])
|
||||
default:
|
||||
t.Fatalf("want type *Entry, got %T: %#v", pVal, pVal)
|
||||
}
|
||||
}()
|
||||
|
||||
logger := New()
|
||||
logger.Out = &bytes.Buffer{}
|
||||
entry := NewEntry(logger)
|
||||
entry.WithField("err", errBoom).Panicf("kaboom %v", true)
|
||||
}
|
40
vendor/github.com/Sirupsen/logrus/examples/basic/basic.go
generated
vendored
40
vendor/github.com/Sirupsen/logrus/examples/basic/basic.go
generated
vendored
|
@ -1,40 +0,0 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"github.com/Sirupsen/logrus"
|
||||
)
|
||||
|
||||
var log = logrus.New()
|
||||
|
||||
func init() {
|
||||
log.Formatter = new(logrus.JSONFormatter)
|
||||
log.Formatter = new(logrus.TextFormatter) // default
|
||||
}
|
||||
|
||||
func main() {
|
||||
defer func() {
|
||||
err := recover()
|
||||
if err != nil {
|
||||
log.WithFields(logrus.Fields{
|
||||
"omg": true,
|
||||
"err": err,
|
||||
"number": 100,
|
||||
}).Fatal("The ice breaks!")
|
||||
}
|
||||
}()
|
||||
|
||||
log.WithFields(logrus.Fields{
|
||||
"animal": "walrus",
|
||||
"size": 10,
|
||||
}).Info("A group of walrus emerges from the ocean")
|
||||
|
||||
log.WithFields(logrus.Fields{
|
||||
"omg": true,
|
||||
"number": 122,
|
||||
}).Warn("The group's number increased tremendously!")
|
||||
|
||||
log.WithFields(logrus.Fields{
|
||||
"animal": "orca",
|
||||
"size": 9009,
|
||||
}).Panic("It's over 9000!")
|
||||
}
|
35
vendor/github.com/Sirupsen/logrus/examples/hook/hook.go
generated
vendored
35
vendor/github.com/Sirupsen/logrus/examples/hook/hook.go
generated
vendored
|
@ -1,35 +0,0 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/Sirupsen/logrus/hooks/airbrake"
|
||||
"github.com/tobi/airbrake-go"
|
||||
)
|
||||
|
||||
var log = logrus.New()
|
||||
|
||||
func init() {
|
||||
log.Formatter = new(logrus.TextFormatter) // default
|
||||
log.Hooks.Add(new(logrus_airbrake.AirbrakeHook))
|
||||
}
|
||||
|
||||
func main() {
|
||||
airbrake.Endpoint = "https://exceptions.whatever.com/notifier_api/v2/notices.xml"
|
||||
airbrake.ApiKey = "whatever"
|
||||
airbrake.Environment = "production"
|
||||
|
||||
log.WithFields(logrus.Fields{
|
||||
"animal": "walrus",
|
||||
"size": 10,
|
||||
}).Info("A group of walrus emerges from the ocean")
|
||||
|
||||
log.WithFields(logrus.Fields{
|
||||
"omg": true,
|
||||
"number": 122,
|
||||
}).Warn("The group's number increased tremendously!")
|
||||
|
||||
log.WithFields(logrus.Fields{
|
||||
"omg": true,
|
||||
"number": 100,
|
||||
}).Fatal("The ice breaks!")
|
||||
}
|
88
vendor/github.com/Sirupsen/logrus/formatter_bench_test.go
generated
vendored
88
vendor/github.com/Sirupsen/logrus/formatter_bench_test.go
generated
vendored
|
@ -1,88 +0,0 @@
|
|||
package logrus
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
// smallFields is a small size data set for benchmarking
|
||||
var smallFields = Fields{
|
||||
"foo": "bar",
|
||||
"baz": "qux",
|
||||
"one": "two",
|
||||
"three": "four",
|
||||
}
|
||||
|
||||
// largeFields is a large size data set for benchmarking
|
||||
var largeFields = Fields{
|
||||
"foo": "bar",
|
||||
"baz": "qux",
|
||||
"one": "two",
|
||||
"three": "four",
|
||||
"five": "six",
|
||||
"seven": "eight",
|
||||
"nine": "ten",
|
||||
"eleven": "twelve",
|
||||
"thirteen": "fourteen",
|
||||
"fifteen": "sixteen",
|
||||
"seventeen": "eighteen",
|
||||
"nineteen": "twenty",
|
||||
"a": "b",
|
||||
"c": "d",
|
||||
"e": "f",
|
||||
"g": "h",
|
||||
"i": "j",
|
||||
"k": "l",
|
||||
"m": "n",
|
||||
"o": "p",
|
||||
"q": "r",
|
||||
"s": "t",
|
||||
"u": "v",
|
||||
"w": "x",
|
||||
"y": "z",
|
||||
"this": "will",
|
||||
"make": "thirty",
|
||||
"entries": "yeah",
|
||||
}
|
||||
|
||||
func BenchmarkSmallTextFormatter(b *testing.B) {
|
||||
doBenchmark(b, &TextFormatter{DisableColors: true}, smallFields)
|
||||
}
|
||||
|
||||
func BenchmarkLargeTextFormatter(b *testing.B) {
|
||||
doBenchmark(b, &TextFormatter{DisableColors: true}, largeFields)
|
||||
}
|
||||
|
||||
func BenchmarkSmallColoredTextFormatter(b *testing.B) {
|
||||
doBenchmark(b, &TextFormatter{ForceColors: true}, smallFields)
|
||||
}
|
||||
|
||||
func BenchmarkLargeColoredTextFormatter(b *testing.B) {
|
||||
doBenchmark(b, &TextFormatter{ForceColors: true}, largeFields)
|
||||
}
|
||||
|
||||
func BenchmarkSmallJSONFormatter(b *testing.B) {
|
||||
doBenchmark(b, &JSONFormatter{}, smallFields)
|
||||
}
|
||||
|
||||
func BenchmarkLargeJSONFormatter(b *testing.B) {
|
||||
doBenchmark(b, &JSONFormatter{}, largeFields)
|
||||
}
|
||||
|
||||
func doBenchmark(b *testing.B, formatter Formatter, fields Fields) {
|
||||
entry := &Entry{
|
||||
Time: time.Time{},
|
||||
Level: InfoLevel,
|
||||
Message: "message",
|
||||
Data: fields,
|
||||
}
|
||||
var d []byte
|
||||
var err error
|
||||
for i := 0; i < b.N; i++ {
|
||||
d, err = formatter.Format(entry)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
b.SetBytes(int64(len(d)))
|
||||
}
|
||||
}
|
122
vendor/github.com/Sirupsen/logrus/hook_test.go
generated
vendored
122
vendor/github.com/Sirupsen/logrus/hook_test.go
generated
vendored
|
@ -1,122 +0,0 @@
|
|||
package logrus
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
type TestHook struct {
|
||||
Fired bool
|
||||
}
|
||||
|
||||
func (hook *TestHook) Fire(entry *Entry) error {
|
||||
hook.Fired = true
|
||||
return nil
|
||||
}
|
||||
|
||||
func (hook *TestHook) Levels() []Level {
|
||||
return []Level{
|
||||
DebugLevel,
|
||||
InfoLevel,
|
||||
WarnLevel,
|
||||
ErrorLevel,
|
||||
FatalLevel,
|
||||
PanicLevel,
|
||||
}
|
||||
}
|
||||
|
||||
func TestHookFires(t *testing.T) {
|
||||
hook := new(TestHook)
|
||||
|
||||
LogAndAssertJSON(t, func(log *Logger) {
|
||||
log.Hooks.Add(hook)
|
||||
assert.Equal(t, hook.Fired, false)
|
||||
|
||||
log.Print("test")
|
||||
}, func(fields Fields) {
|
||||
assert.Equal(t, hook.Fired, true)
|
||||
})
|
||||
}
|
||||
|
||||
type ModifyHook struct {
|
||||
}
|
||||
|
||||
func (hook *ModifyHook) Fire(entry *Entry) error {
|
||||
entry.Data["wow"] = "whale"
|
||||
return nil
|
||||
}
|
||||
|
||||
func (hook *ModifyHook) Levels() []Level {
|
||||
return []Level{
|
||||
DebugLevel,
|
||||
InfoLevel,
|
||||
WarnLevel,
|
||||
ErrorLevel,
|
||||
FatalLevel,
|
||||
PanicLevel,
|
||||
}
|
||||
}
|
||||
|
||||
func TestHookCanModifyEntry(t *testing.T) {
|
||||
hook := new(ModifyHook)
|
||||
|
||||
LogAndAssertJSON(t, func(log *Logger) {
|
||||
log.Hooks.Add(hook)
|
||||
log.WithField("wow", "elephant").Print("test")
|
||||
}, func(fields Fields) {
|
||||
assert.Equal(t, fields["wow"], "whale")
|
||||
})
|
||||
}
|
||||
|
||||
func TestCanFireMultipleHooks(t *testing.T) {
|
||||
hook1 := new(ModifyHook)
|
||||
hook2 := new(TestHook)
|
||||
|
||||
LogAndAssertJSON(t, func(log *Logger) {
|
||||
log.Hooks.Add(hook1)
|
||||
log.Hooks.Add(hook2)
|
||||
|
||||
log.WithField("wow", "elephant").Print("test")
|
||||
}, func(fields Fields) {
|
||||
assert.Equal(t, fields["wow"], "whale")
|
||||
assert.Equal(t, hook2.Fired, true)
|
||||
})
|
||||
}
|
||||
|
||||
type ErrorHook struct {
|
||||
Fired bool
|
||||
}
|
||||
|
||||
func (hook *ErrorHook) Fire(entry *Entry) error {
|
||||
hook.Fired = true
|
||||
return nil
|
||||
}
|
||||
|
||||
func (hook *ErrorHook) Levels() []Level {
|
||||
return []Level{
|
||||
ErrorLevel,
|
||||
}
|
||||
}
|
||||
|
||||
func TestErrorHookShouldntFireOnInfo(t *testing.T) {
|
||||
hook := new(ErrorHook)
|
||||
|
||||
LogAndAssertJSON(t, func(log *Logger) {
|
||||
log.Hooks.Add(hook)
|
||||
log.Info("test")
|
||||
}, func(fields Fields) {
|
||||
assert.Equal(t, hook.Fired, false)
|
||||
})
|
||||
}
|
||||
|
||||
func TestErrorHookShouldFireOnError(t *testing.T) {
|
||||
hook := new(ErrorHook)
|
||||
|
||||
LogAndAssertJSON(t, func(log *Logger) {
|
||||
log.Hooks.Add(hook)
|
||||
log.Error("test")
|
||||
}, func(fields Fields) {
|
||||
assert.Equal(t, hook.Fired, true)
|
||||
})
|
||||
}
|
54
vendor/github.com/Sirupsen/logrus/hooks/airbrake/airbrake.go
generated
vendored
54
vendor/github.com/Sirupsen/logrus/hooks/airbrake/airbrake.go
generated
vendored
|
@ -1,54 +0,0 @@
|
|||
package logrus_airbrake
|
||||
|
||||
import (
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/tobi/airbrake-go"
|
||||
)
|
||||
|
||||
// AirbrakeHook to send exceptions to an exception-tracking service compatible
|
||||
// with the Airbrake API. You must set:
|
||||
// * airbrake.Endpoint
|
||||
// * airbrake.ApiKey
|
||||
// * airbrake.Environment (only sends exceptions when set to "production")
|
||||
//
|
||||
// Before using this hook, to send an error. Entries that trigger an Error,
|
||||
// Fatal or Panic should now include an "error" field to send to Airbrake.
|
||||
type AirbrakeHook struct{}
|
||||
|
||||
func (hook *AirbrakeHook) Fire(entry *logrus.Entry) error {
|
||||
if entry.Data["error"] == nil {
|
||||
entry.Logger.WithFields(logrus.Fields{
|
||||
"source": "airbrake",
|
||||
"endpoint": airbrake.Endpoint,
|
||||
}).Warn("Exceptions sent to Airbrake must have an 'error' key with the error")
|
||||
return nil
|
||||
}
|
||||
|
||||
err, ok := entry.Data["error"].(error)
|
||||
if !ok {
|
||||
entry.Logger.WithFields(logrus.Fields{
|
||||
"source": "airbrake",
|
||||
"endpoint": airbrake.Endpoint,
|
||||
}).Warn("Exceptions sent to Airbrake must have an `error` key of type `error`")
|
||||
return nil
|
||||
}
|
||||
|
||||
airErr := airbrake.Notify(err)
|
||||
if airErr != nil {
|
||||
entry.Logger.WithFields(logrus.Fields{
|
||||
"source": "airbrake",
|
||||
"endpoint": airbrake.Endpoint,
|
||||
"error": airErr,
|
||||
}).Warn("Failed to send error to Airbrake")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (hook *AirbrakeHook) Levels() []logrus.Level {
|
||||
return []logrus.Level{
|
||||
logrus.ErrorLevel,
|
||||
logrus.FatalLevel,
|
||||
logrus.PanicLevel,
|
||||
}
|
||||
}
|
28
vendor/github.com/Sirupsen/logrus/hooks/papertrail/README.md
generated
vendored
28
vendor/github.com/Sirupsen/logrus/hooks/papertrail/README.md
generated
vendored
|
@ -1,28 +0,0 @@
|
|||
# Papertrail Hook for Logrus <img src="http://i.imgur.com/hTeVwmJ.png" width="40" height="40" alt=":walrus:" class="emoji" title=":walrus:" />
|
||||
|
||||
[Papertrail](https://papertrailapp.com) provides hosted log management. Once stored in Papertrail, you can [group](http://help.papertrailapp.com/kb/how-it-works/groups/) your logs on various dimensions, [search](http://help.papertrailapp.com/kb/how-it-works/search-syntax) them, and trigger [alerts](http://help.papertrailapp.com/kb/how-it-works/alerts).
|
||||
|
||||
In most deployments, you'll want to send logs to Papertrail via their [remote_syslog](http://help.papertrailapp.com/kb/configuration/configuring-centralized-logging-from-text-log-files-in-unix/) daemon, which requires no application-specific configuration. This hook is intended for relatively low-volume logging, likely in managed cloud hosting deployments where installing `remote_syslog` is not possible.
|
||||
|
||||
## Usage
|
||||
|
||||
You can find your Papertrail UDP port on your [Papertrail account page](https://papertrailapp.com/account/destinations). Substitute it below for `YOUR_PAPERTRAIL_UDP_PORT`.
|
||||
|
||||
For `YOUR_APP_NAME`, substitute a short string that will readily identify your application or service in the logs.
|
||||
|
||||
```go
|
||||
import (
|
||||
"log/syslog"
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/Sirupsen/logrus/hooks/papertrail"
|
||||
)
|
||||
|
||||
func main() {
|
||||
log := logrus.New()
|
||||
hook, err := logrus_papertrail.NewPapertrailHook("logs.papertrailapp.com", YOUR_PAPERTRAIL_UDP_PORT, YOUR_APP_NAME)
|
||||
|
||||
if err == nil {
|
||||
log.Hooks.Add(hook)
|
||||
}
|
||||
}
|
||||
```
|
55
vendor/github.com/Sirupsen/logrus/hooks/papertrail/papertrail.go
generated
vendored
55
vendor/github.com/Sirupsen/logrus/hooks/papertrail/papertrail.go
generated
vendored
|
@ -1,55 +0,0 @@
|
|||
package logrus_papertrail
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
)
|
||||
|
||||
const (
|
||||
format = "Jan 2 15:04:05"
|
||||
)
|
||||
|
||||
// PapertrailHook to send logs to a logging service compatible with the Papertrail API.
|
||||
type PapertrailHook struct {
|
||||
Host string
|
||||
Port int
|
||||
AppName string
|
||||
UDPConn net.Conn
|
||||
}
|
||||
|
||||
// NewPapertrailHook creates a hook to be added to an instance of logger.
|
||||
func NewPapertrailHook(host string, port int, appName string) (*PapertrailHook, error) {
|
||||
conn, err := net.Dial("udp", fmt.Sprintf("%s:%d", host, port))
|
||||
return &PapertrailHook{host, port, appName, conn}, err
|
||||
}
|
||||
|
||||
// Fire is called when a log event is fired.
|
||||
func (hook *PapertrailHook) Fire(entry *logrus.Entry) error {
|
||||
date := time.Now().Format(format)
|
||||
msg, _ := entry.String()
|
||||
payload := fmt.Sprintf("<22> %s %s: %s", date, hook.AppName, msg)
|
||||
|
||||
bytesWritten, err := hook.UDPConn.Write([]byte(payload))
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Unable to send log line to Papertrail via UDP. Wrote %d bytes before error: %v", bytesWritten, err)
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Levels returns the available logging levels.
|
||||
func (hook *PapertrailHook) Levels() []logrus.Level {
|
||||
return []logrus.Level{
|
||||
logrus.PanicLevel,
|
||||
logrus.FatalLevel,
|
||||
logrus.ErrorLevel,
|
||||
logrus.WarnLevel,
|
||||
logrus.InfoLevel,
|
||||
logrus.DebugLevel,
|
||||
}
|
||||
}
|
26
vendor/github.com/Sirupsen/logrus/hooks/papertrail/papertrail_test.go
generated
vendored
26
vendor/github.com/Sirupsen/logrus/hooks/papertrail/papertrail_test.go
generated
vendored
|
@ -1,26 +0,0 @@
|
|||
package logrus_papertrail
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/stvp/go-udp-testing"
|
||||
)
|
||||
|
||||
func TestWritingToUDP(t *testing.T) {
|
||||
port := 16661
|
||||
udp.SetAddr(fmt.Sprintf(":%d", port))
|
||||
|
||||
hook, err := NewPapertrailHook("localhost", port, "test")
|
||||
if err != nil {
|
||||
t.Errorf("Unable to connect to local UDP server.")
|
||||
}
|
||||
|
||||
log := logrus.New()
|
||||
log.Hooks.Add(hook)
|
||||
|
||||
udp.ShouldReceive(t, "foo", func() {
|
||||
log.Info("foo")
|
||||
})
|
||||
}
|
61
vendor/github.com/Sirupsen/logrus/hooks/sentry/README.md
generated
vendored
61
vendor/github.com/Sirupsen/logrus/hooks/sentry/README.md
generated
vendored
|
@ -1,61 +0,0 @@
|
|||
# Sentry Hook for Logrus <img src="http://i.imgur.com/hTeVwmJ.png" width="40" height="40" alt=":walrus:" class="emoji" title=":walrus:" />
|
||||
|
||||
[Sentry](https://getsentry.com) provides both self-hosted and hosted
|
||||
solutions for exception tracking.
|
||||
Both client and server are
|
||||
[open source](https://github.com/getsentry/sentry).
|
||||
|
||||
## Usage
|
||||
|
||||
Every sentry application defined on the server gets a different
|
||||
[DSN](https://www.getsentry.com/docs/). In the example below replace
|
||||
`YOUR_DSN` with the one created for your application.
|
||||
|
||||
```go
|
||||
import (
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/Sirupsen/logrus/hooks/sentry"
|
||||
)
|
||||
|
||||
func main() {
|
||||
log := logrus.New()
|
||||
hook, err := logrus_sentry.NewSentryHook(YOUR_DSN, []logrus.Level{
|
||||
logrus.PanicLevel,
|
||||
logrus.FatalLevel,
|
||||
logrus.ErrorLevel,
|
||||
})
|
||||
|
||||
if err == nil {
|
||||
log.Hooks.Add(hook)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Special fields
|
||||
|
||||
Some logrus fields have a special meaning in this hook,
|
||||
these are server_name and logger.
|
||||
When logs are sent to sentry these fields are treated differently.
|
||||
- server_name (also known as hostname) is the name of the server which
|
||||
is logging the event (hostname.example.com)
|
||||
- logger is the part of the application which is logging the event.
|
||||
In go this usually means setting it to the name of the package.
|
||||
|
||||
## Timeout
|
||||
|
||||
`Timeout` is the time the sentry hook will wait for a response
|
||||
from the sentry server.
|
||||
|
||||
If this time elapses with no response from
|
||||
the server an error will be returned.
|
||||
|
||||
If `Timeout` is set to 0 the SentryHook will not wait for a reply
|
||||
and will assume a correct delivery.
|
||||
|
||||
The SentryHook has a default timeout of `100 milliseconds` when created
|
||||
with a call to `NewSentryHook`. This can be changed by assigning a value to the `Timeout` field:
|
||||
|
||||
```go
|
||||
hook, _ := logrus_sentry.NewSentryHook(...)
|
||||
hook.Timeout = 20*time.Seconds
|
||||
```
|
100
vendor/github.com/Sirupsen/logrus/hooks/sentry/sentry.go
generated
vendored
100
vendor/github.com/Sirupsen/logrus/hooks/sentry/sentry.go
generated
vendored
|
@ -1,100 +0,0 @@
|
|||
package logrus_sentry
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/getsentry/raven-go"
|
||||
)
|
||||
|
||||
var (
|
||||
severityMap = map[logrus.Level]raven.Severity{
|
||||
logrus.DebugLevel: raven.DEBUG,
|
||||
logrus.InfoLevel: raven.INFO,
|
||||
logrus.WarnLevel: raven.WARNING,
|
||||
logrus.ErrorLevel: raven.ERROR,
|
||||
logrus.FatalLevel: raven.FATAL,
|
||||
logrus.PanicLevel: raven.FATAL,
|
||||
}
|
||||
)
|
||||
|
||||
func getAndDel(d logrus.Fields, key string) (string, bool) {
|
||||
var (
|
||||
ok bool
|
||||
v interface{}
|
||||
val string
|
||||
)
|
||||
if v, ok = d[key]; !ok {
|
||||
return "", false
|
||||
}
|
||||
|
||||
if val, ok = v.(string); !ok {
|
||||
return "", false
|
||||
}
|
||||
delete(d, key)
|
||||
return val, true
|
||||
}
|
||||
|
||||
// SentryHook delivers logs to a sentry server.
|
||||
type SentryHook struct {
|
||||
// Timeout sets the time to wait for a delivery error from the sentry server.
|
||||
// If this is set to zero the server will not wait for any response and will
|
||||
// consider the message correctly sent
|
||||
Timeout time.Duration
|
||||
|
||||
client *raven.Client
|
||||
levels []logrus.Level
|
||||
}
|
||||
|
||||
// NewSentryHook creates a hook to be added to an instance of logger
|
||||
// and initializes the raven client.
|
||||
// This method sets the timeout to 100 milliseconds.
|
||||
func NewSentryHook(DSN string, levels []logrus.Level) (*SentryHook, error) {
|
||||
client, err := raven.NewClient(DSN, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &SentryHook{100 * time.Millisecond, client, levels}, nil
|
||||
}
|
||||
|
||||
// Called when an event should be sent to sentry
|
||||
// Special fields that sentry uses to give more information to the server
|
||||
// are extracted from entry.Data (if they are found)
|
||||
// These fields are: logger and server_name
|
||||
func (hook *SentryHook) Fire(entry *logrus.Entry) error {
|
||||
packet := &raven.Packet{
|
||||
Message: entry.Message,
|
||||
Timestamp: raven.Timestamp(entry.Time),
|
||||
Level: severityMap[entry.Level],
|
||||
Platform: "go",
|
||||
}
|
||||
|
||||
d := entry.Data
|
||||
|
||||
if logger, ok := getAndDel(d, "logger"); ok {
|
||||
packet.Logger = logger
|
||||
}
|
||||
if serverName, ok := getAndDel(d, "server_name"); ok {
|
||||
packet.ServerName = serverName
|
||||
}
|
||||
packet.Extra = map[string]interface{}(d)
|
||||
|
||||
_, errCh := hook.client.Capture(packet, nil)
|
||||
timeout := hook.Timeout
|
||||
if timeout != 0 {
|
||||
timeoutCh := time.After(timeout)
|
||||
select {
|
||||
case err := <-errCh:
|
||||
return err
|
||||
case <-timeoutCh:
|
||||
return fmt.Errorf("no response from sentry server in %s", timeout)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Levels returns the available logging levels.
|
||||
func (hook *SentryHook) Levels() []logrus.Level {
|
||||
return hook.levels
|
||||
}
|
97
vendor/github.com/Sirupsen/logrus/hooks/sentry/sentry_test.go
generated
vendored
97
vendor/github.com/Sirupsen/logrus/hooks/sentry/sentry_test.go
generated
vendored
|
@ -1,97 +0,0 @@
|
|||
package logrus_sentry
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/getsentry/raven-go"
|
||||
)
|
||||
|
||||
const (
|
||||
message = "error message"
|
||||
server_name = "testserver.internal"
|
||||
logger_name = "test.logger"
|
||||
)
|
||||
|
||||
func getTestLogger() *logrus.Logger {
|
||||
l := logrus.New()
|
||||
l.Out = ioutil.Discard
|
||||
return l
|
||||
}
|
||||
|
||||
func WithTestDSN(t *testing.T, tf func(string, <-chan *raven.Packet)) {
|
||||
pch := make(chan *raven.Packet, 1)
|
||||
s := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
|
||||
defer req.Body.Close()
|
||||
d := json.NewDecoder(req.Body)
|
||||
p := &raven.Packet{}
|
||||
err := d.Decode(p)
|
||||
if err != nil {
|
||||
t.Fatal(err.Error())
|
||||
}
|
||||
|
||||
pch <- p
|
||||
}))
|
||||
defer s.Close()
|
||||
|
||||
fragments := strings.SplitN(s.URL, "://", 2)
|
||||
dsn := fmt.Sprintf(
|
||||
"%s://public:secret@%s/sentry/project-id",
|
||||
fragments[0],
|
||||
fragments[1],
|
||||
)
|
||||
tf(dsn, pch)
|
||||
}
|
||||
|
||||
func TestSpecialFields(t *testing.T) {
|
||||
WithTestDSN(t, func(dsn string, pch <-chan *raven.Packet) {
|
||||
logger := getTestLogger()
|
||||
|
||||
hook, err := NewSentryHook(dsn, []logrus.Level{
|
||||
logrus.ErrorLevel,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
t.Fatal(err.Error())
|
||||
}
|
||||
logger.Hooks.Add(hook)
|
||||
logger.WithFields(logrus.Fields{
|
||||
"server_name": server_name,
|
||||
"logger": logger_name,
|
||||
}).Error(message)
|
||||
|
||||
packet := <-pch
|
||||
if packet.Logger != logger_name {
|
||||
t.Errorf("logger should have been %s, was %s", logger_name, packet.Logger)
|
||||
}
|
||||
|
||||
if packet.ServerName != server_name {
|
||||
t.Errorf("server_name should have been %s, was %s", server_name, packet.ServerName)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestSentryHandler(t *testing.T) {
|
||||
WithTestDSN(t, func(dsn string, pch <-chan *raven.Packet) {
|
||||
logger := getTestLogger()
|
||||
hook, err := NewSentryHook(dsn, []logrus.Level{
|
||||
logrus.ErrorLevel,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err.Error())
|
||||
}
|
||||
logger.Hooks.Add(hook)
|
||||
|
||||
logger.Error(message)
|
||||
packet := <-pch
|
||||
if packet.Message != message {
|
||||
t.Errorf("message should have been %s, was %s", message, packet.Message)
|
||||
}
|
||||
})
|
||||
}
|
20
vendor/github.com/Sirupsen/logrus/hooks/syslog/README.md
generated
vendored
20
vendor/github.com/Sirupsen/logrus/hooks/syslog/README.md
generated
vendored
|
@ -1,20 +0,0 @@
|
|||
# Syslog Hooks for Logrus <img src="http://i.imgur.com/hTeVwmJ.png" width="40" height="40" alt=":walrus:" class="emoji" title=":walrus:"/>
|
||||
|
||||
## Usage
|
||||
|
||||
```go
|
||||
import (
|
||||
"log/syslog"
|
||||
"github.com/Sirupsen/logrus"
|
||||
logrus_syslog "github.com/Sirupsen/logrus/hooks/syslog"
|
||||
)
|
||||
|
||||
func main() {
|
||||
log := logrus.New()
|
||||
hook, err := logrus_syslog.NewSyslogHook("udp", "localhost:514", syslog.LOG_INFO, "")
|
||||
|
||||
if err == nil {
|
||||
log.Hooks.Add(hook)
|
||||
}
|
||||
}
|
||||
```
|
59
vendor/github.com/Sirupsen/logrus/hooks/syslog/syslog.go
generated
vendored
59
vendor/github.com/Sirupsen/logrus/hooks/syslog/syslog.go
generated
vendored
|
@ -1,59 +0,0 @@
|
|||
package logrus_syslog
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/Sirupsen/logrus"
|
||||
"log/syslog"
|
||||
"os"
|
||||
)
|
||||
|
||||
// SyslogHook to send logs via syslog.
|
||||
type SyslogHook struct {
|
||||
Writer *syslog.Writer
|
||||
SyslogNetwork string
|
||||
SyslogRaddr string
|
||||
}
|
||||
|
||||
// Creates a hook to be added to an instance of logger. This is called with
|
||||
// `hook, err := NewSyslogHook("udp", "localhost:514", syslog.LOG_DEBUG, "")`
|
||||
// `if err == nil { log.Hooks.Add(hook) }`
|
||||
func NewSyslogHook(network, raddr string, priority syslog.Priority, tag string) (*SyslogHook, error) {
|
||||
w, err := syslog.Dial(network, raddr, priority, tag)
|
||||
return &SyslogHook{w, network, raddr}, err
|
||||
}
|
||||
|
||||
func (hook *SyslogHook) Fire(entry *logrus.Entry) error {
|
||||
line, err := entry.String()
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Unable to read entry, %v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
switch entry.Level {
|
||||
case logrus.PanicLevel:
|
||||
return hook.Writer.Crit(line)
|
||||
case logrus.FatalLevel:
|
||||
return hook.Writer.Crit(line)
|
||||
case logrus.ErrorLevel:
|
||||
return hook.Writer.Err(line)
|
||||
case logrus.WarnLevel:
|
||||
return hook.Writer.Warning(line)
|
||||
case logrus.InfoLevel:
|
||||
return hook.Writer.Info(line)
|
||||
case logrus.DebugLevel:
|
||||
return hook.Writer.Debug(line)
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func (hook *SyslogHook) Levels() []logrus.Level {
|
||||
return []logrus.Level{
|
||||
logrus.PanicLevel,
|
||||
logrus.FatalLevel,
|
||||
logrus.ErrorLevel,
|
||||
logrus.WarnLevel,
|
||||
logrus.InfoLevel,
|
||||
logrus.DebugLevel,
|
||||
}
|
||||
}
|
26
vendor/github.com/Sirupsen/logrus/hooks/syslog/syslog_test.go
generated
vendored
26
vendor/github.com/Sirupsen/logrus/hooks/syslog/syslog_test.go
generated
vendored
|
@ -1,26 +0,0 @@
|
|||
package logrus_syslog
|
||||
|
||||
import (
|
||||
"github.com/Sirupsen/logrus"
|
||||
"log/syslog"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestLocalhostAddAndPrint(t *testing.T) {
|
||||
log := logrus.New()
|
||||
hook, err := NewSyslogHook("udp", "localhost:514", syslog.LOG_INFO, "")
|
||||
|
||||
if err != nil {
|
||||
t.Errorf("Unable to connect to local syslog.")
|
||||
}
|
||||
|
||||
log.Hooks.Add(hook)
|
||||
|
||||
for _, level := range hook.Levels() {
|
||||
if len(log.Hooks[level]) != 1 {
|
||||
t.Errorf("SyslogHook was not added. The length of log.Hooks[%v]: %v", level, len(log.Hooks[level]))
|
||||
}
|
||||
}
|
||||
|
||||
log.Info("Congratulations!")
|
||||
}
|
283
vendor/github.com/Sirupsen/logrus/logrus_test.go
generated
vendored
283
vendor/github.com/Sirupsen/logrus/logrus_test.go
generated
vendored
|
@ -1,283 +0,0 @@
|
|||
package logrus
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"strconv"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func LogAndAssertJSON(t *testing.T, log func(*Logger), assertions func(fields Fields)) {
|
||||
var buffer bytes.Buffer
|
||||
var fields Fields
|
||||
|
||||
logger := New()
|
||||
logger.Out = &buffer
|
||||
logger.Formatter = new(JSONFormatter)
|
||||
|
||||
log(logger)
|
||||
|
||||
err := json.Unmarshal(buffer.Bytes(), &fields)
|
||||
assert.Nil(t, err)
|
||||
|
||||
assertions(fields)
|
||||
}
|
||||
|
||||
func LogAndAssertText(t *testing.T, log func(*Logger), assertions func(fields map[string]string)) {
|
||||
var buffer bytes.Buffer
|
||||
|
||||
logger := New()
|
||||
logger.Out = &buffer
|
||||
logger.Formatter = &TextFormatter{
|
||||
DisableColors: true,
|
||||
}
|
||||
|
||||
log(logger)
|
||||
|
||||
fields := make(map[string]string)
|
||||
for _, kv := range strings.Split(buffer.String(), " ") {
|
||||
if !strings.Contains(kv, "=") {
|
||||
continue
|
||||
}
|
||||
kvArr := strings.Split(kv, "=")
|
||||
key := strings.TrimSpace(kvArr[0])
|
||||
val := kvArr[1]
|
||||
if kvArr[1][0] == '"' {
|
||||
var err error
|
||||
val, err = strconv.Unquote(val)
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
fields[key] = val
|
||||
}
|
||||
assertions(fields)
|
||||
}
|
||||
|
||||
func TestPrint(t *testing.T) {
|
||||
LogAndAssertJSON(t, func(log *Logger) {
|
||||
log.Print("test")
|
||||
}, func(fields Fields) {
|
||||
assert.Equal(t, fields["msg"], "test")
|
||||
assert.Equal(t, fields["level"], "info")
|
||||
})
|
||||
}
|
||||
|
||||
func TestInfo(t *testing.T) {
|
||||
LogAndAssertJSON(t, func(log *Logger) {
|
||||
log.Info("test")
|
||||
}, func(fields Fields) {
|
||||
assert.Equal(t, fields["msg"], "test")
|
||||
assert.Equal(t, fields["level"], "info")
|
||||
})
|
||||
}
|
||||
|
||||
func TestWarn(t *testing.T) {
|
||||
LogAndAssertJSON(t, func(log *Logger) {
|
||||
log.Warn("test")
|
||||
}, func(fields Fields) {
|
||||
assert.Equal(t, fields["msg"], "test")
|
||||
assert.Equal(t, fields["level"], "warning")
|
||||
})
|
||||
}
|
||||
|
||||
func TestInfolnShouldAddSpacesBetweenStrings(t *testing.T) {
|
||||
LogAndAssertJSON(t, func(log *Logger) {
|
||||
log.Infoln("test", "test")
|
||||
}, func(fields Fields) {
|
||||
assert.Equal(t, fields["msg"], "test test")
|
||||
})
|
||||
}
|
||||
|
||||
func TestInfolnShouldAddSpacesBetweenStringAndNonstring(t *testing.T) {
|
||||
LogAndAssertJSON(t, func(log *Logger) {
|
||||
log.Infoln("test", 10)
|
||||
}, func(fields Fields) {
|
||||
assert.Equal(t, fields["msg"], "test 10")
|
||||
})
|
||||
}
|
||||
|
||||
func TestInfolnShouldAddSpacesBetweenTwoNonStrings(t *testing.T) {
|
||||
LogAndAssertJSON(t, func(log *Logger) {
|
||||
log.Infoln(10, 10)
|
||||
}, func(fields Fields) {
|
||||
assert.Equal(t, fields["msg"], "10 10")
|
||||
})
|
||||
}
|
||||
|
||||
func TestInfoShouldAddSpacesBetweenTwoNonStrings(t *testing.T) {
|
||||
LogAndAssertJSON(t, func(log *Logger) {
|
||||
log.Infoln(10, 10)
|
||||
}, func(fields Fields) {
|
||||
assert.Equal(t, fields["msg"], "10 10")
|
||||
})
|
||||
}
|
||||
|
||||
func TestInfoShouldNotAddSpacesBetweenStringAndNonstring(t *testing.T) {
|
||||
LogAndAssertJSON(t, func(log *Logger) {
|
||||
log.Info("test", 10)
|
||||
}, func(fields Fields) {
|
||||
assert.Equal(t, fields["msg"], "test10")
|
||||
})
|
||||
}
|
||||
|
||||
func TestInfoShouldNotAddSpacesBetweenStrings(t *testing.T) {
|
||||
LogAndAssertJSON(t, func(log *Logger) {
|
||||
log.Info("test", "test")
|
||||
}, func(fields Fields) {
|
||||
assert.Equal(t, fields["msg"], "testtest")
|
||||
})
|
||||
}
|
||||
|
||||
func TestWithFieldsShouldAllowAssignments(t *testing.T) {
|
||||
var buffer bytes.Buffer
|
||||
var fields Fields
|
||||
|
||||
logger := New()
|
||||
logger.Out = &buffer
|
||||
logger.Formatter = new(JSONFormatter)
|
||||
|
||||
localLog := logger.WithFields(Fields{
|
||||
"key1": "value1",
|
||||
})
|
||||
|
||||
localLog.WithField("key2", "value2").Info("test")
|
||||
err := json.Unmarshal(buffer.Bytes(), &fields)
|
||||
assert.Nil(t, err)
|
||||
|
||||
assert.Equal(t, "value2", fields["key2"])
|
||||
assert.Equal(t, "value1", fields["key1"])
|
||||
|
||||
buffer = bytes.Buffer{}
|
||||
fields = Fields{}
|
||||
localLog.Info("test")
|
||||
err = json.Unmarshal(buffer.Bytes(), &fields)
|
||||
assert.Nil(t, err)
|
||||
|
||||
_, ok := fields["key2"]
|
||||
assert.Equal(t, false, ok)
|
||||
assert.Equal(t, "value1", fields["key1"])
|
||||
}
|
||||
|
||||
func TestUserSuppliedFieldDoesNotOverwriteDefaults(t *testing.T) {
|
||||
LogAndAssertJSON(t, func(log *Logger) {
|
||||
log.WithField("msg", "hello").Info("test")
|
||||
}, func(fields Fields) {
|
||||
assert.Equal(t, fields["msg"], "test")
|
||||
})
|
||||
}
|
||||
|
||||
func TestUserSuppliedMsgFieldHasPrefix(t *testing.T) {
|
||||
LogAndAssertJSON(t, func(log *Logger) {
|
||||
log.WithField("msg", "hello").Info("test")
|
||||
}, func(fields Fields) {
|
||||
assert.Equal(t, fields["msg"], "test")
|
||||
assert.Equal(t, fields["fields.msg"], "hello")
|
||||
})
|
||||
}
|
||||
|
||||
func TestUserSuppliedTimeFieldHasPrefix(t *testing.T) {
|
||||
LogAndAssertJSON(t, func(log *Logger) {
|
||||
log.WithField("time", "hello").Info("test")
|
||||
}, func(fields Fields) {
|
||||
assert.Equal(t, fields["fields.time"], "hello")
|
||||
})
|
||||
}
|
||||
|
||||
func TestUserSuppliedLevelFieldHasPrefix(t *testing.T) {
|
||||
LogAndAssertJSON(t, func(log *Logger) {
|
||||
log.WithField("level", 1).Info("test")
|
||||
}, func(fields Fields) {
|
||||
assert.Equal(t, fields["level"], "info")
|
||||
assert.Equal(t, fields["fields.level"], 1)
|
||||
})
|
||||
}
|
||||
|
||||
func TestDefaultFieldsAreNotPrefixed(t *testing.T) {
|
||||
LogAndAssertText(t, func(log *Logger) {
|
||||
ll := log.WithField("herp", "derp")
|
||||
ll.Info("hello")
|
||||
ll.Info("bye")
|
||||
}, func(fields map[string]string) {
|
||||
for _, fieldName := range []string{"fields.level", "fields.time", "fields.msg"} {
|
||||
if _, ok := fields[fieldName]; ok {
|
||||
t.Fatalf("should not have prefixed %q: %v", fieldName, fields)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestDoubleLoggingDoesntPrefixPreviousFields(t *testing.T) {
|
||||
|
||||
var buffer bytes.Buffer
|
||||
var fields Fields
|
||||
|
||||
logger := New()
|
||||
logger.Out = &buffer
|
||||
logger.Formatter = new(JSONFormatter)
|
||||
|
||||
llog := logger.WithField("context", "eating raw fish")
|
||||
|
||||
llog.Info("looks delicious")
|
||||
|
||||
err := json.Unmarshal(buffer.Bytes(), &fields)
|
||||
assert.NoError(t, err, "should have decoded first message")
|
||||
assert.Equal(t, len(fields), 4, "should only have msg/time/level/context fields")
|
||||
assert.Equal(t, fields["msg"], "looks delicious")
|
||||
assert.Equal(t, fields["context"], "eating raw fish")
|
||||
|
||||
buffer.Reset()
|
||||
|
||||
llog.Warn("omg it is!")
|
||||
|
||||
err = json.Unmarshal(buffer.Bytes(), &fields)
|
||||
assert.NoError(t, err, "should have decoded second message")
|
||||
assert.Equal(t, len(fields), 4, "should only have msg/time/level/context fields")
|
||||
assert.Equal(t, fields["msg"], "omg it is!")
|
||||
assert.Equal(t, fields["context"], "eating raw fish")
|
||||
assert.Nil(t, fields["fields.msg"], "should not have prefixed previous `msg` entry")
|
||||
|
||||
}
|
||||
|
||||
func TestConvertLevelToString(t *testing.T) {
|
||||
assert.Equal(t, "debug", DebugLevel.String())
|
||||
assert.Equal(t, "info", InfoLevel.String())
|
||||
assert.Equal(t, "warning", WarnLevel.String())
|
||||
assert.Equal(t, "error", ErrorLevel.String())
|
||||
assert.Equal(t, "fatal", FatalLevel.String())
|
||||
assert.Equal(t, "panic", PanicLevel.String())
|
||||
}
|
||||
|
||||
func TestParseLevel(t *testing.T) {
|
||||
l, err := ParseLevel("panic")
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, PanicLevel, l)
|
||||
|
||||
l, err = ParseLevel("fatal")
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, FatalLevel, l)
|
||||
|
||||
l, err = ParseLevel("error")
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, ErrorLevel, l)
|
||||
|
||||
l, err = ParseLevel("warn")
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, WarnLevel, l)
|
||||
|
||||
l, err = ParseLevel("warning")
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, WarnLevel, l)
|
||||
|
||||
l, err = ParseLevel("info")
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, InfoLevel, l)
|
||||
|
||||
l, err = ParseLevel("debug")
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, DebugLevel, l)
|
||||
|
||||
l, err = ParseLevel("invalid")
|
||||
assert.Equal(t, "not a valid logrus Level: \"invalid\"", err.Error())
|
||||
}
|
33
vendor/github.com/Sirupsen/logrus/text_formatter_test.go
generated
vendored
33
vendor/github.com/Sirupsen/logrus/text_formatter_test.go
generated
vendored
|
@ -1,33 +0,0 @@
|
|||
package logrus
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestQuoting(t *testing.T) {
|
||||
tf := &TextFormatter{DisableColors: true}
|
||||
|
||||
checkQuoting := func(q bool, value interface{}) {
|
||||
b, _ := tf.Format(WithField("test", value))
|
||||
idx := bytes.Index(b, ([]byte)("test="))
|
||||
cont := bytes.Contains(b[idx+5:], []byte{'"'})
|
||||
if cont != q {
|
||||
if q {
|
||||
t.Errorf("quoting expected for: %#v", value)
|
||||
} else {
|
||||
t.Errorf("quoting not expected for: %#v", value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
checkQuoting(false, "abcd")
|
||||
checkQuoting(false, "v1.0")
|
||||
checkQuoting(true, "/foobar")
|
||||
checkQuoting(true, "x y")
|
||||
checkQuoting(true, "x,y")
|
||||
checkQuoting(false, errors.New("invalid"))
|
||||
checkQuoting(true, errors.New("invalid argument"))
|
||||
}
|
21
vendor/github.com/codegangsta/cli/LICENSE
generated
vendored
21
vendor/github.com/codegangsta/cli/LICENSE
generated
vendored
|
@ -1,21 +0,0 @@
|
|||
Copyright (C) 2013 Jeremy Saenz
|
||||
All Rights Reserved.
|
||||
|
||||
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.
|
298
vendor/github.com/codegangsta/cli/README.md
generated
vendored
298
vendor/github.com/codegangsta/cli/README.md
generated
vendored
|
@ -1,298 +0,0 @@
|
|||
[![Build Status](https://travis-ci.org/codegangsta/cli.png?branch=master)](https://travis-ci.org/codegangsta/cli)
|
||||
|
||||
# cli.go
|
||||
cli.go is simple, fast, and fun package for building command line apps in Go. The goal is to enable developers to write fast and distributable command line applications in an expressive way.
|
||||
|
||||
You can view the API docs here:
|
||||
http://godoc.org/github.com/codegangsta/cli
|
||||
|
||||
## Overview
|
||||
Command line apps are usually so tiny that there is absolutely no reason why your code should *not* be self-documenting. Things like generating help text and parsing command flags/options should not hinder productivity when writing a command line app.
|
||||
|
||||
**This is where cli.go comes into play.** cli.go makes command line programming fun, organized, and expressive!
|
||||
|
||||
## Installation
|
||||
Make sure you have a working Go environment (go 1.1 is *required*). [See the install instructions](http://golang.org/doc/install.html).
|
||||
|
||||
To install `cli.go`, simply run:
|
||||
```
|
||||
$ go get github.com/codegangsta/cli
|
||||
```
|
||||
|
||||
Make sure your `PATH` includes to the `$GOPATH/bin` directory so your commands can be easily used:
|
||||
```
|
||||
export PATH=$PATH:$GOPATH/bin
|
||||
```
|
||||
|
||||
## Getting Started
|
||||
One of the philosophies behind cli.go is that an API should be playful and full of discovery. So a cli.go app can be as little as one line of code in `main()`.
|
||||
|
||||
``` go
|
||||
package main
|
||||
|
||||
import (
|
||||
"os"
|
||||
"github.com/codegangsta/cli"
|
||||
)
|
||||
|
||||
func main() {
|
||||
cli.NewApp().Run(os.Args)
|
||||
}
|
||||
```
|
||||
|
||||
This app will run and show help text, but is not very useful. Let's give an action to execute and some help documentation:
|
||||
|
||||
``` go
|
||||
package main
|
||||
|
||||
import (
|
||||
"os"
|
||||
"github.com/codegangsta/cli"
|
||||
)
|
||||
|
||||
func main() {
|
||||
app := cli.NewApp()
|
||||
app.Name = "boom"
|
||||
app.Usage = "make an explosive entrance"
|
||||
app.Action = func(c *cli.Context) {
|
||||
println("boom! I say!")
|
||||
}
|
||||
|
||||
app.Run(os.Args)
|
||||
}
|
||||
```
|
||||
|
||||
Running this already gives you a ton of functionality, plus support for things like subcommands and flags, which are covered below.
|
||||
|
||||
## Example
|
||||
|
||||
Being a programmer can be a lonely job. Thankfully by the power of automation that is not the case! Let's create a greeter app to fend off our demons of loneliness!
|
||||
|
||||
Start by creating a directory named `greet`, and within it, add a file, `greet.go` with the following code in it:
|
||||
|
||||
``` go
|
||||
package main
|
||||
|
||||
import (
|
||||
"os"
|
||||
"github.com/codegangsta/cli"
|
||||
)
|
||||
|
||||
func main() {
|
||||
app := cli.NewApp()
|
||||
app.Name = "greet"
|
||||
app.Usage = "fight the loneliness!"
|
||||
app.Action = func(c *cli.Context) {
|
||||
println("Hello friend!")
|
||||
}
|
||||
|
||||
app.Run(os.Args)
|
||||
}
|
||||
```
|
||||
|
||||
Install our command to the `$GOPATH/bin` directory:
|
||||
|
||||
```
|
||||
$ go install
|
||||
```
|
||||
|
||||
Finally run our new command:
|
||||
|
||||
```
|
||||
$ greet
|
||||
Hello friend!
|
||||
```
|
||||
|
||||
cli.go also generates some bitchass help text:
|
||||
```
|
||||
$ greet help
|
||||
NAME:
|
||||
greet - fight the loneliness!
|
||||
|
||||
USAGE:
|
||||
greet [global options] command [command options] [arguments...]
|
||||
|
||||
VERSION:
|
||||
0.0.0
|
||||
|
||||
COMMANDS:
|
||||
help, h Shows a list of commands or help for one command
|
||||
|
||||
GLOBAL OPTIONS
|
||||
--version Shows version information
|
||||
```
|
||||
|
||||
### Arguments
|
||||
You can lookup arguments by calling the `Args` function on `cli.Context`.
|
||||
|
||||
``` go
|
||||
...
|
||||
app.Action = func(c *cli.Context) {
|
||||
println("Hello", c.Args()[0])
|
||||
}
|
||||
...
|
||||
```
|
||||
|
||||
### Flags
|
||||
Setting and querying flags is simple.
|
||||
``` go
|
||||
...
|
||||
app.Flags = []cli.Flag {
|
||||
cli.StringFlag{
|
||||
Name: "lang",
|
||||
Value: "english",
|
||||
Usage: "language for the greeting",
|
||||
},
|
||||
}
|
||||
app.Action = func(c *cli.Context) {
|
||||
name := "someone"
|
||||
if len(c.Args()) > 0 {
|
||||
name = c.Args()[0]
|
||||
}
|
||||
if c.String("lang") == "spanish" {
|
||||
println("Hola", name)
|
||||
} else {
|
||||
println("Hello", name)
|
||||
}
|
||||
}
|
||||
...
|
||||
```
|
||||
|
||||
#### Alternate Names
|
||||
|
||||
You can set alternate (or short) names for flags by providing a comma-delimited list for the `Name`. e.g.
|
||||
|
||||
``` go
|
||||
app.Flags = []cli.Flag {
|
||||
cli.StringFlag{
|
||||
Name: "lang, l",
|
||||
Value: "english",
|
||||
Usage: "language for the greeting",
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
That flag can then be set with `--lang spanish` or `-l spanish`. Note that giving two different forms of the same flag in the same command invocation is an error.
|
||||
|
||||
#### Values from the Environment
|
||||
|
||||
You can also have the default value set from the environment via `EnvVar`. e.g.
|
||||
|
||||
``` go
|
||||
app.Flags = []cli.Flag {
|
||||
cli.StringFlag{
|
||||
Name: "lang, l",
|
||||
Value: "english",
|
||||
Usage: "language for the greeting",
|
||||
EnvVar: "APP_LANG",
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
The `EnvVar` may also be given as a comma-delimited "cascade", where the first environment variable that resolves is used as the default.
|
||||
|
||||
``` go
|
||||
app.Flags = []cli.Flag {
|
||||
cli.StringFlag{
|
||||
Name: "lang, l",
|
||||
Value: "english",
|
||||
Usage: "language for the greeting",
|
||||
EnvVar: "LEGACY_COMPAT_LANG,APP_LANG,LANG",
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
### Subcommands
|
||||
|
||||
Subcommands can be defined for a more git-like command line app.
|
||||
```go
|
||||
...
|
||||
app.Commands = []cli.Command{
|
||||
{
|
||||
Name: "add",
|
||||
ShortName: "a",
|
||||
Usage: "add a task to the list",
|
||||
Action: func(c *cli.Context) {
|
||||
println("added task: ", c.Args().First())
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "complete",
|
||||
ShortName: "c",
|
||||
Usage: "complete a task on the list",
|
||||
Action: func(c *cli.Context) {
|
||||
println("completed task: ", c.Args().First())
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "template",
|
||||
ShortName: "r",
|
||||
Usage: "options for task templates",
|
||||
Subcommands: []cli.Command{
|
||||
{
|
||||
Name: "add",
|
||||
Usage: "add a new template",
|
||||
Action: func(c *cli.Context) {
|
||||
println("new task template: ", c.Args().First())
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "remove",
|
||||
Usage: "remove an existing template",
|
||||
Action: func(c *cli.Context) {
|
||||
println("removed task template: ", c.Args().First())
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
...
|
||||
```
|
||||
|
||||
### Bash Completion
|
||||
|
||||
You can enable completion commands by setting the `EnableBashCompletion`
|
||||
flag on the `App` object. By default, this setting will only auto-complete to
|
||||
show an app's subcommands, but you can write your own completion methods for
|
||||
the App or its subcommands.
|
||||
```go
|
||||
...
|
||||
var tasks = []string{"cook", "clean", "laundry", "eat", "sleep", "code"}
|
||||
app := cli.NewApp()
|
||||
app.EnableBashCompletion = true
|
||||
app.Commands = []cli.Command{
|
||||
{
|
||||
Name: "complete",
|
||||
ShortName: "c",
|
||||
Usage: "complete a task on the list",
|
||||
Action: func(c *cli.Context) {
|
||||
println("completed task: ", c.Args().First())
|
||||
},
|
||||
BashComplete: func(c *cli.Context) {
|
||||
// This will complete if no args are passed
|
||||
if len(c.Args()) > 0 {
|
||||
return
|
||||
}
|
||||
for _, t := range tasks {
|
||||
fmt.Println(t)
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
...
|
||||
```
|
||||
|
||||
#### To Enable
|
||||
|
||||
Source the `autocomplete/bash_autocomplete` file in your `.bashrc` file while
|
||||
setting the `PROG` variable to the name of your program:
|
||||
|
||||
`PROG=myprogram source /.../cli/autocomplete/bash_autocomplete`
|
||||
|
||||
|
||||
## Contribution Guidelines
|
||||
Feel free to put up a pull request to fix a bug or maybe add a feature. I will give it a code review and make sure that it does not break backwards compatibility. If I or any other collaborators agree that it is in line with the vision of the project, we will work with you to get the code into a mergeable state and merge it into the master branch.
|
||||
|
||||
If you are have contributed something significant to the project, I will most likely add you as a collaborator. As a collaborator you are given the ability to merge others pull requests. It is very important that new code does not break existing code, so be careful about what code you do choose to merge. If you have any questions feel free to link @codegangsta to the issue in question and we can review it together.
|
||||
|
||||
If you feel like you have contributed to the project but have not yet been added as a collaborator, I probably forgot to add you. Hit @codegangsta up over email and we will get it figured out.
|
275
vendor/github.com/codegangsta/cli/app.go
generated
vendored
275
vendor/github.com/codegangsta/cli/app.go
generated
vendored
|
@ -1,275 +0,0 @@
|
|||
package cli
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"text/tabwriter"
|
||||
"text/template"
|
||||
"time"
|
||||
)
|
||||
|
||||
// App is the main structure of a cli application. It is recomended that
|
||||
// and app be created with the cli.NewApp() function
|
||||
type App struct {
|
||||
// The name of the program. Defaults to os.Args[0]
|
||||
Name string
|
||||
// Description of the program.
|
||||
Usage string
|
||||
// Version of the program
|
||||
Version string
|
||||
// List of commands to execute
|
||||
Commands []Command
|
||||
// List of flags to parse
|
||||
Flags []Flag
|
||||
// Boolean to enable bash completion commands
|
||||
EnableBashCompletion bool
|
||||
// Boolean to hide built-in help command
|
||||
HideHelp bool
|
||||
// Boolean to hide built-in version flag
|
||||
HideVersion bool
|
||||
// An action to execute when the bash-completion flag is set
|
||||
BashComplete func(context *Context)
|
||||
// An action to execute before any subcommands are run, but after the context is ready
|
||||
// If a non-nil error is returned, no subcommands are run
|
||||
Before func(context *Context) error
|
||||
// The action to execute when no subcommands are specified
|
||||
Action func(context *Context)
|
||||
// Execute this function if the proper command cannot be found
|
||||
CommandNotFound func(context *Context, command string)
|
||||
// Compilation date
|
||||
Compiled time.Time
|
||||
// Author
|
||||
Author string
|
||||
// Author e-mail
|
||||
Email string
|
||||
// Writer writer to write output to
|
||||
Writer io.Writer
|
||||
}
|
||||
|
||||
// Tries to find out when this binary was compiled.
|
||||
// Returns the current time if it fails to find it.
|
||||
func compileTime() time.Time {
|
||||
info, err := os.Stat(os.Args[0])
|
||||
if err != nil {
|
||||
return time.Now()
|
||||
}
|
||||
return info.ModTime()
|
||||
}
|
||||
|
||||
// Creates a new cli Application with some reasonable defaults for Name, Usage, Version and Action.
|
||||
func NewApp() *App {
|
||||
return &App{
|
||||
Name: os.Args[0],
|
||||
Usage: "A new cli application",
|
||||
Version: "0.0.0",
|
||||
BashComplete: DefaultAppComplete,
|
||||
Action: helpCommand.Action,
|
||||
Compiled: compileTime(),
|
||||
Author: "Author",
|
||||
Email: "unknown@email",
|
||||
Writer: os.Stdout,
|
||||
}
|
||||
}
|
||||
|
||||
// Entry point to the cli app. Parses the arguments slice and routes to the proper flag/args combination
|
||||
func (a *App) Run(arguments []string) error {
|
||||
if HelpPrinter == nil {
|
||||
defer func() {
|
||||
HelpPrinter = nil
|
||||
}()
|
||||
|
||||
HelpPrinter = func(templ string, data interface{}) {
|
||||
w := tabwriter.NewWriter(a.Writer, 0, 8, 1, '\t', 0)
|
||||
t := template.Must(template.New("help").Parse(templ))
|
||||
err := t.Execute(w, data)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
w.Flush()
|
||||
}
|
||||
}
|
||||
|
||||
// append help to commands
|
||||
if a.Command(helpCommand.Name) == nil && !a.HideHelp {
|
||||
a.Commands = append(a.Commands, helpCommand)
|
||||
a.appendFlag(HelpFlag)
|
||||
}
|
||||
|
||||
//append version/help flags
|
||||
if a.EnableBashCompletion {
|
||||
a.appendFlag(BashCompletionFlag)
|
||||
}
|
||||
|
||||
if !a.HideVersion {
|
||||
a.appendFlag(VersionFlag)
|
||||
}
|
||||
|
||||
// parse flags
|
||||
set := flagSet(a.Name, a.Flags)
|
||||
set.SetOutput(ioutil.Discard)
|
||||
err := set.Parse(arguments[1:])
|
||||
nerr := normalizeFlags(a.Flags, set)
|
||||
if nerr != nil {
|
||||
fmt.Fprintln(a.Writer, nerr)
|
||||
context := NewContext(a, set, set)
|
||||
ShowAppHelp(context)
|
||||
fmt.Fprintln(a.Writer)
|
||||
return nerr
|
||||
}
|
||||
context := NewContext(a, set, set)
|
||||
|
||||
if err != nil {
|
||||
fmt.Fprintf(a.Writer, "Incorrect Usage.\n\n")
|
||||
ShowAppHelp(context)
|
||||
fmt.Fprintln(a.Writer)
|
||||
return err
|
||||
}
|
||||
|
||||
if checkCompletions(context) {
|
||||
return nil
|
||||
}
|
||||
|
||||
if checkHelp(context) {
|
||||
return nil
|
||||
}
|
||||
|
||||
if checkVersion(context) {
|
||||
return nil
|
||||
}
|
||||
|
||||
if a.Before != nil {
|
||||
err := a.Before(context)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
args := context.Args()
|
||||
if args.Present() {
|
||||
name := args.First()
|
||||
c := a.Command(name)
|
||||
if c != nil {
|
||||
return c.Run(context)
|
||||
}
|
||||
}
|
||||
|
||||
// Run default Action
|
||||
a.Action(context)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Another entry point to the cli app, takes care of passing arguments and error handling
|
||||
func (a *App) RunAndExitOnError() {
|
||||
if err := a.Run(os.Args); err != nil {
|
||||
fmt.Fprintln(os.Stderr, err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
// Invokes the subcommand given the context, parses ctx.Args() to generate command-specific flags
|
||||
func (a *App) RunAsSubcommand(ctx *Context) error {
|
||||
// append help to commands
|
||||
if len(a.Commands) > 0 {
|
||||
if a.Command(helpCommand.Name) == nil && !a.HideHelp {
|
||||
a.Commands = append(a.Commands, helpCommand)
|
||||
a.appendFlag(HelpFlag)
|
||||
}
|
||||
}
|
||||
|
||||
// append flags
|
||||
if a.EnableBashCompletion {
|
||||
a.appendFlag(BashCompletionFlag)
|
||||
}
|
||||
|
||||
// parse flags
|
||||
set := flagSet(a.Name, a.Flags)
|
||||
set.SetOutput(ioutil.Discard)
|
||||
err := set.Parse(ctx.Args().Tail())
|
||||
nerr := normalizeFlags(a.Flags, set)
|
||||
context := NewContext(a, set, ctx.globalSet)
|
||||
|
||||
if nerr != nil {
|
||||
fmt.Fprintln(a.Writer, nerr)
|
||||
if len(a.Commands) > 0 {
|
||||
ShowSubcommandHelp(context)
|
||||
} else {
|
||||
ShowCommandHelp(ctx, context.Args().First())
|
||||
}
|
||||
fmt.Fprintln(a.Writer)
|
||||
return nerr
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
fmt.Fprintf(a.Writer, "Incorrect Usage.\n\n")
|
||||
ShowSubcommandHelp(context)
|
||||
return err
|
||||
}
|
||||
|
||||
if checkCompletions(context) {
|
||||
return nil
|
||||
}
|
||||
|
||||
if len(a.Commands) > 0 {
|
||||
if checkSubcommandHelp(context) {
|
||||
return nil
|
||||
}
|
||||
} else {
|
||||
if checkCommandHelp(ctx, context.Args().First()) {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
if a.Before != nil {
|
||||
err := a.Before(context)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
args := context.Args()
|
||||
if args.Present() {
|
||||
name := args.First()
|
||||
c := a.Command(name)
|
||||
if c != nil {
|
||||
return c.Run(context)
|
||||
}
|
||||
}
|
||||
|
||||
// Run default Action
|
||||
if len(a.Commands) > 0 {
|
||||
a.Action(context)
|
||||
} else {
|
||||
a.Action(ctx)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Returns the named command on App. Returns nil if the command does not exist
|
||||
func (a *App) Command(name string) *Command {
|
||||
for _, c := range a.Commands {
|
||||
if c.HasName(name) {
|
||||
return &c
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *App) hasFlag(flag Flag) bool {
|
||||
for _, f := range a.Flags {
|
||||
if flag == f {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func (a *App) appendFlag(flag Flag) {
|
||||
if !a.hasFlag(flag) {
|
||||
a.Flags = append(a.Flags, flag)
|
||||
}
|
||||
}
|
467
vendor/github.com/codegangsta/cli/app_test.go
generated
vendored
467
vendor/github.com/codegangsta/cli/app_test.go
generated
vendored
|
@ -1,467 +0,0 @@
|
|||
package cli_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/codegangsta/cli"
|
||||
)
|
||||
|
||||
func ExampleApp() {
|
||||
// set args for examples sake
|
||||
os.Args = []string{"greet", "--name", "Jeremy"}
|
||||
|
||||
app := cli.NewApp()
|
||||
app.Name = "greet"
|
||||
app.Flags = []cli.Flag{
|
||||
cli.StringFlag{Name: "name", Value: "bob", Usage: "a name to say"},
|
||||
}
|
||||
app.Action = func(c *cli.Context) {
|
||||
fmt.Printf("Hello %v\n", c.String("name"))
|
||||
}
|
||||
app.Run(os.Args)
|
||||
// Output:
|
||||
// Hello Jeremy
|
||||
}
|
||||
|
||||
func ExampleAppSubcommand() {
|
||||
// set args for examples sake
|
||||
os.Args = []string{"say", "hi", "english", "--name", "Jeremy"}
|
||||
app := cli.NewApp()
|
||||
app.Name = "say"
|
||||
app.Commands = []cli.Command{
|
||||
{
|
||||
Name: "hello",
|
||||
ShortName: "hi",
|
||||
Usage: "use it to see a description",
|
||||
Description: "This is how we describe hello the function",
|
||||
Subcommands: []cli.Command{
|
||||
{
|
||||
Name: "english",
|
||||
ShortName: "en",
|
||||
Usage: "sends a greeting in english",
|
||||
Description: "greets someone in english",
|
||||
Flags: []cli.Flag{
|
||||
cli.StringFlag{
|
||||
Name: "name",
|
||||
Value: "Bob",
|
||||
Usage: "Name of the person to greet",
|
||||
},
|
||||
},
|
||||
Action: func(c *cli.Context) {
|
||||
fmt.Println("Hello,", c.String("name"))
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
app.Run(os.Args)
|
||||
// Output:
|
||||
// Hello, Jeremy
|
||||
}
|
||||
|
||||
func ExampleAppHelp() {
|
||||
// set args for examples sake
|
||||
os.Args = []string{"greet", "h", "describeit"}
|
||||
|
||||
app := cli.NewApp()
|
||||
app.Name = "greet"
|
||||
app.Flags = []cli.Flag{
|
||||
cli.StringFlag{Name: "name", Value: "bob", Usage: "a name to say"},
|
||||
}
|
||||
app.Commands = []cli.Command{
|
||||
{
|
||||
Name: "describeit",
|
||||
ShortName: "d",
|
||||
Usage: "use it to see a description",
|
||||
Description: "This is how we describe describeit the function",
|
||||
Action: func(c *cli.Context) {
|
||||
fmt.Printf("i like to describe things")
|
||||
},
|
||||
},
|
||||
}
|
||||
app.Run(os.Args)
|
||||
// Output:
|
||||
// NAME:
|
||||
// describeit - use it to see a description
|
||||
//
|
||||
// USAGE:
|
||||
// command describeit [arguments...]
|
||||
//
|
||||
// DESCRIPTION:
|
||||
// This is how we describe describeit the function
|
||||
}
|
||||
|
||||
func ExampleAppBashComplete() {
|
||||
// set args for examples sake
|
||||
os.Args = []string{"greet", "--generate-bash-completion"}
|
||||
|
||||
app := cli.NewApp()
|
||||
app.Name = "greet"
|
||||
app.EnableBashCompletion = true
|
||||
app.Commands = []cli.Command{
|
||||
{
|
||||
Name: "describeit",
|
||||
ShortName: "d",
|
||||
Usage: "use it to see a description",
|
||||
Description: "This is how we describe describeit the function",
|
||||
Action: func(c *cli.Context) {
|
||||
fmt.Printf("i like to describe things")
|
||||
},
|
||||
}, {
|
||||
Name: "next",
|
||||
Usage: "next example",
|
||||
Description: "more stuff to see when generating bash completion",
|
||||
Action: func(c *cli.Context) {
|
||||
fmt.Printf("the next example")
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
app.Run(os.Args)
|
||||
// Output:
|
||||
// describeit
|
||||
// d
|
||||
// next
|
||||
// help
|
||||
// h
|
||||
}
|
||||
|
||||
func TestApp_Run(t *testing.T) {
|
||||
s := ""
|
||||
|
||||
app := cli.NewApp()
|
||||
app.Action = func(c *cli.Context) {
|
||||
s = s + c.Args().First()
|
||||
}
|
||||
|
||||
err := app.Run([]string{"command", "foo"})
|
||||
expect(t, err, nil)
|
||||
err = app.Run([]string{"command", "bar"})
|
||||
expect(t, err, nil)
|
||||
expect(t, s, "foobar")
|
||||
}
|
||||
|
||||
var commandAppTests = []struct {
|
||||
name string
|
||||
expected bool
|
||||
}{
|
||||
{"foobar", true},
|
||||
{"batbaz", true},
|
||||
{"b", true},
|
||||
{"f", true},
|
||||
{"bat", false},
|
||||
{"nothing", false},
|
||||
}
|
||||
|
||||
func TestApp_Command(t *testing.T) {
|
||||
app := cli.NewApp()
|
||||
fooCommand := cli.Command{Name: "foobar", ShortName: "f"}
|
||||
batCommand := cli.Command{Name: "batbaz", ShortName: "b"}
|
||||
app.Commands = []cli.Command{
|
||||
fooCommand,
|
||||
batCommand,
|
||||
}
|
||||
|
||||
for _, test := range commandAppTests {
|
||||
expect(t, app.Command(test.name) != nil, test.expected)
|
||||
}
|
||||
}
|
||||
|
||||
func TestApp_CommandWithArgBeforeFlags(t *testing.T) {
|
||||
var parsedOption, firstArg string
|
||||
|
||||
app := cli.NewApp()
|
||||
command := cli.Command{
|
||||
Name: "cmd",
|
||||
Flags: []cli.Flag{
|
||||
cli.StringFlag{Name: "option", Value: "", Usage: "some option"},
|
||||
},
|
||||
Action: func(c *cli.Context) {
|
||||
parsedOption = c.String("option")
|
||||
firstArg = c.Args().First()
|
||||
},
|
||||
}
|
||||
app.Commands = []cli.Command{command}
|
||||
|
||||
app.Run([]string{"", "cmd", "my-arg", "--option", "my-option"})
|
||||
|
||||
expect(t, parsedOption, "my-option")
|
||||
expect(t, firstArg, "my-arg")
|
||||
}
|
||||
|
||||
func TestApp_Float64Flag(t *testing.T) {
|
||||
var meters float64
|
||||
|
||||
app := cli.NewApp()
|
||||
app.Flags = []cli.Flag{
|
||||
cli.Float64Flag{Name: "height", Value: 1.5, Usage: "Set the height, in meters"},
|
||||
}
|
||||
app.Action = func(c *cli.Context) {
|
||||
meters = c.Float64("height")
|
||||
}
|
||||
|
||||
app.Run([]string{"", "--height", "1.93"})
|
||||
expect(t, meters, 1.93)
|
||||
}
|
||||
|
||||
func TestApp_ParseSliceFlags(t *testing.T) {
|
||||
var parsedOption, firstArg string
|
||||
var parsedIntSlice []int
|
||||
var parsedStringSlice []string
|
||||
|
||||
app := cli.NewApp()
|
||||
command := cli.Command{
|
||||
Name: "cmd",
|
||||
Flags: []cli.Flag{
|
||||
cli.IntSliceFlag{Name: "p", Value: &cli.IntSlice{}, Usage: "set one or more ip addr"},
|
||||
cli.StringSliceFlag{Name: "ip", Value: &cli.StringSlice{}, Usage: "set one or more ports to open"},
|
||||
},
|
||||
Action: func(c *cli.Context) {
|
||||
parsedIntSlice = c.IntSlice("p")
|
||||
parsedStringSlice = c.StringSlice("ip")
|
||||
parsedOption = c.String("option")
|
||||
firstArg = c.Args().First()
|
||||
},
|
||||
}
|
||||
app.Commands = []cli.Command{command}
|
||||
|
||||
app.Run([]string{"", "cmd", "my-arg", "-p", "22", "-p", "80", "-ip", "8.8.8.8", "-ip", "8.8.4.4"})
|
||||
|
||||
IntsEquals := func(a, b []int) bool {
|
||||
if len(a) != len(b) {
|
||||
return false
|
||||
}
|
||||
for i, v := range a {
|
||||
if v != b[i] {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
StrsEquals := func(a, b []string) bool {
|
||||
if len(a) != len(b) {
|
||||
return false
|
||||
}
|
||||
for i, v := range a {
|
||||
if v != b[i] {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
var expectedIntSlice = []int{22, 80}
|
||||
var expectedStringSlice = []string{"8.8.8.8", "8.8.4.4"}
|
||||
|
||||
if !IntsEquals(parsedIntSlice, expectedIntSlice) {
|
||||
t.Errorf("%v does not match %v", parsedIntSlice, expectedIntSlice)
|
||||
}
|
||||
|
||||
if !StrsEquals(parsedStringSlice, expectedStringSlice) {
|
||||
t.Errorf("%v does not match %v", parsedStringSlice, expectedStringSlice)
|
||||
}
|
||||
}
|
||||
|
||||
func TestApp_DefaultStdout(t *testing.T) {
|
||||
app := cli.NewApp()
|
||||
|
||||
if app.Writer != os.Stdout {
|
||||
t.Error("Default output writer not set.")
|
||||
}
|
||||
}
|
||||
|
||||
type mockWriter struct {
|
||||
written []byte
|
||||
}
|
||||
|
||||
func (fw *mockWriter) Write(p []byte) (n int, err error) {
|
||||
if fw.written == nil {
|
||||
fw.written = p
|
||||
} else {
|
||||
fw.written = append(fw.written, p...)
|
||||
}
|
||||
|
||||
return len(p), nil
|
||||
}
|
||||
|
||||
func (fw *mockWriter) GetWritten() (b []byte) {
|
||||
return fw.written
|
||||
}
|
||||
|
||||
func TestApp_SetStdout(t *testing.T) {
|
||||
w := &mockWriter{}
|
||||
|
||||
app := cli.NewApp()
|
||||
app.Name = "test"
|
||||
app.Writer = w
|
||||
|
||||
err := app.Run([]string{"help"})
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("Run error: %s", err)
|
||||
}
|
||||
|
||||
if len(w.written) == 0 {
|
||||
t.Error("App did not write output to desired writer.")
|
||||
}
|
||||
}
|
||||
|
||||
func TestApp_BeforeFunc(t *testing.T) {
|
||||
beforeRun, subcommandRun := false, false
|
||||
beforeError := fmt.Errorf("fail")
|
||||
var err error
|
||||
|
||||
app := cli.NewApp()
|
||||
|
||||
app.Before = func(c *cli.Context) error {
|
||||
beforeRun = true
|
||||
s := c.String("opt")
|
||||
if s == "fail" {
|
||||
return beforeError
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
app.Commands = []cli.Command{
|
||||
cli.Command{
|
||||
Name: "sub",
|
||||
Action: func(c *cli.Context) {
|
||||
subcommandRun = true
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
app.Flags = []cli.Flag{
|
||||
cli.StringFlag{Name: "opt"},
|
||||
}
|
||||
|
||||
// run with the Before() func succeeding
|
||||
err = app.Run([]string{"command", "--opt", "succeed", "sub"})
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("Run error: %s", err)
|
||||
}
|
||||
|
||||
if beforeRun == false {
|
||||
t.Errorf("Before() not executed when expected")
|
||||
}
|
||||
|
||||
if subcommandRun == false {
|
||||
t.Errorf("Subcommand not executed when expected")
|
||||
}
|
||||
|
||||
// reset
|
||||
beforeRun, subcommandRun = false, false
|
||||
|
||||
// run with the Before() func failing
|
||||
err = app.Run([]string{"command", "--opt", "fail", "sub"})
|
||||
|
||||
// should be the same error produced by the Before func
|
||||
if err != beforeError {
|
||||
t.Errorf("Run error expected, but not received")
|
||||
}
|
||||
|
||||
if beforeRun == false {
|
||||
t.Errorf("Before() not executed when expected")
|
||||
}
|
||||
|
||||
if subcommandRun == true {
|
||||
t.Errorf("Subcommand executed when NOT expected")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestAppHelpPrinter(t *testing.T) {
|
||||
oldPrinter := cli.HelpPrinter
|
||||
defer func() {
|
||||
cli.HelpPrinter = oldPrinter
|
||||
}()
|
||||
|
||||
var wasCalled = false
|
||||
cli.HelpPrinter = func(template string, data interface{}) {
|
||||
wasCalled = true
|
||||
}
|
||||
|
||||
app := cli.NewApp()
|
||||
app.Run([]string{"-h"})
|
||||
|
||||
if wasCalled == false {
|
||||
t.Errorf("Help printer expected to be called, but was not")
|
||||
}
|
||||
}
|
||||
|
||||
func TestAppVersionPrinter(t *testing.T) {
|
||||
oldPrinter := cli.VersionPrinter
|
||||
defer func() {
|
||||
cli.VersionPrinter = oldPrinter
|
||||
}()
|
||||
|
||||
var wasCalled = false
|
||||
cli.VersionPrinter = func(c *cli.Context) {
|
||||
wasCalled = true
|
||||
}
|
||||
|
||||
app := cli.NewApp()
|
||||
ctx := cli.NewContext(app, nil, nil)
|
||||
cli.ShowVersion(ctx)
|
||||
|
||||
if wasCalled == false {
|
||||
t.Errorf("Version printer expected to be called, but was not")
|
||||
}
|
||||
}
|
||||
|
||||
func TestAppCommandNotFound(t *testing.T) {
|
||||
beforeRun, subcommandRun := false, false
|
||||
app := cli.NewApp()
|
||||
|
||||
app.CommandNotFound = func(c *cli.Context, command string) {
|
||||
beforeRun = true
|
||||
}
|
||||
|
||||
app.Commands = []cli.Command{
|
||||
cli.Command{
|
||||
Name: "bar",
|
||||
Action: func(c *cli.Context) {
|
||||
subcommandRun = true
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
app.Run([]string{"command", "foo"})
|
||||
|
||||
expect(t, beforeRun, true)
|
||||
expect(t, subcommandRun, false)
|
||||
}
|
||||
|
||||
func TestGlobalFlagsInSubcommands(t *testing.T) {
|
||||
subcommandRun := false
|
||||
app := cli.NewApp()
|
||||
|
||||
app.Flags = []cli.Flag{
|
||||
cli.BoolFlag{Name: "debug, d", Usage: "Enable debugging"},
|
||||
}
|
||||
|
||||
app.Commands = []cli.Command{
|
||||
cli.Command{
|
||||
Name: "foo",
|
||||
Subcommands: []cli.Command{
|
||||
{
|
||||
Name: "bar",
|
||||
Action: func(c *cli.Context) {
|
||||
if c.GlobalBool("debug") {
|
||||
subcommandRun = true
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
app.Run([]string{"command", "-d", "foo", "bar"})
|
||||
|
||||
expect(t, subcommandRun, true)
|
||||
}
|
13
vendor/github.com/codegangsta/cli/autocomplete/bash_autocomplete
generated
vendored
13
vendor/github.com/codegangsta/cli/autocomplete/bash_autocomplete
generated
vendored
|
@ -1,13 +0,0 @@
|
|||
#! /bin/bash
|
||||
|
||||
_cli_bash_autocomplete() {
|
||||
local cur prev opts base
|
||||
COMPREPLY=()
|
||||
cur="${COMP_WORDS[COMP_CWORD]}"
|
||||
prev="${COMP_WORDS[COMP_CWORD-1]}"
|
||||
opts=$( ${COMP_WORDS[@]:0:$COMP_CWORD} --generate-bash-completion )
|
||||
COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
|
||||
return 0
|
||||
}
|
||||
|
||||
complete -F _cli_bash_autocomplete $PROG
|
5
vendor/github.com/codegangsta/cli/autocomplete/zsh_autocomplete
generated
vendored
5
vendor/github.com/codegangsta/cli/autocomplete/zsh_autocomplete
generated
vendored
|
@ -1,5 +0,0 @@
|
|||
autoload -U compinit && compinit
|
||||
autoload -U bashcompinit && bashcompinit
|
||||
|
||||
script_dir=$(dirname $0)
|
||||
source ${script_dir}/bash_autocomplete
|
19
vendor/github.com/codegangsta/cli/cli.go
generated
vendored
19
vendor/github.com/codegangsta/cli/cli.go
generated
vendored
|
@ -1,19 +0,0 @@
|
|||
// Package cli provides a minimal framework for creating and organizing command line
|
||||
// Go applications. cli is designed to be easy to understand and write, the most simple
|
||||
// cli application can be written as follows:
|
||||
// func main() {
|
||||
// cli.NewApp().Run(os.Args)
|
||||
// }
|
||||
//
|
||||
// Of course this application does not do much, so let's make this an actual application:
|
||||
// func main() {
|
||||
// app := cli.NewApp()
|
||||
// app.Name = "greet"
|
||||
// app.Usage = "say a greeting"
|
||||
// app.Action = func(c *cli.Context) {
|
||||
// println("Greetings")
|
||||
// }
|
||||
//
|
||||
// app.Run(os.Args)
|
||||
// }
|
||||
package cli
|
100
vendor/github.com/codegangsta/cli/cli_test.go
generated
vendored
100
vendor/github.com/codegangsta/cli/cli_test.go
generated
vendored
|
@ -1,100 +0,0 @@
|
|||
package cli_test
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/codegangsta/cli"
|
||||
)
|
||||
|
||||
func Example() {
|
||||
app := cli.NewApp()
|
||||
app.Name = "todo"
|
||||
app.Usage = "task list on the command line"
|
||||
app.Commands = []cli.Command{
|
||||
{
|
||||
Name: "add",
|
||||
ShortName: "a",
|
||||
Usage: "add a task to the list",
|
||||
Action: func(c *cli.Context) {
|
||||
println("added task: ", c.Args().First())
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "complete",
|
||||
ShortName: "c",
|
||||
Usage: "complete a task on the list",
|
||||
Action: func(c *cli.Context) {
|
||||
println("completed task: ", c.Args().First())
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
app.Run(os.Args)
|
||||
}
|
||||
|
||||
func ExampleSubcommand() {
|
||||
app := cli.NewApp()
|
||||
app.Name = "say"
|
||||
app.Commands = []cli.Command{
|
||||
{
|
||||
Name: "hello",
|
||||
ShortName: "hi",
|
||||
Usage: "use it to see a description",
|
||||
Description: "This is how we describe hello the function",
|
||||
Subcommands: []cli.Command{
|
||||
{
|
||||
Name: "english",
|
||||
ShortName: "en",
|
||||
Usage: "sends a greeting in english",
|
||||
Description: "greets someone in english",
|
||||
Flags: []cli.Flag{
|
||||
cli.StringFlag{
|
||||
Name: "name",
|
||||
Value: "Bob",
|
||||
Usage: "Name of the person to greet",
|
||||
},
|
||||
},
|
||||
Action: func(c *cli.Context) {
|
||||
println("Hello, ", c.String("name"))
|
||||
},
|
||||
}, {
|
||||
Name: "spanish",
|
||||
ShortName: "sp",
|
||||
Usage: "sends a greeting in spanish",
|
||||
Flags: []cli.Flag{
|
||||
cli.StringFlag{
|
||||
Name: "surname",
|
||||
Value: "Jones",
|
||||
Usage: "Surname of the person to greet",
|
||||
},
|
||||
},
|
||||
Action: func(c *cli.Context) {
|
||||
println("Hola, ", c.String("surname"))
|
||||
},
|
||||
}, {
|
||||
Name: "french",
|
||||
ShortName: "fr",
|
||||
Usage: "sends a greeting in french",
|
||||
Flags: []cli.Flag{
|
||||
cli.StringFlag{
|
||||
Name: "nickname",
|
||||
Value: "Stevie",
|
||||
Usage: "Nickname of the person to greet",
|
||||
},
|
||||
},
|
||||
Action: func(c *cli.Context) {
|
||||
println("Bonjour, ", c.String("nickname"))
|
||||
},
|
||||
},
|
||||
},
|
||||
}, {
|
||||
Name: "bye",
|
||||
Usage: "says goodbye",
|
||||
Action: func(c *cli.Context) {
|
||||
println("bye")
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
app.Run(os.Args)
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue