Browse Source

better logging

tags/0.0.2
Vladimir Smagin 3 weeks ago
parent
commit
376b852824
100 changed files with 8512 additions and 17 deletions
  1. +1
    -0
      .gitignore
  2. +2
    -0
      go.mod
  3. +10
    -0
      go.sum
  4. +49
    -17
      main.go
  5. +16
    -0
      vendor/github.com/withmandala/go-log/.editorconfig
  6. +20
    -0
      vendor/github.com/withmandala/go-log/.gitignore
  7. +77
    -0
      vendor/github.com/withmandala/go-log/README.md
  8. +42
    -0
      vendor/github.com/withmandala/go-log/buffer/buffer.go
  9. +104
    -0
      vendor/github.com/withmandala/go-log/colorful/colorful.go
  10. +16
    -0
      vendor/github.com/withmandala/go-log/glide.lock
  11. +9
    -0
      vendor/github.com/withmandala/go-log/glide.yaml
  12. +342
    -0
      vendor/github.com/withmandala/go-log/log.go
  13. +3
    -0
      vendor/golang.org/x/crypto/AUTHORS
  14. +3
    -0
      vendor/golang.org/x/crypto/CONTRIBUTORS
  15. +27
    -0
      vendor/golang.org/x/crypto/LICENSE
  16. +22
    -0
      vendor/golang.org/x/crypto/PATENTS
  17. +987
    -0
      vendor/golang.org/x/crypto/ssh/terminal/terminal.go
  18. +114
    -0
      vendor/golang.org/x/crypto/ssh/terminal/util.go
  19. +12
    -0
      vendor/golang.org/x/crypto/ssh/terminal/util_aix.go
  20. +12
    -0
      vendor/golang.org/x/crypto/ssh/terminal/util_bsd.go
  21. +10
    -0
      vendor/golang.org/x/crypto/ssh/terminal/util_linux.go
  22. +58
    -0
      vendor/golang.org/x/crypto/ssh/terminal/util_plan9.go
  23. +124
    -0
      vendor/golang.org/x/crypto/ssh/terminal/util_solaris.go
  24. +105
    -0
      vendor/golang.org/x/crypto/ssh/terminal/util_windows.go
  25. +3
    -0
      vendor/golang.org/x/sys/AUTHORS
  26. +3
    -0
      vendor/golang.org/x/sys/CONTRIBUTORS
  27. +27
    -0
      vendor/golang.org/x/sys/LICENSE
  28. +22
    -0
      vendor/golang.org/x/sys/PATENTS
  29. +2
    -0
      vendor/golang.org/x/sys/unix/.gitignore
  30. +173
    -0
      vendor/golang.org/x/sys/unix/README.md
  31. +124
    -0
      vendor/golang.org/x/sys/unix/affinity_linux.go
  32. +14
    -0
      vendor/golang.org/x/sys/unix/aliases.go
  33. +17
    -0
      vendor/golang.org/x/sys/unix/asm_aix_ppc64.s
  34. +29
    -0
      vendor/golang.org/x/sys/unix/asm_darwin_386.s
  35. +29
    -0
      vendor/golang.org/x/sys/unix/asm_darwin_amd64.s
  36. +30
    -0
      vendor/golang.org/x/sys/unix/asm_darwin_arm.s
  37. +30
    -0
      vendor/golang.org/x/sys/unix/asm_darwin_arm64.s
  38. +29
    -0
      vendor/golang.org/x/sys/unix/asm_dragonfly_amd64.s
  39. +29
    -0
      vendor/golang.org/x/sys/unix/asm_freebsd_386.s
  40. +29
    -0
      vendor/golang.org/x/sys/unix/asm_freebsd_amd64.s
  41. +29
    -0
      vendor/golang.org/x/sys/unix/asm_freebsd_arm.s
  42. +29
    -0
      vendor/golang.org/x/sys/unix/asm_freebsd_arm64.s
  43. +65
    -0
      vendor/golang.org/x/sys/unix/asm_linux_386.s
  44. +57
    -0
      vendor/golang.org/x/sys/unix/asm_linux_amd64.s
  45. +56
    -0
      vendor/golang.org/x/sys/unix/asm_linux_arm.s
  46. +52
    -0
      vendor/golang.org/x/sys/unix/asm_linux_arm64.s
  47. +56
    -0
      vendor/golang.org/x/sys/unix/asm_linux_mips64x.s
  48. +54
    -0
      vendor/golang.org/x/sys/unix/asm_linux_mipsx.s
  49. +44
    -0
      vendor/golang.org/x/sys/unix/asm_linux_ppc64x.s
  50. +56
    -0
      vendor/golang.org/x/sys/unix/asm_linux_s390x.s
  51. +29
    -0
      vendor/golang.org/x/sys/unix/asm_netbsd_386.s
  52. +29
    -0
      vendor/golang.org/x/sys/unix/asm_netbsd_amd64.s
  53. +29
    -0
      vendor/golang.org/x/sys/unix/asm_netbsd_arm.s
  54. +29
    -0
      vendor/golang.org/x/sys/unix/asm_netbsd_arm64.s
  55. +29
    -0
      vendor/golang.org/x/sys/unix/asm_openbsd_386.s
  56. +29
    -0
      vendor/golang.org/x/sys/unix/asm_openbsd_amd64.s
  57. +29
    -0
      vendor/golang.org/x/sys/unix/asm_openbsd_arm.s
  58. +17
    -0
      vendor/golang.org/x/sys/unix/asm_solaris_amd64.s
  59. +35
    -0
      vendor/golang.org/x/sys/unix/bluetooth_linux.go
  60. +195
    -0
      vendor/golang.org/x/sys/unix/cap_freebsd.go
  61. +13
    -0
      vendor/golang.org/x/sys/unix/constants.go
  62. +27
    -0
      vendor/golang.org/x/sys/unix/dev_aix_ppc.go
  63. +29
    -0
      vendor/golang.org/x/sys/unix/dev_aix_ppc64.go
  64. +24
    -0
      vendor/golang.org/x/sys/unix/dev_darwin.go
  65. +30
    -0
      vendor/golang.org/x/sys/unix/dev_dragonfly.go
  66. +30
    -0
      vendor/golang.org/x/sys/unix/dev_freebsd.go
  67. +42
    -0
      vendor/golang.org/x/sys/unix/dev_linux.go
  68. +29
    -0
      vendor/golang.org/x/sys/unix/dev_netbsd.go
  69. +29
    -0
      vendor/golang.org/x/sys/unix/dev_openbsd.go
  70. +17
    -0
      vendor/golang.org/x/sys/unix/dirent.go
  71. +9
    -0
      vendor/golang.org/x/sys/unix/endian_big.go
  72. +9
    -0
      vendor/golang.org/x/sys/unix/endian_little.go
  73. +31
    -0
      vendor/golang.org/x/sys/unix/env_unix.go
  74. +227
    -0
      vendor/golang.org/x/sys/unix/errors_freebsd_386.go
  75. +227
    -0
      vendor/golang.org/x/sys/unix/errors_freebsd_amd64.go
  76. +226
    -0
      vendor/golang.org/x/sys/unix/errors_freebsd_arm.go
  77. +32
    -0
      vendor/golang.org/x/sys/unix/fcntl.go
  78. +18
    -0
      vendor/golang.org/x/sys/unix/fcntl_darwin.go
  79. +13
    -0
      vendor/golang.org/x/sys/unix/fcntl_linux_32bit.go
  80. +62
    -0
      vendor/golang.org/x/sys/unix/gccgo.go
  81. +39
    -0
      vendor/golang.org/x/sys/unix/gccgo_c.c
  82. +20
    -0
      vendor/golang.org/x/sys/unix/gccgo_linux_amd64.go
  83. +30
    -0
      vendor/golang.org/x/sys/unix/ioctl.go
  84. +212
    -0
      vendor/golang.org/x/sys/unix/mkall.sh
  85. +659
    -0
      vendor/golang.org/x/sys/unix/mkerrors.sh
  86. +265
    -0
      vendor/golang.org/x/sys/unix/mksysctl_openbsd.pl
  87. +166
    -0
      vendor/golang.org/x/sys/unix/openbsd_pledge.go
  88. +44
    -0
      vendor/golang.org/x/sys/unix/openbsd_unveil.go
  89. +15
    -0
      vendor/golang.org/x/sys/unix/pagesize_unix.go
  90. +30
    -0
      vendor/golang.org/x/sys/unix/race.go
  91. +25
    -0
      vendor/golang.org/x/sys/unix/race0.go
  92. +36
    -0
      vendor/golang.org/x/sys/unix/sockcmsg_linux.go
  93. +117
    -0
      vendor/golang.org/x/sys/unix/sockcmsg_unix.go
  94. +26
    -0
      vendor/golang.org/x/sys/unix/str.go
  95. +54
    -0
      vendor/golang.org/x/sys/unix/syscall.go
  96. +549
    -0
      vendor/golang.org/x/sys/unix/syscall_aix.go
  97. +34
    -0
      vendor/golang.org/x/sys/unix/syscall_aix_ppc.go
  98. +34
    -0
      vendor/golang.org/x/sys/unix/syscall_aix_ppc64.go
  99. +624
    -0
      vendor/golang.org/x/sys/unix/syscall_bsd.go
  100. +706
    -0
      vendor/golang.org/x/sys/unix/syscall_darwin.go

+ 1
- 0
.gitignore View File

@@ -1 +1,2 @@
config.yaml
compare-pg

+ 2
- 0
go.mod View File

@@ -4,5 +4,7 @@ go 1.14

require (
github.com/lib/pq v1.7.0
github.com/withmandala/go-log v0.1.0
golang.org/x/crypto v0.0.0-20200709230013-948cd5f35899 // indirect
gopkg.in/yaml.v2 v2.3.0
)

+ 10
- 0
go.sum View File

@@ -1,5 +1,15 @@
github.com/lib/pq v1.7.0 h1:h93mCPfUSkaul3Ka/VG8uZdmW1uMHDGxzu0NWHuJmHY=
github.com/lib/pq v1.7.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/withmandala/go-log v0.1.0 h1:wINmTEe7BQ6zEA8sE7lSsYeaxCLluK6RFjF/IB5tzkA=
github.com/withmandala/go-log v0.1.0/go.mod h1:/V9xQUTW74VjYm3u2Liv/bIUGLWoL9z2GlHwtscp4vg=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20200709230013-948cd5f35899 h1:DZhuSZLsGlFL4CmhA8BcRA0mnthyA/nZ00AqCUo7vHg=
golang.org/x/crypto v0.0.0-20200709230013-948cd5f35899/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d h1:+R4KGOnez64A81RvjARKc4UT5/tI9ujCIVX+P5KiHuI=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=


+ 49
- 17
main.go View File

@@ -4,12 +4,15 @@ import (
"database/sql"
"fmt"
"io/ioutil"
"log"
"os"

_ "github.com/lib/pq"
"github.com/withmandala/go-log"
"gopkg.in/yaml.v2"
)

var logger *log.Logger

type config struct {
Credentials map[string]string `yaml:"credentials"`
}
@@ -23,14 +26,16 @@ func loadConfig() config {

yamldata, err := ioutil.ReadFile("config.yaml")
if err != nil {
log.Fatalf("Error opening file %v", err)
logger.Errorf("Error opening file %v", err)
os.Exit(1)
}

marshErr := yaml.Unmarshal(yamldata, &conf)
if marshErr != nil {
log.Fatalf("Config file malformed: %v", marshErr)
logger.Fatalf("Config file malformed: %v", marshErr)
os.Exit(1)
}
log.Println("Loaded config:", conf)
logger.Info("Loaded config:", conf)
return conf
}

@@ -40,33 +45,48 @@ func getCount(db *sql.DB, tableName string) int {
row := db.QueryRow(sqlStatement)
switch err := row.Scan(&cnt); err {
case sql.ErrNoRows:
log.Println("No rows were returned!")
logger.Warn("No rows were returned!")
case nil:
return cnt
default:
log.Println("Error", err, "DB", db)
logger.Error("Error", err, "DB", db)
}
return 0
return -1
}

func getSize(db *sql.DB, tableName string) string {
sqlStatement := fmt.Sprintf("SELECT pg_size_pretty( pg_total_relation_size('%v') );", tableName)
var size string
row := db.QueryRow(sqlStatement)
switch err := row.Scan(&size); err {
case sql.ErrNoRows:
logger.Warn("No rows were returned!")
case nil:
return size
default:
logger.Error("Error", err, "DB", db)
}
return "NAN"
}

func getTableNames(db *sql.DB) []string {
rows, err := db.Query("SELECT tablename FROM pg_catalog.pg_tables WHERE schemaname != 'pg_catalog' AND schemaname != 'information_schema';")
resultSet := []string{}
if err != nil {
log.Fatalln(err)
logger.Error(err)
}
defer rows.Close()
for rows.Next() {
var tableName string
err = rows.Scan(&tableName)
if err != nil {
log.Fatalln(err)
logger.Error(err)
}
resultSet = append(resultSet, tableName)
}
err = rows.Err()
if err != nil {
log.Fatalln(err)
logger.Error(err)
}
return resultSet
}
@@ -81,7 +101,7 @@ func inList(list []string, value string) bool {
}

func main() {
logger = log.New(os.Stderr).WithColor()
// Config
conf := loadConfig()
pg := pgConnections{}
@@ -91,15 +111,15 @@ func main() {
for pgName, pgConnectString := range conf.Credentials {
db, err := sql.Open("postgres", pgConnectString)
if err != nil {
log.Fatalln(err)
logger.Error(err)
}
defer db.Close()

err = db.Ping()
if err != nil {
log.Fatalln(err)
logger.Error(err)
}
log.Println(pgName, "successfully connected!")
logger.Info(pgName, "successfully connected!")
pgConfigs[pgName] = db
}
pg.Handlers = pgConfigs
@@ -117,10 +137,22 @@ func main() {

// Show records count
for _, tableName := range tablesList {
log.Println("Table name:", tableName)
logger.Info("Table name:", tableName)
counts := []int{}
differenceFlag := false
for pgName, handlerDB := range pg.Handlers {
log.Println("Postgres name:", pgName, "Count:", getCount(handlerDB, tableName))
size := getSize(handlerDB, tableName)
count := getCount(handlerDB, tableName)
logger.Info("Postgres name:", pgName, "\tCount:", count, "\tSize:", size)
if len(counts) > 0 && counts[len(counts)-1] != count {
differenceFlag = true
}
counts = append(counts, count)
}
if differenceFlag {
logger.Warn("------------ TABLES DIFFERENT ------------")
} else {
logger.Info("------------")
}
log.Println("------------")
}
}

+ 16
- 0
vendor/github.com/withmandala/go-log/.editorconfig View File

@@ -0,0 +1,16 @@
# EditorConfig configuration file

# Set as top-most config file
root = true

# Set for every file
[*]
end_of_line = lf
insert_final_newline = true

# Set indentation for Golang file
[*.go]
charset = utf-8
indent_style = tab
indent_size = 4
trim_trailing_whitespace = true

+ 20
- 0
vendor/github.com/withmandala/go-log/.gitignore View File

@@ -0,0 +1,20 @@
# Binaries for programs and plugins
*.exe
*.dll
*.so
*.dylib

# Test binary, build with `go test -c`
*.test

# Output of the go coverage tool, specifically when used with LiteIDE
*.out

# Project-local glide cache, RE: https://github.com/Masterminds/glide/issues/736
.glide/

# Vendor folder
vendor/

# Environment variable file
.env

+ 77
- 0
vendor/github.com/withmandala/go-log/README.md View File

@@ -0,0 +1,77 @@
Golang Logging Library
=======================

The colorful and simple logging library for Golang.

## What is this

Opinionated logging library that able to output to `io.Reader` with file descriptors (`os.Stdout`, `os.Stderr`,
regular file, etc.) with automatic terminal color support.

The log serverity and behavior can be described as follows:

| Severity | Description | Caller Info |
|:--------:|:------------|:-----------:|
| Fatal | Unrecoverable error and automatically exit after logging | Yes |
| Error | Recoverable error but need attention | Yes |
| Warn | Minor error and does not output the caller info | No |
| Info | Informational message | No |
| Debug | Debug message, only shown when debug enabled | Yes |
| Trace | Trace message, only shown when debug enabled | No |

## Getting started

Add the `go-log` package using

```
go get github.com/withmandala/go-log
```

And import it to your package by

```go
import (
"github.com/withmandala/go-log"
)
```

Use the `go-log` package with

```go
logger := log.New(os.Stderr)
logger.Info("Hi, this is your logger")
```

## Color support

The library will try to automatically detect the `io.Reader` file descriptor when calling `log.New()` for color
support. But, if you insist to use or not to use color, you can add `.WithColor()` or `.WithoutColor()` respectively.

```go
// With color
logger := log.New(os.Stderr).WithColor()

// Without color
logger := log.New(os.Stderr).WithoutColor()
```

## Debug output

The log library will suppress the `.Debug()` and `.Trace()` output by default. To enable or disable the debug output,
call `(Logger).WithDebug()` or `(Logger).WithoutDebug()` respectively.

```go
// Enable debugging
logger := log.New(os.Stderr).WithDebug()
// Print debug output
logger.Debug("Test debug output")
// Disable debug output
logger.WithoutDebug()
logger.Debug("Test debug output") // This message will not be printed
```

## Be Quiet

If somehow the log is annoying to you, just shush it by calling `(Logger).Quiet()` and **ALL** log output will be
disappear, although `.Fatal()` will silently quit the program with error. To re-enable the log output use
`(Logger).NoQuiet()`.

+ 42
- 0
vendor/github.com/withmandala/go-log/buffer/buffer.go View File

@@ -0,0 +1,42 @@
// Buffer-like byte slice
// Copyright (c) 2017 Fadhli Dzil Ikram

package buffer

// Buffer type wrap up byte slice built-in type
type Buffer []byte

// Reset buffer position to start
func (b *Buffer) Reset() {
*b = Buffer([]byte(*b)[:0])
}

// Append byte slice to buffer
func (b *Buffer) Append(data []byte) {
*b = append(*b, data...)
}

// AppendByte to buffer
func (b *Buffer) AppendByte(data byte) {
*b = append(*b, data)
}

// AppendInt to buffer
func (b *Buffer) AppendInt(val int, width int) {
var repr [8]byte
reprCount := len(repr) - 1
for val >= 10 || width > 1 {
reminder := val / 10
repr[reprCount] = byte('0' + val - reminder*10)
val = reminder
reprCount--
width--
}
repr[reprCount] = byte('0' + val)
b.Append(repr[reprCount:])
}

// Bytes return underlying slice data
func (b Buffer) Bytes() []byte {
return []byte(b)
}

+ 104
- 0
vendor/github.com/withmandala/go-log/colorful/colorful.go View File

@@ -0,0 +1,104 @@
// The color engine for the go-log library
// Copyright (c) 2017 Fadhli Dzil Ikram

package colorful

import "github.com/withmandala/go-log/buffer"

// ColorBuffer add color option to buffer append
type ColorBuffer struct {
buffer.Buffer
}

// color pallete map
var (
colorOff = []byte("\033[0m")
colorRed = []byte("\033[0;31m")
colorGreen = []byte("\033[0;32m")
colorOrange = []byte("\033[0;33m")
colorBlue = []byte("\033[0;34m")
colorPurple = []byte("\033[0;35m")
colorCyan = []byte("\033[0;36m")
colorGray = []byte("\033[0;37m")
)

// Off apply no color to the data
func (cb *ColorBuffer) Off() {
cb.Append(colorOff)
}

// Red apply red color to the data
func (cb *ColorBuffer) Red() {
cb.Append(colorRed)
}

// Green apply green color to the data
func (cb *ColorBuffer) Green() {
cb.Append(colorGreen)
}

// Orange apply orange color to the data
func (cb *ColorBuffer) Orange() {
cb.Append(colorOrange)
}

// Blue apply blue color to the data
func (cb *ColorBuffer) Blue() {
cb.Append(colorBlue)
}

// Purple apply purple color to the data
func (cb *ColorBuffer) Purple() {
cb.Append(colorPurple)
}

// Cyan apply cyan color to the data
func (cb *ColorBuffer) Cyan() {
cb.Append(colorCyan)
}

// Gray apply gray color to the data
func (cb *ColorBuffer) Gray() {
cb.Append(colorGray)
}

// mixer mix the color on and off byte with the actual data
func mixer(data []byte, color []byte) []byte {
var result []byte
return append(append(append(result, color...), data...), colorOff...)
}

// Red apply red color to the data
func Red(data []byte) []byte {
return mixer(data, colorRed)
}

// Green apply green color to the data
func Green(data []byte) []byte {
return mixer(data, colorGreen)
}

// Orange apply orange color to the data
func Orange(data []byte) []byte {
return mixer(data, colorOrange)
}

// Blue apply blue color to the data
func Blue(data []byte) []byte {
return mixer(data, colorBlue)
}

// Purple apply purple color to the data
func Purple(data []byte) []byte {
return mixer(data, colorPurple)
}

// Cyan apply cyan color to the data
func Cyan(data []byte) []byte {
return mixer(data, colorCyan)
}

// Gray apply gray color to the data
func Gray(data []byte) []byte {
return mixer(data, colorGray)
}

+ 16
- 0
vendor/github.com/withmandala/go-log/glide.lock View File

@@ -0,0 +1,16 @@
hash: d7a9bf434d5702922d7355aab91dcfe2cd2b4a16413e2ff78bf8888875e63b84
updated: 2017-02-21T07:51:40.24027024+07:00
imports:
- name: github.com/smartystreets/goconvey
version: d4c757aa9afd1e2fc1832aaab209b5794eb336e1
subpackages:
- convey
- name: golang.org/x/crypto
version: 453249f01cfeb54c3d549ddb75ff152ca243f9d8
subpackages:
- ssh/terminal
- name: golang.org/x/sys
version: 075e574b89e4c2d22f2286a7e2b919519c6f3547
subpackages:
- unix
testImports: []

+ 9
- 0
vendor/github.com/withmandala/go-log/glide.yaml View File

@@ -0,0 +1,9 @@
package: github.com/withmandala/go-log
import:
- package: golang.org/x/crypto
subpackages:
- ssh/terminal
- package: github.com/smartystreets/goconvey
version: ^1.6.2
subpackages:
- convey

+ 342
- 0
vendor/github.com/withmandala/go-log/log.go View File

@@ -0,0 +1,342 @@
// The colorful and simple logging library
// Copyright (c) 2017 Fadhli Dzil Ikram

package log

import (
"fmt"
"io"
"os"
"path/filepath"
"runtime"
"sync"
"time"

"github.com/withmandala/go-log/colorful"
"golang.org/x/crypto/ssh/terminal"
)

// FdWriter interface extends existing io.Writer with file descriptor function
// support
type FdWriter interface {
io.Writer
Fd() uintptr
}

// Logger struct define the underlying storage for single logger
type Logger struct {
mu sync.RWMutex
color bool
out FdWriter
debug bool
timestamp bool
quiet bool
buf colorful.ColorBuffer
}

// Prefix struct define plain and color byte
type Prefix struct {
Plain []byte
Color []byte
File bool
}

var (
// Plain prefix template
plainFatal = []byte("[FATAL] ")
plainError = []byte("[ERROR] ")
plainWarn = []byte("[WARN] ")
plainInfo = []byte("[INFO] ")
plainDebug = []byte("[DEBUG] ")
plainTrace = []byte("[TRACE] ")

// FatalPrefix show fatal prefix
FatalPrefix = Prefix{
Plain: plainFatal,
Color: colorful.Red(plainFatal),
File: true,
}

// ErrorPrefix show error prefix
ErrorPrefix = Prefix{
Plain: plainError,
Color: colorful.Red(plainError),
File: true,
}

// WarnPrefix show warn prefix
WarnPrefix = Prefix{
Plain: plainWarn,
Color: colorful.Orange(plainWarn),
}

// InfoPrefix show info prefix
InfoPrefix = Prefix{
Plain: plainInfo,
Color: colorful.Green(plainInfo),
}

// DebugPrefix show info prefix
DebugPrefix = Prefix{
Plain: plainDebug,
Color: colorful.Purple(plainDebug),
File: true,
}

// TracePrefix show info prefix
TracePrefix = Prefix{
Plain: plainTrace,
Color: colorful.Cyan(plainTrace),
}
)

// New returns new Logger instance with predefined writer output and
// automatically detect terminal coloring support
func New(out FdWriter) *Logger {
return &Logger{
color: terminal.IsTerminal(int(out.Fd())),
out: out,
timestamp: true,
}
}

// WithColor explicitly turn on colorful features on the log
func (l *Logger) WithColor() *Logger {
l.mu.Lock()
defer l.mu.Unlock()
l.color = true
return l
}

// WithoutColor explicitly turn off colorful features on the log
func (l *Logger) WithoutColor() *Logger {
l.mu.Lock()
defer l.mu.Unlock()
l.color = false
return l
}

// WithDebug turn on debugging output on the log to reveal debug and trace level
func (l *Logger) WithDebug() *Logger {
l.mu.Lock()
defer l.mu.Unlock()
l.debug = true
return l
}

// WithoutDebug turn off debugging output on the log
func (l *Logger) WithoutDebug() *Logger {
l.mu.Lock()
defer l.mu.Unlock()
l.debug = false
return l
}

// IsDebug check the state of debugging output
func (l *Logger) IsDebug() bool {
l.mu.RLock()
defer l.mu.RUnlock()
return l.debug
}

// WithTimestamp turn on timestamp output on the log
func (l *Logger) WithTimestamp() *Logger {
l.mu.Lock()
defer l.mu.Unlock()
l.timestamp = true
return l
}

// WithoutTimestamp turn off timestamp output on the log
func (l *Logger) WithoutTimestamp() *Logger {
l.mu.Lock()
defer l.mu.Unlock()
l.timestamp = false
return l
}

// Quiet turn off all log output
func (l *Logger) Quiet() *Logger {
l.mu.Lock()
defer l.mu.Unlock()
l.quiet = true
return l
}

// NoQuiet turn on all log output
func (l *Logger) NoQuiet() *Logger {
l.mu.Lock()
defer l.mu.Unlock()
l.quiet = false
return l
}

// IsQuiet check for quiet state
func (l *Logger) IsQuiet() bool {
l.mu.RLock()
defer l.mu.RUnlock()
return l.quiet
}

// Output print the actual value
func (l *Logger) Output(depth int, prefix Prefix, data string) error {
// Check if quiet is requested, and try to return no error and be quiet
if l.IsQuiet() {
return nil
}
// Get current time
now := time.Now()
// Temporary storage for file and line tracing
var file string
var line int
var fn string
// Check if the specified prefix needs to be included with file logging
if prefix.File {
var ok bool
var pc uintptr

// Get the caller filename and line
if pc, file, line, ok = runtime.Caller(depth + 1); !ok {
file = "<unknown file>"
fn = "<unknown function>"
line = 0
} else {
file = filepath.Base(file)
fn = runtime.FuncForPC(pc).Name()
}
}
// Acquire exclusive access to the shared buffer
l.mu.Lock()
defer l.mu.Unlock()
// Reset buffer so it start from the begining
l.buf.Reset()
// Write prefix to the buffer
if l.color {
l.buf.Append(prefix.Color)
} else {
l.buf.Append(prefix.Plain)
}
// Check if the log require timestamping
if l.timestamp {
// Print timestamp color if color enabled
if l.color {
l.buf.Blue()
}
// Print date and time
year, month, day := now.Date()
l.buf.AppendInt(year, 4)
l.buf.AppendByte('/')
l.buf.AppendInt(int(month), 2)
l.buf.AppendByte('/')
l.buf.AppendInt(day, 2)
l.buf.AppendByte(' ')
hour, min, sec := now.Clock()
l.buf.AppendInt(hour, 2)
l.buf.AppendByte(':')
l.buf.AppendInt(min, 2)
l.buf.AppendByte(':')
l.buf.AppendInt(sec, 2)
l.buf.AppendByte(' ')
// Print reset color if color enabled
if l.color {
l.buf.Off()
}
}
// Add caller filename and line if enabled
if prefix.File {
// Print color start if enabled
if l.color {
l.buf.Orange()
}
// Print filename and line
l.buf.Append([]byte(fn))
l.buf.AppendByte(':')
l.buf.Append([]byte(file))
l.buf.AppendByte(':')
l.buf.AppendInt(line, 0)
l.buf.AppendByte(' ')
// Print color stop
if l.color {
l.buf.Off()
}
}
// Print the actual string data from caller
l.buf.Append([]byte(data))
if len(data) == 0 || data[len(data)-1] != '\n' {
l.buf.AppendByte('\n')
}
// Flush buffer to output
_, err := l.out.Write(l.buf.Buffer)
return err
}

// Fatal print fatal message to output and quit the application with status 1
func (l *Logger) Fatal(v ...interface{}) {
l.Output(1, FatalPrefix, fmt.Sprintln(v...))
os.Exit(1)
}

// Fatalf print formatted fatal message to output and quit the application
// with status 1
func (l *Logger) Fatalf(format string, v ...interface{}) {
l.Output(1, FatalPrefix, fmt.Sprintf(format, v...))
os.Exit(1)
}

// Error print error message to output
func (l *Logger) Error(v ...interface{}) {
l.Output(1, ErrorPrefix, fmt.Sprintln(v...))
}

// Errorf print formatted error message to output
func (l *Logger) Errorf(format string, v ...interface{}) {
l.Output(1, ErrorPrefix, fmt.Sprintf(format, v...))
}

// Warn print warning message to output
func (l *Logger) Warn(v ...interface{}) {
l.Output(1, WarnPrefix, fmt.Sprintln(v...))
}

// Warnf print formatted warning message to output
func (l *Logger) Warnf(format string, v ...interface{}) {
l.Output(1, WarnPrefix, fmt.Sprintf(format, v...))
}

// Info print informational message to output
func (l *Logger) Info(v ...interface{}) {
l.Output(1, InfoPrefix, fmt.Sprintln(v...))
}

// Infof print formatted informational message to output
func (l *Logger) Infof(format string, v ...interface{}) {
l.Output(1, InfoPrefix, fmt.Sprintf(format, v...))
}

// Debug print debug message to output if debug output enabled
func (l *Logger) Debug(v ...interface{}) {
if l.IsDebug() {
l.Output(1, DebugPrefix, fmt.Sprintln(v...))
}
}

// Debugf print formatted debug message to output if debug output enabled
func (l *Logger) Debugf(format string, v ...interface{}) {
if l.IsDebug() {
l.Output(1, DebugPrefix, fmt.Sprintf(format, v...))
}
}

// Trace print trace message to output if debug output enabled
func (l *Logger) Trace(v ...interface{}) {
if l.IsDebug() {
l.Output(1, TracePrefix, fmt.Sprintln(v...))
}
}

// Tracef print formatted trace message to output if debug output enabled
func (l *Logger) Tracef(format string, v ...interface{}) {
if l.IsDebug() {
l.Output(1, TracePrefix, fmt.Sprintf(format, v...))
}
}

+ 3
- 0
vendor/golang.org/x/crypto/AUTHORS View File

@@ -0,0 +1,3 @@
# This source code refers to The Go Authors for copyright purposes.
# The master list of authors is in the main Go distribution,
# visible at https://tip.golang.org/AUTHORS.

+ 3
- 0
vendor/golang.org/x/crypto/CONTRIBUTORS View File

@@ -0,0 +1,3 @@
# This source code was written by the Go contributors.
# The master list of contributors is in the main Go distribution,
# visible at https://tip.golang.org/CONTRIBUTORS.

+ 27
- 0
vendor/golang.org/x/crypto/LICENSE View File

@@ -0,0 +1,27 @@
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
met:

* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
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 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.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

+ 22
- 0
vendor/golang.org/x/crypto/PATENTS View 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.

+ 987
- 0
vendor/golang.org/x/crypto/ssh/terminal/terminal.go View File

@@ -0,0 +1,987 @@
// 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 (
"bytes"
"io"
"runtime"
"strconv"
"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 []rune

// 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
// pasteActive is true iff there is a bracketed paste operation in
// progress.
pasteActive 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: []rune(prompt),
termWidth: 80,
termHeight: 24,
echo: true,
historyIndex: -1,
}
}

const (
keyCtrlC = 3
keyCtrlD = 4
keyCtrlU = 21
keyEnter = '\r'
keyEscape = 27
keyBackspace = 127
keyUnknown = 0xd800 /* UTF-16 surrogate area */ + iota
keyUp
keyDown
keyLeft
keyRight
keyAltLeft
keyAltRight
keyHome
keyEnd
keyDeleteWord
keyDeleteLine
keyClearScreen
keyPasteStart
keyPasteEnd
)

var (
crlf = []byte{'\r', '\n'}
pasteStart = []byte{keyEscape, '[', '2', '0', '0', '~'}
pasteEnd = []byte{keyEscape, '[', '2', '0', '1', '~'}
)

// 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, pasteActive bool) (rune, []byte) {
if len(b) == 0 {
return utf8.RuneError, nil
}

if !pasteActive {
switch b[0] {
case 1: // ^A
return keyHome, b[1:]
case 2: // ^B
return keyLeft, b[1:]
case 5: // ^E
return keyEnd, b[1:]
case 6: // ^F
return keyRight, b[1:]
case 8: // ^H
return keyBackspace, b[1:]
case 11: // ^K
return keyDeleteLine, b[1:]
case 12: // ^L
return keyClearScreen, b[1:]
case 23: // ^W
return keyDeleteWord, b[1:]
case 14: // ^N
return keyDown, b[1:]
case 16: // ^P
return keyUp, b[1:]
}
}

if b[0] != keyEscape {
if !utf8.FullRune(b) {
return utf8.RuneError, b
}
r, l := utf8.DecodeRune(b)
return r, b[l:]
}

if !pasteActive && 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:]
case 'H':
return keyHome, b[3:]
case 'F':
return keyEnd, b[3:]
}
}

if !pasteActive && 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 !pasteActive && len(b) >= 6 && bytes.Equal(b[:6], pasteStart) {
return keyPasteStart, b[6:]
}

if pasteActive && len(b) >= 6 && bytes.Equal(b[:6], pasteEnd) {
return keyPasteEnd, 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' || c == '~' {
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 := visualLength(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) {
m := []rune{}

// 1 unit up can be expressed as ^[[A or ^[A
// 5 units up can be expressed as ^[[5A

if up == 1 {
m = append(m, keyEscape, '[', 'A')
} else if up > 1 {
m = append(m, keyEscape, '[')
m = append(m, []rune(strconv.Itoa(up))...)
m = append(m, 'A')
}

if down == 1 {
m = append(m, keyEscape, '[', 'B')
} else if down > 1 {
m = append(m, keyEscape, '[')
m = append(m, []rune(strconv.Itoa(down))...)
m = append(m, 'B')
}

if right == 1 {
m = append(m, keyEscape, '[', 'C')
} else if right > 1 {
m = append(m, keyEscape, '[')
m = append(m, []rune(strconv.Itoa(right))...)
m = append(m, 'C')
}

if left == 1 {
m = append(m, keyEscape, '[', 'D')
} else if left > 1 {
m = append(m, keyEscape, '[')
m = append(m, []rune(strconv.Itoa(left))...)
m = append(m, 'D')
}

t.queue(m)
}

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) advanceCursor(places int) {
t.cursorX += places
t.cursorY += t.cursorX / t.termWidth
if t.cursorY > t.maxLine {
t.maxLine = t.cursorY
}
t.cursorX = t.cursorX % t.termWidth

if places > 0 && t.cursorX == 0 {
// Normally terminals will advance the current position
// when writing a character. But that doesn't happen
// for the last character in a line. However, when
// writing a character (except a new line) that causes
// a line wrap, the position will be advanced two
// places.
//
// So, if we are stopping at the end of a line, we
// need to write a newline so that our cursor can be
// advanced to the next line.
t.outBuf = append(t.outBuf, '\r', '\n')
}
}

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.advanceCursor(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
}

// visualLength returns the number of visible glyphs in s.
func visualLength(runes []rune) int {
inEscapeSeq := false
length := 0

for _, r := range runes {
switch {
case inEscapeSeq:
if (r >= 'a' && r <= 'z') || (r >= 'A' && r <= 'Z') {
inEscapeSeq = false
}
case r == '\x1b':
inEscapeSeq = true
default:
length++
}
}

return length
}

// 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) {
if t.pasteActive && key != keyEnter {
t.addKeyToLine(key)
return
}

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.advanceCursor(1)
}
t.line = t.line[:t.pos]
t.moveCursorToPos(t.pos)
case keyCtrlD:
// Erase the character under the current position.
// The EOF case when the line is empty is handled in
// readLine().
if t.pos < len(t.line) {
t.pos++
t.eraseNPreviousChars(1)
}
case keyCtrlU:
t.eraseNPreviousChars(t.pos)
case keyClearScreen:
// Erases the screen and moves the cursor to the home position.
t.queue([]rune("\x1b[2J\x1b[H"))
t.queue(t.prompt)
t.cursorX, t.cursorY = 0, 0
t.advanceCursor(visualLength(t.prompt))
t.setLine(t.line, 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
}
t.addKeyToLine(key)
}
return
}

// addKeyToLine inserts the given key at the current position in the current
// line.
func (t *Terminal) addKeyToLine(key rune) {
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)
}

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.advanceCursor(visualLength(line[:todo]))
line = line[todo:]
}
}

// writeWithCRLF writes buf to w but replaces all occurrences of \n with \r\n.
func writeWithCRLF(w io.Writer, buf []byte) (n int, err error) {
for len(buf) > 0 {
i := bytes.IndexByte(buf, '\n')
todo := len(buf)
if i >= 0 {
todo = i
}

var nn int
nn, err = w.Write(buf[:todo])
n += nn
if err != nil {
return n, err
}
buf = buf[todo:]

if i >= 0 {
if _, err = w.Write(crlf); err != nil {
return n, err
}
n++
buf = buf[1:]
}
}

return n, nil
}

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 writeWithCRLF(t.c, 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 = writeWithCRLF(t.c, buf); err != nil {
return
}

t.writeLine(t.prompt)
if t.echo {
t.writeLine(t.line)
}

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 = []rune(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(t.prompt)
t.c.Write(t.outBuf)
t.outBuf = t.outBuf[:0]
}

lineIsPasted := t.pasteActive

for {
rest := t.remainder
lineOk := false
for !lineOk {
var key rune
key, rest = bytesToKey(rest, t.pasteActive)
if key == utf8.RuneError {
break
}
if !t.pasteActive {
if key == keyCtrlD {
if len(t.line) == 0 {
return "", io.EOF
}
}
if key == keyCtrlC {
return "", io.EOF
}
if key == keyPasteStart {
t.pasteActive = true
if len(t.line) == 0 {
lineIsPasted = true
}
continue
}
} else if key == keyPasteEnd {
t.pasteActive = false
continue
}
if !t.pasteActive {
lineIsPasted = false
}
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)
}
if lineIsPasted {
err = ErrPasteIndicator
}
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)]
}
}

// 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 = []rune(prompt)
}

func (t *Terminal) clearAndRepaintLinePlusNPrevious(numPrevLines int) {
// Move cursor to column zero at the start of the line.
t.move(t.cursorY, 0, t.cursorX, 0)
t.cursorX, t.cursorY = 0, 0
t.clearLineToRight()
for t.cursorY < numPrevLines {
// Move down a line
t.move(0, 1, 0, 0)
t.cursorY++
t.clearLineToRight()
}
// Move back to beginning.
t.move(t.cursorY, 0, 0, 0)
t.cursorX, t.cursorY = 0, 0

t.queue(t.prompt)
t.advanceCursor(visualLength(t.prompt))
t.writeLine(t.line)
t.moveCursorToPos(t.pos)
}

func (t *Terminal) SetSize(width, height int) error {
t.lock.Lock()
defer t.lock.Unlock()

if width == 0 {
width = 1
}

oldWidth := t.termWidth
t.termWidth, t.termHeight = width, height

switch {
case width == oldWidth:
// If the width didn't change then nothing else needs to be
// done.
return nil
case len(t.line) == 0 && t.cursorX == 0 && t.cursorY == 0:
// If there is nothing on current line and no prompt printed,
// just do nothing
return nil
case width < oldWidth:
// Some terminals (e.g. xterm) will truncate lines that were
// too long when shinking. Others, (e.g. gnome-terminal) will
// attempt to wrap them. For the former, repainting t.maxLine
// works great, but that behaviour goes badly wrong in the case
// of the latter because they have doubled every full line.

// We assume that we are working on a terminal that wraps lines
// and adjust the cursor position based on every previous line
// wrapping and turning into two. This causes the prompt on
// xterms to move upwards, which isn't great, but it avoids a
// huge mess with gnome-terminal.
if t.cursorX >= t.termWidth {
t.cursorX = t.termWidth - 1
}
t.cursorY *= 2
t.clearAndRepaintLinePlusNPrevious(t.maxLine * 2)
case width > oldWidth:
// If the terminal expands then our position calculations will
// be wrong in the future because we think the cursor is
// |t.pos| chars into the string, but there will be a gap at
// the end of any wrapped line.
//
// But the position will actually be correct until we move, so
// we can move back to the beginning and repaint everything.
t.clearAndRepaintLinePlusNPrevious(t.maxLine)
}

_, err := t.c.Write(t.outBuf)
t.outBuf = t.outBuf[:0]
return err
}

type pasteIndicatorError struct{}

func (pasteIndicatorError) Error() string {
return "terminal: ErrPasteIndicator not correctly handled"
}

// ErrPasteIndicator may be returned from ReadLine as the error, in addition
// to valid line data. It indicates that bracketed paste mode is enabled and
// that the returned line consists only of pasted data. Programs may wish to
// interpret pasted data more literally than typed data.
var ErrPasteIndicator = pasteIndicatorError{}

// SetBracketedPasteMode requests that the terminal bracket paste operations
// with markers. Not all terminals support this but, if it is supported, then
// enabling this mode will stop any autocomplete callback from running due to
// pastes. Additionally, any lines that are completely pasted will be returned
// from ReadLine with the error set to ErrPasteIndicator.
func (t *Terminal) SetBracketedPasteMode(on bool) {
if on {
io.WriteString(t.c, "\x1b[?2004h")
} else {
io.WriteString(t.c, "\x1b[?2004l")
}
}

// 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
}

// readPasswordLine reads from reader until it finds \n or io.EOF.
// The slice returned does not include the \n.
// readPasswordLine also ignores any \r it finds.
// Windows uses \r as end of line. So, on Windows, readPasswordLine
// reads until it finds \r and ignores any \n it finds during processing.
func readPasswordLine(reader io.Reader) ([]byte, error) {
var buf [1]byte
var ret []byte

for {
n, err := reader.Read(buf[:])
if n > 0 {
switch buf[0] {
case '\b':
if len(ret) > 0 {
ret = ret[:len(ret)-1]
}
case '\n':
if runtime.GOOS != "windows" {
return ret, nil
}
// otherwise ignore \n
case '\r':
if runtime.GOOS == "windows" {
return ret, nil
}
// otherwise ignore \r
default:
ret = append(ret, buf[0])
}
continue
}
if err != nil {
if err == io.EOF && len(ret) > 0 {
return ret, nil
}
return ret, err
}
}
}

+ 114
- 0
vendor/golang.org/x/crypto/ssh/terminal/util.go View File

@@ -0,0 +1,114 @@
// 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 aix darwin dragonfly freebsd linux,!appengine netbsd openbsd

// 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 "golang.org/x/crypto/ssh/terminal"

import (
"golang.org/x/sys/unix"
)

// State contains the state of a terminal.
type State struct {
termios unix.Termios
}

// IsTerminal returns whether the given file descriptor is a terminal.
func IsTerminal(fd int) bool {
_, err := unix.IoctlGetTermios(fd, ioctlReadTermios)
return err == nil
}

// 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) {
termios, err := unix.IoctlGetTermios(fd, ioctlReadTermios)
if err != nil {
return nil, err
}

oldState := State{termios: *termios}

// This attempts to replicate the behaviour documented for cfmakeraw in
// the termios(3) manpage.
termios.Iflag &^= unix.IGNBRK | unix.BRKINT | unix.PARMRK | unix.ISTRIP | unix.INLCR | unix.IGNCR | unix.ICRNL | unix.IXON
termios.Oflag &^= unix.OPOST
termios.Lflag &^= unix.ECHO | unix.ECHONL | unix.ICANON | unix.ISIG | unix.IEXTEN
termios.Cflag &^= unix.CSIZE | unix.PARENB
termios.Cflag |= unix.CS8
termios.Cc[unix.VMIN] = 1
termios.Cc[unix.VTIME] = 0
if err := unix.IoctlSetTermios(fd, ioctlWriteTermios, termios); err != nil {
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) {
termios, err := unix.IoctlGetTermios(fd, ioctlReadTermios)
if err != nil {
return nil, err
}

return &State{termios: *termios}, nil
}

// Restore restores the terminal connected to the given file descriptor to a
// previous state.
func Restore(fd int, state *State) error {
return unix.IoctlSetTermios(fd, ioctlWriteTermios, &state.termios)
}

// GetSize returns the dimensions of the given terminal.
func GetSize(fd int) (width, height int, err error) {
ws, err := unix.IoctlGetWinsize(fd, unix.TIOCGWINSZ)
if err != nil {
return -1, -1, err
}
return int(ws.Col), int(ws.Row), nil
}

// passwordReader is an io.Reader that reads from a specific file descriptor.
type passwordReader int

func (r passwordReader) Read(buf []byte) (int, error) {
return unix.Read(int(r), buf)
}

// 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) {
termios, err := unix.IoctlGetTermios(fd, ioctlReadTermios)
if err != nil {
return nil, err
}

newState := *termios
newState.Lflag &^= unix.ECHO
newState.Lflag |= unix.ICANON | unix.ISIG
newState.Iflag |= unix.ICRNL
if err := unix.IoctlSetTermios(fd, ioctlWriteTermios, &newState); err != nil {
return nil, err
}

defer unix.IoctlSetTermios(fd, ioctlWriteTermios, termios)

return readPasswordLine(passwordReader(fd))
}

+ 12
- 0
vendor/golang.org/x/crypto/ssh/terminal/util_aix.go View File

@@ -0,0 +1,12 @@
// Copyright 2018 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 aix

package terminal

import "golang.org/x/sys/unix"

const ioctlReadTermios = unix.TCGETS
const ioctlWriteTermios = unix.TCSETS

+ 12
- 0
vendor/golang.org/x/crypto/ssh/terminal/util_bsd.go View File

@@ -0,0 +1,12 @@
// 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 dragonfly freebsd netbsd openbsd

package terminal

import "golang.org/x/sys/unix"

const ioctlReadTermios = unix.TIOCGETA
const ioctlWriteTermios = unix.TIOCSETA

+ 10
- 0
vendor/golang.org/x/crypto/ssh/terminal/util_linux.go View File

@@ -0,0 +1,10 @@
// 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 terminal

import "golang.org/x/sys/unix"

const ioctlReadTermios = unix.TCGETS
const ioctlWriteTermios = unix.TCSETS

+ 58
- 0
vendor/golang.org/x/crypto/ssh/terminal/util_plan9.go View File

@@ -0,0 +1,58 @@
// Copyright 2016 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 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 (
"fmt"
"runtime"
)

type State struct{}

// IsTerminal returns whether the given file descriptor is a terminal.
func IsTerminal(fd int) bool {
return false
}

// 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) {
return nil, fmt.Errorf("terminal: MakeRaw not implemented on %s/%s", runtime.GOOS, runtime.GOARCH)
}

// 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) {
return nil, fmt.Errorf("terminal: GetState not implemented on %s/%s", runtime.GOOS, runtime.GOARCH)
}