Vendor dependencies
Signed-off-by: Alexander Morozov <lk4d4@docker.com>
This commit is contained in:
parent
9f1a65e941
commit
e17cf1ad4f
474 changed files with 71500 additions and 0 deletions
21
vendor/src/github.com/Azure/go-ansiterm/LICENSE
vendored
Normal file
21
vendor/src/github.com/Azure/go-ansiterm/LICENSE
vendored
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright (c) 2015 Microsoft Corporation
|
||||||
|
|
||||||
|
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.
|
9
vendor/src/github.com/Azure/go-ansiterm/README.md
vendored
Normal file
9
vendor/src/github.com/Azure/go-ansiterm/README.md
vendored
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
# go-ansiterm
|
||||||
|
|
||||||
|
This is a cross platform Ansi Terminal Emulation library. It reads a stream of Ansi characters and produces the appropriate function calls. The results of the function calls are platform dependent.
|
||||||
|
|
||||||
|
For example the parser might receive "ESC, [, A" as a stream of three characters. This is the code for Cursor Up (http://www.vt100.net/docs/vt510-rm/CUU). The parser then calls the cursor up function (CUU()) on an event handler. The event handler determines what platform specific work must be done to cause the cursor to move up one position.
|
||||||
|
|
||||||
|
The parser (parser.go) is a partial implementation of this state machine (http://vt100.net/emu/vt500_parser.png). There are also two event handler implementations, one for tests (test_event_handler.go) to validate that the expected events are being produced and called, the other is a Windows implementation (winterm/win_event_handler.go).
|
||||||
|
|
||||||
|
See parser_test.go for examples exercising the state machine and generating appropriate function calls.
|
188
vendor/src/github.com/Azure/go-ansiterm/constants.go
vendored
Normal file
188
vendor/src/github.com/Azure/go-ansiterm/constants.go
vendored
Normal file
|
@ -0,0 +1,188 @@
|
||||||
|
package ansiterm
|
||||||
|
|
||||||
|
const LogEnv = "DEBUG_TERMINAL"
|
||||||
|
|
||||||
|
// ANSI constants
|
||||||
|
// References:
|
||||||
|
// -- http://www.ecma-international.org/publications/standards/Ecma-048.htm
|
||||||
|
// -- http://man7.org/linux/man-pages/man4/console_codes.4.html
|
||||||
|
// -- http://manpages.ubuntu.com/manpages/intrepid/man4/console_codes.4.html
|
||||||
|
// -- http://en.wikipedia.org/wiki/ANSI_escape_code
|
||||||
|
// -- http://vt100.net/emu/dec_ansi_parser
|
||||||
|
// -- http://vt100.net/emu/vt500_parser.svg
|
||||||
|
// -- http://invisible-island.net/xterm/ctlseqs/ctlseqs.html
|
||||||
|
// -- http://www.inwap.com/pdp10/ansicode.txt
|
||||||
|
const (
|
||||||
|
// ECMA-48 Set Graphics Rendition
|
||||||
|
// Note:
|
||||||
|
// -- Constants leading with an underscore (e.g., _ANSI_xxx) are unsupported or reserved
|
||||||
|
// -- Fonts could possibly be supported via SetCurrentConsoleFontEx
|
||||||
|
// -- Windows does not expose the per-window cursor (i.e., caret) blink times
|
||||||
|
ANSI_SGR_RESET = 0
|
||||||
|
ANSI_SGR_BOLD = 1
|
||||||
|
ANSI_SGR_DIM = 2
|
||||||
|
_ANSI_SGR_ITALIC = 3
|
||||||
|
ANSI_SGR_UNDERLINE = 4
|
||||||
|
_ANSI_SGR_BLINKSLOW = 5
|
||||||
|
_ANSI_SGR_BLINKFAST = 6
|
||||||
|
ANSI_SGR_REVERSE = 7
|
||||||
|
_ANSI_SGR_INVISIBLE = 8
|
||||||
|
_ANSI_SGR_LINETHROUGH = 9
|
||||||
|
_ANSI_SGR_FONT_00 = 10
|
||||||
|
_ANSI_SGR_FONT_01 = 11
|
||||||
|
_ANSI_SGR_FONT_02 = 12
|
||||||
|
_ANSI_SGR_FONT_03 = 13
|
||||||
|
_ANSI_SGR_FONT_04 = 14
|
||||||
|
_ANSI_SGR_FONT_05 = 15
|
||||||
|
_ANSI_SGR_FONT_06 = 16
|
||||||
|
_ANSI_SGR_FONT_07 = 17
|
||||||
|
_ANSI_SGR_FONT_08 = 18
|
||||||
|
_ANSI_SGR_FONT_09 = 19
|
||||||
|
_ANSI_SGR_FONT_10 = 20
|
||||||
|
_ANSI_SGR_DOUBLEUNDERLINE = 21
|
||||||
|
ANSI_SGR_BOLD_DIM_OFF = 22
|
||||||
|
_ANSI_SGR_ITALIC_OFF = 23
|
||||||
|
ANSI_SGR_UNDERLINE_OFF = 24
|
||||||
|
_ANSI_SGR_BLINK_OFF = 25
|
||||||
|
_ANSI_SGR_RESERVED_00 = 26
|
||||||
|
ANSI_SGR_REVERSE_OFF = 27
|
||||||
|
_ANSI_SGR_INVISIBLE_OFF = 28
|
||||||
|
_ANSI_SGR_LINETHROUGH_OFF = 29
|
||||||
|
ANSI_SGR_FOREGROUND_BLACK = 30
|
||||||
|
ANSI_SGR_FOREGROUND_RED = 31
|
||||||
|
ANSI_SGR_FOREGROUND_GREEN = 32
|
||||||
|
ANSI_SGR_FOREGROUND_YELLOW = 33
|
||||||
|
ANSI_SGR_FOREGROUND_BLUE = 34
|
||||||
|
ANSI_SGR_FOREGROUND_MAGENTA = 35
|
||||||
|
ANSI_SGR_FOREGROUND_CYAN = 36
|
||||||
|
ANSI_SGR_FOREGROUND_WHITE = 37
|
||||||
|
_ANSI_SGR_RESERVED_01 = 38
|
||||||
|
ANSI_SGR_FOREGROUND_DEFAULT = 39
|
||||||
|
ANSI_SGR_BACKGROUND_BLACK = 40
|
||||||
|
ANSI_SGR_BACKGROUND_RED = 41
|
||||||
|
ANSI_SGR_BACKGROUND_GREEN = 42
|
||||||
|
ANSI_SGR_BACKGROUND_YELLOW = 43
|
||||||
|
ANSI_SGR_BACKGROUND_BLUE = 44
|
||||||
|
ANSI_SGR_BACKGROUND_MAGENTA = 45
|
||||||
|
ANSI_SGR_BACKGROUND_CYAN = 46
|
||||||
|
ANSI_SGR_BACKGROUND_WHITE = 47
|
||||||
|
_ANSI_SGR_RESERVED_02 = 48
|
||||||
|
ANSI_SGR_BACKGROUND_DEFAULT = 49
|
||||||
|
// 50 - 65: Unsupported
|
||||||
|
|
||||||
|
ANSI_MAX_CMD_LENGTH = 4096
|
||||||
|
|
||||||
|
MAX_INPUT_EVENTS = 128
|
||||||
|
DEFAULT_WIDTH = 80
|
||||||
|
DEFAULT_HEIGHT = 24
|
||||||
|
|
||||||
|
ANSI_BEL = 0x07
|
||||||
|
ANSI_BACKSPACE = 0x08
|
||||||
|
ANSI_TAB = 0x09
|
||||||
|
ANSI_LINE_FEED = 0x0A
|
||||||
|
ANSI_VERTICAL_TAB = 0x0B
|
||||||
|
ANSI_FORM_FEED = 0x0C
|
||||||
|
ANSI_CARRIAGE_RETURN = 0x0D
|
||||||
|
ANSI_ESCAPE_PRIMARY = 0x1B
|
||||||
|
ANSI_ESCAPE_SECONDARY = 0x5B
|
||||||
|
ANSI_OSC_STRING_ENTRY = 0x5D
|
||||||
|
ANSI_COMMAND_FIRST = 0x40
|
||||||
|
ANSI_COMMAND_LAST = 0x7E
|
||||||
|
DCS_ENTRY = 0x90
|
||||||
|
CSI_ENTRY = 0x9B
|
||||||
|
OSC_STRING = 0x9D
|
||||||
|
ANSI_PARAMETER_SEP = ";"
|
||||||
|
ANSI_CMD_G0 = '('
|
||||||
|
ANSI_CMD_G1 = ')'
|
||||||
|
ANSI_CMD_G2 = '*'
|
||||||
|
ANSI_CMD_G3 = '+'
|
||||||
|
ANSI_CMD_DECPNM = '>'
|
||||||
|
ANSI_CMD_DECPAM = '='
|
||||||
|
ANSI_CMD_OSC = ']'
|
||||||
|
ANSI_CMD_STR_TERM = '\\'
|
||||||
|
|
||||||
|
KEY_CONTROL_PARAM_2 = ";2"
|
||||||
|
KEY_CONTROL_PARAM_3 = ";3"
|
||||||
|
KEY_CONTROL_PARAM_4 = ";4"
|
||||||
|
KEY_CONTROL_PARAM_5 = ";5"
|
||||||
|
KEY_CONTROL_PARAM_6 = ";6"
|
||||||
|
KEY_CONTROL_PARAM_7 = ";7"
|
||||||
|
KEY_CONTROL_PARAM_8 = ";8"
|
||||||
|
KEY_ESC_CSI = "\x1B["
|
||||||
|
KEY_ESC_N = "\x1BN"
|
||||||
|
KEY_ESC_O = "\x1BO"
|
||||||
|
|
||||||
|
FILL_CHARACTER = ' '
|
||||||
|
)
|
||||||
|
|
||||||
|
func getByteRange(start byte, end byte) []byte {
|
||||||
|
bytes := make([]byte, 0, 32)
|
||||||
|
for i := start; i <= end; i++ {
|
||||||
|
bytes = append(bytes, byte(i))
|
||||||
|
}
|
||||||
|
|
||||||
|
return bytes
|
||||||
|
}
|
||||||
|
|
||||||
|
var ToGroundBytes = getToGroundBytes()
|
||||||
|
var Executors = getExecuteBytes()
|
||||||
|
|
||||||
|
// SPACE 20+A0 hex Always and everywhere a blank space
|
||||||
|
// Intermediate 20-2F hex !"#$%&'()*+,-./
|
||||||
|
var Intermeds = getByteRange(0x20, 0x2F)
|
||||||
|
|
||||||
|
// Parameters 30-3F hex 0123456789:;<=>?
|
||||||
|
// CSI Parameters 30-39, 3B hex 0123456789;
|
||||||
|
var CsiParams = getByteRange(0x30, 0x3F)
|
||||||
|
|
||||||
|
var CsiCollectables = append(getByteRange(0x30, 0x39), getByteRange(0x3B, 0x3F)...)
|
||||||
|
|
||||||
|
// Uppercase 40-5F hex @ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_
|
||||||
|
var UpperCase = getByteRange(0x40, 0x5F)
|
||||||
|
|
||||||
|
// Lowercase 60-7E hex `abcdefghijlkmnopqrstuvwxyz{|}~
|
||||||
|
var LowerCase = getByteRange(0x60, 0x7E)
|
||||||
|
|
||||||
|
// Alphabetics 40-7E hex (all of upper and lower case)
|
||||||
|
var Alphabetics = append(UpperCase, LowerCase...)
|
||||||
|
|
||||||
|
var Printables = getByteRange(0x20, 0x7F)
|
||||||
|
|
||||||
|
var EscapeIntermediateToGroundBytes = getByteRange(0x30, 0x7E)
|
||||||
|
var EscapeToGroundBytes = getEscapeToGroundBytes()
|
||||||
|
|
||||||
|
// See http://www.vt100.net/emu/vt500_parser.png for description of the complex
|
||||||
|
// byte ranges below
|
||||||
|
|
||||||
|
func getEscapeToGroundBytes() []byte {
|
||||||
|
escapeToGroundBytes := getByteRange(0x30, 0x4F)
|
||||||
|
escapeToGroundBytes = append(escapeToGroundBytes, getByteRange(0x51, 0x57)...)
|
||||||
|
escapeToGroundBytes = append(escapeToGroundBytes, 0x59)
|
||||||
|
escapeToGroundBytes = append(escapeToGroundBytes, 0x5A)
|
||||||
|
escapeToGroundBytes = append(escapeToGroundBytes, 0x5C)
|
||||||
|
escapeToGroundBytes = append(escapeToGroundBytes, getByteRange(0x60, 0x7E)...)
|
||||||
|
return escapeToGroundBytes
|
||||||
|
}
|
||||||
|
|
||||||
|
func getExecuteBytes() []byte {
|
||||||
|
executeBytes := getByteRange(0x00, 0x17)
|
||||||
|
executeBytes = append(executeBytes, 0x19)
|
||||||
|
executeBytes = append(executeBytes, getByteRange(0x1C, 0x1F)...)
|
||||||
|
return executeBytes
|
||||||
|
}
|
||||||
|
|
||||||
|
func getToGroundBytes() []byte {
|
||||||
|
groundBytes := []byte{0x18}
|
||||||
|
groundBytes = append(groundBytes, 0x1A)
|
||||||
|
groundBytes = append(groundBytes, getByteRange(0x80, 0x8F)...)
|
||||||
|
groundBytes = append(groundBytes, getByteRange(0x91, 0x97)...)
|
||||||
|
groundBytes = append(groundBytes, 0x99)
|
||||||
|
groundBytes = append(groundBytes, 0x9A)
|
||||||
|
groundBytes = append(groundBytes, 0x9C)
|
||||||
|
return groundBytes
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete 7F hex Always and everywhere ignored
|
||||||
|
// C1 Control 80-9F hex 32 additional control characters
|
||||||
|
// G1 Displayable A1-FE hex 94 additional displayable characters
|
||||||
|
// Special A0+FF hex Same as SPACE and DELETE
|
7
vendor/src/github.com/Azure/go-ansiterm/context.go
vendored
Normal file
7
vendor/src/github.com/Azure/go-ansiterm/context.go
vendored
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
package ansiterm
|
||||||
|
|
||||||
|
type AnsiContext struct {
|
||||||
|
currentChar byte
|
||||||
|
paramBuffer []byte
|
||||||
|
interBuffer []byte
|
||||||
|
}
|
49
vendor/src/github.com/Azure/go-ansiterm/csi_entry_state.go
vendored
Normal file
49
vendor/src/github.com/Azure/go-ansiterm/csi_entry_state.go
vendored
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
package ansiterm
|
||||||
|
|
||||||
|
type CsiEntryState struct {
|
||||||
|
BaseState
|
||||||
|
}
|
||||||
|
|
||||||
|
func (csiState CsiEntryState) Handle(b byte) (s State, e error) {
|
||||||
|
logger.Infof("CsiEntry::Handle %#x", b)
|
||||||
|
|
||||||
|
nextState, err := csiState.BaseState.Handle(b)
|
||||||
|
if nextState != nil || err != nil {
|
||||||
|
return nextState, err
|
||||||
|
}
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case sliceContains(Alphabetics, b):
|
||||||
|
return csiState.parser.Ground, nil
|
||||||
|
case sliceContains(CsiCollectables, b):
|
||||||
|
return csiState.parser.CsiParam, nil
|
||||||
|
case sliceContains(Executors, b):
|
||||||
|
return csiState, csiState.parser.execute()
|
||||||
|
}
|
||||||
|
|
||||||
|
return csiState, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (csiState CsiEntryState) Transition(s State) error {
|
||||||
|
logger.Infof("CsiEntry::Transition %s --> %s", csiState.Name(), s.Name())
|
||||||
|
csiState.BaseState.Transition(s)
|
||||||
|
|
||||||
|
switch s {
|
||||||
|
case csiState.parser.Ground:
|
||||||
|
return csiState.parser.csiDispatch()
|
||||||
|
case csiState.parser.CsiParam:
|
||||||
|
switch {
|
||||||
|
case sliceContains(CsiParams, csiState.parser.context.currentChar):
|
||||||
|
csiState.parser.collectParam()
|
||||||
|
case sliceContains(Intermeds, csiState.parser.context.currentChar):
|
||||||
|
csiState.parser.collectInter()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (csiState CsiEntryState) Enter() error {
|
||||||
|
csiState.parser.clear()
|
||||||
|
return nil
|
||||||
|
}
|
38
vendor/src/github.com/Azure/go-ansiterm/csi_param_state.go
vendored
Normal file
38
vendor/src/github.com/Azure/go-ansiterm/csi_param_state.go
vendored
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
package ansiterm
|
||||||
|
|
||||||
|
type CsiParamState struct {
|
||||||
|
BaseState
|
||||||
|
}
|
||||||
|
|
||||||
|
func (csiState CsiParamState) Handle(b byte) (s State, e error) {
|
||||||
|
logger.Infof("CsiParam::Handle %#x", b)
|
||||||
|
|
||||||
|
nextState, err := csiState.BaseState.Handle(b)
|
||||||
|
if nextState != nil || err != nil {
|
||||||
|
return nextState, err
|
||||||
|
}
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case sliceContains(Alphabetics, b):
|
||||||
|
return csiState.parser.Ground, nil
|
||||||
|
case sliceContains(CsiCollectables, b):
|
||||||
|
csiState.parser.collectParam()
|
||||||
|
return csiState, nil
|
||||||
|
case sliceContains(Executors, b):
|
||||||
|
return csiState, csiState.parser.execute()
|
||||||
|
}
|
||||||
|
|
||||||
|
return csiState, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (csiState CsiParamState) Transition(s State) error {
|
||||||
|
logger.Infof("CsiParam::Transition %s --> %s", csiState.Name(), s.Name())
|
||||||
|
csiState.BaseState.Transition(s)
|
||||||
|
|
||||||
|
switch s {
|
||||||
|
case csiState.parser.Ground:
|
||||||
|
return csiState.parser.csiDispatch()
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
36
vendor/src/github.com/Azure/go-ansiterm/escape_intermediate_state.go
vendored
Normal file
36
vendor/src/github.com/Azure/go-ansiterm/escape_intermediate_state.go
vendored
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
package ansiterm
|
||||||
|
|
||||||
|
type EscapeIntermediateState struct {
|
||||||
|
BaseState
|
||||||
|
}
|
||||||
|
|
||||||
|
func (escState EscapeIntermediateState) Handle(b byte) (s State, e error) {
|
||||||
|
logger.Infof("EscapeIntermediateState::Handle %#x", b)
|
||||||
|
nextState, err := escState.BaseState.Handle(b)
|
||||||
|
if nextState != nil || err != nil {
|
||||||
|
return nextState, err
|
||||||
|
}
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case sliceContains(Intermeds, b):
|
||||||
|
return escState, escState.parser.collectInter()
|
||||||
|
case sliceContains(Executors, b):
|
||||||
|
return escState, escState.parser.execute()
|
||||||
|
case sliceContains(EscapeIntermediateToGroundBytes, b):
|
||||||
|
return escState.parser.Ground, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return escState, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (escState EscapeIntermediateState) Transition(s State) error {
|
||||||
|
logger.Infof("EscapeIntermediateState::Transition %s --> %s", escState.Name(), s.Name())
|
||||||
|
escState.BaseState.Transition(s)
|
||||||
|
|
||||||
|
switch s {
|
||||||
|
case escState.parser.Ground:
|
||||||
|
return escState.parser.escDispatch()
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
47
vendor/src/github.com/Azure/go-ansiterm/escape_state.go
vendored
Normal file
47
vendor/src/github.com/Azure/go-ansiterm/escape_state.go
vendored
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
package ansiterm
|
||||||
|
|
||||||
|
type EscapeState struct {
|
||||||
|
BaseState
|
||||||
|
}
|
||||||
|
|
||||||
|
func (escState EscapeState) Handle(b byte) (s State, e error) {
|
||||||
|
logger.Infof("EscapeState::Handle %#x", b)
|
||||||
|
nextState, err := escState.BaseState.Handle(b)
|
||||||
|
if nextState != nil || err != nil {
|
||||||
|
return nextState, err
|
||||||
|
}
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case b == ANSI_ESCAPE_SECONDARY:
|
||||||
|
return escState.parser.CsiEntry, nil
|
||||||
|
case b == ANSI_OSC_STRING_ENTRY:
|
||||||
|
return escState.parser.OscString, nil
|
||||||
|
case sliceContains(Executors, b):
|
||||||
|
return escState, escState.parser.execute()
|
||||||
|
case sliceContains(EscapeToGroundBytes, b):
|
||||||
|
return escState.parser.Ground, nil
|
||||||
|
case sliceContains(Intermeds, b):
|
||||||
|
return escState.parser.EscapeIntermediate, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return escState, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (escState EscapeState) Transition(s State) error {
|
||||||
|
logger.Infof("Escape::Transition %s --> %s", escState.Name(), s.Name())
|
||||||
|
escState.BaseState.Transition(s)
|
||||||
|
|
||||||
|
switch s {
|
||||||
|
case escState.parser.Ground:
|
||||||
|
return escState.parser.escDispatch()
|
||||||
|
case escState.parser.EscapeIntermediate:
|
||||||
|
return escState.parser.collectInter()
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (escState EscapeState) Enter() error {
|
||||||
|
escState.parser.clear()
|
||||||
|
return nil
|
||||||
|
}
|
90
vendor/src/github.com/Azure/go-ansiterm/event_handler.go
vendored
Normal file
90
vendor/src/github.com/Azure/go-ansiterm/event_handler.go
vendored
Normal file
|
@ -0,0 +1,90 @@
|
||||||
|
package ansiterm
|
||||||
|
|
||||||
|
type AnsiEventHandler interface {
|
||||||
|
// Print
|
||||||
|
Print(b byte) error
|
||||||
|
|
||||||
|
// Execute C0 commands
|
||||||
|
Execute(b byte) error
|
||||||
|
|
||||||
|
// CUrsor Up
|
||||||
|
CUU(int) error
|
||||||
|
|
||||||
|
// CUrsor Down
|
||||||
|
CUD(int) error
|
||||||
|
|
||||||
|
// CUrsor Forward
|
||||||
|
CUF(int) error
|
||||||
|
|
||||||
|
// CUrsor Backward
|
||||||
|
CUB(int) error
|
||||||
|
|
||||||
|
// Cursor to Next Line
|
||||||
|
CNL(int) error
|
||||||
|
|
||||||
|
// Cursor to Previous Line
|
||||||
|
CPL(int) error
|
||||||
|
|
||||||
|
// Cursor Horizontal position Absolute
|
||||||
|
CHA(int) error
|
||||||
|
|
||||||
|
// Vertical line Position Absolute
|
||||||
|
VPA(int) error
|
||||||
|
|
||||||
|
// CUrsor Position
|
||||||
|
CUP(int, int) error
|
||||||
|
|
||||||
|
// Horizontal and Vertical Position (depends on PUM)
|
||||||
|
HVP(int, int) error
|
||||||
|
|
||||||
|
// Text Cursor Enable Mode
|
||||||
|
DECTCEM(bool) error
|
||||||
|
|
||||||
|
// Origin Mode
|
||||||
|
DECOM(bool) error
|
||||||
|
|
||||||
|
// 132 Column Mode
|
||||||
|
DECCOLM(bool) error
|
||||||
|
|
||||||
|
// Erase in Display
|
||||||
|
ED(int) error
|
||||||
|
|
||||||
|
// Erase in Line
|
||||||
|
EL(int) error
|
||||||
|
|
||||||
|
// Insert Line
|
||||||
|
IL(int) error
|
||||||
|
|
||||||
|
// Delete Line
|
||||||
|
DL(int) error
|
||||||
|
|
||||||
|
// Insert Character
|
||||||
|
ICH(int) error
|
||||||
|
|
||||||
|
// Delete Character
|
||||||
|
DCH(int) error
|
||||||
|
|
||||||
|
// Set Graphics Rendition
|
||||||
|
SGR([]int) error
|
||||||
|
|
||||||
|
// Pan Down
|
||||||
|
SU(int) error
|
||||||
|
|
||||||
|
// Pan Up
|
||||||
|
SD(int) error
|
||||||
|
|
||||||
|
// Device Attributes
|
||||||
|
DA([]string) error
|
||||||
|
|
||||||
|
// Set Top and Bottom Margins
|
||||||
|
DECSTBM(int, int) error
|
||||||
|
|
||||||
|
// Index
|
||||||
|
IND() error
|
||||||
|
|
||||||
|
// Reverse Index
|
||||||
|
RI() error
|
||||||
|
|
||||||
|
// Flush updates from previous commands
|
||||||
|
Flush() error
|
||||||
|
}
|
24
vendor/src/github.com/Azure/go-ansiterm/ground_state.go
vendored
Normal file
24
vendor/src/github.com/Azure/go-ansiterm/ground_state.go
vendored
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
package ansiterm
|
||||||
|
|
||||||
|
type GroundState struct {
|
||||||
|
BaseState
|
||||||
|
}
|
||||||
|
|
||||||
|
func (gs GroundState) Handle(b byte) (s State, e error) {
|
||||||
|
gs.parser.context.currentChar = b
|
||||||
|
|
||||||
|
nextState, err := gs.BaseState.Handle(b)
|
||||||
|
if nextState != nil || err != nil {
|
||||||
|
return nextState, err
|
||||||
|
}
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case sliceContains(Printables, b):
|
||||||
|
return gs, gs.parser.print()
|
||||||
|
|
||||||
|
case sliceContains(Executors, b):
|
||||||
|
return gs, gs.parser.execute()
|
||||||
|
}
|
||||||
|
|
||||||
|
return gs, nil
|
||||||
|
}
|
31
vendor/src/github.com/Azure/go-ansiterm/osc_string_state.go
vendored
Normal file
31
vendor/src/github.com/Azure/go-ansiterm/osc_string_state.go
vendored
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
package ansiterm
|
||||||
|
|
||||||
|
type OscStringState struct {
|
||||||
|
BaseState
|
||||||
|
}
|
||||||
|
|
||||||
|
func (oscState OscStringState) Handle(b byte) (s State, e error) {
|
||||||
|
logger.Infof("OscString::Handle %#x", b)
|
||||||
|
nextState, err := oscState.BaseState.Handle(b)
|
||||||
|
if nextState != nil || err != nil {
|
||||||
|
return nextState, err
|
||||||
|
}
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case isOscStringTerminator(b):
|
||||||
|
return oscState.parser.Ground, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return oscState, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// See below for OSC string terminators for linux
|
||||||
|
// http://man7.org/linux/man-pages/man4/console_codes.4.html
|
||||||
|
func isOscStringTerminator(b byte) bool {
|
||||||
|
|
||||||
|
if b == ANSI_BEL || b == 0x5C {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
137
vendor/src/github.com/Azure/go-ansiterm/parser.go
vendored
Normal file
137
vendor/src/github.com/Azure/go-ansiterm/parser.go
vendored
Normal file
|
@ -0,0 +1,137 @@
|
||||||
|
package ansiterm
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/Sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
var logger *logrus.Logger
|
||||||
|
|
||||||
|
type AnsiParser struct {
|
||||||
|
currState State
|
||||||
|
eventHandler AnsiEventHandler
|
||||||
|
context *AnsiContext
|
||||||
|
CsiEntry State
|
||||||
|
CsiParam State
|
||||||
|
DcsEntry State
|
||||||
|
Escape State
|
||||||
|
EscapeIntermediate State
|
||||||
|
Error State
|
||||||
|
Ground State
|
||||||
|
OscString State
|
||||||
|
stateMap []State
|
||||||
|
}
|
||||||
|
|
||||||
|
func CreateParser(initialState string, evtHandler AnsiEventHandler) *AnsiParser {
|
||||||
|
logFile := ioutil.Discard
|
||||||
|
|
||||||
|
if isDebugEnv := os.Getenv(LogEnv); isDebugEnv == "1" {
|
||||||
|
logFile, _ = os.Create("ansiParser.log")
|
||||||
|
}
|
||||||
|
|
||||||
|
logger = &logrus.Logger{
|
||||||
|
Out: logFile,
|
||||||
|
Formatter: new(logrus.TextFormatter),
|
||||||
|
Level: logrus.InfoLevel,
|
||||||
|
}
|
||||||
|
|
||||||
|
parser := &AnsiParser{
|
||||||
|
eventHandler: evtHandler,
|
||||||
|
context: &AnsiContext{},
|
||||||
|
}
|
||||||
|
|
||||||
|
parser.CsiEntry = CsiEntryState{BaseState{name: "CsiEntry", parser: parser}}
|
||||||
|
parser.CsiParam = CsiParamState{BaseState{name: "CsiParam", parser: parser}}
|
||||||
|
parser.DcsEntry = DcsEntryState{BaseState{name: "DcsEntry", parser: parser}}
|
||||||
|
parser.Escape = EscapeState{BaseState{name: "Escape", parser: parser}}
|
||||||
|
parser.EscapeIntermediate = EscapeIntermediateState{BaseState{name: "EscapeIntermediate", parser: parser}}
|
||||||
|
parser.Error = ErrorState{BaseState{name: "Error", parser: parser}}
|
||||||
|
parser.Ground = GroundState{BaseState{name: "Ground", parser: parser}}
|
||||||
|
parser.OscString = OscStringState{BaseState{name: "OscString", parser: parser}}
|
||||||
|
|
||||||
|
parser.stateMap = []State{
|
||||||
|
parser.CsiEntry,
|
||||||
|
parser.CsiParam,
|
||||||
|
parser.DcsEntry,
|
||||||
|
parser.Escape,
|
||||||
|
parser.EscapeIntermediate,
|
||||||
|
parser.Error,
|
||||||
|
parser.Ground,
|
||||||
|
parser.OscString,
|
||||||
|
}
|
||||||
|
|
||||||
|
parser.currState = getState(initialState, parser.stateMap)
|
||||||
|
|
||||||
|
logger.Infof("CreateParser: parser %p", parser)
|
||||||
|
return parser
|
||||||
|
}
|
||||||
|
|
||||||
|
func getState(name string, states []State) State {
|
||||||
|
for _, el := range states {
|
||||||
|
if el.Name() == name {
|
||||||
|
return el
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ap *AnsiParser) Parse(bytes []byte) (int, error) {
|
||||||
|
for i, b := range bytes {
|
||||||
|
if err := ap.handle(b); err != nil {
|
||||||
|
return i, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return len(bytes), ap.eventHandler.Flush()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ap *AnsiParser) handle(b byte) error {
|
||||||
|
ap.context.currentChar = b
|
||||||
|
newState, err := ap.currState.Handle(b)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if newState == nil {
|
||||||
|
logger.Warning("newState is nil")
|
||||||
|
return errors.New(fmt.Sprintf("New state of 'nil' is invalid."))
|
||||||
|
}
|
||||||
|
|
||||||
|
if newState != ap.currState {
|
||||||
|
if err := ap.changeState(newState); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ap *AnsiParser) changeState(newState State) error {
|
||||||
|
logger.Infof("ChangeState %s --> %s", ap.currState.Name(), newState.Name())
|
||||||
|
|
||||||
|
// Exit old state
|
||||||
|
if err := ap.currState.Exit(); err != nil {
|
||||||
|
logger.Infof("Exit state '%s' failed with : '%v'", ap.currState.Name(), err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Perform transition action
|
||||||
|
if err := ap.currState.Transition(newState); err != nil {
|
||||||
|
logger.Infof("Transition from '%s' to '%s' failed with: '%v'", ap.currState.Name(), newState.Name, err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enter new state
|
||||||
|
if err := newState.Enter(); err != nil {
|
||||||
|
logger.Infof("Enter state '%s' failed with: '%v'", newState.Name(), err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
ap.currState = newState
|
||||||
|
return nil
|
||||||
|
}
|
103
vendor/src/github.com/Azure/go-ansiterm/parser_action_helpers.go
vendored
Normal file
103
vendor/src/github.com/Azure/go-ansiterm/parser_action_helpers.go
vendored
Normal file
|
@ -0,0 +1,103 @@
|
||||||
|
package ansiterm
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
|
func parseParams(bytes []byte) ([]string, error) {
|
||||||
|
paramBuff := make([]byte, 0, 0)
|
||||||
|
params := []string{}
|
||||||
|
|
||||||
|
for _, v := range bytes {
|
||||||
|
if v == ';' {
|
||||||
|
if len(paramBuff) > 0 {
|
||||||
|
// Completed parameter, append it to the list
|
||||||
|
s := string(paramBuff)
|
||||||
|
params = append(params, s)
|
||||||
|
paramBuff = make([]byte, 0, 0)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
paramBuff = append(paramBuff, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Last parameter may not be terminated with ';'
|
||||||
|
if len(paramBuff) > 0 {
|
||||||
|
s := string(paramBuff)
|
||||||
|
params = append(params, s)
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Infof("Parsed params: %v with length: %d", params, len(params))
|
||||||
|
return params, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseCmd(context AnsiContext) (string, error) {
|
||||||
|
return string(context.currentChar), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getInt(params []string, dflt int) int {
|
||||||
|
i := getInts(params, 1, dflt)[0]
|
||||||
|
logger.Infof("getInt: %v", i)
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
|
||||||
|
func getInts(params []string, minCount int, dflt int) []int {
|
||||||
|
ints := []int{}
|
||||||
|
|
||||||
|
for _, v := range params {
|
||||||
|
i, _ := strconv.Atoi(v)
|
||||||
|
// Zero is mapped to the default value in VT100.
|
||||||
|
if i == 0 {
|
||||||
|
i = dflt
|
||||||
|
}
|
||||||
|
ints = append(ints, i)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(ints) < minCount {
|
||||||
|
remaining := minCount - len(ints)
|
||||||
|
for i := 0; i < remaining; i++ {
|
||||||
|
ints = append(ints, dflt)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Infof("getInts: %v", ints)
|
||||||
|
|
||||||
|
return ints
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ap *AnsiParser) modeDispatch(param string, set bool) error {
|
||||||
|
switch param {
|
||||||
|
case "?3":
|
||||||
|
return ap.eventHandler.DECCOLM(set)
|
||||||
|
case "?6":
|
||||||
|
return ap.eventHandler.DECOM(set)
|
||||||
|
case "?25":
|
||||||
|
return ap.eventHandler.DECTCEM(set)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ap *AnsiParser) hDispatch(params []string) error {
|
||||||
|
if len(params) == 1 {
|
||||||
|
return ap.modeDispatch(params[0], true)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ap *AnsiParser) lDispatch(params []string) error {
|
||||||
|
if len(params) == 1 {
|
||||||
|
return ap.modeDispatch(params[0], false)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getEraseParam(params []string) int {
|
||||||
|
param := getInt(params, 0)
|
||||||
|
if param < 0 || 3 < param {
|
||||||
|
param = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
return param
|
||||||
|
}
|
122
vendor/src/github.com/Azure/go-ansiterm/parser_actions.go
vendored
Normal file
122
vendor/src/github.com/Azure/go-ansiterm/parser_actions.go
vendored
Normal file
|
@ -0,0 +1,122 @@
|
||||||
|
package ansiterm
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (ap *AnsiParser) collectParam() error {
|
||||||
|
currChar := ap.context.currentChar
|
||||||
|
logger.Infof("collectParam %#x", currChar)
|
||||||
|
ap.context.paramBuffer = append(ap.context.paramBuffer, currChar)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ap *AnsiParser) collectInter() error {
|
||||||
|
currChar := ap.context.currentChar
|
||||||
|
logger.Infof("collectInter %#x", currChar)
|
||||||
|
ap.context.paramBuffer = append(ap.context.interBuffer, currChar)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ap *AnsiParser) escDispatch() error {
|
||||||
|
cmd, _ := parseCmd(*ap.context)
|
||||||
|
intermeds := ap.context.interBuffer
|
||||||
|
logger.Infof("escDispatch currentChar: %#x", ap.context.currentChar)
|
||||||
|
logger.Infof("escDispatch: %v(%v)", cmd, intermeds)
|
||||||
|
|
||||||
|
switch cmd {
|
||||||
|
case "D": // IND
|
||||||
|
return ap.eventHandler.IND()
|
||||||
|
case "E": // NEL, equivalent to CRLF
|
||||||
|
err := ap.eventHandler.Execute(ANSI_CARRIAGE_RETURN)
|
||||||
|
if err == nil {
|
||||||
|
err = ap.eventHandler.Execute(ANSI_LINE_FEED)
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
case "M": // RI
|
||||||
|
return ap.eventHandler.RI()
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ap *AnsiParser) csiDispatch() error {
|
||||||
|
cmd, _ := parseCmd(*ap.context)
|
||||||
|
params, _ := parseParams(ap.context.paramBuffer)
|
||||||
|
|
||||||
|
logger.Infof("csiDispatch: %v(%v)", cmd, params)
|
||||||
|
|
||||||
|
switch cmd {
|
||||||
|
case "@":
|
||||||
|
return ap.eventHandler.ICH(getInt(params, 1))
|
||||||
|
case "A":
|
||||||
|
return ap.eventHandler.CUU(getInt(params, 1))
|
||||||
|
case "B":
|
||||||
|
return ap.eventHandler.CUD(getInt(params, 1))
|
||||||
|
case "C":
|
||||||
|
return ap.eventHandler.CUF(getInt(params, 1))
|
||||||
|
case "D":
|
||||||
|
return ap.eventHandler.CUB(getInt(params, 1))
|
||||||
|
case "E":
|
||||||
|
return ap.eventHandler.CNL(getInt(params, 1))
|
||||||
|
case "F":
|
||||||
|
return ap.eventHandler.CPL(getInt(params, 1))
|
||||||
|
case "G":
|
||||||
|
return ap.eventHandler.CHA(getInt(params, 1))
|
||||||
|
case "H":
|
||||||
|
ints := getInts(params, 2, 1)
|
||||||
|
x, y := ints[0], ints[1]
|
||||||
|
return ap.eventHandler.CUP(x, y)
|
||||||
|
case "J":
|
||||||
|
param := getEraseParam(params)
|
||||||
|
return ap.eventHandler.ED(param)
|
||||||
|
case "K":
|
||||||
|
param := getEraseParam(params)
|
||||||
|
return ap.eventHandler.EL(param)
|
||||||
|
case "L":
|
||||||
|
return ap.eventHandler.IL(getInt(params, 1))
|
||||||
|
case "M":
|
||||||
|
return ap.eventHandler.DL(getInt(params, 1))
|
||||||
|
case "P":
|
||||||
|
return ap.eventHandler.DCH(getInt(params, 1))
|
||||||
|
case "S":
|
||||||
|
return ap.eventHandler.SU(getInt(params, 1))
|
||||||
|
case "T":
|
||||||
|
return ap.eventHandler.SD(getInt(params, 1))
|
||||||
|
case "c":
|
||||||
|
return ap.eventHandler.DA(params)
|
||||||
|
case "d":
|
||||||
|
return ap.eventHandler.VPA(getInt(params, 1))
|
||||||
|
case "f":
|
||||||
|
ints := getInts(params, 2, 1)
|
||||||
|
x, y := ints[0], ints[1]
|
||||||
|
return ap.eventHandler.HVP(x, y)
|
||||||
|
case "h":
|
||||||
|
return ap.hDispatch(params)
|
||||||
|
case "l":
|
||||||
|
return ap.lDispatch(params)
|
||||||
|
case "m":
|
||||||
|
return ap.eventHandler.SGR(getInts(params, 1, 0))
|
||||||
|
case "r":
|
||||||
|
ints := getInts(params, 2, 1)
|
||||||
|
top, bottom := ints[0], ints[1]
|
||||||
|
return ap.eventHandler.DECSTBM(top, bottom)
|
||||||
|
default:
|
||||||
|
logger.Errorf(fmt.Sprintf("Unsupported CSI command: '%s', with full context: %v", cmd, ap.context))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ap *AnsiParser) print() error {
|
||||||
|
return ap.eventHandler.Print(ap.context.currentChar)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ap *AnsiParser) clear() error {
|
||||||
|
ap.context = &AnsiContext{}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ap *AnsiParser) execute() error {
|
||||||
|
return ap.eventHandler.Execute(ap.context.currentChar)
|
||||||
|
}
|
114
vendor/src/github.com/Azure/go-ansiterm/parser_test_helpers.go
vendored
Normal file
114
vendor/src/github.com/Azure/go-ansiterm/parser_test_helpers.go
vendored
Normal file
|
@ -0,0 +1,114 @@
|
||||||
|
package ansiterm
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func getStateNames() []string {
|
||||||
|
parser, _ := createTestParser("Ground")
|
||||||
|
|
||||||
|
stateNames := []string{}
|
||||||
|
for _, state := range parser.stateMap {
|
||||||
|
stateNames = append(stateNames, state.Name())
|
||||||
|
}
|
||||||
|
|
||||||
|
return stateNames
|
||||||
|
}
|
||||||
|
|
||||||
|
func stateTransitionHelper(t *testing.T, start string, end string, bytes []byte) {
|
||||||
|
for _, b := range bytes {
|
||||||
|
bytes := []byte{byte(b)}
|
||||||
|
parser, _ := createTestParser(start)
|
||||||
|
parser.Parse(bytes)
|
||||||
|
validateState(t, parser.currState, end)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func anyToXHelper(t *testing.T, bytes []byte, expectedState string) {
|
||||||
|
for _, s := range getStateNames() {
|
||||||
|
stateTransitionHelper(t, s, expectedState, bytes)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func funcCallParamHelper(t *testing.T, bytes []byte, start string, expected string, expectedCalls []string) {
|
||||||
|
parser, evtHandler := createTestParser(start)
|
||||||
|
parser.Parse(bytes)
|
||||||
|
validateState(t, parser.currState, expected)
|
||||||
|
validateFuncCalls(t, evtHandler.FunctionCalls, expectedCalls)
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseParamsHelper(t *testing.T, bytes []byte, expectedParams []string) {
|
||||||
|
params, err := parseParams(bytes)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Parameter parse error: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(params) != len(expectedParams) {
|
||||||
|
t.Errorf("Parsed parameters: %v", params)
|
||||||
|
t.Errorf("Expected parameters: %v", expectedParams)
|
||||||
|
t.Errorf("Parameter length failure: %d != %d", len(params), len(expectedParams))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, v := range expectedParams {
|
||||||
|
if v != params[i] {
|
||||||
|
t.Errorf("Parsed parameters: %v", params)
|
||||||
|
t.Errorf("Expected parameters: %v", expectedParams)
|
||||||
|
t.Errorf("Parameter parse failure: %s != %s at position %d", v, params[i], i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func cursorSingleParamHelper(t *testing.T, command byte, funcName string) {
|
||||||
|
funcCallParamHelper(t, []byte{command}, "CsiEntry", "Ground", []string{fmt.Sprintf("%s([1])", funcName)})
|
||||||
|
funcCallParamHelper(t, []byte{'0', command}, "CsiEntry", "Ground", []string{fmt.Sprintf("%s([1])", funcName)})
|
||||||
|
funcCallParamHelper(t, []byte{'2', command}, "CsiEntry", "Ground", []string{fmt.Sprintf("%s([2])", funcName)})
|
||||||
|
funcCallParamHelper(t, []byte{'2', '3', command}, "CsiEntry", "Ground", []string{fmt.Sprintf("%s([23])", funcName)})
|
||||||
|
funcCallParamHelper(t, []byte{'2', ';', '3', command}, "CsiEntry", "Ground", []string{fmt.Sprintf("%s([2])", funcName)})
|
||||||
|
funcCallParamHelper(t, []byte{'2', ';', '3', ';', '4', command}, "CsiEntry", "Ground", []string{fmt.Sprintf("%s([2])", funcName)})
|
||||||
|
}
|
||||||
|
|
||||||
|
func cursorTwoParamHelper(t *testing.T, command byte, funcName string) {
|
||||||
|
funcCallParamHelper(t, []byte{command}, "CsiEntry", "Ground", []string{fmt.Sprintf("%s([1 1])", funcName)})
|
||||||
|
funcCallParamHelper(t, []byte{'0', command}, "CsiEntry", "Ground", []string{fmt.Sprintf("%s([1 1])", funcName)})
|
||||||
|
funcCallParamHelper(t, []byte{'2', command}, "CsiEntry", "Ground", []string{fmt.Sprintf("%s([2 1])", funcName)})
|
||||||
|
funcCallParamHelper(t, []byte{'2', '3', command}, "CsiEntry", "Ground", []string{fmt.Sprintf("%s([23 1])", funcName)})
|
||||||
|
funcCallParamHelper(t, []byte{'2', ';', '3', command}, "CsiEntry", "Ground", []string{fmt.Sprintf("%s([2 3])", funcName)})
|
||||||
|
funcCallParamHelper(t, []byte{'2', ';', '3', ';', '4', command}, "CsiEntry", "Ground", []string{fmt.Sprintf("%s([2 3])", funcName)})
|
||||||
|
}
|
||||||
|
|
||||||
|
func eraseHelper(t *testing.T, command byte, funcName string) {
|
||||||
|
funcCallParamHelper(t, []byte{command}, "CsiEntry", "Ground", []string{fmt.Sprintf("%s([0])", funcName)})
|
||||||
|
funcCallParamHelper(t, []byte{'0', command}, "CsiEntry", "Ground", []string{fmt.Sprintf("%s([0])", funcName)})
|
||||||
|
funcCallParamHelper(t, []byte{'1', command}, "CsiEntry", "Ground", []string{fmt.Sprintf("%s([1])", funcName)})
|
||||||
|
funcCallParamHelper(t, []byte{'2', command}, "CsiEntry", "Ground", []string{fmt.Sprintf("%s([2])", funcName)})
|
||||||
|
funcCallParamHelper(t, []byte{'3', command}, "CsiEntry", "Ground", []string{fmt.Sprintf("%s([3])", funcName)})
|
||||||
|
funcCallParamHelper(t, []byte{'4', command}, "CsiEntry", "Ground", []string{fmt.Sprintf("%s([0])", funcName)})
|
||||||
|
funcCallParamHelper(t, []byte{'1', ';', '2', command}, "CsiEntry", "Ground", []string{fmt.Sprintf("%s([1])", funcName)})
|
||||||
|
}
|
||||||
|
|
||||||
|
func scrollHelper(t *testing.T, command byte, funcName string) {
|
||||||
|
funcCallParamHelper(t, []byte{command}, "CsiEntry", "Ground", []string{fmt.Sprintf("%s([1])", funcName)})
|
||||||
|
funcCallParamHelper(t, []byte{'0', command}, "CsiEntry", "Ground", []string{fmt.Sprintf("%s([1])", funcName)})
|
||||||
|
funcCallParamHelper(t, []byte{'1', command}, "CsiEntry", "Ground", []string{fmt.Sprintf("%s([1])", funcName)})
|
||||||
|
funcCallParamHelper(t, []byte{'5', command}, "CsiEntry", "Ground", []string{fmt.Sprintf("%s([5])", funcName)})
|
||||||
|
funcCallParamHelper(t, []byte{'4', ';', '6', command}, "CsiEntry", "Ground", []string{fmt.Sprintf("%s([4])", funcName)})
|
||||||
|
}
|
||||||
|
|
||||||
|
func clearOnStateChangeHelper(t *testing.T, start string, end string, bytes []byte) {
|
||||||
|
p, _ := createTestParser(start)
|
||||||
|
fillContext(p.context)
|
||||||
|
p.Parse(bytes)
|
||||||
|
validateState(t, p.currState, end)
|
||||||
|
validateEmptyContext(t, p.context)
|
||||||
|
}
|
||||||
|
|
||||||
|
func c0Helper(t *testing.T, bytes []byte, expectedState string, expectedCalls []string) {
|
||||||
|
parser, evtHandler := createTestParser("Ground")
|
||||||
|
parser.Parse(bytes)
|
||||||
|
validateState(t, parser.currState, expectedState)
|
||||||
|
validateFuncCalls(t, evtHandler.FunctionCalls, expectedCalls)
|
||||||
|
}
|
66
vendor/src/github.com/Azure/go-ansiterm/parser_test_utilities.go
vendored
Normal file
66
vendor/src/github.com/Azure/go-ansiterm/parser_test_utilities.go
vendored
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
package ansiterm
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func createTestParser(s string) (*AnsiParser, *TestAnsiEventHandler) {
|
||||||
|
evtHandler := CreateTestAnsiEventHandler()
|
||||||
|
parser := CreateParser(s, evtHandler)
|
||||||
|
|
||||||
|
return parser, evtHandler
|
||||||
|
}
|
||||||
|
|
||||||
|
func validateState(t *testing.T, actualState State, expectedStateName string) {
|
||||||
|
actualName := "Nil"
|
||||||
|
|
||||||
|
if actualState != nil {
|
||||||
|
actualName = actualState.Name()
|
||||||
|
}
|
||||||
|
|
||||||
|
if actualName != expectedStateName {
|
||||||
|
t.Errorf("Invalid State: '%s' != '%s'", actualName, expectedStateName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func validateFuncCalls(t *testing.T, actualCalls []string, expectedCalls []string) {
|
||||||
|
actualCount := len(actualCalls)
|
||||||
|
expectedCount := len(expectedCalls)
|
||||||
|
|
||||||
|
if actualCount != expectedCount {
|
||||||
|
t.Errorf("Actual calls: %v", actualCalls)
|
||||||
|
t.Errorf("Expected calls: %v", expectedCalls)
|
||||||
|
t.Errorf("Call count error: %d != %d", actualCount, expectedCount)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, v := range actualCalls {
|
||||||
|
if v != expectedCalls[i] {
|
||||||
|
t.Errorf("Actual calls: %v", actualCalls)
|
||||||
|
t.Errorf("Expected calls: %v", expectedCalls)
|
||||||
|
t.Errorf("Mismatched calls: %s != %s with lengths %d and %d", v, expectedCalls[i], len(v), len(expectedCalls[i]))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func fillContext(context *AnsiContext) {
|
||||||
|
context.currentChar = 'A'
|
||||||
|
context.paramBuffer = []byte{'C', 'D', 'E'}
|
||||||
|
context.interBuffer = []byte{'F', 'G', 'H'}
|
||||||
|
}
|
||||||
|
|
||||||
|
func validateEmptyContext(t *testing.T, context *AnsiContext) {
|
||||||
|
var expectedCurrChar byte = 0x0
|
||||||
|
if context.currentChar != expectedCurrChar {
|
||||||
|
t.Errorf("Currentchar mismatch '%#x' != '%#x'", context.currentChar, expectedCurrChar)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(context.paramBuffer) != 0 {
|
||||||
|
t.Errorf("Non-empty parameter buffer: %v", context.paramBuffer)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(context.paramBuffer) != 0 {
|
||||||
|
t.Errorf("Non-empty intermediate buffer: %v", context.interBuffer)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
71
vendor/src/github.com/Azure/go-ansiterm/states.go
vendored
Normal file
71
vendor/src/github.com/Azure/go-ansiterm/states.go
vendored
Normal file
|
@ -0,0 +1,71 @@
|
||||||
|
package ansiterm
|
||||||
|
|
||||||
|
type StateId int
|
||||||
|
|
||||||
|
type State interface {
|
||||||
|
Enter() error
|
||||||
|
Exit() error
|
||||||
|
Handle(byte) (State, error)
|
||||||
|
Name() string
|
||||||
|
Transition(State) error
|
||||||
|
}
|
||||||
|
|
||||||
|
type BaseState struct {
|
||||||
|
name string
|
||||||
|
parser *AnsiParser
|
||||||
|
}
|
||||||
|
|
||||||
|
func (base BaseState) Enter() error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (base BaseState) Exit() error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (base BaseState) Handle(b byte) (s State, e error) {
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case b == CSI_ENTRY:
|
||||||
|
return base.parser.CsiEntry, nil
|
||||||
|
case b == DCS_ENTRY:
|
||||||
|
return base.parser.DcsEntry, nil
|
||||||
|
case b == ANSI_ESCAPE_PRIMARY:
|
||||||
|
return base.parser.Escape, nil
|
||||||
|
case b == OSC_STRING:
|
||||||
|
return base.parser.OscString, nil
|
||||||
|
case sliceContains(ToGroundBytes, b):
|
||||||
|
return base.parser.Ground, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (base BaseState) Name() string {
|
||||||
|
return base.name
|
||||||
|
}
|
||||||
|
|
||||||
|
func (base BaseState) Transition(s State) error {
|
||||||
|
if s == base.parser.Ground {
|
||||||
|
execBytes := []byte{0x18}
|
||||||
|
execBytes = append(execBytes, 0x1A)
|
||||||
|
execBytes = append(execBytes, getByteRange(0x80, 0x8F)...)
|
||||||
|
execBytes = append(execBytes, getByteRange(0x91, 0x97)...)
|
||||||
|
execBytes = append(execBytes, 0x99)
|
||||||
|
execBytes = append(execBytes, 0x9A)
|
||||||
|
|
||||||
|
if sliceContains(execBytes, base.parser.context.currentChar) {
|
||||||
|
return base.parser.execute()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type DcsEntryState struct {
|
||||||
|
BaseState
|
||||||
|
}
|
||||||
|
|
||||||
|
type ErrorState struct {
|
||||||
|
BaseState
|
||||||
|
}
|
173
vendor/src/github.com/Azure/go-ansiterm/test_event_handler.go
vendored
Normal file
173
vendor/src/github.com/Azure/go-ansiterm/test_event_handler.go
vendored
Normal file
|
@ -0,0 +1,173 @@
|
||||||
|
package ansiterm
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
|
type TestAnsiEventHandler struct {
|
||||||
|
FunctionCalls []string
|
||||||
|
}
|
||||||
|
|
||||||
|
func CreateTestAnsiEventHandler() *TestAnsiEventHandler {
|
||||||
|
evtHandler := TestAnsiEventHandler{}
|
||||||
|
evtHandler.FunctionCalls = make([]string, 0)
|
||||||
|
return &evtHandler
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *TestAnsiEventHandler) recordCall(call string, params []string) {
|
||||||
|
s := fmt.Sprintf("%s(%v)", call, params)
|
||||||
|
h.FunctionCalls = append(h.FunctionCalls, s)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *TestAnsiEventHandler) Print(b byte) error {
|
||||||
|
h.recordCall("Print", []string{string(b)})
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *TestAnsiEventHandler) Execute(b byte) error {
|
||||||
|
h.recordCall("Execute", []string{string(b)})
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *TestAnsiEventHandler) CUU(param int) error {
|
||||||
|
h.recordCall("CUU", []string{strconv.Itoa(param)})
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *TestAnsiEventHandler) CUD(param int) error {
|
||||||
|
h.recordCall("CUD", []string{strconv.Itoa(param)})
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *TestAnsiEventHandler) CUF(param int) error {
|
||||||
|
h.recordCall("CUF", []string{strconv.Itoa(param)})
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *TestAnsiEventHandler) CUB(param int) error {
|
||||||
|
h.recordCall("CUB", []string{strconv.Itoa(param)})
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *TestAnsiEventHandler) CNL(param int) error {
|
||||||
|
h.recordCall("CNL", []string{strconv.Itoa(param)})
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *TestAnsiEventHandler) CPL(param int) error {
|
||||||
|
h.recordCall("CPL", []string{strconv.Itoa(param)})
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *TestAnsiEventHandler) CHA(param int) error {
|
||||||
|
h.recordCall("CHA", []string{strconv.Itoa(param)})
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *TestAnsiEventHandler) VPA(param int) error {
|
||||||
|
h.recordCall("VPA", []string{strconv.Itoa(param)})
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *TestAnsiEventHandler) CUP(x int, y int) error {
|
||||||
|
xS, yS := strconv.Itoa(x), strconv.Itoa(y)
|
||||||
|
h.recordCall("CUP", []string{xS, yS})
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *TestAnsiEventHandler) HVP(x int, y int) error {
|
||||||
|
xS, yS := strconv.Itoa(x), strconv.Itoa(y)
|
||||||
|
h.recordCall("HVP", []string{xS, yS})
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *TestAnsiEventHandler) DECTCEM(visible bool) error {
|
||||||
|
h.recordCall("DECTCEM", []string{strconv.FormatBool(visible)})
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *TestAnsiEventHandler) DECOM(visible bool) error {
|
||||||
|
h.recordCall("DECOM", []string{strconv.FormatBool(visible)})
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *TestAnsiEventHandler) DECCOLM(use132 bool) error {
|
||||||
|
h.recordCall("DECOLM", []string{strconv.FormatBool(use132)})
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *TestAnsiEventHandler) ED(param int) error {
|
||||||
|
h.recordCall("ED", []string{strconv.Itoa(param)})
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *TestAnsiEventHandler) EL(param int) error {
|
||||||
|
h.recordCall("EL", []string{strconv.Itoa(param)})
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *TestAnsiEventHandler) IL(param int) error {
|
||||||
|
h.recordCall("IL", []string{strconv.Itoa(param)})
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *TestAnsiEventHandler) DL(param int) error {
|
||||||
|
h.recordCall("DL", []string{strconv.Itoa(param)})
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *TestAnsiEventHandler) ICH(param int) error {
|
||||||
|
h.recordCall("ICH", []string{strconv.Itoa(param)})
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *TestAnsiEventHandler) DCH(param int) error {
|
||||||
|
h.recordCall("DCH", []string{strconv.Itoa(param)})
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *TestAnsiEventHandler) SGR(params []int) error {
|
||||||
|
strings := []string{}
|
||||||
|
for _, v := range params {
|
||||||
|
strings = append(strings, strconv.Itoa(v))
|
||||||
|
}
|
||||||
|
|
||||||
|
h.recordCall("SGR", strings)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *TestAnsiEventHandler) SU(param int) error {
|
||||||
|
h.recordCall("SU", []string{strconv.Itoa(param)})
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *TestAnsiEventHandler) SD(param int) error {
|
||||||
|
h.recordCall("SD", []string{strconv.Itoa(param)})
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *TestAnsiEventHandler) DA(params []string) error {
|
||||||
|
h.recordCall("DA", params)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *TestAnsiEventHandler) DECSTBM(top int, bottom int) error {
|
||||||
|
topS, bottomS := strconv.Itoa(top), strconv.Itoa(bottom)
|
||||||
|
h.recordCall("DECSTBM", []string{topS, bottomS})
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *TestAnsiEventHandler) RI() error {
|
||||||
|
h.recordCall("RI", nil)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *TestAnsiEventHandler) IND() error {
|
||||||
|
h.recordCall("IND", nil)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *TestAnsiEventHandler) Flush() error {
|
||||||
|
return nil
|
||||||
|
}
|
21
vendor/src/github.com/Azure/go-ansiterm/utilities.go
vendored
Normal file
21
vendor/src/github.com/Azure/go-ansiterm/utilities.go
vendored
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
package ansiterm
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
|
func sliceContains(bytes []byte, b byte) bool {
|
||||||
|
for _, v := range bytes {
|
||||||
|
if v == b {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func convertBytesToInteger(bytes []byte) int {
|
||||||
|
s := string(bytes)
|
||||||
|
i, _ := strconv.Atoi(s)
|
||||||
|
return i
|
||||||
|
}
|
182
vendor/src/github.com/Azure/go-ansiterm/winterm/ansi.go
vendored
Normal file
182
vendor/src/github.com/Azure/go-ansiterm/winterm/ansi.go
vendored
Normal file
|
@ -0,0 +1,182 @@
|
||||||
|
// +build windows
|
||||||
|
|
||||||
|
package winterm
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"syscall"
|
||||||
|
|
||||||
|
. "github.com/Azure/go-ansiterm"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Windows keyboard constants
|
||||||
|
// See https://msdn.microsoft.com/en-us/library/windows/desktop/dd375731(v=vs.85).aspx.
|
||||||
|
const (
|
||||||
|
VK_PRIOR = 0x21 // PAGE UP key
|
||||||
|
VK_NEXT = 0x22 // PAGE DOWN key
|
||||||
|
VK_END = 0x23 // END key
|
||||||
|
VK_HOME = 0x24 // HOME key
|
||||||
|
VK_LEFT = 0x25 // LEFT ARROW key
|
||||||
|
VK_UP = 0x26 // UP ARROW key
|
||||||
|
VK_RIGHT = 0x27 // RIGHT ARROW key
|
||||||
|
VK_DOWN = 0x28 // DOWN ARROW key
|
||||||
|
VK_SELECT = 0x29 // SELECT key
|
||||||
|
VK_PRINT = 0x2A // PRINT key
|
||||||
|
VK_EXECUTE = 0x2B // EXECUTE key
|
||||||
|
VK_SNAPSHOT = 0x2C // PRINT SCREEN key
|
||||||
|
VK_INSERT = 0x2D // INS key
|
||||||
|
VK_DELETE = 0x2E // DEL key
|
||||||
|
VK_HELP = 0x2F // HELP key
|
||||||
|
VK_F1 = 0x70 // F1 key
|
||||||
|
VK_F2 = 0x71 // F2 key
|
||||||
|
VK_F3 = 0x72 // F3 key
|
||||||
|
VK_F4 = 0x73 // F4 key
|
||||||
|
VK_F5 = 0x74 // F5 key
|
||||||
|
VK_F6 = 0x75 // F6 key
|
||||||
|
VK_F7 = 0x76 // F7 key
|
||||||
|
VK_F8 = 0x77 // F8 key
|
||||||
|
VK_F9 = 0x78 // F9 key
|
||||||
|
VK_F10 = 0x79 // F10 key
|
||||||
|
VK_F11 = 0x7A // F11 key
|
||||||
|
VK_F12 = 0x7B // F12 key
|
||||||
|
|
||||||
|
RIGHT_ALT_PRESSED = 0x0001
|
||||||
|
LEFT_ALT_PRESSED = 0x0002
|
||||||
|
RIGHT_CTRL_PRESSED = 0x0004
|
||||||
|
LEFT_CTRL_PRESSED = 0x0008
|
||||||
|
SHIFT_PRESSED = 0x0010
|
||||||
|
NUMLOCK_ON = 0x0020
|
||||||
|
SCROLLLOCK_ON = 0x0040
|
||||||
|
CAPSLOCK_ON = 0x0080
|
||||||
|
ENHANCED_KEY = 0x0100
|
||||||
|
)
|
||||||
|
|
||||||
|
type ansiCommand struct {
|
||||||
|
CommandBytes []byte
|
||||||
|
Command string
|
||||||
|
Parameters []string
|
||||||
|
IsSpecial bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func newAnsiCommand(command []byte) *ansiCommand {
|
||||||
|
|
||||||
|
if isCharacterSelectionCmdChar(command[1]) {
|
||||||
|
// Is Character Set Selection commands
|
||||||
|
return &ansiCommand{
|
||||||
|
CommandBytes: command,
|
||||||
|
Command: string(command),
|
||||||
|
IsSpecial: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// last char is command character
|
||||||
|
lastCharIndex := len(command) - 1
|
||||||
|
|
||||||
|
ac := &ansiCommand{
|
||||||
|
CommandBytes: command,
|
||||||
|
Command: string(command[lastCharIndex]),
|
||||||
|
IsSpecial: false,
|
||||||
|
}
|
||||||
|
|
||||||
|
// more than a single escape
|
||||||
|
if lastCharIndex != 0 {
|
||||||
|
start := 1
|
||||||
|
// skip if double char escape sequence
|
||||||
|
if command[0] == ANSI_ESCAPE_PRIMARY && command[1] == ANSI_ESCAPE_SECONDARY {
|
||||||
|
start++
|
||||||
|
}
|
||||||
|
// convert this to GetNextParam method
|
||||||
|
ac.Parameters = strings.Split(string(command[start:lastCharIndex]), ANSI_PARAMETER_SEP)
|
||||||
|
}
|
||||||
|
|
||||||
|
return ac
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ac *ansiCommand) paramAsSHORT(index int, defaultValue SHORT) SHORT {
|
||||||
|
if index < 0 || index >= len(ac.Parameters) {
|
||||||
|
return defaultValue
|
||||||
|
}
|
||||||
|
|
||||||
|
param, err := strconv.ParseInt(ac.Parameters[index], 10, 16)
|
||||||
|
if err != nil {
|
||||||
|
return defaultValue
|
||||||
|
}
|
||||||
|
|
||||||
|
return SHORT(param)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ac *ansiCommand) String() string {
|
||||||
|
return fmt.Sprintf("0x%v \"%v\" (\"%v\")",
|
||||||
|
bytesToHex(ac.CommandBytes),
|
||||||
|
ac.Command,
|
||||||
|
strings.Join(ac.Parameters, "\",\""))
|
||||||
|
}
|
||||||
|
|
||||||
|
// isAnsiCommandChar returns true if the passed byte falls within the range of ANSI commands.
|
||||||
|
// See http://manpages.ubuntu.com/manpages/intrepid/man4/console_codes.4.html.
|
||||||
|
func isAnsiCommandChar(b byte) bool {
|
||||||
|
switch {
|
||||||
|
case ANSI_COMMAND_FIRST <= b && b <= ANSI_COMMAND_LAST && b != ANSI_ESCAPE_SECONDARY:
|
||||||
|
return true
|
||||||
|
case b == ANSI_CMD_G1 || b == ANSI_CMD_OSC || b == ANSI_CMD_DECPAM || b == ANSI_CMD_DECPNM:
|
||||||
|
// non-CSI escape sequence terminator
|
||||||
|
return true
|
||||||
|
case b == ANSI_CMD_STR_TERM || b == ANSI_BEL:
|
||||||
|
// String escape sequence terminator
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func isXtermOscSequence(command []byte, current byte) bool {
|
||||||
|
return (len(command) >= 2 && command[0] == ANSI_ESCAPE_PRIMARY && command[1] == ANSI_CMD_OSC && current != ANSI_BEL)
|
||||||
|
}
|
||||||
|
|
||||||
|
func isCharacterSelectionCmdChar(b byte) bool {
|
||||||
|
return (b == ANSI_CMD_G0 || b == ANSI_CMD_G1 || b == ANSI_CMD_G2 || b == ANSI_CMD_G3)
|
||||||
|
}
|
||||||
|
|
||||||
|
// bytesToHex converts a slice of bytes to a human-readable string.
|
||||||
|
func bytesToHex(b []byte) string {
|
||||||
|
hex := make([]string, len(b))
|
||||||
|
for i, ch := range b {
|
||||||
|
hex[i] = fmt.Sprintf("%X", ch)
|
||||||
|
}
|
||||||
|
return strings.Join(hex, "")
|
||||||
|
}
|
||||||
|
|
||||||
|
// ensureInRange adjusts the passed value, if necessary, to ensure it is within
|
||||||
|
// the passed min / max range.
|
||||||
|
func ensureInRange(n SHORT, min SHORT, max SHORT) SHORT {
|
||||||
|
if n < min {
|
||||||
|
return min
|
||||||
|
} else if n > max {
|
||||||
|
return max
|
||||||
|
} else {
|
||||||
|
return n
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetStdFile(nFile int) (*os.File, uintptr) {
|
||||||
|
var file *os.File
|
||||||
|
switch nFile {
|
||||||
|
case syscall.STD_INPUT_HANDLE:
|
||||||
|
file = os.Stdin
|
||||||
|
case syscall.STD_OUTPUT_HANDLE:
|
||||||
|
file = os.Stdout
|
||||||
|
case syscall.STD_ERROR_HANDLE:
|
||||||
|
file = os.Stderr
|
||||||
|
default:
|
||||||
|
panic(fmt.Errorf("Invalid standard handle identifier: %v", nFile))
|
||||||
|
}
|
||||||
|
|
||||||
|
fd, err := syscall.GetStdHandle(nFile)
|
||||||
|
if err != nil {
|
||||||
|
panic(fmt.Errorf("Invalid standard handle indentifier: %v -- %v", nFile, err))
|
||||||
|
}
|
||||||
|
|
||||||
|
return file, uintptr(fd)
|
||||||
|
}
|
329
vendor/src/github.com/Azure/go-ansiterm/winterm/api.go
vendored
Normal file
329
vendor/src/github.com/Azure/go-ansiterm/winterm/api.go
vendored
Normal file
|
@ -0,0 +1,329 @@
|
||||||
|
// +build windows
|
||||||
|
|
||||||
|
package winterm
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"syscall"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
//===========================================================================================================
|
||||||
|
// IMPORTANT NOTE:
|
||||||
|
//
|
||||||
|
// The methods below make extensive use of the "unsafe" package to obtain the required pointers.
|
||||||
|
// Beginning in Go 1.3, the garbage collector may release local variables (e.g., incoming arguments, stack
|
||||||
|
// variables) the pointers reference *before* the API completes.
|
||||||
|
//
|
||||||
|
// As a result, in those cases, the code must hint that the variables remain in active by invoking the
|
||||||
|
// dummy method "use" (see below). Newer versions of Go are planned to change the mechanism to no longer
|
||||||
|
// require unsafe pointers.
|
||||||
|
//
|
||||||
|
// If you add or modify methods, ENSURE protection of local variables through the "use" builtin to inform
|
||||||
|
// the garbage collector the variables remain in use if:
|
||||||
|
//
|
||||||
|
// -- The value is not a pointer (e.g., int32, struct)
|
||||||
|
// -- The value is not referenced by the method after passing the pointer to Windows
|
||||||
|
//
|
||||||
|
// See http://golang.org/doc/go1.3.
|
||||||
|
//===========================================================================================================
|
||||||
|
|
||||||
|
var (
|
||||||
|
kernel32DLL = syscall.NewLazyDLL("kernel32.dll")
|
||||||
|
|
||||||
|
getConsoleCursorInfoProc = kernel32DLL.NewProc("GetConsoleCursorInfo")
|
||||||
|
setConsoleCursorInfoProc = kernel32DLL.NewProc("SetConsoleCursorInfo")
|
||||||
|
setConsoleCursorPositionProc = kernel32DLL.NewProc("SetConsoleCursorPosition")
|
||||||
|
setConsoleModeProc = kernel32DLL.NewProc("SetConsoleMode")
|
||||||
|
getConsoleScreenBufferInfoProc = kernel32DLL.NewProc("GetConsoleScreenBufferInfo")
|
||||||
|
setConsoleScreenBufferSizeProc = kernel32DLL.NewProc("SetConsoleScreenBufferSize")
|
||||||
|
scrollConsoleScreenBufferProc = kernel32DLL.NewProc("ScrollConsoleScreenBufferA")
|
||||||
|
setConsoleTextAttributeProc = kernel32DLL.NewProc("SetConsoleTextAttribute")
|
||||||
|
setConsoleWindowInfoProc = kernel32DLL.NewProc("SetConsoleWindowInfo")
|
||||||
|
writeConsoleOutputProc = kernel32DLL.NewProc("WriteConsoleOutputW")
|
||||||
|
readConsoleInputProc = kernel32DLL.NewProc("ReadConsoleInputW")
|
||||||
|
waitForSingleObjectProc = kernel32DLL.NewProc("WaitForSingleObject")
|
||||||
|
)
|
||||||
|
|
||||||
|
// Windows Console constants
|
||||||
|
const (
|
||||||
|
// Console modes
|
||||||
|
// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms686033(v=vs.85).aspx.
|
||||||
|
ENABLE_PROCESSED_INPUT = 0x0001
|
||||||
|
ENABLE_LINE_INPUT = 0x0002
|
||||||
|
ENABLE_ECHO_INPUT = 0x0004
|
||||||
|
ENABLE_WINDOW_INPUT = 0x0008
|
||||||
|
ENABLE_MOUSE_INPUT = 0x0010
|
||||||
|
ENABLE_INSERT_MODE = 0x0020
|
||||||
|
ENABLE_QUICK_EDIT_MODE = 0x0040
|
||||||
|
ENABLE_EXTENDED_FLAGS = 0x0080
|
||||||
|
|
||||||
|
ENABLE_PROCESSED_OUTPUT = 0x0001
|
||||||
|
ENABLE_WRAP_AT_EOL_OUTPUT = 0x0002
|
||||||
|
|
||||||
|
// Character attributes
|
||||||
|
// Note:
|
||||||
|
// -- The attributes are combined to produce various colors (e.g., Blue + Green will create Cyan).
|
||||||
|
// Clearing all foreground or background colors results in black; setting all creates white.
|
||||||
|
// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms682088(v=vs.85).aspx#_win32_character_attributes.
|
||||||
|
FOREGROUND_BLUE WORD = 0x0001
|
||||||
|
FOREGROUND_GREEN WORD = 0x0002
|
||||||
|
FOREGROUND_RED WORD = 0x0004
|
||||||
|
FOREGROUND_INTENSITY WORD = 0x0008
|
||||||
|
FOREGROUND_MASK WORD = 0x000F
|
||||||
|
|
||||||
|
BACKGROUND_BLUE WORD = 0x0010
|
||||||
|
BACKGROUND_GREEN WORD = 0x0020
|
||||||
|
BACKGROUND_RED WORD = 0x0040
|
||||||
|
BACKGROUND_INTENSITY WORD = 0x0080
|
||||||
|
BACKGROUND_MASK WORD = 0x00F0
|
||||||
|
|
||||||
|
COMMON_LVB_MASK WORD = 0xFF00
|
||||||
|
COMMON_LVB_REVERSE_VIDEO WORD = 0x4000
|
||||||
|
COMMON_LVB_UNDERSCORE WORD = 0x8000
|
||||||
|
|
||||||
|
// Input event types
|
||||||
|
// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms683499(v=vs.85).aspx.
|
||||||
|
KEY_EVENT = 0x0001
|
||||||
|
MOUSE_EVENT = 0x0002
|
||||||
|
WINDOW_BUFFER_SIZE_EVENT = 0x0004
|
||||||
|
MENU_EVENT = 0x0008
|
||||||
|
FOCUS_EVENT = 0x0010
|
||||||
|
|
||||||
|
// WaitForSingleObject return codes
|
||||||
|
WAIT_ABANDONED = 0x00000080
|
||||||
|
WAIT_FAILED = 0xFFFFFFFF
|
||||||
|
WAIT_SIGNALED = 0x0000000
|
||||||
|
WAIT_TIMEOUT = 0x00000102
|
||||||
|
|
||||||
|
// WaitForSingleObject wait duration
|
||||||
|
WAIT_INFINITE = 0xFFFFFFFF
|
||||||
|
WAIT_ONE_SECOND = 1000
|
||||||
|
WAIT_HALF_SECOND = 500
|
||||||
|
WAIT_QUARTER_SECOND = 250
|
||||||
|
)
|
||||||
|
|
||||||
|
// Windows API Console types
|
||||||
|
// -- See https://msdn.microsoft.com/en-us/library/windows/desktop/aa383751(v=vs.85).aspx for core types (e.g., SHORT)
|
||||||
|
// -- See https://msdn.microsoft.com/en-us/library/windows/desktop/ms682101(v=vs.85).aspx for Console specific types (e.g., COORD)
|
||||||
|
// -- See https://msdn.microsoft.com/en-us/library/aa296569(v=vs.60).aspx for comments on alignment
|
||||||
|
type (
|
||||||
|
SHORT int16
|
||||||
|
BOOL int32
|
||||||
|
WORD uint16
|
||||||
|
WCHAR uint16
|
||||||
|
DWORD uint32
|
||||||
|
|
||||||
|
CHAR_INFO struct {
|
||||||
|
UnicodeChar WCHAR
|
||||||
|
Attributes WORD
|
||||||
|
}
|
||||||
|
|
||||||
|
CONSOLE_CURSOR_INFO struct {
|
||||||
|
Size DWORD
|
||||||
|
Visible BOOL
|
||||||
|
}
|
||||||
|
|
||||||
|
CONSOLE_SCREEN_BUFFER_INFO struct {
|
||||||
|
Size COORD
|
||||||
|
CursorPosition COORD
|
||||||
|
Attributes WORD
|
||||||
|
Window SMALL_RECT
|
||||||
|
MaximumWindowSize COORD
|
||||||
|
}
|
||||||
|
|
||||||
|
COORD struct {
|
||||||
|
X SHORT
|
||||||
|
Y SHORT
|
||||||
|
}
|
||||||
|
|
||||||
|
SMALL_RECT struct {
|
||||||
|
Left SHORT
|
||||||
|
Top SHORT
|
||||||
|
Right SHORT
|
||||||
|
Bottom SHORT
|
||||||
|
}
|
||||||
|
|
||||||
|
// INPUT_RECORD is a C/C++ union of which KEY_EVENT_RECORD is one case, it is also the largest
|
||||||
|
// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms683499(v=vs.85).aspx.
|
||||||
|
INPUT_RECORD struct {
|
||||||
|
EventType WORD
|
||||||
|
KeyEvent KEY_EVENT_RECORD
|
||||||
|
}
|
||||||
|
|
||||||
|
KEY_EVENT_RECORD struct {
|
||||||
|
KeyDown BOOL
|
||||||
|
RepeatCount WORD
|
||||||
|
VirtualKeyCode WORD
|
||||||
|
VirtualScanCode WORD
|
||||||
|
UnicodeChar WCHAR
|
||||||
|
ControlKeyState DWORD
|
||||||
|
}
|
||||||
|
|
||||||
|
WINDOW_BUFFER_SIZE struct {
|
||||||
|
Size COORD
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
// boolToBOOL converts a Go bool into a Windows BOOL.
|
||||||
|
func boolToBOOL(f bool) BOOL {
|
||||||
|
if f {
|
||||||
|
return BOOL(1)
|
||||||
|
} else {
|
||||||
|
return BOOL(0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetConsoleCursorInfo retrieves information about the size and visiblity of the console cursor.
|
||||||
|
// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms683163(v=vs.85).aspx.
|
||||||
|
func GetConsoleCursorInfo(handle uintptr, cursorInfo *CONSOLE_CURSOR_INFO) error {
|
||||||
|
r1, r2, err := getConsoleCursorInfoProc.Call(handle, uintptr(unsafe.Pointer(cursorInfo)), 0)
|
||||||
|
return checkError(r1, r2, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetConsoleCursorInfo sets the size and visiblity of the console cursor.
|
||||||
|
// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms686019(v=vs.85).aspx.
|
||||||
|
func SetConsoleCursorInfo(handle uintptr, cursorInfo *CONSOLE_CURSOR_INFO) error {
|
||||||
|
r1, r2, err := setConsoleCursorInfoProc.Call(handle, uintptr(unsafe.Pointer(cursorInfo)), 0)
|
||||||
|
return checkError(r1, r2, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetConsoleCursorPosition location of the console cursor.
|
||||||
|
// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms686025(v=vs.85).aspx.
|
||||||
|
func SetConsoleCursorPosition(handle uintptr, coord COORD) error {
|
||||||
|
r1, r2, err := setConsoleCursorPositionProc.Call(handle, coordToPointer(coord))
|
||||||
|
use(coord)
|
||||||
|
return checkError(r1, r2, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetConsoleMode gets the console mode for given file descriptor
|
||||||
|
// See http://msdn.microsoft.com/en-us/library/windows/desktop/ms683167(v=vs.85).aspx.
|
||||||
|
func GetConsoleMode(handle uintptr) (mode uint32, err error) {
|
||||||
|
err = syscall.GetConsoleMode(syscall.Handle(handle), &mode)
|
||||||
|
return mode, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetConsoleMode sets the console mode for given file descriptor
|
||||||
|
// See http://msdn.microsoft.com/en-us/library/windows/desktop/ms686033(v=vs.85).aspx.
|
||||||
|
func SetConsoleMode(handle uintptr, mode uint32) error {
|
||||||
|
r1, r2, err := setConsoleModeProc.Call(handle, uintptr(mode), 0)
|
||||||
|
use(mode)
|
||||||
|
return checkError(r1, r2, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetConsoleScreenBufferInfo retrieves information about the specified console screen buffer.
|
||||||
|
// See http://msdn.microsoft.com/en-us/library/windows/desktop/ms683171(v=vs.85).aspx.
|
||||||
|
func GetConsoleScreenBufferInfo(handle uintptr) (*CONSOLE_SCREEN_BUFFER_INFO, error) {
|
||||||
|
info := CONSOLE_SCREEN_BUFFER_INFO{}
|
||||||
|
err := checkError(getConsoleScreenBufferInfoProc.Call(handle, uintptr(unsafe.Pointer(&info)), 0))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &info, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func ScrollConsoleScreenBuffer(handle uintptr, scrollRect SMALL_RECT, clipRect SMALL_RECT, destOrigin COORD, char CHAR_INFO) error {
|
||||||
|
r1, r2, err := scrollConsoleScreenBufferProc.Call(handle, uintptr(unsafe.Pointer(&scrollRect)), uintptr(unsafe.Pointer(&clipRect)), coordToPointer(destOrigin), uintptr(unsafe.Pointer(&char)))
|
||||||
|
use(scrollRect)
|
||||||
|
use(clipRect)
|
||||||
|
use(destOrigin)
|
||||||
|
use(char)
|
||||||
|
return checkError(r1, r2, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetConsoleScreenBufferSize sets the size of the console screen buffer.
|
||||||
|
// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms686044(v=vs.85).aspx.
|
||||||
|
func SetConsoleScreenBufferSize(handle uintptr, coord COORD) error {
|
||||||
|
r1, r2, err := setConsoleScreenBufferSizeProc.Call(handle, coordToPointer(coord))
|
||||||
|
use(coord)
|
||||||
|
return checkError(r1, r2, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetConsoleTextAttribute sets the attributes of characters written to the
|
||||||
|
// console screen buffer by the WriteFile or WriteConsole function.
|
||||||
|
// See http://msdn.microsoft.com/en-us/library/windows/desktop/ms686047(v=vs.85).aspx.
|
||||||
|
func SetConsoleTextAttribute(handle uintptr, attribute WORD) error {
|
||||||
|
r1, r2, err := setConsoleTextAttributeProc.Call(handle, uintptr(attribute), 0)
|
||||||
|
use(attribute)
|
||||||
|
return checkError(r1, r2, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetConsoleWindowInfo sets the size and position of the console screen buffer's window.
|
||||||
|
// Note that the size and location must be within and no larger than the backing console screen buffer.
|
||||||
|
// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms686125(v=vs.85).aspx.
|
||||||
|
func SetConsoleWindowInfo(handle uintptr, isAbsolute bool, rect SMALL_RECT) error {
|
||||||
|
r1, r2, err := setConsoleWindowInfoProc.Call(handle, uintptr(boolToBOOL(isAbsolute)), uintptr(unsafe.Pointer(&rect)))
|
||||||
|
use(isAbsolute)
|
||||||
|
use(rect)
|
||||||
|
return checkError(r1, r2, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// WriteConsoleOutput writes the CHAR_INFOs from the provided buffer to the active console buffer.
|
||||||
|
// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms687404(v=vs.85).aspx.
|
||||||
|
func WriteConsoleOutput(handle uintptr, buffer []CHAR_INFO, bufferSize COORD, bufferCoord COORD, writeRegion *SMALL_RECT) error {
|
||||||
|
r1, r2, err := writeConsoleOutputProc.Call(handle, uintptr(unsafe.Pointer(&buffer[0])), coordToPointer(bufferSize), coordToPointer(bufferCoord), uintptr(unsafe.Pointer(writeRegion)))
|
||||||
|
use(buffer)
|
||||||
|
use(bufferSize)
|
||||||
|
use(bufferCoord)
|
||||||
|
return checkError(r1, r2, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReadConsoleInput reads (and removes) data from the console input buffer.
|
||||||
|
// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms684961(v=vs.85).aspx.
|
||||||
|
func ReadConsoleInput(handle uintptr, buffer []INPUT_RECORD, count *uint32) error {
|
||||||
|
r1, r2, err := readConsoleInputProc.Call(handle, uintptr(unsafe.Pointer(&buffer[0])), uintptr(len(buffer)), uintptr(unsafe.Pointer(count)))
|
||||||
|
use(buffer)
|
||||||
|
return checkError(r1, r2, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// WaitForSingleObject waits for the passed handle to be signaled.
|
||||||
|
// It returns true if the handle was signaled; false otherwise.
|
||||||
|
// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms687032(v=vs.85).aspx.
|
||||||
|
func WaitForSingleObject(handle uintptr, msWait uint32) (bool, error) {
|
||||||
|
r1, _, err := waitForSingleObjectProc.Call(handle, uintptr(DWORD(msWait)))
|
||||||
|
switch r1 {
|
||||||
|
case WAIT_ABANDONED, WAIT_TIMEOUT:
|
||||||
|
return false, nil
|
||||||
|
case WAIT_SIGNALED:
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
use(msWait)
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// String helpers
|
||||||
|
func (info CONSOLE_SCREEN_BUFFER_INFO) String() string {
|
||||||
|
return fmt.Sprintf("Size(%v) Cursor(%v) Window(%v) Max(%v)", info.Size, info.CursorPosition, info.Window, info.MaximumWindowSize)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (coord COORD) String() string {
|
||||||
|
return fmt.Sprintf("%v,%v", coord.X, coord.Y)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rect SMALL_RECT) String() string {
|
||||||
|
return fmt.Sprintf("(%v,%v),(%v,%v)", rect.Left, rect.Top, rect.Right, rect.Bottom)
|
||||||
|
}
|
||||||
|
|
||||||
|
// checkError evaluates the results of a Windows API call and returns the error if it failed.
|
||||||
|
func checkError(r1, r2 uintptr, err error) error {
|
||||||
|
// Windows APIs return non-zero to indicate success
|
||||||
|
if r1 != 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the error if provided, otherwise default to EINVAL
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return syscall.EINVAL
|
||||||
|
}
|
||||||
|
|
||||||
|
// coordToPointer converts a COORD into a uintptr (by fooling the type system).
|
||||||
|
func coordToPointer(c COORD) uintptr {
|
||||||
|
// Note: This code assumes the two SHORTs are correctly laid out; the "cast" to DWORD is just to get a pointer to pass.
|
||||||
|
return uintptr(*((*DWORD)(unsafe.Pointer(&c))))
|
||||||
|
}
|
||||||
|
|
||||||
|
// use is a no-op, but the compiler cannot see that it is.
|
||||||
|
// Calling use(p) ensures that p is kept live until that point.
|
||||||
|
func use(p interface{}) {}
|
102
vendor/src/github.com/Azure/go-ansiterm/winterm/attr_translation.go
vendored
Normal file
102
vendor/src/github.com/Azure/go-ansiterm/winterm/attr_translation.go
vendored
Normal file
|
@ -0,0 +1,102 @@
|
||||||
|
// +build windows
|
||||||
|
|
||||||
|
package winterm
|
||||||
|
|
||||||
|
import (
|
||||||
|
. "github.com/Azure/go-ansiterm"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
FOREGROUND_COLOR_MASK = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE
|
||||||
|
BACKGROUND_COLOR_MASK = BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE
|
||||||
|
)
|
||||||
|
|
||||||
|
// collectAnsiIntoWindowsAttributes modifies the passed Windows text mode flags to reflect the
|
||||||
|
// request represented by the passed ANSI mode.
|
||||||
|
func collectAnsiIntoWindowsAttributes(windowsMode WORD, inverted bool, baseMode WORD, ansiMode SHORT) (WORD, bool) {
|
||||||
|
switch ansiMode {
|
||||||
|
|
||||||
|
// Mode styles
|
||||||
|
case ANSI_SGR_BOLD:
|
||||||
|
windowsMode = windowsMode | FOREGROUND_INTENSITY
|
||||||
|
|
||||||
|
case ANSI_SGR_DIM, ANSI_SGR_BOLD_DIM_OFF:
|
||||||
|
windowsMode &^= FOREGROUND_INTENSITY
|
||||||
|
|
||||||
|
case ANSI_SGR_UNDERLINE:
|
||||||
|
windowsMode = windowsMode | COMMON_LVB_UNDERSCORE
|
||||||
|
|
||||||
|
case ANSI_SGR_REVERSE:
|
||||||
|
inverted = true
|
||||||
|
|
||||||
|
case ANSI_SGR_REVERSE_OFF:
|
||||||
|
inverted = false
|
||||||
|
|
||||||
|
case ANSI_SGR_UNDERLINE_OFF:
|
||||||
|
windowsMode &^= COMMON_LVB_UNDERSCORE
|
||||||
|
|
||||||
|
// Foreground colors
|
||||||
|
case ANSI_SGR_FOREGROUND_DEFAULT:
|
||||||
|
windowsMode = (windowsMode &^ FOREGROUND_MASK) | (baseMode & FOREGROUND_MASK)
|
||||||
|
|
||||||
|
case ANSI_SGR_FOREGROUND_BLACK:
|
||||||
|
windowsMode = (windowsMode &^ FOREGROUND_COLOR_MASK)
|
||||||
|
|
||||||
|
case ANSI_SGR_FOREGROUND_RED:
|
||||||
|
windowsMode = (windowsMode &^ FOREGROUND_COLOR_MASK) | FOREGROUND_RED
|
||||||
|
|
||||||
|
case ANSI_SGR_FOREGROUND_GREEN:
|
||||||
|
windowsMode = (windowsMode &^ FOREGROUND_COLOR_MASK) | FOREGROUND_GREEN
|
||||||
|
|
||||||
|
case ANSI_SGR_FOREGROUND_YELLOW:
|
||||||
|
windowsMode = (windowsMode &^ FOREGROUND_COLOR_MASK) | FOREGROUND_RED | FOREGROUND_GREEN
|
||||||
|
|
||||||
|
case ANSI_SGR_FOREGROUND_BLUE:
|
||||||
|
windowsMode = (windowsMode &^ FOREGROUND_COLOR_MASK) | FOREGROUND_BLUE
|
||||||
|
|
||||||
|
case ANSI_SGR_FOREGROUND_MAGENTA:
|
||||||
|
windowsMode = (windowsMode &^ FOREGROUND_COLOR_MASK) | FOREGROUND_RED | FOREGROUND_BLUE
|
||||||
|
|
||||||
|
case ANSI_SGR_FOREGROUND_CYAN:
|
||||||
|
windowsMode = (windowsMode &^ FOREGROUND_COLOR_MASK) | FOREGROUND_GREEN | FOREGROUND_BLUE
|
||||||
|
|
||||||
|
case ANSI_SGR_FOREGROUND_WHITE:
|
||||||
|
windowsMode = (windowsMode &^ FOREGROUND_COLOR_MASK) | FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE
|
||||||
|
|
||||||
|
// Background colors
|
||||||
|
case ANSI_SGR_BACKGROUND_DEFAULT:
|
||||||
|
// Black with no intensity
|
||||||
|
windowsMode = (windowsMode &^ BACKGROUND_MASK) | (baseMode & BACKGROUND_MASK)
|
||||||
|
|
||||||
|
case ANSI_SGR_BACKGROUND_BLACK:
|
||||||
|
windowsMode = (windowsMode &^ BACKGROUND_COLOR_MASK)
|
||||||
|
|
||||||
|
case ANSI_SGR_BACKGROUND_RED:
|
||||||
|
windowsMode = (windowsMode &^ BACKGROUND_COLOR_MASK) | BACKGROUND_RED
|
||||||
|
|
||||||
|
case ANSI_SGR_BACKGROUND_GREEN:
|
||||||
|
windowsMode = (windowsMode &^ BACKGROUND_COLOR_MASK) | BACKGROUND_GREEN
|
||||||
|
|
||||||
|
case ANSI_SGR_BACKGROUND_YELLOW:
|
||||||
|
windowsMode = (windowsMode &^ BACKGROUND_COLOR_MASK) | BACKGROUND_RED | BACKGROUND_GREEN
|
||||||
|
|
||||||
|
case ANSI_SGR_BACKGROUND_BLUE:
|
||||||
|
windowsMode = (windowsMode &^ BACKGROUND_COLOR_MASK) | BACKGROUND_BLUE
|
||||||
|
|
||||||
|
case ANSI_SGR_BACKGROUND_MAGENTA:
|
||||||
|
windowsMode = (windowsMode &^ BACKGROUND_COLOR_MASK) | BACKGROUND_RED | BACKGROUND_BLUE
|
||||||
|
|
||||||
|
case ANSI_SGR_BACKGROUND_CYAN:
|
||||||
|
windowsMode = (windowsMode &^ BACKGROUND_COLOR_MASK) | BACKGROUND_GREEN | BACKGROUND_BLUE
|
||||||
|
|
||||||
|
case ANSI_SGR_BACKGROUND_WHITE:
|
||||||
|
windowsMode = (windowsMode &^ BACKGROUND_COLOR_MASK) | BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE
|
||||||
|
}
|
||||||
|
|
||||||
|
return windowsMode, inverted
|
||||||
|
}
|
||||||
|
|
||||||
|
// invertAttributes inverts the foreground and background colors of a Windows attributes value
|
||||||
|
func invertAttributes(windowsMode WORD) WORD {
|
||||||
|
return (COMMON_LVB_MASK & windowsMode) | ((FOREGROUND_MASK & windowsMode) << 4) | ((BACKGROUND_MASK & windowsMode) >> 4)
|
||||||
|
}
|
101
vendor/src/github.com/Azure/go-ansiterm/winterm/cursor_helpers.go
vendored
Normal file
101
vendor/src/github.com/Azure/go-ansiterm/winterm/cursor_helpers.go
vendored
Normal file
|
@ -0,0 +1,101 @@
|
||||||
|
// +build windows
|
||||||
|
|
||||||
|
package winterm
|
||||||
|
|
||||||
|
const (
|
||||||
|
Horizontal = iota
|
||||||
|
Vertical
|
||||||
|
)
|
||||||
|
|
||||||
|
func (h *WindowsAnsiEventHandler) getCursorWindow(info *CONSOLE_SCREEN_BUFFER_INFO) SMALL_RECT {
|
||||||
|
if h.originMode {
|
||||||
|
sr := h.effectiveSr(info.Window)
|
||||||
|
return SMALL_RECT{
|
||||||
|
Top: sr.top,
|
||||||
|
Bottom: sr.bottom,
|
||||||
|
Left: 0,
|
||||||
|
Right: info.Size.X - 1,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return SMALL_RECT{
|
||||||
|
Top: info.Window.Top,
|
||||||
|
Bottom: info.Window.Bottom,
|
||||||
|
Left: 0,
|
||||||
|
Right: info.Size.X - 1,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// setCursorPosition sets the cursor to the specified position, bounded to the screen size
|
||||||
|
func (h *WindowsAnsiEventHandler) setCursorPosition(position COORD, window SMALL_RECT) error {
|
||||||
|
position.X = ensureInRange(position.X, window.Left, window.Right)
|
||||||
|
position.Y = ensureInRange(position.Y, window.Top, window.Bottom)
|
||||||
|
err := SetConsoleCursorPosition(h.fd, position)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
logger.Infof("Cursor position set: (%d, %d)", position.X, position.Y)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *WindowsAnsiEventHandler) moveCursorVertical(param int) error {
|
||||||
|
return h.moveCursor(Vertical, param)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *WindowsAnsiEventHandler) moveCursorHorizontal(param int) error {
|
||||||
|
return h.moveCursor(Horizontal, param)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *WindowsAnsiEventHandler) moveCursor(moveMode int, param int) error {
|
||||||
|
info, err := GetConsoleScreenBufferInfo(h.fd)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
position := info.CursorPosition
|
||||||
|
switch moveMode {
|
||||||
|
case Horizontal:
|
||||||
|
position.X += SHORT(param)
|
||||||
|
case Vertical:
|
||||||
|
position.Y += SHORT(param)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = h.setCursorPosition(position, h.getCursorWindow(info)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *WindowsAnsiEventHandler) moveCursorLine(param int) error {
|
||||||
|
info, err := GetConsoleScreenBufferInfo(h.fd)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
position := info.CursorPosition
|
||||||
|
position.X = 0
|
||||||
|
position.Y += SHORT(param)
|
||||||
|
|
||||||
|
if err = h.setCursorPosition(position, h.getCursorWindow(info)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *WindowsAnsiEventHandler) moveCursorColumn(param int) error {
|
||||||
|
info, err := GetConsoleScreenBufferInfo(h.fd)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
position := info.CursorPosition
|
||||||
|
position.X = SHORT(param) - 1
|
||||||
|
|
||||||
|
if err = h.setCursorPosition(position, h.getCursorWindow(info)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
86
vendor/src/github.com/Azure/go-ansiterm/winterm/erase_helpers.go
vendored
Normal file
86
vendor/src/github.com/Azure/go-ansiterm/winterm/erase_helpers.go
vendored
Normal file
|
@ -0,0 +1,86 @@
|
||||||
|
// +build windows
|
||||||
|
|
||||||
|
package winterm
|
||||||
|
|
||||||
|
import (
|
||||||
|
. "github.com/Azure/go-ansiterm"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (h *WindowsAnsiEventHandler) clearRange(attributes WORD, fromCoord COORD, toCoord COORD) error {
|
||||||
|
// Ignore an invalid (negative area) request
|
||||||
|
if toCoord.Y < fromCoord.Y {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var err error
|
||||||
|
|
||||||
|
var coordStart = COORD{}
|
||||||
|
var coordEnd = COORD{}
|
||||||
|
|
||||||
|
xCurrent, yCurrent := fromCoord.X, fromCoord.Y
|
||||||
|
xEnd, yEnd := toCoord.X, toCoord.Y
|
||||||
|
|
||||||
|
// Clear any partial initial line
|
||||||
|
if xCurrent > 0 {
|
||||||
|
coordStart.X, coordStart.Y = xCurrent, yCurrent
|
||||||
|
coordEnd.X, coordEnd.Y = xEnd, yCurrent
|
||||||
|
|
||||||
|
err = h.clearRect(attributes, coordStart, coordEnd)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
xCurrent = 0
|
||||||
|
yCurrent += 1
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear intervening rectangular section
|
||||||
|
if yCurrent < yEnd {
|
||||||
|
coordStart.X, coordStart.Y = xCurrent, yCurrent
|
||||||
|
coordEnd.X, coordEnd.Y = xEnd, yEnd-1
|
||||||
|
|
||||||
|
err = h.clearRect(attributes, coordStart, coordEnd)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
xCurrent = 0
|
||||||
|
yCurrent = yEnd
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear remaining partial ending line
|
||||||
|
coordStart.X, coordStart.Y = xCurrent, yCurrent
|
||||||
|
coordEnd.X, coordEnd.Y = xEnd, yEnd
|
||||||
|
|
||||||
|
err = h.clearRect(attributes, coordStart, coordEnd)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *WindowsAnsiEventHandler) clearRect(attributes WORD, fromCoord COORD, toCoord COORD) error {
|
||||||
|
region := SMALL_RECT{Top: fromCoord.Y, Left: fromCoord.X, Bottom: toCoord.Y, Right: toCoord.X}
|
||||||
|
width := toCoord.X - fromCoord.X + 1
|
||||||
|
height := toCoord.Y - fromCoord.Y + 1
|
||||||
|
size := uint32(width) * uint32(height)
|
||||||
|
|
||||||
|
if size <= 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer := make([]CHAR_INFO, size)
|
||||||
|
|
||||||
|
char := CHAR_INFO{WCHAR(FILL_CHARACTER), attributes}
|
||||||
|
for i := 0; i < int(size); i++ {
|
||||||
|
buffer[i] = char
|
||||||
|
}
|
||||||
|
|
||||||
|
err := WriteConsoleOutput(h.fd, buffer, COORD{X: width, Y: height}, COORD{X: 0, Y: 0}, ®ion)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
118
vendor/src/github.com/Azure/go-ansiterm/winterm/scroll_helper.go
vendored
Normal file
118
vendor/src/github.com/Azure/go-ansiterm/winterm/scroll_helper.go
vendored
Normal file
|
@ -0,0 +1,118 @@
|
||||||
|
// +build windows
|
||||||
|
|
||||||
|
package winterm
|
||||||
|
|
||||||
|
// effectiveSr gets the current effective scroll region in buffer coordinates
|
||||||
|
func (h *WindowsAnsiEventHandler) effectiveSr(window SMALL_RECT) scrollRegion {
|
||||||
|
top := AddInRange(window.Top, h.sr.top, window.Top, window.Bottom)
|
||||||
|
bottom := AddInRange(window.Top, h.sr.bottom, window.Top, window.Bottom)
|
||||||
|
if top >= bottom {
|
||||||
|
top = window.Top
|
||||||
|
bottom = window.Bottom
|
||||||
|
}
|
||||||
|
return scrollRegion{top: top, bottom: bottom}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *WindowsAnsiEventHandler) scrollUp(param int) error {
|
||||||
|
info, err := GetConsoleScreenBufferInfo(h.fd)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
sr := h.effectiveSr(info.Window)
|
||||||
|
return h.scroll(param, sr, info)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *WindowsAnsiEventHandler) scrollDown(param int) error {
|
||||||
|
return h.scrollUp(-param)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *WindowsAnsiEventHandler) deleteLines(param int) error {
|
||||||
|
info, err := GetConsoleScreenBufferInfo(h.fd)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
start := info.CursorPosition.Y
|
||||||
|
sr := h.effectiveSr(info.Window)
|
||||||
|
// Lines cannot be inserted or deleted outside the scrolling region.
|
||||||
|
if start >= sr.top && start <= sr.bottom {
|
||||||
|
sr.top = start
|
||||||
|
return h.scroll(param, sr, info)
|
||||||
|
} else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *WindowsAnsiEventHandler) insertLines(param int) error {
|
||||||
|
return h.deleteLines(-param)
|
||||||
|
}
|
||||||
|
|
||||||
|
// scroll scrolls the provided scroll region by param lines. The scroll region is in buffer coordinates.
|
||||||
|
func (h *WindowsAnsiEventHandler) scroll(param int, sr scrollRegion, info *CONSOLE_SCREEN_BUFFER_INFO) error {
|
||||||
|
logger.Infof("scroll: scrollTop: %d, scrollBottom: %d", sr.top, sr.bottom)
|
||||||
|
logger.Infof("scroll: windowTop: %d, windowBottom: %d", info.Window.Top, info.Window.Bottom)
|
||||||
|
|
||||||
|
// Copy from and clip to the scroll region (full buffer width)
|
||||||
|
scrollRect := SMALL_RECT{
|
||||||
|
Top: sr.top,
|
||||||
|
Bottom: sr.bottom,
|
||||||
|
Left: 0,
|
||||||
|
Right: info.Size.X - 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Origin to which area should be copied
|
||||||
|
destOrigin := COORD{
|
||||||
|
X: 0,
|
||||||
|
Y: sr.top - SHORT(param),
|
||||||
|
}
|
||||||
|
|
||||||
|
char := CHAR_INFO{
|
||||||
|
UnicodeChar: ' ',
|
||||||
|
Attributes: h.attributes,
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := ScrollConsoleScreenBuffer(h.fd, scrollRect, scrollRect, destOrigin, char); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *WindowsAnsiEventHandler) deleteCharacters(param int) error {
|
||||||
|
info, err := GetConsoleScreenBufferInfo(h.fd)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return h.scrollLine(param, info.CursorPosition, info)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *WindowsAnsiEventHandler) insertCharacters(param int) error {
|
||||||
|
return h.deleteCharacters(-param)
|
||||||
|
}
|
||||||
|
|
||||||
|
// scrollLine scrolls a line horizontally starting at the provided position by a number of columns.
|
||||||
|
func (h *WindowsAnsiEventHandler) scrollLine(columns int, position COORD, info *CONSOLE_SCREEN_BUFFER_INFO) error {
|
||||||
|
// Copy from and clip to the scroll region (full buffer width)
|
||||||
|
scrollRect := SMALL_RECT{
|
||||||
|
Top: position.Y,
|
||||||
|
Bottom: position.Y,
|
||||||
|
Left: position.X,
|
||||||
|
Right: info.Size.X - 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Origin to which area should be copied
|
||||||
|
destOrigin := COORD{
|
||||||
|
X: position.X - SHORT(columns),
|
||||||
|
Y: position.Y,
|
||||||
|
}
|
||||||
|
|
||||||
|
char := CHAR_INFO{
|
||||||
|
UnicodeChar: ' ',
|
||||||
|
Attributes: h.attributes,
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := ScrollConsoleScreenBuffer(h.fd, scrollRect, scrollRect, destOrigin, char); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
9
vendor/src/github.com/Azure/go-ansiterm/winterm/utilities.go
vendored
Normal file
9
vendor/src/github.com/Azure/go-ansiterm/winterm/utilities.go
vendored
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
// +build windows
|
||||||
|
|
||||||
|
package winterm
|
||||||
|
|
||||||
|
// AddInRange increments a value by the passed quantity while ensuring the values
|
||||||
|
// always remain within the supplied min / max range.
|
||||||
|
func AddInRange(n SHORT, increment SHORT, min SHORT, max SHORT) SHORT {
|
||||||
|
return ensureInRange(n+increment, min, max)
|
||||||
|
}
|
725
vendor/src/github.com/Azure/go-ansiterm/winterm/win_event_handler.go
vendored
Normal file
725
vendor/src/github.com/Azure/go-ansiterm/winterm/win_event_handler.go
vendored
Normal file
|
@ -0,0 +1,725 @@
|
||||||
|
// +build windows
|
||||||
|
|
||||||
|
package winterm
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
. "github.com/Azure/go-ansiterm"
|
||||||
|
"github.com/Sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
var logger *logrus.Logger
|
||||||
|
|
||||||
|
type WindowsAnsiEventHandler struct {
|
||||||
|
fd uintptr
|
||||||
|
file *os.File
|
||||||
|
infoReset *CONSOLE_SCREEN_BUFFER_INFO
|
||||||
|
sr scrollRegion
|
||||||
|
buffer bytes.Buffer
|
||||||
|
attributes WORD
|
||||||
|
inverted bool
|
||||||
|
wrapNext bool
|
||||||
|
drewMarginByte bool
|
||||||
|
originMode bool
|
||||||
|
marginByte byte
|
||||||
|
curInfo *CONSOLE_SCREEN_BUFFER_INFO
|
||||||
|
curPos COORD
|
||||||
|
}
|
||||||
|
|
||||||
|
func CreateWinEventHandler(fd uintptr, file *os.File) AnsiEventHandler {
|
||||||
|
logFile := ioutil.Discard
|
||||||
|
|
||||||
|
if isDebugEnv := os.Getenv(LogEnv); isDebugEnv == "1" {
|
||||||
|
logFile, _ = os.Create("winEventHandler.log")
|
||||||
|
}
|
||||||
|
|
||||||
|
logger = &logrus.Logger{
|
||||||
|
Out: logFile,
|
||||||
|
Formatter: new(logrus.TextFormatter),
|
||||||
|
Level: logrus.DebugLevel,
|
||||||
|
}
|
||||||
|
|
||||||
|
infoReset, err := GetConsoleScreenBufferInfo(fd)
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return &WindowsAnsiEventHandler{
|
||||||
|
fd: fd,
|
||||||
|
file: file,
|
||||||
|
infoReset: infoReset,
|
||||||
|
attributes: infoReset.Attributes,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type scrollRegion struct {
|
||||||
|
top SHORT
|
||||||
|
bottom SHORT
|
||||||
|
}
|
||||||
|
|
||||||
|
// simulateLF simulates a LF or CR+LF by scrolling if necessary to handle the
|
||||||
|
// current cursor position and scroll region settings, in which case it returns
|
||||||
|
// true. If no special handling is necessary, then it does nothing and returns
|
||||||
|
// false.
|
||||||
|
//
|
||||||
|
// In the false case, the caller should ensure that a carriage return
|
||||||
|
// and line feed are inserted or that the text is otherwise wrapped.
|
||||||
|
func (h *WindowsAnsiEventHandler) simulateLF(includeCR bool) (bool, error) {
|
||||||
|
if h.wrapNext {
|
||||||
|
if err := h.Flush(); err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
h.clearWrap()
|
||||||
|
}
|
||||||
|
pos, info, err := h.getCurrentInfo()
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
sr := h.effectiveSr(info.Window)
|
||||||
|
if pos.Y == sr.bottom {
|
||||||
|
// Scrolling is necessary. Let Windows automatically scroll if the scrolling region
|
||||||
|
// is the full window.
|
||||||
|
if sr.top == info.Window.Top && sr.bottom == info.Window.Bottom {
|
||||||
|
if includeCR {
|
||||||
|
pos.X = 0
|
||||||
|
h.updatePos(pos)
|
||||||
|
}
|
||||||
|
return false, nil
|
||||||
|
} else {
|
||||||
|
// A custom scroll region is active. Scroll the window manually to simulate
|
||||||
|
// the LF.
|
||||||
|
if err := h.Flush(); err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
logger.Info("Simulating LF inside scroll region")
|
||||||
|
if err := h.scrollUp(1); err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
if includeCR {
|
||||||
|
pos.X = 0
|
||||||
|
if err := SetConsoleCursorPosition(h.fd, pos); err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
} else if pos.Y < info.Window.Bottom {
|
||||||
|
// Let Windows handle the LF.
|
||||||
|
pos.Y++
|
||||||
|
if includeCR {
|
||||||
|
pos.X = 0
|
||||||
|
}
|
||||||
|
h.updatePos(pos)
|
||||||
|
return false, nil
|
||||||
|
} else {
|
||||||
|
// The cursor is at the bottom of the screen but outside the scroll
|
||||||
|
// region. Skip the LF.
|
||||||
|
logger.Info("Simulating LF outside scroll region")
|
||||||
|
if includeCR {
|
||||||
|
if err := h.Flush(); err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
pos.X = 0
|
||||||
|
if err := SetConsoleCursorPosition(h.fd, pos); err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// executeLF executes a LF without a CR.
|
||||||
|
func (h *WindowsAnsiEventHandler) executeLF() error {
|
||||||
|
handled, err := h.simulateLF(false)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if !handled {
|
||||||
|
// Windows LF will reset the cursor column position. Write the LF
|
||||||
|
// and restore the cursor position.
|
||||||
|
pos, _, err := h.getCurrentInfo()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
h.buffer.WriteByte(ANSI_LINE_FEED)
|
||||||
|
if pos.X != 0 {
|
||||||
|
if err := h.Flush(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
logger.Info("Resetting cursor position for LF without CR")
|
||||||
|
if err := SetConsoleCursorPosition(h.fd, pos); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *WindowsAnsiEventHandler) Print(b byte) error {
|
||||||
|
if h.wrapNext {
|
||||||
|
h.buffer.WriteByte(h.marginByte)
|
||||||
|
h.clearWrap()
|
||||||
|
if _, err := h.simulateLF(true); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pos, info, err := h.getCurrentInfo()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if pos.X == info.Size.X-1 {
|
||||||
|
h.wrapNext = true
|
||||||
|
h.marginByte = b
|
||||||
|
} else {
|
||||||
|
pos.X++
|
||||||
|
h.updatePos(pos)
|
||||||
|
h.buffer.WriteByte(b)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *WindowsAnsiEventHandler) Execute(b byte) error {
|
||||||
|
switch b {
|
||||||
|
case ANSI_TAB:
|
||||||
|
logger.Info("Execute(TAB)")
|
||||||
|
// Move to the next tab stop, but preserve auto-wrap if already set.
|
||||||
|
if !h.wrapNext {
|
||||||
|
pos, info, err := h.getCurrentInfo()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
pos.X = (pos.X + 8) - pos.X%8
|
||||||
|
if pos.X >= info.Size.X {
|
||||||
|
pos.X = info.Size.X - 1
|
||||||
|
}
|
||||||
|
if err := h.Flush(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := SetConsoleCursorPosition(h.fd, pos); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
|
||||||
|
case ANSI_BEL:
|
||||||
|
h.buffer.WriteByte(ANSI_BEL)
|
||||||
|
return nil
|
||||||
|
|
||||||
|
case ANSI_BACKSPACE:
|
||||||
|
if h.wrapNext {
|
||||||
|
if err := h.Flush(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
h.clearWrap()
|
||||||
|
}
|
||||||
|
pos, _, err := h.getCurrentInfo()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if pos.X > 0 {
|
||||||
|
pos.X--
|
||||||
|
h.updatePos(pos)
|
||||||
|
h.buffer.WriteByte(ANSI_BACKSPACE)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
|
||||||
|
case ANSI_VERTICAL_TAB, ANSI_FORM_FEED:
|
||||||
|
// Treat as true LF.
|
||||||
|
return h.executeLF()
|
||||||
|
|
||||||
|
case ANSI_LINE_FEED:
|
||||||
|
// Simulate a CR and LF for now since there is no way in go-ansiterm
|
||||||
|
// to tell if the LF should include CR (and more things break when it's
|
||||||
|
// missing than when it's incorrectly added).
|
||||||
|
handled, err := h.simulateLF(true)
|
||||||
|
if handled || err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return h.buffer.WriteByte(ANSI_LINE_FEED)
|
||||||
|
|
||||||
|
case ANSI_CARRIAGE_RETURN:
|
||||||
|
if h.wrapNext {
|
||||||
|
if err := h.Flush(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
h.clearWrap()
|
||||||
|
}
|
||||||
|
pos, _, err := h.getCurrentInfo()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if pos.X != 0 {
|
||||||
|
pos.X = 0
|
||||||
|
h.updatePos(pos)
|
||||||
|
h.buffer.WriteByte(ANSI_CARRIAGE_RETURN)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *WindowsAnsiEventHandler) CUU(param int) error {
|
||||||
|
if err := h.Flush(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
logger.Infof("CUU: [%v]", []string{strconv.Itoa(param)})
|
||||||
|
h.clearWrap()
|
||||||
|
return h.moveCursorVertical(-param)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *WindowsAnsiEventHandler) CUD(param int) error {
|
||||||
|
if err := h.Flush(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
logger.Infof("CUD: [%v]", []string{strconv.Itoa(param)})
|
||||||
|
h.clearWrap()
|
||||||
|
return h.moveCursorVertical(param)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *WindowsAnsiEventHandler) CUF(param int) error {
|
||||||
|
if err := h.Flush(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
logger.Infof("CUF: [%v]", []string{strconv.Itoa(param)})
|
||||||
|
h.clearWrap()
|
||||||
|
return h.moveCursorHorizontal(param)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *WindowsAnsiEventHandler) CUB(param int) error {
|
||||||
|
if err := h.Flush(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
logger.Infof("CUB: [%v]", []string{strconv.Itoa(param)})
|
||||||
|
h.clearWrap()
|
||||||
|
return h.moveCursorHorizontal(-param)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *WindowsAnsiEventHandler) CNL(param int) error {
|
||||||
|
if err := h.Flush(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
logger.Infof("CNL: [%v]", []string{strconv.Itoa(param)})
|
||||||
|
h.clearWrap()
|
||||||
|
return h.moveCursorLine(param)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *WindowsAnsiEventHandler) CPL(param int) error {
|
||||||
|
if err := h.Flush(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
logger.Infof("CPL: [%v]", []string{strconv.Itoa(param)})
|
||||||
|
h.clearWrap()
|
||||||
|
return h.moveCursorLine(-param)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *WindowsAnsiEventHandler) CHA(param int) error {
|
||||||
|
if err := h.Flush(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
logger.Infof("CHA: [%v]", []string{strconv.Itoa(param)})
|
||||||
|
h.clearWrap()
|
||||||
|
return h.moveCursorColumn(param)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *WindowsAnsiEventHandler) VPA(param int) error {
|
||||||
|
if err := h.Flush(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
logger.Infof("VPA: [[%d]]", param)
|
||||||
|
h.clearWrap()
|
||||||
|
info, err := GetConsoleScreenBufferInfo(h.fd)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
window := h.getCursorWindow(info)
|
||||||
|
position := info.CursorPosition
|
||||||
|
position.Y = window.Top + SHORT(param) - 1
|
||||||
|
return h.setCursorPosition(position, window)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *WindowsAnsiEventHandler) CUP(row int, col int) error {
|
||||||
|
if err := h.Flush(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
logger.Infof("CUP: [[%d %d]]", row, col)
|
||||||
|
h.clearWrap()
|
||||||
|
info, err := GetConsoleScreenBufferInfo(h.fd)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
window := h.getCursorWindow(info)
|
||||||
|
position := COORD{window.Left + SHORT(col) - 1, window.Top + SHORT(row) - 1}
|
||||||
|
return h.setCursorPosition(position, window)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *WindowsAnsiEventHandler) HVP(row int, col int) error {
|
||||||
|
if err := h.Flush(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
logger.Infof("HVP: [[%d %d]]", row, col)
|
||||||
|
h.clearWrap()
|
||||||
|
return h.CUP(row, col)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *WindowsAnsiEventHandler) DECTCEM(visible bool) error {
|
||||||
|
if err := h.Flush(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
logger.Infof("DECTCEM: [%v]", []string{strconv.FormatBool(visible)})
|
||||||
|
h.clearWrap()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *WindowsAnsiEventHandler) DECOM(enable bool) error {
|
||||||
|
if err := h.Flush(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
logger.Infof("DECOM: [%v]", []string{strconv.FormatBool(enable)})
|
||||||
|
h.clearWrap()
|
||||||
|
h.originMode = enable
|
||||||
|
return h.CUP(1, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *WindowsAnsiEventHandler) DECCOLM(use132 bool) error {
|
||||||
|
if err := h.Flush(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
logger.Infof("DECCOLM: [%v]", []string{strconv.FormatBool(use132)})
|
||||||
|
h.clearWrap()
|
||||||
|
if err := h.ED(2); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
info, err := GetConsoleScreenBufferInfo(h.fd)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
targetWidth := SHORT(80)
|
||||||
|
if use132 {
|
||||||
|
targetWidth = 132
|
||||||
|
}
|
||||||
|
if info.Size.X < targetWidth {
|
||||||
|
if err := SetConsoleScreenBufferSize(h.fd, COORD{targetWidth, info.Size.Y}); err != nil {
|
||||||
|
logger.Info("set buffer failed:", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
window := info.Window
|
||||||
|
window.Left = 0
|
||||||
|
window.Right = targetWidth - 1
|
||||||
|
if err := SetConsoleWindowInfo(h.fd, true, window); err != nil {
|
||||||
|
logger.Info("set window failed:", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if info.Size.X > targetWidth {
|
||||||
|
if err := SetConsoleScreenBufferSize(h.fd, COORD{targetWidth, info.Size.Y}); err != nil {
|
||||||
|
logger.Info("set buffer failed:", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return SetConsoleCursorPosition(h.fd, COORD{0, 0})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *WindowsAnsiEventHandler) ED(param int) error {
|
||||||
|
if err := h.Flush(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
logger.Infof("ED: [%v]", []string{strconv.Itoa(param)})
|
||||||
|
h.clearWrap()
|
||||||
|
|
||||||
|
// [J -- Erases from the cursor to the end of the screen, including the cursor position.
|
||||||
|
// [1J -- Erases from the beginning of the screen to the cursor, including the cursor position.
|
||||||
|
// [2J -- Erases the complete display. The cursor does not move.
|
||||||
|
// Notes:
|
||||||
|
// -- Clearing the entire buffer, versus just the Window, works best for Windows Consoles
|
||||||
|
|
||||||
|
info, err := GetConsoleScreenBufferInfo(h.fd)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
var start COORD
|
||||||
|
var end COORD
|
||||||
|
|
||||||
|
switch param {
|
||||||
|
case 0:
|
||||||
|
start = info.CursorPosition
|
||||||
|
end = COORD{info.Size.X - 1, info.Size.Y - 1}
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
start = COORD{0, 0}
|
||||||
|
end = info.CursorPosition
|
||||||
|
|
||||||
|
case 2:
|
||||||
|
start = COORD{0, 0}
|
||||||
|
end = COORD{info.Size.X - 1, info.Size.Y - 1}
|
||||||
|
}
|
||||||
|
|
||||||
|
err = h.clearRange(h.attributes, start, end)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the whole buffer was cleared, move the window to the top while preserving
|
||||||
|
// the window-relative cursor position.
|
||||||
|
if param == 2 {
|
||||||
|
pos := info.CursorPosition
|
||||||
|
window := info.Window
|
||||||
|
pos.Y -= window.Top
|
||||||
|
window.Bottom -= window.Top
|
||||||
|
window.Top = 0
|
||||||
|
if err := SetConsoleCursorPosition(h.fd, pos); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := SetConsoleWindowInfo(h.fd, true, window); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *WindowsAnsiEventHandler) EL(param int) error {
|
||||||
|
if err := h.Flush(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
logger.Infof("EL: [%v]", strconv.Itoa(param))
|
||||||
|
h.clearWrap()
|
||||||
|
|
||||||
|
// [K -- Erases from the cursor to the end of the line, including the cursor position.
|
||||||
|
// [1K -- Erases from the beginning of the line to the cursor, including the cursor position.
|
||||||
|
// [2K -- Erases the complete line.
|
||||||
|
|
||||||
|
info, err := GetConsoleScreenBufferInfo(h.fd)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
var start COORD
|
||||||
|
var end COORD
|
||||||
|
|
||||||
|
switch param {
|
||||||
|
case 0:
|
||||||
|
start = info.CursorPosition
|
||||||
|
end = COORD{info.Size.X, info.CursorPosition.Y}
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
start = COORD{0, info.CursorPosition.Y}
|
||||||
|
end = info.CursorPosition
|
||||||
|
|
||||||
|
case 2:
|
||||||
|
start = COORD{0, info.CursorPosition.Y}
|
||||||
|
end = COORD{info.Size.X, info.CursorPosition.Y}
|
||||||
|
}
|
||||||
|
|
||||||
|
err = h.clearRange(h.attributes, start, end)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *WindowsAnsiEventHandler) IL(param int) error {
|
||||||
|
if err := h.Flush(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
logger.Infof("IL: [%v]", strconv.Itoa(param))
|
||||||
|
h.clearWrap()
|
||||||
|
return h.insertLines(param)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *WindowsAnsiEventHandler) DL(param int) error {
|
||||||
|
if err := h.Flush(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
logger.Infof("DL: [%v]", strconv.Itoa(param))
|
||||||
|
h.clearWrap()
|
||||||
|
return h.deleteLines(param)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *WindowsAnsiEventHandler) ICH(param int) error {
|
||||||
|
if err := h.Flush(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
logger.Infof("ICH: [%v]", strconv.Itoa(param))
|
||||||
|
h.clearWrap()
|
||||||
|
return h.insertCharacters(param)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *WindowsAnsiEventHandler) DCH(param int) error {
|
||||||
|
if err := h.Flush(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
logger.Infof("DCH: [%v]", strconv.Itoa(param))
|
||||||
|
h.clearWrap()
|
||||||
|
return h.deleteCharacters(param)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *WindowsAnsiEventHandler) SGR(params []int) error {
|
||||||
|
if err := h.Flush(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
strings := []string{}
|
||||||
|
for _, v := range params {
|
||||||
|
strings = append(strings, strconv.Itoa(v))
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Infof("SGR: [%v]", strings)
|
||||||
|
|
||||||
|
if len(params) <= 0 {
|
||||||
|
h.attributes = h.infoReset.Attributes
|
||||||
|
h.inverted = false
|
||||||
|
} else {
|
||||||
|
for _, attr := range params {
|
||||||
|
|
||||||
|
if attr == ANSI_SGR_RESET {
|
||||||
|
h.attributes = h.infoReset.Attributes
|
||||||
|
h.inverted = false
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
h.attributes, h.inverted = collectAnsiIntoWindowsAttributes(h.attributes, h.inverted, h.infoReset.Attributes, SHORT(attr))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
attributes := h.attributes
|
||||||
|
if h.inverted {
|
||||||
|
attributes = invertAttributes(attributes)
|
||||||
|
}
|
||||||
|
err := SetConsoleTextAttribute(h.fd, attributes)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *WindowsAnsiEventHandler) SU(param int) error {
|
||||||
|
if err := h.Flush(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
logger.Infof("SU: [%v]", []string{strconv.Itoa(param)})
|
||||||
|
h.clearWrap()
|
||||||
|
return h.scrollUp(param)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *WindowsAnsiEventHandler) SD(param int) error {
|
||||||
|
if err := h.Flush(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
logger.Infof("SD: [%v]", []string{strconv.Itoa(param)})
|
||||||
|
h.clearWrap()
|
||||||
|
return h.scrollDown(param)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *WindowsAnsiEventHandler) DA(params []string) error {
|
||||||
|
logger.Infof("DA: [%v]", params)
|
||||||
|
// DA cannot be implemented because it must send data on the VT100 input stream,
|
||||||
|
// which is not available to go-ansiterm.
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *WindowsAnsiEventHandler) DECSTBM(top int, bottom int) error {
|
||||||
|
if err := h.Flush(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
logger.Infof("DECSTBM: [%d, %d]", top, bottom)
|
||||||
|
|
||||||
|
// Windows is 0 indexed, Linux is 1 indexed
|
||||||
|
h.sr.top = SHORT(top - 1)
|
||||||
|
h.sr.bottom = SHORT(bottom - 1)
|
||||||
|
|
||||||
|
// This command also moves the cursor to the origin.
|
||||||
|
h.clearWrap()
|
||||||
|
return h.CUP(1, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *WindowsAnsiEventHandler) RI() error {
|
||||||
|
if err := h.Flush(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
logger.Info("RI: []")
|
||||||
|
h.clearWrap()
|
||||||
|
|
||||||
|
info, err := GetConsoleScreenBufferInfo(h.fd)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
sr := h.effectiveSr(info.Window)
|
||||||
|
if info.CursorPosition.Y == sr.top {
|
||||||
|
return h.scrollDown(1)
|
||||||
|
} else {
|
||||||
|
return h.moveCursorVertical(-1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *WindowsAnsiEventHandler) IND() error {
|
||||||
|
logger.Info("IND: []")
|
||||||
|
return h.executeLF()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *WindowsAnsiEventHandler) Flush() error {
|
||||||
|
h.curInfo = nil
|
||||||
|
if h.buffer.Len() > 0 {
|
||||||
|
logger.Infof("Flush: [%s]", h.buffer.Bytes())
|
||||||
|
if _, err := h.buffer.WriteTo(h.file); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if h.wrapNext && !h.drewMarginByte {
|
||||||
|
logger.Infof("Flush: drawing margin byte '%c'", h.marginByte)
|
||||||
|
|
||||||
|
info, err := GetConsoleScreenBufferInfo(h.fd)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
charInfo := []CHAR_INFO{{UnicodeChar: WCHAR(h.marginByte), Attributes: info.Attributes}}
|
||||||
|
size := COORD{1, 1}
|
||||||
|
position := COORD{0, 0}
|
||||||
|
region := SMALL_RECT{Left: info.CursorPosition.X, Top: info.CursorPosition.Y, Right: info.CursorPosition.X, Bottom: info.CursorPosition.Y}
|
||||||
|
if err := WriteConsoleOutput(h.fd, charInfo, size, position, ®ion); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
h.drewMarginByte = true
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// cacheConsoleInfo ensures that the current console screen information has been queried
|
||||||
|
// since the last call to Flush(). It must be called before accessing h.curInfo or h.curPos.
|
||||||
|
func (h *WindowsAnsiEventHandler) getCurrentInfo() (COORD, *CONSOLE_SCREEN_BUFFER_INFO, error) {
|
||||||
|
if h.curInfo == nil {
|
||||||
|
info, err := GetConsoleScreenBufferInfo(h.fd)
|
||||||
|
if err != nil {
|
||||||
|
return COORD{}, nil, err
|
||||||
|
}
|
||||||
|
h.curInfo = info
|
||||||
|
h.curPos = info.CursorPosition
|
||||||
|
}
|
||||||
|
return h.curPos, h.curInfo, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *WindowsAnsiEventHandler) updatePos(pos COORD) {
|
||||||
|
if h.curInfo == nil {
|
||||||
|
panic("failed to call getCurrentInfo before calling updatePos")
|
||||||
|
}
|
||||||
|
h.curPos = pos
|
||||||
|
}
|
||||||
|
|
||||||
|
// clearWrap clears the state where the cursor is in the margin
|
||||||
|
// waiting for the next character before wrapping the line. This must
|
||||||
|
// be done before most operations that act on the cursor.
|
||||||
|
func (h *WindowsAnsiEventHandler) clearWrap() {
|
||||||
|
h.wrapNext = false
|
||||||
|
h.drewMarginByte = false
|
||||||
|
}
|
1
vendor/src/github.com/Sirupsen/logrus/.gitignore
vendored
Normal file
1
vendor/src/github.com/Sirupsen/logrus/.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
logrus
|
7
vendor/src/github.com/Sirupsen/logrus/.travis.yml
vendored
Normal file
7
vendor/src/github.com/Sirupsen/logrus/.travis.yml
vendored
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
language: go
|
||||||
|
go:
|
||||||
|
- 1.3
|
||||||
|
- 1.4
|
||||||
|
- tip
|
||||||
|
install:
|
||||||
|
- go get -t ./...
|
55
vendor/src/github.com/Sirupsen/logrus/CHANGELOG.md
vendored
Normal file
55
vendor/src/github.com/Sirupsen/logrus/CHANGELOG.md
vendored
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
# 0.9.0 (Unreleased)
|
||||||
|
|
||||||
|
* logrus/text_formatter: don't emit empty msg
|
||||||
|
* logrus/hooks/airbrake: move out of main repository
|
||||||
|
* logrus/hooks/sentry: move out of main repository
|
||||||
|
* logrus/hooks/papertrail: move out of main repository
|
||||||
|
* logrus/hooks/bugsnag: move out of main repository
|
||||||
|
|
||||||
|
# 0.8.7
|
||||||
|
|
||||||
|
* logrus/core: fix possible race (#216)
|
||||||
|
* logrus/doc: small typo fixes and doc improvements
|
||||||
|
|
||||||
|
|
||||||
|
# 0.8.6
|
||||||
|
|
||||||
|
* hooks/raven: allow passing an initialized client
|
||||||
|
|
||||||
|
# 0.8.5
|
||||||
|
|
||||||
|
* logrus/core: revert #208
|
||||||
|
|
||||||
|
# 0.8.4
|
||||||
|
|
||||||
|
* formatter/text: fix data race (#218)
|
||||||
|
|
||||||
|
# 0.8.3
|
||||||
|
|
||||||
|
* logrus/core: fix entry log level (#208)
|
||||||
|
* logrus/core: improve performance of text formatter by 40%
|
||||||
|
* logrus/core: expose `LevelHooks` type
|
||||||
|
* logrus/core: add support for DragonflyBSD and NetBSD
|
||||||
|
* formatter/text: print structs more verbosely
|
||||||
|
|
||||||
|
# 0.8.2
|
||||||
|
|
||||||
|
* logrus: fix more Fatal family functions
|
||||||
|
|
||||||
|
# 0.8.1
|
||||||
|
|
||||||
|
* logrus: fix not exiting on `Fatalf` and `Fatalln`
|
||||||
|
|
||||||
|
# 0.8.0
|
||||||
|
|
||||||
|
* logrus: defaults to stderr instead of stdout
|
||||||
|
* hooks/sentry: add special field for `*http.Request`
|
||||||
|
* formatter/text: ignore Windows for colors
|
||||||
|
|
||||||
|
# 0.7.3
|
||||||
|
|
||||||
|
* formatter/\*: allow configuration of timestamp layout
|
||||||
|
|
||||||
|
# 0.7.2
|
||||||
|
|
||||||
|
* formatter/text: Add configuration option for time format (#158)
|
21
vendor/src/github.com/Sirupsen/logrus/LICENSE
vendored
Normal file
21
vendor/src/github.com/Sirupsen/logrus/LICENSE
vendored
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright (c) 2014 Simon Eskildsen
|
||||||
|
|
||||||
|
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.
|
365
vendor/src/github.com/Sirupsen/logrus/README.md
vendored
Normal file
365
vendor/src/github.com/Sirupsen/logrus/README.md
vendored
Normal file
|
@ -0,0 +1,365 @@
|
||||||
|
# Logrus <img src="http://i.imgur.com/hTeVwmJ.png" width="40" height="40" alt=":walrus:" class="emoji" title=":walrus:"/> [![Build Status](https://travis-ci.org/Sirupsen/logrus.svg?branch=master)](https://travis-ci.org/Sirupsen/logrus) [![godoc reference](https://godoc.org/github.com/Sirupsen/logrus?status.png)][godoc]
|
||||||
|
|
||||||
|
Logrus is a structured logger for Go (golang), completely API compatible with
|
||||||
|
the standard library logger. [Godoc][godoc]. **Please note the Logrus API is not
|
||||||
|
yet stable (pre 1.0). Logrus itself is completely stable and has been used in
|
||||||
|
many large deployments. The core API is unlikely to change much but please
|
||||||
|
version control your Logrus to make sure you aren't fetching latest `master` on
|
||||||
|
every build.**
|
||||||
|
|
||||||
|
Nicely color-coded in development (when a TTY is attached, otherwise just
|
||||||
|
plain text):
|
||||||
|
|
||||||
|
![Colored](http://i.imgur.com/PY7qMwd.png)
|
||||||
|
|
||||||
|
With `log.Formatter = new(logrus.JSONFormatter)`, for easy parsing by logstash
|
||||||
|
or Splunk:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{"animal":"walrus","level":"info","msg":"A group of walrus emerges from the
|
||||||
|
ocean","size":10,"time":"2014-03-10 19:57:38.562264131 -0400 EDT"}
|
||||||
|
|
||||||
|
{"level":"warning","msg":"The group's number increased tremendously!",
|
||||||
|
"number":122,"omg":true,"time":"2014-03-10 19:57:38.562471297 -0400 EDT"}
|
||||||
|
|
||||||
|
{"animal":"walrus","level":"info","msg":"A giant walrus appears!",
|
||||||
|
"size":10,"time":"2014-03-10 19:57:38.562500591 -0400 EDT"}
|
||||||
|
|
||||||
|
{"animal":"walrus","level":"info","msg":"Tremendously sized cow enters the ocean.",
|
||||||
|
"size":9,"time":"2014-03-10 19:57:38.562527896 -0400 EDT"}
|
||||||
|
|
||||||
|
{"level":"fatal","msg":"The ice breaks!","number":100,"omg":true,
|
||||||
|
"time":"2014-03-10 19:57:38.562543128 -0400 EDT"}
|
||||||
|
```
|
||||||
|
|
||||||
|
With the default `log.Formatter = new(&log.TextFormatter{})` when a TTY is not
|
||||||
|
attached, the output is compatible with the
|
||||||
|
[logfmt](http://godoc.org/github.com/kr/logfmt) format:
|
||||||
|
|
||||||
|
```text
|
||||||
|
time="2015-03-26T01:27:38-04:00" level=debug msg="Started observing beach" animal=walrus number=8
|
||||||
|
time="2015-03-26T01:27:38-04:00" level=info msg="A group of walrus emerges from the ocean" animal=walrus size=10
|
||||||
|
time="2015-03-26T01:27:38-04:00" level=warning msg="The group's number increased tremendously!" number=122 omg=true
|
||||||
|
time="2015-03-26T01:27:38-04:00" level=debug msg="Temperature changes" temperature=-4
|
||||||
|
time="2015-03-26T01:27:38-04:00" level=panic msg="It's over 9000!" animal=orca size=9009
|
||||||
|
time="2015-03-26T01:27:38-04:00" level=fatal msg="The ice breaks!" err=&{0x2082280c0 map[animal:orca size:9009] 2015-03-26 01:27:38.441574009 -0400 EDT panic It's over 9000!} number=100 omg=true
|
||||||
|
exit status 1
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Example
|
||||||
|
|
||||||
|
The simplest way to use Logrus is simply the package-level exported logger:
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
log "github.com/Sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
log.WithFields(log.Fields{
|
||||||
|
"animal": "walrus",
|
||||||
|
}).Info("A walrus appears")
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Note that it's completely api-compatible with the stdlib logger, so you can
|
||||||
|
replace your `log` imports everywhere with `log "github.com/Sirupsen/logrus"`
|
||||||
|
and you'll now have the flexibility of Logrus. You can customize it all you
|
||||||
|
want:
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
log "github.com/Sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
// Log as JSON instead of the default ASCII formatter.
|
||||||
|
log.SetFormatter(&log.JSONFormatter{})
|
||||||
|
|
||||||
|
// Output to stderr instead of stdout, could also be a file.
|
||||||
|
log.SetOutput(os.Stderr)
|
||||||
|
|
||||||
|
// Only log the warning severity or above.
|
||||||
|
log.SetLevel(log.WarnLevel)
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
log.WithFields(log.Fields{
|
||||||
|
"animal": "walrus",
|
||||||
|
"size": 10,
|
||||||
|
}).Info("A group of walrus emerges from the ocean")
|
||||||
|
|
||||||
|
log.WithFields(log.Fields{
|
||||||
|
"omg": true,
|
||||||
|
"number": 122,
|
||||||
|
}).Warn("The group's number increased tremendously!")
|
||||||
|
|
||||||
|
log.WithFields(log.Fields{
|
||||||
|
"omg": true,
|
||||||
|
"number": 100,
|
||||||
|
}).Fatal("The ice breaks!")
|
||||||
|
|
||||||
|
// A common pattern is to re-use fields between logging statements by re-using
|
||||||
|
// the logrus.Entry returned from WithFields()
|
||||||
|
contextLogger := log.WithFields(log.Fields{
|
||||||
|
"common": "this is a common field",
|
||||||
|
"other": "I also should be logged always",
|
||||||
|
})
|
||||||
|
|
||||||
|
contextLogger.Info("I'll be logged with common and other field")
|
||||||
|
contextLogger.Info("Me too")
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
For more advanced usage such as logging to multiple locations from the same
|
||||||
|
application, you can also create an instance of the `logrus` Logger:
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/Sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Create a new instance of the logger. You can have any number of instances.
|
||||||
|
var log = logrus.New()
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
// The API for setting attributes is a little different than the package level
|
||||||
|
// exported logger. See Godoc.
|
||||||
|
log.Out = os.Stderr
|
||||||
|
|
||||||
|
log.WithFields(logrus.Fields{
|
||||||
|
"animal": "walrus",
|
||||||
|
"size": 10,
|
||||||
|
}).Info("A group of walrus emerges from the ocean")
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Fields
|
||||||
|
|
||||||
|
Logrus encourages careful, structured logging though logging fields instead of
|
||||||
|
long, unparseable error messages. For example, instead of: `log.Fatalf("Failed
|
||||||
|
to send event %s to topic %s with key %d")`, you should log the much more
|
||||||
|
discoverable:
|
||||||
|
|
||||||
|
```go
|
||||||
|
log.WithFields(log.Fields{
|
||||||
|
"event": event,
|
||||||
|
"topic": topic,
|
||||||
|
"key": key,
|
||||||
|
}).Fatal("Failed to send event")
|
||||||
|
```
|
||||||
|
|
||||||
|
We've found this API forces you to think about logging in a way that produces
|
||||||
|
much more useful logging messages. We've been in countless situations where just
|
||||||
|
a single added field to a log statement that was already there would've saved us
|
||||||
|
hours. The `WithFields` call is optional.
|
||||||
|
|
||||||
|
In general, with Logrus using any of the `printf`-family functions should be
|
||||||
|
seen as a hint you should add a field, however, you can still use the
|
||||||
|
`printf`-family functions with Logrus.
|
||||||
|
|
||||||
|
#### Hooks
|
||||||
|
|
||||||
|
You can add hooks for logging levels. For example to send errors to an exception
|
||||||
|
tracking service on `Error`, `Fatal` and `Panic`, info to StatsD or log to
|
||||||
|
multiple places simultaneously, e.g. syslog.
|
||||||
|
|
||||||
|
Logrus comes with [built-in hooks](hooks/). Add those, or your custom hook, in
|
||||||
|
`init`:
|
||||||
|
|
||||||
|
```go
|
||||||
|
import (
|
||||||
|
log "github.com/Sirupsen/logrus"
|
||||||
|
"gopkg.in/gemnasium/logrus-airbrake-hook.v2" // the package is named "aibrake"
|
||||||
|
logrus_syslog "github.com/Sirupsen/logrus/hooks/syslog"
|
||||||
|
"log/syslog"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
|
||||||
|
// Use the Airbrake hook to report errors that have Error severity or above to
|
||||||
|
// an exception tracker. You can create custom hooks, see the Hooks section.
|
||||||
|
log.AddHook(airbrake.NewHook(123, "xyz", "production"))
|
||||||
|
|
||||||
|
hook, err := logrus_syslog.NewSyslogHook("udp", "localhost:514", syslog.LOG_INFO, "")
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Unable to connect to local syslog daemon")
|
||||||
|
} else {
|
||||||
|
log.AddHook(hook)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
Note: Syslog hook also support connecting to local syslog (Ex. "/dev/log" or "/var/run/syslog" or "/var/run/log"). For the detail, please check the [syslog hook README](hooks/syslog/README.md).
|
||||||
|
|
||||||
|
| Hook | Description |
|
||||||
|
| ----- | ----------- |
|
||||||
|
| [Airbrake](https://github.com/gemnasium/logrus-airbrake-hook) | Send errors to the Airbrake API V3. Uses the official [`gobrake`](https://github.com/airbrake/gobrake) behind the scenes. |
|
||||||
|
| [Airbrake "legacy"](https://github.com/gemnasium/logrus-airbrake-legacy-hook) | Send errors to an exception tracking service compatible with the Airbrake API V2. Uses [`airbrake-go`](https://github.com/tobi/airbrake-go) behind the scenes. |
|
||||||
|
| [Papertrail](https://github.com/polds/logrus-papertrail-hook) | Send errors to the [Papertrail](https://papertrailapp.com) hosted logging service via UDP. |
|
||||||
|
| [Syslog](https://github.com/Sirupsen/logrus/blob/master/hooks/syslog/syslog.go) | Send errors to remote syslog server. Uses standard library `log/syslog` behind the scenes. |
|
||||||
|
| [Bugsnag](https://github.com/Shopify/logrus-bugsnag/blob/master/bugsnag.go) | Send errors to the Bugsnag exception tracking service. |
|
||||||
|
| [Sentry](https://github.com/evalphobia/logrus_sentry) | Send errors to the Sentry error logging and aggregation service. |
|
||||||
|
| [Hiprus](https://github.com/nubo/hiprus) | Send errors to a channel in hipchat. |
|
||||||
|
| [Logrusly](https://github.com/sebest/logrusly) | Send logs to [Loggly](https://www.loggly.com/) |
|
||||||
|
| [Slackrus](https://github.com/johntdyer/slackrus) | Hook for Slack chat. |
|
||||||
|
| [Journalhook](https://github.com/wercker/journalhook) | Hook for logging to `systemd-journald` |
|
||||||
|
| [Graylog](https://github.com/gemnasium/logrus-graylog-hook) | Hook for logging to [Graylog](http://graylog2.org/) |
|
||||||
|
| [Raygun](https://github.com/squirkle/logrus-raygun-hook) | Hook for logging to [Raygun.io](http://raygun.io/) |
|
||||||
|
| [LFShook](https://github.com/rifflock/lfshook) | Hook for logging to the local filesystem |
|
||||||
|
| [Honeybadger](https://github.com/agonzalezro/logrus_honeybadger) | Hook for sending exceptions to Honeybadger |
|
||||||
|
| [Mail](https://github.com/zbindenren/logrus_mail) | Hook for sending exceptions via mail |
|
||||||
|
| [Rollrus](https://github.com/heroku/rollrus) | Hook for sending errors to rollbar |
|
||||||
|
| [Fluentd](https://github.com/evalphobia/logrus_fluent) | Hook for logging to fluentd |
|
||||||
|
| [Mongodb](https://github.com/weekface/mgorus) | Hook for logging to mongodb |
|
||||||
|
| [InfluxDB](https://github.com/Abramovic/logrus_influxdb) | Hook for logging to influxdb |
|
||||||
|
| [Octokit](https://github.com/dorajistyle/logrus-octokit-hook) | Hook for logging to github via octokit |
|
||||||
|
| [DeferPanic](https://github.com/deferpanic/dp-logrus) | Hook for logging to DeferPanic |
|
||||||
|
|
||||||
|
#### Level logging
|
||||||
|
|
||||||
|
Logrus has six logging levels: Debug, Info, Warning, Error, Fatal and Panic.
|
||||||
|
|
||||||
|
```go
|
||||||
|
log.Debug("Useful debugging information.")
|
||||||
|
log.Info("Something noteworthy happened!")
|
||||||
|
log.Warn("You should probably take a look at this.")
|
||||||
|
log.Error("Something failed but I'm not quitting.")
|
||||||
|
// Calls os.Exit(1) after logging
|
||||||
|
log.Fatal("Bye.")
|
||||||
|
// Calls panic() after logging
|
||||||
|
log.Panic("I'm bailing.")
|
||||||
|
```
|
||||||
|
|
||||||
|
You can set the logging level on a `Logger`, then it will only log entries with
|
||||||
|
that severity or anything above it:
|
||||||
|
|
||||||
|
```go
|
||||||
|
// Will log anything that is info or above (warn, error, fatal, panic). Default.
|
||||||
|
log.SetLevel(log.InfoLevel)
|
||||||
|
```
|
||||||
|
|
||||||
|
It may be useful to set `log.Level = logrus.DebugLevel` in a debug or verbose
|
||||||
|
environment if your application has that.
|
||||||
|
|
||||||
|
#### Entries
|
||||||
|
|
||||||
|
Besides the fields added with `WithField` or `WithFields` some fields are
|
||||||
|
automatically added to all logging events:
|
||||||
|
|
||||||
|
1. `time`. The timestamp when the entry was created.
|
||||||
|
2. `msg`. The logging message passed to `{Info,Warn,Error,Fatal,Panic}` after
|
||||||
|
the `AddFields` call. E.g. `Failed to send event.`
|
||||||
|
3. `level`. The logging level. E.g. `info`.
|
||||||
|
|
||||||
|
#### Environments
|
||||||
|
|
||||||
|
Logrus has no notion of environment.
|
||||||
|
|
||||||
|
If you wish for hooks and formatters to only be used in specific environments,
|
||||||
|
you should handle that yourself. For example, if your application has a global
|
||||||
|
variable `Environment`, which is a string representation of the environment you
|
||||||
|
could do:
|
||||||
|
|
||||||
|
```go
|
||||||
|
import (
|
||||||
|
log "github.com/Sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
init() {
|
||||||
|
// do something here to set environment depending on an environment variable
|
||||||
|
// or command-line flag
|
||||||
|
if Environment == "production" {
|
||||||
|
log.SetFormatter(&log.JSONFormatter{})
|
||||||
|
} else {
|
||||||
|
// The TextFormatter is default, you don't actually have to do this.
|
||||||
|
log.SetFormatter(&log.TextFormatter{})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
This configuration is how `logrus` was intended to be used, but JSON in
|
||||||
|
production is mostly only useful if you do log aggregation with tools like
|
||||||
|
Splunk or Logstash.
|
||||||
|
|
||||||
|
#### Formatters
|
||||||
|
|
||||||
|
The built-in logging formatters are:
|
||||||
|
|
||||||
|
* `logrus.TextFormatter`. Logs the event in colors if stdout is a tty, otherwise
|
||||||
|
without colors.
|
||||||
|
* *Note:* to force colored output when there is no TTY, set the `ForceColors`
|
||||||
|
field to `true`. To force no colored output even if there is a TTY set the
|
||||||
|
`DisableColors` field to `true`
|
||||||
|
* `logrus.JSONFormatter`. Logs fields as JSON.
|
||||||
|
* `logrus/formatters/logstash.LogstashFormatter`. Logs fields as [Logstash](http://logstash.net) Events.
|
||||||
|
|
||||||
|
```go
|
||||||
|
logrus.SetFormatter(&logstash.LogstashFormatter{Type: "application_name"})
|
||||||
|
```
|
||||||
|
|
||||||
|
Third party logging formatters:
|
||||||
|
|
||||||
|
* [`prefixed`](https://github.com/x-cray/logrus-prefixed-formatter). Displays log entry source along with alternative layout.
|
||||||
|
* [`zalgo`](https://github.com/aybabtme/logzalgo). Invoking the P͉̫o̳̼̊w̖͈̰͎e̬͔̭͂r͚̼̹̲ ̫͓͉̳͈ō̠͕͖̚f̝͍̠ ͕̲̞͖͑Z̖̫̤̫ͪa͉̬͈̗l͖͎g̳̥o̰̥̅!̣͔̲̻͊̄ ̙̘̦̹̦.
|
||||||
|
|
||||||
|
You can define your formatter by implementing the `Formatter` interface,
|
||||||
|
requiring a `Format` method. `Format` takes an `*Entry`. `entry.Data` is a
|
||||||
|
`Fields` type (`map[string]interface{}`) with all your fields as well as the
|
||||||
|
default ones (see Entries section above):
|
||||||
|
|
||||||
|
```go
|
||||||
|
type MyJSONFormatter struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
log.SetFormatter(new(MyJSONFormatter))
|
||||||
|
|
||||||
|
func (f *MyJSONFormatter) Format(entry *Entry) ([]byte, error) {
|
||||||
|
// Note this doesn't include Time, Level and Message which are available on
|
||||||
|
// the Entry. Consult `godoc` on information about those fields or read the
|
||||||
|
// source of the official loggers.
|
||||||
|
serialized, err := json.Marshal(entry.Data)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("Failed to marshal fields to JSON, %v", err)
|
||||||
|
}
|
||||||
|
return append(serialized, '\n'), nil
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Logger as an `io.Writer`
|
||||||
|
|
||||||
|
Logrus can be transformed into an `io.Writer`. That writer is the end of an `io.Pipe` and it is your responsibility to close it.
|
||||||
|
|
||||||
|
```go
|
||||||
|
w := logger.Writer()
|
||||||
|
defer w.Close()
|
||||||
|
|
||||||
|
srv := http.Server{
|
||||||
|
// create a stdlib log.Logger that writes to
|
||||||
|
// logrus.Logger.
|
||||||
|
ErrorLog: log.New(w, "", 0),
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Each line written to that writer will be printed the usual way, using formatters
|
||||||
|
and hooks. The level for those entries is `info`.
|
||||||
|
|
||||||
|
#### Rotation
|
||||||
|
|
||||||
|
Log rotation is not provided with Logrus. Log rotation should be done by an
|
||||||
|
external program (like `logrotate(8)`) that can compress and delete old log
|
||||||
|
entries. It should not be a feature of the application-level logger.
|
||||||
|
|
||||||
|
#### Tools
|
||||||
|
|
||||||
|
| Tool | Description |
|
||||||
|
| ---- | ----------- |
|
||||||
|
|[Logrus Mate](https://github.com/gogap/logrus_mate)|Logrus mate is a tool for Logrus to manage loggers, you can initial logger's level, hook and formatter by config file, the logger will generated with different config at different environment.|
|
||||||
|
|
||||||
|
[godoc]: https://godoc.org/github.com/Sirupsen/logrus
|
26
vendor/src/github.com/Sirupsen/logrus/doc.go
vendored
Normal file
26
vendor/src/github.com/Sirupsen/logrus/doc.go
vendored
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
/*
|
||||||
|
Package logrus is a structured logger for Go, completely API compatible with the standard library logger.
|
||||||
|
|
||||||
|
|
||||||
|
The simplest way to use Logrus is simply the package-level exported logger:
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
log "github.com/Sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
log.WithFields(log.Fields{
|
||||||
|
"animal": "walrus",
|
||||||
|
"number": 1,
|
||||||
|
"size": 10,
|
||||||
|
}).Info("A walrus appears")
|
||||||
|
}
|
||||||
|
|
||||||
|
Output:
|
||||||
|
time="2015-09-07T08:48:33Z" level=info msg="A walrus appears" animal=walrus number=1 size=10
|
||||||
|
|
||||||
|
For a full guide visit https://github.com/Sirupsen/logrus
|
||||||
|
*/
|
||||||
|
package logrus
|
264
vendor/src/github.com/Sirupsen/logrus/entry.go
vendored
Normal file
264
vendor/src/github.com/Sirupsen/logrus/entry.go
vendored
Normal file
|
@ -0,0 +1,264 @@
|
||||||
|
package logrus
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Defines the key when adding errors using WithError.
|
||||||
|
var ErrorKey = "error"
|
||||||
|
|
||||||
|
// An entry is the final or intermediate Logrus logging entry. It contains all
|
||||||
|
// the fields passed with WithField{,s}. It's finally logged when Debug, Info,
|
||||||
|
// Warn, Error, Fatal or Panic is called on it. These objects can be reused and
|
||||||
|
// passed around as much as you wish to avoid field duplication.
|
||||||
|
type Entry struct {
|
||||||
|
Logger *Logger
|
||||||
|
|
||||||
|
// Contains all the fields set by the user.
|
||||||
|
Data Fields
|
||||||
|
|
||||||
|
// Time at which the log entry was created
|
||||||
|
Time time.Time
|
||||||
|
|
||||||
|
// Level the log entry was logged at: Debug, Info, Warn, Error, Fatal or Panic
|
||||||
|
Level Level
|
||||||
|
|
||||||
|
// Message passed to Debug, Info, Warn, Error, Fatal or Panic
|
||||||
|
Message string
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewEntry(logger *Logger) *Entry {
|
||||||
|
return &Entry{
|
||||||
|
Logger: logger,
|
||||||
|
// Default is three fields, give a little extra room
|
||||||
|
Data: make(Fields, 5),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns a reader for the entry, which is a proxy to the formatter.
|
||||||
|
func (entry *Entry) Reader() (*bytes.Buffer, error) {
|
||||||
|
serialized, err := entry.Logger.Formatter.Format(entry)
|
||||||
|
return bytes.NewBuffer(serialized), err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns the string representation from the reader and ultimately the
|
||||||
|
// formatter.
|
||||||
|
func (entry *Entry) String() (string, error) {
|
||||||
|
reader, err := entry.Reader()
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
return reader.String(), err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add an error as single field (using the key defined in ErrorKey) to the Entry.
|
||||||
|
func (entry *Entry) WithError(err error) *Entry {
|
||||||
|
return entry.WithField(ErrorKey, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add a single field to the Entry.
|
||||||
|
func (entry *Entry) WithField(key string, value interface{}) *Entry {
|
||||||
|
return entry.WithFields(Fields{key: value})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add a map of fields to the Entry.
|
||||||
|
func (entry *Entry) WithFields(fields Fields) *Entry {
|
||||||
|
data := Fields{}
|
||||||
|
for k, v := range entry.Data {
|
||||||
|
data[k] = v
|
||||||
|
}
|
||||||
|
for k, v := range fields {
|
||||||
|
data[k] = v
|
||||||
|
}
|
||||||
|
return &Entry{Logger: entry.Logger, Data: data}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This function is not declared with a pointer value because otherwise
|
||||||
|
// race conditions will occur when using multiple goroutines
|
||||||
|
func (entry Entry) log(level Level, msg string) {
|
||||||
|
entry.Time = time.Now()
|
||||||
|
entry.Level = level
|
||||||
|
entry.Message = msg
|
||||||
|
|
||||||
|
if err := entry.Logger.Hooks.Fire(level, &entry); err != nil {
|
||||||
|
entry.Logger.mu.Lock()
|
||||||
|
fmt.Fprintf(os.Stderr, "Failed to fire hook: %v\n", err)
|
||||||
|
entry.Logger.mu.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
reader, err := entry.Reader()
|
||||||
|
if err != nil {
|
||||||
|
entry.Logger.mu.Lock()
|
||||||
|
fmt.Fprintf(os.Stderr, "Failed to obtain reader, %v\n", err)
|
||||||
|
entry.Logger.mu.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
entry.Logger.mu.Lock()
|
||||||
|
defer entry.Logger.mu.Unlock()
|
||||||
|
|
||||||
|
_, err = io.Copy(entry.Logger.Out, reader)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "Failed to write to log, %v\n", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// To avoid Entry#log() returning a value that only would make sense for
|
||||||
|
// panic() to use in Entry#Panic(), we avoid the allocation by checking
|
||||||
|
// directly here.
|
||||||
|
if level <= PanicLevel {
|
||||||
|
panic(&entry)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (entry *Entry) Debug(args ...interface{}) {
|
||||||
|
if entry.Logger.Level >= DebugLevel {
|
||||||
|
entry.log(DebugLevel, fmt.Sprint(args...))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (entry *Entry) Print(args ...interface{}) {
|
||||||
|
entry.Info(args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (entry *Entry) Info(args ...interface{}) {
|
||||||
|
if entry.Logger.Level >= InfoLevel {
|
||||||
|
entry.log(InfoLevel, fmt.Sprint(args...))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (entry *Entry) Warn(args ...interface{}) {
|
||||||
|
if entry.Logger.Level >= WarnLevel {
|
||||||
|
entry.log(WarnLevel, fmt.Sprint(args...))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (entry *Entry) Warning(args ...interface{}) {
|
||||||
|
entry.Warn(args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (entry *Entry) Error(args ...interface{}) {
|
||||||
|
if entry.Logger.Level >= ErrorLevel {
|
||||||
|
entry.log(ErrorLevel, fmt.Sprint(args...))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (entry *Entry) Fatal(args ...interface{}) {
|
||||||
|
if entry.Logger.Level >= FatalLevel {
|
||||||
|
entry.log(FatalLevel, fmt.Sprint(args...))
|
||||||
|
}
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (entry *Entry) Panic(args ...interface{}) {
|
||||||
|
if entry.Logger.Level >= PanicLevel {
|
||||||
|
entry.log(PanicLevel, fmt.Sprint(args...))
|
||||||
|
}
|
||||||
|
panic(fmt.Sprint(args...))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Entry Printf family functions
|
||||||
|
|
||||||
|
func (entry *Entry) Debugf(format string, args ...interface{}) {
|
||||||
|
if entry.Logger.Level >= DebugLevel {
|
||||||
|
entry.Debug(fmt.Sprintf(format, args...))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (entry *Entry) Infof(format string, args ...interface{}) {
|
||||||
|
if entry.Logger.Level >= InfoLevel {
|
||||||
|
entry.Info(fmt.Sprintf(format, args...))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (entry *Entry) Printf(format string, args ...interface{}) {
|
||||||
|
entry.Infof(format, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (entry *Entry) Warnf(format string, args ...interface{}) {
|
||||||
|
if entry.Logger.Level >= WarnLevel {
|
||||||
|
entry.Warn(fmt.Sprintf(format, args...))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (entry *Entry) Warningf(format string, args ...interface{}) {
|
||||||
|
entry.Warnf(format, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (entry *Entry) Errorf(format string, args ...interface{}) {
|
||||||
|
if entry.Logger.Level >= ErrorLevel {
|
||||||
|
entry.Error(fmt.Sprintf(format, args...))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (entry *Entry) Fatalf(format string, args ...interface{}) {
|
||||||
|
if entry.Logger.Level >= FatalLevel {
|
||||||
|
entry.Fatal(fmt.Sprintf(format, args...))
|
||||||
|
}
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (entry *Entry) Panicf(format string, args ...interface{}) {
|
||||||
|
if entry.Logger.Level >= PanicLevel {
|
||||||
|
entry.Panic(fmt.Sprintf(format, args...))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Entry Println family functions
|
||||||
|
|
||||||
|
func (entry *Entry) Debugln(args ...interface{}) {
|
||||||
|
if entry.Logger.Level >= DebugLevel {
|
||||||
|
entry.Debug(entry.sprintlnn(args...))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (entry *Entry) Infoln(args ...interface{}) {
|
||||||
|
if entry.Logger.Level >= InfoLevel {
|
||||||
|
entry.Info(entry.sprintlnn(args...))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (entry *Entry) Println(args ...interface{}) {
|
||||||
|
entry.Infoln(args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (entry *Entry) Warnln(args ...interface{}) {
|
||||||
|
if entry.Logger.Level >= WarnLevel {
|
||||||
|
entry.Warn(entry.sprintlnn(args...))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (entry *Entry) Warningln(args ...interface{}) {
|
||||||
|
entry.Warnln(args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (entry *Entry) Errorln(args ...interface{}) {
|
||||||
|
if entry.Logger.Level >= ErrorLevel {
|
||||||
|
entry.Error(entry.sprintlnn(args...))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (entry *Entry) Fatalln(args ...interface{}) {
|
||||||
|
if entry.Logger.Level >= FatalLevel {
|
||||||
|
entry.Fatal(entry.sprintlnn(args...))
|
||||||
|
}
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (entry *Entry) Panicln(args ...interface{}) {
|
||||||
|
if entry.Logger.Level >= PanicLevel {
|
||||||
|
entry.Panic(entry.sprintlnn(args...))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sprintlnn => Sprint no newline. This is to get the behavior of how
|
||||||
|
// fmt.Sprintln where spaces are always added between operands, regardless of
|
||||||
|
// their type. Instead of vendoring the Sprintln implementation to spare a
|
||||||
|
// string allocation, we do the simplest thing.
|
||||||
|
func (entry *Entry) sprintlnn(args ...interface{}) string {
|
||||||
|
msg := fmt.Sprintln(args...)
|
||||||
|
return msg[:len(msg)-1]
|
||||||
|
}
|
193
vendor/src/github.com/Sirupsen/logrus/exported.go
vendored
Normal file
193
vendor/src/github.com/Sirupsen/logrus/exported.go
vendored
Normal file
|
@ -0,0 +1,193 @@
|
||||||
|
package logrus
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// std is the name of the standard logger in stdlib `log`
|
||||||
|
std = New()
|
||||||
|
)
|
||||||
|
|
||||||
|
func StandardLogger() *Logger {
|
||||||
|
return std
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetOutput sets the standard logger output.
|
||||||
|
func SetOutput(out io.Writer) {
|
||||||
|
std.mu.Lock()
|
||||||
|
defer std.mu.Unlock()
|
||||||
|
std.Out = out
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetFormatter sets the standard logger formatter.
|
||||||
|
func SetFormatter(formatter Formatter) {
|
||||||
|
std.mu.Lock()
|
||||||
|
defer std.mu.Unlock()
|
||||||
|
std.Formatter = formatter
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetLevel sets the standard logger level.
|
||||||
|
func SetLevel(level Level) {
|
||||||
|
std.mu.Lock()
|
||||||
|
defer std.mu.Unlock()
|
||||||
|
std.Level = level
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetLevel returns the standard logger level.
|
||||||
|
func GetLevel() Level {
|
||||||
|
std.mu.Lock()
|
||||||
|
defer std.mu.Unlock()
|
||||||
|
return std.Level
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddHook adds a hook to the standard logger hooks.
|
||||||
|
func AddHook(hook Hook) {
|
||||||
|
std.mu.Lock()
|
||||||
|
defer std.mu.Unlock()
|
||||||
|
std.Hooks.Add(hook)
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithError creates an entry from the standard logger and adds an error to it, using the value defined in ErrorKey as key.
|
||||||
|
func WithError(err error) *Entry {
|
||||||
|
return std.WithField(ErrorKey, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithField creates an entry from the standard logger and adds a field to
|
||||||
|
// it. If you want multiple fields, use `WithFields`.
|
||||||
|
//
|
||||||
|
// Note that it doesn't log until you call Debug, Print, Info, Warn, Fatal
|
||||||
|
// or Panic on the Entry it returns.
|
||||||
|
func WithField(key string, value interface{}) *Entry {
|
||||||
|
return std.WithField(key, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithFields creates an entry from the standard logger and adds multiple
|
||||||
|
// fields to it. This is simply a helper for `WithField`, invoking it
|
||||||
|
// once for each field.
|
||||||
|
//
|
||||||
|
// Note that it doesn't log until you call Debug, Print, Info, Warn, Fatal
|
||||||
|
// or Panic on the Entry it returns.
|
||||||
|
func WithFields(fields Fields) *Entry {
|
||||||
|
return std.WithFields(fields)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Debug logs a message at level Debug on the standard logger.
|
||||||
|
func Debug(args ...interface{}) {
|
||||||
|
std.Debug(args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Print logs a message at level Info on the standard logger.
|
||||||
|
func Print(args ...interface{}) {
|
||||||
|
std.Print(args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Info logs a message at level Info on the standard logger.
|
||||||
|
func Info(args ...interface{}) {
|
||||||
|
std.Info(args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Warn logs a message at level Warn on the standard logger.
|
||||||
|
func Warn(args ...interface{}) {
|
||||||
|
std.Warn(args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Warning logs a message at level Warn on the standard logger.
|
||||||
|
func Warning(args ...interface{}) {
|
||||||
|
std.Warning(args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Error logs a message at level Error on the standard logger.
|
||||||
|
func Error(args ...interface{}) {
|
||||||
|
std.Error(args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Panic logs a message at level Panic on the standard logger.
|
||||||
|
func Panic(args ...interface{}) {
|
||||||
|
std.Panic(args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fatal logs a message at level Fatal on the standard logger.
|
||||||
|
func Fatal(args ...interface{}) {
|
||||||
|
std.Fatal(args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Debugf logs a message at level Debug on the standard logger.
|
||||||
|
func Debugf(format string, args ...interface{}) {
|
||||||
|
std.Debugf(format, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Printf logs a message at level Info on the standard logger.
|
||||||
|
func Printf(format string, args ...interface{}) {
|
||||||
|
std.Printf(format, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Infof logs a message at level Info on the standard logger.
|
||||||
|
func Infof(format string, args ...interface{}) {
|
||||||
|
std.Infof(format, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Warnf logs a message at level Warn on the standard logger.
|
||||||
|
func Warnf(format string, args ...interface{}) {
|
||||||
|
std.Warnf(format, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Warningf logs a message at level Warn on the standard logger.
|
||||||
|
func Warningf(format string, args ...interface{}) {
|
||||||
|
std.Warningf(format, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Errorf logs a message at level Error on the standard logger.
|
||||||
|
func Errorf(format string, args ...interface{}) {
|
||||||
|
std.Errorf(format, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Panicf logs a message at level Panic on the standard logger.
|
||||||
|
func Panicf(format string, args ...interface{}) {
|
||||||
|
std.Panicf(format, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fatalf logs a message at level Fatal on the standard logger.
|
||||||
|
func Fatalf(format string, args ...interface{}) {
|
||||||
|
std.Fatalf(format, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Debugln logs a message at level Debug on the standard logger.
|
||||||
|
func Debugln(args ...interface{}) {
|
||||||
|
std.Debugln(args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Println logs a message at level Info on the standard logger.
|
||||||
|
func Println(args ...interface{}) {
|
||||||
|
std.Println(args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Infoln logs a message at level Info on the standard logger.
|
||||||
|
func Infoln(args ...interface{}) {
|
||||||
|
std.Infoln(args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Warnln logs a message at level Warn on the standard logger.
|
||||||
|
func Warnln(args ...interface{}) {
|
||||||
|
std.Warnln(args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Warningln logs a message at level Warn on the standard logger.
|
||||||
|
func Warningln(args ...interface{}) {
|
||||||
|
std.Warningln(args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Errorln logs a message at level Error on the standard logger.
|
||||||
|
func Errorln(args ...interface{}) {
|
||||||
|
std.Errorln(args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Panicln logs a message at level Panic on the standard logger.
|
||||||
|
func Panicln(args ...interface{}) {
|
||||||
|
std.Panicln(args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fatalln logs a message at level Fatal on the standard logger.
|
||||||
|
func Fatalln(args ...interface{}) {
|
||||||
|
std.Fatalln(args...)
|
||||||
|
}
|
48
vendor/src/github.com/Sirupsen/logrus/formatter.go
vendored
Normal file
48
vendor/src/github.com/Sirupsen/logrus/formatter.go
vendored
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
package logrus
|
||||||
|
|
||||||
|
import "time"
|
||||||
|
|
||||||
|
const DefaultTimestampFormat = time.RFC3339
|
||||||
|
|
||||||
|
// The Formatter interface is used to implement a custom Formatter. It takes an
|
||||||
|
// `Entry`. It exposes all the fields, including the default ones:
|
||||||
|
//
|
||||||
|
// * `entry.Data["msg"]`. The message passed from Info, Warn, Error ..
|
||||||
|
// * `entry.Data["time"]`. The timestamp.
|
||||||
|
// * `entry.Data["level"]. The level the entry was logged at.
|
||||||
|
//
|
||||||
|
// Any additional fields added with `WithField` or `WithFields` are also in
|
||||||
|
// `entry.Data`. Format is expected to return an array of bytes which are then
|
||||||
|
// logged to `logger.Out`.
|
||||||
|
type Formatter interface {
|
||||||
|
Format(*Entry) ([]byte, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is to not silently overwrite `time`, `msg` and `level` fields when
|
||||||
|
// dumping it. If this code wasn't there doing:
|
||||||
|
//
|
||||||
|
// logrus.WithField("level", 1).Info("hello")
|
||||||
|
//
|
||||||
|
// Would just silently drop the user provided level. Instead with this code
|
||||||
|
// it'll logged as:
|
||||||
|
//
|
||||||
|
// {"level": "info", "fields.level": 1, "msg": "hello", "time": "..."}
|
||||||
|
//
|
||||||
|
// It's not exported because it's still using Data in an opinionated way. It's to
|
||||||
|
// avoid code duplication between the two default formatters.
|
||||||
|
func prefixFieldClashes(data Fields) {
|
||||||
|
_, ok := data["time"]
|
||||||
|
if ok {
|
||||||
|
data["fields.time"] = data["time"]
|
||||||
|
}
|
||||||
|
|
||||||
|
_, ok = data["msg"]
|
||||||
|
if ok {
|
||||||
|
data["fields.msg"] = data["msg"]
|
||||||
|
}
|
||||||
|
|
||||||
|
_, ok = data["level"]
|
||||||
|
if ok {
|
||||||
|
data["fields.level"] = data["level"]
|
||||||
|
}
|
||||||
|
}
|
34
vendor/src/github.com/Sirupsen/logrus/hooks.go
vendored
Normal file
34
vendor/src/github.com/Sirupsen/logrus/hooks.go
vendored
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
package logrus
|
||||||
|
|
||||||
|
// A hook to be fired when logging on the logging levels returned from
|
||||||
|
// `Levels()` on your implementation of the interface. Note that this is not
|
||||||
|
// fired in a goroutine or a channel with workers, you should handle such
|
||||||
|
// functionality yourself if your call is non-blocking and you don't wish for
|
||||||
|
// the logging calls for levels returned from `Levels()` to block.
|
||||||
|
type Hook interface {
|
||||||
|
Levels() []Level
|
||||||
|
Fire(*Entry) error
|
||||||
|
}
|
||||||
|
|
||||||
|
// Internal type for storing the hooks on a logger instance.
|
||||||
|
type LevelHooks map[Level][]Hook
|
||||||
|
|
||||||
|
// Add a hook to an instance of logger. This is called with
|
||||||
|
// `log.Hooks.Add(new(MyHook))` where `MyHook` implements the `Hook` interface.
|
||||||
|
func (hooks LevelHooks) Add(hook Hook) {
|
||||||
|
for _, level := range hook.Levels() {
|
||||||
|
hooks[level] = append(hooks[level], hook)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fire all the hooks for the passed level. Used by `entry.log` to fire
|
||||||
|
// appropriate hooks for a log entry.
|
||||||
|
func (hooks LevelHooks) Fire(level Level, entry *Entry) error {
|
||||||
|
for _, hook := range hooks[level] {
|
||||||
|
if err := hook.Fire(entry); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
41
vendor/src/github.com/Sirupsen/logrus/json_formatter.go
vendored
Normal file
41
vendor/src/github.com/Sirupsen/logrus/json_formatter.go
vendored
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
package logrus
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
type JSONFormatter struct {
|
||||||
|
// TimestampFormat sets the format used for marshaling timestamps.
|
||||||
|
TimestampFormat string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *JSONFormatter) Format(entry *Entry) ([]byte, error) {
|
||||||
|
data := make(Fields, len(entry.Data)+3)
|
||||||
|
for k, v := range entry.Data {
|
||||||
|
switch v := v.(type) {
|
||||||
|
case error:
|
||||||
|
// Otherwise errors are ignored by `encoding/json`
|
||||||
|
// https://github.com/Sirupsen/logrus/issues/137
|
||||||
|
data[k] = v.Error()
|
||||||
|
default:
|
||||||
|
data[k] = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
prefixFieldClashes(data)
|
||||||
|
|
||||||
|
timestampFormat := f.TimestampFormat
|
||||||
|
if timestampFormat == "" {
|
||||||
|
timestampFormat = DefaultTimestampFormat
|
||||||
|
}
|
||||||
|
|
||||||
|
data["time"] = entry.Time.Format(timestampFormat)
|
||||||
|
data["msg"] = entry.Message
|
||||||
|
data["level"] = entry.Level.String()
|
||||||
|
|
||||||
|
serialized, err := json.Marshal(data)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("Failed to marshal fields to JSON, %v", err)
|
||||||
|
}
|
||||||
|
return append(serialized, '\n'), nil
|
||||||
|
}
|
212
vendor/src/github.com/Sirupsen/logrus/logger.go
vendored
Normal file
212
vendor/src/github.com/Sirupsen/logrus/logger.go
vendored
Normal file
|
@ -0,0 +1,212 @@
|
||||||
|
package logrus
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Logger struct {
|
||||||
|
// The logs are `io.Copy`'d to this in a mutex. It's common to set this to a
|
||||||
|
// file, or leave it default which is `os.Stderr`. You can also set this to
|
||||||
|
// something more adventorous, such as logging to Kafka.
|
||||||
|
Out io.Writer
|
||||||
|
// Hooks for the logger instance. These allow firing events based on logging
|
||||||
|
// levels and log entries. For example, to send errors to an error tracking
|
||||||
|
// service, log to StatsD or dump the core on fatal errors.
|
||||||
|
Hooks LevelHooks
|
||||||
|
// All log entries pass through the formatter before logged to Out. The
|
||||||
|
// included formatters are `TextFormatter` and `JSONFormatter` for which
|
||||||
|
// TextFormatter is the default. In development (when a TTY is attached) it
|
||||||
|
// logs with colors, but to a file it wouldn't. You can easily implement your
|
||||||
|
// own that implements the `Formatter` interface, see the `README` or included
|
||||||
|
// formatters for examples.
|
||||||
|
Formatter Formatter
|
||||||
|
// The logging level the logger should log at. This is typically (and defaults
|
||||||
|
// to) `logrus.Info`, which allows Info(), Warn(), Error() and Fatal() to be
|
||||||
|
// logged. `logrus.Debug` is useful in
|
||||||
|
Level Level
|
||||||
|
// Used to sync writing to the log.
|
||||||
|
mu sync.Mutex
|
||||||
|
}
|
||||||
|
|
||||||
|
// Creates a new logger. Configuration should be set by changing `Formatter`,
|
||||||
|
// `Out` and `Hooks` directly on the default logger instance. You can also just
|
||||||
|
// instantiate your own:
|
||||||
|
//
|
||||||
|
// var log = &Logger{
|
||||||
|
// Out: os.Stderr,
|
||||||
|
// Formatter: new(JSONFormatter),
|
||||||
|
// Hooks: make(LevelHooks),
|
||||||
|
// Level: logrus.DebugLevel,
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// It's recommended to make this a global instance called `log`.
|
||||||
|
func New() *Logger {
|
||||||
|
return &Logger{
|
||||||
|
Out: os.Stderr,
|
||||||
|
Formatter: new(TextFormatter),
|
||||||
|
Hooks: make(LevelHooks),
|
||||||
|
Level: InfoLevel,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Adds a field to the log entry, note that you it doesn't log until you call
|
||||||
|
// Debug, Print, Info, Warn, Fatal or Panic. It only creates a log entry.
|
||||||
|
// If you want multiple fields, use `WithFields`.
|
||||||
|
func (logger *Logger) WithField(key string, value interface{}) *Entry {
|
||||||
|
return NewEntry(logger).WithField(key, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Adds a struct of fields to the log entry. All it does is call `WithField` for
|
||||||
|
// each `Field`.
|
||||||
|
func (logger *Logger) WithFields(fields Fields) *Entry {
|
||||||
|
return NewEntry(logger).WithFields(fields)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add an error as single field to the log entry. All it does is call
|
||||||
|
// `WithError` for the given `error`.
|
||||||
|
func (logger *Logger) WithError(err error) *Entry {
|
||||||
|
return NewEntry(logger).WithError(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) Debugf(format string, args ...interface{}) {
|
||||||
|
if logger.Level >= DebugLevel {
|
||||||
|
NewEntry(logger).Debugf(format, args...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) Infof(format string, args ...interface{}) {
|
||||||
|
if logger.Level >= InfoLevel {
|
||||||
|
NewEntry(logger).Infof(format, args...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) Printf(format string, args ...interface{}) {
|
||||||
|
NewEntry(logger).Printf(format, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) Warnf(format string, args ...interface{}) {
|
||||||
|
if logger.Level >= WarnLevel {
|
||||||
|
NewEntry(logger).Warnf(format, args...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) Warningf(format string, args ...interface{}) {
|
||||||
|
if logger.Level >= WarnLevel {
|
||||||
|
NewEntry(logger).Warnf(format, args...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) Errorf(format string, args ...interface{}) {
|
||||||
|
if logger.Level >= ErrorLevel {
|
||||||
|
NewEntry(logger).Errorf(format, args...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) Fatalf(format string, args ...interface{}) {
|
||||||
|
if logger.Level >= FatalLevel {
|
||||||
|
NewEntry(logger).Fatalf(format, args...)
|
||||||
|
}
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) Panicf(format string, args ...interface{}) {
|
||||||
|
if logger.Level >= PanicLevel {
|
||||||
|
NewEntry(logger).Panicf(format, args...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) Debug(args ...interface{}) {
|
||||||
|
if logger.Level >= DebugLevel {
|
||||||
|
NewEntry(logger).Debug(args...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) Info(args ...interface{}) {
|
||||||
|
if logger.Level >= InfoLevel {
|
||||||
|
NewEntry(logger).Info(args...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) Print(args ...interface{}) {
|
||||||
|
NewEntry(logger).Info(args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) Warn(args ...interface{}) {
|
||||||
|
if logger.Level >= WarnLevel {
|
||||||
|
NewEntry(logger).Warn(args...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) Warning(args ...interface{}) {
|
||||||
|
if logger.Level >= WarnLevel {
|
||||||
|
NewEntry(logger).Warn(args...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) Error(args ...interface{}) {
|
||||||
|
if logger.Level >= ErrorLevel {
|
||||||
|
NewEntry(logger).Error(args...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) Fatal(args ...interface{}) {
|
||||||
|
if logger.Level >= FatalLevel {
|
||||||
|
NewEntry(logger).Fatal(args...)
|
||||||
|
}
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) Panic(args ...interface{}) {
|
||||||
|
if logger.Level >= PanicLevel {
|
||||||
|
NewEntry(logger).Panic(args...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) Debugln(args ...interface{}) {
|
||||||
|
if logger.Level >= DebugLevel {
|
||||||
|
NewEntry(logger).Debugln(args...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) Infoln(args ...interface{}) {
|
||||||
|
if logger.Level >= InfoLevel {
|
||||||
|
NewEntry(logger).Infoln(args...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) Println(args ...interface{}) {
|
||||||
|
NewEntry(logger).Println(args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) Warnln(args ...interface{}) {
|
||||||
|
if logger.Level >= WarnLevel {
|
||||||
|
NewEntry(logger).Warnln(args...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) Warningln(args ...interface{}) {
|
||||||
|
if logger.Level >= WarnLevel {
|
||||||
|
NewEntry(logger).Warnln(args...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) Errorln(args ...interface{}) {
|
||||||
|
if logger.Level >= ErrorLevel {
|
||||||
|
NewEntry(logger).Errorln(args...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) Fatalln(args ...interface{}) {
|
||||||
|
if logger.Level >= FatalLevel {
|
||||||
|
NewEntry(logger).Fatalln(args...)
|
||||||
|
}
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) Panicln(args ...interface{}) {
|
||||||
|
if logger.Level >= PanicLevel {
|
||||||
|
NewEntry(logger).Panicln(args...)
|
||||||
|
}
|
||||||
|
}
|
98
vendor/src/github.com/Sirupsen/logrus/logrus.go
vendored
Normal file
98
vendor/src/github.com/Sirupsen/logrus/logrus.go
vendored
Normal file
|
@ -0,0 +1,98 @@
|
||||||
|
package logrus
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Fields type, used to pass to `WithFields`.
|
||||||
|
type Fields map[string]interface{}
|
||||||
|
|
||||||
|
// Level type
|
||||||
|
type Level uint8
|
||||||
|
|
||||||
|
// Convert the Level to a string. E.g. PanicLevel becomes "panic".
|
||||||
|
func (level Level) String() string {
|
||||||
|
switch level {
|
||||||
|
case DebugLevel:
|
||||||
|
return "debug"
|
||||||
|
case InfoLevel:
|
||||||
|
return "info"
|
||||||
|
case WarnLevel:
|
||||||
|
return "warning"
|
||||||
|
case ErrorLevel:
|
||||||
|
return "error"
|
||||||
|
case FatalLevel:
|
||||||
|
return "fatal"
|
||||||
|
case PanicLevel:
|
||||||
|
return "panic"
|
||||||
|
}
|
||||||
|
|
||||||
|
return "unknown"
|
||||||
|
}
|
||||||
|
|
||||||
|
// ParseLevel takes a string level and returns the Logrus log level constant.
|
||||||
|
func ParseLevel(lvl string) (Level, error) {
|
||||||
|
switch lvl {
|
||||||
|
case "panic":
|
||||||
|
return PanicLevel, nil
|
||||||
|
case "fatal":
|
||||||
|
return FatalLevel, nil
|
||||||
|
case "error":
|
||||||
|
return ErrorLevel, nil
|
||||||
|
case "warn", "warning":
|
||||||
|
return WarnLevel, nil
|
||||||
|
case "info":
|
||||||
|
return InfoLevel, nil
|
||||||
|
case "debug":
|
||||||
|
return DebugLevel, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var l Level
|
||||||
|
return l, fmt.Errorf("not a valid logrus Level: %q", lvl)
|
||||||
|
}
|
||||||
|
|
||||||
|
// These are the different logging levels. You can set the logging level to log
|
||||||
|
// on your instance of logger, obtained with `logrus.New()`.
|
||||||
|
const (
|
||||||
|
// PanicLevel level, highest level of severity. Logs and then calls panic with the
|
||||||
|
// message passed to Debug, Info, ...
|
||||||
|
PanicLevel Level = iota
|
||||||
|
// FatalLevel level. Logs and then calls `os.Exit(1)`. It will exit even if the
|
||||||
|
// logging level is set to Panic.
|
||||||
|
FatalLevel
|
||||||
|
// ErrorLevel level. Logs. Used for errors that should definitely be noted.
|
||||||
|
// Commonly used for hooks to send errors to an error tracking service.
|
||||||
|
ErrorLevel
|
||||||
|
// WarnLevel level. Non-critical entries that deserve eyes.
|
||||||
|
WarnLevel
|
||||||
|
// InfoLevel level. General operational entries about what's going on inside the
|
||||||
|
// application.
|
||||||
|
InfoLevel
|
||||||
|
// DebugLevel level. Usually only enabled when debugging. Very verbose logging.
|
||||||
|
DebugLevel
|
||||||
|
)
|
||||||
|
|
||||||
|
// Won't compile if StdLogger can't be realized by a log.Logger
|
||||||
|
var (
|
||||||
|
_ StdLogger = &log.Logger{}
|
||||||
|
_ StdLogger = &Entry{}
|
||||||
|
_ StdLogger = &Logger{}
|
||||||
|
)
|
||||||
|
|
||||||
|
// StdLogger is what your logrus-enabled library should take, that way
|
||||||
|
// it'll accept a stdlib logger and a logrus logger. There's no standard
|
||||||
|
// interface, this is the closest we get, unfortunately.
|
||||||
|
type StdLogger interface {
|
||||||
|
Print(...interface{})
|
||||||
|
Printf(string, ...interface{})
|
||||||
|
Println(...interface{})
|
||||||
|
|
||||||
|
Fatal(...interface{})
|
||||||
|
Fatalf(string, ...interface{})
|
||||||
|
Fatalln(...interface{})
|
||||||
|
|
||||||
|
Panic(...interface{})
|
||||||
|
Panicf(string, ...interface{})
|
||||||
|
Panicln(...interface{})
|
||||||
|
}
|
9
vendor/src/github.com/Sirupsen/logrus/terminal_bsd.go
vendored
Normal file
9
vendor/src/github.com/Sirupsen/logrus/terminal_bsd.go
vendored
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
// +build darwin freebsd openbsd netbsd dragonfly
|
||||||
|
|
||||||
|
package logrus
|
||||||
|
|
||||||
|
import "syscall"
|
||||||
|
|
||||||
|
const ioctlReadTermios = syscall.TIOCGETA
|
||||||
|
|
||||||
|
type Termios syscall.Termios
|
12
vendor/src/github.com/Sirupsen/logrus/terminal_linux.go
vendored
Normal file
12
vendor/src/github.com/Sirupsen/logrus/terminal_linux.go
vendored
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
// Based on ssh/terminal:
|
||||||
|
// 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 logrus
|
||||||
|
|
||||||
|
import "syscall"
|
||||||
|
|
||||||
|
const ioctlReadTermios = syscall.TCGETS
|
||||||
|
|
||||||
|
type Termios syscall.Termios
|
21
vendor/src/github.com/Sirupsen/logrus/terminal_notwindows.go
vendored
Normal file
21
vendor/src/github.com/Sirupsen/logrus/terminal_notwindows.go
vendored
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
// Based on ssh/terminal:
|
||||||
|
// 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 darwin freebsd openbsd netbsd dragonfly
|
||||||
|
|
||||||
|
package logrus
|
||||||
|
|
||||||
|
import (
|
||||||
|
"syscall"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
// IsTerminal returns true if stderr's file descriptor is a terminal.
|
||||||
|
func IsTerminal() bool {
|
||||||
|
fd := syscall.Stderr
|
||||||
|
var termios Termios
|
||||||
|
_, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlReadTermios, uintptr(unsafe.Pointer(&termios)), 0, 0, 0)
|
||||||
|
return err == 0
|
||||||
|
}
|
15
vendor/src/github.com/Sirupsen/logrus/terminal_solaris.go
vendored
Normal file
15
vendor/src/github.com/Sirupsen/logrus/terminal_solaris.go
vendored
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
// +build solaris
|
||||||
|
|
||||||
|
package logrus
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"golang.org/x/sys/unix"
|
||||||
|
)
|
||||||
|
|
||||||
|
// IsTerminal returns true if the given file descriptor is a terminal.
|
||||||
|
func IsTerminal() bool {
|
||||||
|
_, err := unix.IoctlGetTermios(int(os.Stdout.Fd()), unix.TCGETA)
|
||||||
|
return err == nil
|
||||||
|
}
|
27
vendor/src/github.com/Sirupsen/logrus/terminal_windows.go
vendored
Normal file
27
vendor/src/github.com/Sirupsen/logrus/terminal_windows.go
vendored
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
// Based on ssh/terminal:
|
||||||
|
// 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 windows
|
||||||
|
|
||||||
|
package logrus
|
||||||
|
|
||||||
|
import (
|
||||||
|
"syscall"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
var kernel32 = syscall.NewLazyDLL("kernel32.dll")
|
||||||
|
|
||||||
|
var (
|
||||||
|
procGetConsoleMode = kernel32.NewProc("GetConsoleMode")
|
||||||
|
)
|
||||||
|
|
||||||
|
// IsTerminal returns true if stderr's file descriptor is a terminal.
|
||||||
|
func IsTerminal() bool {
|
||||||
|
fd := syscall.Stderr
|
||||||
|
var st uint32
|
||||||
|
r, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, uintptr(fd), uintptr(unsafe.Pointer(&st)), 0)
|
||||||
|
return r != 0 && e == 0
|
||||||
|
}
|
161
vendor/src/github.com/Sirupsen/logrus/text_formatter.go
vendored
Normal file
161
vendor/src/github.com/Sirupsen/logrus/text_formatter.go
vendored
Normal file
|
@ -0,0 +1,161 @@
|
||||||
|
package logrus
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"runtime"
|
||||||
|
"sort"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
nocolor = 0
|
||||||
|
red = 31
|
||||||
|
green = 32
|
||||||
|
yellow = 33
|
||||||
|
blue = 34
|
||||||
|
gray = 37
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
baseTimestamp time.Time
|
||||||
|
isTerminal bool
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
baseTimestamp = time.Now()
|
||||||
|
isTerminal = IsTerminal()
|
||||||
|
}
|
||||||
|
|
||||||
|
func miniTS() int {
|
||||||
|
return int(time.Since(baseTimestamp) / time.Second)
|
||||||
|
}
|
||||||
|
|
||||||
|
type TextFormatter struct {
|
||||||
|
// Set to true to bypass checking for a TTY before outputting colors.
|
||||||
|
ForceColors bool
|
||||||
|
|
||||||
|
// Force disabling colors.
|
||||||
|
DisableColors bool
|
||||||
|
|
||||||
|
// Disable timestamp logging. useful when output is redirected to logging
|
||||||
|
// system that already adds timestamps.
|
||||||
|
DisableTimestamp bool
|
||||||
|
|
||||||
|
// Enable logging the full timestamp when a TTY is attached instead of just
|
||||||
|
// the time passed since beginning of execution.
|
||||||
|
FullTimestamp bool
|
||||||
|
|
||||||
|
// TimestampFormat to use for display when a full timestamp is printed
|
||||||
|
TimestampFormat string
|
||||||
|
|
||||||
|
// The fields are sorted by default for a consistent output. For applications
|
||||||
|
// that log extremely frequently and don't use the JSON formatter this may not
|
||||||
|
// be desired.
|
||||||
|
DisableSorting bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *TextFormatter) Format(entry *Entry) ([]byte, error) {
|
||||||
|
var keys []string = make([]string, 0, len(entry.Data))
|
||||||
|
for k := range entry.Data {
|
||||||
|
keys = append(keys, k)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !f.DisableSorting {
|
||||||
|
sort.Strings(keys)
|
||||||
|
}
|
||||||
|
|
||||||
|
b := &bytes.Buffer{}
|
||||||
|
|
||||||
|
prefixFieldClashes(entry.Data)
|
||||||
|
|
||||||
|
isColorTerminal := isTerminal && (runtime.GOOS != "windows")
|
||||||
|
isColored := (f.ForceColors || isColorTerminal) && !f.DisableColors
|
||||||
|
|
||||||
|
timestampFormat := f.TimestampFormat
|
||||||
|
if timestampFormat == "" {
|
||||||
|
timestampFormat = DefaultTimestampFormat
|
||||||
|
}
|
||||||
|
if isColored {
|
||||||
|
f.printColored(b, entry, keys, timestampFormat)
|
||||||
|
} else {
|
||||||
|
if !f.DisableTimestamp {
|
||||||
|
f.appendKeyValue(b, "time", entry.Time.Format(timestampFormat))
|
||||||
|
}
|
||||||
|
f.appendKeyValue(b, "level", entry.Level.String())
|
||||||
|
if entry.Message != "" {
|
||||||
|
f.appendKeyValue(b, "msg", entry.Message)
|
||||||
|
}
|
||||||
|
for _, key := range keys {
|
||||||
|
f.appendKeyValue(b, key, entry.Data[key])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
b.WriteByte('\n')
|
||||||
|
return b.Bytes(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *TextFormatter) printColored(b *bytes.Buffer, entry *Entry, keys []string, timestampFormat string) {
|
||||||
|
var levelColor int
|
||||||
|
switch entry.Level {
|
||||||
|
case DebugLevel:
|
||||||
|
levelColor = gray
|
||||||
|
case WarnLevel:
|
||||||
|
levelColor = yellow
|
||||||
|
case ErrorLevel, FatalLevel, PanicLevel:
|
||||||
|
levelColor = red
|
||||||
|
default:
|
||||||
|
levelColor = blue
|
||||||
|
}
|
||||||
|
|
||||||
|
levelText := strings.ToUpper(entry.Level.String())[0:4]
|
||||||
|
|
||||||
|
if !f.FullTimestamp {
|
||||||
|
fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m[%04d] %-44s ", levelColor, levelText, miniTS(), entry.Message)
|
||||||
|
} else {
|
||||||
|
fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m[%s] %-44s ", levelColor, levelText, entry.Time.Format(timestampFormat), entry.Message)
|
||||||
|
}
|
||||||
|
for _, k := range keys {
|
||||||
|
v := entry.Data[k]
|
||||||
|
fmt.Fprintf(b, " \x1b[%dm%s\x1b[0m=%+v", levelColor, k, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func needsQuoting(text string) bool {
|
||||||
|
for _, ch := range text {
|
||||||
|
if !((ch >= 'a' && ch <= 'z') ||
|
||||||
|
(ch >= 'A' && ch <= 'Z') ||
|
||||||
|
(ch >= '0' && ch <= '9') ||
|
||||||
|
ch == '-' || ch == '.') {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *TextFormatter) appendKeyValue(b *bytes.Buffer, key string, value interface{}) {
|
||||||
|
|
||||||
|
b.WriteString(key)
|
||||||
|
b.WriteByte('=')
|
||||||
|
|
||||||
|
switch value := value.(type) {
|
||||||
|
case string:
|
||||||
|
if needsQuoting(value) {
|
||||||
|
b.WriteString(value)
|
||||||
|
} else {
|
||||||
|
fmt.Fprintf(b, "%q", value)
|
||||||
|
}
|
||||||
|
case error:
|
||||||
|
errmsg := value.Error()
|
||||||
|
if needsQuoting(errmsg) {
|
||||||
|
b.WriteString(errmsg)
|
||||||
|
} else {
|
||||||
|
fmt.Fprintf(b, "%q", value)
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
fmt.Fprint(b, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
b.WriteByte(' ')
|
||||||
|
}
|
31
vendor/src/github.com/Sirupsen/logrus/writer.go
vendored
Normal file
31
vendor/src/github.com/Sirupsen/logrus/writer.go
vendored
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
package logrus
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"io"
|
||||||
|
"runtime"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (logger *Logger) Writer() *io.PipeWriter {
|
||||||
|
reader, writer := io.Pipe()
|
||||||
|
|
||||||
|
go logger.writerScanner(reader)
|
||||||
|
runtime.SetFinalizer(writer, writerFinalizer)
|
||||||
|
|
||||||
|
return writer
|
||||||
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) writerScanner(reader *io.PipeReader) {
|
||||||
|
scanner := bufio.NewScanner(reader)
|
||||||
|
for scanner.Scan() {
|
||||||
|
logger.Print(scanner.Text())
|
||||||
|
}
|
||||||
|
if err := scanner.Err(); err != nil {
|
||||||
|
logger.Errorf("Error while reading from Writer: %s", err)
|
||||||
|
}
|
||||||
|
reader.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
func writerFinalizer(writer *io.PipeWriter) {
|
||||||
|
writer.Close()
|
||||||
|
}
|
1
vendor/src/github.com/cloudfoundry/gosigar/.gitignore
vendored
Normal file
1
vendor/src/github.com/cloudfoundry/gosigar/.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
.vagrant
|
8
vendor/src/github.com/cloudfoundry/gosigar/.travis.yml
vendored
Normal file
8
vendor/src/github.com/cloudfoundry/gosigar/.travis.yml
vendored
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
language: go
|
||||||
|
|
||||||
|
go:
|
||||||
|
- 1.2
|
||||||
|
|
||||||
|
install:
|
||||||
|
- 'go install github.com/onsi/ginkgo/ginkgo'
|
||||||
|
script: 'ginkgo -r'
|
201
vendor/src/github.com/cloudfoundry/gosigar/LICENSE
vendored
Normal file
201
vendor/src/github.com/cloudfoundry/gosigar/LICENSE
vendored
Normal file
|
@ -0,0 +1,201 @@
|
||||||
|
Apache License
|
||||||
|
Version 2.0, January 2004
|
||||||
|
http://www.apache.org/licenses/
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||||
|
|
||||||
|
1. Definitions.
|
||||||
|
|
||||||
|
"License" shall mean the terms and conditions for use, reproduction,
|
||||||
|
and distribution as defined by Sections 1 through 9 of this document.
|
||||||
|
|
||||||
|
"Licensor" shall mean the copyright owner or entity authorized by
|
||||||
|
the copyright owner that is granting the License.
|
||||||
|
|
||||||
|
"Legal Entity" shall mean the union of the acting entity and all
|
||||||
|
other entities that control, are controlled by, or are under common
|
||||||
|
control with that entity. For the purposes of this definition,
|
||||||
|
"control" means (i) the power, direct or indirect, to cause the
|
||||||
|
direction or management of such entity, whether by contract or
|
||||||
|
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||||
|
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||||
|
|
||||||
|
"You" (or "Your") shall mean an individual or Legal Entity
|
||||||
|
exercising permissions granted by this License.
|
||||||
|
|
||||||
|
"Source" form shall mean the preferred form for making modifications,
|
||||||
|
including but not limited to software source code, documentation
|
||||||
|
source, and configuration files.
|
||||||
|
|
||||||
|
"Object" form shall mean any form resulting from mechanical
|
||||||
|
transformation or translation of a Source form, including but
|
||||||
|
not limited to compiled object code, generated documentation,
|
||||||
|
and conversions to other media types.
|
||||||
|
|
||||||
|
"Work" shall mean the work of authorship, whether in Source or
|
||||||
|
Object form, made available under the License, as indicated by a
|
||||||
|
copyright notice that is included in or attached to the work
|
||||||
|
(an example is provided in the Appendix below).
|
||||||
|
|
||||||
|
"Derivative Works" shall mean any work, whether in Source or Object
|
||||||
|
form, that is based on (or derived from) the Work and for which the
|
||||||
|
editorial revisions, annotations, elaborations, or other modifications
|
||||||
|
represent, as a whole, an original work of authorship. For the purposes
|
||||||
|
of this License, Derivative Works shall not include works that remain
|
||||||
|
separable from, or merely link (or bind by name) to the interfaces of,
|
||||||
|
the Work and Derivative Works thereof.
|
||||||
|
|
||||||
|
"Contribution" shall mean any work of authorship, including
|
||||||
|
the original version of the Work and any modifications or additions
|
||||||
|
to that Work or Derivative Works thereof, that is intentionally
|
||||||
|
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||||
|
or by an individual or Legal Entity authorized to submit on behalf of
|
||||||
|
the copyright owner. For the purposes of this definition, "submitted"
|
||||||
|
means any form of electronic, verbal, or written communication sent
|
||||||
|
to the Licensor or its representatives, including but not limited to
|
||||||
|
communication on electronic mailing lists, source code control systems,
|
||||||
|
and issue tracking systems that are managed by, or on behalf of, the
|
||||||
|
Licensor for the purpose of discussing and improving the Work, but
|
||||||
|
excluding communication that is conspicuously marked or otherwise
|
||||||
|
designated in writing by the copyright owner as "Not a Contribution."
|
||||||
|
|
||||||
|
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||||
|
on behalf of whom a Contribution has been received by Licensor and
|
||||||
|
subsequently incorporated within the Work.
|
||||||
|
|
||||||
|
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
copyright license to reproduce, prepare Derivative Works of,
|
||||||
|
publicly display, publicly perform, sublicense, and distribute the
|
||||||
|
Work and such Derivative Works in Source or Object form.
|
||||||
|
|
||||||
|
3. Grant of Patent License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor 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, and otherwise transfer the Work,
|
||||||
|
where such license applies only to those patent claims licensable
|
||||||
|
by such Contributor that are necessarily infringed by their
|
||||||
|
Contribution(s) alone or by combination of their Contribution(s)
|
||||||
|
with the Work to which such Contribution(s) was submitted. If You
|
||||||
|
institute patent litigation against any entity (including a
|
||||||
|
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||||
|
or a Contribution incorporated within the Work constitutes direct
|
||||||
|
or contributory patent infringement, then any patent licenses
|
||||||
|
granted to You under this License for that Work shall terminate
|
||||||
|
as of the date such litigation is filed.
|
||||||
|
|
||||||
|
4. Redistribution. You may reproduce and distribute copies of the
|
||||||
|
Work or Derivative Works thereof in any medium, with or without
|
||||||
|
modifications, and in Source or Object form, provided that You
|
||||||
|
meet the following conditions:
|
||||||
|
|
||||||
|
(a) You must give any other recipients of the Work or
|
||||||
|
Derivative Works a copy of this License; and
|
||||||
|
|
||||||
|
(b) You must cause any modified files to carry prominent notices
|
||||||
|
stating that You changed the files; and
|
||||||
|
|
||||||
|
(c) You must retain, in the Source form of any Derivative Works
|
||||||
|
that You distribute, all copyright, patent, trademark, and
|
||||||
|
attribution notices from the Source form of the Work,
|
||||||
|
excluding those notices that do not pertain to any part of
|
||||||
|
the Derivative Works; and
|
||||||
|
|
||||||
|
(d) If the Work includes a "NOTICE" text file as part of its
|
||||||
|
distribution, then any Derivative Works that You distribute must
|
||||||
|
include a readable copy of the attribution notices contained
|
||||||
|
within such NOTICE file, excluding those notices that do not
|
||||||
|
pertain to any part of the Derivative Works, in at least one
|
||||||
|
of the following places: within a NOTICE text file distributed
|
||||||
|
as part of the Derivative Works; within the Source form or
|
||||||
|
documentation, if provided along with the Derivative Works; or,
|
||||||
|
within a display generated by the Derivative Works, if and
|
||||||
|
wherever such third-party notices normally appear. The contents
|
||||||
|
of the NOTICE file are for informational purposes only and
|
||||||
|
do not modify the License. You may add Your own attribution
|
||||||
|
notices within Derivative Works that You distribute, alongside
|
||||||
|
or as an addendum to the NOTICE text from the Work, provided
|
||||||
|
that such additional attribution notices cannot be construed
|
||||||
|
as modifying the License.
|
||||||
|
|
||||||
|
You may add Your own copyright statement to Your modifications and
|
||||||
|
may provide additional or different license terms and conditions
|
||||||
|
for use, reproduction, or distribution of Your modifications, or
|
||||||
|
for any such Derivative Works as a whole, provided Your use,
|
||||||
|
reproduction, and distribution of the Work otherwise complies with
|
||||||
|
the conditions stated in this License.
|
||||||
|
|
||||||
|
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||||
|
any Contribution intentionally submitted for inclusion in the Work
|
||||||
|
by You to the Licensor shall be under the terms and conditions of
|
||||||
|
this License, without any additional terms or conditions.
|
||||||
|
Notwithstanding the above, nothing herein shall supersede or modify
|
||||||
|
the terms of any separate license agreement you may have executed
|
||||||
|
with Licensor regarding such Contributions.
|
||||||
|
|
||||||
|
6. Trademarks. This License does not grant permission to use the trade
|
||||||
|
names, trademarks, service marks, or product names of the Licensor,
|
||||||
|
except as required for reasonable and customary use in describing the
|
||||||
|
origin of the Work and reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
|
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||||
|
agreed to in writing, Licensor provides the Work (and each
|
||||||
|
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
implied, including, without limitation, any warranties or conditions
|
||||||
|
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||||
|
appropriateness of using or redistributing the Work and assume any
|
||||||
|
risks associated with Your exercise of permissions under this License.
|
||||||
|
|
||||||
|
8. Limitation of Liability. In no event and under no legal theory,
|
||||||
|
whether in tort (including negligence), contract, or otherwise,
|
||||||
|
unless required by applicable law (such as deliberate and grossly
|
||||||
|
negligent acts) or agreed to in writing, shall any Contributor be
|
||||||
|
liable to You for damages, including any direct, indirect, special,
|
||||||
|
incidental, or consequential damages of any character arising as a
|
||||||
|
result of this License or out of the use or inability to use the
|
||||||
|
Work (including but not limited to damages for loss of goodwill,
|
||||||
|
work stoppage, computer failure or malfunction, or any and all
|
||||||
|
other commercial damages or losses), even if such Contributor
|
||||||
|
has been advised of the possibility of such damages.
|
||||||
|
|
||||||
|
9. Accepting Warranty or Additional Liability. While redistributing
|
||||||
|
the Work or Derivative Works thereof, You may choose to offer,
|
||||||
|
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||||
|
or other liability obligations and/or rights consistent with this
|
||||||
|
License. However, in accepting such obligations, You may act only
|
||||||
|
on Your own behalf and on Your sole responsibility, not on behalf
|
||||||
|
of any other Contributor, and only if You agree to indemnify,
|
||||||
|
defend, and hold each Contributor harmless for any liability
|
||||||
|
incurred by, or claims asserted against, such Contributor by reason
|
||||||
|
of your accepting any such warranty or additional liability.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
APPENDIX: How to apply the Apache License to your work.
|
||||||
|
|
||||||
|
To apply the Apache License to your work, attach the following
|
||||||
|
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||||
|
replaced with your own identifying information. (Don't include
|
||||||
|
the brackets!) The text should be enclosed in the appropriate
|
||||||
|
comment syntax for the file format. We also recommend that a
|
||||||
|
file or class name and description of purpose be included on the
|
||||||
|
same "printed page" as the copyright notice for easier
|
||||||
|
identification within third-party archives.
|
||||||
|
|
||||||
|
Copyright [yyyy] [name of copyright owner]
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
9
vendor/src/github.com/cloudfoundry/gosigar/NOTICE
vendored
Normal file
9
vendor/src/github.com/cloudfoundry/gosigar/NOTICE
vendored
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
Copyright (c) [2009-2011] VMware, Inc. All Rights Reserved.
|
||||||
|
|
||||||
|
This product is licensed to you under the Apache License, Version 2.0 (the "License").
|
||||||
|
You may not use this product except in compliance with the License.
|
||||||
|
|
||||||
|
This product includes a number of subcomponents with
|
||||||
|
separate copyright notices and license terms. Your use of these
|
||||||
|
subcomponents is subject to the terms and conditions of the
|
||||||
|
subcomponent's license, as noted in the LICENSE file.
|
22
vendor/src/github.com/cloudfoundry/gosigar/README.md
vendored
Normal file
22
vendor/src/github.com/cloudfoundry/gosigar/README.md
vendored
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
# Go sigar
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
Go sigar is a golang implementation of the
|
||||||
|
[sigar API](https://github.com/hyperic/sigar). The Go version of
|
||||||
|
sigar has a very similar interface, but is being written from scratch
|
||||||
|
in pure go/cgo, rather than cgo bindings for libsigar.
|
||||||
|
|
||||||
|
## Test drive
|
||||||
|
|
||||||
|
$ go get github.com/cloudfoundry/gosigar
|
||||||
|
$ cd $GOPATH/src/github.com/cloudfoundry/gosigar/examples
|
||||||
|
$ go run uptime.go
|
||||||
|
|
||||||
|
## Supported platforms
|
||||||
|
|
||||||
|
Currently targeting modern flavors of darwin and linux.
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
Apache 2.0
|
25
vendor/src/github.com/cloudfoundry/gosigar/Vagrantfile
vendored
Normal file
25
vendor/src/github.com/cloudfoundry/gosigar/Vagrantfile
vendored
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
# Vagrantfile API/syntax version. Don't touch unless you know what you're doing!
|
||||||
|
VAGRANTFILE_API_VERSION = "2"
|
||||||
|
|
||||||
|
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
|
||||||
|
config.vm.box = "hashicorp/precise64"
|
||||||
|
config.vm.provision "shell", inline: "mkdir -p /home/vagrant/go"
|
||||||
|
config.vm.synced_folder ".", "/home/vagrant/go/src/github.com/cloudfoundry/gosigar"
|
||||||
|
config.vm.provision "shell", inline: "chown -R vagrant:vagrant /home/vagrant/go"
|
||||||
|
install_go = <<-BASH
|
||||||
|
set -e
|
||||||
|
|
||||||
|
if [ ! -d "/usr/local/go" ]; then
|
||||||
|
cd /tmp && wget https://storage.googleapis.com/golang/go1.3.3.linux-amd64.tar.gz
|
||||||
|
cd /usr/local
|
||||||
|
tar xvzf /tmp/go1.3.3.linux-amd64.tar.gz
|
||||||
|
echo 'export GOPATH=/home/vagrant/go; export PATH=/usr/local/go/bin:$PATH:$GOPATH/bin' >> /home/vagrant/.bashrc
|
||||||
|
fi
|
||||||
|
export GOPATH=/home/vagrant/go
|
||||||
|
export PATH=/usr/local/go/bin:$PATH:$GOPATH/bin
|
||||||
|
/usr/local/go/bin/go get -u github.com/onsi/ginkgo/ginkgo
|
||||||
|
/usr/local/go/bin/go get -u github.com/onsi/gomega;
|
||||||
|
BASH
|
||||||
|
config.vm.provision "shell", inline: 'apt-get install -y git-core'
|
||||||
|
config.vm.provision "shell", inline: install_go
|
||||||
|
end
|
69
vendor/src/github.com/cloudfoundry/gosigar/concrete_sigar.go
vendored
Normal file
69
vendor/src/github.com/cloudfoundry/gosigar/concrete_sigar.go
vendored
Normal file
|
@ -0,0 +1,69 @@
|
||||||
|
package sigar
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ConcreteSigar struct{}
|
||||||
|
|
||||||
|
func (c *ConcreteSigar) CollectCpuStats(collectionInterval time.Duration) (<-chan Cpu, chan<- struct{}) {
|
||||||
|
// samplesCh is buffered to 1 value to immediately return first CPU sample
|
||||||
|
samplesCh := make(chan Cpu, 1)
|
||||||
|
|
||||||
|
stopCh := make(chan struct{})
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
var cpuUsage Cpu
|
||||||
|
|
||||||
|
// Immediately provide non-delta value.
|
||||||
|
// samplesCh is buffered to 1 value, so it will not block.
|
||||||
|
cpuUsage.Get()
|
||||||
|
samplesCh <- cpuUsage
|
||||||
|
|
||||||
|
ticker := time.NewTicker(collectionInterval)
|
||||||
|
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-ticker.C:
|
||||||
|
previousCpuUsage := cpuUsage
|
||||||
|
|
||||||
|
cpuUsage.Get()
|
||||||
|
|
||||||
|
select {
|
||||||
|
case samplesCh <- cpuUsage.Delta(previousCpuUsage):
|
||||||
|
default:
|
||||||
|
// Include default to avoid channel blocking
|
||||||
|
}
|
||||||
|
|
||||||
|
case <-stopCh:
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
return samplesCh, stopCh
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ConcreteSigar) GetLoadAverage() (LoadAverage, error) {
|
||||||
|
l := LoadAverage{}
|
||||||
|
err := l.Get()
|
||||||
|
return l, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ConcreteSigar) GetMem() (Mem, error) {
|
||||||
|
m := Mem{}
|
||||||
|
err := m.Get()
|
||||||
|
return m, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ConcreteSigar) GetSwap() (Swap, error) {
|
||||||
|
s := Swap{}
|
||||||
|
err := s.Get()
|
||||||
|
return s, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ConcreteSigar) GetFileSystemUsage(path string) (FileSystemUsage, error) {
|
||||||
|
f := FileSystemUsage{}
|
||||||
|
err := f.Get(path)
|
||||||
|
return f, err
|
||||||
|
}
|
467
vendor/src/github.com/cloudfoundry/gosigar/sigar_darwin.go
vendored
Normal file
467
vendor/src/github.com/cloudfoundry/gosigar/sigar_darwin.go
vendored
Normal file
|
@ -0,0 +1,467 @@
|
||||||
|
// Copyright (c) 2012 VMware, Inc.
|
||||||
|
|
||||||
|
package sigar
|
||||||
|
|
||||||
|
/*
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <sys/sysctl.h>
|
||||||
|
#include <sys/mount.h>
|
||||||
|
#include <mach/mach_init.h>
|
||||||
|
#include <mach/mach_host.h>
|
||||||
|
#include <mach/host_info.h>
|
||||||
|
#include <libproc.h>
|
||||||
|
#include <mach/processor_info.h>
|
||||||
|
#include <mach/vm_map.h>
|
||||||
|
*/
|
||||||
|
import "C"
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/binary"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"syscall"
|
||||||
|
"time"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (self *LoadAverage) Get() error {
|
||||||
|
avg := []C.double{0, 0, 0}
|
||||||
|
|
||||||
|
C.getloadavg(&avg[0], C.int(len(avg)))
|
||||||
|
|
||||||
|
self.One = float64(avg[0])
|
||||||
|
self.Five = float64(avg[1])
|
||||||
|
self.Fifteen = float64(avg[2])
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *Uptime) Get() error {
|
||||||
|
tv := syscall.Timeval32{}
|
||||||
|
|
||||||
|
if err := sysctlbyname("kern.boottime", &tv); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
self.Length = time.Since(time.Unix(int64(tv.Sec), int64(tv.Usec)*1000)).Seconds()
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *Mem) Get() error {
|
||||||
|
var vmstat C.vm_statistics_data_t
|
||||||
|
|
||||||
|
if err := sysctlbyname("hw.memsize", &self.Total); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := vm_info(&vmstat); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
kern := uint64(vmstat.inactive_count) << 12
|
||||||
|
self.Free = uint64(vmstat.free_count) << 12
|
||||||
|
|
||||||
|
self.Used = self.Total - self.Free
|
||||||
|
self.ActualFree = self.Free + kern
|
||||||
|
self.ActualUsed = self.Used - kern
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type xsw_usage struct {
|
||||||
|
Total, Avail, Used uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *Swap) Get() error {
|
||||||
|
sw_usage := xsw_usage{}
|
||||||
|
|
||||||
|
if err := sysctlbyname("vm.swapusage", &sw_usage); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
self.Total = sw_usage.Total
|
||||||
|
self.Used = sw_usage.Used
|
||||||
|
self.Free = sw_usage.Avail
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *Cpu) Get() error {
|
||||||
|
var count C.mach_msg_type_number_t = C.HOST_CPU_LOAD_INFO_COUNT
|
||||||
|
var cpuload C.host_cpu_load_info_data_t
|
||||||
|
|
||||||
|
status := C.host_statistics(C.host_t(C.mach_host_self()),
|
||||||
|
C.HOST_CPU_LOAD_INFO,
|
||||||
|
C.host_info_t(unsafe.Pointer(&cpuload)),
|
||||||
|
&count)
|
||||||
|
|
||||||
|
if status != C.KERN_SUCCESS {
|
||||||
|
return fmt.Errorf("host_statistics error=%d", status)
|
||||||
|
}
|
||||||
|
|
||||||
|
self.User = uint64(cpuload.cpu_ticks[C.CPU_STATE_USER])
|
||||||
|
self.Sys = uint64(cpuload.cpu_ticks[C.CPU_STATE_SYSTEM])
|
||||||
|
self.Idle = uint64(cpuload.cpu_ticks[C.CPU_STATE_IDLE])
|
||||||
|
self.Nice = uint64(cpuload.cpu_ticks[C.CPU_STATE_NICE])
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *CpuList) Get() error {
|
||||||
|
var count C.mach_msg_type_number_t
|
||||||
|
var cpuload *C.processor_cpu_load_info_data_t
|
||||||
|
var ncpu C.natural_t
|
||||||
|
|
||||||
|
status := C.host_processor_info(C.host_t(C.mach_host_self()),
|
||||||
|
C.PROCESSOR_CPU_LOAD_INFO,
|
||||||
|
&ncpu,
|
||||||
|
(*C.processor_info_array_t)(unsafe.Pointer(&cpuload)),
|
||||||
|
&count)
|
||||||
|
|
||||||
|
if status != C.KERN_SUCCESS {
|
||||||
|
return fmt.Errorf("host_processor_info error=%d", status)
|
||||||
|
}
|
||||||
|
|
||||||
|
// jump through some cgo casting hoops and ensure we properly free
|
||||||
|
// the memory that cpuload points to
|
||||||
|
target := C.vm_map_t(C.mach_task_self_)
|
||||||
|
address := C.vm_address_t(uintptr(unsafe.Pointer(cpuload)))
|
||||||
|
defer C.vm_deallocate(target, address, C.vm_size_t(ncpu))
|
||||||
|
|
||||||
|
// the body of struct processor_cpu_load_info
|
||||||
|
// aka processor_cpu_load_info_data_t
|
||||||
|
var cpu_ticks [C.CPU_STATE_MAX]uint32
|
||||||
|
|
||||||
|
// copy the cpuload array to a []byte buffer
|
||||||
|
// where we can binary.Read the data
|
||||||
|
size := int(ncpu) * binary.Size(cpu_ticks)
|
||||||
|
buf := C.GoBytes(unsafe.Pointer(cpuload), C.int(size))
|
||||||
|
|
||||||
|
bbuf := bytes.NewBuffer(buf)
|
||||||
|
|
||||||
|
self.List = make([]Cpu, 0, ncpu)
|
||||||
|
|
||||||
|
for i := 0; i < int(ncpu); i++ {
|
||||||
|
cpu := Cpu{}
|
||||||
|
|
||||||
|
err := binary.Read(bbuf, binary.LittleEndian, &cpu_ticks)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
cpu.User = uint64(cpu_ticks[C.CPU_STATE_USER])
|
||||||
|
cpu.Sys = uint64(cpu_ticks[C.CPU_STATE_SYSTEM])
|
||||||
|
cpu.Idle = uint64(cpu_ticks[C.CPU_STATE_IDLE])
|
||||||
|
cpu.Nice = uint64(cpu_ticks[C.CPU_STATE_NICE])
|
||||||
|
|
||||||
|
self.List = append(self.List, cpu)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *FileSystemList) Get() error {
|
||||||
|
num, err := getfsstat(nil, C.MNT_NOWAIT)
|
||||||
|
if num < 0 {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
buf := make([]syscall.Statfs_t, num)
|
||||||
|
|
||||||
|
num, err = getfsstat(buf, C.MNT_NOWAIT)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
fslist := make([]FileSystem, 0, num)
|
||||||
|
|
||||||
|
for i := 0; i < num; i++ {
|
||||||
|
fs := FileSystem{}
|
||||||
|
|
||||||
|
fs.DirName = bytePtrToString(&buf[i].Mntonname[0])
|
||||||
|
fs.DevName = bytePtrToString(&buf[i].Mntfromname[0])
|
||||||
|
fs.SysTypeName = bytePtrToString(&buf[i].Fstypename[0])
|
||||||
|
|
||||||
|
fslist = append(fslist, fs)
|
||||||
|
}
|
||||||
|
|
||||||
|
self.List = fslist
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *ProcList) Get() error {
|
||||||
|
n := C.proc_listpids(C.PROC_ALL_PIDS, 0, nil, 0)
|
||||||
|
if n <= 0 {
|
||||||
|
return syscall.EINVAL
|
||||||
|
}
|
||||||
|
buf := make([]byte, n)
|
||||||
|
n = C.proc_listpids(C.PROC_ALL_PIDS, 0, unsafe.Pointer(&buf[0]), n)
|
||||||
|
if n <= 0 {
|
||||||
|
return syscall.ENOMEM
|
||||||
|
}
|
||||||
|
|
||||||
|
var pid int32
|
||||||
|
num := int(n) / binary.Size(pid)
|
||||||
|
list := make([]int, 0, num)
|
||||||
|
bbuf := bytes.NewBuffer(buf)
|
||||||
|
|
||||||
|
for i := 0; i < num; i++ {
|
||||||
|
if err := binary.Read(bbuf, binary.LittleEndian, &pid); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if pid == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
list = append(list, int(pid))
|
||||||
|
}
|
||||||
|
|
||||||
|
self.List = list
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *ProcState) Get(pid int) error {
|
||||||
|
info := C.struct_proc_taskallinfo{}
|
||||||
|
|
||||||
|
if err := task_info(pid, &info); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
self.Name = C.GoString(&info.pbsd.pbi_comm[0])
|
||||||
|
|
||||||
|
switch info.pbsd.pbi_status {
|
||||||
|
case C.SIDL:
|
||||||
|
self.State = RunStateIdle
|
||||||
|
case C.SRUN:
|
||||||
|
self.State = RunStateRun
|
||||||
|
case C.SSLEEP:
|
||||||
|
self.State = RunStateSleep
|
||||||
|
case C.SSTOP:
|
||||||
|
self.State = RunStateStop
|
||||||
|
case C.SZOMB:
|
||||||
|
self.State = RunStateZombie
|
||||||
|
default:
|
||||||
|
self.State = RunStateUnknown
|
||||||
|
}
|
||||||
|
|
||||||
|
self.Ppid = int(info.pbsd.pbi_ppid)
|
||||||
|
|
||||||
|
self.Tty = int(info.pbsd.e_tdev)
|
||||||
|
|
||||||
|
self.Priority = int(info.ptinfo.pti_priority)
|
||||||
|
|
||||||
|
self.Nice = int(info.pbsd.pbi_nice)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *ProcMem) Get(pid int) error {
|
||||||
|
info := C.struct_proc_taskallinfo{}
|
||||||
|
|
||||||
|
if err := task_info(pid, &info); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
self.Size = uint64(info.ptinfo.pti_virtual_size)
|
||||||
|
self.Resident = uint64(info.ptinfo.pti_resident_size)
|
||||||
|
self.PageFaults = uint64(info.ptinfo.pti_faults)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *ProcTime) Get(pid int) error {
|
||||||
|
info := C.struct_proc_taskallinfo{}
|
||||||
|
|
||||||
|
if err := task_info(pid, &info); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
self.User =
|
||||||
|
uint64(info.ptinfo.pti_total_user) / uint64(time.Millisecond)
|
||||||
|
|
||||||
|
self.Sys =
|
||||||
|
uint64(info.ptinfo.pti_total_system) / uint64(time.Millisecond)
|
||||||
|
|
||||||
|
self.Total = self.User + self.Sys
|
||||||
|
|
||||||
|
self.StartTime = (uint64(info.pbsd.pbi_start_tvsec) * 1000) +
|
||||||
|
(uint64(info.pbsd.pbi_start_tvusec) / 1000)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *ProcArgs) Get(pid int) error {
|
||||||
|
var args []string
|
||||||
|
|
||||||
|
argv := func(arg string) {
|
||||||
|
args = append(args, arg)
|
||||||
|
}
|
||||||
|
|
||||||
|
err := kern_procargs(pid, nil, argv, nil)
|
||||||
|
|
||||||
|
self.List = args
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *ProcExe) Get(pid int) error {
|
||||||
|
exe := func(arg string) {
|
||||||
|
self.Name = arg
|
||||||
|
}
|
||||||
|
|
||||||
|
return kern_procargs(pid, exe, nil, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// wrapper around sysctl KERN_PROCARGS2
|
||||||
|
// callbacks params are optional,
|
||||||
|
// up to the caller as to which pieces of data they want
|
||||||
|
func kern_procargs(pid int,
|
||||||
|
exe func(string),
|
||||||
|
argv func(string),
|
||||||
|
env func(string, string)) error {
|
||||||
|
|
||||||
|
mib := []C.int{C.CTL_KERN, C.KERN_PROCARGS2, C.int(pid)}
|
||||||
|
argmax := uintptr(C.ARG_MAX)
|
||||||
|
buf := make([]byte, argmax)
|
||||||
|
err := sysctl(mib, &buf[0], &argmax, nil, 0)
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
bbuf := bytes.NewBuffer(buf)
|
||||||
|
bbuf.Truncate(int(argmax))
|
||||||
|
|
||||||
|
var argc int32
|
||||||
|
binary.Read(bbuf, binary.LittleEndian, &argc)
|
||||||
|
|
||||||
|
path, err := bbuf.ReadBytes(0)
|
||||||
|
if exe != nil {
|
||||||
|
exe(string(chop(path)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// skip trailing \0's
|
||||||
|
for {
|
||||||
|
c, _ := bbuf.ReadByte()
|
||||||
|
if c != 0 {
|
||||||
|
bbuf.UnreadByte()
|
||||||
|
break // start of argv[0]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < int(argc); i++ {
|
||||||
|
arg, err := bbuf.ReadBytes(0)
|
||||||
|
if err == io.EOF {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if argv != nil {
|
||||||
|
argv(string(chop(arg)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if env == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
delim := []byte{61} // "="
|
||||||
|
|
||||||
|
for {
|
||||||
|
line, err := bbuf.ReadBytes(0)
|
||||||
|
if err == io.EOF || line[0] == 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
pair := bytes.SplitN(chop(line), delim, 2)
|
||||||
|
env(string(pair[0]), string(pair[1]))
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// XXX copied from zsyscall_darwin_amd64.go
|
||||||
|
func sysctl(mib []C.int, old *byte, oldlen *uintptr,
|
||||||
|
new *byte, newlen uintptr) (err error) {
|
||||||
|
var p0 unsafe.Pointer
|
||||||
|
p0 = unsafe.Pointer(&mib[0])
|
||||||
|
_, _, e1 := syscall.Syscall6(syscall.SYS___SYSCTL, uintptr(p0),
|
||||||
|
uintptr(len(mib)),
|
||||||
|
uintptr(unsafe.Pointer(old)), uintptr(unsafe.Pointer(oldlen)),
|
||||||
|
uintptr(unsafe.Pointer(new)), uintptr(newlen))
|
||||||
|
if e1 != 0 {
|
||||||
|
err = e1
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func vm_info(vmstat *C.vm_statistics_data_t) error {
|
||||||
|
var count C.mach_msg_type_number_t = C.HOST_VM_INFO_COUNT
|
||||||
|
|
||||||
|
status := C.host_statistics(
|
||||||
|
C.host_t(C.mach_host_self()),
|
||||||
|
C.HOST_VM_INFO,
|
||||||
|
C.host_info_t(unsafe.Pointer(vmstat)),
|
||||||
|
&count)
|
||||||
|
|
||||||
|
if status != C.KERN_SUCCESS {
|
||||||
|
return fmt.Errorf("host_statistics=%d", status)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// generic Sysctl buffer unmarshalling
|
||||||
|
func sysctlbyname(name string, data interface{}) (err error) {
|
||||||
|
val, err := syscall.Sysctl(name)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
buf := []byte(val)
|
||||||
|
|
||||||
|
switch v := data.(type) {
|
||||||
|
case *uint64:
|
||||||
|
*v = *(*uint64)(unsafe.Pointer(&buf[0]))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
bbuf := bytes.NewBuffer([]byte(val))
|
||||||
|
return binary.Read(bbuf, binary.LittleEndian, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
// syscall.Getfsstat() wrapper is broken, roll our own to workaround.
|
||||||
|
func getfsstat(buf []syscall.Statfs_t, flags int) (n int, err error) {
|
||||||
|
var ptr uintptr
|
||||||
|
var size uintptr
|
||||||
|
|
||||||
|
if len(buf) > 0 {
|
||||||
|
ptr = uintptr(unsafe.Pointer(&buf[0]))
|
||||||
|
size = unsafe.Sizeof(buf[0]) * uintptr(len(buf))
|
||||||
|
} else {
|
||||||
|
ptr = uintptr(0)
|
||||||
|
size = uintptr(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
trap := uintptr(syscall.SYS_GETFSSTAT64)
|
||||||
|
ret, _, errno := syscall.Syscall(trap, ptr, size, uintptr(flags))
|
||||||
|
|
||||||
|
n = int(ret)
|
||||||
|
if errno != 0 {
|
||||||
|
err = errno
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func task_info(pid int, info *C.struct_proc_taskallinfo) error {
|
||||||
|
size := C.int(unsafe.Sizeof(*info))
|
||||||
|
ptr := unsafe.Pointer(info)
|
||||||
|
|
||||||
|
n := C.proc_pidinfo(C.int(pid), C.PROC_PIDTASKALLINFO, 0, ptr, size)
|
||||||
|
if n != size {
|
||||||
|
return syscall.ENOMEM
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
126
vendor/src/github.com/cloudfoundry/gosigar/sigar_format.go
vendored
Normal file
126
vendor/src/github.com/cloudfoundry/gosigar/sigar_format.go
vendored
Normal file
|
@ -0,0 +1,126 @@
|
||||||
|
// Copyright (c) 2012 VMware, Inc.
|
||||||
|
|
||||||
|
package sigar
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Go version of apr_strfsize
|
||||||
|
func FormatSize(size uint64) string {
|
||||||
|
ord := []string{"K", "M", "G", "T", "P", "E"}
|
||||||
|
o := 0
|
||||||
|
buf := new(bytes.Buffer)
|
||||||
|
w := bufio.NewWriter(buf)
|
||||||
|
|
||||||
|
if size < 973 {
|
||||||
|
fmt.Fprintf(w, "%3d ", size)
|
||||||
|
w.Flush()
|
||||||
|
return buf.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
for {
|
||||||
|
remain := size & 1023
|
||||||
|
size >>= 10
|
||||||
|
|
||||||
|
if size >= 973 {
|
||||||
|
o++
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if size < 9 || (size == 9 && remain < 973) {
|
||||||
|
remain = ((remain * 5) + 256) / 512
|
||||||
|
if remain >= 10 {
|
||||||
|
size++
|
||||||
|
remain = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Fprintf(w, "%d.%d%s", size, remain, ord[o])
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
if remain >= 512 {
|
||||||
|
size++
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Fprintf(w, "%3d%s", size, ord[o])
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
w.Flush()
|
||||||
|
return buf.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
func FormatPercent(percent float64) string {
|
||||||
|
return strconv.FormatFloat(percent, 'f', -1, 64) + "%"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *FileSystemUsage) UsePercent() float64 {
|
||||||
|
b_used := (self.Total - self.Free) / 1024
|
||||||
|
b_avail := self.Avail / 1024
|
||||||
|
utotal := b_used + b_avail
|
||||||
|
used := b_used
|
||||||
|
|
||||||
|
if utotal != 0 {
|
||||||
|
u100 := used * 100
|
||||||
|
pct := u100 / utotal
|
||||||
|
if u100%utotal != 0 {
|
||||||
|
pct += 1
|
||||||
|
}
|
||||||
|
return (float64(pct) / float64(100)) * 100.0
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0.0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *Uptime) Format() string {
|
||||||
|
buf := new(bytes.Buffer)
|
||||||
|
w := bufio.NewWriter(buf)
|
||||||
|
uptime := uint64(self.Length)
|
||||||
|
|
||||||
|
days := uptime / (60 * 60 * 24)
|
||||||
|
|
||||||
|
if days != 0 {
|
||||||
|
s := ""
|
||||||
|
if days > 1 {
|
||||||
|
s = "s"
|
||||||
|
}
|
||||||
|
fmt.Fprintf(w, "%d day%s, ", days, s)
|
||||||
|
}
|
||||||
|
|
||||||
|
minutes := uptime / 60
|
||||||
|
hours := minutes / 60
|
||||||
|
hours %= 24
|
||||||
|
minutes %= 60
|
||||||
|
|
||||||
|
fmt.Fprintf(w, "%2d:%02d", hours, minutes)
|
||||||
|
|
||||||
|
w.Flush()
|
||||||
|
return buf.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *ProcTime) FormatStartTime() string {
|
||||||
|
if self.StartTime == 0 {
|
||||||
|
return "00:00"
|
||||||
|
}
|
||||||
|
start := time.Unix(int64(self.StartTime)/1000, 0)
|
||||||
|
format := "Jan02"
|
||||||
|
if time.Since(start).Seconds() < (60 * 60 * 24) {
|
||||||
|
format = "15:04"
|
||||||
|
}
|
||||||
|
return start.Format(format)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *ProcTime) FormatTotal() string {
|
||||||
|
t := self.Total / 1000
|
||||||
|
ss := t % 60
|
||||||
|
t /= 60
|
||||||
|
mm := t % 60
|
||||||
|
t /= 60
|
||||||
|
hh := t % 24
|
||||||
|
return fmt.Sprintf("%02d:%02d:%02d", hh, mm, ss)
|
||||||
|
}
|
141
vendor/src/github.com/cloudfoundry/gosigar/sigar_interface.go
vendored
Normal file
141
vendor/src/github.com/cloudfoundry/gosigar/sigar_interface.go
vendored
Normal file
|
@ -0,0 +1,141 @@
|
||||||
|
package sigar
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Sigar interface {
|
||||||
|
CollectCpuStats(collectionInterval time.Duration) (<-chan Cpu, chan<- struct{})
|
||||||
|
GetLoadAverage() (LoadAverage, error)
|
||||||
|
GetMem() (Mem, error)
|
||||||
|
GetSwap() (Swap, error)
|
||||||
|
GetFileSystemUsage(string) (FileSystemUsage, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type Cpu struct {
|
||||||
|
User uint64
|
||||||
|
Nice uint64
|
||||||
|
Sys uint64
|
||||||
|
Idle uint64
|
||||||
|
Wait uint64
|
||||||
|
Irq uint64
|
||||||
|
SoftIrq uint64
|
||||||
|
Stolen uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cpu *Cpu) Total() uint64 {
|
||||||
|
return cpu.User + cpu.Nice + cpu.Sys + cpu.Idle +
|
||||||
|
cpu.Wait + cpu.Irq + cpu.SoftIrq + cpu.Stolen
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cpu Cpu) Delta(other Cpu) Cpu {
|
||||||
|
return Cpu{
|
||||||
|
User: cpu.User - other.User,
|
||||||
|
Nice: cpu.Nice - other.Nice,
|
||||||
|
Sys: cpu.Sys - other.Sys,
|
||||||
|
Idle: cpu.Idle - other.Idle,
|
||||||
|
Wait: cpu.Wait - other.Wait,
|
||||||
|
Irq: cpu.Irq - other.Irq,
|
||||||
|
SoftIrq: cpu.SoftIrq - other.SoftIrq,
|
||||||
|
Stolen: cpu.Stolen - other.Stolen,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type LoadAverage struct {
|
||||||
|
One, Five, Fifteen float64
|
||||||
|
}
|
||||||
|
|
||||||
|
type Uptime struct {
|
||||||
|
Length float64
|
||||||
|
}
|
||||||
|
|
||||||
|
type Mem struct {
|
||||||
|
Total uint64
|
||||||
|
Used uint64
|
||||||
|
Free uint64
|
||||||
|
ActualFree uint64
|
||||||
|
ActualUsed uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
type Swap struct {
|
||||||
|
Total uint64
|
||||||
|
Used uint64
|
||||||
|
Free uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
type CpuList struct {
|
||||||
|
List []Cpu
|
||||||
|
}
|
||||||
|
|
||||||
|
type FileSystem struct {
|
||||||
|
DirName string
|
||||||
|
DevName string
|
||||||
|
TypeName string
|
||||||
|
SysTypeName string
|
||||||
|
Options string
|
||||||
|
Flags uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
type FileSystemList struct {
|
||||||
|
List []FileSystem
|
||||||
|
}
|
||||||
|
|
||||||
|
type FileSystemUsage struct {
|
||||||
|
Total uint64
|
||||||
|
Used uint64
|
||||||
|
Free uint64
|
||||||
|
Avail uint64
|
||||||
|
Files uint64
|
||||||
|
FreeFiles uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
type ProcList struct {
|
||||||
|
List []int
|
||||||
|
}
|
||||||
|
|
||||||
|
type RunState byte
|
||||||
|
|
||||||
|
const (
|
||||||
|
RunStateSleep = 'S'
|
||||||
|
RunStateRun = 'R'
|
||||||
|
RunStateStop = 'T'
|
||||||
|
RunStateZombie = 'Z'
|
||||||
|
RunStateIdle = 'D'
|
||||||
|
RunStateUnknown = '?'
|
||||||
|
)
|
||||||
|
|
||||||
|
type ProcState struct {
|
||||||
|
Name string
|
||||||
|
State RunState
|
||||||
|
Ppid int
|
||||||
|
Tty int
|
||||||
|
Priority int
|
||||||
|
Nice int
|
||||||
|
Processor int
|
||||||
|
}
|
||||||
|
|
||||||
|
type ProcMem struct {
|
||||||
|
Size uint64
|
||||||
|
Resident uint64
|
||||||
|
Share uint64
|
||||||
|
MinorFaults uint64
|
||||||
|
MajorFaults uint64
|
||||||
|
PageFaults uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
type ProcTime struct {
|
||||||
|
StartTime uint64
|
||||||
|
User uint64
|
||||||
|
Sys uint64
|
||||||
|
Total uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
type ProcArgs struct {
|
||||||
|
List []string
|
||||||
|
}
|
||||||
|
|
||||||
|
type ProcExe struct {
|
||||||
|
Name string
|
||||||
|
Cwd string
|
||||||
|
Root string
|
||||||
|
}
|
386
vendor/src/github.com/cloudfoundry/gosigar/sigar_linux.go
vendored
Normal file
386
vendor/src/github.com/cloudfoundry/gosigar/sigar_linux.go
vendored
Normal file
|
@ -0,0 +1,386 @@
|
||||||
|
// Copyright (c) 2012 VMware, Inc.
|
||||||
|
|
||||||
|
package sigar
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"bytes"
|
||||||
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"syscall"
|
||||||
|
)
|
||||||
|
|
||||||
|
var system struct {
|
||||||
|
ticks uint64
|
||||||
|
btime uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
var Procd string
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
system.ticks = 100 // C.sysconf(C._SC_CLK_TCK)
|
||||||
|
|
||||||
|
Procd = "/proc"
|
||||||
|
|
||||||
|
// grab system boot time
|
||||||
|
readFile(Procd+"/stat", func(line string) bool {
|
||||||
|
if strings.HasPrefix(line, "btime") {
|
||||||
|
system.btime, _ = strtoull(line[6:])
|
||||||
|
return false // stop reading
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *LoadAverage) Get() error {
|
||||||
|
line, err := ioutil.ReadFile(Procd + "/loadavg")
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
fields := strings.Fields(string(line))
|
||||||
|
|
||||||
|
self.One, _ = strconv.ParseFloat(fields[0], 64)
|
||||||
|
self.Five, _ = strconv.ParseFloat(fields[1], 64)
|
||||||
|
self.Fifteen, _ = strconv.ParseFloat(fields[2], 64)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *Uptime) Get() error {
|
||||||
|
sysinfo := syscall.Sysinfo_t{}
|
||||||
|
|
||||||
|
if err := syscall.Sysinfo(&sysinfo); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
self.Length = float64(sysinfo.Uptime)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *Mem) Get() error {
|
||||||
|
var buffers, cached uint64
|
||||||
|
table := map[string]*uint64{
|
||||||
|
"MemTotal": &self.Total,
|
||||||
|
"MemFree": &self.Free,
|
||||||
|
"Buffers": &buffers,
|
||||||
|
"Cached": &cached,
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := parseMeminfo(table); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
self.Used = self.Total - self.Free
|
||||||
|
kern := buffers + cached
|
||||||
|
self.ActualFree = self.Free + kern
|
||||||
|
self.ActualUsed = self.Used - kern
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *Swap) Get() error {
|
||||||
|
table := map[string]*uint64{
|
||||||
|
"SwapTotal": &self.Total,
|
||||||
|
"SwapFree": &self.Free,
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := parseMeminfo(table); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
self.Used = self.Total - self.Free
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *Cpu) Get() error {
|
||||||
|
return readFile(Procd+"/stat", func(line string) bool {
|
||||||
|
if len(line) > 4 && line[0:4] == "cpu " {
|
||||||
|
parseCpuStat(self, line)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *CpuList) Get() error {
|
||||||
|
capacity := len(self.List)
|
||||||
|
if capacity == 0 {
|
||||||
|
capacity = 4
|
||||||
|
}
|
||||||
|
list := make([]Cpu, 0, capacity)
|
||||||
|
|
||||||
|
err := readFile(Procd+"/stat", func(line string) bool {
|
||||||
|
if len(line) > 3 && line[0:3] == "cpu" && line[3] != ' ' {
|
||||||
|
cpu := Cpu{}
|
||||||
|
parseCpuStat(&cpu, line)
|
||||||
|
list = append(list, cpu)
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
|
||||||
|
self.List = list
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *FileSystemList) Get() error {
|
||||||
|
capacity := len(self.List)
|
||||||
|
if capacity == 0 {
|
||||||
|
capacity = 10
|
||||||
|
}
|
||||||
|
fslist := make([]FileSystem, 0, capacity)
|
||||||
|
|
||||||
|
err := readFile("/etc/mtab", func(line string) bool {
|
||||||
|
fields := strings.Fields(line)
|
||||||
|
|
||||||
|
fs := FileSystem{}
|
||||||
|
fs.DevName = fields[0]
|
||||||
|
fs.DirName = fields[1]
|
||||||
|
fs.SysTypeName = fields[2]
|
||||||
|
fs.Options = fields[3]
|
||||||
|
|
||||||
|
fslist = append(fslist, fs)
|
||||||
|
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
|
||||||
|
self.List = fslist
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *ProcList) Get() error {
|
||||||
|
dir, err := os.Open(Procd)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer dir.Close()
|
||||||
|
|
||||||
|
const readAllDirnames = -1 // see os.File.Readdirnames doc
|
||||||
|
|
||||||
|
names, err := dir.Readdirnames(readAllDirnames)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
capacity := len(names)
|
||||||
|
list := make([]int, 0, capacity)
|
||||||
|
|
||||||
|
for _, name := range names {
|
||||||
|
if name[0] < '0' || name[0] > '9' {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
pid, err := strconv.Atoi(name)
|
||||||
|
if err == nil {
|
||||||
|
list = append(list, pid)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.List = list
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *ProcState) Get(pid int) error {
|
||||||
|
contents, err := readProcFile(pid, "stat")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
fields := strings.Fields(string(contents))
|
||||||
|
|
||||||
|
self.Name = fields[1][1 : len(fields[1])-1] // strip ()'s
|
||||||
|
|
||||||
|
self.State = RunState(fields[2][0])
|
||||||
|
|
||||||
|
self.Ppid, _ = strconv.Atoi(fields[3])
|
||||||
|
|
||||||
|
self.Tty, _ = strconv.Atoi(fields[6])
|
||||||
|
|
||||||
|
self.Priority, _ = strconv.Atoi(fields[17])
|
||||||
|
|
||||||
|
self.Nice, _ = strconv.Atoi(fields[18])
|
||||||
|
|
||||||
|
self.Processor, _ = strconv.Atoi(fields[38])
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *ProcMem) Get(pid int) error {
|
||||||
|
contents, err := readProcFile(pid, "statm")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
fields := strings.Fields(string(contents))
|
||||||
|
|
||||||
|
size, _ := strtoull(fields[0])
|
||||||
|
self.Size = size << 12
|
||||||
|
|
||||||
|
rss, _ := strtoull(fields[1])
|
||||||
|
self.Resident = rss << 12
|
||||||
|
|
||||||
|
share, _ := strtoull(fields[2])
|
||||||
|
self.Share = share << 12
|
||||||
|
|
||||||
|
contents, err = readProcFile(pid, "stat")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
fields = strings.Fields(string(contents))
|
||||||
|
|
||||||
|
self.MinorFaults, _ = strtoull(fields[10])
|
||||||
|
self.MajorFaults, _ = strtoull(fields[12])
|
||||||
|
self.PageFaults = self.MinorFaults + self.MajorFaults
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *ProcTime) Get(pid int) error {
|
||||||
|
contents, err := readProcFile(pid, "stat")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
fields := strings.Fields(string(contents))
|
||||||
|
|
||||||
|
user, _ := strtoull(fields[13])
|
||||||
|
sys, _ := strtoull(fields[14])
|
||||||
|
// convert to millis
|
||||||
|
self.User = user * (1000 / system.ticks)
|
||||||
|
self.Sys = sys * (1000 / system.ticks)
|
||||||
|
self.Total = self.User + self.Sys
|
||||||
|
|
||||||
|
// convert to millis
|
||||||
|
self.StartTime, _ = strtoull(fields[21])
|
||||||
|
self.StartTime /= system.ticks
|
||||||
|
self.StartTime += system.btime
|
||||||
|
self.StartTime *= 1000
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *ProcArgs) Get(pid int) error {
|
||||||
|
contents, err := readProcFile(pid, "cmdline")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
bbuf := bytes.NewBuffer(contents)
|
||||||
|
|
||||||
|
var args []string
|
||||||
|
|
||||||
|
for {
|
||||||
|
arg, err := bbuf.ReadBytes(0)
|
||||||
|
if err == io.EOF {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
args = append(args, string(chop(arg)))
|
||||||
|
}
|
||||||
|
|
||||||
|
self.List = args
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *ProcExe) Get(pid int) error {
|
||||||
|
fields := map[string]*string{
|
||||||
|
"exe": &self.Name,
|
||||||
|
"cwd": &self.Cwd,
|
||||||
|
"root": &self.Root,
|
||||||
|
}
|
||||||
|
|
||||||
|
for name, field := range fields {
|
||||||
|
val, err := os.Readlink(procFileName(pid, name))
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
*field = val
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseMeminfo(table map[string]*uint64) error {
|
||||||
|
return readFile(Procd+"/meminfo", func(line string) bool {
|
||||||
|
fields := strings.Split(line, ":")
|
||||||
|
|
||||||
|
if ptr := table[fields[0]]; ptr != nil {
|
||||||
|
num := strings.TrimLeft(fields[1], " ")
|
||||||
|
val, err := strtoull(strings.Fields(num)[0])
|
||||||
|
if err == nil {
|
||||||
|
*ptr = val * 1024
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseCpuStat(self *Cpu, line string) error {
|
||||||
|
fields := strings.Fields(line)
|
||||||
|
|
||||||
|
self.User, _ = strtoull(fields[1])
|
||||||
|
self.Nice, _ = strtoull(fields[2])
|
||||||
|
self.Sys, _ = strtoull(fields[3])
|
||||||
|
self.Idle, _ = strtoull(fields[4])
|
||||||
|
self.Wait, _ = strtoull(fields[5])
|
||||||
|
self.Irq, _ = strtoull(fields[6])
|
||||||
|
self.SoftIrq, _ = strtoull(fields[7])
|
||||||
|
self.Stolen, _ = strtoull(fields[8])
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func readFile(file string, handler func(string) bool) error {
|
||||||
|
contents, err := ioutil.ReadFile(file)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
reader := bufio.NewReader(bytes.NewBuffer(contents))
|
||||||
|
|
||||||
|
for {
|
||||||
|
line, _, err := reader.ReadLine()
|
||||||
|
if err == io.EOF {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if !handler(string(line)) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func strtoull(val string) (uint64, error) {
|
||||||
|
return strconv.ParseUint(val, 10, 64)
|
||||||
|
}
|
||||||
|
|
||||||
|
func procFileName(pid int, name string) string {
|
||||||
|
return Procd + "/" + strconv.Itoa(pid) + "/" + name
|
||||||
|
}
|
||||||
|
|
||||||
|
func readProcFile(pid int, name string) ([]byte, error) {
|
||||||
|
path := procFileName(pid, name)
|
||||||
|
contents, err := ioutil.ReadFile(path)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
if perr, ok := err.(*os.PathError); ok {
|
||||||
|
if perr.Err == syscall.ENOENT {
|
||||||
|
return nil, syscall.ESRCH
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return contents, err
|
||||||
|
}
|
26
vendor/src/github.com/cloudfoundry/gosigar/sigar_unix.go
vendored
Normal file
26
vendor/src/github.com/cloudfoundry/gosigar/sigar_unix.go
vendored
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
// Copyright (c) 2012 VMware, Inc.
|
||||||
|
|
||||||
|
// +build darwin freebsd linux netbsd openbsd
|
||||||
|
|
||||||
|
package sigar
|
||||||
|
|
||||||
|
import "syscall"
|
||||||
|
|
||||||
|
func (self *FileSystemUsage) Get(path string) error {
|
||||||
|
stat := syscall.Statfs_t{}
|
||||||
|
err := syscall.Statfs(path, &stat)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
bsize := stat.Bsize / 512
|
||||||
|
|
||||||
|
self.Total = (uint64(stat.Blocks) * uint64(bsize)) >> 1
|
||||||
|
self.Free = (uint64(stat.Bfree) * uint64(bsize)) >> 1
|
||||||
|
self.Avail = (uint64(stat.Bavail) * uint64(bsize)) >> 1
|
||||||
|
self.Used = self.Total - self.Free
|
||||||
|
self.Files = stat.Files
|
||||||
|
self.FreeFiles = stat.Ffree
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
22
vendor/src/github.com/cloudfoundry/gosigar/sigar_util.go
vendored
Normal file
22
vendor/src/github.com/cloudfoundry/gosigar/sigar_util.go
vendored
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
// Copyright (c) 2012 VMware, Inc.
|
||||||
|
|
||||||
|
package sigar
|
||||||
|
|
||||||
|
import (
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
func bytePtrToString(ptr *int8) string {
|
||||||
|
bytes := (*[10000]byte)(unsafe.Pointer(ptr))
|
||||||
|
|
||||||
|
n := 0
|
||||||
|
for bytes[n] != 0 {
|
||||||
|
n++
|
||||||
|
}
|
||||||
|
|
||||||
|
return string(bytes[0:n])
|
||||||
|
}
|
||||||
|
|
||||||
|
func chop(buf []byte) []byte {
|
||||||
|
return buf[0 : len(buf)-1]
|
||||||
|
}
|
100
vendor/src/github.com/cloudfoundry/gosigar/sigar_windows.go
vendored
Normal file
100
vendor/src/github.com/cloudfoundry/gosigar/sigar_windows.go
vendored
Normal file
|
@ -0,0 +1,100 @@
|
||||||
|
// Copyright (c) 2012 VMware, Inc.
|
||||||
|
|
||||||
|
package sigar
|
||||||
|
|
||||||
|
// #include <stdlib.h>
|
||||||
|
// #include <windows.h>
|
||||||
|
import "C"
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *LoadAverage) Get() error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *Uptime) Get() error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *Mem) Get() error {
|
||||||
|
var statex C.MEMORYSTATUSEX
|
||||||
|
statex.dwLength = C.DWORD(unsafe.Sizeof(statex))
|
||||||
|
|
||||||
|
succeeded := C.GlobalMemoryStatusEx(&statex)
|
||||||
|
if succeeded == C.FALSE {
|
||||||
|
lastError := C.GetLastError()
|
||||||
|
return fmt.Errorf("GlobalMemoryStatusEx failed with error: %d", int(lastError))
|
||||||
|
}
|
||||||
|
|
||||||
|
self.Total = uint64(statex.ullTotalPhys)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *Swap) Get() error {
|
||||||
|
return notImplemented()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *Cpu) Get() error {
|
||||||
|
return notImplemented()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *CpuList) Get() error {
|
||||||
|
return notImplemented()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *FileSystemList) Get() error {
|
||||||
|
return notImplemented()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *ProcList) Get() error {
|
||||||
|
return notImplemented()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *ProcState) Get(pid int) error {
|
||||||
|
return notImplemented()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *ProcMem) Get(pid int) error {
|
||||||
|
return notImplemented()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *ProcTime) Get(pid int) error {
|
||||||
|
return notImplemented()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *ProcArgs) Get(pid int) error {
|
||||||
|
return notImplemented()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *ProcExe) Get(pid int) error {
|
||||||
|
return notImplemented()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *FileSystemUsage) Get(path string) error {
|
||||||
|
var availableBytes C.ULARGE_INTEGER
|
||||||
|
var totalBytes C.ULARGE_INTEGER
|
||||||
|
var totalFreeBytes C.ULARGE_INTEGER
|
||||||
|
|
||||||
|
pathChars := C.CString(path)
|
||||||
|
defer C.free(unsafe.Pointer(pathChars))
|
||||||
|
|
||||||
|
succeeded := C.GetDiskFreeSpaceEx((*C.CHAR)(pathChars), &availableBytes, &totalBytes, &totalFreeBytes)
|
||||||
|
if succeeded == C.FALSE {
|
||||||
|
lastError := C.GetLastError()
|
||||||
|
return fmt.Errorf("GetDiskFreeSpaceEx failed with error: %d", int(lastError))
|
||||||
|
}
|
||||||
|
|
||||||
|
self.Total = *(*uint64)(unsafe.Pointer(&totalBytes))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func notImplemented() error {
|
||||||
|
panic("Not Implemented")
|
||||||
|
return nil
|
||||||
|
}
|
19
vendor/src/github.com/codegangsta/cli/.travis.yml
vendored
Normal file
19
vendor/src/github.com/codegangsta/cli/.travis.yml
vendored
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
language: go
|
||||||
|
sudo: false
|
||||||
|
|
||||||
|
go:
|
||||||
|
- 1.0.3
|
||||||
|
- 1.1.2
|
||||||
|
- 1.2.2
|
||||||
|
- 1.3.3
|
||||||
|
- 1.4.2
|
||||||
|
- 1.5.1
|
||||||
|
- tip
|
||||||
|
|
||||||
|
matrix:
|
||||||
|
allow_failures:
|
||||||
|
- go: tip
|
||||||
|
|
||||||
|
script:
|
||||||
|
- go vet ./...
|
||||||
|
- go test -v ./...
|
21
vendor/src/github.com/codegangsta/cli/LICENSE
vendored
Normal file
21
vendor/src/github.com/codegangsta/cli/LICENSE
vendored
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
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.
|
341
vendor/src/github.com/codegangsta/cli/README.md
vendored
Normal file
341
vendor/src/github.com/codegangsta/cli/README.md
vendored
Normal file
|
@ -0,0 +1,341 @@
|
||||||
|
[![Coverage](http://gocover.io/_badge/github.com/codegangsta/cli?0)](http://gocover.io/github.com/codegangsta/cli)
|
||||||
|
[![Build Status](https://travis-ci.org/codegangsta/cli.png?branch=master)](https://travis-ci.org/codegangsta/cli)
|
||||||
|
[![GoDoc](https://godoc.org/github.com/codegangsta/cli?status.svg)](https://godoc.org/github.com/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.
|
||||||
|
|
||||||
|
## 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 neat 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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
...
|
||||||
|
```
|
||||||
|
|
||||||
|
You can also set a destination variable for a flag, to which the content will be scanned.
|
||||||
|
``` go
|
||||||
|
...
|
||||||
|
var language string
|
||||||
|
app.Flags = []cli.Flag {
|
||||||
|
cli.StringFlag{
|
||||||
|
Name: "lang",
|
||||||
|
Value: "english",
|
||||||
|
Usage: "language for the greeting",
|
||||||
|
Destination: &language,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
app.Action = func(c *cli.Context) {
|
||||||
|
name := "someone"
|
||||||
|
if len(c.Args()) > 0 {
|
||||||
|
name = c.Args()[0]
|
||||||
|
}
|
||||||
|
if language == "spanish" {
|
||||||
|
println("Hola", name)
|
||||||
|
} else {
|
||||||
|
println("Hello", name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
...
|
||||||
|
```
|
||||||
|
|
||||||
|
See full list of flags at http://godoc.org/github.com/codegangsta/cli
|
||||||
|
|
||||||
|
#### 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",
|
||||||
|
Aliases: []string{"a"},
|
||||||
|
Usage: "add a task to the list",
|
||||||
|
Action: func(c *cli.Context) {
|
||||||
|
println("added task: ", c.Args().First())
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "complete",
|
||||||
|
Aliases: []string{"c"},
|
||||||
|
Usage: "complete a task on the list",
|
||||||
|
Action: func(c *cli.Context) {
|
||||||
|
println("completed task: ", c.Args().First())
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "template",
|
||||||
|
Aliases: []string{"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",
|
||||||
|
Aliases: []string{"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`
|
||||||
|
|
||||||
|
#### To Distribute
|
||||||
|
|
||||||
|
Copy `autocomplete/bash_autocomplete` into `/etc/bash_completion.d/` and rename
|
||||||
|
it to the name of the program you wish to add autocomplete support for (or
|
||||||
|
automatically install it there if you are distributing a package). Don't forget
|
||||||
|
to source the file to make it active in the current shell.
|
||||||
|
|
||||||
|
```
|
||||||
|
sudo cp src/bash_autocomplete /etc/bash_completion.d/<myprogram>
|
||||||
|
source /etc/bash_completion.d/<myprogram>
|
||||||
|
```
|
||||||
|
|
||||||
|
Alternatively, you can just document that users should source the generic
|
||||||
|
`autocomplete/bash_autocomplete` in their bash configuration with `$PROG` set
|
||||||
|
to the name of their program (as above).
|
||||||
|
|
||||||
|
## 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 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.
|
334
vendor/src/github.com/codegangsta/cli/app.go
vendored
Normal file
334
vendor/src/github.com/codegangsta/cli/app.go
vendored
Normal file
|
@ -0,0 +1,334 @@
|
||||||
|
package cli
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"path"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// App is the main structure of a cli application. It is recomended that
|
||||||
|
// an app be created with the cli.NewApp() function
|
||||||
|
type App struct {
|
||||||
|
// The name of the program. Defaults to path.Base(os.Args[0])
|
||||||
|
Name string
|
||||||
|
// Full name of command for help, defaults to Name
|
||||||
|
HelpName string
|
||||||
|
// Description of the program.
|
||||||
|
Usage string
|
||||||
|
// Description of the program argument format.
|
||||||
|
ArgsUsage 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
|
||||||
|
// An action to execute after any subcommands are run, but after the subcommand has finished
|
||||||
|
// It is run even if Action() panics
|
||||||
|
After 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
|
||||||
|
// List of all authors who contributed
|
||||||
|
Authors []Author
|
||||||
|
// Copyright of the binary if any
|
||||||
|
Copyright string
|
||||||
|
// Name of Author (Note: Use App.Authors, this is deprecated)
|
||||||
|
Author string
|
||||||
|
// Email of Author (Note: Use App.Authors, this is deprecated)
|
||||||
|
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: path.Base(os.Args[0]),
|
||||||
|
HelpName: path.Base(os.Args[0]),
|
||||||
|
Usage: "A new cli application",
|
||||||
|
Version: "0.0.0",
|
||||||
|
BashComplete: DefaultAppComplete,
|
||||||
|
Action: helpCommand.Action,
|
||||||
|
Compiled: compileTime(),
|
||||||
|
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) (err error) {
|
||||||
|
if a.Author != "" || a.Email != "" {
|
||||||
|
a.Authors = append(a.Authors, Author{Name: a.Author, Email: a.Email})
|
||||||
|
}
|
||||||
|
|
||||||
|
newCmds := []Command{}
|
||||||
|
for _, c := range a.Commands {
|
||||||
|
if c.HelpName == "" {
|
||||||
|
c.HelpName = fmt.Sprintf("%s %s", a.HelpName, c.Name)
|
||||||
|
}
|
||||||
|
newCmds = append(newCmds, c)
|
||||||
|
}
|
||||||
|
a.Commands = newCmds
|
||||||
|
|
||||||
|
// append help to commands
|
||||||
|
if a.Command(helpCommand.Name) == nil && !a.HideHelp {
|
||||||
|
a.Commands = append(a.Commands, helpCommand)
|
||||||
|
if (HelpFlag != BoolFlag{}) {
|
||||||
|
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, nil)
|
||||||
|
ShowAppHelp(context)
|
||||||
|
return nerr
|
||||||
|
}
|
||||||
|
context := NewContext(a, set, nil)
|
||||||
|
|
||||||
|
if checkCompletions(context) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintln(a.Writer, "Incorrect Usage.")
|
||||||
|
fmt.Fprintln(a.Writer)
|
||||||
|
ShowAppHelp(context)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if !a.HideHelp && checkHelp(context) {
|
||||||
|
ShowAppHelp(context)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if !a.HideVersion && checkVersion(context) {
|
||||||
|
ShowVersion(context)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if a.After != nil {
|
||||||
|
defer func() {
|
||||||
|
afterErr := a.After(context)
|
||||||
|
if afterErr != nil {
|
||||||
|
if err != nil {
|
||||||
|
err = NewMultiError(err, afterErr)
|
||||||
|
} else {
|
||||||
|
err = afterErr
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
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) (err error) {
|
||||||
|
// append help to commands
|
||||||
|
if len(a.Commands) > 0 {
|
||||||
|
if a.Command(helpCommand.Name) == nil && !a.HideHelp {
|
||||||
|
a.Commands = append(a.Commands, helpCommand)
|
||||||
|
if (HelpFlag != BoolFlag{}) {
|
||||||
|
a.appendFlag(HelpFlag)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
newCmds := []Command{}
|
||||||
|
for _, c := range a.Commands {
|
||||||
|
if c.HelpName == "" {
|
||||||
|
c.HelpName = fmt.Sprintf("%s %s", a.HelpName, c.Name)
|
||||||
|
}
|
||||||
|
newCmds = append(newCmds, c)
|
||||||
|
}
|
||||||
|
a.Commands = newCmds
|
||||||
|
|
||||||
|
// 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)
|
||||||
|
|
||||||
|
if nerr != nil {
|
||||||
|
fmt.Fprintln(a.Writer, nerr)
|
||||||
|
fmt.Fprintln(a.Writer)
|
||||||
|
if len(a.Commands) > 0 {
|
||||||
|
ShowSubcommandHelp(context)
|
||||||
|
} else {
|
||||||
|
ShowCommandHelp(ctx, context.Args().First())
|
||||||
|
}
|
||||||
|
return nerr
|
||||||
|
}
|
||||||
|
|
||||||
|
if checkCompletions(context) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintln(a.Writer, "Incorrect Usage.")
|
||||||
|
fmt.Fprintln(a.Writer)
|
||||||
|
ShowSubcommandHelp(context)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(a.Commands) > 0 {
|
||||||
|
if checkSubcommandHelp(context) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if checkCommandHelp(ctx, context.Args().First()) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if a.After != nil {
|
||||||
|
defer func() {
|
||||||
|
afterErr := a.After(context)
|
||||||
|
if afterErr != nil {
|
||||||
|
if err != nil {
|
||||||
|
err = NewMultiError(err, afterErr)
|
||||||
|
} else {
|
||||||
|
err = afterErr
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Author represents someone who has contributed to a cli project.
|
||||||
|
type Author struct {
|
||||||
|
Name string // The Authors name
|
||||||
|
Email string // The Authors email
|
||||||
|
}
|
||||||
|
|
||||||
|
// String makes Author comply to the Stringer interface, to allow an easy print in the templating process
|
||||||
|
func (a Author) String() string {
|
||||||
|
e := ""
|
||||||
|
if a.Email != "" {
|
||||||
|
e = "<" + a.Email + "> "
|
||||||
|
}
|
||||||
|
|
||||||
|
return fmt.Sprintf("%v %v", a.Name, e)
|
||||||
|
}
|
40
vendor/src/github.com/codegangsta/cli/cli.go
vendored
Normal file
40
vendor/src/github.com/codegangsta/cli/cli.go
vendored
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
// 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
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type MultiError struct {
|
||||||
|
Errors []error
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewMultiError(err ...error) MultiError {
|
||||||
|
return MultiError{Errors: err}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m MultiError) Error() string {
|
||||||
|
errs := make([]string, len(m.Errors))
|
||||||
|
for i, err := range m.Errors {
|
||||||
|
errs[i] = err.Error()
|
||||||
|
}
|
||||||
|
|
||||||
|
return strings.Join(errs, "\n")
|
||||||
|
}
|
216
vendor/src/github.com/codegangsta/cli/command.go
vendored
Normal file
216
vendor/src/github.com/codegangsta/cli/command.go
vendored
Normal file
|
@ -0,0 +1,216 @@
|
||||||
|
package cli
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Command is a subcommand for a cli.App.
|
||||||
|
type Command struct {
|
||||||
|
// The name of the command
|
||||||
|
Name string
|
||||||
|
// short name of the command. Typically one character (deprecated, use `Aliases`)
|
||||||
|
ShortName string
|
||||||
|
// A list of aliases for the command
|
||||||
|
Aliases []string
|
||||||
|
// A short description of the usage of this command
|
||||||
|
Usage string
|
||||||
|
// A longer explanation of how the command works
|
||||||
|
Description string
|
||||||
|
// A short description of the arguments of this command
|
||||||
|
ArgsUsage string
|
||||||
|
// The function to call when checking for bash command completions
|
||||||
|
BashComplete func(context *Context)
|
||||||
|
// An action to execute before any sub-subcommands are run, but after the context is ready
|
||||||
|
// If a non-nil error is returned, no sub-subcommands are run
|
||||||
|
Before func(context *Context) error
|
||||||
|
// An action to execute after any subcommands are run, but after the subcommand has finished
|
||||||
|
// It is run even if Action() panics
|
||||||
|
After func(context *Context) error
|
||||||
|
// The function to call when this command is invoked
|
||||||
|
Action func(context *Context)
|
||||||
|
// List of child commands
|
||||||
|
Subcommands []Command
|
||||||
|
// List of flags to parse
|
||||||
|
Flags []Flag
|
||||||
|
// Treat all flags as normal arguments if true
|
||||||
|
SkipFlagParsing bool
|
||||||
|
// Boolean to hide built-in help command
|
||||||
|
HideHelp bool
|
||||||
|
|
||||||
|
// Full name of command for help, defaults to full command name, including parent commands.
|
||||||
|
HelpName string
|
||||||
|
commandNamePath []string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns the full name of the command.
|
||||||
|
// For subcommands this ensures that parent commands are part of the command path
|
||||||
|
func (c Command) FullName() string {
|
||||||
|
if c.commandNamePath == nil {
|
||||||
|
return c.Name
|
||||||
|
}
|
||||||
|
return strings.Join(c.commandNamePath, " ")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Invokes the command given the context, parses ctx.Args() to generate command-specific flags
|
||||||
|
func (c Command) Run(ctx *Context) error {
|
||||||
|
if len(c.Subcommands) > 0 || c.Before != nil || c.After != nil {
|
||||||
|
return c.startApp(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !c.HideHelp && (HelpFlag != BoolFlag{}) {
|
||||||
|
// append help to flags
|
||||||
|
c.Flags = append(
|
||||||
|
c.Flags,
|
||||||
|
HelpFlag,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if ctx.App.EnableBashCompletion {
|
||||||
|
c.Flags = append(c.Flags, BashCompletionFlag)
|
||||||
|
}
|
||||||
|
|
||||||
|
set := flagSet(c.Name, c.Flags)
|
||||||
|
set.SetOutput(ioutil.Discard)
|
||||||
|
|
||||||
|
var err error
|
||||||
|
if !c.SkipFlagParsing {
|
||||||
|
firstFlagIndex := -1
|
||||||
|
terminatorIndex := -1
|
||||||
|
for index, arg := range ctx.Args() {
|
||||||
|
if arg == "--" {
|
||||||
|
terminatorIndex = index
|
||||||
|
break
|
||||||
|
} else if strings.HasPrefix(arg, "-") && firstFlagIndex == -1 {
|
||||||
|
firstFlagIndex = index
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if firstFlagIndex > -1 {
|
||||||
|
args := ctx.Args()
|
||||||
|
regularArgs := make([]string, len(args[1:firstFlagIndex]))
|
||||||
|
copy(regularArgs, args[1:firstFlagIndex])
|
||||||
|
|
||||||
|
var flagArgs []string
|
||||||
|
if terminatorIndex > -1 {
|
||||||
|
flagArgs = args[firstFlagIndex:terminatorIndex]
|
||||||
|
regularArgs = append(regularArgs, args[terminatorIndex:]...)
|
||||||
|
} else {
|
||||||
|
flagArgs = args[firstFlagIndex:]
|
||||||
|
}
|
||||||
|
|
||||||
|
err = set.Parse(append(flagArgs, regularArgs...))
|
||||||
|
} else {
|
||||||
|
err = set.Parse(ctx.Args().Tail())
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if c.SkipFlagParsing {
|
||||||
|
err = set.Parse(append([]string{"--"}, ctx.Args().Tail()...))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintln(ctx.App.Writer, "Incorrect Usage.")
|
||||||
|
fmt.Fprintln(ctx.App.Writer)
|
||||||
|
ShowCommandHelp(ctx, c.Name)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
nerr := normalizeFlags(c.Flags, set)
|
||||||
|
if nerr != nil {
|
||||||
|
fmt.Fprintln(ctx.App.Writer, nerr)
|
||||||
|
fmt.Fprintln(ctx.App.Writer)
|
||||||
|
ShowCommandHelp(ctx, c.Name)
|
||||||
|
return nerr
|
||||||
|
}
|
||||||
|
context := NewContext(ctx.App, set, ctx)
|
||||||
|
|
||||||
|
if checkCommandCompletions(context, c.Name) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if checkCommandHelp(context, c.Name) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
context.Command = c
|
||||||
|
c.Action(context)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c Command) Names() []string {
|
||||||
|
names := []string{c.Name}
|
||||||
|
|
||||||
|
if c.ShortName != "" {
|
||||||
|
names = append(names, c.ShortName)
|
||||||
|
}
|
||||||
|
|
||||||
|
return append(names, c.Aliases...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns true if Command.Name or Command.ShortName matches given name
|
||||||
|
func (c Command) HasName(name string) bool {
|
||||||
|
for _, n := range c.Names() {
|
||||||
|
if n == name {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c Command) startApp(ctx *Context) error {
|
||||||
|
app := NewApp()
|
||||||
|
|
||||||
|
// set the name and usage
|
||||||
|
app.Name = fmt.Sprintf("%s %s", ctx.App.Name, c.Name)
|
||||||
|
if c.HelpName == "" {
|
||||||
|
app.HelpName = c.HelpName
|
||||||
|
} else {
|
||||||
|
app.HelpName = fmt.Sprintf("%s %s", ctx.App.Name, c.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.Description != "" {
|
||||||
|
app.Usage = c.Description
|
||||||
|
} else {
|
||||||
|
app.Usage = c.Usage
|
||||||
|
}
|
||||||
|
|
||||||
|
// set CommandNotFound
|
||||||
|
app.CommandNotFound = ctx.App.CommandNotFound
|
||||||
|
|
||||||
|
// set the flags and commands
|
||||||
|
app.Commands = c.Subcommands
|
||||||
|
app.Flags = c.Flags
|
||||||
|
app.HideHelp = c.HideHelp
|
||||||
|
|
||||||
|
app.Version = ctx.App.Version
|
||||||
|
app.HideVersion = ctx.App.HideVersion
|
||||||
|
app.Compiled = ctx.App.Compiled
|
||||||
|
app.Author = ctx.App.Author
|
||||||
|
app.Email = ctx.App.Email
|
||||||
|
app.Writer = ctx.App.Writer
|
||||||
|
|
||||||
|
// bash completion
|
||||||
|
app.EnableBashCompletion = ctx.App.EnableBashCompletion
|
||||||
|
if c.BashComplete != nil {
|
||||||
|
app.BashComplete = c.BashComplete
|
||||||
|
}
|
||||||
|
|
||||||
|
// set the actions
|
||||||
|
app.Before = c.Before
|
||||||
|
app.After = c.After
|
||||||
|
if c.Action != nil {
|
||||||
|
app.Action = c.Action
|
||||||
|
} else {
|
||||||
|
app.Action = helpSubcommand.Action
|
||||||
|
}
|
||||||
|
|
||||||
|
var newCmds []Command
|
||||||
|
for _, cc := range app.Commands {
|
||||||
|
cc.commandNamePath = []string{c.Name, cc.Name}
|
||||||
|
newCmds = append(newCmds, cc)
|
||||||
|
}
|
||||||
|
app.Commands = newCmds
|
||||||
|
|
||||||
|
return app.RunAsSubcommand(ctx)
|
||||||
|
}
|
388
vendor/src/github.com/codegangsta/cli/context.go
vendored
Normal file
388
vendor/src/github.com/codegangsta/cli/context.go
vendored
Normal file
|
@ -0,0 +1,388 @@
|
||||||
|
package cli
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"flag"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Context is a type that is passed through to
|
||||||
|
// each Handler action in a cli application. Context
|
||||||
|
// can be used to retrieve context-specific Args and
|
||||||
|
// parsed command-line options.
|
||||||
|
type Context struct {
|
||||||
|
App *App
|
||||||
|
Command Command
|
||||||
|
flagSet *flag.FlagSet
|
||||||
|
setFlags map[string]bool
|
||||||
|
globalSetFlags map[string]bool
|
||||||
|
parentContext *Context
|
||||||
|
}
|
||||||
|
|
||||||
|
// Creates a new context. For use in when invoking an App or Command action.
|
||||||
|
func NewContext(app *App, set *flag.FlagSet, parentCtx *Context) *Context {
|
||||||
|
return &Context{App: app, flagSet: set, parentContext: parentCtx}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Looks up the value of a local int flag, returns 0 if no int flag exists
|
||||||
|
func (c *Context) Int(name string) int {
|
||||||
|
return lookupInt(name, c.flagSet)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Looks up the value of a local time.Duration flag, returns 0 if no time.Duration flag exists
|
||||||
|
func (c *Context) Duration(name string) time.Duration {
|
||||||
|
return lookupDuration(name, c.flagSet)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Looks up the value of a local float64 flag, returns 0 if no float64 flag exists
|
||||||
|
func (c *Context) Float64(name string) float64 {
|
||||||
|
return lookupFloat64(name, c.flagSet)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Looks up the value of a local bool flag, returns false if no bool flag exists
|
||||||
|
func (c *Context) Bool(name string) bool {
|
||||||
|
return lookupBool(name, c.flagSet)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Looks up the value of a local boolT flag, returns false if no bool flag exists
|
||||||
|
func (c *Context) BoolT(name string) bool {
|
||||||
|
return lookupBoolT(name, c.flagSet)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Looks up the value of a local string flag, returns "" if no string flag exists
|
||||||
|
func (c *Context) String(name string) string {
|
||||||
|
return lookupString(name, c.flagSet)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Looks up the value of a local string slice flag, returns nil if no string slice flag exists
|
||||||
|
func (c *Context) StringSlice(name string) []string {
|
||||||
|
return lookupStringSlice(name, c.flagSet)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Looks up the value of a local int slice flag, returns nil if no int slice flag exists
|
||||||
|
func (c *Context) IntSlice(name string) []int {
|
||||||
|
return lookupIntSlice(name, c.flagSet)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Looks up the value of a local generic flag, returns nil if no generic flag exists
|
||||||
|
func (c *Context) Generic(name string) interface{} {
|
||||||
|
return lookupGeneric(name, c.flagSet)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Looks up the value of a global int flag, returns 0 if no int flag exists
|
||||||
|
func (c *Context) GlobalInt(name string) int {
|
||||||
|
if fs := lookupGlobalFlagSet(name, c); fs != nil {
|
||||||
|
return lookupInt(name, fs)
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// Looks up the value of a global time.Duration flag, returns 0 if no time.Duration flag exists
|
||||||
|
func (c *Context) GlobalDuration(name string) time.Duration {
|
||||||
|
if fs := lookupGlobalFlagSet(name, c); fs != nil {
|
||||||
|
return lookupDuration(name, fs)
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// Looks up the value of a global bool flag, returns false if no bool flag exists
|
||||||
|
func (c *Context) GlobalBool(name string) bool {
|
||||||
|
if fs := lookupGlobalFlagSet(name, c); fs != nil {
|
||||||
|
return lookupBool(name, fs)
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Looks up the value of a global string flag, returns "" if no string flag exists
|
||||||
|
func (c *Context) GlobalString(name string) string {
|
||||||
|
if fs := lookupGlobalFlagSet(name, c); fs != nil {
|
||||||
|
return lookupString(name, fs)
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// Looks up the value of a global string slice flag, returns nil if no string slice flag exists
|
||||||
|
func (c *Context) GlobalStringSlice(name string) []string {
|
||||||
|
if fs := lookupGlobalFlagSet(name, c); fs != nil {
|
||||||
|
return lookupStringSlice(name, fs)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Looks up the value of a global int slice flag, returns nil if no int slice flag exists
|
||||||
|
func (c *Context) GlobalIntSlice(name string) []int {
|
||||||
|
if fs := lookupGlobalFlagSet(name, c); fs != nil {
|
||||||
|
return lookupIntSlice(name, fs)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Looks up the value of a global generic flag, returns nil if no generic flag exists
|
||||||
|
func (c *Context) GlobalGeneric(name string) interface{} {
|
||||||
|
if fs := lookupGlobalFlagSet(name, c); fs != nil {
|
||||||
|
return lookupGeneric(name, fs)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns the number of flags set
|
||||||
|
func (c *Context) NumFlags() int {
|
||||||
|
return c.flagSet.NFlag()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determines if the flag was actually set
|
||||||
|
func (c *Context) IsSet(name string) bool {
|
||||||
|
if c.setFlags == nil {
|
||||||
|
c.setFlags = make(map[string]bool)
|
||||||
|
c.flagSet.Visit(func(f *flag.Flag) {
|
||||||
|
c.setFlags[f.Name] = true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return c.setFlags[name] == true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determines if the global flag was actually set
|
||||||
|
func (c *Context) GlobalIsSet(name string) bool {
|
||||||
|
if c.globalSetFlags == nil {
|
||||||
|
c.globalSetFlags = make(map[string]bool)
|
||||||
|
ctx := c
|
||||||
|
if ctx.parentContext != nil {
|
||||||
|
ctx = ctx.parentContext
|
||||||
|
}
|
||||||
|
for ; ctx != nil && c.globalSetFlags[name] == false; ctx = ctx.parentContext {
|
||||||
|
ctx.flagSet.Visit(func(f *flag.Flag) {
|
||||||
|
c.globalSetFlags[f.Name] = true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return c.globalSetFlags[name]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns a slice of flag names used in this context.
|
||||||
|
func (c *Context) FlagNames() (names []string) {
|
||||||
|
for _, flag := range c.Command.Flags {
|
||||||
|
name := strings.Split(flag.GetName(), ",")[0]
|
||||||
|
if name == "help" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
names = append(names, name)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns a slice of global flag names used by the app.
|
||||||
|
func (c *Context) GlobalFlagNames() (names []string) {
|
||||||
|
for _, flag := range c.App.Flags {
|
||||||
|
name := strings.Split(flag.GetName(), ",")[0]
|
||||||
|
if name == "help" || name == "version" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
names = append(names, name)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns the parent context, if any
|
||||||
|
func (c *Context) Parent() *Context {
|
||||||
|
return c.parentContext
|
||||||
|
}
|
||||||
|
|
||||||
|
type Args []string
|
||||||
|
|
||||||
|
// Returns the command line arguments associated with the context.
|
||||||
|
func (c *Context) Args() Args {
|
||||||
|
args := Args(c.flagSet.Args())
|
||||||
|
return args
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns the nth argument, or else a blank string
|
||||||
|
func (a Args) Get(n int) string {
|
||||||
|
if len(a) > n {
|
||||||
|
return a[n]
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns the first argument, or else a blank string
|
||||||
|
func (a Args) First() string {
|
||||||
|
return a.Get(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the rest of the arguments (not the first one)
|
||||||
|
// or else an empty string slice
|
||||||
|
func (a Args) Tail() []string {
|
||||||
|
if len(a) >= 2 {
|
||||||
|
return []string(a)[1:]
|
||||||
|
}
|
||||||
|
return []string{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Checks if there are any arguments present
|
||||||
|
func (a Args) Present() bool {
|
||||||
|
return len(a) != 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// Swaps arguments at the given indexes
|
||||||
|
func (a Args) Swap(from, to int) error {
|
||||||
|
if from >= len(a) || to >= len(a) {
|
||||||
|
return errors.New("index out of range")
|
||||||
|
}
|
||||||
|
a[from], a[to] = a[to], a[from]
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func lookupGlobalFlagSet(name string, ctx *Context) *flag.FlagSet {
|
||||||
|
if ctx.parentContext != nil {
|
||||||
|
ctx = ctx.parentContext
|
||||||
|
}
|
||||||
|
for ; ctx != nil; ctx = ctx.parentContext {
|
||||||
|
if f := ctx.flagSet.Lookup(name); f != nil {
|
||||||
|
return ctx.flagSet
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func lookupInt(name string, set *flag.FlagSet) int {
|
||||||
|
f := set.Lookup(name)
|
||||||
|
if f != nil {
|
||||||
|
val, err := strconv.Atoi(f.Value.String())
|
||||||
|
if err != nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return val
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func lookupDuration(name string, set *flag.FlagSet) time.Duration {
|
||||||
|
f := set.Lookup(name)
|
||||||
|
if f != nil {
|
||||||
|
val, err := time.ParseDuration(f.Value.String())
|
||||||
|
if err == nil {
|
||||||
|
return val
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func lookupFloat64(name string, set *flag.FlagSet) float64 {
|
||||||
|
f := set.Lookup(name)
|
||||||
|
if f != nil {
|
||||||
|
val, err := strconv.ParseFloat(f.Value.String(), 64)
|
||||||
|
if err != nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return val
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func lookupString(name string, set *flag.FlagSet) string {
|
||||||
|
f := set.Lookup(name)
|
||||||
|
if f != nil {
|
||||||
|
return f.Value.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func lookupStringSlice(name string, set *flag.FlagSet) []string {
|
||||||
|
f := set.Lookup(name)
|
||||||
|
if f != nil {
|
||||||
|
return (f.Value.(*StringSlice)).Value()
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func lookupIntSlice(name string, set *flag.FlagSet) []int {
|
||||||
|
f := set.Lookup(name)
|
||||||
|
if f != nil {
|
||||||
|
return (f.Value.(*IntSlice)).Value()
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func lookupGeneric(name string, set *flag.FlagSet) interface{} {
|
||||||
|
f := set.Lookup(name)
|
||||||
|
if f != nil {
|
||||||
|
return f.Value
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func lookupBool(name string, set *flag.FlagSet) bool {
|
||||||
|
f := set.Lookup(name)
|
||||||
|
if f != nil {
|
||||||
|
val, err := strconv.ParseBool(f.Value.String())
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return val
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func lookupBoolT(name string, set *flag.FlagSet) bool {
|
||||||
|
f := set.Lookup(name)
|
||||||
|
if f != nil {
|
||||||
|
val, err := strconv.ParseBool(f.Value.String())
|
||||||
|
if err != nil {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return val
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func copyFlag(name string, ff *flag.Flag, set *flag.FlagSet) {
|
||||||
|
switch ff.Value.(type) {
|
||||||
|
case *StringSlice:
|
||||||
|
default:
|
||||||
|
set.Set(name, ff.Value.String())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func normalizeFlags(flags []Flag, set *flag.FlagSet) error {
|
||||||
|
visited := make(map[string]bool)
|
||||||
|
set.Visit(func(f *flag.Flag) {
|
||||||
|
visited[f.Name] = true
|
||||||
|
})
|
||||||
|
for _, f := range flags {
|
||||||
|
parts := strings.Split(f.GetName(), ",")
|
||||||
|
if len(parts) == 1 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
var ff *flag.Flag
|
||||||
|
for _, name := range parts {
|
||||||
|
name = strings.Trim(name, " ")
|
||||||
|
if visited[name] {
|
||||||
|
if ff != nil {
|
||||||
|
return errors.New("Cannot use two forms of the same flag: " + name + " " + ff.Name)
|
||||||
|
}
|
||||||
|
ff = set.Lookup(name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ff == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
for _, name := range parts {
|
||||||
|
name = strings.Trim(name, " ")
|
||||||
|
if !visited[name] {
|
||||||
|
copyFlag(name, ff, set)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
527
vendor/src/github.com/codegangsta/cli/flag.go
vendored
Normal file
527
vendor/src/github.com/codegangsta/cli/flag.go
vendored
Normal file
|
@ -0,0 +1,527 @@
|
||||||
|
package cli
|
||||||
|
|
||||||
|
import (
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// This flag enables bash-completion for all commands and subcommands
|
||||||
|
var BashCompletionFlag = BoolFlag{
|
||||||
|
Name: "generate-bash-completion",
|
||||||
|
}
|
||||||
|
|
||||||
|
// This flag prints the version for the application
|
||||||
|
var VersionFlag = BoolFlag{
|
||||||
|
Name: "version, v",
|
||||||
|
Usage: "print the version",
|
||||||
|
}
|
||||||
|
|
||||||
|
// This flag prints the help for all commands and subcommands
|
||||||
|
// Set to the zero value (BoolFlag{}) to disable flag -- keeps subcommand
|
||||||
|
// unless HideHelp is set to true)
|
||||||
|
var HelpFlag = BoolFlag{
|
||||||
|
Name: "help, h",
|
||||||
|
Usage: "show help",
|
||||||
|
}
|
||||||
|
|
||||||
|
// Flag is a common interface related to parsing flags in cli.
|
||||||
|
// For more advanced flag parsing techniques, it is recomended that
|
||||||
|
// this interface be implemented.
|
||||||
|
type Flag interface {
|
||||||
|
fmt.Stringer
|
||||||
|
// Apply Flag settings to the given flag set
|
||||||
|
Apply(*flag.FlagSet)
|
||||||
|
GetName() string
|
||||||
|
}
|
||||||
|
|
||||||
|
func flagSet(name string, flags []Flag) *flag.FlagSet {
|
||||||
|
set := flag.NewFlagSet(name, flag.ContinueOnError)
|
||||||
|
|
||||||
|
for _, f := range flags {
|
||||||
|
f.Apply(set)
|
||||||
|
}
|
||||||
|
return set
|
||||||
|
}
|
||||||
|
|
||||||
|
func eachName(longName string, fn func(string)) {
|
||||||
|
parts := strings.Split(longName, ",")
|
||||||
|
for _, name := range parts {
|
||||||
|
name = strings.Trim(name, " ")
|
||||||
|
fn(name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generic is a generic parseable type identified by a specific flag
|
||||||
|
type Generic interface {
|
||||||
|
Set(value string) error
|
||||||
|
String() string
|
||||||
|
}
|
||||||
|
|
||||||
|
// GenericFlag is the flag type for types implementing Generic
|
||||||
|
type GenericFlag struct {
|
||||||
|
Name string
|
||||||
|
Value Generic
|
||||||
|
Usage string
|
||||||
|
EnvVar string
|
||||||
|
}
|
||||||
|
|
||||||
|
// String returns the string representation of the generic flag to display the
|
||||||
|
// help text to the user (uses the String() method of the generic flag to show
|
||||||
|
// the value)
|
||||||
|
func (f GenericFlag) String() string {
|
||||||
|
return withEnvHint(f.EnvVar, fmt.Sprintf("%s%s \"%v\"\t%v", prefixFor(f.Name), f.Name, f.Value, f.Usage))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply takes the flagset and calls Set on the generic flag with the value
|
||||||
|
// provided by the user for parsing by the flag
|
||||||
|
func (f GenericFlag) Apply(set *flag.FlagSet) {
|
||||||
|
val := f.Value
|
||||||
|
if f.EnvVar != "" {
|
||||||
|
for _, envVar := range strings.Split(f.EnvVar, ",") {
|
||||||
|
envVar = strings.TrimSpace(envVar)
|
||||||
|
if envVal := os.Getenv(envVar); envVal != "" {
|
||||||
|
val.Set(envVal)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
eachName(f.Name, func(name string) {
|
||||||
|
set.Var(f.Value, name, f.Usage)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f GenericFlag) GetName() string {
|
||||||
|
return f.Name
|
||||||
|
}
|
||||||
|
|
||||||
|
// StringSlice is an opaque type for []string to satisfy flag.Value
|
||||||
|
type StringSlice []string
|
||||||
|
|
||||||
|
// Set appends the string value to the list of values
|
||||||
|
func (f *StringSlice) Set(value string) error {
|
||||||
|
*f = append(*f, value)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// String returns a readable representation of this value (for usage defaults)
|
||||||
|
func (f *StringSlice) String() string {
|
||||||
|
return fmt.Sprintf("%s", *f)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Value returns the slice of strings set by this flag
|
||||||
|
func (f *StringSlice) Value() []string {
|
||||||
|
return *f
|
||||||
|
}
|
||||||
|
|
||||||
|
// StringSlice is a string flag that can be specified multiple times on the
|
||||||
|
// command-line
|
||||||
|
type StringSliceFlag struct {
|
||||||
|
Name string
|
||||||
|
Value *StringSlice
|
||||||
|
Usage string
|
||||||
|
EnvVar string
|
||||||
|
}
|
||||||
|
|
||||||
|
// String returns the usage
|
||||||
|
func (f StringSliceFlag) String() string {
|
||||||
|
firstName := strings.Trim(strings.Split(f.Name, ",")[0], " ")
|
||||||
|
pref := prefixFor(firstName)
|
||||||
|
return withEnvHint(f.EnvVar, fmt.Sprintf("%s [%v]\t%v", prefixedNames(f.Name), pref+firstName+" option "+pref+firstName+" option", f.Usage))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply populates the flag given the flag set and environment
|
||||||
|
func (f StringSliceFlag) Apply(set *flag.FlagSet) {
|
||||||
|
if f.EnvVar != "" {
|
||||||
|
for _, envVar := range strings.Split(f.EnvVar, ",") {
|
||||||
|
envVar = strings.TrimSpace(envVar)
|
||||||
|
if envVal := os.Getenv(envVar); envVal != "" {
|
||||||
|
newVal := &StringSlice{}
|
||||||
|
for _, s := range strings.Split(envVal, ",") {
|
||||||
|
s = strings.TrimSpace(s)
|
||||||
|
newVal.Set(s)
|
||||||
|
}
|
||||||
|
f.Value = newVal
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
eachName(f.Name, func(name string) {
|
||||||
|
if f.Value == nil {
|
||||||
|
f.Value = &StringSlice{}
|
||||||
|
}
|
||||||
|
set.Var(f.Value, name, f.Usage)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f StringSliceFlag) GetName() string {
|
||||||
|
return f.Name
|
||||||
|
}
|
||||||
|
|
||||||
|
// StringSlice is an opaque type for []int to satisfy flag.Value
|
||||||
|
type IntSlice []int
|
||||||
|
|
||||||
|
// Set parses the value into an integer and appends it to the list of values
|
||||||
|
func (f *IntSlice) Set(value string) error {
|
||||||
|
tmp, err := strconv.Atoi(value)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
} else {
|
||||||
|
*f = append(*f, tmp)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// String returns a readable representation of this value (for usage defaults)
|
||||||
|
func (f *IntSlice) String() string {
|
||||||
|
return fmt.Sprintf("%d", *f)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Value returns the slice of ints set by this flag
|
||||||
|
func (f *IntSlice) Value() []int {
|
||||||
|
return *f
|
||||||
|
}
|
||||||
|
|
||||||
|
// IntSliceFlag is an int flag that can be specified multiple times on the
|
||||||
|
// command-line
|
||||||
|
type IntSliceFlag struct {
|
||||||
|
Name string
|
||||||
|
Value *IntSlice
|
||||||
|
Usage string
|
||||||
|
EnvVar string
|
||||||
|
}
|
||||||
|
|
||||||
|
// String returns the usage
|
||||||
|
func (f IntSliceFlag) String() string {
|
||||||
|
firstName := strings.Trim(strings.Split(f.Name, ",")[0], " ")
|
||||||
|
pref := prefixFor(firstName)
|
||||||
|
return withEnvHint(f.EnvVar, fmt.Sprintf("%s [%v]\t%v", prefixedNames(f.Name), pref+firstName+" option "+pref+firstName+" option", f.Usage))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply populates the flag given the flag set and environment
|
||||||
|
func (f IntSliceFlag) Apply(set *flag.FlagSet) {
|
||||||
|
if f.EnvVar != "" {
|
||||||
|
for _, envVar := range strings.Split(f.EnvVar, ",") {
|
||||||
|
envVar = strings.TrimSpace(envVar)
|
||||||
|
if envVal := os.Getenv(envVar); envVal != "" {
|
||||||
|
newVal := &IntSlice{}
|
||||||
|
for _, s := range strings.Split(envVal, ",") {
|
||||||
|
s = strings.TrimSpace(s)
|
||||||
|
err := newVal.Set(s)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
f.Value = newVal
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
eachName(f.Name, func(name string) {
|
||||||
|
if f.Value == nil {
|
||||||
|
f.Value = &IntSlice{}
|
||||||
|
}
|
||||||
|
set.Var(f.Value, name, f.Usage)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f IntSliceFlag) GetName() string {
|
||||||
|
return f.Name
|
||||||
|
}
|
||||||
|
|
||||||
|
// BoolFlag is a switch that defaults to false
|
||||||
|
type BoolFlag struct {
|
||||||
|
Name string
|
||||||
|
Usage string
|
||||||
|
EnvVar string
|
||||||
|
Destination *bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// String returns a readable representation of this value (for usage defaults)
|
||||||
|
func (f BoolFlag) String() string {
|
||||||
|
return withEnvHint(f.EnvVar, fmt.Sprintf("%s\t%v", prefixedNames(f.Name), f.Usage))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply populates the flag given the flag set and environment
|
||||||
|
func (f BoolFlag) Apply(set *flag.FlagSet) {
|
||||||
|
val := false
|
||||||
|
if f.EnvVar != "" {
|
||||||
|
for _, envVar := range strings.Split(f.EnvVar, ",") {
|
||||||
|
envVar = strings.TrimSpace(envVar)
|
||||||
|
if envVal := os.Getenv(envVar); envVal != "" {
|
||||||
|
envValBool, err := strconv.ParseBool(envVal)
|
||||||
|
if err == nil {
|
||||||
|
val = envValBool
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
eachName(f.Name, func(name string) {
|
||||||
|
if f.Destination != nil {
|
||||||
|
set.BoolVar(f.Destination, name, val, f.Usage)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
set.Bool(name, val, f.Usage)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f BoolFlag) GetName() string {
|
||||||
|
return f.Name
|
||||||
|
}
|
||||||
|
|
||||||
|
// BoolTFlag this represents a boolean flag that is true by default, but can
|
||||||
|
// still be set to false by --some-flag=false
|
||||||
|
type BoolTFlag struct {
|
||||||
|
Name string
|
||||||
|
Usage string
|
||||||
|
EnvVar string
|
||||||
|
Destination *bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// String returns a readable representation of this value (for usage defaults)
|
||||||
|
func (f BoolTFlag) String() string {
|
||||||
|
return withEnvHint(f.EnvVar, fmt.Sprintf("%s\t%v", prefixedNames(f.Name), f.Usage))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply populates the flag given the flag set and environment
|
||||||
|
func (f BoolTFlag) Apply(set *flag.FlagSet) {
|
||||||
|
val := true
|
||||||
|
if f.EnvVar != "" {
|
||||||
|
for _, envVar := range strings.Split(f.EnvVar, ",") {
|
||||||
|
envVar = strings.TrimSpace(envVar)
|
||||||
|
if envVal := os.Getenv(envVar); envVal != "" {
|
||||||
|
envValBool, err := strconv.ParseBool(envVal)
|
||||||
|
if err == nil {
|
||||||
|
val = envValBool
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
eachName(f.Name, func(name string) {
|
||||||
|
if f.Destination != nil {
|
||||||
|
set.BoolVar(f.Destination, name, val, f.Usage)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
set.Bool(name, val, f.Usage)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f BoolTFlag) GetName() string {
|
||||||
|
return f.Name
|
||||||
|
}
|
||||||
|
|
||||||
|
// StringFlag represents a flag that takes as string value
|
||||||
|
type StringFlag struct {
|
||||||
|
Name string
|
||||||
|
Value string
|
||||||
|
Usage string
|
||||||
|
EnvVar string
|
||||||
|
Destination *string
|
||||||
|
}
|
||||||
|
|
||||||
|
// String returns the usage
|
||||||
|
func (f StringFlag) String() string {
|
||||||
|
var fmtString string
|
||||||
|
fmtString = "%s %v\t%v"
|
||||||
|
|
||||||
|
if len(f.Value) > 0 {
|
||||||
|
fmtString = "%s \"%v\"\t%v"
|
||||||
|
} else {
|
||||||
|
fmtString = "%s %v\t%v"
|
||||||
|
}
|
||||||
|
|
||||||
|
return withEnvHint(f.EnvVar, fmt.Sprintf(fmtString, prefixedNames(f.Name), f.Value, f.Usage))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply populates the flag given the flag set and environment
|
||||||
|
func (f StringFlag) Apply(set *flag.FlagSet) {
|
||||||
|
if f.EnvVar != "" {
|
||||||
|
for _, envVar := range strings.Split(f.EnvVar, ",") {
|
||||||
|
envVar = strings.TrimSpace(envVar)
|
||||||
|
if envVal := os.Getenv(envVar); envVal != "" {
|
||||||
|
f.Value = envVal
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
eachName(f.Name, func(name string) {
|
||||||
|
if f.Destination != nil {
|
||||||
|
set.StringVar(f.Destination, name, f.Value, f.Usage)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
set.String(name, f.Value, f.Usage)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f StringFlag) GetName() string {
|
||||||
|
return f.Name
|
||||||
|
}
|
||||||
|
|
||||||
|
// IntFlag is a flag that takes an integer
|
||||||
|
// Errors if the value provided cannot be parsed
|
||||||
|
type IntFlag struct {
|
||||||
|
Name string
|
||||||
|
Value int
|
||||||
|
Usage string
|
||||||
|
EnvVar string
|
||||||
|
Destination *int
|
||||||
|
}
|
||||||
|
|
||||||
|
// String returns the usage
|
||||||
|
func (f IntFlag) String() string {
|
||||||
|
return withEnvHint(f.EnvVar, fmt.Sprintf("%s \"%v\"\t%v", prefixedNames(f.Name), f.Value, f.Usage))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply populates the flag given the flag set and environment
|
||||||
|
func (f IntFlag) Apply(set *flag.FlagSet) {
|
||||||
|
if f.EnvVar != "" {
|
||||||
|
for _, envVar := range strings.Split(f.EnvVar, ",") {
|
||||||
|
envVar = strings.TrimSpace(envVar)
|
||||||
|
if envVal := os.Getenv(envVar); envVal != "" {
|
||||||
|
envValInt, err := strconv.ParseInt(envVal, 0, 64)
|
||||||
|
if err == nil {
|
||||||
|
f.Value = int(envValInt)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
eachName(f.Name, func(name string) {
|
||||||
|
if f.Destination != nil {
|
||||||
|
set.IntVar(f.Destination, name, f.Value, f.Usage)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
set.Int(name, f.Value, f.Usage)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f IntFlag) GetName() string {
|
||||||
|
return f.Name
|
||||||
|
}
|
||||||
|
|
||||||
|
// DurationFlag is a flag that takes a duration specified in Go's duration
|
||||||
|
// format: https://golang.org/pkg/time/#ParseDuration
|
||||||
|
type DurationFlag struct {
|
||||||
|
Name string
|
||||||
|
Value time.Duration
|
||||||
|
Usage string
|
||||||
|
EnvVar string
|
||||||
|
Destination *time.Duration
|
||||||
|
}
|
||||||
|
|
||||||
|
// String returns a readable representation of this value (for usage defaults)
|
||||||
|
func (f DurationFlag) String() string {
|
||||||
|
return withEnvHint(f.EnvVar, fmt.Sprintf("%s \"%v\"\t%v", prefixedNames(f.Name), f.Value, f.Usage))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply populates the flag given the flag set and environment
|
||||||
|
func (f DurationFlag) Apply(set *flag.FlagSet) {
|
||||||
|
if f.EnvVar != "" {
|
||||||
|
for _, envVar := range strings.Split(f.EnvVar, ",") {
|
||||||
|
envVar = strings.TrimSpace(envVar)
|
||||||
|
if envVal := os.Getenv(envVar); envVal != "" {
|
||||||
|
envValDuration, err := time.ParseDuration(envVal)
|
||||||
|
if err == nil {
|
||||||
|
f.Value = envValDuration
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
eachName(f.Name, func(name string) {
|
||||||
|
if f.Destination != nil {
|
||||||
|
set.DurationVar(f.Destination, name, f.Value, f.Usage)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
set.Duration(name, f.Value, f.Usage)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f DurationFlag) GetName() string {
|
||||||
|
return f.Name
|
||||||
|
}
|
||||||
|
|
||||||
|
// Float64Flag is a flag that takes an float value
|
||||||
|
// Errors if the value provided cannot be parsed
|
||||||
|
type Float64Flag struct {
|
||||||
|
Name string
|
||||||
|
Value float64
|
||||||
|
Usage string
|
||||||
|
EnvVar string
|
||||||
|
Destination *float64
|
||||||
|
}
|
||||||
|
|
||||||
|
// String returns the usage
|
||||||
|
func (f Float64Flag) String() string {
|
||||||
|
return withEnvHint(f.EnvVar, fmt.Sprintf("%s \"%v\"\t%v", prefixedNames(f.Name), f.Value, f.Usage))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply populates the flag given the flag set and environment
|
||||||
|
func (f Float64Flag) Apply(set *flag.FlagSet) {
|
||||||
|
if f.EnvVar != "" {
|
||||||
|
for _, envVar := range strings.Split(f.EnvVar, ",") {
|
||||||
|
envVar = strings.TrimSpace(envVar)
|
||||||
|
if envVal := os.Getenv(envVar); envVal != "" {
|
||||||
|
envValFloat, err := strconv.ParseFloat(envVal, 10)
|
||||||
|
if err == nil {
|
||||||
|
f.Value = float64(envValFloat)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
eachName(f.Name, func(name string) {
|
||||||
|
if f.Destination != nil {
|
||||||
|
set.Float64Var(f.Destination, name, f.Value, f.Usage)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
set.Float64(name, f.Value, f.Usage)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f Float64Flag) GetName() string {
|
||||||
|
return f.Name
|
||||||
|
}
|
||||||
|
|
||||||
|
func prefixFor(name string) (prefix string) {
|
||||||
|
if len(name) == 1 {
|
||||||
|
prefix = "-"
|
||||||
|
} else {
|
||||||
|
prefix = "--"
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func prefixedNames(fullName string) (prefixed string) {
|
||||||
|
parts := strings.Split(fullName, ",")
|
||||||
|
for i, name := range parts {
|
||||||
|
name = strings.Trim(name, " ")
|
||||||
|
prefixed += prefixFor(name) + name
|
||||||
|
if i < len(parts)-1 {
|
||||||
|
prefixed += ", "
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func withEnvHint(envVar, str string) string {
|
||||||
|
envText := ""
|
||||||
|
if envVar != "" {
|
||||||
|
envText = fmt.Sprintf(" [$%s]", strings.Join(strings.Split(envVar, ","), ", $"))
|
||||||
|
}
|
||||||
|
return str + envText
|
||||||
|
}
|
246
vendor/src/github.com/codegangsta/cli/help.go
vendored
Normal file
246
vendor/src/github.com/codegangsta/cli/help.go
vendored
Normal file
|
@ -0,0 +1,246 @@
|
||||||
|
package cli
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"strings"
|
||||||
|
"text/tabwriter"
|
||||||
|
"text/template"
|
||||||
|
)
|
||||||
|
|
||||||
|
// The text template for the Default help topic.
|
||||||
|
// cli.go uses text/template to render templates. You can
|
||||||
|
// render custom help text by setting this variable.
|
||||||
|
var AppHelpTemplate = `NAME:
|
||||||
|
{{.Name}} - {{.Usage}}
|
||||||
|
|
||||||
|
USAGE:
|
||||||
|
{{.HelpName}} {{if .Flags}}[global options]{{end}}{{if .Commands}} command [command options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments...]{{end}}
|
||||||
|
{{if .Version}}
|
||||||
|
VERSION:
|
||||||
|
{{.Version}}
|
||||||
|
{{end}}{{if len .Authors}}
|
||||||
|
AUTHOR(S):
|
||||||
|
{{range .Authors}}{{ . }}{{end}}
|
||||||
|
{{end}}{{if .Commands}}
|
||||||
|
COMMANDS:
|
||||||
|
{{range .Commands}}{{join .Names ", "}}{{ "\t" }}{{.Usage}}
|
||||||
|
{{end}}{{end}}{{if .Flags}}
|
||||||
|
GLOBAL OPTIONS:
|
||||||
|
{{range .Flags}}{{.}}
|
||||||
|
{{end}}{{end}}{{if .Copyright }}
|
||||||
|
COPYRIGHT:
|
||||||
|
{{.Copyright}}
|
||||||
|
{{end}}
|
||||||
|
`
|
||||||
|
|
||||||
|
// The text template for the command help topic.
|
||||||
|
// cli.go uses text/template to render templates. You can
|
||||||
|
// render custom help text by setting this variable.
|
||||||
|
var CommandHelpTemplate = `NAME:
|
||||||
|
{{.HelpName}} - {{.Usage}}
|
||||||
|
|
||||||
|
USAGE:
|
||||||
|
{{.HelpName}}{{if .Flags}} [command options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments...]{{end}}{{if .Description}}
|
||||||
|
|
||||||
|
DESCRIPTION:
|
||||||
|
{{.Description}}{{end}}{{if .Flags}}
|
||||||
|
|
||||||
|
OPTIONS:
|
||||||
|
{{range .Flags}}{{.}}
|
||||||
|
{{end}}{{ end }}
|
||||||
|
`
|
||||||
|
|
||||||
|
// The text template for the subcommand help topic.
|
||||||
|
// cli.go uses text/template to render templates. You can
|
||||||
|
// render custom help text by setting this variable.
|
||||||
|
var SubcommandHelpTemplate = `NAME:
|
||||||
|
{{.HelpName}} - {{.Usage}}
|
||||||
|
|
||||||
|
USAGE:
|
||||||
|
{{.HelpName}} command{{if .Flags}} [command options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments...]{{end}}
|
||||||
|
|
||||||
|
COMMANDS:
|
||||||
|
{{range .Commands}}{{join .Names ", "}}{{ "\t" }}{{.Usage}}
|
||||||
|
{{end}}{{if .Flags}}
|
||||||
|
OPTIONS:
|
||||||
|
{{range .Flags}}{{.}}
|
||||||
|
{{end}}{{end}}
|
||||||
|
`
|
||||||
|
|
||||||
|
var helpCommand = Command{
|
||||||
|
Name: "help",
|
||||||
|
Aliases: []string{"h"},
|
||||||
|
Usage: "Shows a list of commands or help for one command",
|
||||||
|
ArgsUsage: "[command]",
|
||||||
|
Action: func(c *Context) {
|
||||||
|
args := c.Args()
|
||||||
|
if args.Present() {
|
||||||
|
ShowCommandHelp(c, args.First())
|
||||||
|
} else {
|
||||||
|
ShowAppHelp(c)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
var helpSubcommand = Command{
|
||||||
|
Name: "help",
|
||||||
|
Aliases: []string{"h"},
|
||||||
|
Usage: "Shows a list of commands or help for one command",
|
||||||
|
ArgsUsage: "[command]",
|
||||||
|
Action: func(c *Context) {
|
||||||
|
args := c.Args()
|
||||||
|
if args.Present() {
|
||||||
|
ShowCommandHelp(c, args.First())
|
||||||
|
} else {
|
||||||
|
ShowSubcommandHelp(c)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prints help for the App or Command
|
||||||
|
type helpPrinter func(w io.Writer, templ string, data interface{})
|
||||||
|
|
||||||
|
var HelpPrinter helpPrinter = printHelp
|
||||||
|
|
||||||
|
// Prints version for the App
|
||||||
|
var VersionPrinter = printVersion
|
||||||
|
|
||||||
|
func ShowAppHelp(c *Context) {
|
||||||
|
HelpPrinter(c.App.Writer, AppHelpTemplate, c.App)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prints the list of subcommands as the default app completion method
|
||||||
|
func DefaultAppComplete(c *Context) {
|
||||||
|
for _, command := range c.App.Commands {
|
||||||
|
for _, name := range command.Names() {
|
||||||
|
fmt.Fprintln(c.App.Writer, name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prints help for the given command
|
||||||
|
func ShowCommandHelp(ctx *Context, command string) {
|
||||||
|
// show the subcommand help for a command with subcommands
|
||||||
|
if command == "" {
|
||||||
|
HelpPrinter(ctx.App.Writer, SubcommandHelpTemplate, ctx.App)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, c := range ctx.App.Commands {
|
||||||
|
if c.HasName(command) {
|
||||||
|
HelpPrinter(ctx.App.Writer, CommandHelpTemplate, c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ctx.App.CommandNotFound != nil {
|
||||||
|
ctx.App.CommandNotFound(ctx, command)
|
||||||
|
} else {
|
||||||
|
fmt.Fprintf(ctx.App.Writer, "No help topic for '%v'\n", command)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prints help for the given subcommand
|
||||||
|
func ShowSubcommandHelp(c *Context) {
|
||||||
|
ShowCommandHelp(c, c.Command.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prints the version number of the App
|
||||||
|
func ShowVersion(c *Context) {
|
||||||
|
VersionPrinter(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
func printVersion(c *Context) {
|
||||||
|
fmt.Fprintf(c.App.Writer, "%v version %v\n", c.App.Name, c.App.Version)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prints the lists of commands within a given context
|
||||||
|
func ShowCompletions(c *Context) {
|
||||||
|
a := c.App
|
||||||
|
if a != nil && a.BashComplete != nil {
|
||||||
|
a.BashComplete(c)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prints the custom completions for a given command
|
||||||
|
func ShowCommandCompletions(ctx *Context, command string) {
|
||||||
|
c := ctx.App.Command(command)
|
||||||
|
if c != nil && c.BashComplete != nil {
|
||||||
|
c.BashComplete(ctx)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func printHelp(out io.Writer, templ string, data interface{}) {
|
||||||
|
funcMap := template.FuncMap{
|
||||||
|
"join": strings.Join,
|
||||||
|
}
|
||||||
|
|
||||||
|
w := tabwriter.NewWriter(out, 0, 8, 1, '\t', 0)
|
||||||
|
t := template.Must(template.New("help").Funcs(funcMap).Parse(templ))
|
||||||
|
err := t.Execute(w, data)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
w.Flush()
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkVersion(c *Context) bool {
|
||||||
|
found := false
|
||||||
|
if VersionFlag.Name != "" {
|
||||||
|
eachName(VersionFlag.Name, func(name string) {
|
||||||
|
if c.GlobalBool(name) || c.Bool(name) {
|
||||||
|
found = true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return found
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkHelp(c *Context) bool {
|
||||||
|
found := false
|
||||||
|
if HelpFlag.Name != "" {
|
||||||
|
eachName(HelpFlag.Name, func(name string) {
|
||||||
|
if c.GlobalBool(name) || c.Bool(name) {
|
||||||
|
found = true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return found
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkCommandHelp(c *Context, name string) bool {
|
||||||
|
if c.Bool("h") || c.Bool("help") {
|
||||||
|
ShowCommandHelp(c, name)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkSubcommandHelp(c *Context) bool {
|
||||||
|
if c.GlobalBool("h") || c.GlobalBool("help") {
|
||||||
|
ShowSubcommandHelp(c)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkCompletions(c *Context) bool {
|
||||||
|
if (c.GlobalBool(BashCompletionFlag.Name) || c.Bool(BashCompletionFlag.Name)) && c.App.EnableBashCompletion {
|
||||||
|
ShowCompletions(c)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkCommandCompletions(c *Context, name string) bool {
|
||||||
|
if c.Bool(BashCompletionFlag.Name) && c.App.EnableBashCompletion {
|
||||||
|
ShowCommandCompletions(c, name)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
191
vendor/src/github.com/coreos/go-systemd/LICENSE
vendored
Normal file
191
vendor/src/github.com/coreos/go-systemd/LICENSE
vendored
Normal file
|
@ -0,0 +1,191 @@
|
||||||
|
Apache License
|
||||||
|
Version 2.0, January 2004
|
||||||
|
http://www.apache.org/licenses/
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||||
|
|
||||||
|
1. Definitions.
|
||||||
|
|
||||||
|
"License" shall mean the terms and conditions for use, reproduction, and
|
||||||
|
distribution as defined by Sections 1 through 9 of this document.
|
||||||
|
|
||||||
|
"Licensor" shall mean the copyright owner or entity authorized by the copyright
|
||||||
|
owner that is granting the License.
|
||||||
|
|
||||||
|
"Legal Entity" shall mean the union of the acting entity and all other entities
|
||||||
|
that control, are controlled by, or are under common control with that entity.
|
||||||
|
For the purposes of this definition, "control" means (i) the power, direct or
|
||||||
|
indirect, to cause the direction or management of such entity, whether by
|
||||||
|
contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||||
|
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||||
|
|
||||||
|
"You" (or "Your") shall mean an individual or Legal Entity exercising
|
||||||
|
permissions granted by this License.
|
||||||
|
|
||||||
|
"Source" form shall mean the preferred form for making modifications, including
|
||||||
|
but not limited to software source code, documentation source, and configuration
|
||||||
|
files.
|
||||||
|
|
||||||
|
"Object" form shall mean any form resulting from mechanical transformation or
|
||||||
|
translation of a Source form, including but not limited to compiled object code,
|
||||||
|
generated documentation, and conversions to other media types.
|
||||||
|
|
||||||
|
"Work" shall mean the work of authorship, whether in Source or Object form, made
|
||||||
|
available under the License, as indicated by a copyright notice that is included
|
||||||
|
in or attached to the work (an example is provided in the Appendix below).
|
||||||
|
|
||||||
|
"Derivative Works" shall mean any work, whether in Source or Object form, that
|
||||||
|
is based on (or derived from) the Work and for which the editorial revisions,
|
||||||
|
annotations, elaborations, or other modifications represent, as a whole, an
|
||||||
|
original work of authorship. For the purposes of this License, Derivative Works
|
||||||
|
shall not include works that remain separable from, or merely link (or bind by
|
||||||
|
name) to the interfaces of, the Work and Derivative Works thereof.
|
||||||
|
|
||||||
|
"Contribution" shall mean any work of authorship, including the original version
|
||||||
|
of the Work and any modifications or additions to that Work or Derivative Works
|
||||||
|
thereof, that is intentionally submitted to Licensor for inclusion in the Work
|
||||||
|
by the copyright owner or by an individual or Legal Entity authorized to submit
|
||||||
|
on behalf of the copyright owner. For the purposes of this definition,
|
||||||
|
"submitted" means any form of electronic, verbal, or written communication sent
|
||||||
|
to the Licensor or its representatives, including but not limited to
|
||||||
|
communication on electronic mailing lists, source code control systems, and
|
||||||
|
issue tracking systems that are managed by, or on behalf of, the Licensor for
|
||||||
|
the purpose of discussing and improving the Work, but excluding communication
|
||||||
|
that is conspicuously marked or otherwise designated in writing by the copyright
|
||||||
|
owner as "Not a Contribution."
|
||||||
|
|
||||||
|
"Contributor" shall mean Licensor and any individual or Legal Entity on behalf
|
||||||
|
of whom a Contribution has been received by Licensor and subsequently
|
||||||
|
incorporated within the Work.
|
||||||
|
|
||||||
|
2. Grant of Copyright License.
|
||||||
|
|
||||||
|
Subject to the terms and conditions of this License, each Contributor hereby
|
||||||
|
grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
|
||||||
|
irrevocable copyright license to reproduce, prepare Derivative Works of,
|
||||||
|
publicly display, publicly perform, sublicense, and distribute the Work and such
|
||||||
|
Derivative Works in Source or Object form.
|
||||||
|
|
||||||
|
3. Grant of Patent License.
|
||||||
|
|
||||||
|
Subject to the terms and conditions of this License, each Contributor 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, and otherwise transfer the Work, where
|
||||||
|
such license applies only to those patent claims licensable by such Contributor
|
||||||
|
that are necessarily infringed by their Contribution(s) alone or by combination
|
||||||
|
of their Contribution(s) with the Work to which such Contribution(s) was
|
||||||
|
submitted. If You institute patent litigation against any entity (including a
|
||||||
|
cross-claim or counterclaim in a lawsuit) alleging that the Work or a
|
||||||
|
Contribution incorporated within the Work constitutes direct or contributory
|
||||||
|
patent infringement, then any patent licenses granted to You under this License
|
||||||
|
for that Work shall terminate as of the date such litigation is filed.
|
||||||
|
|
||||||
|
4. Redistribution.
|
||||||
|
|
||||||
|
You may reproduce and distribute copies of the Work or Derivative Works thereof
|
||||||
|
in any medium, with or without modifications, and in Source or Object form,
|
||||||
|
provided that You meet the following conditions:
|
||||||
|
|
||||||
|
You must give any other recipients of the Work or Derivative Works a copy of
|
||||||
|
this License; and
|
||||||
|
You must cause any modified files to carry prominent notices stating that You
|
||||||
|
changed the files; and
|
||||||
|
You must retain, in the Source form of any Derivative Works that You distribute,
|
||||||
|
all copyright, patent, trademark, and attribution notices from the Source form
|
||||||
|
of the Work, excluding those notices that do not pertain to any part of the
|
||||||
|
Derivative Works; and
|
||||||
|
If the Work includes a "NOTICE" text file as part of its distribution, then any
|
||||||
|
Derivative Works that You distribute must include a readable copy of the
|
||||||
|
attribution notices contained within such NOTICE file, excluding those notices
|
||||||
|
that do not pertain to any part of the Derivative Works, in at least one of the
|
||||||
|
following places: within a NOTICE text file distributed as part of the
|
||||||
|
Derivative Works; within the Source form or documentation, if provided along
|
||||||
|
with the Derivative Works; or, within a display generated by the Derivative
|
||||||
|
Works, if and wherever such third-party notices normally appear. The contents of
|
||||||
|
the NOTICE file are for informational purposes only and do not modify the
|
||||||
|
License. You may add Your own attribution notices within Derivative Works that
|
||||||
|
You distribute, alongside or as an addendum to the NOTICE text from the Work,
|
||||||
|
provided that such additional attribution notices cannot be construed as
|
||||||
|
modifying the License.
|
||||||
|
You may add Your own copyright statement to Your modifications and may provide
|
||||||
|
additional or different license terms and conditions for use, reproduction, or
|
||||||
|
distribution of Your modifications, or for any such Derivative Works as a whole,
|
||||||
|
provided Your use, reproduction, and distribution of the Work otherwise complies
|
||||||
|
with the conditions stated in this License.
|
||||||
|
|
||||||
|
5. Submission of Contributions.
|
||||||
|
|
||||||
|
Unless You explicitly state otherwise, any Contribution intentionally submitted
|
||||||
|
for inclusion in the Work by You to the Licensor shall be under the terms and
|
||||||
|
conditions of this License, without any additional terms or conditions.
|
||||||
|
Notwithstanding the above, nothing herein shall supersede or modify the terms of
|
||||||
|
any separate license agreement you may have executed with Licensor regarding
|
||||||
|
such Contributions.
|
||||||
|
|
||||||
|
6. Trademarks.
|
||||||
|
|
||||||
|
This License does not grant permission to use the trade names, trademarks,
|
||||||
|
service marks, or product names of the Licensor, except as required for
|
||||||
|
reasonable and customary use in describing the origin of the Work and
|
||||||
|
reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
|
7. Disclaimer of Warranty.
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, Licensor provides the
|
||||||
|
Work (and each Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
|
||||||
|
including, without limitation, any warranties or conditions of TITLE,
|
||||||
|
NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are
|
||||||
|
solely responsible for determining the appropriateness of using or
|
||||||
|
redistributing the Work and assume any risks associated with Your exercise of
|
||||||
|
permissions under this License.
|
||||||
|
|
||||||
|
8. Limitation of Liability.
|
||||||
|
|
||||||
|
In no event and under no legal theory, whether in tort (including negligence),
|
||||||
|
contract, or otherwise, unless required by applicable law (such as deliberate
|
||||||
|
and grossly negligent acts) or agreed to in writing, shall any Contributor be
|
||||||
|
liable to You for damages, including any direct, indirect, special, incidental,
|
||||||
|
or consequential damages of any character arising as a result of this License or
|
||||||
|
out of the use or inability to use the Work (including but not limited to
|
||||||
|
damages for loss of goodwill, work stoppage, computer failure or malfunction, or
|
||||||
|
any and all other commercial damages or losses), even if such Contributor has
|
||||||
|
been advised of the possibility of such damages.
|
||||||
|
|
||||||
|
9. Accepting Warranty or Additional Liability.
|
||||||
|
|
||||||
|
While redistributing the Work or Derivative Works thereof, You may choose to
|
||||||
|
offer, and charge a fee for, acceptance of support, warranty, indemnity, or
|
||||||
|
other liability obligations and/or rights consistent with this License. However,
|
||||||
|
in accepting such obligations, You may act only on Your own behalf and on Your
|
||||||
|
sole responsibility, not on behalf of any other Contributor, and only if You
|
||||||
|
agree to indemnify, defend, and hold each Contributor harmless for any liability
|
||||||
|
incurred by, or claims asserted against, such Contributor by reason of your
|
||||||
|
accepting any such warranty or additional liability.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
APPENDIX: How to apply the Apache License to your work
|
||||||
|
|
||||||
|
To apply the Apache License to your work, attach the following boilerplate
|
||||||
|
notice, with the fields enclosed by brackets "[]" replaced with your own
|
||||||
|
identifying information. (Don't include the brackets!) The text should be
|
||||||
|
enclosed in the appropriate comment syntax for the file format. We also
|
||||||
|
recommend that a file or class name and description of purpose be included on
|
||||||
|
the same "printed page" as the copyright notice for easier identification within
|
||||||
|
third-party archives.
|
||||||
|
|
||||||
|
Copyright [yyyy] [name of copyright owner]
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
198
vendor/src/github.com/coreos/go-systemd/dbus/dbus.go
vendored
Normal file
198
vendor/src/github.com/coreos/go-systemd/dbus/dbus.go
vendored
Normal file
|
@ -0,0 +1,198 @@
|
||||||
|
// Copyright 2015 CoreOS, Inc.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
// Integration with the systemd D-Bus API. See http://www.freedesktop.org/wiki/Software/systemd/dbus/
|
||||||
|
package dbus
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/godbus/dbus"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
alpha = `abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ`
|
||||||
|
num = `0123456789`
|
||||||
|
alphanum = alpha + num
|
||||||
|
signalBuffer = 100
|
||||||
|
)
|
||||||
|
|
||||||
|
// needsEscape checks whether a byte in a potential dbus ObjectPath needs to be escaped
|
||||||
|
func needsEscape(i int, b byte) bool {
|
||||||
|
// Escape everything that is not a-z-A-Z-0-9
|
||||||
|
// Also escape 0-9 if it's the first character
|
||||||
|
return strings.IndexByte(alphanum, b) == -1 ||
|
||||||
|
(i == 0 && strings.IndexByte(num, b) != -1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// PathBusEscape sanitizes a constituent string of a dbus ObjectPath using the
|
||||||
|
// rules that systemd uses for serializing special characters.
|
||||||
|
func PathBusEscape(path string) string {
|
||||||
|
// Special case the empty string
|
||||||
|
if len(path) == 0 {
|
||||||
|
return "_"
|
||||||
|
}
|
||||||
|
n := []byte{}
|
||||||
|
for i := 0; i < len(path); i++ {
|
||||||
|
c := path[i]
|
||||||
|
if needsEscape(i, c) {
|
||||||
|
e := fmt.Sprintf("_%x", c)
|
||||||
|
n = append(n, []byte(e)...)
|
||||||
|
} else {
|
||||||
|
n = append(n, c)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return string(n)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Conn is a connection to systemd's dbus endpoint.
|
||||||
|
type Conn struct {
|
||||||
|
// sysconn/sysobj are only used to call dbus methods
|
||||||
|
sysconn *dbus.Conn
|
||||||
|
sysobj dbus.BusObject
|
||||||
|
|
||||||
|
// sigconn/sigobj are only used to receive dbus signals
|
||||||
|
sigconn *dbus.Conn
|
||||||
|
sigobj dbus.BusObject
|
||||||
|
|
||||||
|
jobListener struct {
|
||||||
|
jobs map[dbus.ObjectPath]chan<- string
|
||||||
|
sync.Mutex
|
||||||
|
}
|
||||||
|
subscriber struct {
|
||||||
|
updateCh chan<- *SubStateUpdate
|
||||||
|
errCh chan<- error
|
||||||
|
sync.Mutex
|
||||||
|
ignore map[dbus.ObjectPath]int64
|
||||||
|
cleanIgnore int64
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// New establishes a connection to the system bus and authenticates.
|
||||||
|
// Callers should call Close() when done with the connection.
|
||||||
|
func New() (*Conn, error) {
|
||||||
|
return newConnection(func() (*dbus.Conn, error) {
|
||||||
|
return dbusAuthHelloConnection(dbus.SystemBusPrivate)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewUserConnection establishes a connection to the session bus and
|
||||||
|
// authenticates. This can be used to connect to systemd user instances.
|
||||||
|
// Callers should call Close() when done with the connection.
|
||||||
|
func NewUserConnection() (*Conn, error) {
|
||||||
|
return newConnection(func() (*dbus.Conn, error) {
|
||||||
|
return dbusAuthHelloConnection(dbus.SessionBusPrivate)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewSystemdConnection establishes a private, direct connection to systemd.
|
||||||
|
// This can be used for communicating with systemd without a dbus daemon.
|
||||||
|
// Callers should call Close() when done with the connection.
|
||||||
|
func NewSystemdConnection() (*Conn, error) {
|
||||||
|
return newConnection(func() (*dbus.Conn, error) {
|
||||||
|
// We skip Hello when talking directly to systemd.
|
||||||
|
return dbusAuthConnection(func() (*dbus.Conn, error) {
|
||||||
|
return dbus.Dial("unix:path=/run/systemd/private")
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close closes an established connection
|
||||||
|
func (c *Conn) Close() {
|
||||||
|
c.sysconn.Close()
|
||||||
|
c.sigconn.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
func newConnection(createBus func() (*dbus.Conn, error)) (*Conn, error) {
|
||||||
|
sysconn, err := createBus()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
sigconn, err := createBus()
|
||||||
|
if err != nil {
|
||||||
|
sysconn.Close()
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
c := &Conn{
|
||||||
|
sysconn: sysconn,
|
||||||
|
sysobj: systemdObject(sysconn),
|
||||||
|
sigconn: sigconn,
|
||||||
|
sigobj: systemdObject(sigconn),
|
||||||
|
}
|
||||||
|
|
||||||
|
c.subscriber.ignore = make(map[dbus.ObjectPath]int64)
|
||||||
|
c.jobListener.jobs = make(map[dbus.ObjectPath]chan<- string)
|
||||||
|
|
||||||
|
// Setup the listeners on jobs so that we can get completions
|
||||||
|
c.sigconn.BusObject().Call("org.freedesktop.DBus.AddMatch", 0,
|
||||||
|
"type='signal', interface='org.freedesktop.systemd1.Manager', member='JobRemoved'")
|
||||||
|
|
||||||
|
c.dispatch()
|
||||||
|
return c, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetManagerProperty returns the value of a property on the org.freedesktop.systemd1.Manager
|
||||||
|
// interface. The value is returned in its string representation, as defined at
|
||||||
|
// https://developer.gnome.org/glib/unstable/gvariant-text.html
|
||||||
|
func (c *Conn) GetManagerProperty(prop string) (string, error) {
|
||||||
|
variant, err := c.sysobj.GetProperty("org.freedesktop.systemd1.Manager." + prop)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return variant.String(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func dbusAuthConnection(createBus func() (*dbus.Conn, error)) (*dbus.Conn, error) {
|
||||||
|
conn, err := createBus()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only use EXTERNAL method, and hardcode the uid (not username)
|
||||||
|
// to avoid a username lookup (which requires a dynamically linked
|
||||||
|
// libc)
|
||||||
|
methods := []dbus.Auth{dbus.AuthExternal(strconv.Itoa(os.Getuid()))}
|
||||||
|
|
||||||
|
err = conn.Auth(methods)
|
||||||
|
if err != nil {
|
||||||
|
conn.Close()
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return conn, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func dbusAuthHelloConnection(createBus func() (*dbus.Conn, error)) (*dbus.Conn, error) {
|
||||||
|
conn, err := dbusAuthConnection(createBus)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = conn.Hello(); err != nil {
|
||||||
|
conn.Close()
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return conn, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func systemdObject(conn *dbus.Conn) dbus.BusObject {
|
||||||
|
return conn.Object("org.freedesktop.systemd1", dbus.ObjectPath("/org/freedesktop/systemd1"))
|
||||||
|
}
|
442
vendor/src/github.com/coreos/go-systemd/dbus/methods.go
vendored
Normal file
442
vendor/src/github.com/coreos/go-systemd/dbus/methods.go
vendored
Normal file
|
@ -0,0 +1,442 @@
|
||||||
|
// Copyright 2015 CoreOS, Inc.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package dbus
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"path"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"github.com/godbus/dbus"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (c *Conn) jobComplete(signal *dbus.Signal) {
|
||||||
|
var id uint32
|
||||||
|
var job dbus.ObjectPath
|
||||||
|
var unit string
|
||||||
|
var result string
|
||||||
|
dbus.Store(signal.Body, &id, &job, &unit, &result)
|
||||||
|
c.jobListener.Lock()
|
||||||
|
out, ok := c.jobListener.jobs[job]
|
||||||
|
if ok {
|
||||||
|
out <- result
|
||||||
|
delete(c.jobListener.jobs, job)
|
||||||
|
}
|
||||||
|
c.jobListener.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Conn) startJob(ch chan<- string, job string, args ...interface{}) (int, error) {
|
||||||
|
if ch != nil {
|
||||||
|
c.jobListener.Lock()
|
||||||
|
defer c.jobListener.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
var p dbus.ObjectPath
|
||||||
|
err := c.sysobj.Call(job, 0, args...).Store(&p)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if ch != nil {
|
||||||
|
c.jobListener.jobs[p] = ch
|
||||||
|
}
|
||||||
|
|
||||||
|
// ignore error since 0 is fine if conversion fails
|
||||||
|
jobID, _ := strconv.Atoi(path.Base(string(p)))
|
||||||
|
|
||||||
|
return jobID, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// StartUnit enqueues a start job and depending jobs, if any (unless otherwise
|
||||||
|
// specified by the mode string).
|
||||||
|
//
|
||||||
|
// Takes the unit to activate, plus a mode string. The mode needs to be one of
|
||||||
|
// replace, fail, isolate, ignore-dependencies, ignore-requirements. If
|
||||||
|
// "replace" the call will start the unit and its dependencies, possibly
|
||||||
|
// replacing already queued jobs that conflict with this. If "fail" the call
|
||||||
|
// will start the unit and its dependencies, but will fail if this would change
|
||||||
|
// an already queued job. If "isolate" the call will start the unit in question
|
||||||
|
// and terminate all units that aren't dependencies of it. If
|
||||||
|
// "ignore-dependencies" it will start a unit but ignore all its dependencies.
|
||||||
|
// If "ignore-requirements" it will start a unit but only ignore the
|
||||||
|
// requirement dependencies. It is not recommended to make use of the latter
|
||||||
|
// two options.
|
||||||
|
//
|
||||||
|
// If the provided channel is non-nil, a result string will be sent to it upon
|
||||||
|
// job completion: one of done, canceled, timeout, failed, dependency, skipped.
|
||||||
|
// done indicates successful execution of a job. canceled indicates that a job
|
||||||
|
// has been canceled before it finished execution. timeout indicates that the
|
||||||
|
// job timeout was reached. failed indicates that the job failed. dependency
|
||||||
|
// indicates that a job this job has been depending on failed and the job hence
|
||||||
|
// has been removed too. skipped indicates that a job was skipped because it
|
||||||
|
// didn't apply to the units current state.
|
||||||
|
//
|
||||||
|
// If no error occurs, the ID of the underlying systemd job will be returned. There
|
||||||
|
// does exist the possibility for no error to be returned, but for the returned job
|
||||||
|
// ID to be 0. In this case, the actual underlying ID is not 0 and this datapoint
|
||||||
|
// should not be considered authoritative.
|
||||||
|
//
|
||||||
|
// If an error does occur, it will be returned to the user alongside a job ID of 0.
|
||||||
|
func (c *Conn) StartUnit(name string, mode string, ch chan<- string) (int, error) {
|
||||||
|
return c.startJob(ch, "org.freedesktop.systemd1.Manager.StartUnit", name, mode)
|
||||||
|
}
|
||||||
|
|
||||||
|
// StopUnit is similar to StartUnit but stops the specified unit rather
|
||||||
|
// than starting it.
|
||||||
|
func (c *Conn) StopUnit(name string, mode string, ch chan<- string) (int, error) {
|
||||||
|
return c.startJob(ch, "org.freedesktop.systemd1.Manager.StopUnit", name, mode)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReloadUnit reloads a unit. Reloading is done only if the unit is already running and fails otherwise.
|
||||||
|
func (c *Conn) ReloadUnit(name string, mode string, ch chan<- string) (int, error) {
|
||||||
|
return c.startJob(ch, "org.freedesktop.systemd1.Manager.ReloadUnit", name, mode)
|
||||||
|
}
|
||||||
|
|
||||||
|
// RestartUnit restarts a service. If a service is restarted that isn't
|
||||||
|
// running it will be started.
|
||||||
|
func (c *Conn) RestartUnit(name string, mode string, ch chan<- string) (int, error) {
|
||||||
|
return c.startJob(ch, "org.freedesktop.systemd1.Manager.RestartUnit", name, mode)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TryRestartUnit is like RestartUnit, except that a service that isn't running
|
||||||
|
// is not affected by the restart.
|
||||||
|
func (c *Conn) TryRestartUnit(name string, mode string, ch chan<- string) (int, error) {
|
||||||
|
return c.startJob(ch, "org.freedesktop.systemd1.Manager.TryRestartUnit", name, mode)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReloadOrRestart attempts a reload if the unit supports it and use a restart
|
||||||
|
// otherwise.
|
||||||
|
func (c *Conn) ReloadOrRestartUnit(name string, mode string, ch chan<- string) (int, error) {
|
||||||
|
return c.startJob(ch, "org.freedesktop.systemd1.Manager.ReloadOrRestartUnit", name, mode)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReloadOrTryRestart attempts a reload if the unit supports it and use a "Try"
|
||||||
|
// flavored restart otherwise.
|
||||||
|
func (c *Conn) ReloadOrTryRestartUnit(name string, mode string, ch chan<- string) (int, error) {
|
||||||
|
return c.startJob(ch, "org.freedesktop.systemd1.Manager.ReloadOrTryRestartUnit", name, mode)
|
||||||
|
}
|
||||||
|
|
||||||
|
// StartTransientUnit() may be used to create and start a transient unit, which
|
||||||
|
// will be released as soon as it is not running or referenced anymore or the
|
||||||
|
// system is rebooted. name is the unit name including suffix, and must be
|
||||||
|
// unique. mode is the same as in StartUnit(), properties contains properties
|
||||||
|
// of the unit.
|
||||||
|
func (c *Conn) StartTransientUnit(name string, mode string, properties []Property, ch chan<- string) (int, error) {
|
||||||
|
return c.startJob(ch, "org.freedesktop.systemd1.Manager.StartTransientUnit", name, mode, properties, make([]PropertyCollection, 0))
|
||||||
|
}
|
||||||
|
|
||||||
|
// KillUnit takes the unit name and a UNIX signal number to send. All of the unit's
|
||||||
|
// processes are killed.
|
||||||
|
func (c *Conn) KillUnit(name string, signal int32) {
|
||||||
|
c.sysobj.Call("org.freedesktop.systemd1.Manager.KillUnit", 0, name, "all", signal).Store()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ResetFailedUnit resets the "failed" state of a specific unit.
|
||||||
|
func (c *Conn) ResetFailedUnit(name string) error {
|
||||||
|
return c.sysobj.Call("org.freedesktop.systemd1.Manager.ResetFailedUnit", 0, name).Store()
|
||||||
|
}
|
||||||
|
|
||||||
|
// getProperties takes the unit name and returns all of its dbus object properties, for the given dbus interface
|
||||||
|
func (c *Conn) getProperties(unit string, dbusInterface string) (map[string]interface{}, error) {
|
||||||
|
var err error
|
||||||
|
var props map[string]dbus.Variant
|
||||||
|
|
||||||
|
path := unitPath(unit)
|
||||||
|
if !path.IsValid() {
|
||||||
|
return nil, errors.New("invalid unit name: " + unit)
|
||||||
|
}
|
||||||
|
|
||||||
|
obj := c.sysconn.Object("org.freedesktop.systemd1", path)
|
||||||
|
err = obj.Call("org.freedesktop.DBus.Properties.GetAll", 0, dbusInterface).Store(&props)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
out := make(map[string]interface{}, len(props))
|
||||||
|
for k, v := range props {
|
||||||
|
out[k] = v.Value()
|
||||||
|
}
|
||||||
|
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetUnitProperties takes the unit name and returns all of its dbus object properties.
|
||||||
|
func (c *Conn) GetUnitProperties(unit string) (map[string]interface{}, error) {
|
||||||
|
return c.getProperties(unit, "org.freedesktop.systemd1.Unit")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Conn) getProperty(unit string, dbusInterface string, propertyName string) (*Property, error) {
|
||||||
|
var err error
|
||||||
|
var prop dbus.Variant
|
||||||
|
|
||||||
|
path := unitPath(unit)
|
||||||
|
if !path.IsValid() {
|
||||||
|
return nil, errors.New("invalid unit name: " + unit)
|
||||||
|
}
|
||||||
|
|
||||||
|
obj := c.sysconn.Object("org.freedesktop.systemd1", path)
|
||||||
|
err = obj.Call("org.freedesktop.DBus.Properties.Get", 0, dbusInterface, propertyName).Store(&prop)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &Property{Name: propertyName, Value: prop}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Conn) GetUnitProperty(unit string, propertyName string) (*Property, error) {
|
||||||
|
return c.getProperty(unit, "org.freedesktop.systemd1.Unit", propertyName)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetUnitTypeProperties returns the extra properties for a unit, specific to the unit type.
|
||||||
|
// Valid values for unitType: Service, Socket, Target, Device, Mount, Automount, Snapshot, Timer, Swap, Path, Slice, Scope
|
||||||
|
// return "dbus.Error: Unknown interface" if the unitType is not the correct type of the unit
|
||||||
|
func (c *Conn) GetUnitTypeProperties(unit string, unitType string) (map[string]interface{}, error) {
|
||||||
|
return c.getProperties(unit, "org.freedesktop.systemd1."+unitType)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetUnitProperties() may be used to modify certain unit properties at runtime.
|
||||||
|
// Not all properties may be changed at runtime, but many resource management
|
||||||
|
// settings (primarily those in systemd.cgroup(5)) may. The changes are applied
|
||||||
|
// instantly, and stored on disk for future boots, unless runtime is true, in which
|
||||||
|
// case the settings only apply until the next reboot. name is the name of the unit
|
||||||
|
// to modify. properties are the settings to set, encoded as an array of property
|
||||||
|
// name and value pairs.
|
||||||
|
func (c *Conn) SetUnitProperties(name string, runtime bool, properties ...Property) error {
|
||||||
|
return c.sysobj.Call("org.freedesktop.systemd1.Manager.SetUnitProperties", 0, name, runtime, properties).Store()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Conn) GetUnitTypeProperty(unit string, unitType string, propertyName string) (*Property, error) {
|
||||||
|
return c.getProperty(unit, "org.freedesktop.systemd1."+unitType, propertyName)
|
||||||
|
}
|
||||||
|
|
||||||
|
type UnitStatus struct {
|
||||||
|
Name string // The primary unit name as string
|
||||||
|
Description string // The human readable description string
|
||||||
|
LoadState string // The load state (i.e. whether the unit file has been loaded successfully)
|
||||||
|
ActiveState string // The active state (i.e. whether the unit is currently started or not)
|
||||||
|
SubState string // The sub state (a more fine-grained version of the active state that is specific to the unit type, which the active state is not)
|
||||||
|
Followed string // A unit that is being followed in its state by this unit, if there is any, otherwise the empty string.
|
||||||
|
Path dbus.ObjectPath // The unit object path
|
||||||
|
JobId uint32 // If there is a job queued for the job unit the numeric job id, 0 otherwise
|
||||||
|
JobType string // The job type as string
|
||||||
|
JobPath dbus.ObjectPath // The job object path
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListUnits returns an array with all currently loaded units. Note that
|
||||||
|
// units may be known by multiple names at the same time, and hence there might
|
||||||
|
// be more unit names loaded than actual units behind them.
|
||||||
|
func (c *Conn) ListUnits() ([]UnitStatus, error) {
|
||||||
|
result := make([][]interface{}, 0)
|
||||||
|
err := c.sysobj.Call("org.freedesktop.systemd1.Manager.ListUnits", 0).Store(&result)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
resultInterface := make([]interface{}, len(result))
|
||||||
|
for i := range result {
|
||||||
|
resultInterface[i] = result[i]
|
||||||
|
}
|
||||||
|
|
||||||
|
status := make([]UnitStatus, len(result))
|
||||||
|
statusInterface := make([]interface{}, len(status))
|
||||||
|
for i := range status {
|
||||||
|
statusInterface[i] = &status[i]
|
||||||
|
}
|
||||||
|
|
||||||
|
err = dbus.Store(resultInterface, statusInterface...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return status, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type UnitFile struct {
|
||||||
|
Path string
|
||||||
|
Type string
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListUnitFiles returns an array of all available units on disk.
|
||||||
|
func (c *Conn) ListUnitFiles() ([]UnitFile, error) {
|
||||||
|
result := make([][]interface{}, 0)
|
||||||
|
err := c.sysobj.Call("org.freedesktop.systemd1.Manager.ListUnitFiles", 0).Store(&result)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
resultInterface := make([]interface{}, len(result))
|
||||||
|
for i := range result {
|
||||||
|
resultInterface[i] = result[i]
|
||||||
|
}
|
||||||
|
|
||||||
|
files := make([]UnitFile, len(result))
|
||||||
|
fileInterface := make([]interface{}, len(files))
|
||||||
|
for i := range files {
|
||||||
|
fileInterface[i] = &files[i]
|
||||||
|
}
|
||||||
|
|
||||||
|
err = dbus.Store(resultInterface, fileInterface...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return files, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type LinkUnitFileChange EnableUnitFileChange
|
||||||
|
|
||||||
|
// LinkUnitFiles() links unit files (that are located outside of the
|
||||||
|
// usual unit search paths) into the unit search path.
|
||||||
|
//
|
||||||
|
// It takes a list of absolute paths to unit files to link and two
|
||||||
|
// booleans. The first boolean controls whether the unit shall be
|
||||||
|
// enabled for runtime only (true, /run), or persistently (false,
|
||||||
|
// /etc).
|
||||||
|
// The second controls whether symlinks pointing to other units shall
|
||||||
|
// be replaced if necessary.
|
||||||
|
//
|
||||||
|
// This call returns a list of the changes made. The list consists of
|
||||||
|
// structures with three strings: the type of the change (one of symlink
|
||||||
|
// or unlink), the file name of the symlink and the destination of the
|
||||||
|
// symlink.
|
||||||
|
func (c *Conn) LinkUnitFiles(files []string, runtime bool, force bool) ([]LinkUnitFileChange, error) {
|
||||||
|
result := make([][]interface{}, 0)
|
||||||
|
err := c.sysobj.Call("org.freedesktop.systemd1.Manager.LinkUnitFiles", 0, files, runtime, force).Store(&result)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
resultInterface := make([]interface{}, len(result))
|
||||||
|
for i := range result {
|
||||||
|
resultInterface[i] = result[i]
|
||||||
|
}
|
||||||
|
|
||||||
|
changes := make([]LinkUnitFileChange, len(result))
|
||||||
|
changesInterface := make([]interface{}, len(changes))
|
||||||
|
for i := range changes {
|
||||||
|
changesInterface[i] = &changes[i]
|
||||||
|
}
|
||||||
|
|
||||||
|
err = dbus.Store(resultInterface, changesInterface...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return changes, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// EnableUnitFiles() may be used to enable one or more units in the system (by
|
||||||
|
// creating symlinks to them in /etc or /run).
|
||||||
|
//
|
||||||
|
// It takes a list of unit files to enable (either just file names or full
|
||||||
|
// absolute paths if the unit files are residing outside the usual unit
|
||||||
|
// search paths), and two booleans: the first controls whether the unit shall
|
||||||
|
// be enabled for runtime only (true, /run), or persistently (false, /etc).
|
||||||
|
// The second one controls whether symlinks pointing to other units shall
|
||||||
|
// be replaced if necessary.
|
||||||
|
//
|
||||||
|
// This call returns one boolean and an array with the changes made. The
|
||||||
|
// boolean signals whether the unit files contained any enablement
|
||||||
|
// information (i.e. an [Install]) section. The changes list consists of
|
||||||
|
// structures with three strings: the type of the change (one of symlink
|
||||||
|
// or unlink), the file name of the symlink and the destination of the
|
||||||
|
// symlink.
|
||||||
|
func (c *Conn) EnableUnitFiles(files []string, runtime bool, force bool) (bool, []EnableUnitFileChange, error) {
|
||||||
|
var carries_install_info bool
|
||||||
|
|
||||||
|
result := make([][]interface{}, 0)
|
||||||
|
err := c.sysobj.Call("org.freedesktop.systemd1.Manager.EnableUnitFiles", 0, files, runtime, force).Store(&carries_install_info, &result)
|
||||||
|
if err != nil {
|
||||||
|
return false, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
resultInterface := make([]interface{}, len(result))
|
||||||
|
for i := range result {
|
||||||
|
resultInterface[i] = result[i]
|
||||||
|
}
|
||||||
|
|
||||||
|
changes := make([]EnableUnitFileChange, len(result))
|
||||||
|
changesInterface := make([]interface{}, len(changes))
|
||||||
|
for i := range changes {
|
||||||
|
changesInterface[i] = &changes[i]
|
||||||
|
}
|
||||||
|
|
||||||
|
err = dbus.Store(resultInterface, changesInterface...)
|
||||||
|
if err != nil {
|
||||||
|
return false, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return carries_install_info, changes, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type EnableUnitFileChange struct {
|
||||||
|
Type string // Type of the change (one of symlink or unlink)
|
||||||
|
Filename string // File name of the symlink
|
||||||
|
Destination string // Destination of the symlink
|
||||||
|
}
|
||||||
|
|
||||||
|
// DisableUnitFiles() may be used to disable one or more units in the system (by
|
||||||
|
// removing symlinks to them from /etc or /run).
|
||||||
|
//
|
||||||
|
// It takes a list of unit files to disable (either just file names or full
|
||||||
|
// absolute paths if the unit files are residing outside the usual unit
|
||||||
|
// search paths), and one boolean: whether the unit was enabled for runtime
|
||||||
|
// only (true, /run), or persistently (false, /etc).
|
||||||
|
//
|
||||||
|
// This call returns an array with the changes made. The changes list
|
||||||
|
// consists of structures with three strings: the type of the change (one of
|
||||||
|
// symlink or unlink), the file name of the symlink and the destination of the
|
||||||
|
// symlink.
|
||||||
|
func (c *Conn) DisableUnitFiles(files []string, runtime bool) ([]DisableUnitFileChange, error) {
|
||||||
|
result := make([][]interface{}, 0)
|
||||||
|
err := c.sysobj.Call("org.freedesktop.systemd1.Manager.DisableUnitFiles", 0, files, runtime).Store(&result)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
resultInterface := make([]interface{}, len(result))
|
||||||
|
for i := range result {
|
||||||
|
resultInterface[i] = result[i]
|
||||||
|
}
|
||||||
|
|
||||||
|
changes := make([]DisableUnitFileChange, len(result))
|
||||||
|
changesInterface := make([]interface{}, len(changes))
|
||||||
|
for i := range changes {
|
||||||
|
changesInterface[i] = &changes[i]
|
||||||
|
}
|
||||||
|
|
||||||
|
err = dbus.Store(resultInterface, changesInterface...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return changes, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type DisableUnitFileChange struct {
|
||||||
|
Type string // Type of the change (one of symlink or unlink)
|
||||||
|
Filename string // File name of the symlink
|
||||||
|
Destination string // Destination of the symlink
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reload instructs systemd to scan for and reload unit files. This is
|
||||||
|
// equivalent to a 'systemctl daemon-reload'.
|
||||||
|
func (c *Conn) Reload() error {
|
||||||
|
return c.sysobj.Call("org.freedesktop.systemd1.Manager.Reload", 0).Store()
|
||||||
|
}
|
||||||
|
|
||||||
|
func unitPath(name string) dbus.ObjectPath {
|
||||||
|
return dbus.ObjectPath("/org/freedesktop/systemd1/unit/" + PathBusEscape(name))
|
||||||
|
}
|
218
vendor/src/github.com/coreos/go-systemd/dbus/properties.go
vendored
Normal file
218
vendor/src/github.com/coreos/go-systemd/dbus/properties.go
vendored
Normal file
|
@ -0,0 +1,218 @@
|
||||||
|
// Copyright 2015 CoreOS, Inc.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package dbus
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/godbus/dbus"
|
||||||
|
)
|
||||||
|
|
||||||
|
// From the systemd docs:
|
||||||
|
//
|
||||||
|
// The properties array of StartTransientUnit() may take many of the settings
|
||||||
|
// that may also be configured in unit files. Not all parameters are currently
|
||||||
|
// accepted though, but we plan to cover more properties with future release.
|
||||||
|
// Currently you may set the Description, Slice and all dependency types of
|
||||||
|
// units, as well as RemainAfterExit, ExecStart for service units,
|
||||||
|
// TimeoutStopUSec and PIDs for scope units, and CPUAccounting, CPUShares,
|
||||||
|
// BlockIOAccounting, BlockIOWeight, BlockIOReadBandwidth,
|
||||||
|
// BlockIOWriteBandwidth, BlockIODeviceWeight, MemoryAccounting, MemoryLimit,
|
||||||
|
// DevicePolicy, DeviceAllow for services/scopes/slices. These fields map
|
||||||
|
// directly to their counterparts in unit files and as normal D-Bus object
|
||||||
|
// properties. The exception here is the PIDs field of scope units which is
|
||||||
|
// used for construction of the scope only and specifies the initial PIDs to
|
||||||
|
// add to the scope object.
|
||||||
|
|
||||||
|
type Property struct {
|
||||||
|
Name string
|
||||||
|
Value dbus.Variant
|
||||||
|
}
|
||||||
|
|
||||||
|
type PropertyCollection struct {
|
||||||
|
Name string
|
||||||
|
Properties []Property
|
||||||
|
}
|
||||||
|
|
||||||
|
type execStart struct {
|
||||||
|
Path string // the binary path to execute
|
||||||
|
Args []string // an array with all arguments to pass to the executed command, starting with argument 0
|
||||||
|
UncleanIsFailure bool // a boolean whether it should be considered a failure if the process exits uncleanly
|
||||||
|
}
|
||||||
|
|
||||||
|
// PropExecStart sets the ExecStart service property. The first argument is a
|
||||||
|
// slice with the binary path to execute followed by the arguments to pass to
|
||||||
|
// the executed command. See
|
||||||
|
// http://www.freedesktop.org/software/systemd/man/systemd.service.html#ExecStart=
|
||||||
|
func PropExecStart(command []string, uncleanIsFailure bool) Property {
|
||||||
|
execStarts := []execStart{
|
||||||
|
execStart{
|
||||||
|
Path: command[0],
|
||||||
|
Args: command,
|
||||||
|
UncleanIsFailure: uncleanIsFailure,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
return Property{
|
||||||
|
Name: "ExecStart",
|
||||||
|
Value: dbus.MakeVariant(execStarts),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// PropRemainAfterExit sets the RemainAfterExit service property. See
|
||||||
|
// http://www.freedesktop.org/software/systemd/man/systemd.service.html#RemainAfterExit=
|
||||||
|
func PropRemainAfterExit(b bool) Property {
|
||||||
|
return Property{
|
||||||
|
Name: "RemainAfterExit",
|
||||||
|
Value: dbus.MakeVariant(b),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// PropDescription sets the Description unit property. See
|
||||||
|
// http://www.freedesktop.org/software/systemd/man/systemd.unit#Description=
|
||||||
|
func PropDescription(desc string) Property {
|
||||||
|
return Property{
|
||||||
|
Name: "Description",
|
||||||
|
Value: dbus.MakeVariant(desc),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func propDependency(name string, units []string) Property {
|
||||||
|
return Property{
|
||||||
|
Name: name,
|
||||||
|
Value: dbus.MakeVariant(units),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// PropRequires sets the Requires unit property. See
|
||||||
|
// http://www.freedesktop.org/software/systemd/man/systemd.unit.html#Requires=
|
||||||
|
func PropRequires(units ...string) Property {
|
||||||
|
return propDependency("Requires", units)
|
||||||
|
}
|
||||||
|
|
||||||
|
// PropRequiresOverridable sets the RequiresOverridable unit property. See
|
||||||
|
// http://www.freedesktop.org/software/systemd/man/systemd.unit.html#RequiresOverridable=
|
||||||
|
func PropRequiresOverridable(units ...string) Property {
|
||||||
|
return propDependency("RequiresOverridable", units)
|
||||||
|
}
|
||||||
|
|
||||||
|
// PropRequisite sets the Requisite unit property. See
|
||||||
|
// http://www.freedesktop.org/software/systemd/man/systemd.unit.html#Requisite=
|
||||||
|
func PropRequisite(units ...string) Property {
|
||||||
|
return propDependency("Requisite", units)
|
||||||
|
}
|
||||||
|
|
||||||
|
// PropRequisiteOverridable sets the RequisiteOverridable unit property. See
|
||||||
|
// http://www.freedesktop.org/software/systemd/man/systemd.unit.html#RequisiteOverridable=
|
||||||
|
func PropRequisiteOverridable(units ...string) Property {
|
||||||
|
return propDependency("RequisiteOverridable", units)
|
||||||
|
}
|
||||||
|
|
||||||
|
// PropWants sets the Wants unit property. See
|
||||||
|
// http://www.freedesktop.org/software/systemd/man/systemd.unit.html#Wants=
|
||||||
|
func PropWants(units ...string) Property {
|
||||||
|
return propDependency("Wants", units)
|
||||||
|
}
|
||||||
|
|
||||||
|
// PropBindsTo sets the BindsTo unit property. See
|
||||||
|
// http://www.freedesktop.org/software/systemd/man/systemd.unit.html#BindsTo=
|
||||||
|
func PropBindsTo(units ...string) Property {
|
||||||
|
return propDependency("BindsTo", units)
|
||||||
|
}
|
||||||
|
|
||||||
|
// PropRequiredBy sets the RequiredBy unit property. See
|
||||||
|
// http://www.freedesktop.org/software/systemd/man/systemd.unit.html#RequiredBy=
|
||||||
|
func PropRequiredBy(units ...string) Property {
|
||||||
|
return propDependency("RequiredBy", units)
|
||||||
|
}
|
||||||
|
|
||||||
|
// PropRequiredByOverridable sets the RequiredByOverridable unit property. See
|
||||||
|
// http://www.freedesktop.org/software/systemd/man/systemd.unit.html#RequiredByOverridable=
|
||||||
|
func PropRequiredByOverridable(units ...string) Property {
|
||||||
|
return propDependency("RequiredByOverridable", units)
|
||||||
|
}
|
||||||
|
|
||||||
|
// PropWantedBy sets the WantedBy unit property. See
|
||||||
|
// http://www.freedesktop.org/software/systemd/man/systemd.unit.html#WantedBy=
|
||||||
|
func PropWantedBy(units ...string) Property {
|
||||||
|
return propDependency("WantedBy", units)
|
||||||
|
}
|
||||||
|
|
||||||
|
// PropBoundBy sets the BoundBy unit property. See
|
||||||
|
// http://www.freedesktop.org/software/systemd/main/systemd.unit.html#BoundBy=
|
||||||
|
func PropBoundBy(units ...string) Property {
|
||||||
|
return propDependency("BoundBy", units)
|
||||||
|
}
|
||||||
|
|
||||||
|
// PropConflicts sets the Conflicts unit property. See
|
||||||
|
// http://www.freedesktop.org/software/systemd/man/systemd.unit.html#Conflicts=
|
||||||
|
func PropConflicts(units ...string) Property {
|
||||||
|
return propDependency("Conflicts", units)
|
||||||
|
}
|
||||||
|
|
||||||
|
// PropConflictedBy sets the ConflictedBy unit property. See
|
||||||
|
// http://www.freedesktop.org/software/systemd/man/systemd.unit.html#ConflictedBy=
|
||||||
|
func PropConflictedBy(units ...string) Property {
|
||||||
|
return propDependency("ConflictedBy", units)
|
||||||
|
}
|
||||||
|
|
||||||
|
// PropBefore sets the Before unit property. See
|
||||||
|
// http://www.freedesktop.org/software/systemd/man/systemd.unit.html#Before=
|
||||||
|
func PropBefore(units ...string) Property {
|
||||||
|
return propDependency("Before", units)
|
||||||
|
}
|
||||||
|
|
||||||
|
// PropAfter sets the After unit property. See
|
||||||
|
// http://www.freedesktop.org/software/systemd/man/systemd.unit.html#After=
|
||||||
|
func PropAfter(units ...string) Property {
|
||||||
|
return propDependency("After", units)
|
||||||
|
}
|
||||||
|
|
||||||
|
// PropOnFailure sets the OnFailure unit property. See
|
||||||
|
// http://www.freedesktop.org/software/systemd/man/systemd.unit.html#OnFailure=
|
||||||
|
func PropOnFailure(units ...string) Property {
|
||||||
|
return propDependency("OnFailure", units)
|
||||||
|
}
|
||||||
|
|
||||||
|
// PropTriggers sets the Triggers unit property. See
|
||||||
|
// http://www.freedesktop.org/software/systemd/man/systemd.unit.html#Triggers=
|
||||||
|
func PropTriggers(units ...string) Property {
|
||||||
|
return propDependency("Triggers", units)
|
||||||
|
}
|
||||||
|
|
||||||
|
// PropTriggeredBy sets the TriggeredBy unit property. See
|
||||||
|
// http://www.freedesktop.org/software/systemd/man/systemd.unit.html#TriggeredBy=
|
||||||
|
func PropTriggeredBy(units ...string) Property {
|
||||||
|
return propDependency("TriggeredBy", units)
|
||||||
|
}
|
||||||
|
|
||||||
|
// PropPropagatesReloadTo sets the PropagatesReloadTo unit property. See
|
||||||
|
// http://www.freedesktop.org/software/systemd/man/systemd.unit.html#PropagatesReloadTo=
|
||||||
|
func PropPropagatesReloadTo(units ...string) Property {
|
||||||
|
return propDependency("PropagatesReloadTo", units)
|
||||||
|
}
|
||||||
|
|
||||||
|
// PropRequiresMountsFor sets the RequiresMountsFor unit property. See
|
||||||
|
// http://www.freedesktop.org/software/systemd/man/systemd.unit.html#RequiresMountsFor=
|
||||||
|
func PropRequiresMountsFor(units ...string) Property {
|
||||||
|
return propDependency("RequiresMountsFor", units)
|
||||||
|
}
|
||||||
|
|
||||||
|
// PropSlice sets the Slice unit property. See
|
||||||
|
// http://www.freedesktop.org/software/systemd/man/systemd.resource-control.html#Slice=
|
||||||
|
func PropSlice(slice string) Property {
|
||||||
|
return Property{
|
||||||
|
Name: "Slice",
|
||||||
|
Value: dbus.MakeVariant(slice),
|
||||||
|
}
|
||||||
|
}
|
47
vendor/src/github.com/coreos/go-systemd/dbus/set.go
vendored
Normal file
47
vendor/src/github.com/coreos/go-systemd/dbus/set.go
vendored
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
// Copyright 2015 CoreOS, Inc.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package dbus
|
||||||
|
|
||||||
|
type set struct {
|
||||||
|
data map[string]bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *set) Add(value string) {
|
||||||
|
s.data[value] = true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *set) Remove(value string) {
|
||||||
|
delete(s.data, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *set) Contains(value string) (exists bool) {
|
||||||
|
_, exists = s.data[value]
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *set) Length() int {
|
||||||
|
return len(s.data)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *set) Values() (values []string) {
|
||||||
|
for val, _ := range s.data {
|
||||||
|
values = append(values, val)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func newSet() *set {
|
||||||
|
return &set{make(map[string]bool)}
|
||||||
|
}
|
250
vendor/src/github.com/coreos/go-systemd/dbus/subscription.go
vendored
Normal file
250
vendor/src/github.com/coreos/go-systemd/dbus/subscription.go
vendored
Normal file
|
@ -0,0 +1,250 @@
|
||||||
|
// Copyright 2015 CoreOS, Inc.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package dbus
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/godbus/dbus"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
cleanIgnoreInterval = int64(10 * time.Second)
|
||||||
|
ignoreInterval = int64(30 * time.Millisecond)
|
||||||
|
)
|
||||||
|
|
||||||
|
// Subscribe sets up this connection to subscribe to all systemd dbus events.
|
||||||
|
// This is required before calling SubscribeUnits. When the connection closes
|
||||||
|
// systemd will automatically stop sending signals so there is no need to
|
||||||
|
// explicitly call Unsubscribe().
|
||||||
|
func (c *Conn) Subscribe() error {
|
||||||
|
c.sigconn.BusObject().Call("org.freedesktop.DBus.AddMatch", 0,
|
||||||
|
"type='signal',interface='org.freedesktop.systemd1.Manager',member='UnitNew'")
|
||||||
|
c.sigconn.BusObject().Call("org.freedesktop.DBus.AddMatch", 0,
|
||||||
|
"type='signal',interface='org.freedesktop.DBus.Properties',member='PropertiesChanged'")
|
||||||
|
|
||||||
|
err := c.sigobj.Call("org.freedesktop.systemd1.Manager.Subscribe", 0).Store()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unsubscribe this connection from systemd dbus events.
|
||||||
|
func (c *Conn) Unsubscribe() error {
|
||||||
|
err := c.sigobj.Call("org.freedesktop.systemd1.Manager.Unsubscribe", 0).Store()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Conn) dispatch() {
|
||||||
|
ch := make(chan *dbus.Signal, signalBuffer)
|
||||||
|
|
||||||
|
c.sigconn.Signal(ch)
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
for {
|
||||||
|
signal, ok := <-ch
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if signal.Name == "org.freedesktop.systemd1.Manager.JobRemoved" {
|
||||||
|
c.jobComplete(signal)
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.subscriber.updateCh == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
var unitPath dbus.ObjectPath
|
||||||
|
switch signal.Name {
|
||||||
|
case "org.freedesktop.systemd1.Manager.JobRemoved":
|
||||||
|
unitName := signal.Body[2].(string)
|
||||||
|
c.sysobj.Call("org.freedesktop.systemd1.Manager.GetUnit", 0, unitName).Store(&unitPath)
|
||||||
|
case "org.freedesktop.systemd1.Manager.UnitNew":
|
||||||
|
unitPath = signal.Body[1].(dbus.ObjectPath)
|
||||||
|
case "org.freedesktop.DBus.Properties.PropertiesChanged":
|
||||||
|
if signal.Body[0].(string) == "org.freedesktop.systemd1.Unit" {
|
||||||
|
unitPath = signal.Path
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if unitPath == dbus.ObjectPath("") {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
c.sendSubStateUpdate(unitPath)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns two unbuffered channels which will receive all changed units every
|
||||||
|
// interval. Deleted units are sent as nil.
|
||||||
|
func (c *Conn) SubscribeUnits(interval time.Duration) (<-chan map[string]*UnitStatus, <-chan error) {
|
||||||
|
return c.SubscribeUnitsCustom(interval, 0, func(u1, u2 *UnitStatus) bool { return *u1 != *u2 }, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SubscribeUnitsCustom is like SubscribeUnits but lets you specify the buffer
|
||||||
|
// size of the channels, the comparison function for detecting changes and a filter
|
||||||
|
// function for cutting down on the noise that your channel receives.
|
||||||
|
func (c *Conn) SubscribeUnitsCustom(interval time.Duration, buffer int, isChanged func(*UnitStatus, *UnitStatus) bool, filterUnit func(string) bool) (<-chan map[string]*UnitStatus, <-chan error) {
|
||||||
|
old := make(map[string]*UnitStatus)
|
||||||
|
statusChan := make(chan map[string]*UnitStatus, buffer)
|
||||||
|
errChan := make(chan error, buffer)
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
for {
|
||||||
|
timerChan := time.After(interval)
|
||||||
|
|
||||||
|
units, err := c.ListUnits()
|
||||||
|
if err == nil {
|
||||||
|
cur := make(map[string]*UnitStatus)
|
||||||
|
for i := range units {
|
||||||
|
if filterUnit != nil && filterUnit(units[i].Name) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
cur[units[i].Name] = &units[i]
|
||||||
|
}
|
||||||
|
|
||||||
|
// add all new or changed units
|
||||||
|
changed := make(map[string]*UnitStatus)
|
||||||
|
for n, u := range cur {
|
||||||
|
if oldU, ok := old[n]; !ok || isChanged(oldU, u) {
|
||||||
|
changed[n] = u
|
||||||
|
}
|
||||||
|
delete(old, n)
|
||||||
|
}
|
||||||
|
|
||||||
|
// add all deleted units
|
||||||
|
for oldN := range old {
|
||||||
|
changed[oldN] = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
old = cur
|
||||||
|
|
||||||
|
if len(changed) != 0 {
|
||||||
|
statusChan <- changed
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
errChan <- err
|
||||||
|
}
|
||||||
|
|
||||||
|
<-timerChan
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
return statusChan, errChan
|
||||||
|
}
|
||||||
|
|
||||||
|
type SubStateUpdate struct {
|
||||||
|
UnitName string
|
||||||
|
SubState string
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetSubStateSubscriber writes to updateCh when any unit's substate changes.
|
||||||
|
// Although this writes to updateCh on every state change, the reported state
|
||||||
|
// may be more recent than the change that generated it (due to an unavoidable
|
||||||
|
// race in the systemd dbus interface). That is, this method provides a good
|
||||||
|
// way to keep a current view of all units' states, but is not guaranteed to
|
||||||
|
// show every state transition they go through. Furthermore, state changes
|
||||||
|
// will only be written to the channel with non-blocking writes. If updateCh
|
||||||
|
// is full, it attempts to write an error to errCh; if errCh is full, the error
|
||||||
|
// passes silently.
|
||||||
|
func (c *Conn) SetSubStateSubscriber(updateCh chan<- *SubStateUpdate, errCh chan<- error) {
|
||||||
|
c.subscriber.Lock()
|
||||||
|
defer c.subscriber.Unlock()
|
||||||
|
c.subscriber.updateCh = updateCh
|
||||||
|
c.subscriber.errCh = errCh
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Conn) sendSubStateUpdate(path dbus.ObjectPath) {
|
||||||
|
c.subscriber.Lock()
|
||||||
|
defer c.subscriber.Unlock()
|
||||||
|
|
||||||
|
if c.shouldIgnore(path) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
info, err := c.GetUnitProperties(string(path))
|
||||||
|
if err != nil {
|
||||||
|
select {
|
||||||
|
case c.subscriber.errCh <- err:
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
name := info["Id"].(string)
|
||||||
|
substate := info["SubState"].(string)
|
||||||
|
|
||||||
|
update := &SubStateUpdate{name, substate}
|
||||||
|
select {
|
||||||
|
case c.subscriber.updateCh <- update:
|
||||||
|
default:
|
||||||
|
select {
|
||||||
|
case c.subscriber.errCh <- errors.New("update channel full!"):
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
c.updateIgnore(path, info)
|
||||||
|
}
|
||||||
|
|
||||||
|
// The ignore functions work around a wart in the systemd dbus interface.
|
||||||
|
// Requesting the properties of an unloaded unit will cause systemd to send a
|
||||||
|
// pair of UnitNew/UnitRemoved signals. Because we need to get a unit's
|
||||||
|
// properties on UnitNew (as that's the only indication of a new unit coming up
|
||||||
|
// for the first time), we would enter an infinite loop if we did not attempt
|
||||||
|
// to detect and ignore these spurious signals. The signal themselves are
|
||||||
|
// indistinguishable from relevant ones, so we (somewhat hackishly) ignore an
|
||||||
|
// unloaded unit's signals for a short time after requesting its properties.
|
||||||
|
// This means that we will miss e.g. a transient unit being restarted
|
||||||
|
// *immediately* upon failure and also a transient unit being started
|
||||||
|
// immediately after requesting its status (with systemctl status, for example,
|
||||||
|
// because this causes a UnitNew signal to be sent which then causes us to fetch
|
||||||
|
// the properties).
|
||||||
|
|
||||||
|
func (c *Conn) shouldIgnore(path dbus.ObjectPath) bool {
|
||||||
|
t, ok := c.subscriber.ignore[path]
|
||||||
|
return ok && t >= time.Now().UnixNano()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Conn) updateIgnore(path dbus.ObjectPath, info map[string]interface{}) {
|
||||||
|
c.cleanIgnore()
|
||||||
|
|
||||||
|
// unit is unloaded - it will trigger bad systemd dbus behavior
|
||||||
|
if info["LoadState"].(string) == "not-found" {
|
||||||
|
c.subscriber.ignore[path] = time.Now().UnixNano() + ignoreInterval
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// without this, ignore would grow unboundedly over time
|
||||||
|
func (c *Conn) cleanIgnore() {
|
||||||
|
now := time.Now().UnixNano()
|
||||||
|
if c.subscriber.cleanIgnore < now {
|
||||||
|
c.subscriber.cleanIgnore = now + cleanIgnoreInterval
|
||||||
|
|
||||||
|
for p, t := range c.subscriber.ignore {
|
||||||
|
if t < now {
|
||||||
|
delete(c.subscriber.ignore, p)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
57
vendor/src/github.com/coreos/go-systemd/dbus/subscription_set.go
vendored
Normal file
57
vendor/src/github.com/coreos/go-systemd/dbus/subscription_set.go
vendored
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
// Copyright 2015 CoreOS, Inc.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package dbus
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// SubscriptionSet returns a subscription set which is like conn.Subscribe but
|
||||||
|
// can filter to only return events for a set of units.
|
||||||
|
type SubscriptionSet struct {
|
||||||
|
*set
|
||||||
|
conn *Conn
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *SubscriptionSet) filter(unit string) bool {
|
||||||
|
return !s.Contains(unit)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Subscribe starts listening for dbus events for all of the units in the set.
|
||||||
|
// Returns channels identical to conn.SubscribeUnits.
|
||||||
|
func (s *SubscriptionSet) Subscribe() (<-chan map[string]*UnitStatus, <-chan error) {
|
||||||
|
// TODO: Make fully evented by using systemd 209 with properties changed values
|
||||||
|
return s.conn.SubscribeUnitsCustom(time.Second, 0,
|
||||||
|
mismatchUnitStatus,
|
||||||
|
func(unit string) bool { return s.filter(unit) },
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewSubscriptionSet returns a new subscription set.
|
||||||
|
func (conn *Conn) NewSubscriptionSet() *SubscriptionSet {
|
||||||
|
return &SubscriptionSet{newSet(), conn}
|
||||||
|
}
|
||||||
|
|
||||||
|
// mismatchUnitStatus returns true if the provided UnitStatus objects
|
||||||
|
// are not equivalent. false is returned if the objects are equivalent.
|
||||||
|
// Only the Name, Description and state-related fields are used in
|
||||||
|
// the comparison.
|
||||||
|
func mismatchUnitStatus(u1, u2 *UnitStatus) bool {
|
||||||
|
return u1.Name != u2.Name ||
|
||||||
|
u1.Description != u2.Description ||
|
||||||
|
u1.LoadState != u2.LoadState ||
|
||||||
|
u1.ActiveState != u2.ActiveState ||
|
||||||
|
u1.SubState != u2.SubState
|
||||||
|
}
|
270
vendor/src/github.com/coreos/go-systemd/util/util.go
vendored
Normal file
270
vendor/src/github.com/coreos/go-systemd/util/util.go
vendored
Normal file
|
@ -0,0 +1,270 @@
|
||||||
|
// Copyright 2015 CoreOS, Inc.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
// Package util contains utility functions related to systemd that applications
|
||||||
|
// can use to check things like whether systemd is running. Note that some of
|
||||||
|
// these functions attempt to manually load systemd libraries at runtime rather
|
||||||
|
// than linking against them.
|
||||||
|
package util
|
||||||
|
|
||||||
|
// #cgo LDFLAGS: -ldl
|
||||||
|
// #include <stdlib.h>
|
||||||
|
// #include <dlfcn.h>
|
||||||
|
// #include <sys/types.h>
|
||||||
|
// #include <unistd.h>
|
||||||
|
//
|
||||||
|
// int
|
||||||
|
// my_sd_pid_get_owner_uid(void *f, pid_t pid, uid_t *uid)
|
||||||
|
// {
|
||||||
|
// int (*sd_pid_get_owner_uid)(pid_t, uid_t *);
|
||||||
|
//
|
||||||
|
// sd_pid_get_owner_uid = (int (*)(pid_t, uid_t *))f;
|
||||||
|
// return sd_pid_get_owner_uid(pid, uid);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// int
|
||||||
|
// my_sd_pid_get_unit(void *f, pid_t pid, char **unit)
|
||||||
|
// {
|
||||||
|
// int (*sd_pid_get_unit)(pid_t, char **);
|
||||||
|
//
|
||||||
|
// sd_pid_get_unit = (int (*)(pid_t, char **))f;
|
||||||
|
// return sd_pid_get_unit(pid, unit);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// int
|
||||||
|
// my_sd_pid_get_slice(void *f, pid_t pid, char **slice)
|
||||||
|
// {
|
||||||
|
// int (*sd_pid_get_slice)(pid_t, char **);
|
||||||
|
//
|
||||||
|
// sd_pid_get_slice = (int (*)(pid_t, char **))f;
|
||||||
|
// return sd_pid_get_slice(pid, slice);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// int
|
||||||
|
// am_session_leader()
|
||||||
|
// {
|
||||||
|
// return (getsid(0) == getpid());
|
||||||
|
// }
|
||||||
|
import "C"
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
"syscall"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
var ErrSoNotFound = errors.New("unable to open a handle to libsystemd")
|
||||||
|
|
||||||
|
// libHandle represents an open handle to the systemd C library
|
||||||
|
type libHandle struct {
|
||||||
|
handle unsafe.Pointer
|
||||||
|
libname string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *libHandle) Close() error {
|
||||||
|
if r := C.dlclose(h.handle); r != 0 {
|
||||||
|
return fmt.Errorf("error closing %v: %d", h.libname, r)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// getHandle tries to get a handle to a systemd library (.so), attempting to
|
||||||
|
// access it by several different names and returning the first that is
|
||||||
|
// successfully opened. Callers are responsible for closing the handler.
|
||||||
|
// If no library can be successfully opened, an error is returned.
|
||||||
|
func getHandle() (*libHandle, error) {
|
||||||
|
for _, name := range []string{
|
||||||
|
// systemd < 209
|
||||||
|
"libsystemd-login.so",
|
||||||
|
"libsystemd-login.so.0",
|
||||||
|
|
||||||
|
// systemd >= 209 merged libsystemd-login into libsystemd proper
|
||||||
|
"libsystemd.so",
|
||||||
|
"libsystemd.so.0",
|
||||||
|
} {
|
||||||
|
libname := C.CString(name)
|
||||||
|
defer C.free(unsafe.Pointer(libname))
|
||||||
|
handle := C.dlopen(libname, C.RTLD_LAZY)
|
||||||
|
if handle != nil {
|
||||||
|
h := &libHandle{
|
||||||
|
handle: handle,
|
||||||
|
libname: name,
|
||||||
|
}
|
||||||
|
return h, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil, ErrSoNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetRunningSlice attempts to retrieve the name of the systemd slice in which
|
||||||
|
// the current process is running.
|
||||||
|
// This function is a wrapper around the libsystemd C library; if it cannot be
|
||||||
|
// opened, an error is returned.
|
||||||
|
func GetRunningSlice() (slice string, err error) {
|
||||||
|
var h *libHandle
|
||||||
|
h, err = getHandle()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer func() {
|
||||||
|
if err1 := h.Close(); err1 != nil {
|
||||||
|
err = err1
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
sym := C.CString("sd_pid_get_slice")
|
||||||
|
defer C.free(unsafe.Pointer(sym))
|
||||||
|
sd_pid_get_slice := C.dlsym(h.handle, sym)
|
||||||
|
if sd_pid_get_slice == nil {
|
||||||
|
err = fmt.Errorf("error resolving sd_pid_get_slice function")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var s string
|
||||||
|
sl := C.CString(s)
|
||||||
|
defer C.free(unsafe.Pointer(sl))
|
||||||
|
|
||||||
|
ret := C.my_sd_pid_get_slice(sd_pid_get_slice, 0, &sl)
|
||||||
|
if ret < 0 {
|
||||||
|
err = fmt.Errorf("error calling sd_pid_get_slice: %v", syscall.Errno(-ret))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
return C.GoString(sl), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// RunningFromSystemService tries to detect whether the current process has
|
||||||
|
// been invoked from a system service. The condition for this is whether the
|
||||||
|
// process is _not_ a user process. User processes are those running in session
|
||||||
|
// scopes or under per-user `systemd --user` instances.
|
||||||
|
//
|
||||||
|
// To avoid false positives on systems without `pam_systemd` (which is
|
||||||
|
// responsible for creating user sessions), this function also uses a heuristic
|
||||||
|
// to detect whether it's being invoked from a session leader process. This is
|
||||||
|
// the case if the current process is executed directly from a service file
|
||||||
|
// (e.g. with `ExecStart=/this/cmd`). Note that this heuristic will fail if the
|
||||||
|
// command is instead launched in a subshell or similar so that it is not
|
||||||
|
// session leader (e.g. `ExecStart=/bin/bash -c "/this/cmd"`)
|
||||||
|
//
|
||||||
|
// This function is a wrapper around the libsystemd C library; if this is
|
||||||
|
// unable to successfully open a handle to the library for any reason (e.g. it
|
||||||
|
// cannot be found), an errr will be returned
|
||||||
|
func RunningFromSystemService() (ret bool, err error) {
|
||||||
|
var h *libHandle
|
||||||
|
h, err = getHandle()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer func() {
|
||||||
|
if err1 := h.Close(); err1 != nil {
|
||||||
|
err = err1
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
sym := C.CString("sd_pid_get_owner_uid")
|
||||||
|
defer C.free(unsafe.Pointer(sym))
|
||||||
|
sd_pid_get_owner_uid := C.dlsym(h.handle, sym)
|
||||||
|
if sd_pid_get_owner_uid == nil {
|
||||||
|
err = fmt.Errorf("error resolving sd_pid_get_owner_uid function")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var uid C.uid_t
|
||||||
|
errno := C.my_sd_pid_get_owner_uid(sd_pid_get_owner_uid, 0, &uid)
|
||||||
|
serrno := syscall.Errno(-errno)
|
||||||
|
// when we're running from a unit file, sd_pid_get_owner_uid returns
|
||||||
|
// ENOENT (systemd <220) or ENXIO (systemd >=220)
|
||||||
|
switch {
|
||||||
|
case errno >= 0:
|
||||||
|
ret = false
|
||||||
|
case serrno == syscall.ENOENT, serrno == syscall.ENXIO:
|
||||||
|
// Since the implementation of sessions in systemd relies on
|
||||||
|
// the `pam_systemd` module, using the sd_pid_get_owner_uid
|
||||||
|
// heuristic alone can result in false positives if that module
|
||||||
|
// (or PAM itself) is not present or properly configured on the
|
||||||
|
// system. As such, we also check if we're the session leader,
|
||||||
|
// which should be the case if we're invoked from a unit file,
|
||||||
|
// but not if e.g. we're invoked from the command line from a
|
||||||
|
// user's login session
|
||||||
|
ret = C.am_session_leader() == 1
|
||||||
|
default:
|
||||||
|
err = fmt.Errorf("error calling sd_pid_get_owner_uid: %v", syscall.Errno(-errno))
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// CurrentUnitName attempts to retrieve the name of the systemd system unit
|
||||||
|
// from which the calling process has been invoked. It wraps the systemd
|
||||||
|
// `sd_pid_get_unit` call, with the same caveat: for processes not part of a
|
||||||
|
// systemd system unit, this function will return an error.
|
||||||
|
func CurrentUnitName() (unit string, err error) {
|
||||||
|
var h *libHandle
|
||||||
|
h, err = getHandle()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer func() {
|
||||||
|
if err1 := h.Close(); err1 != nil {
|
||||||
|
err = err1
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
sym := C.CString("sd_pid_get_unit")
|
||||||
|
defer C.free(unsafe.Pointer(sym))
|
||||||
|
sd_pid_get_unit := C.dlsym(h.handle, sym)
|
||||||
|
if sd_pid_get_unit == nil {
|
||||||
|
err = fmt.Errorf("error resolving sd_pid_get_unit function")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var s string
|
||||||
|
u := C.CString(s)
|
||||||
|
defer C.free(unsafe.Pointer(u))
|
||||||
|
|
||||||
|
ret := C.my_sd_pid_get_unit(sd_pid_get_unit, 0, &u)
|
||||||
|
if ret < 0 {
|
||||||
|
err = fmt.Errorf("error calling sd_pid_get_unit: %v", syscall.Errno(-ret))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
unit = C.GoString(u)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsRunningSystemd checks whether the host was booted with systemd as its init
|
||||||
|
// system. This functions similarly to systemd's `sd_booted(3)`: internally, it
|
||||||
|
// checks whether /run/systemd/system/ exists and is a directory.
|
||||||
|
// http://www.freedesktop.org/software/systemd/man/sd_booted.html
|
||||||
|
func IsRunningSystemd() bool {
|
||||||
|
fi, err := os.Lstat("/run/systemd/system")
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return fi.IsDir()
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetMachineID returns a host's 128-bit machine ID as a string. This functions
|
||||||
|
// similarly to systemd's `sd_id128_get_machine`: internally, it simply reads
|
||||||
|
// the contents of /etc/machine-id
|
||||||
|
// http://www.freedesktop.org/software/systemd/man/sd_id128_get_machine.html
|
||||||
|
func GetMachineID() (string, error) {
|
||||||
|
machineID, err := ioutil.ReadFile("/etc/machine-id")
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("failed to read /etc/machine-id: %v", err)
|
||||||
|
}
|
||||||
|
return strings.TrimSpace(string(machineID)), nil
|
||||||
|
}
|
8
vendor/src/github.com/cyberdelia/go-metrics-graphite/AUTHORS
vendored
Normal file
8
vendor/src/github.com/cyberdelia/go-metrics-graphite/AUTHORS
vendored
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
These people have provided bug fixes, new features or improved the documentation.
|
||||||
|
|
||||||
|
* Daniel Garcia <daniel@danielgarcia.info>
|
||||||
|
* Peter Teichman <peter@thefactory.com>
|
||||||
|
* Phillip Kovalev <twilightfeel@gmail.com>
|
||||||
|
* Richard Crowley <r@rcrowley.org>
|
||||||
|
* Timothée Peignier <timothee.peignier@tryphon.org>
|
||||||
|
* Tomás Senart <tsenart@gmail.com>
|
22
vendor/src/github.com/cyberdelia/go-metrics-graphite/LICENSE
vendored
Normal file
22
vendor/src/github.com/cyberdelia/go-metrics-graphite/LICENSE
vendored
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
Copyright 2015 Timothée Peignier. All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without modification,
|
||||||
|
are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
2. 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.
|
||||||
|
|
||||||
|
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 HOLDER 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.
|
19
vendor/src/github.com/cyberdelia/go-metrics-graphite/README.md
vendored
Normal file
19
vendor/src/github.com/cyberdelia/go-metrics-graphite/README.md
vendored
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
This is a reporter for the [go-metrics](https://github.com/rcrowley/go-metrics)
|
||||||
|
library which will post the metrics to Graphite. It was originally part of the
|
||||||
|
`go-metrics` library itself, but has been split off to make maintenance of
|
||||||
|
both the core library and the client easier.
|
||||||
|
|
||||||
|
### Usage
|
||||||
|
|
||||||
|
```go
|
||||||
|
import "github.com/cyberdelia/go-metrics-graphite"
|
||||||
|
|
||||||
|
|
||||||
|
go graphite.Graphite(metrics.DefaultRegistry,
|
||||||
|
1*time.Second, "some.prefix", addr)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Migrating from `rcrowley/go-metrics` implementation
|
||||||
|
|
||||||
|
Simply modify the import from `"github.com/rcrowley/go-metrics/librato"` to
|
||||||
|
`"github.com/cyberdelia/go-metrics-graphite"` and it should Just Work.
|
113
vendor/src/github.com/cyberdelia/go-metrics-graphite/graphite.go
vendored
Normal file
113
vendor/src/github.com/cyberdelia/go-metrics-graphite/graphite.go
vendored
Normal file
|
@ -0,0 +1,113 @@
|
||||||
|
package graphite
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"net"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/rcrowley/go-metrics"
|
||||||
|
)
|
||||||
|
|
||||||
|
// GraphiteConfig provides a container with configuration parameters for
|
||||||
|
// the Graphite exporter
|
||||||
|
type GraphiteConfig struct {
|
||||||
|
Addr *net.TCPAddr // Network address to connect to
|
||||||
|
Registry metrics.Registry // Registry to be exported
|
||||||
|
FlushInterval time.Duration // Flush interval
|
||||||
|
DurationUnit time.Duration // Time conversion unit for durations
|
||||||
|
Prefix string // Prefix to be prepended to metric names
|
||||||
|
Percentiles []float64 // Percentiles to export from timers and histograms
|
||||||
|
}
|
||||||
|
|
||||||
|
// Graphite is a blocking exporter function which reports metrics in r
|
||||||
|
// to a graphite server located at addr, flushing them every d duration
|
||||||
|
// and prepending metric names with prefix.
|
||||||
|
func Graphite(r metrics.Registry, d time.Duration, prefix string, addr *net.TCPAddr) {
|
||||||
|
GraphiteWithConfig(GraphiteConfig{
|
||||||
|
Addr: addr,
|
||||||
|
Registry: r,
|
||||||
|
FlushInterval: d,
|
||||||
|
DurationUnit: time.Nanosecond,
|
||||||
|
Prefix: prefix,
|
||||||
|
Percentiles: []float64{0.5, 0.75, 0.95, 0.99, 0.999},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// GraphiteWithConfig is a blocking exporter function just like Graphite,
|
||||||
|
// but it takes a GraphiteConfig instead.
|
||||||
|
func GraphiteWithConfig(c GraphiteConfig) {
|
||||||
|
for _ = range time.Tick(c.FlushInterval) {
|
||||||
|
if err := graphite(&c); nil != err {
|
||||||
|
log.Println(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GraphiteOnce performs a single submission to Graphite, returning a
|
||||||
|
// non-nil error on failed connections. This can be used in a loop
|
||||||
|
// similar to GraphiteWithConfig for custom error handling.
|
||||||
|
func GraphiteOnce(c GraphiteConfig) error {
|
||||||
|
return graphite(&c)
|
||||||
|
}
|
||||||
|
|
||||||
|
func graphite(c *GraphiteConfig) error {
|
||||||
|
now := time.Now().Unix()
|
||||||
|
du := float64(c.DurationUnit)
|
||||||
|
conn, err := net.DialTCP("tcp", nil, c.Addr)
|
||||||
|
if nil != err {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer conn.Close()
|
||||||
|
w := bufio.NewWriter(conn)
|
||||||
|
c.Registry.Each(func(name string, i interface{}) {
|
||||||
|
switch metric := i.(type) {
|
||||||
|
case metrics.Counter:
|
||||||
|
fmt.Fprintf(w, "%s.%s.count %d %d\n", c.Prefix, name, metric.Count(), now)
|
||||||
|
case metrics.Gauge:
|
||||||
|
fmt.Fprintf(w, "%s.%s.value %d %d\n", c.Prefix, name, metric.Value(), now)
|
||||||
|
case metrics.GaugeFloat64:
|
||||||
|
fmt.Fprintf(w, "%s.%s.value %f %d\n", c.Prefix, name, metric.Value(), now)
|
||||||
|
case metrics.Histogram:
|
||||||
|
h := metric.Snapshot()
|
||||||
|
ps := h.Percentiles(c.Percentiles)
|
||||||
|
fmt.Fprintf(w, "%s.%s.count %d %d\n", c.Prefix, name, h.Count(), now)
|
||||||
|
fmt.Fprintf(w, "%s.%s.min %d %d\n", c.Prefix, name, h.Min(), now)
|
||||||
|
fmt.Fprintf(w, "%s.%s.max %d %d\n", c.Prefix, name, h.Max(), now)
|
||||||
|
fmt.Fprintf(w, "%s.%s.mean %.2f %d\n", c.Prefix, name, h.Mean(), now)
|
||||||
|
fmt.Fprintf(w, "%s.%s.std-dev %.2f %d\n", c.Prefix, name, h.StdDev(), now)
|
||||||
|
for psIdx, psKey := range c.Percentiles {
|
||||||
|
key := strings.Replace(strconv.FormatFloat(psKey*100.0, 'f', -1, 64), ".", "", 1)
|
||||||
|
fmt.Fprintf(w, "%s.%s.%s-percentile %.2f %d\n", c.Prefix, name, key, ps[psIdx], now)
|
||||||
|
}
|
||||||
|
case metrics.Meter:
|
||||||
|
m := metric.Snapshot()
|
||||||
|
fmt.Fprintf(w, "%s.%s.count %d %d\n", c.Prefix, name, m.Count(), now)
|
||||||
|
fmt.Fprintf(w, "%s.%s.one-minute %.2f %d\n", c.Prefix, name, m.Rate1(), now)
|
||||||
|
fmt.Fprintf(w, "%s.%s.five-minute %.2f %d\n", c.Prefix, name, m.Rate5(), now)
|
||||||
|
fmt.Fprintf(w, "%s.%s.fifteen-minute %.2f %d\n", c.Prefix, name, m.Rate15(), now)
|
||||||
|
fmt.Fprintf(w, "%s.%s.mean %.2f %d\n", c.Prefix, name, m.RateMean(), now)
|
||||||
|
case metrics.Timer:
|
||||||
|
t := metric.Snapshot()
|
||||||
|
ps := t.Percentiles(c.Percentiles)
|
||||||
|
fmt.Fprintf(w, "%s.%s.count %d %d\n", c.Prefix, name, t.Count(), now)
|
||||||
|
fmt.Fprintf(w, "%s.%s.min %d %d\n", c.Prefix, name, t.Min()/int64(du), now)
|
||||||
|
fmt.Fprintf(w, "%s.%s.max %d %d\n", c.Prefix, name, t.Max()/int64(du), now)
|
||||||
|
fmt.Fprintf(w, "%s.%s.mean %.2f %d\n", c.Prefix, name, t.Mean()/du, now)
|
||||||
|
fmt.Fprintf(w, "%s.%s.std-dev %.2f %d\n", c.Prefix, name, t.StdDev()/du, now)
|
||||||
|
for psIdx, psKey := range c.Percentiles {
|
||||||
|
key := strings.Replace(strconv.FormatFloat(psKey*100.0, 'f', -1, 64), ".", "", 1)
|
||||||
|
fmt.Fprintf(w, "%s.%s.%s-percentile %.2f %d\n", c.Prefix, name, key, ps[psIdx]/du, now)
|
||||||
|
}
|
||||||
|
fmt.Fprintf(w, "%s.%s.one-minute %.2f %d\n", c.Prefix, name, t.Rate1(), now)
|
||||||
|
fmt.Fprintf(w, "%s.%s.five-minute %.2f %d\n", c.Prefix, name, t.Rate5(), now)
|
||||||
|
fmt.Fprintf(w, "%s.%s.fifteen-minute %.2f %d\n", c.Prefix, name, t.Rate15(), now)
|
||||||
|
fmt.Fprintf(w, "%s.%s.mean-rate %.2f %d\n", c.Prefix, name, t.RateMean(), now)
|
||||||
|
}
|
||||||
|
w.Flush()
|
||||||
|
})
|
||||||
|
return nil
|
||||||
|
}
|
191
vendor/src/github.com/docker/docker/LICENSE
vendored
Normal file
191
vendor/src/github.com/docker/docker/LICENSE
vendored
Normal file
|
@ -0,0 +1,191 @@
|
||||||
|
|
||||||
|
Apache License
|
||||||
|
Version 2.0, January 2004
|
||||||
|
https://www.apache.org/licenses/
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||||
|
|
||||||
|
1. Definitions.
|
||||||
|
|
||||||
|
"License" shall mean the terms and conditions for use, reproduction,
|
||||||
|
and distribution as defined by Sections 1 through 9 of this document.
|
||||||
|
|
||||||
|
"Licensor" shall mean the copyright owner or entity authorized by
|
||||||
|
the copyright owner that is granting the License.
|
||||||
|
|
||||||
|
"Legal Entity" shall mean the union of the acting entity and all
|
||||||
|
other entities that control, are controlled by, or are under common
|
||||||
|
control with that entity. For the purposes of this definition,
|
||||||
|
"control" means (i) the power, direct or indirect, to cause the
|
||||||
|
direction or management of such entity, whether by contract or
|
||||||
|
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||||
|
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||||
|
|
||||||
|
"You" (or "Your") shall mean an individual or Legal Entity
|
||||||
|
exercising permissions granted by this License.
|
||||||
|
|
||||||
|
"Source" form shall mean the preferred form for making modifications,
|
||||||
|
including but not limited to software source code, documentation
|
||||||
|
source, and configuration files.
|
||||||
|
|
||||||
|
"Object" form shall mean any form resulting from mechanical
|
||||||
|
transformation or translation of a Source form, including but
|
||||||
|
not limited to compiled object code, generated documentation,
|
||||||
|
and conversions to other media types.
|
||||||
|
|
||||||
|
"Work" shall mean the work of authorship, whether in Source or
|
||||||
|
Object form, made available under the License, as indicated by a
|
||||||
|
copyright notice that is included in or attached to the work
|
||||||
|
(an example is provided in the Appendix below).
|
||||||
|
|
||||||
|
"Derivative Works" shall mean any work, whether in Source or Object
|
||||||
|
form, that is based on (or derived from) the Work and for which the
|
||||||
|
editorial revisions, annotations, elaborations, or other modifications
|
||||||
|
represent, as a whole, an original work of authorship. For the purposes
|
||||||
|
of this License, Derivative Works shall not include works that remain
|
||||||
|
separable from, or merely link (or bind by name) to the interfaces of,
|
||||||
|
the Work and Derivative Works thereof.
|
||||||
|
|
||||||
|
"Contribution" shall mean any work of authorship, including
|
||||||
|
the original version of the Work and any modifications or additions
|
||||||
|
to that Work or Derivative Works thereof, that is intentionally
|
||||||
|
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||||
|
or by an individual or Legal Entity authorized to submit on behalf of
|
||||||
|
the copyright owner. For the purposes of this definition, "submitted"
|
||||||
|
means any form of electronic, verbal, or written communication sent
|
||||||
|
to the Licensor or its representatives, including but not limited to
|
||||||
|
communication on electronic mailing lists, source code control systems,
|
||||||
|
and issue tracking systems that are managed by, or on behalf of, the
|
||||||
|
Licensor for the purpose of discussing and improving the Work, but
|
||||||
|
excluding communication that is conspicuously marked or otherwise
|
||||||
|
designated in writing by the copyright owner as "Not a Contribution."
|
||||||
|
|
||||||
|
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||||
|
on behalf of whom a Contribution has been received by Licensor and
|
||||||
|
subsequently incorporated within the Work.
|
||||||
|
|
||||||
|
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
copyright license to reproduce, prepare Derivative Works of,
|
||||||
|
publicly display, publicly perform, sublicense, and distribute the
|
||||||
|
Work and such Derivative Works in Source or Object form.
|
||||||
|
|
||||||
|
3. Grant of Patent License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor 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, and otherwise transfer the Work,
|
||||||
|
where such license applies only to those patent claims licensable
|
||||||
|
by such Contributor that are necessarily infringed by their
|
||||||
|
Contribution(s) alone or by combination of their Contribution(s)
|
||||||
|
with the Work to which such Contribution(s) was submitted. If You
|
||||||
|
institute patent litigation against any entity (including a
|
||||||
|
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||||
|
or a Contribution incorporated within the Work constitutes direct
|
||||||
|
or contributory patent infringement, then any patent licenses
|
||||||
|
granted to You under this License for that Work shall terminate
|
||||||
|
as of the date such litigation is filed.
|
||||||
|
|
||||||
|
4. Redistribution. You may reproduce and distribute copies of the
|
||||||
|
Work or Derivative Works thereof in any medium, with or without
|
||||||
|
modifications, and in Source or Object form, provided that You
|
||||||
|
meet the following conditions:
|
||||||
|
|
||||||
|
(a) You must give any other recipients of the Work or
|
||||||
|
Derivative Works a copy of this License; and
|
||||||
|
|
||||||
|
(b) You must cause any modified files to carry prominent notices
|
||||||
|
stating that You changed the files; and
|
||||||
|
|
||||||
|
(c) You must retain, in the Source form of any Derivative Works
|
||||||
|
that You distribute, all copyright, patent, trademark, and
|
||||||
|
attribution notices from the Source form of the Work,
|
||||||
|
excluding those notices that do not pertain to any part of
|
||||||
|
the Derivative Works; and
|
||||||
|
|
||||||
|
(d) If the Work includes a "NOTICE" text file as part of its
|
||||||
|
distribution, then any Derivative Works that You distribute must
|
||||||
|
include a readable copy of the attribution notices contained
|
||||||
|
within such NOTICE file, excluding those notices that do not
|
||||||
|
pertain to any part of the Derivative Works, in at least one
|
||||||
|
of the following places: within a NOTICE text file distributed
|
||||||
|
as part of the Derivative Works; within the Source form or
|
||||||
|
documentation, if provided along with the Derivative Works; or,
|
||||||
|
within a display generated by the Derivative Works, if and
|
||||||
|
wherever such third-party notices normally appear. The contents
|
||||||
|
of the NOTICE file are for informational purposes only and
|
||||||
|
do not modify the License. You may add Your own attribution
|
||||||
|
notices within Derivative Works that You distribute, alongside
|
||||||
|
or as an addendum to the NOTICE text from the Work, provided
|
||||||
|
that such additional attribution notices cannot be construed
|
||||||
|
as modifying the License.
|
||||||
|
|
||||||
|
You may add Your own copyright statement to Your modifications and
|
||||||
|
may provide additional or different license terms and conditions
|
||||||
|
for use, reproduction, or distribution of Your modifications, or
|
||||||
|
for any such Derivative Works as a whole, provided Your use,
|
||||||
|
reproduction, and distribution of the Work otherwise complies with
|
||||||
|
the conditions stated in this License.
|
||||||
|
|
||||||
|
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||||
|
any Contribution intentionally submitted for inclusion in the Work
|
||||||
|
by You to the Licensor shall be under the terms and conditions of
|
||||||
|
this License, without any additional terms or conditions.
|
||||||
|
Notwithstanding the above, nothing herein shall supersede or modify
|
||||||
|
the terms of any separate license agreement you may have executed
|
||||||
|
with Licensor regarding such Contributions.
|
||||||
|
|
||||||
|
6. Trademarks. This License does not grant permission to use the trade
|
||||||
|
names, trademarks, service marks, or product names of the Licensor,
|
||||||
|
except as required for reasonable and customary use in describing the
|
||||||
|
origin of the Work and reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
|
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||||
|
agreed to in writing, Licensor provides the Work (and each
|
||||||
|
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
implied, including, without limitation, any warranties or conditions
|
||||||
|
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||||
|
appropriateness of using or redistributing the Work and assume any
|
||||||
|
risks associated with Your exercise of permissions under this License.
|
||||||
|
|
||||||
|
8. Limitation of Liability. In no event and under no legal theory,
|
||||||
|
whether in tort (including negligence), contract, or otherwise,
|
||||||
|
unless required by applicable law (such as deliberate and grossly
|
||||||
|
negligent acts) or agreed to in writing, shall any Contributor be
|
||||||
|
liable to You for damages, including any direct, indirect, special,
|
||||||
|
incidental, or consequential damages of any character arising as a
|
||||||
|
result of this License or out of the use or inability to use the
|
||||||
|
Work (including but not limited to damages for loss of goodwill,
|
||||||
|
work stoppage, computer failure or malfunction, or any and all
|
||||||
|
other commercial damages or losses), even if such Contributor
|
||||||
|
has been advised of the possibility of such damages.
|
||||||
|
|
||||||
|
9. Accepting Warranty or Additional Liability. While redistributing
|
||||||
|
the Work or Derivative Works thereof, You may choose to offer,
|
||||||
|
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||||
|
or other liability obligations and/or rights consistent with this
|
||||||
|
License. However, in accepting such obligations, You may act only
|
||||||
|
on Your own behalf and on Your sole responsibility, not on behalf
|
||||||
|
of any other Contributor, and only if You agree to indemnify,
|
||||||
|
defend, and hold each Contributor harmless for any liability
|
||||||
|
incurred by, or claims asserted against, such Contributor by reason
|
||||||
|
of your accepting any such warranty or additional liability.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
Copyright 2013-2016 Docker, Inc.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
340
vendor/src/github.com/docker/docker/contrib/docker-engine-selinux/LICENSE
vendored
Normal file
340
vendor/src/github.com/docker/docker/contrib/docker-engine-selinux/LICENSE
vendored
Normal file
|
@ -0,0 +1,340 @@
|
||||||
|
GNU GENERAL PUBLIC LICENSE
|
||||||
|
Version 2, June 1991
|
||||||
|
|
||||||
|
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
|
||||||
|
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
Everyone is permitted to copy and distribute verbatim copies
|
||||||
|
of this license document, but changing it is not allowed.
|
||||||
|
|
||||||
|
Preamble
|
||||||
|
|
||||||
|
The licenses for most software are designed to take away your
|
||||||
|
freedom to share and change it. By contrast, the GNU General Public
|
||||||
|
License is intended to guarantee your freedom to share and change free
|
||||||
|
software--to make sure the software is free for all its users. This
|
||||||
|
General Public License applies to most of the Free Software
|
||||||
|
Foundation's software and to any other program whose authors commit to
|
||||||
|
using it. (Some other Free Software Foundation software is covered by
|
||||||
|
the GNU Library General Public License instead.) You can apply it to
|
||||||
|
your programs, too.
|
||||||
|
|
||||||
|
When we speak of free software, we are referring to freedom, not
|
||||||
|
price. Our General Public Licenses are designed to make sure that you
|
||||||
|
have the freedom to distribute copies of free software (and charge for
|
||||||
|
this service if you wish), that you receive source code or can get it
|
||||||
|
if you want it, that you can change the software or use pieces of it
|
||||||
|
in new free programs; and that you know you can do these things.
|
||||||
|
|
||||||
|
To protect your rights, we need to make restrictions that forbid
|
||||||
|
anyone to deny you these rights or to ask you to surrender the rights.
|
||||||
|
These restrictions translate to certain responsibilities for you if you
|
||||||
|
distribute copies of the software, or if you modify it.
|
||||||
|
|
||||||
|
For example, if you distribute copies of such a program, whether
|
||||||
|
gratis or for a fee, you must give the recipients all the rights that
|
||||||
|
you have. You must make sure that they, too, receive or can get the
|
||||||
|
source code. And you must show them these terms so they know their
|
||||||
|
rights.
|
||||||
|
|
||||||
|
We protect your rights with two steps: (1) copyright the software, and
|
||||||
|
(2) offer you this license which gives you legal permission to copy,
|
||||||
|
distribute and/or modify the software.
|
||||||
|
|
||||||
|
Also, for each author's protection and ours, we want to make certain
|
||||||
|
that everyone understands that there is no warranty for this free
|
||||||
|
software. If the software is modified by someone else and passed on, we
|
||||||
|
want its recipients to know that what they have is not the original, so
|
||||||
|
that any problems introduced by others will not reflect on the original
|
||||||
|
authors' reputations.
|
||||||
|
|
||||||
|
Finally, any free program is threatened constantly by software
|
||||||
|
patents. We wish to avoid the danger that redistributors of a free
|
||||||
|
program will individually obtain patent licenses, in effect making the
|
||||||
|
program proprietary. To prevent this, we have made it clear that any
|
||||||
|
patent must be licensed for everyone's free use or not licensed at all.
|
||||||
|
|
||||||
|
The precise terms and conditions for copying, distribution and
|
||||||
|
modification follow.
|
||||||
|
|
||||||
|
GNU GENERAL PUBLIC LICENSE
|
||||||
|
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||||
|
|
||||||
|
0. This License applies to any program or other work which contains
|
||||||
|
a notice placed by the copyright holder saying it may be distributed
|
||||||
|
under the terms of this General Public License. The "Program", below,
|
||||||
|
refers to any such program or work, and a "work based on the Program"
|
||||||
|
means either the Program or any derivative work under copyright law:
|
||||||
|
that is to say, a work containing the Program or a portion of it,
|
||||||
|
either verbatim or with modifications and/or translated into another
|
||||||
|
language. (Hereinafter, translation is included without limitation in
|
||||||
|
the term "modification".) Each licensee is addressed as "you".
|
||||||
|
|
||||||
|
Activities other than copying, distribution and modification are not
|
||||||
|
covered by this License; they are outside its scope. The act of
|
||||||
|
running the Program is not restricted, and the output from the Program
|
||||||
|
is covered only if its contents constitute a work based on the
|
||||||
|
Program (independent of having been made by running the Program).
|
||||||
|
Whether that is true depends on what the Program does.
|
||||||
|
|
||||||
|
1. You may copy and distribute verbatim copies of the Program's
|
||||||
|
source code as you receive it, in any medium, provided that you
|
||||||
|
conspicuously and appropriately publish on each copy an appropriate
|
||||||
|
copyright notice and disclaimer of warranty; keep intact all the
|
||||||
|
notices that refer to this License and to the absence of any warranty;
|
||||||
|
and give any other recipients of the Program a copy of this License
|
||||||
|
along with the Program.
|
||||||
|
|
||||||
|
You may charge a fee for the physical act of transferring a copy, and
|
||||||
|
you may at your option offer warranty protection in exchange for a fee.
|
||||||
|
|
||||||
|
2. You may modify your copy or copies of the Program or any portion
|
||||||
|
of it, thus forming a work based on the Program, and copy and
|
||||||
|
distribute such modifications or work under the terms of Section 1
|
||||||
|
above, provided that you also meet all of these conditions:
|
||||||
|
|
||||||
|
a) You must cause the modified files to carry prominent notices
|
||||||
|
stating that you changed the files and the date of any change.
|
||||||
|
|
||||||
|
b) You must cause any work that you distribute or publish, that in
|
||||||
|
whole or in part contains or is derived from the Program or any
|
||||||
|
part thereof, to be licensed as a whole at no charge to all third
|
||||||
|
parties under the terms of this License.
|
||||||
|
|
||||||
|
c) If the modified program normally reads commands interactively
|
||||||
|
when run, you must cause it, when started running for such
|
||||||
|
interactive use in the most ordinary way, to print or display an
|
||||||
|
announcement including an appropriate copyright notice and a
|
||||||
|
notice that there is no warranty (or else, saying that you provide
|
||||||
|
a warranty) and that users may redistribute the program under
|
||||||
|
these conditions, and telling the user how to view a copy of this
|
||||||
|
License. (Exception: if the Program itself is interactive but
|
||||||
|
does not normally print such an announcement, your work based on
|
||||||
|
the Program is not required to print an announcement.)
|
||||||
|
|
||||||
|
These requirements apply to the modified work as a whole. If
|
||||||
|
identifiable sections of that work are not derived from the Program,
|
||||||
|
and can be reasonably considered independent and separate works in
|
||||||
|
themselves, then this License, and its terms, do not apply to those
|
||||||
|
sections when you distribute them as separate works. But when you
|
||||||
|
distribute the same sections as part of a whole which is a work based
|
||||||
|
on the Program, the distribution of the whole must be on the terms of
|
||||||
|
this License, whose permissions for other licensees extend to the
|
||||||
|
entire whole, and thus to each and every part regardless of who wrote it.
|
||||||
|
|
||||||
|
Thus, it is not the intent of this section to claim rights or contest
|
||||||
|
your rights to work written entirely by you; rather, the intent is to
|
||||||
|
exercise the right to control the distribution of derivative or
|
||||||
|
collective works based on the Program.
|
||||||
|
|
||||||
|
In addition, mere aggregation of another work not based on the Program
|
||||||
|
with the Program (or with a work based on the Program) on a volume of
|
||||||
|
a storage or distribution medium does not bring the other work under
|
||||||
|
the scope of this License.
|
||||||
|
|
||||||
|
3. You may copy and distribute the Program (or a work based on it,
|
||||||
|
under Section 2) in object code or executable form under the terms of
|
||||||
|
Sections 1 and 2 above provided that you also do one of the following:
|
||||||
|
|
||||||
|
a) Accompany it with the complete corresponding machine-readable
|
||||||
|
source code, which must be distributed under the terms of Sections
|
||||||
|
1 and 2 above on a medium customarily used for software interchange; or,
|
||||||
|
|
||||||
|
b) Accompany it with a written offer, valid for at least three
|
||||||
|
years, to give any third party, for a charge no more than your
|
||||||
|
cost of physically performing source distribution, a complete
|
||||||
|
machine-readable copy of the corresponding source code, to be
|
||||||
|
distributed under the terms of Sections 1 and 2 above on a medium
|
||||||
|
customarily used for software interchange; or,
|
||||||
|
|
||||||
|
c) Accompany it with the information you received as to the offer
|
||||||
|
to distribute corresponding source code. (This alternative is
|
||||||
|
allowed only for noncommercial distribution and only if you
|
||||||
|
received the program in object code or executable form with such
|
||||||
|
an offer, in accord with Subsection b above.)
|
||||||
|
|
||||||
|
The source code for a work means the preferred form of the work for
|
||||||
|
making modifications to it. For an executable work, complete source
|
||||||
|
code means all the source code for all modules it contains, plus any
|
||||||
|
associated interface definition files, plus the scripts used to
|
||||||
|
control compilation and installation of the executable. However, as a
|
||||||
|
special exception, the source code distributed need not include
|
||||||
|
anything that is normally distributed (in either source or binary
|
||||||
|
form) with the major components (compiler, kernel, and so on) of the
|
||||||
|
operating system on which the executable runs, unless that component
|
||||||
|
itself accompanies the executable.
|
||||||
|
|
||||||
|
If distribution of executable or object code is made by offering
|
||||||
|
access to copy from a designated place, then offering equivalent
|
||||||
|
access to copy the source code from the same place counts as
|
||||||
|
distribution of the source code, even though third parties are not
|
||||||
|
compelled to copy the source along with the object code.
|
||||||
|
|
||||||
|
4. You may not copy, modify, sublicense, or distribute the Program
|
||||||
|
except as expressly provided under this License. Any attempt
|
||||||
|
otherwise to copy, modify, sublicense or distribute the Program is
|
||||||
|
void, and will automatically terminate your rights under this License.
|
||||||
|
However, parties who have received copies, or rights, from you under
|
||||||
|
this License will not have their licenses terminated so long as such
|
||||||
|
parties remain in full compliance.
|
||||||
|
|
||||||
|
5. You are not required to accept this License, since you have not
|
||||||
|
signed it. However, nothing else grants you permission to modify or
|
||||||
|
distribute the Program or its derivative works. These actions are
|
||||||
|
prohibited by law if you do not accept this License. Therefore, by
|
||||||
|
modifying or distributing the Program (or any work based on the
|
||||||
|
Program), you indicate your acceptance of this License to do so, and
|
||||||
|
all its terms and conditions for copying, distributing or modifying
|
||||||
|
the Program or works based on it.
|
||||||
|
|
||||||
|
6. Each time you redistribute the Program (or any work based on the
|
||||||
|
Program), the recipient automatically receives a license from the
|
||||||
|
original licensor to copy, distribute or modify the Program subject to
|
||||||
|
these terms and conditions. You may not impose any further
|
||||||
|
restrictions on the recipients' exercise of the rights granted herein.
|
||||||
|
You are not responsible for enforcing compliance by third parties to
|
||||||
|
this License.
|
||||||
|
|
||||||
|
7. If, as a consequence of a court judgment or allegation of patent
|
||||||
|
infringement or for any other reason (not limited to patent issues),
|
||||||
|
conditions are imposed on you (whether by court order, agreement or
|
||||||
|
otherwise) that contradict the conditions of this License, they do not
|
||||||
|
excuse you from the conditions of this License. If you cannot
|
||||||
|
distribute so as to satisfy simultaneously your obligations under this
|
||||||
|
License and any other pertinent obligations, then as a consequence you
|
||||||
|
may not distribute the Program at all. For example, if a patent
|
||||||
|
license would not permit royalty-free redistribution of the Program by
|
||||||
|
all those who receive copies directly or indirectly through you, then
|
||||||
|
the only way you could satisfy both it and this License would be to
|
||||||
|
refrain entirely from distribution of the Program.
|
||||||
|
|
||||||
|
If any portion of this section is held invalid or unenforceable under
|
||||||
|
any particular circumstance, the balance of the section is intended to
|
||||||
|
apply and the section as a whole is intended to apply in other
|
||||||
|
circumstances.
|
||||||
|
|
||||||
|
It is not the purpose of this section to induce you to infringe any
|
||||||
|
patents or other property right claims or to contest validity of any
|
||||||
|
such claims; this section has the sole purpose of protecting the
|
||||||
|
integrity of the free software distribution system, which is
|
||||||
|
implemented by public license practices. Many people have made
|
||||||
|
generous contributions to the wide range of software distributed
|
||||||
|
through that system in reliance on consistent application of that
|
||||||
|
system; it is up to the author/donor to decide if he or she is willing
|
||||||
|
to distribute software through any other system and a licensee cannot
|
||||||
|
impose that choice.
|
||||||
|
|
||||||
|
This section is intended to make thoroughly clear what is believed to
|
||||||
|
be a consequence of the rest of this License.
|
||||||
|
|
||||||
|
8. If the distribution and/or use of the Program is restricted in
|
||||||
|
certain countries either by patents or by copyrighted interfaces, the
|
||||||
|
original copyright holder who places the Program under this License
|
||||||
|
may add an explicit geographical distribution limitation excluding
|
||||||
|
those countries, so that distribution is permitted only in or among
|
||||||
|
countries not thus excluded. In such case, this License incorporates
|
||||||
|
the limitation as if written in the body of this License.
|
||||||
|
|
||||||
|
9. The Free Software Foundation may publish revised and/or new versions
|
||||||
|
of the General Public License from time to time. Such new versions will
|
||||||
|
be similar in spirit to the present version, but may differ in detail to
|
||||||
|
address new problems or concerns.
|
||||||
|
|
||||||
|
Each version is given a distinguishing version number. If the Program
|
||||||
|
specifies a version number of this License which applies to it and "any
|
||||||
|
later version", you have the option of following the terms and conditions
|
||||||
|
either of that version or of any later version published by the Free
|
||||||
|
Software Foundation. If the Program does not specify a version number of
|
||||||
|
this License, you may choose any version ever published by the Free Software
|
||||||
|
Foundation.
|
||||||
|
|
||||||
|
10. If you wish to incorporate parts of the Program into other free
|
||||||
|
programs whose distribution conditions are different, write to the author
|
||||||
|
to ask for permission. For software which is copyrighted by the Free
|
||||||
|
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||||
|
make exceptions for this. Our decision will be guided by the two goals
|
||||||
|
of preserving the free status of all derivatives of our free software and
|
||||||
|
of promoting the sharing and reuse of software generally.
|
||||||
|
|
||||||
|
NO WARRANTY
|
||||||
|
|
||||||
|
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||||
|
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||||
|
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||||
|
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||||
|
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||||
|
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||||
|
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||||
|
REPAIR OR CORRECTION.
|
||||||
|
|
||||||
|
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||||
|
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||||
|
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||||
|
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||||
|
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||||
|
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||||
|
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||||
|
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||||
|
POSSIBILITY OF SUCH DAMAGES.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
How to Apply These Terms to Your New Programs
|
||||||
|
|
||||||
|
If you develop a new program, and you want it to be of the greatest
|
||||||
|
possible use to the public, the best way to achieve this is to make it
|
||||||
|
free software which everyone can redistribute and change under these terms.
|
||||||
|
|
||||||
|
To do so, attach the following notices to the program. It is safest
|
||||||
|
to attach them to the start of each source file to most effectively
|
||||||
|
convey the exclusion of warranty; and each file should have at least
|
||||||
|
the "copyright" line and a pointer to where the full notice is found.
|
||||||
|
|
||||||
|
<one line to give the program's name and a brief idea of what it does.>
|
||||||
|
Copyright (C) <year> <name of author>
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
|
||||||
|
|
||||||
|
Also add information on how to contact you by electronic and paper mail.
|
||||||
|
|
||||||
|
If the program is interactive, make it output a short notice like this
|
||||||
|
when it starts in an interactive mode:
|
||||||
|
|
||||||
|
Gnomovision version 69, Copyright (C) year name of author
|
||||||
|
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||||
|
This is free software, and you are welcome to redistribute it
|
||||||
|
under certain conditions; type `show c' for details.
|
||||||
|
|
||||||
|
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||||
|
parts of the General Public License. Of course, the commands you use may
|
||||||
|
be called something other than `show w' and `show c'; they could even be
|
||||||
|
mouse-clicks or menu items--whatever suits your program.
|
||||||
|
|
||||||
|
You should also get your employer (if you work as a programmer) or your
|
||||||
|
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||||
|
necessary. Here is a sample; alter the names:
|
||||||
|
|
||||||
|
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||||
|
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||||
|
|
||||||
|
<signature of Ty Coon>, 1 April 1989
|
||||||
|
Ty Coon, President of Vice
|
||||||
|
|
||||||
|
This General Public License does not permit incorporating your program into
|
||||||
|
proprietary programs. If your program is a subroutine library, you may
|
||||||
|
consider it more useful to permit linking proprietary applications with the
|
||||||
|
library. If this is what you want to do, use the GNU Library General
|
||||||
|
Public License instead of this License.
|
22
vendor/src/github.com/docker/docker/contrib/syntax/vim/LICENSE
vendored
Normal file
22
vendor/src/github.com/docker/docker/contrib/syntax/vim/LICENSE
vendored
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
Copyright (c) 2013 Honza Pokorny
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
1. Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
2. 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.
|
||||||
|
|
||||||
|
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.
|
27
vendor/src/github.com/docker/docker/pkg/mflag/LICENSE
vendored
Normal file
27
vendor/src/github.com/docker/docker/pkg/mflag/LICENSE
vendored
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
Copyright (c) 2014-2016 The Docker & 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.
|
92
vendor/src/github.com/docker/docker/pkg/mount/flags.go
vendored
Normal file
92
vendor/src/github.com/docker/docker/pkg/mount/flags.go
vendored
Normal file
|
@ -0,0 +1,92 @@
|
||||||
|
package mount
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Parse fstab type mount options into mount() flags
|
||||||
|
// and device specific data
|
||||||
|
func parseOptions(options string) (int, string) {
|
||||||
|
var (
|
||||||
|
flag int
|
||||||
|
data []string
|
||||||
|
)
|
||||||
|
|
||||||
|
flags := map[string]struct {
|
||||||
|
clear bool
|
||||||
|
flag int
|
||||||
|
}{
|
||||||
|
"defaults": {false, 0},
|
||||||
|
"ro": {false, RDONLY},
|
||||||
|
"rw": {true, RDONLY},
|
||||||
|
"suid": {true, NOSUID},
|
||||||
|
"nosuid": {false, NOSUID},
|
||||||
|
"dev": {true, NODEV},
|
||||||
|
"nodev": {false, NODEV},
|
||||||
|
"exec": {true, NOEXEC},
|
||||||
|
"noexec": {false, NOEXEC},
|
||||||
|
"sync": {false, SYNCHRONOUS},
|
||||||
|
"async": {true, SYNCHRONOUS},
|
||||||
|
"dirsync": {false, DIRSYNC},
|
||||||
|
"remount": {false, REMOUNT},
|
||||||
|
"mand": {false, MANDLOCK},
|
||||||
|
"nomand": {true, MANDLOCK},
|
||||||
|
"atime": {true, NOATIME},
|
||||||
|
"noatime": {false, NOATIME},
|
||||||
|
"diratime": {true, NODIRATIME},
|
||||||
|
"nodiratime": {false, NODIRATIME},
|
||||||
|
"bind": {false, BIND},
|
||||||
|
"rbind": {false, RBIND},
|
||||||
|
"unbindable": {false, UNBINDABLE},
|
||||||
|
"runbindable": {false, RUNBINDABLE},
|
||||||
|
"private": {false, PRIVATE},
|
||||||
|
"rprivate": {false, RPRIVATE},
|
||||||
|
"shared": {false, SHARED},
|
||||||
|
"rshared": {false, RSHARED},
|
||||||
|
"slave": {false, SLAVE},
|
||||||
|
"rslave": {false, RSLAVE},
|
||||||
|
"relatime": {false, RELATIME},
|
||||||
|
"norelatime": {true, RELATIME},
|
||||||
|
"strictatime": {false, STRICTATIME},
|
||||||
|
"nostrictatime": {true, STRICTATIME},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, o := range strings.Split(options, ",") {
|
||||||
|
// If the option does not exist in the flags table or the flag
|
||||||
|
// is not supported on the platform,
|
||||||
|
// then it is a data value for a specific fs type
|
||||||
|
if f, exists := flags[o]; exists && f.flag != 0 {
|
||||||
|
if f.clear {
|
||||||
|
flag &= ^f.flag
|
||||||
|
} else {
|
||||||
|
flag |= f.flag
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
data = append(data, o)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return flag, strings.Join(data, ",")
|
||||||
|
}
|
||||||
|
|
||||||
|
// ParseTmpfsOptions parse fstab type mount options into flags and data
|
||||||
|
func ParseTmpfsOptions(options string) (int, string, error) {
|
||||||
|
flags, data := parseOptions(options)
|
||||||
|
validFlags := map[string]bool{
|
||||||
|
"": true,
|
||||||
|
"size": true,
|
||||||
|
"mode": true,
|
||||||
|
"uid": true,
|
||||||
|
"gid": true,
|
||||||
|
"nr_inodes": true,
|
||||||
|
"nr_blocks": true,
|
||||||
|
"mpol": true,
|
||||||
|
}
|
||||||
|
for _, o := range strings.Split(data, ",") {
|
||||||
|
opt := strings.SplitN(o, "=", 2)
|
||||||
|
if !validFlags[opt[0]] {
|
||||||
|
return 0, "", fmt.Errorf("Invalid tmpfs option %q", opt)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return flags, data, nil
|
||||||
|
}
|
48
vendor/src/github.com/docker/docker/pkg/mount/flags_freebsd.go
vendored
Normal file
48
vendor/src/github.com/docker/docker/pkg/mount/flags_freebsd.go
vendored
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
// +build freebsd,cgo
|
||||||
|
|
||||||
|
package mount
|
||||||
|
|
||||||
|
/*
|
||||||
|
#include <sys/mount.h>
|
||||||
|
*/
|
||||||
|
import "C"
|
||||||
|
|
||||||
|
const (
|
||||||
|
// RDONLY will mount the filesystem as read-only.
|
||||||
|
RDONLY = C.MNT_RDONLY
|
||||||
|
|
||||||
|
// NOSUID will not allow set-user-identifier or set-group-identifier bits to
|
||||||
|
// take effect.
|
||||||
|
NOSUID = C.MNT_NOSUID
|
||||||
|
|
||||||
|
// NOEXEC will not allow execution of any binaries on the mounted file system.
|
||||||
|
NOEXEC = C.MNT_NOEXEC
|
||||||
|
|
||||||
|
// SYNCHRONOUS will allow any I/O to the file system to be done synchronously.
|
||||||
|
SYNCHRONOUS = C.MNT_SYNCHRONOUS
|
||||||
|
|
||||||
|
// NOATIME will not update the file access time when reading from a file.
|
||||||
|
NOATIME = C.MNT_NOATIME
|
||||||
|
)
|
||||||
|
|
||||||
|
// These flags are unsupported.
|
||||||
|
const (
|
||||||
|
BIND = 0
|
||||||
|
DIRSYNC = 0
|
||||||
|
MANDLOCK = 0
|
||||||
|
NODEV = 0
|
||||||
|
NODIRATIME = 0
|
||||||
|
UNBINDABLE = 0
|
||||||
|
RUNBINDABLE = 0
|
||||||
|
PRIVATE = 0
|
||||||
|
RPRIVATE = 0
|
||||||
|
SHARED = 0
|
||||||
|
RSHARED = 0
|
||||||
|
SLAVE = 0
|
||||||
|
RSLAVE = 0
|
||||||
|
RBIND = 0
|
||||||
|
RELATIVE = 0
|
||||||
|
RELATIME = 0
|
||||||
|
REMOUNT = 0
|
||||||
|
STRICTATIME = 0
|
||||||
|
)
|
85
vendor/src/github.com/docker/docker/pkg/mount/flags_linux.go
vendored
Normal file
85
vendor/src/github.com/docker/docker/pkg/mount/flags_linux.go
vendored
Normal file
|
@ -0,0 +1,85 @@
|
||||||
|
package mount
|
||||||
|
|
||||||
|
import (
|
||||||
|
"syscall"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// RDONLY will mount the file system read-only.
|
||||||
|
RDONLY = syscall.MS_RDONLY
|
||||||
|
|
||||||
|
// NOSUID will not allow set-user-identifier or set-group-identifier bits to
|
||||||
|
// take effect.
|
||||||
|
NOSUID = syscall.MS_NOSUID
|
||||||
|
|
||||||
|
// NODEV will not interpret character or block special devices on the file
|
||||||
|
// system.
|
||||||
|
NODEV = syscall.MS_NODEV
|
||||||
|
|
||||||
|
// NOEXEC will not allow execution of any binaries on the mounted file system.
|
||||||
|
NOEXEC = syscall.MS_NOEXEC
|
||||||
|
|
||||||
|
// SYNCHRONOUS will allow I/O to the file system to be done synchronously.
|
||||||
|
SYNCHRONOUS = syscall.MS_SYNCHRONOUS
|
||||||
|
|
||||||
|
// DIRSYNC will force all directory updates within the file system to be done
|
||||||
|
// synchronously. This affects the following system calls: create, link,
|
||||||
|
// unlink, symlink, mkdir, rmdir, mknod and rename.
|
||||||
|
DIRSYNC = syscall.MS_DIRSYNC
|
||||||
|
|
||||||
|
// REMOUNT will attempt to remount an already-mounted file system. This is
|
||||||
|
// commonly used to change the mount flags for a file system, especially to
|
||||||
|
// make a readonly file system writeable. It does not change device or mount
|
||||||
|
// point.
|
||||||
|
REMOUNT = syscall.MS_REMOUNT
|
||||||
|
|
||||||
|
// MANDLOCK will force mandatory locks on a filesystem.
|
||||||
|
MANDLOCK = syscall.MS_MANDLOCK
|
||||||
|
|
||||||
|
// NOATIME will not update the file access time when reading from a file.
|
||||||
|
NOATIME = syscall.MS_NOATIME
|
||||||
|
|
||||||
|
// NODIRATIME will not update the directory access time.
|
||||||
|
NODIRATIME = syscall.MS_NODIRATIME
|
||||||
|
|
||||||
|
// BIND remounts a subtree somewhere else.
|
||||||
|
BIND = syscall.MS_BIND
|
||||||
|
|
||||||
|
// RBIND remounts a subtree and all possible submounts somewhere else.
|
||||||
|
RBIND = syscall.MS_BIND | syscall.MS_REC
|
||||||
|
|
||||||
|
// UNBINDABLE creates a mount which cannot be cloned through a bind operation.
|
||||||
|
UNBINDABLE = syscall.MS_UNBINDABLE
|
||||||
|
|
||||||
|
// RUNBINDABLE marks the entire mount tree as UNBINDABLE.
|
||||||
|
RUNBINDABLE = syscall.MS_UNBINDABLE | syscall.MS_REC
|
||||||
|
|
||||||
|
// PRIVATE creates a mount which carries no propagation abilities.
|
||||||
|
PRIVATE = syscall.MS_PRIVATE
|
||||||
|
|
||||||
|
// RPRIVATE marks the entire mount tree as PRIVATE.
|
||||||
|
RPRIVATE = syscall.MS_PRIVATE | syscall.MS_REC
|
||||||
|
|
||||||
|
// SLAVE creates a mount which receives propagation from its master, but not
|
||||||
|
// vice versa.
|
||||||
|
SLAVE = syscall.MS_SLAVE
|
||||||
|
|
||||||
|
// RSLAVE marks the entire mount tree as SLAVE.
|
||||||
|
RSLAVE = syscall.MS_SLAVE | syscall.MS_REC
|
||||||
|
|
||||||
|
// SHARED creates a mount which provides the ability to create mirrors of
|
||||||
|
// that mount such that mounts and unmounts within any of the mirrors
|
||||||
|
// propagate to the other mirrors.
|
||||||
|
SHARED = syscall.MS_SHARED
|
||||||
|
|
||||||
|
// RSHARED marks the entire mount tree as SHARED.
|
||||||
|
RSHARED = syscall.MS_SHARED | syscall.MS_REC
|
||||||
|
|
||||||
|
// RELATIME updates inode access times relative to modify or change time.
|
||||||
|
RELATIME = syscall.MS_RELATIME
|
||||||
|
|
||||||
|
// STRICTATIME allows to explicitly request full atime updates. This makes
|
||||||
|
// it possible for the kernel to default to relatime or noatime but still
|
||||||
|
// allow userspace to override it.
|
||||||
|
STRICTATIME = syscall.MS_STRICTATIME
|
||||||
|
)
|
30
vendor/src/github.com/docker/docker/pkg/mount/flags_unsupported.go
vendored
Normal file
30
vendor/src/github.com/docker/docker/pkg/mount/flags_unsupported.go
vendored
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
// +build !linux,!freebsd freebsd,!cgo
|
||||||
|
|
||||||
|
package mount
|
||||||
|
|
||||||
|
// These flags are unsupported.
|
||||||
|
const (
|
||||||
|
BIND = 0
|
||||||
|
DIRSYNC = 0
|
||||||
|
MANDLOCK = 0
|
||||||
|
NOATIME = 0
|
||||||
|
NODEV = 0
|
||||||
|
NODIRATIME = 0
|
||||||
|
NOEXEC = 0
|
||||||
|
NOSUID = 0
|
||||||
|
UNBINDABLE = 0
|
||||||
|
RUNBINDABLE = 0
|
||||||
|
PRIVATE = 0
|
||||||
|
RPRIVATE = 0
|
||||||
|
SHARED = 0
|
||||||
|
RSHARED = 0
|
||||||
|
SLAVE = 0
|
||||||
|
RSLAVE = 0
|
||||||
|
RBIND = 0
|
||||||
|
RELATIME = 0
|
||||||
|
RELATIVE = 0
|
||||||
|
REMOUNT = 0
|
||||||
|
STRICTATIME = 0
|
||||||
|
SYNCHRONOUS = 0
|
||||||
|
RDONLY = 0
|
||||||
|
)
|
74
vendor/src/github.com/docker/docker/pkg/mount/mount.go
vendored
Normal file
74
vendor/src/github.com/docker/docker/pkg/mount/mount.go
vendored
Normal file
|
@ -0,0 +1,74 @@
|
||||||
|
package mount
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// GetMounts retrieves a list of mounts for the current running process.
|
||||||
|
func GetMounts() ([]*Info, error) {
|
||||||
|
return parseMountTable()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mounted looks at /proc/self/mountinfo to determine of the specified
|
||||||
|
// mountpoint has been mounted
|
||||||
|
func Mounted(mountpoint string) (bool, error) {
|
||||||
|
entries, err := parseMountTable()
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Search the table for the mountpoint
|
||||||
|
for _, e := range entries {
|
||||||
|
if e.Mountpoint == mountpoint {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mount will mount filesystem according to the specified configuration, on the
|
||||||
|
// condition that the target path is *not* already mounted. Options must be
|
||||||
|
// specified like the mount or fstab unix commands: "opt1=val1,opt2=val2". See
|
||||||
|
// flags.go for supported option flags.
|
||||||
|
func Mount(device, target, mType, options string) error {
|
||||||
|
flag, _ := parseOptions(options)
|
||||||
|
if flag&REMOUNT != REMOUNT {
|
||||||
|
if mounted, err := Mounted(target); err != nil || mounted {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ForceMount(device, target, mType, options)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ForceMount will mount a filesystem according to the specified configuration,
|
||||||
|
// *regardless* if the target path is not already mounted. Options must be
|
||||||
|
// specified like the mount or fstab unix commands: "opt1=val1,opt2=val2". See
|
||||||
|
// flags.go for supported option flags.
|
||||||
|
func ForceMount(device, target, mType, options string) error {
|
||||||
|
flag, data := parseOptions(options)
|
||||||
|
if err := mount(device, target, mType, uintptr(flag), data); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unmount will unmount the target filesystem, so long as it is mounted.
|
||||||
|
func Unmount(target string) error {
|
||||||
|
if mounted, err := Mounted(target); err != nil || !mounted {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return ForceUnmount(target)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ForceUnmount will force an unmount of the target filesystem, regardless if
|
||||||
|
// it is mounted or not.
|
||||||
|
func ForceUnmount(target string) (err error) {
|
||||||
|
// Simple retry logic for unmount
|
||||||
|
for i := 0; i < 10; i++ {
|
||||||
|
if err = unmount(target, 0); err == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
time.Sleep(100 * time.Millisecond)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
59
vendor/src/github.com/docker/docker/pkg/mount/mounter_freebsd.go
vendored
Normal file
59
vendor/src/github.com/docker/docker/pkg/mount/mounter_freebsd.go
vendored
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
package mount
|
||||||
|
|
||||||
|
/*
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/_iovec.h>
|
||||||
|
#include <sys/mount.h>
|
||||||
|
#include <sys/param.h>
|
||||||
|
*/
|
||||||
|
import "C"
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
"syscall"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
func allocateIOVecs(options []string) []C.struct_iovec {
|
||||||
|
out := make([]C.struct_iovec, len(options))
|
||||||
|
for i, option := range options {
|
||||||
|
out[i].iov_base = unsafe.Pointer(C.CString(option))
|
||||||
|
out[i].iov_len = C.size_t(len(option) + 1)
|
||||||
|
}
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
func mount(device, target, mType string, flag uintptr, data string) error {
|
||||||
|
isNullFS := false
|
||||||
|
|
||||||
|
xs := strings.Split(data, ",")
|
||||||
|
for _, x := range xs {
|
||||||
|
if x == "bind" {
|
||||||
|
isNullFS = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
options := []string{"fspath", target}
|
||||||
|
if isNullFS {
|
||||||
|
options = append(options, "fstype", "nullfs", "target", device)
|
||||||
|
} else {
|
||||||
|
options = append(options, "fstype", mType, "from", device)
|
||||||
|
}
|
||||||
|
rawOptions := allocateIOVecs(options)
|
||||||
|
for _, rawOption := range rawOptions {
|
||||||
|
defer C.free(rawOption.iov_base)
|
||||||
|
}
|
||||||
|
|
||||||
|
if errno := C.nmount(&rawOptions[0], C.uint(len(options)), C.int(flag)); errno != 0 {
|
||||||
|
reason := C.GoString(C.strerror(*C.__error()))
|
||||||
|
return fmt.Errorf("Failed to call nmount: %s", reason)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func unmount(target string, flag int) error {
|
||||||
|
return syscall.Unmount(target, flag)
|
||||||
|
}
|
21
vendor/src/github.com/docker/docker/pkg/mount/mounter_linux.go
vendored
Normal file
21
vendor/src/github.com/docker/docker/pkg/mount/mounter_linux.go
vendored
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
package mount
|
||||||
|
|
||||||
|
import (
|
||||||
|
"syscall"
|
||||||
|
)
|
||||||
|
|
||||||
|
func mount(device, target, mType string, flag uintptr, data string) error {
|
||||||
|
if err := syscall.Mount(device, target, mType, flag, data); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we have a bind mount or remount, remount...
|
||||||
|
if flag&syscall.MS_BIND == syscall.MS_BIND && flag&syscall.MS_RDONLY == syscall.MS_RDONLY {
|
||||||
|
return syscall.Mount(device, target, mType, flag|syscall.MS_REMOUNT, data)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func unmount(target string, flag int) error {
|
||||||
|
return syscall.Unmount(target, flag)
|
||||||
|
}
|
11
vendor/src/github.com/docker/docker/pkg/mount/mounter_unsupported.go
vendored
Normal file
11
vendor/src/github.com/docker/docker/pkg/mount/mounter_unsupported.go
vendored
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
// +build !linux,!freebsd freebsd,!cgo
|
||||||
|
|
||||||
|
package mount
|
||||||
|
|
||||||
|
func mount(device, target, mType string, flag uintptr, data string) error {
|
||||||
|
panic("Not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
func unmount(target string, flag int) error {
|
||||||
|
panic("Not implemented")
|
||||||
|
}
|
40
vendor/src/github.com/docker/docker/pkg/mount/mountinfo.go
vendored
Normal file
40
vendor/src/github.com/docker/docker/pkg/mount/mountinfo.go
vendored
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
package mount
|
||||||
|
|
||||||
|
// Info reveals information about a particular mounted filesystem. This
|
||||||
|
// struct is populated from the content in the /proc/<pid>/mountinfo file.
|
||||||
|
type Info struct {
|
||||||
|
// ID is a unique identifier of the mount (may be reused after umount).
|
||||||
|
ID int
|
||||||
|
|
||||||
|
// Parent indicates the ID of the mount parent (or of self for the top of the
|
||||||
|
// mount tree).
|
||||||
|
Parent int
|
||||||
|
|
||||||
|
// Major indicates one half of the device ID which identifies the device class.
|
||||||
|
Major int
|
||||||
|
|
||||||
|
// Minor indicates one half of the device ID which identifies a specific
|
||||||
|
// instance of device.
|
||||||
|
Minor int
|
||||||
|
|
||||||
|
// Root of the mount within the filesystem.
|
||||||
|
Root string
|
||||||
|
|
||||||
|
// Mountpoint indicates the mount point relative to the process's root.
|
||||||
|
Mountpoint string
|
||||||
|
|
||||||
|
// Opts represents mount-specific options.
|
||||||
|
Opts string
|
||||||
|
|
||||||
|
// Optional represents optional fields.
|
||||||
|
Optional string
|
||||||
|
|
||||||
|
// Fstype indicates the type of filesystem, such as EXT3.
|
||||||
|
Fstype string
|
||||||
|
|
||||||
|
// Source indicates filesystem specific information or "none".
|
||||||
|
Source string
|
||||||
|
|
||||||
|
// VfsOpts represents per super block options.
|
||||||
|
VfsOpts string
|
||||||
|
}
|
41
vendor/src/github.com/docker/docker/pkg/mount/mountinfo_freebsd.go
vendored
Normal file
41
vendor/src/github.com/docker/docker/pkg/mount/mountinfo_freebsd.go
vendored
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
package mount
|
||||||
|
|
||||||
|
/*
|
||||||
|
#include <sys/param.h>
|
||||||
|
#include <sys/ucred.h>
|
||||||
|
#include <sys/mount.h>
|
||||||
|
*/
|
||||||
|
import "C"
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"reflect"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Parse /proc/self/mountinfo because comparing Dev and ino does not work from
|
||||||
|
// bind mounts.
|
||||||
|
func parseMountTable() ([]*Info, error) {
|
||||||
|
var rawEntries *C.struct_statfs
|
||||||
|
|
||||||
|
count := int(C.getmntinfo(&rawEntries, C.MNT_WAIT))
|
||||||
|
if count == 0 {
|
||||||
|
return nil, fmt.Errorf("Failed to call getmntinfo")
|
||||||
|
}
|
||||||
|
|
||||||
|
var entries []C.struct_statfs
|
||||||
|
header := (*reflect.SliceHeader)(unsafe.Pointer(&entries))
|
||||||
|
header.Cap = count
|
||||||
|
header.Len = count
|
||||||
|
header.Data = uintptr(unsafe.Pointer(rawEntries))
|
||||||
|
|
||||||
|
var out []*Info
|
||||||
|
for _, entry := range entries {
|
||||||
|
var mountinfo Info
|
||||||
|
mountinfo.Mountpoint = C.GoString(&entry.f_mntonname[0])
|
||||||
|
mountinfo.Source = C.GoString(&entry.f_mntfromname[0])
|
||||||
|
mountinfo.Fstype = C.GoString(&entry.f_fstypename[0])
|
||||||
|
out = append(out, &mountinfo)
|
||||||
|
}
|
||||||
|
return out, nil
|
||||||
|
}
|
95
vendor/src/github.com/docker/docker/pkg/mount/mountinfo_linux.go
vendored
Normal file
95
vendor/src/github.com/docker/docker/pkg/mount/mountinfo_linux.go
vendored
Normal file
|
@ -0,0 +1,95 @@
|
||||||
|
// +build linux
|
||||||
|
|
||||||
|
package mount
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
/* 36 35 98:0 /mnt1 /mnt2 rw,noatime master:1 - ext3 /dev/root rw,errors=continue
|
||||||
|
(1)(2)(3) (4) (5) (6) (7) (8) (9) (10) (11)
|
||||||
|
|
||||||
|
(1) mount ID: unique identifier of the mount (may be reused after umount)
|
||||||
|
(2) parent ID: ID of parent (or of self for the top of the mount tree)
|
||||||
|
(3) major:minor: value of st_dev for files on filesystem
|
||||||
|
(4) root: root of the mount within the filesystem
|
||||||
|
(5) mount point: mount point relative to the process's root
|
||||||
|
(6) mount options: per mount options
|
||||||
|
(7) optional fields: zero or more fields of the form "tag[:value]"
|
||||||
|
(8) separator: marks the end of the optional fields
|
||||||
|
(9) filesystem type: name of filesystem of the form "type[.subtype]"
|
||||||
|
(10) mount source: filesystem specific information or "none"
|
||||||
|
(11) super options: per super block options*/
|
||||||
|
mountinfoFormat = "%d %d %d:%d %s %s %s %s"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Parse /proc/self/mountinfo because comparing Dev and ino does not work from
|
||||||
|
// bind mounts
|
||||||
|
func parseMountTable() ([]*Info, error) {
|
||||||
|
f, err := os.Open("/proc/self/mountinfo")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
return parseInfoFile(f)
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseInfoFile(r io.Reader) ([]*Info, error) {
|
||||||
|
var (
|
||||||
|
s = bufio.NewScanner(r)
|
||||||
|
out = []*Info{}
|
||||||
|
)
|
||||||
|
|
||||||
|
for s.Scan() {
|
||||||
|
if err := s.Err(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
p = &Info{}
|
||||||
|
text = s.Text()
|
||||||
|
optionalFields string
|
||||||
|
)
|
||||||
|
|
||||||
|
if _, err := fmt.Sscanf(text, mountinfoFormat,
|
||||||
|
&p.ID, &p.Parent, &p.Major, &p.Minor,
|
||||||
|
&p.Root, &p.Mountpoint, &p.Opts, &optionalFields); err != nil {
|
||||||
|
return nil, fmt.Errorf("Scanning '%s' failed: %s", text, err)
|
||||||
|
}
|
||||||
|
// Safe as mountinfo encodes mountpoints with spaces as \040.
|
||||||
|
index := strings.Index(text, " - ")
|
||||||
|
postSeparatorFields := strings.Fields(text[index+3:])
|
||||||
|
if len(postSeparatorFields) < 3 {
|
||||||
|
return nil, fmt.Errorf("Error found less than 3 fields post '-' in %q", text)
|
||||||
|
}
|
||||||
|
|
||||||
|
if optionalFields != "-" {
|
||||||
|
p.Optional = optionalFields
|
||||||
|
}
|
||||||
|
|
||||||
|
p.Fstype = postSeparatorFields[0]
|
||||||
|
p.Source = postSeparatorFields[1]
|
||||||
|
p.VfsOpts = strings.Join(postSeparatorFields[2:], " ")
|
||||||
|
out = append(out, p)
|
||||||
|
}
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// PidMountInfo collects the mounts for a specific process ID. If the process
|
||||||
|
// ID is unknown, it is better to use `GetMounts` which will inspect
|
||||||
|
// "/proc/self/mountinfo" instead.
|
||||||
|
func PidMountInfo(pid int) ([]*Info, error) {
|
||||||
|
f, err := os.Open(fmt.Sprintf("/proc/%d/mountinfo", pid))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
return parseInfoFile(f)
|
||||||
|
}
|
12
vendor/src/github.com/docker/docker/pkg/mount/mountinfo_unsupported.go
vendored
Normal file
12
vendor/src/github.com/docker/docker/pkg/mount/mountinfo_unsupported.go
vendored
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
// +build !linux,!freebsd freebsd,!cgo
|
||||||
|
|
||||||
|
package mount
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"runtime"
|
||||||
|
)
|
||||||
|
|
||||||
|
func parseMountTable() ([]*Info, error) {
|
||||||
|
return nil, fmt.Errorf("mount.parseMountTable is not implemented on %s/%s", runtime.GOOS, runtime.GOARCH)
|
||||||
|
}
|
70
vendor/src/github.com/docker/docker/pkg/mount/sharedsubtree_linux.go
vendored
Normal file
70
vendor/src/github.com/docker/docker/pkg/mount/sharedsubtree_linux.go
vendored
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
// +build linux
|
||||||
|
|
||||||
|
package mount
|
||||||
|
|
||||||
|
// MakeShared ensures a mounted filesystem has the SHARED mount option enabled.
|
||||||
|
// See the supported options in flags.go for further reference.
|
||||||
|
func MakeShared(mountPoint string) error {
|
||||||
|
return ensureMountedAs(mountPoint, "shared")
|
||||||
|
}
|
||||||
|
|
||||||
|
// MakeRShared ensures a mounted filesystem has the RSHARED mount option enabled.
|
||||||
|
// See the supported options in flags.go for further reference.
|
||||||
|
func MakeRShared(mountPoint string) error {
|
||||||
|
return ensureMountedAs(mountPoint, "rshared")
|
||||||
|
}
|
||||||
|
|
||||||
|
// MakePrivate ensures a mounted filesystem has the PRIVATE mount option enabled.
|
||||||
|
// See the supported options in flags.go for further reference.
|
||||||
|
func MakePrivate(mountPoint string) error {
|
||||||
|
return ensureMountedAs(mountPoint, "private")
|
||||||
|
}
|
||||||
|
|
||||||
|
// MakeRPrivate ensures a mounted filesystem has the RPRIVATE mount option
|
||||||
|
// enabled. See the supported options in flags.go for further reference.
|
||||||
|
func MakeRPrivate(mountPoint string) error {
|
||||||
|
return ensureMountedAs(mountPoint, "rprivate")
|
||||||
|
}
|
||||||
|
|
||||||
|
// MakeSlave ensures a mounted filesystem has the SLAVE mount option enabled.
|
||||||
|
// See the supported options in flags.go for further reference.
|
||||||
|
func MakeSlave(mountPoint string) error {
|
||||||
|
return ensureMountedAs(mountPoint, "slave")
|
||||||
|
}
|
||||||
|
|
||||||
|
// MakeRSlave ensures a mounted filesystem has the RSLAVE mount option enabled.
|
||||||
|
// See the supported options in flags.go for further reference.
|
||||||
|
func MakeRSlave(mountPoint string) error {
|
||||||
|
return ensureMountedAs(mountPoint, "rslave")
|
||||||
|
}
|
||||||
|
|
||||||
|
// MakeUnbindable ensures a mounted filesystem has the UNBINDABLE mount option
|
||||||
|
// enabled. See the supported options in flags.go for further reference.
|
||||||
|
func MakeUnbindable(mountPoint string) error {
|
||||||
|
return ensureMountedAs(mountPoint, "unbindable")
|
||||||
|
}
|
||||||
|
|
||||||
|
// MakeRUnbindable ensures a mounted filesystem has the RUNBINDABLE mount
|
||||||
|
// option enabled. See the supported options in flags.go for further reference.
|
||||||
|
func MakeRUnbindable(mountPoint string) error {
|
||||||
|
return ensureMountedAs(mountPoint, "runbindable")
|
||||||
|
}
|
||||||
|
|
||||||
|
func ensureMountedAs(mountPoint, options string) error {
|
||||||
|
mounted, err := Mounted(mountPoint)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if !mounted {
|
||||||
|
if err := Mount(mountPoint, mountPoint, "none", "bind,rw"); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mounted, err = Mounted(mountPoint)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return ForceMount("", mountPoint, "none", options)
|
||||||
|
}
|
104
vendor/src/github.com/docker/docker/pkg/pubsub/publisher.go
vendored
Normal file
104
vendor/src/github.com/docker/docker/pkg/pubsub/publisher.go
vendored
Normal file
|
@ -0,0 +1,104 @@
|
||||||
|
package pubsub
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// NewPublisher creates a new pub/sub publisher to broadcast messages.
|
||||||
|
// The duration is used as the send timeout as to not block the publisher publishing
|
||||||
|
// messages to other clients if one client is slow or unresponsive.
|
||||||
|
// The buffer is used when creating new channels for subscribers.
|
||||||
|
func NewPublisher(publishTimeout time.Duration, buffer int) *Publisher {
|
||||||
|
return &Publisher{
|
||||||
|
buffer: buffer,
|
||||||
|
timeout: publishTimeout,
|
||||||
|
subscribers: make(map[subscriber]topicFunc),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type subscriber chan interface{}
|
||||||
|
type topicFunc func(v interface{}) bool
|
||||||
|
|
||||||
|
// Publisher is basic pub/sub structure. Allows to send events and subscribe
|
||||||
|
// to them. Can be safely used from multiple goroutines.
|
||||||
|
type Publisher struct {
|
||||||
|
m sync.RWMutex
|
||||||
|
buffer int
|
||||||
|
timeout time.Duration
|
||||||
|
subscribers map[subscriber]topicFunc
|
||||||
|
}
|
||||||
|
|
||||||
|
// Len returns the number of subscribers for the publisher
|
||||||
|
func (p *Publisher) Len() int {
|
||||||
|
p.m.RLock()
|
||||||
|
i := len(p.subscribers)
|
||||||
|
p.m.RUnlock()
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
|
||||||
|
// Subscribe adds a new subscriber to the publisher returning the channel.
|
||||||
|
func (p *Publisher) Subscribe() chan interface{} {
|
||||||
|
return p.SubscribeTopic(nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SubscribeTopic adds a new subscriber that filters messages sent by a topic.
|
||||||
|
func (p *Publisher) SubscribeTopic(topic topicFunc) chan interface{} {
|
||||||
|
ch := make(chan interface{}, p.buffer)
|
||||||
|
p.m.Lock()
|
||||||
|
p.subscribers[ch] = topic
|
||||||
|
p.m.Unlock()
|
||||||
|
return ch
|
||||||
|
}
|
||||||
|
|
||||||
|
// Evict removes the specified subscriber from receiving any more messages.
|
||||||
|
func (p *Publisher) Evict(sub chan interface{}) {
|
||||||
|
p.m.Lock()
|
||||||
|
delete(p.subscribers, sub)
|
||||||
|
close(sub)
|
||||||
|
p.m.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Publish sends the data in v to all subscribers currently registered with the publisher.
|
||||||
|
func (p *Publisher) Publish(v interface{}) {
|
||||||
|
p.m.RLock()
|
||||||
|
wg := new(sync.WaitGroup)
|
||||||
|
for sub, topic := range p.subscribers {
|
||||||
|
wg.Add(1)
|
||||||
|
|
||||||
|
go p.sendTopic(sub, topic, v, wg)
|
||||||
|
}
|
||||||
|
wg.Wait()
|
||||||
|
p.m.RUnlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close closes the channels to all subscribers registered with the publisher.
|
||||||
|
func (p *Publisher) Close() {
|
||||||
|
p.m.Lock()
|
||||||
|
for sub := range p.subscribers {
|
||||||
|
delete(p.subscribers, sub)
|
||||||
|
close(sub)
|
||||||
|
}
|
||||||
|
p.m.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Publisher) sendTopic(sub subscriber, topic topicFunc, v interface{}, wg *sync.WaitGroup) {
|
||||||
|
defer wg.Done()
|
||||||
|
if topic != nil && !topic(v) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// send under a select as to not block if the receiver is unavailable
|
||||||
|
if p.timeout > 0 {
|
||||||
|
select {
|
||||||
|
case sub <- v:
|
||||||
|
case <-time.After(p.timeout):
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
select {
|
||||||
|
case sub <- v:
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue