Add vendoring ahead of sources
This commit is contained in:
parent
35cb9b60c2
commit
3810641021
25
vendor/github.com/d2r2/go-bh1750/.travis.yml
generated
vendored
Normal file
25
vendor/github.com/d2r2/go-bh1750/.travis.yml
generated
vendored
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
language: go
|
||||||
|
go:
|
||||||
|
# - "1.10"
|
||||||
|
- "tip"
|
||||||
|
|
||||||
|
# first part of the GOARCH workaround
|
||||||
|
# setting the GOARCH directly doesn't work, since the value will be overwritten later
|
||||||
|
# so set it to a temporary environment variable first
|
||||||
|
env:
|
||||||
|
global:
|
||||||
|
TRAVIS_CGO_ENABLED=1
|
||||||
|
TRAVIS_GOOS=linux
|
||||||
|
matrix:
|
||||||
|
- TRAVIS_GOARCH=amd64
|
||||||
|
- TRAVIS_GOARCH=arm TRAVIS_CC=arm-linux-gnueabi-gcc TRAVIS_GOARM=6
|
||||||
|
|
||||||
|
# second part of the GOARCH workaround
|
||||||
|
# now actually set the GOARCH env variable to the value of the temporary variable set earlier
|
||||||
|
before_install:
|
||||||
|
- sudo apt-get install gcc-arm-linux-gnueabi # for CGO cross compile to ARM
|
||||||
|
- export CGO_ENABLED=$TRAVIS_CGO_ENABLED GOARCH=$TRAVIS_GOARCH GOARM=$TRAVIS_GOARM GOOS=$TRAVIS_GOOS CC=$TRAVIS_CC
|
||||||
|
- go env # for debugging
|
||||||
|
- go tool dist env # for debugging
|
||||||
|
|
||||||
|
|
21
vendor/github.com/d2r2/go-bh1750/LICENSE
generated
vendored
Normal file
21
vendor/github.com/d2r2/go-bh1750/LICENSE
generated
vendored
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2018 Denis Dyakov
|
||||||
|
|
||||||
|
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.
|
91
vendor/github.com/d2r2/go-bh1750/README.md
generated
vendored
Normal file
91
vendor/github.com/d2r2/go-bh1750/README.md
generated
vendored
Normal file
|
@ -0,0 +1,91 @@
|
||||||
|
|
||||||
|
BH1750 ambient light sensor
|
||||||
|
=====================
|
||||||
|
|
||||||
|
[![Build Status](https://travis-ci.org/d2r2/go-bh1750.svg?branch=master)](https://travis-ci.org/d2r2/go-bh1750)
|
||||||
|
[![Go Report Card](https://goreportcard.com/badge/github.com/d2r2/go-bh1750)](https://goreportcard.com/report/github.com/d2r2/go-bh1750)
|
||||||
|
[![GoDoc](https://godoc.org/github.com/d2r2/go-bh1750?status.svg)](https://godoc.org/github.com/d2r2/go-bh1750)
|
||||||
|
[![MIT License](http://img.shields.io/badge/License-MIT-yellow.svg)](./LICENSE)
|
||||||
|
|
||||||
|
BH1750 ([general specification](https://raw.github.com/d2r2/go-bh1750/master/docs/bh1750fvi-e-186247.pdf)) is a power effective ambient light sensor with spectral response close to human eye. Sensor returns measured ambient light value in lux units. Easily integrated with Arduino and Raspberry PI via i2c communication interface:
|
||||||
|
![image](https://raw.github.com/d2r2/go-bh1750/master/docs/bh1750.jpg)
|
||||||
|
|
||||||
|
Here is a library written in [Go programming language](https://golang.org/) for Raspberry PI and counterparts, which gives you in the output ambient light value (making all necessary i2c-bus interacting and values computing).
|
||||||
|
|
||||||
|
Golang usage
|
||||||
|
------------
|
||||||
|
|
||||||
|
|
||||||
|
```go
|
||||||
|
func main() {
|
||||||
|
// Create new connection to i2c-bus on 0 line with address 0x23.
|
||||||
|
// Use i2cdetect utility to find device address over the i2c-bus
|
||||||
|
i2c, err := i2c.NewI2C(0x23, 0)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
defer i2c.Close()
|
||||||
|
|
||||||
|
sensor := bh1750.NewBH1750()
|
||||||
|
|
||||||
|
resolution := bh1750.HighResolution
|
||||||
|
amb, err := sensor.MeasureAmbientLight(i2c, resolution)
|
||||||
|
if err != nil {
|
||||||
|
lg.Fatal(err)
|
||||||
|
}
|
||||||
|
log.Printf("Ambient light (%s) = %v lx", resolution, amb)
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
Getting help
|
||||||
|
------------
|
||||||
|
|
||||||
|
GoDoc [documentation](http://godoc.org/github.com/d2r2/go-bh1750)
|
||||||
|
|
||||||
|
Installation
|
||||||
|
------------
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ go get -u github.com/d2r2/go-bh1750
|
||||||
|
```
|
||||||
|
|
||||||
|
Troubleshooting
|
||||||
|
--------------
|
||||||
|
|
||||||
|
- *How to obtain fresh Golang installation to RPi device (either any RPi clone):*
|
||||||
|
If your RaspberryPI golang installation taken by default from repository is outdated, you may consider
|
||||||
|
to install actual golang manually from official Golang [site](https://golang.org/dl/). Download
|
||||||
|
tar.gz file containing armv6l in the name. Follow installation instructions.
|
||||||
|
|
||||||
|
- *How to enable I2C bus on RPi device:*
|
||||||
|
If you employ RaspberryPI, use raspi-config utility to activate i2c-bus on the OS level.
|
||||||
|
Go to "Interfacing Options" menu, to active I2C bus.
|
||||||
|
Probably you will need to reboot to load i2c kernel module.
|
||||||
|
Finally you should have device like /dev/i2c-1 present in the system.
|
||||||
|
|
||||||
|
- *How to find I2C bus allocation and device address:*
|
||||||
|
Use i2cdetect utility in format "i2cdetect -y X", where X may vary from 0 to 5 or more,
|
||||||
|
to discover address occupied by peripheral device. To install utility you should run
|
||||||
|
`apt install i2c-tools` on debian-kind system. `i2cdetect -y 1` sample output:
|
||||||
|
```
|
||||||
|
0 1 2 3 4 5 6 7 8 9 a b c d e f
|
||||||
|
00: -- -- -- -- -- -- -- -- -- -- -- -- --
|
||||||
|
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
|
||||||
|
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
|
||||||
|
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
|
||||||
|
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
|
||||||
|
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
|
||||||
|
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
|
||||||
|
70: -- -- -- -- -- -- 76 --
|
||||||
|
```
|
||||||
|
|
||||||
|
Contact
|
||||||
|
-------
|
||||||
|
|
||||||
|
Please use [Github issue tracker](https://github.com/d2r2/go-bh1750/issues) for filing bugs or feature requests.
|
||||||
|
|
||||||
|
|
||||||
|
License
|
||||||
|
-------
|
||||||
|
|
||||||
|
Go-bh1750 is licensed under MIT License.
|
323
vendor/github.com/d2r2/go-bh1750/bh1750.go
generated
vendored
Normal file
323
vendor/github.com/d2r2/go-bh1750/bh1750.go
generated
vendored
Normal file
|
@ -0,0 +1,323 @@
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// Copyright (c) 2018 Denis Dyakov
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
package bh1750
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/binary"
|
||||||
|
"errors"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
i2c "github.com/d2r2/go-i2c"
|
||||||
|
"github.com/davecgh/go-spew/spew"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Command bytes
|
||||||
|
const (
|
||||||
|
// No active state.
|
||||||
|
CMD_POWER_DOWN = 0x00
|
||||||
|
|
||||||
|
// Waiting for measurement command.
|
||||||
|
CMD_POWER_ON = 0x01
|
||||||
|
|
||||||
|
// Reset Data register value.
|
||||||
|
// Reset command is not acceptable in Power Down mode.
|
||||||
|
CMD_RESET = 0x07
|
||||||
|
|
||||||
|
// Start measurement at 1lx resolution.
|
||||||
|
// Measurement Time is typically 120ms.
|
||||||
|
CMD_CONTINUOUSLY_H_RES_MODE = 0x10
|
||||||
|
|
||||||
|
// Start measurement at 0.5lx resolution.
|
||||||
|
// Measurement Time is typically 120ms.
|
||||||
|
CMD_CONTINUOUSLY_H_RES_MODE2 = 0x11
|
||||||
|
|
||||||
|
// Start measurement at 4lx resolution.
|
||||||
|
// Measurement Time is typically 16ms.
|
||||||
|
CMD_CONTINUOUSLY_L_RES_MODE = 0x13
|
||||||
|
|
||||||
|
// Start measurement at 1lx resolution.
|
||||||
|
// Measurement Time is typically 120ms.
|
||||||
|
// It is automatically set to Power Down mode after measurement
|
||||||
|
CMD_ONE_TIME_H_RES_MODE = 0x20
|
||||||
|
|
||||||
|
// Start measurement at 0.5lx resolution.
|
||||||
|
// Measurement Time is typically 120ms.
|
||||||
|
// It is automatically set to Power Down mode after measurement.
|
||||||
|
CMD_ONE_TIME_H_RES_MODE2 = 0x21
|
||||||
|
|
||||||
|
// Start measurement at 4lx resolution.
|
||||||
|
// Measurement Time is typically 16ms.
|
||||||
|
// It is automatically set to Power Down mode after measurement.
|
||||||
|
CMD_ONE_TIME_L_RES_MODE = 0x23
|
||||||
|
|
||||||
|
// Change measurement time. 01000_MT[7,6,5]
|
||||||
|
CMD_CHANGE_MEAS_TIME_HIGH = 0x40
|
||||||
|
|
||||||
|
// Change measurement time. 011_MT[4,3,2,1,0]
|
||||||
|
CMD_CHANGE_MEAS_TIME_LOW = 0x60
|
||||||
|
)
|
||||||
|
|
||||||
|
// ResolutionMode define sensor sensitivity
|
||||||
|
// and measure time. Be aware, that improving
|
||||||
|
// sensitivity lead to increasing of measurement time.
|
||||||
|
type ResolutionMode int
|
||||||
|
|
||||||
|
const (
|
||||||
|
// LowResolution precision 4 lx, 16 ms measurement time
|
||||||
|
LowResolution ResolutionMode = iota + 1
|
||||||
|
// HighResolution precision 1 lx, 120 ms measurement time
|
||||||
|
HighResolution
|
||||||
|
// HighestResolution precision 0.5 lx, 120 ms measurement time
|
||||||
|
HighestResolution
|
||||||
|
)
|
||||||
|
|
||||||
|
// String define stringer interface.
|
||||||
|
func (v ResolutionMode) String() string {
|
||||||
|
switch v {
|
||||||
|
case LowResolution:
|
||||||
|
return "Low Resolution"
|
||||||
|
case HighResolution:
|
||||||
|
return "High Resolution"
|
||||||
|
case HighestResolution:
|
||||||
|
return "Highest Resolution"
|
||||||
|
default:
|
||||||
|
return "<unknown>"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// BH1750 it's a sensor itself.
|
||||||
|
type BH1750 struct {
|
||||||
|
// Since sensor have no register
|
||||||
|
// to report current state, we save
|
||||||
|
// last issued command to fill this gap.
|
||||||
|
lastCmd byte
|
||||||
|
lastResolution ResolutionMode
|
||||||
|
factor byte
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewBH1750 return new sensor instance.
|
||||||
|
func NewBH1750() *BH1750 {
|
||||||
|
v := &BH1750{}
|
||||||
|
v.factor = v.GetDefaultSensivityFactor()
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset clear ambient light register value.
|
||||||
|
func (v *BH1750) Reset(i2c *i2c.I2C) error {
|
||||||
|
lg.Debug("Reset sensor...")
|
||||||
|
_, err := i2c.WriteBytes([]byte{CMD_RESET})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
v.lastCmd = CMD_RESET
|
||||||
|
time.Sleep(time.Microsecond * 3)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// PowerDown return register to idle state.
|
||||||
|
func (v *BH1750) PowerDown(i2c *i2c.I2C) error {
|
||||||
|
lg.Debug("Power down sensor...")
|
||||||
|
_, err := i2c.WriteBytes([]byte{CMD_POWER_DOWN})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
v.lastCmd = CMD_POWER_DOWN
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// PowerOn activate sensor.
|
||||||
|
func (v *BH1750) PowerOn(i2c *i2c.I2C) error {
|
||||||
|
lg.Debug("Power on sensor...")
|
||||||
|
_, err := i2c.WriteBytes([]byte{CMD_POWER_ON})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
v.lastCmd = CMD_POWER_ON
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get internal parameters used to program sensor.
|
||||||
|
func (v *BH1750) getResolutionData(resolution ResolutionMode) (cmd byte,
|
||||||
|
wait time.Duration, divider uint32) {
|
||||||
|
|
||||||
|
switch resolution {
|
||||||
|
case LowResolution:
|
||||||
|
cmd = CMD_ONE_TIME_L_RES_MODE
|
||||||
|
divider = 1
|
||||||
|
// typical measure time is 16 ms,
|
||||||
|
// but as it was found 24 ms max time
|
||||||
|
// gives better results
|
||||||
|
wait = time.Millisecond * 24
|
||||||
|
case HighResolution:
|
||||||
|
cmd = CMD_ONE_TIME_H_RES_MODE
|
||||||
|
divider = 1
|
||||||
|
// typical measure time
|
||||||
|
wait = time.Millisecond * 120
|
||||||
|
case HighestResolution:
|
||||||
|
cmd = CMD_ONE_TIME_H_RES_MODE2
|
||||||
|
divider = 2
|
||||||
|
// typical measure time
|
||||||
|
wait = time.Millisecond * 120
|
||||||
|
}
|
||||||
|
wait = wait * time.Duration(v.factor) /
|
||||||
|
time.Duration(v.GetDefaultSensivityFactor())
|
||||||
|
|
||||||
|
return cmd, wait, divider
|
||||||
|
}
|
||||||
|
|
||||||
|
// MeasureAmbientLight measure and return ambient light once in lux.
|
||||||
|
func (v *BH1750) MeasureAmbientLight(i2c *i2c.I2C,
|
||||||
|
resolution ResolutionMode) (uint16, error) {
|
||||||
|
|
||||||
|
lg.Debug("Run one time measure...")
|
||||||
|
|
||||||
|
cmd, wait, divider := v.getResolutionData(resolution)
|
||||||
|
|
||||||
|
v.lastCmd = cmd
|
||||||
|
v.lastResolution = resolution
|
||||||
|
|
||||||
|
_, err := i2c.WriteBytes([]byte{cmd})
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
time.Sleep(wait)
|
||||||
|
|
||||||
|
var data struct {
|
||||||
|
Data [2]byte
|
||||||
|
}
|
||||||
|
err = readDataToStruct(i2c, 2, binary.BigEndian, &data)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
amb := uint16(uint32(uint16(data.Data[0])<<8|uint16(data.Data[1])) *
|
||||||
|
5 / 6 / divider)
|
||||||
|
|
||||||
|
return amb, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// StartMeasureAmbientLightContinuously start continuous
|
||||||
|
// measurement process. Use FetchMeasuredAmbientLight to get
|
||||||
|
// average ambient light amount collected and calculated over a time.
|
||||||
|
// Use PowerDown to stop measurements and return sensor to idle state.
|
||||||
|
func (v *BH1750) StartMeasureAmbientLightContinuously(i2c *i2c.I2C,
|
||||||
|
resolution ResolutionMode) (wait time.Duration, err error) {
|
||||||
|
|
||||||
|
lg.Debug("Start measures continuously...")
|
||||||
|
|
||||||
|
cmd, wait, _ := v.getResolutionData(resolution)
|
||||||
|
|
||||||
|
v.lastCmd = cmd
|
||||||
|
v.lastResolution = resolution
|
||||||
|
|
||||||
|
_, err = i2c.WriteBytes([]byte{cmd})
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait first time to collect necessary
|
||||||
|
// amount of light for correct results.
|
||||||
|
// It's not necessary to wait next time
|
||||||
|
// same amount of time, because
|
||||||
|
// sensor accumulate average lux amount
|
||||||
|
// without any overwrite old value.
|
||||||
|
time.Sleep(wait)
|
||||||
|
|
||||||
|
// In any case we are returning same
|
||||||
|
// recommended amount of time to wait
|
||||||
|
// between measures.
|
||||||
|
return wait, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// FetchMeasuredAmbientLight return current average ambient light in lux.
|
||||||
|
// Previous command should be any continuous measurement initiation,
|
||||||
|
// otherwise error will be reported.
|
||||||
|
func (v *BH1750) FetchMeasuredAmbientLight(i2c *i2c.I2C) (uint16, error) {
|
||||||
|
|
||||||
|
lg.Debug("Fetch measured data...")
|
||||||
|
|
||||||
|
cmd, _, divider := v.getResolutionData(v.lastResolution)
|
||||||
|
|
||||||
|
if v.lastCmd != cmd {
|
||||||
|
return 0, errors.New(
|
||||||
|
"can't fetch measured ambient light, since last command doesn't match")
|
||||||
|
}
|
||||||
|
|
||||||
|
var data struct {
|
||||||
|
Data [2]byte
|
||||||
|
}
|
||||||
|
err := readDataToStruct(i2c, 2, binary.BigEndian, &data)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
amb := uint16(uint32(uint16(data.Data[0])<<8|uint16(data.Data[1])) *
|
||||||
|
5 / 6 / divider)
|
||||||
|
|
||||||
|
return amb, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetDefaultSensivityFactor return factor value
|
||||||
|
// used when your sensor have no any protection cover.
|
||||||
|
// This is default setting according to specification.
|
||||||
|
func (v *BH1750) GetDefaultSensivityFactor() byte {
|
||||||
|
return 69
|
||||||
|
}
|
||||||
|
|
||||||
|
// ChangeSensivityFactor used when you close sensor
|
||||||
|
// with protection cover, which change (ordinary decrease)
|
||||||
|
// expected amount of light falling on the sensor.
|
||||||
|
// In this case you should calibrate you sensor and find
|
||||||
|
// appropriate factor to get in output correct ambient light value.
|
||||||
|
// Be aware, that improving sensitivity will increase
|
||||||
|
// measurement time.
|
||||||
|
func (v *BH1750) ChangeSensivityFactor(i2c *i2c.I2C, factor byte) error {
|
||||||
|
|
||||||
|
lg.Debug("Change sensitivity factor...")
|
||||||
|
|
||||||
|
// minimum limit
|
||||||
|
const minValue = 31
|
||||||
|
// maximum limit
|
||||||
|
const maxValue = 254
|
||||||
|
|
||||||
|
if factor < minValue || factor > maxValue {
|
||||||
|
return errors.New(spew.Sprintf("sensitivity factor value exceed range [%d..%d]",
|
||||||
|
minValue, maxValue))
|
||||||
|
}
|
||||||
|
|
||||||
|
high := (factor & 0xE0) >> 5
|
||||||
|
_, err := i2c.WriteBytes([]byte{CMD_CHANGE_MEAS_TIME_HIGH | high})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
low := (factor & 0x1F)
|
||||||
|
_, err = i2c.WriteBytes([]byte{CMD_CHANGE_MEAS_TIME_LOW | low})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
v.factor = factor
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
10
vendor/github.com/d2r2/go-bh1750/logger.go
generated
vendored
Normal file
10
vendor/github.com/d2r2/go-bh1750/logger.go
generated
vendored
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
package bh1750
|
||||||
|
|
||||||
|
import logger "github.com/d2r2/go-logger"
|
||||||
|
|
||||||
|
// You can manage verbosity of log output
|
||||||
|
// in the package by changing last parameter value.
|
||||||
|
var lg = logger.NewPackageLogger("bh1750",
|
||||||
|
logger.DebugLevel,
|
||||||
|
// logger.InfoLevel,
|
||||||
|
)
|
106
vendor/github.com/d2r2/go-bh1750/utils.go
generated
vendored
Normal file
106
vendor/github.com/d2r2/go-bh1750/utils.go
generated
vendored
Normal file
|
@ -0,0 +1,106 @@
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// Copyright (c) 2018 Denis Dyakov
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
package bh1750
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/binary"
|
||||||
|
"math"
|
||||||
|
|
||||||
|
i2c "github.com/d2r2/go-i2c"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Utility functions
|
||||||
|
|
||||||
|
// getS16BE extract 2-byte integer as signed big-endian.
|
||||||
|
func getS16BE(buf []byte) int16 {
|
||||||
|
v := int16(buf[0])<<8 + int16(buf[1])
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
|
// getS16LE extract 2-byte integer as signed little-endian.
|
||||||
|
func getS16LE(buf []byte) int16 {
|
||||||
|
w := getS16BE(buf)
|
||||||
|
// exchange bytes
|
||||||
|
v := (w&0xFF)<<8 + w>>8
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
|
// getU16BE extract 2-byte integer as unsigned big-endian.
|
||||||
|
func getU16BE(buf []byte) uint16 {
|
||||||
|
v := uint16(buf[0])<<8 + uint16(buf[1])
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
|
// getU16LE extract 2-byte integer as unsigned little-endian.
|
||||||
|
func getU16LE(buf []byte) uint16 {
|
||||||
|
w := getU16BE(buf)
|
||||||
|
// exchange bytes
|
||||||
|
v := (w&0xFF)<<8 + w>>8
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
|
func calcCRC1(seed byte, buf []byte) byte {
|
||||||
|
for i := 0; i < len(buf); i++ {
|
||||||
|
b := buf[ /*len(buf)-1-*/ i]
|
||||||
|
for j := 0; j < 8; j++ {
|
||||||
|
if (seed^b)&0x01 != 0 {
|
||||||
|
seed ^= 0x18
|
||||||
|
seed >>= 1
|
||||||
|
seed |= 0x80
|
||||||
|
// crc = crc ^ 0x8c
|
||||||
|
} else {
|
||||||
|
seed >>= 1
|
||||||
|
}
|
||||||
|
b >>= 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return seed
|
||||||
|
}
|
||||||
|
|
||||||
|
// Round float amount to certain precision.
|
||||||
|
func round64(value float64, precision int) float64 {
|
||||||
|
value2 := math.Round(value*math.Pow10(precision)) /
|
||||||
|
math.Pow10(precision)
|
||||||
|
return value2
|
||||||
|
}
|
||||||
|
|
||||||
|
// Round float amount to certain precision.
|
||||||
|
func round32(value float32, precision int) float32 {
|
||||||
|
return float32(round64(float64(value), precision))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read byte block from i2c device to struct object.
|
||||||
|
func readDataToStruct(i2c *i2c.I2C, byteCount int,
|
||||||
|
byteOrder binary.ByteOrder, obj interface{}) error {
|
||||||
|
buf1 := make([]byte, byteCount)
|
||||||
|
_, err := i2c.ReadBytes(buf1)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
buf := bytes.NewBuffer(buf1)
|
||||||
|
err = binary.Read(buf, byteOrder, obj)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
25
vendor/github.com/d2r2/go-i2c/.travis.yml
generated
vendored
Normal file
25
vendor/github.com/d2r2/go-i2c/.travis.yml
generated
vendored
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
language: go
|
||||||
|
go:
|
||||||
|
- "1.10"
|
||||||
|
# - "tip"
|
||||||
|
|
||||||
|
# first part of the GOARCH workaround
|
||||||
|
# setting the GOARCH directly doesn't work, since the value will be overwritten later
|
||||||
|
# so set it to a temporary environment variable first
|
||||||
|
env:
|
||||||
|
global:
|
||||||
|
TRAVIS_CGO_ENABLED=1
|
||||||
|
TRAVIS_GOOS=linux
|
||||||
|
matrix:
|
||||||
|
- TRAVIS_GOARCH=amd64
|
||||||
|
- TRAVIS_GOARCH=arm TRAVIS_CC=arm-linux-gnueabi-gcc TRAVIS_GOARM=6
|
||||||
|
|
||||||
|
# second part of the GOARCH workaround
|
||||||
|
# now actually set the GOARCH env variable to the value of the temporary variable set earlier
|
||||||
|
before_install:
|
||||||
|
- sudo apt-get install gcc-arm-linux-gnueabi crossbuild-essential-armel # for CGO cross compile to ARM
|
||||||
|
- export CGO_ENABLED=$TRAVIS_CGO_ENABLED GOARCH=$TRAVIS_GOARCH GOARM=$TRAVIS_GOARM GOOS=$TRAVIS_GOOS CC=$TRAVIS_CC
|
||||||
|
- go env # for debugging
|
||||||
|
- go tool dist env # for debugging
|
||||||
|
|
||||||
|
|
22
vendor/github.com/d2r2/go-i2c/LICENSE
generated
vendored
Normal file
22
vendor/github.com/d2r2/go-i2c/LICENSE
generated
vendored
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2016 Denis Dyakov
|
||||||
|
Copyright (c) 2013 Dave Cheney
|
||||||
|
|
||||||
|
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.
|
97
vendor/github.com/d2r2/go-i2c/README.md
generated
vendored
Normal file
97
vendor/github.com/d2r2/go-i2c/README.md
generated
vendored
Normal file
|
@ -0,0 +1,97 @@
|
||||||
|
I2C-bus interaction of peripheral sensors with Raspberry PI embedded linux or respective clones
|
||||||
|
==============================================================================================
|
||||||
|
|
||||||
|
[![Build Status](https://travis-ci.org/d2r2/go-i2c.svg?branch=master)](https://travis-ci.org/d2r2/go-i2c)
|
||||||
|
[![Go Report Card](https://goreportcard.com/badge/github.com/d2r2/go-i2c)](https://goreportcard.com/report/github.com/d2r2/go-i2c)
|
||||||
|
[![GoDoc](https://godoc.org/github.com/d2r2/go-i2c?status.svg)](https://godoc.org/github.com/d2r2/go-i2c)
|
||||||
|
[![MIT License](http://img.shields.io/badge/License-MIT-yellow.svg)](./LICENSE)
|
||||||
|
|
||||||
|
This library written in [Go programming language](https://golang.org/) intended to activate and interact with the I2C bus by reading and writing data.
|
||||||
|
|
||||||
|
Compatibility
|
||||||
|
-------------
|
||||||
|
|
||||||
|
Tested on Raspberry Pi 1 (model B), Raspberry Pi 3 B+, Banana Pi (model M1), Orange Pi Zero, Orange Pi One.
|
||||||
|
|
||||||
|
Golang usage
|
||||||
|
------------
|
||||||
|
|
||||||
|
```go
|
||||||
|
func main() {
|
||||||
|
// Create new connection to I2C bus on 2 line with address 0x27
|
||||||
|
i2c, err := i2c.NewI2C(0x27, 2)
|
||||||
|
if err != nil { log.Fatal(err) }
|
||||||
|
// Free I2C connection on exit
|
||||||
|
defer i2c.Close()
|
||||||
|
....
|
||||||
|
// Here goes code specific for sending and reading data
|
||||||
|
// to and from device connected via I2C bus, like:
|
||||||
|
_, err := i2c.Write([]byte{0x1, 0xF3})
|
||||||
|
if err != nil { log.Fatal(err) }
|
||||||
|
....
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Tutorial
|
||||||
|
--------
|
||||||
|
|
||||||
|
My [repositories](https://github.com/d2r2?tab=repositories) contain quite a lot projects, which use i2c library as a starting point to interact with various peripheral devices and sensors for use on embedded Linux devices. All these libraries start with a standard call to open I2C-connection to specific bus line and address, than pass i2c instance to device.
|
||||||
|
|
||||||
|
In its turn, go-i2c use [go-logger](https://github.com/d2r2/go-logger) library to output debug and other notification's lines which produce all necessary levels of logging. You can manage what level of verbosity you would like to see, by adding call:
|
||||||
|
```go
|
||||||
|
// Uncomment/comment next line to suppress/increase verbosity of output
|
||||||
|
logger.ChangePackageLogLevel("i2c", logger.InfoLevel)
|
||||||
|
```
|
||||||
|
Once you put this call, it will decrease verbosity from default "Debug" up to next "Info" level, reducing the number of low-level console outputs that occur during interaction with the I2C bus. Please, find examples in corresponding I2C-driven sensors among my projects.
|
||||||
|
|
||||||
|
You will find here the list of all devices and sensors supported by me, that reference this library:
|
||||||
|
|
||||||
|
- [Liquid-crystal display driven by Hitachi HD44780 IC](https://github.com/d2r2/go-hd44780).
|
||||||
|
- [BMP180/BMP280/BME280 temperature and pressure sensors](https://github.com/d2r2/go-bsbmp).
|
||||||
|
- [DHT12/AM2320 humidity and temperature sensors](https://github.com/d2r2/go-aosong).
|
||||||
|
- [Si7021 relative humidity and temperature sensor](https://github.com/d2r2/go-si7021).
|
||||||
|
- [SHT3x humidity and temperature sensor](https://github.com/d2r2/go-sht3x).
|
||||||
|
- [VL53L0X time-of-flight ranging sensor](https://github.com/d2r2/go-vl53l0x).
|
||||||
|
- [BH1750 ambient light sensor](https://github.com/d2r2/go-bh1750).
|
||||||
|
- [MPL3115A2 pressure and temperature sensor](https://github.com/d2r2/go-mpl3115a2).
|
||||||
|
|
||||||
|
|
||||||
|
Getting help
|
||||||
|
------------
|
||||||
|
|
||||||
|
GoDoc [documentation](http://godoc.org/github.com/d2r2/go-i2c)
|
||||||
|
|
||||||
|
Troubleshooting
|
||||||
|
--------------
|
||||||
|
|
||||||
|
- *How to obtain fresh Golang installation to RPi device (either any RPi clone):*
|
||||||
|
If your RaspberryPI golang installation taken by default from repository is outdated, you may consider
|
||||||
|
to install actual golang manually from official Golang [site](https://golang.org/dl/). Download
|
||||||
|
tar.gz file containing armv6l in the name. Follow installation instructions.
|
||||||
|
|
||||||
|
- *How to enable I2C bus on RPi device:*
|
||||||
|
If you employ RaspberryPI, use raspi-config utility to activate i2c-bus on the OS level.
|
||||||
|
Go to "Interfacing Options" menu, to active I2C bus.
|
||||||
|
Probably you will need to reboot to load i2c kernel module.
|
||||||
|
Finally you should have device like /dev/i2c-1 present in the system.
|
||||||
|
|
||||||
|
- *How to find I2C bus allocation and device address:*
|
||||||
|
Use i2cdetect utility in format "i2cdetect -y X", where X may vary from 0 to 5 or more,
|
||||||
|
to discover address occupied by peripheral device. To install utility you should run
|
||||||
|
`apt install i2c-tools` on debian-kind system. `i2cdetect -y 1` sample output:
|
||||||
|
```
|
||||||
|
0 1 2 3 4 5 6 7 8 9 a b c d e f
|
||||||
|
00: -- -- -- -- -- -- -- -- -- -- -- -- --
|
||||||
|
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
|
||||||
|
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
|
||||||
|
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
|
||||||
|
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
|
||||||
|
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
|
||||||
|
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
|
||||||
|
70: -- -- -- -- -- -- 76 --
|
||||||
|
```
|
||||||
|
|
||||||
|
License
|
||||||
|
-------
|
||||||
|
|
||||||
|
Go-i2c is licensed under MIT License.
|
12
vendor/github.com/d2r2/go-i2c/cgo.go
generated
vendored
Normal file
12
vendor/github.com/d2r2/go-i2c/cgo.go
generated
vendored
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
// +build linux,cgo
|
||||||
|
|
||||||
|
package i2c
|
||||||
|
|
||||||
|
// #include <linux/i2c-dev.h>
|
||||||
|
import "C"
|
||||||
|
|
||||||
|
// Get I2C_SLAVE constant value from
|
||||||
|
// Linux OS I2C declaration file.
|
||||||
|
const (
|
||||||
|
I2C_SLAVE = C.I2C_SLAVE
|
||||||
|
)
|
241
vendor/github.com/d2r2/go-i2c/i2c.go
generated
vendored
Normal file
241
vendor/github.com/d2r2/go-i2c/i2c.go
generated
vendored
Normal file
|
@ -0,0 +1,241 @@
|
||||||
|
// Package i2c provides low level control over the Linux i2c bus.
|
||||||
|
//
|
||||||
|
// Before usage you should load the i2c-dev kernel module
|
||||||
|
//
|
||||||
|
// sudo modprobe i2c-dev
|
||||||
|
//
|
||||||
|
// Each i2c bus can address 127 independent i2c devices, and most
|
||||||
|
// Linux systems contain several buses.
|
||||||
|
|
||||||
|
package i2c
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/hex"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"syscall"
|
||||||
|
)
|
||||||
|
|
||||||
|
// I2C represents a connection to I2C-device.
|
||||||
|
type I2C struct {
|
||||||
|
addr uint8
|
||||||
|
bus int
|
||||||
|
rc *os.File
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewI2C opens a connection for I2C-device.
|
||||||
|
// SMBus (System Management Bus) protocol over I2C
|
||||||
|
// supported as well: you should preliminary specify
|
||||||
|
// register address to read from, either write register
|
||||||
|
// together with the data in case of write operations.
|
||||||
|
func NewI2C(addr uint8, bus int) (*I2C, error) {
|
||||||
|
f, err := os.OpenFile(fmt.Sprintf("/dev/i2c-%d", bus), os.O_RDWR, 0600)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err := ioctl(f.Fd(), I2C_SLAVE, uintptr(addr)); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
v := &I2C{rc: f, bus: bus, addr: addr}
|
||||||
|
return v, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetBus return bus line, where I2C-device is allocated.
|
||||||
|
func (v *I2C) GetBus() int {
|
||||||
|
return v.bus
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetAddr return device occupied address in the bus.
|
||||||
|
func (v *I2C) GetAddr() uint8 {
|
||||||
|
return v.addr
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *I2C) write(buf []byte) (int, error) {
|
||||||
|
return v.rc.Write(buf)
|
||||||
|
}
|
||||||
|
|
||||||
|
// WriteBytes send bytes to the remote I2C-device. The interpretation of
|
||||||
|
// the message is implementation-dependent.
|
||||||
|
func (v *I2C) WriteBytes(buf []byte) (int, error) {
|
||||||
|
lg.Debugf("Write %d hex bytes: [%+v]", len(buf), hex.EncodeToString(buf))
|
||||||
|
return v.write(buf)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *I2C) read(buf []byte) (int, error) {
|
||||||
|
return v.rc.Read(buf)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReadBytes read bytes from I2C-device.
|
||||||
|
// Number of bytes read correspond to buf parameter length.
|
||||||
|
func (v *I2C) ReadBytes(buf []byte) (int, error) {
|
||||||
|
n, err := v.read(buf)
|
||||||
|
if err != nil {
|
||||||
|
return n, err
|
||||||
|
}
|
||||||
|
lg.Debugf("Read %d hex bytes: [%+v]", len(buf), hex.EncodeToString(buf))
|
||||||
|
return n, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close I2C-connection.
|
||||||
|
func (v *I2C) Close() error {
|
||||||
|
return v.rc.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReadRegBytes read count of n byte's sequence from I2C-device
|
||||||
|
// starting from reg address.
|
||||||
|
// SMBus (System Management Bus) protocol over I2C.
|
||||||
|
func (v *I2C) ReadRegBytes(reg byte, n int) ([]byte, int, error) {
|
||||||
|
lg.Debugf("Read %d bytes starting from reg 0x%0X...", n, reg)
|
||||||
|
_, err := v.WriteBytes([]byte{reg})
|
||||||
|
if err != nil {
|
||||||
|
return nil, 0, err
|
||||||
|
}
|
||||||
|
buf := make([]byte, n)
|
||||||
|
c, err := v.ReadBytes(buf)
|
||||||
|
if err != nil {
|
||||||
|
return nil, 0, err
|
||||||
|
}
|
||||||
|
return buf, c, nil
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReadRegU8 reads byte from I2C-device register specified in reg.
|
||||||
|
// SMBus (System Management Bus) protocol over I2C.
|
||||||
|
func (v *I2C) ReadRegU8(reg byte) (byte, error) {
|
||||||
|
_, err := v.WriteBytes([]byte{reg})
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
buf := make([]byte, 1)
|
||||||
|
_, err = v.ReadBytes(buf)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
lg.Debugf("Read U8 %d from reg 0x%0X", buf[0], reg)
|
||||||
|
return buf[0], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// WriteRegU8 writes byte to I2C-device register specified in reg.
|
||||||
|
// SMBus (System Management Bus) protocol over I2C.
|
||||||
|
func (v *I2C) WriteRegU8(reg byte, value byte) error {
|
||||||
|
buf := []byte{reg, value}
|
||||||
|
_, err := v.WriteBytes(buf)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
lg.Debugf("Write U8 %d to reg 0x%0X", value, reg)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReadRegU16BE reads unsigned big endian word (16 bits)
|
||||||
|
// from I2C-device starting from address specified in reg.
|
||||||
|
// SMBus (System Management Bus) protocol over I2C.
|
||||||
|
func (v *I2C) ReadRegU16BE(reg byte) (uint16, error) {
|
||||||
|
_, err := v.WriteBytes([]byte{reg})
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
buf := make([]byte, 2)
|
||||||
|
_, err = v.ReadBytes(buf)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
w := uint16(buf[0])<<8 + uint16(buf[1])
|
||||||
|
lg.Debugf("Read U16 %d from reg 0x%0X", w, reg)
|
||||||
|
return w, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReadRegU16LE reads unsigned little endian word (16 bits)
|
||||||
|
// from I2C-device starting from address specified in reg.
|
||||||
|
// SMBus (System Management Bus) protocol over I2C.
|
||||||
|
func (v *I2C) ReadRegU16LE(reg byte) (uint16, error) {
|
||||||
|
w, err := v.ReadRegU16BE(reg)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
// exchange bytes
|
||||||
|
w = (w&0xFF)<<8 + w>>8
|
||||||
|
return w, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReadRegS16BE reads signed big endian word (16 bits)
|
||||||
|
// from I2C-device starting from address specified in reg.
|
||||||
|
// SMBus (System Management Bus) protocol over I2C.
|
||||||
|
func (v *I2C) ReadRegS16BE(reg byte) (int16, error) {
|
||||||
|
_, err := v.WriteBytes([]byte{reg})
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
buf := make([]byte, 2)
|
||||||
|
_, err = v.ReadBytes(buf)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
w := int16(buf[0])<<8 + int16(buf[1])
|
||||||
|
lg.Debugf("Read S16 %d from reg 0x%0X", w, reg)
|
||||||
|
return w, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReadRegS16LE reads signed little endian word (16 bits)
|
||||||
|
// from I2C-device starting from address specified in reg.
|
||||||
|
// SMBus (System Management Bus) protocol over I2C.
|
||||||
|
func (v *I2C) ReadRegS16LE(reg byte) (int16, error) {
|
||||||
|
w, err := v.ReadRegS16BE(reg)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
// exchange bytes
|
||||||
|
w = (w&0xFF)<<8 + w>>8
|
||||||
|
return w, nil
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// WriteRegU16BE writes unsigned big endian word (16 bits)
|
||||||
|
// value to I2C-device starting from address specified in reg.
|
||||||
|
// SMBus (System Management Bus) protocol over I2C.
|
||||||
|
func (v *I2C) WriteRegU16BE(reg byte, value uint16) error {
|
||||||
|
buf := []byte{reg, byte((value & 0xFF00) >> 8), byte(value & 0xFF)}
|
||||||
|
_, err := v.WriteBytes(buf)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
lg.Debugf("Write U16 %d to reg 0x%0X", value, reg)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// WriteRegU16LE writes unsigned little endian word (16 bits)
|
||||||
|
// value to I2C-device starting from address specified in reg.
|
||||||
|
// SMBus (System Management Bus) protocol over I2C.
|
||||||
|
func (v *I2C) WriteRegU16LE(reg byte, value uint16) error {
|
||||||
|
w := (value*0xFF00)>>8 + value<<8
|
||||||
|
return v.WriteRegU16BE(reg, w)
|
||||||
|
}
|
||||||
|
|
||||||
|
// WriteRegS16BE writes signed big endian word (16 bits)
|
||||||
|
// value to I2C-device starting from address specified in reg.
|
||||||
|
// SMBus (System Management Bus) protocol over I2C.
|
||||||
|
func (v *I2C) WriteRegS16BE(reg byte, value int16) error {
|
||||||
|
buf := []byte{reg, byte((uint16(value) & 0xFF00) >> 8), byte(value & 0xFF)}
|
||||||
|
_, err := v.WriteBytes(buf)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
lg.Debugf("Write S16 %d to reg 0x%0X", value, reg)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// WriteRegS16LE writes signed little endian word (16 bits)
|
||||||
|
// value to I2C-device starting from address specified in reg.
|
||||||
|
// SMBus (System Management Bus) protocol over I2C.
|
||||||
|
func (v *I2C) WriteRegS16LE(reg byte, value int16) error {
|
||||||
|
w := int16((uint16(value)*0xFF00)>>8) + value<<8
|
||||||
|
return v.WriteRegS16BE(reg, w)
|
||||||
|
}
|
||||||
|
|
||||||
|
func ioctl(fd, cmd, arg uintptr) error {
|
||||||
|
_, _, err := syscall.Syscall6(syscall.SYS_IOCTL, fd, cmd, arg, 0, 0, 0)
|
||||||
|
if err != 0 {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
11
vendor/github.com/d2r2/go-i2c/logger.go
generated
vendored
Normal file
11
vendor/github.com/d2r2/go-i2c/logger.go
generated
vendored
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
package i2c
|
||||||
|
|
||||||
|
import logger "github.com/d2r2/go-logger"
|
||||||
|
|
||||||
|
// You can manage verbosity of log output
|
||||||
|
// in the package by changing last parameter value
|
||||||
|
// (comment/uncomment corresponding lines).
|
||||||
|
var lg = logger.NewPackageLogger("i2c",
|
||||||
|
logger.DebugLevel,
|
||||||
|
// logger.InfoLevel,
|
||||||
|
)
|
11
vendor/github.com/d2r2/go-i2c/noncgo.go
generated
vendored
Normal file
11
vendor/github.com/d2r2/go-i2c/noncgo.go
generated
vendored
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
// +build !cgo
|
||||||
|
|
||||||
|
package i2c
|
||||||
|
|
||||||
|
// Use hard-coded value for system I2C_SLAVE
|
||||||
|
// constant, if OS not Linux or CGO disabled.
|
||||||
|
// This is not a good approach, but
|
||||||
|
// can be used as a last resort.
|
||||||
|
const (
|
||||||
|
I2C_SLAVE = 0x0703
|
||||||
|
)
|
2
vendor/github.com/d2r2/go-logger/README.md
generated
vendored
Normal file
2
vendor/github.com/d2r2/go-logger/README.md
generated
vendored
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
Golang logger functionality with logging separation by package to improve debug process
|
||||||
|
|
161
vendor/github.com/d2r2/go-logger/file.go
generated
vendored
Normal file
161
vendor/github.com/d2r2/go-logger/file.go
generated
vendored
Normal file
|
@ -0,0 +1,161 @@
|
||||||
|
package logger
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
"path"
|
||||||
|
"path/filepath"
|
||||||
|
"sort"
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
type File struct {
|
||||||
|
sync.RWMutex
|
||||||
|
Path string
|
||||||
|
File *os.File
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *File) Flush() error {
|
||||||
|
v.Lock()
|
||||||
|
defer v.Unlock()
|
||||||
|
if v.File != nil {
|
||||||
|
err := v.File.Sync()
|
||||||
|
v.File = nil
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *File) Close() error {
|
||||||
|
v.Lock()
|
||||||
|
defer v.Unlock()
|
||||||
|
if v.File != nil {
|
||||||
|
err := v.File.Close()
|
||||||
|
v.File = nil
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *File) getRotatedFileList() ([]logFile, error) {
|
||||||
|
var list []logFile
|
||||||
|
err := filepath.Walk(path.Dir(v.Path), func(p string,
|
||||||
|
info os.FileInfo, err error) error {
|
||||||
|
pattern := "*" + path.Base(v.Path) + "*"
|
||||||
|
if ok, err := path.Match(pattern, path.Base(p)); ok && err == nil {
|
||||||
|
i := extractIndex(info)
|
||||||
|
list = append(list, logFile{FileInfo: info, Index: i})
|
||||||
|
} else if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
s := &sortLogFiles{Items: list}
|
||||||
|
sort.Sort(s)
|
||||||
|
return s.Items, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *File) doRotate(items []logFile, rotateMaxCount int) error {
|
||||||
|
if len(items) > 0 {
|
||||||
|
// delete last files
|
||||||
|
deleteCount := len(items) - rotateMaxCount + 1
|
||||||
|
if deleteCount > 0 {
|
||||||
|
for i := 0; i < deleteCount; i++ {
|
||||||
|
err := os.Remove(items[i].FileInfo.Name())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
items = items[deleteCount:]
|
||||||
|
}
|
||||||
|
// change names of rest files
|
||||||
|
baseFilePath := items[len(items)-1].FileInfo.Name()
|
||||||
|
movs := make([]int, len(items))
|
||||||
|
// 1st round to change names
|
||||||
|
for i, item := range items {
|
||||||
|
movs[i] = i + 100000
|
||||||
|
err := os.Rename(item.FileInfo.Name(),
|
||||||
|
fmt.Sprintf("%s.%d", baseFilePath, movs[i]))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 2nd round to change names
|
||||||
|
for i, item := range movs {
|
||||||
|
err := os.Rename(fmt.Sprintf("%s.%d", baseFilePath, item),
|
||||||
|
fmt.Sprintf("%s.%d", baseFilePath, len(items)-i))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *File) rotateFiles(rotateMaxSize int64, rotateMaxCount int) error {
|
||||||
|
fs, err := v.File.Stat()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if fs.Size() > rotateMaxSize {
|
||||||
|
if v.File != nil {
|
||||||
|
err := v.File.Close()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
v.File = nil
|
||||||
|
}
|
||||||
|
list, err := v.getRotatedFileList()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err = v.doRotate(list, rotateMaxCount); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *File) getFile() (*os.File, error) {
|
||||||
|
v.Lock()
|
||||||
|
defer v.Unlock()
|
||||||
|
if v.File == nil {
|
||||||
|
file, err := os.OpenFile(v.Path, os.O_RDWR|os.O_APPEND, 0660)
|
||||||
|
if err != nil {
|
||||||
|
file, err = os.Create(v.Path)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
v.File = file
|
||||||
|
}
|
||||||
|
return v.File, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *File) writeToFile(msg string, rotateMaxSize int64, rotateMaxCount int) error {
|
||||||
|
file, err := v.getFile()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
v.Lock()
|
||||||
|
defer v.Unlock()
|
||||||
|
var buf bytes.Buffer
|
||||||
|
buf.WriteString(msg)
|
||||||
|
buf.WriteString(fmt.Sprintln())
|
||||||
|
if _, err := io.Copy(file, &buf); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// if err = file.Sync(); err != nil {
|
||||||
|
// return err
|
||||||
|
// }
|
||||||
|
if err := v.rotateFiles(rotateMaxSize, rotateMaxCount); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
31
vendor/github.com/d2r2/go-logger/format.go
generated
vendored
Normal file
31
vendor/github.com/d2r2/go-logger/format.go
generated
vendored
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
package logger
|
||||||
|
|
||||||
|
import "os"
|
||||||
|
|
||||||
|
type LevelLength int
|
||||||
|
|
||||||
|
const (
|
||||||
|
LevelShort LevelLength = iota
|
||||||
|
LevelLong
|
||||||
|
)
|
||||||
|
|
||||||
|
type FormatOptions struct {
|
||||||
|
TimeFormat string
|
||||||
|
PackageLength int
|
||||||
|
LevelLength LevelLength
|
||||||
|
}
|
||||||
|
|
||||||
|
func FormatMessage(options FormatOptions, level LogLevel, packageName, msg string, colored bool) string {
|
||||||
|
appName := os.Args[0]
|
||||||
|
out := metaFmtStr(colored, level, options, appName,
|
||||||
|
packageName, msg, "%[1]s [%[3]s] %[4]s %[5]s")
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
func (options FormatOptions) GetLevelStr(level LogLevel) string {
|
||||||
|
if options.LevelLength == LevelLong {
|
||||||
|
return level.LongStr()
|
||||||
|
} else {
|
||||||
|
return level.ShortStr()
|
||||||
|
}
|
||||||
|
}
|
309
vendor/github.com/d2r2/go-logger/logger.go
generated
vendored
Normal file
309
vendor/github.com/d2r2/go-logger/logger.go
generated
vendored
Normal file
|
@ -0,0 +1,309 @@
|
||||||
|
package logger
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"path"
|
||||||
|
"path/filepath"
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
type LogLevel int
|
||||||
|
|
||||||
|
const (
|
||||||
|
FatalLevel LogLevel = iota
|
||||||
|
PanicLevel
|
||||||
|
ErrorLevel
|
||||||
|
WarnLevel
|
||||||
|
NotifyLevel
|
||||||
|
InfoLevel
|
||||||
|
DebugLevel
|
||||||
|
)
|
||||||
|
|
||||||
|
func (v LogLevel) String() string {
|
||||||
|
switch v {
|
||||||
|
case FatalLevel:
|
||||||
|
return "Fatal"
|
||||||
|
case PanicLevel:
|
||||||
|
return "Panic"
|
||||||
|
case ErrorLevel:
|
||||||
|
return "Error"
|
||||||
|
case WarnLevel:
|
||||||
|
return "Warning"
|
||||||
|
case NotifyLevel:
|
||||||
|
return "Notice"
|
||||||
|
case InfoLevel:
|
||||||
|
return "Information"
|
||||||
|
case DebugLevel:
|
||||||
|
return "Debug"
|
||||||
|
default:
|
||||||
|
return "<undef>"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v LogLevel) LongStr() string {
|
||||||
|
return v.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v LogLevel) ShortStr() string {
|
||||||
|
switch v {
|
||||||
|
case FatalLevel:
|
||||||
|
return "Fatal"
|
||||||
|
case PanicLevel:
|
||||||
|
return "Panic"
|
||||||
|
case ErrorLevel:
|
||||||
|
return "Error"
|
||||||
|
case WarnLevel:
|
||||||
|
return "Warn"
|
||||||
|
case NotifyLevel:
|
||||||
|
return "Notice"
|
||||||
|
case InfoLevel:
|
||||||
|
return "Info"
|
||||||
|
case DebugLevel:
|
||||||
|
return "Debug"
|
||||||
|
default:
|
||||||
|
return "<undef>"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type Log struct {
|
||||||
|
log *log.Logger
|
||||||
|
colored bool
|
||||||
|
level LogLevel
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewLog(log *log.Logger, colored bool, level LogLevel) *Log {
|
||||||
|
v := &Log{log: log, colored: colored, level: level}
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
|
type Logger struct {
|
||||||
|
sync.RWMutex
|
||||||
|
logs []*Log
|
||||||
|
packages []*Package
|
||||||
|
options FormatOptions
|
||||||
|
logFile *File
|
||||||
|
rotateMaxSize int64
|
||||||
|
rotateMaxCount int
|
||||||
|
enableSyslog bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewLogger() *Logger {
|
||||||
|
stdout := NewLog(log.New(os.Stdout, "", 0), true, DebugLevel)
|
||||||
|
logs := []*Log{stdout}
|
||||||
|
options := FormatOptions{TimeFormat: "2006-01-02T15:04:05.000", LevelLength: LevelShort, PackageLength: 8}
|
||||||
|
l := &Logger{
|
||||||
|
logs: logs,
|
||||||
|
options: options,
|
||||||
|
rotateMaxSize: 1024 * 1024 * 512,
|
||||||
|
rotateMaxCount: 3,
|
||||||
|
}
|
||||||
|
return l
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *Logger) Close() error {
|
||||||
|
v.Lock()
|
||||||
|
defer v.Unlock()
|
||||||
|
|
||||||
|
for _, pack := range v.packages {
|
||||||
|
pack.Close()
|
||||||
|
}
|
||||||
|
v.packages = nil
|
||||||
|
|
||||||
|
if v.logFile != nil {
|
||||||
|
v.logFile.Close()
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *Logger) SetRotateParams(rotateMaxSize int64, rotateMaxCount int) {
|
||||||
|
v.Lock()
|
||||||
|
defer v.Unlock()
|
||||||
|
v.rotateMaxSize = rotateMaxSize
|
||||||
|
v.rotateMaxCount = rotateMaxCount
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *Logger) GetRotateMaxSize() int64 {
|
||||||
|
v.Lock()
|
||||||
|
defer v.Unlock()
|
||||||
|
return v.rotateMaxSize
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *Logger) GetRotateMaxCount() int {
|
||||||
|
v.Lock()
|
||||||
|
defer v.Unlock()
|
||||||
|
return v.rotateMaxCount
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
func (v *Logger) SetApplicationName(appName string) {
|
||||||
|
v.Lock()
|
||||||
|
defer v.Unlock()
|
||||||
|
v.appName = appName
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *Logger) GetApplicationName() string {
|
||||||
|
v.RLock()
|
||||||
|
defer v.RUnlock()
|
||||||
|
return v.appName
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
func (v *Logger) EnableSyslog(enable bool) {
|
||||||
|
v.Lock()
|
||||||
|
defer v.Unlock()
|
||||||
|
v.enableSyslog = enable
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *Logger) GetSyslogEnabled() bool {
|
||||||
|
v.RLock()
|
||||||
|
defer v.RUnlock()
|
||||||
|
return v.enableSyslog
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *Logger) SetFormatOptions(options FormatOptions) {
|
||||||
|
v.Lock()
|
||||||
|
defer v.Unlock()
|
||||||
|
v.options = options
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *Logger) GetFormatOptions() FormatOptions {
|
||||||
|
v.RLock()
|
||||||
|
defer v.RUnlock()
|
||||||
|
return v.options
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *Logger) SetLogFileName(logFilePath string) error {
|
||||||
|
if path.Ext(logFilePath) == "" {
|
||||||
|
logFilePath += ".log"
|
||||||
|
}
|
||||||
|
fp, err := filepath.Abs(logFilePath)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
v.Lock()
|
||||||
|
defer v.Unlock()
|
||||||
|
lf := &File{Path: fp}
|
||||||
|
v.logFile = lf
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *Logger) GetLogFileInfo() *File {
|
||||||
|
v.RLock()
|
||||||
|
defer v.RUnlock()
|
||||||
|
return v.logFile
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *Logger) NewPackageLogger(packageName string, level LogLevel) PackageLog {
|
||||||
|
v.Lock()
|
||||||
|
defer v.Unlock()
|
||||||
|
p := &Package{parent: v, packageName: packageName, level: level}
|
||||||
|
v.packages = append(v.packages, p)
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *Logger) ChangePackageLogLevel(packageName string, level LogLevel) error {
|
||||||
|
var p *Package
|
||||||
|
for _, item := range v.packages {
|
||||||
|
if item.packageName == packageName {
|
||||||
|
p = item
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if p != nil {
|
||||||
|
p.SetLogLevel(level)
|
||||||
|
} else {
|
||||||
|
err := fmt.Errorf("Package log %q is not found", packageName)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *Logger) AddCustomLog(writer io.Writer, colored bool, level LogLevel) {
|
||||||
|
v.Lock()
|
||||||
|
defer v.Unlock()
|
||||||
|
log := NewLog(log.New(writer, "", 0), colored, level)
|
||||||
|
v.logs = append(v.logs, log)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *Logger) getLogs() []*Log {
|
||||||
|
v.RLock()
|
||||||
|
defer v.RUnlock()
|
||||||
|
lst := []*Log{}
|
||||||
|
for _, item := range v.logs {
|
||||||
|
lst = append(lst, item)
|
||||||
|
}
|
||||||
|
return lst
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
globalLock sync.RWMutex
|
||||||
|
lgr *Logger
|
||||||
|
)
|
||||||
|
|
||||||
|
func SetFormatOptions(format FormatOptions) {
|
||||||
|
globalLock.RLock()
|
||||||
|
defer globalLock.RUnlock()
|
||||||
|
lgr.SetFormatOptions(format)
|
||||||
|
}
|
||||||
|
|
||||||
|
func SetRotateParams(rotateMaxSize int64, rotateMaxCount int) {
|
||||||
|
globalLock.RLock()
|
||||||
|
defer globalLock.RUnlock()
|
||||||
|
lgr.SetRotateParams(rotateMaxSize, rotateMaxCount)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewPackageLogger(module string, level LogLevel) PackageLog {
|
||||||
|
globalLock.RLock()
|
||||||
|
defer globalLock.RUnlock()
|
||||||
|
return lgr.NewPackageLogger(module, level)
|
||||||
|
}
|
||||||
|
|
||||||
|
func ChangePackageLogLevel(packageName string, level LogLevel) error {
|
||||||
|
globalLock.RLock()
|
||||||
|
defer globalLock.RUnlock()
|
||||||
|
return lgr.ChangePackageLogLevel(packageName, level)
|
||||||
|
}
|
||||||
|
|
||||||
|
func SetLogFileName(logFilePath string) error {
|
||||||
|
globalLock.RLock()
|
||||||
|
defer globalLock.RUnlock()
|
||||||
|
return lgr.SetLogFileName(logFilePath)
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
func SetApplicationName(appName string) {
|
||||||
|
globalLock.RLock()
|
||||||
|
defer globalLock.RUnlock()
|
||||||
|
lgr.SetApplicationName(appName)
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
func EnableSyslog(enable bool) {
|
||||||
|
globalLock.RLock()
|
||||||
|
defer globalLock.RUnlock()
|
||||||
|
lgr.EnableSyslog(enable)
|
||||||
|
}
|
||||||
|
|
||||||
|
func AddCustomLog(writer io.Writer, colored bool, level LogLevel) {
|
||||||
|
globalLock.RLock()
|
||||||
|
defer globalLock.RUnlock()
|
||||||
|
lgr.AddCustomLog(writer, colored, level)
|
||||||
|
}
|
||||||
|
|
||||||
|
func FinalizeLogger() error {
|
||||||
|
var err error
|
||||||
|
if lgr != nil {
|
||||||
|
err = lgr.Close()
|
||||||
|
}
|
||||||
|
globalLock.Lock()
|
||||||
|
defer globalLock.Unlock()
|
||||||
|
lgr = nil
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
lgr = NewLogger()
|
||||||
|
}
|
258
vendor/github.com/d2r2/go-logger/package.go
generated
vendored
Normal file
258
vendor/github.com/d2r2/go-logger/package.go
generated
vendored
Normal file
|
@ -0,0 +1,258 @@
|
||||||
|
package logger
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log/syslog"
|
||||||
|
"os"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/davecgh/go-spew/spew"
|
||||||
|
)
|
||||||
|
|
||||||
|
type PackageLog interface {
|
||||||
|
Printf(level LogLevel, format string, args ...interface{})
|
||||||
|
Print(level LogLevel, args ...interface{})
|
||||||
|
Debugf(format string, args ...interface{})
|
||||||
|
Debug(args ...interface{})
|
||||||
|
Infof(format string, args ...interface{})
|
||||||
|
Info(args ...interface{})
|
||||||
|
Notifyf(format string, args ...interface{})
|
||||||
|
Notify(args ...interface{})
|
||||||
|
Warningf(format string, args ...interface{})
|
||||||
|
Warnf(format string, args ...interface{})
|
||||||
|
Warning(args ...interface{})
|
||||||
|
Warn(args ...interface{})
|
||||||
|
Errorf(format string, args ...interface{})
|
||||||
|
Error(args ...interface{})
|
||||||
|
Panicf(format string, args ...interface{})
|
||||||
|
Panic(args ...interface{})
|
||||||
|
Fatalf(format string, args ...interface{})
|
||||||
|
Fatal(args ...interface{})
|
||||||
|
}
|
||||||
|
|
||||||
|
type Package struct {
|
||||||
|
sync.RWMutex
|
||||||
|
parent *Logger
|
||||||
|
packageName string
|
||||||
|
level LogLevel
|
||||||
|
syslog *syslog.Writer
|
||||||
|
}
|
||||||
|
|
||||||
|
// Static cast to verify that object implement interface.
|
||||||
|
var _ PackageLog = &Package{}
|
||||||
|
|
||||||
|
func (v *Package) Close() error {
|
||||||
|
v.Lock()
|
||||||
|
defer v.Unlock()
|
||||||
|
if v.syslog != nil {
|
||||||
|
err := v.syslog.Close()
|
||||||
|
v.syslog = nil
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *Package) SetLogLevel(level LogLevel) {
|
||||||
|
v.Lock()
|
||||||
|
defer v.Unlock()
|
||||||
|
v.level = level
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *Package) GetLogLevel() LogLevel {
|
||||||
|
v.RLock()
|
||||||
|
defer v.RUnlock()
|
||||||
|
return v.level
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *Package) getSyslog(level LogLevel, options FormatOptions,
|
||||||
|
appName string) (*syslog.Writer, error) {
|
||||||
|
v.Lock()
|
||||||
|
defer v.Unlock()
|
||||||
|
if v.syslog == nil {
|
||||||
|
tag := metaFmtStr(false, level, options, appName,
|
||||||
|
v.packageName, "", "%[2]s-%[3]s")
|
||||||
|
sl, err := syslog.New(syslog.LOG_DEBUG, tag)
|
||||||
|
if err != nil {
|
||||||
|
err = spew.Errorf("Failed to connect to syslog: %v\n", err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
v.syslog = sl
|
||||||
|
}
|
||||||
|
return v.syslog, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *Package) writeToSyslog(options FormatOptions,
|
||||||
|
level LogLevel, appName string, msg string) error {
|
||||||
|
|
||||||
|
sl, err := v.getSyslog(level, options, appName)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
switch level {
|
||||||
|
case DebugLevel:
|
||||||
|
return sl.Debug(msg)
|
||||||
|
case InfoLevel:
|
||||||
|
return sl.Info(msg)
|
||||||
|
case WarnLevel:
|
||||||
|
return sl.Warning(msg)
|
||||||
|
case ErrorLevel:
|
||||||
|
return sl.Err(msg)
|
||||||
|
case PanicLevel:
|
||||||
|
return sl.Crit(msg)
|
||||||
|
case FatalLevel:
|
||||||
|
return sl.Emerg(msg)
|
||||||
|
default:
|
||||||
|
return sl.Debug(msg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type printLog func(log *Log, msg interface{})
|
||||||
|
type getMessage func(colored bool) interface{}
|
||||||
|
|
||||||
|
func printLogs(logs []*Log, level LogLevel, prnt printLog, getMsg getMessage) {
|
||||||
|
// Console and custom logs output
|
||||||
|
for _, log := range logs {
|
||||||
|
if log.level >= level {
|
||||||
|
prnt(log, getMsg(log.colored))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *Package) print(level LogLevel, msg string) {
|
||||||
|
lvl := v.GetLogLevel()
|
||||||
|
if lvl >= level {
|
||||||
|
appName := getApplicationName()
|
||||||
|
logs := v.parent.getLogs()
|
||||||
|
options := v.parent.GetFormatOptions()
|
||||||
|
out1 := FormatMessage(options, level, v.packageName, msg, false)
|
||||||
|
// File output
|
||||||
|
if lf := v.parent.GetLogFileInfo(); lf != nil {
|
||||||
|
rotateMaxSize := v.parent.GetRotateMaxSize()
|
||||||
|
rotateMaxCount := v.parent.GetRotateMaxCount()
|
||||||
|
if err := lf.writeToFile(out1, rotateMaxSize, rotateMaxCount); err != nil {
|
||||||
|
err = spew.Errorf("Failed to report syslog message %q: %v\n", out1, err)
|
||||||
|
printLogs(logs, FatalLevel,
|
||||||
|
func(log *Log, msg interface{}) {
|
||||||
|
log.log.Fatal(msg)
|
||||||
|
},
|
||||||
|
func(colored bool) interface{} {
|
||||||
|
return err
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Syslog output
|
||||||
|
if v.parent.GetSyslogEnabled() {
|
||||||
|
if err := v.writeToSyslog(options, level, appName, msg); err != nil {
|
||||||
|
err = spew.Errorf("Failed to report syslog message %q: %v\n", msg, err)
|
||||||
|
printLogs(logs, FatalLevel,
|
||||||
|
func(log *Log, msg interface{}) {
|
||||||
|
log.log.Fatal(msg)
|
||||||
|
},
|
||||||
|
func(colored bool) interface{} {
|
||||||
|
return err
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Console and custom logs output
|
||||||
|
outColored1 := FormatMessage(options, level, v.packageName, msg, true)
|
||||||
|
printLogs(logs, level,
|
||||||
|
func(log *Log, msg interface{}) {
|
||||||
|
log.log.Print(msg)
|
||||||
|
},
|
||||||
|
func(colored bool) interface{} {
|
||||||
|
if colored {
|
||||||
|
return outColored1 + fmt.Sprintln()
|
||||||
|
} else {
|
||||||
|
return out1 + fmt.Sprintln()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
// Check critical events
|
||||||
|
if level == PanicLevel {
|
||||||
|
panic(out1)
|
||||||
|
} else if level == FatalLevel {
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *Package) Printf(level LogLevel, format string, args ...interface{}) {
|
||||||
|
lvl := v.GetLogLevel()
|
||||||
|
if lvl >= level {
|
||||||
|
msg := spew.Sprintf(format, args...)
|
||||||
|
v.print(level, msg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *Package) Print(level LogLevel, args ...interface{}) {
|
||||||
|
lvl := v.GetLogLevel()
|
||||||
|
if lvl >= level {
|
||||||
|
msg := fmt.Sprint(args...)
|
||||||
|
v.print(level, msg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *Package) Debugf(format string, args ...interface{}) {
|
||||||
|
v.Printf(DebugLevel, format, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *Package) Debug(args ...interface{}) {
|
||||||
|
v.Print(DebugLevel, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *Package) Infof(format string, args ...interface{}) {
|
||||||
|
v.Printf(InfoLevel, format, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *Package) Info(args ...interface{}) {
|
||||||
|
v.Print(InfoLevel, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *Package) Notifyf(format string, args ...interface{}) {
|
||||||
|
v.Printf(NotifyLevel, format, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *Package) Notify(args ...interface{}) {
|
||||||
|
v.Print(NotifyLevel, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *Package) Warningf(format string, args ...interface{}) {
|
||||||
|
v.Printf(WarnLevel, format, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *Package) Warnf(format string, args ...interface{}) {
|
||||||
|
v.Printf(WarnLevel, format, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *Package) Warning(args ...interface{}) {
|
||||||
|
v.Print(WarnLevel, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *Package) Warn(args ...interface{}) {
|
||||||
|
v.Print(WarnLevel, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *Package) Errorf(format string, args ...interface{}) {
|
||||||
|
v.Printf(ErrorLevel, format, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *Package) Error(args ...interface{}) {
|
||||||
|
v.Print(ErrorLevel, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *Package) Panicf(format string, args ...interface{}) {
|
||||||
|
v.Printf(PanicLevel, format, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *Package) Panic(args ...interface{}) {
|
||||||
|
v.Print(PanicLevel, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *Package) Fatalf(format string, args ...interface{}) {
|
||||||
|
v.Printf(FatalLevel, format, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *Package) Fatal(args ...interface{}) {
|
||||||
|
v.Print(FatalLevel, args...)
|
||||||
|
}
|
133
vendor/github.com/d2r2/go-logger/utils.go
generated
vendored
Normal file
133
vendor/github.com/d2r2/go-logger/utils.go
generated
vendored
Normal file
|
@ -0,0 +1,133 @@
|
||||||
|
package logger
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"path"
|
||||||
|
"regexp"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type logFile struct {
|
||||||
|
FileInfo os.FileInfo
|
||||||
|
Index int
|
||||||
|
}
|
||||||
|
|
||||||
|
type sortLogFiles struct {
|
||||||
|
Items []logFile
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sf *sortLogFiles) Len() int {
|
||||||
|
return len(sf.Items)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sf *sortLogFiles) Less(i, j int) bool {
|
||||||
|
return sf.Items[j].Index < sf.Items[i].Index
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sf *sortLogFiles) Swap(i, j int) {
|
||||||
|
item := sf.Items[i]
|
||||||
|
sf.Items[i] = sf.Items[j]
|
||||||
|
sf.Items[j] = item
|
||||||
|
}
|
||||||
|
|
||||||
|
func findStringSubmatchIndexes(r *regexp.Regexp, s string) map[string][2]int {
|
||||||
|
captures := make(map[string][2]int)
|
||||||
|
ind := r.FindStringSubmatchIndex(s)
|
||||||
|
names := r.SubexpNames()
|
||||||
|
for i, name := range names {
|
||||||
|
if name != "" && i < len(ind)/2 {
|
||||||
|
if ind[i*2] != -1 && ind[i*2+1] != -1 {
|
||||||
|
captures[name] = [2]int{ind[i*2], ind[i*2+1]}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return captures
|
||||||
|
}
|
||||||
|
|
||||||
|
func extractIndex(item os.FileInfo) int {
|
||||||
|
r := regexp.MustCompile(`.+\.log(\.(?P<index>\d+))?`)
|
||||||
|
fileName := path.Base(item.Name())
|
||||||
|
m := findStringSubmatchIndexes(r, fileName)
|
||||||
|
if v, ok := m["index"]; ok {
|
||||||
|
i, _ := strconv.Atoi(fileName[v[0]:v[1]])
|
||||||
|
return i
|
||||||
|
} else {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
nocolor = 0
|
||||||
|
red = 31
|
||||||
|
green = 32
|
||||||
|
yellow = 33
|
||||||
|
blue = 34
|
||||||
|
gray = 37
|
||||||
|
)
|
||||||
|
|
||||||
|
type IndentKind int
|
||||||
|
|
||||||
|
const (
|
||||||
|
LeftIndent = iota
|
||||||
|
CenterIndent
|
||||||
|
RightIndent
|
||||||
|
)
|
||||||
|
|
||||||
|
func cutOrIndentText(text string, length int, indent IndentKind) string {
|
||||||
|
if length < 0 {
|
||||||
|
return text
|
||||||
|
} else if len(text) > length {
|
||||||
|
text = text[:length]
|
||||||
|
} else {
|
||||||
|
switch indent {
|
||||||
|
case LeftIndent:
|
||||||
|
text = text + strings.Repeat(" ", length-len(text))
|
||||||
|
case RightIndent:
|
||||||
|
text = strings.Repeat(" ", length-len(text)) + text
|
||||||
|
case CenterIndent:
|
||||||
|
text = strings.Repeat(" ", (length-len(text))/2) + text +
|
||||||
|
strings.Repeat(" ", length-len(text)-(length-len(text))/2)
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return text
|
||||||
|
}
|
||||||
|
|
||||||
|
func metaFmtStr(colored bool, level LogLevel, options FormatOptions, appName string,
|
||||||
|
packageName string, message string, format string) string {
|
||||||
|
var colorPfx, colorSfx string
|
||||||
|
if colored {
|
||||||
|
var levelColor int
|
||||||
|
switch level {
|
||||||
|
case DebugLevel:
|
||||||
|
levelColor = gray
|
||||||
|
case InfoLevel:
|
||||||
|
levelColor = blue
|
||||||
|
case NotifyLevel, WarnLevel:
|
||||||
|
levelColor = yellow
|
||||||
|
case ErrorLevel, PanicLevel, FatalLevel:
|
||||||
|
levelColor = red
|
||||||
|
default:
|
||||||
|
levelColor = nocolor
|
||||||
|
}
|
||||||
|
colorPfx = "\x1b[" + strconv.Itoa(levelColor) + "m"
|
||||||
|
colorSfx = "\x1b[0m"
|
||||||
|
}
|
||||||
|
arg1 := time.Now().Format(options.TimeFormat)
|
||||||
|
arg2 := appName
|
||||||
|
arg3 := cutOrIndentText(packageName, options.PackageLength, RightIndent)
|
||||||
|
lvlStr := options.GetLevelStr(level)
|
||||||
|
lvlLen := len([]rune(lvlStr))
|
||||||
|
arg4 := colorPfx + cutOrIndentText(strings.ToUpper(lvlStr), lvlLen, LeftIndent) + colorSfx
|
||||||
|
arg5 := message
|
||||||
|
out := fmt.Sprintf(format, arg1, arg2, arg3, arg4, arg5)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
func getApplicationName() string {
|
||||||
|
appName := os.Args[0]
|
||||||
|
return appName
|
||||||
|
}
|
15
vendor/github.com/davecgh/go-spew/LICENSE
generated
vendored
Normal file
15
vendor/github.com/davecgh/go-spew/LICENSE
generated
vendored
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
ISC License
|
||||||
|
|
||||||
|
Copyright (c) 2012-2016 Dave Collins <dave@davec.name>
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
purpose with or without fee is hereby granted, provided that the above
|
||||||
|
copyright notice and this permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
145
vendor/github.com/davecgh/go-spew/spew/bypass.go
generated
vendored
Normal file
145
vendor/github.com/davecgh/go-spew/spew/bypass.go
generated
vendored
Normal file
|
@ -0,0 +1,145 @@
|
||||||
|
// Copyright (c) 2015-2016 Dave Collins <dave@davec.name>
|
||||||
|
//
|
||||||
|
// Permission to use, copy, modify, and distribute this software for any
|
||||||
|
// purpose with or without fee is hereby granted, provided that the above
|
||||||
|
// copyright notice and this permission notice appear in all copies.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
|
// NOTE: Due to the following build constraints, this file will only be compiled
|
||||||
|
// when the code is not running on Google App Engine, compiled by GopherJS, and
|
||||||
|
// "-tags safe" is not added to the go build command line. The "disableunsafe"
|
||||||
|
// tag is deprecated and thus should not be used.
|
||||||
|
// Go versions prior to 1.4 are disabled because they use a different layout
|
||||||
|
// for interfaces which make the implementation of unsafeReflectValue more complex.
|
||||||
|
// +build !js,!appengine,!safe,!disableunsafe,go1.4
|
||||||
|
|
||||||
|
package spew
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// UnsafeDisabled is a build-time constant which specifies whether or
|
||||||
|
// not access to the unsafe package is available.
|
||||||
|
UnsafeDisabled = false
|
||||||
|
|
||||||
|
// ptrSize is the size of a pointer on the current arch.
|
||||||
|
ptrSize = unsafe.Sizeof((*byte)(nil))
|
||||||
|
)
|
||||||
|
|
||||||
|
type flag uintptr
|
||||||
|
|
||||||
|
var (
|
||||||
|
// flagRO indicates whether the value field of a reflect.Value
|
||||||
|
// is read-only.
|
||||||
|
flagRO flag
|
||||||
|
|
||||||
|
// flagAddr indicates whether the address of the reflect.Value's
|
||||||
|
// value may be taken.
|
||||||
|
flagAddr flag
|
||||||
|
)
|
||||||
|
|
||||||
|
// flagKindMask holds the bits that make up the kind
|
||||||
|
// part of the flags field. In all the supported versions,
|
||||||
|
// it is in the lower 5 bits.
|
||||||
|
const flagKindMask = flag(0x1f)
|
||||||
|
|
||||||
|
// Different versions of Go have used different
|
||||||
|
// bit layouts for the flags type. This table
|
||||||
|
// records the known combinations.
|
||||||
|
var okFlags = []struct {
|
||||||
|
ro, addr flag
|
||||||
|
}{{
|
||||||
|
// From Go 1.4 to 1.5
|
||||||
|
ro: 1 << 5,
|
||||||
|
addr: 1 << 7,
|
||||||
|
}, {
|
||||||
|
// Up to Go tip.
|
||||||
|
ro: 1<<5 | 1<<6,
|
||||||
|
addr: 1 << 8,
|
||||||
|
}}
|
||||||
|
|
||||||
|
var flagValOffset = func() uintptr {
|
||||||
|
field, ok := reflect.TypeOf(reflect.Value{}).FieldByName("flag")
|
||||||
|
if !ok {
|
||||||
|
panic("reflect.Value has no flag field")
|
||||||
|
}
|
||||||
|
return field.Offset
|
||||||
|
}()
|
||||||
|
|
||||||
|
// flagField returns a pointer to the flag field of a reflect.Value.
|
||||||
|
func flagField(v *reflect.Value) *flag {
|
||||||
|
return (*flag)(unsafe.Pointer(uintptr(unsafe.Pointer(v)) + flagValOffset))
|
||||||
|
}
|
||||||
|
|
||||||
|
// unsafeReflectValue converts the passed reflect.Value into a one that bypasses
|
||||||
|
// the typical safety restrictions preventing access to unaddressable and
|
||||||
|
// unexported data. It works by digging the raw pointer to the underlying
|
||||||
|
// value out of the protected value and generating a new unprotected (unsafe)
|
||||||
|
// reflect.Value to it.
|
||||||
|
//
|
||||||
|
// This allows us to check for implementations of the Stringer and error
|
||||||
|
// interfaces to be used for pretty printing ordinarily unaddressable and
|
||||||
|
// inaccessible values such as unexported struct fields.
|
||||||
|
func unsafeReflectValue(v reflect.Value) reflect.Value {
|
||||||
|
if !v.IsValid() || (v.CanInterface() && v.CanAddr()) {
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
flagFieldPtr := flagField(&v)
|
||||||
|
*flagFieldPtr &^= flagRO
|
||||||
|
*flagFieldPtr |= flagAddr
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sanity checks against future reflect package changes
|
||||||
|
// to the type or semantics of the Value.flag field.
|
||||||
|
func init() {
|
||||||
|
field, ok := reflect.TypeOf(reflect.Value{}).FieldByName("flag")
|
||||||
|
if !ok {
|
||||||
|
panic("reflect.Value has no flag field")
|
||||||
|
}
|
||||||
|
if field.Type.Kind() != reflect.TypeOf(flag(0)).Kind() {
|
||||||
|
panic("reflect.Value flag field has changed kind")
|
||||||
|
}
|
||||||
|
type t0 int
|
||||||
|
var t struct {
|
||||||
|
A t0
|
||||||
|
// t0 will have flagEmbedRO set.
|
||||||
|
t0
|
||||||
|
// a will have flagStickyRO set
|
||||||
|
a t0
|
||||||
|
}
|
||||||
|
vA := reflect.ValueOf(t).FieldByName("A")
|
||||||
|
va := reflect.ValueOf(t).FieldByName("a")
|
||||||
|
vt0 := reflect.ValueOf(t).FieldByName("t0")
|
||||||
|
|
||||||
|
// Infer flagRO from the difference between the flags
|
||||||
|
// for the (otherwise identical) fields in t.
|
||||||
|
flagPublic := *flagField(&vA)
|
||||||
|
flagWithRO := *flagField(&va) | *flagField(&vt0)
|
||||||
|
flagRO = flagPublic ^ flagWithRO
|
||||||
|
|
||||||
|
// Infer flagAddr from the difference between a value
|
||||||
|
// taken from a pointer and not.
|
||||||
|
vPtrA := reflect.ValueOf(&t).Elem().FieldByName("A")
|
||||||
|
flagNoPtr := *flagField(&vA)
|
||||||
|
flagPtr := *flagField(&vPtrA)
|
||||||
|
flagAddr = flagNoPtr ^ flagPtr
|
||||||
|
|
||||||
|
// Check that the inferred flags tally with one of the known versions.
|
||||||
|
for _, f := range okFlags {
|
||||||
|
if flagRO == f.ro && flagAddr == f.addr {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
panic("reflect.Value read-only flag has changed semantics")
|
||||||
|
}
|
38
vendor/github.com/davecgh/go-spew/spew/bypasssafe.go
generated
vendored
Normal file
38
vendor/github.com/davecgh/go-spew/spew/bypasssafe.go
generated
vendored
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
// Copyright (c) 2015-2016 Dave Collins <dave@davec.name>
|
||||||
|
//
|
||||||
|
// Permission to use, copy, modify, and distribute this software for any
|
||||||
|
// purpose with or without fee is hereby granted, provided that the above
|
||||||
|
// copyright notice and this permission notice appear in all copies.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
|
// NOTE: Due to the following build constraints, this file will only be compiled
|
||||||
|
// when the code is running on Google App Engine, compiled by GopherJS, or
|
||||||
|
// "-tags safe" is added to the go build command line. The "disableunsafe"
|
||||||
|
// tag is deprecated and thus should not be used.
|
||||||
|
// +build js appengine safe disableunsafe !go1.4
|
||||||
|
|
||||||
|
package spew
|
||||||
|
|
||||||
|
import "reflect"
|
||||||
|
|
||||||
|
const (
|
||||||
|
// UnsafeDisabled is a build-time constant which specifies whether or
|
||||||
|
// not access to the unsafe package is available.
|
||||||
|
UnsafeDisabled = true
|
||||||
|
)
|
||||||
|
|
||||||
|
// unsafeReflectValue typically converts the passed reflect.Value into a one
|
||||||
|
// that bypasses the typical safety restrictions preventing access to
|
||||||
|
// unaddressable and unexported data. However, doing this relies on access to
|
||||||
|
// the unsafe package. This is a stub version which simply returns the passed
|
||||||
|
// reflect.Value when the unsafe package is not available.
|
||||||
|
func unsafeReflectValue(v reflect.Value) reflect.Value {
|
||||||
|
return v
|
||||||
|
}
|
341
vendor/github.com/davecgh/go-spew/spew/common.go
generated
vendored
Normal file
341
vendor/github.com/davecgh/go-spew/spew/common.go
generated
vendored
Normal file
|
@ -0,0 +1,341 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2013-2016 Dave Collins <dave@davec.name>
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
* copyright notice and this permission notice appear in all copies.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package spew
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"reflect"
|
||||||
|
"sort"
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Some constants in the form of bytes to avoid string overhead. This mirrors
|
||||||
|
// the technique used in the fmt package.
|
||||||
|
var (
|
||||||
|
panicBytes = []byte("(PANIC=")
|
||||||
|
plusBytes = []byte("+")
|
||||||
|
iBytes = []byte("i")
|
||||||
|
trueBytes = []byte("true")
|
||||||
|
falseBytes = []byte("false")
|
||||||
|
interfaceBytes = []byte("(interface {})")
|
||||||
|
commaNewlineBytes = []byte(",\n")
|
||||||
|
newlineBytes = []byte("\n")
|
||||||
|
openBraceBytes = []byte("{")
|
||||||
|
openBraceNewlineBytes = []byte("{\n")
|
||||||
|
closeBraceBytes = []byte("}")
|
||||||
|
asteriskBytes = []byte("*")
|
||||||
|
colonBytes = []byte(":")
|
||||||
|
colonSpaceBytes = []byte(": ")
|
||||||
|
openParenBytes = []byte("(")
|
||||||
|
closeParenBytes = []byte(")")
|
||||||
|
spaceBytes = []byte(" ")
|
||||||
|
pointerChainBytes = []byte("->")
|
||||||
|
nilAngleBytes = []byte("<nil>")
|
||||||
|
maxNewlineBytes = []byte("<max depth reached>\n")
|
||||||
|
maxShortBytes = []byte("<max>")
|
||||||
|
circularBytes = []byte("<already shown>")
|
||||||
|
circularShortBytes = []byte("<shown>")
|
||||||
|
invalidAngleBytes = []byte("<invalid>")
|
||||||
|
openBracketBytes = []byte("[")
|
||||||
|
closeBracketBytes = []byte("]")
|
||||||
|
percentBytes = []byte("%")
|
||||||
|
precisionBytes = []byte(".")
|
||||||
|
openAngleBytes = []byte("<")
|
||||||
|
closeAngleBytes = []byte(">")
|
||||||
|
openMapBytes = []byte("map[")
|
||||||
|
closeMapBytes = []byte("]")
|
||||||
|
lenEqualsBytes = []byte("len=")
|
||||||
|
capEqualsBytes = []byte("cap=")
|
||||||
|
)
|
||||||
|
|
||||||
|
// hexDigits is used to map a decimal value to a hex digit.
|
||||||
|
var hexDigits = "0123456789abcdef"
|
||||||
|
|
||||||
|
// catchPanic handles any panics that might occur during the handleMethods
|
||||||
|
// calls.
|
||||||
|
func catchPanic(w io.Writer, v reflect.Value) {
|
||||||
|
if err := recover(); err != nil {
|
||||||
|
w.Write(panicBytes)
|
||||||
|
fmt.Fprintf(w, "%v", err)
|
||||||
|
w.Write(closeParenBytes)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// handleMethods attempts to call the Error and String methods on the underlying
|
||||||
|
// type the passed reflect.Value represents and outputes the result to Writer w.
|
||||||
|
//
|
||||||
|
// It handles panics in any called methods by catching and displaying the error
|
||||||
|
// as the formatted value.
|
||||||
|
func handleMethods(cs *ConfigState, w io.Writer, v reflect.Value) (handled bool) {
|
||||||
|
// We need an interface to check if the type implements the error or
|
||||||
|
// Stringer interface. However, the reflect package won't give us an
|
||||||
|
// interface on certain things like unexported struct fields in order
|
||||||
|
// to enforce visibility rules. We use unsafe, when it's available,
|
||||||
|
// to bypass these restrictions since this package does not mutate the
|
||||||
|
// values.
|
||||||
|
if !v.CanInterface() {
|
||||||
|
if UnsafeDisabled {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
v = unsafeReflectValue(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Choose whether or not to do error and Stringer interface lookups against
|
||||||
|
// the base type or a pointer to the base type depending on settings.
|
||||||
|
// Technically calling one of these methods with a pointer receiver can
|
||||||
|
// mutate the value, however, types which choose to satisify an error or
|
||||||
|
// Stringer interface with a pointer receiver should not be mutating their
|
||||||
|
// state inside these interface methods.
|
||||||
|
if !cs.DisablePointerMethods && !UnsafeDisabled && !v.CanAddr() {
|
||||||
|
v = unsafeReflectValue(v)
|
||||||
|
}
|
||||||
|
if v.CanAddr() {
|
||||||
|
v = v.Addr()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Is it an error or Stringer?
|
||||||
|
switch iface := v.Interface().(type) {
|
||||||
|
case error:
|
||||||
|
defer catchPanic(w, v)
|
||||||
|
if cs.ContinueOnMethod {
|
||||||
|
w.Write(openParenBytes)
|
||||||
|
w.Write([]byte(iface.Error()))
|
||||||
|
w.Write(closeParenBytes)
|
||||||
|
w.Write(spaceBytes)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
w.Write([]byte(iface.Error()))
|
||||||
|
return true
|
||||||
|
|
||||||
|
case fmt.Stringer:
|
||||||
|
defer catchPanic(w, v)
|
||||||
|
if cs.ContinueOnMethod {
|
||||||
|
w.Write(openParenBytes)
|
||||||
|
w.Write([]byte(iface.String()))
|
||||||
|
w.Write(closeParenBytes)
|
||||||
|
w.Write(spaceBytes)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
w.Write([]byte(iface.String()))
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// printBool outputs a boolean value as true or false to Writer w.
|
||||||
|
func printBool(w io.Writer, val bool) {
|
||||||
|
if val {
|
||||||
|
w.Write(trueBytes)
|
||||||
|
} else {
|
||||||
|
w.Write(falseBytes)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// printInt outputs a signed integer value to Writer w.
|
||||||
|
func printInt(w io.Writer, val int64, base int) {
|
||||||
|
w.Write([]byte(strconv.FormatInt(val, base)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// printUint outputs an unsigned integer value to Writer w.
|
||||||
|
func printUint(w io.Writer, val uint64, base int) {
|
||||||
|
w.Write([]byte(strconv.FormatUint(val, base)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// printFloat outputs a floating point value using the specified precision,
|
||||||
|
// which is expected to be 32 or 64bit, to Writer w.
|
||||||
|
func printFloat(w io.Writer, val float64, precision int) {
|
||||||
|
w.Write([]byte(strconv.FormatFloat(val, 'g', -1, precision)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// printComplex outputs a complex value using the specified float precision
|
||||||
|
// for the real and imaginary parts to Writer w.
|
||||||
|
func printComplex(w io.Writer, c complex128, floatPrecision int) {
|
||||||
|
r := real(c)
|
||||||
|
w.Write(openParenBytes)
|
||||||
|
w.Write([]byte(strconv.FormatFloat(r, 'g', -1, floatPrecision)))
|
||||||
|
i := imag(c)
|
||||||
|
if i >= 0 {
|
||||||
|
w.Write(plusBytes)
|
||||||
|
}
|
||||||
|
w.Write([]byte(strconv.FormatFloat(i, 'g', -1, floatPrecision)))
|
||||||
|
w.Write(iBytes)
|
||||||
|
w.Write(closeParenBytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
// printHexPtr outputs a uintptr formatted as hexadecimal with a leading '0x'
|
||||||
|
// prefix to Writer w.
|
||||||
|
func printHexPtr(w io.Writer, p uintptr) {
|
||||||
|
// Null pointer.
|
||||||
|
num := uint64(p)
|
||||||
|
if num == 0 {
|
||||||
|
w.Write(nilAngleBytes)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Max uint64 is 16 bytes in hex + 2 bytes for '0x' prefix
|
||||||
|
buf := make([]byte, 18)
|
||||||
|
|
||||||
|
// It's simpler to construct the hex string right to left.
|
||||||
|
base := uint64(16)
|
||||||
|
i := len(buf) - 1
|
||||||
|
for num >= base {
|
||||||
|
buf[i] = hexDigits[num%base]
|
||||||
|
num /= base
|
||||||
|
i--
|
||||||
|
}
|
||||||
|
buf[i] = hexDigits[num]
|
||||||
|
|
||||||
|
// Add '0x' prefix.
|
||||||
|
i--
|
||||||
|
buf[i] = 'x'
|
||||||
|
i--
|
||||||
|
buf[i] = '0'
|
||||||
|
|
||||||
|
// Strip unused leading bytes.
|
||||||
|
buf = buf[i:]
|
||||||
|
w.Write(buf)
|
||||||
|
}
|
||||||
|
|
||||||
|
// valuesSorter implements sort.Interface to allow a slice of reflect.Value
|
||||||
|
// elements to be sorted.
|
||||||
|
type valuesSorter struct {
|
||||||
|
values []reflect.Value
|
||||||
|
strings []string // either nil or same len and values
|
||||||
|
cs *ConfigState
|
||||||
|
}
|
||||||
|
|
||||||
|
// newValuesSorter initializes a valuesSorter instance, which holds a set of
|
||||||
|
// surrogate keys on which the data should be sorted. It uses flags in
|
||||||
|
// ConfigState to decide if and how to populate those surrogate keys.
|
||||||
|
func newValuesSorter(values []reflect.Value, cs *ConfigState) sort.Interface {
|
||||||
|
vs := &valuesSorter{values: values, cs: cs}
|
||||||
|
if canSortSimply(vs.values[0].Kind()) {
|
||||||
|
return vs
|
||||||
|
}
|
||||||
|
if !cs.DisableMethods {
|
||||||
|
vs.strings = make([]string, len(values))
|
||||||
|
for i := range vs.values {
|
||||||
|
b := bytes.Buffer{}
|
||||||
|
if !handleMethods(cs, &b, vs.values[i]) {
|
||||||
|
vs.strings = nil
|
||||||
|
break
|
||||||
|
}
|
||||||
|
vs.strings[i] = b.String()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if vs.strings == nil && cs.SpewKeys {
|
||||||
|
vs.strings = make([]string, len(values))
|
||||||
|
for i := range vs.values {
|
||||||
|
vs.strings[i] = Sprintf("%#v", vs.values[i].Interface())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return vs
|
||||||
|
}
|
||||||
|
|
||||||
|
// canSortSimply tests whether a reflect.Kind is a primitive that can be sorted
|
||||||
|
// directly, or whether it should be considered for sorting by surrogate keys
|
||||||
|
// (if the ConfigState allows it).
|
||||||
|
func canSortSimply(kind reflect.Kind) bool {
|
||||||
|
// This switch parallels valueSortLess, except for the default case.
|
||||||
|
switch kind {
|
||||||
|
case reflect.Bool:
|
||||||
|
return true
|
||||||
|
case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int:
|
||||||
|
return true
|
||||||
|
case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint:
|
||||||
|
return true
|
||||||
|
case reflect.Float32, reflect.Float64:
|
||||||
|
return true
|
||||||
|
case reflect.String:
|
||||||
|
return true
|
||||||
|
case reflect.Uintptr:
|
||||||
|
return true
|
||||||
|
case reflect.Array:
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Len returns the number of values in the slice. It is part of the
|
||||||
|
// sort.Interface implementation.
|
||||||
|
func (s *valuesSorter) Len() int {
|
||||||
|
return len(s.values)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Swap swaps the values at the passed indices. It is part of the
|
||||||
|
// sort.Interface implementation.
|
||||||
|
func (s *valuesSorter) Swap(i, j int) {
|
||||||
|
s.values[i], s.values[j] = s.values[j], s.values[i]
|
||||||
|
if s.strings != nil {
|
||||||
|
s.strings[i], s.strings[j] = s.strings[j], s.strings[i]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// valueSortLess returns whether the first value should sort before the second
|
||||||
|
// value. It is used by valueSorter.Less as part of the sort.Interface
|
||||||
|
// implementation.
|
||||||
|
func valueSortLess(a, b reflect.Value) bool {
|
||||||
|
switch a.Kind() {
|
||||||
|
case reflect.Bool:
|
||||||
|
return !a.Bool() && b.Bool()
|
||||||
|
case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int:
|
||||||
|
return a.Int() < b.Int()
|
||||||
|
case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint:
|
||||||
|
return a.Uint() < b.Uint()
|
||||||
|
case reflect.Float32, reflect.Float64:
|
||||||
|
return a.Float() < b.Float()
|
||||||
|
case reflect.String:
|
||||||
|
return a.String() < b.String()
|
||||||
|
case reflect.Uintptr:
|
||||||
|
return a.Uint() < b.Uint()
|
||||||
|
case reflect.Array:
|
||||||
|
// Compare the contents of both arrays.
|
||||||
|
l := a.Len()
|
||||||
|
for i := 0; i < l; i++ {
|
||||||
|
av := a.Index(i)
|
||||||
|
bv := b.Index(i)
|
||||||
|
if av.Interface() == bv.Interface() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
return valueSortLess(av, bv)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return a.String() < b.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Less returns whether the value at index i should sort before the
|
||||||
|
// value at index j. It is part of the sort.Interface implementation.
|
||||||
|
func (s *valuesSorter) Less(i, j int) bool {
|
||||||
|
if s.strings == nil {
|
||||||
|
return valueSortLess(s.values[i], s.values[j])
|
||||||
|
}
|
||||||
|
return s.strings[i] < s.strings[j]
|
||||||
|
}
|
||||||
|
|
||||||
|
// sortValues is a sort function that handles both native types and any type that
|
||||||
|
// can be converted to error or Stringer. Other inputs are sorted according to
|
||||||
|
// their Value.String() value to ensure display stability.
|
||||||
|
func sortValues(values []reflect.Value, cs *ConfigState) {
|
||||||
|
if len(values) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
sort.Sort(newValuesSorter(values, cs))
|
||||||
|
}
|
306
vendor/github.com/davecgh/go-spew/spew/config.go
generated
vendored
Normal file
306
vendor/github.com/davecgh/go-spew/spew/config.go
generated
vendored
Normal file
|
@ -0,0 +1,306 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2013-2016 Dave Collins <dave@davec.name>
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
* copyright notice and this permission notice appear in all copies.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package spew
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ConfigState houses the configuration options used by spew to format and
|
||||||
|
// display values. There is a global instance, Config, that is used to control
|
||||||
|
// all top-level Formatter and Dump functionality. Each ConfigState instance
|
||||||
|
// provides methods equivalent to the top-level functions.
|
||||||
|
//
|
||||||
|
// The zero value for ConfigState provides no indentation. You would typically
|
||||||
|
// want to set it to a space or a tab.
|
||||||
|
//
|
||||||
|
// Alternatively, you can use NewDefaultConfig to get a ConfigState instance
|
||||||
|
// with default settings. See the documentation of NewDefaultConfig for default
|
||||||
|
// values.
|
||||||
|
type ConfigState struct {
|
||||||
|
// Indent specifies the string to use for each indentation level. The
|
||||||
|
// global config instance that all top-level functions use set this to a
|
||||||
|
// single space by default. If you would like more indentation, you might
|
||||||
|
// set this to a tab with "\t" or perhaps two spaces with " ".
|
||||||
|
Indent string
|
||||||
|
|
||||||
|
// MaxDepth controls the maximum number of levels to descend into nested
|
||||||
|
// data structures. The default, 0, means there is no limit.
|
||||||
|
//
|
||||||
|
// NOTE: Circular data structures are properly detected, so it is not
|
||||||
|
// necessary to set this value unless you specifically want to limit deeply
|
||||||
|
// nested data structures.
|
||||||
|
MaxDepth int
|
||||||
|
|
||||||
|
// DisableMethods specifies whether or not error and Stringer interfaces are
|
||||||
|
// invoked for types that implement them.
|
||||||
|
DisableMethods bool
|
||||||
|
|
||||||
|
// DisablePointerMethods specifies whether or not to check for and invoke
|
||||||
|
// error and Stringer interfaces on types which only accept a pointer
|
||||||
|
// receiver when the current type is not a pointer.
|
||||||
|
//
|
||||||
|
// NOTE: This might be an unsafe action since calling one of these methods
|
||||||
|
// with a pointer receiver could technically mutate the value, however,
|
||||||
|
// in practice, types which choose to satisify an error or Stringer
|
||||||
|
// interface with a pointer receiver should not be mutating their state
|
||||||
|
// inside these interface methods. As a result, this option relies on
|
||||||
|
// access to the unsafe package, so it will not have any effect when
|
||||||
|
// running in environments without access to the unsafe package such as
|
||||||
|
// Google App Engine or with the "safe" build tag specified.
|
||||||
|
DisablePointerMethods bool
|
||||||
|
|
||||||
|
// DisablePointerAddresses specifies whether to disable the printing of
|
||||||
|
// pointer addresses. This is useful when diffing data structures in tests.
|
||||||
|
DisablePointerAddresses bool
|
||||||
|
|
||||||
|
// DisableCapacities specifies whether to disable the printing of capacities
|
||||||
|
// for arrays, slices, maps and channels. This is useful when diffing
|
||||||
|
// data structures in tests.
|
||||||
|
DisableCapacities bool
|
||||||
|
|
||||||
|
// ContinueOnMethod specifies whether or not recursion should continue once
|
||||||
|
// a custom error or Stringer interface is invoked. The default, false,
|
||||||
|
// means it will print the results of invoking the custom error or Stringer
|
||||||
|
// interface and return immediately instead of continuing to recurse into
|
||||||
|
// the internals of the data type.
|
||||||
|
//
|
||||||
|
// NOTE: This flag does not have any effect if method invocation is disabled
|
||||||
|
// via the DisableMethods or DisablePointerMethods options.
|
||||||
|
ContinueOnMethod bool
|
||||||
|
|
||||||
|
// SortKeys specifies map keys should be sorted before being printed. Use
|
||||||
|
// this to have a more deterministic, diffable output. Note that only
|
||||||
|
// native types (bool, int, uint, floats, uintptr and string) and types
|
||||||
|
// that support the error or Stringer interfaces (if methods are
|
||||||
|
// enabled) are supported, with other types sorted according to the
|
||||||
|
// reflect.Value.String() output which guarantees display stability.
|
||||||
|
SortKeys bool
|
||||||
|
|
||||||
|
// SpewKeys specifies that, as a last resort attempt, map keys should
|
||||||
|
// be spewed to strings and sorted by those strings. This is only
|
||||||
|
// considered if SortKeys is true.
|
||||||
|
SpewKeys bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// Config is the active configuration of the top-level functions.
|
||||||
|
// The configuration can be changed by modifying the contents of spew.Config.
|
||||||
|
var Config = ConfigState{Indent: " "}
|
||||||
|
|
||||||
|
// Errorf is a wrapper for fmt.Errorf that treats each argument as if it were
|
||||||
|
// passed with a Formatter interface returned by c.NewFormatter. It returns
|
||||||
|
// the formatted string as a value that satisfies error. See NewFormatter
|
||||||
|
// for formatting details.
|
||||||
|
//
|
||||||
|
// This function is shorthand for the following syntax:
|
||||||
|
//
|
||||||
|
// fmt.Errorf(format, c.NewFormatter(a), c.NewFormatter(b))
|
||||||
|
func (c *ConfigState) Errorf(format string, a ...interface{}) (err error) {
|
||||||
|
return fmt.Errorf(format, c.convertArgs(a)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fprint is a wrapper for fmt.Fprint that treats each argument as if it were
|
||||||
|
// passed with a Formatter interface returned by c.NewFormatter. It returns
|
||||||
|
// the number of bytes written and any write error encountered. See
|
||||||
|
// NewFormatter for formatting details.
|
||||||
|
//
|
||||||
|
// This function is shorthand for the following syntax:
|
||||||
|
//
|
||||||
|
// fmt.Fprint(w, c.NewFormatter(a), c.NewFormatter(b))
|
||||||
|
func (c *ConfigState) Fprint(w io.Writer, a ...interface{}) (n int, err error) {
|
||||||
|
return fmt.Fprint(w, c.convertArgs(a)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fprintf is a wrapper for fmt.Fprintf that treats each argument as if it were
|
||||||
|
// passed with a Formatter interface returned by c.NewFormatter. It returns
|
||||||
|
// the number of bytes written and any write error encountered. See
|
||||||
|
// NewFormatter for formatting details.
|
||||||
|
//
|
||||||
|
// This function is shorthand for the following syntax:
|
||||||
|
//
|
||||||
|
// fmt.Fprintf(w, format, c.NewFormatter(a), c.NewFormatter(b))
|
||||||
|
func (c *ConfigState) Fprintf(w io.Writer, format string, a ...interface{}) (n int, err error) {
|
||||||
|
return fmt.Fprintf(w, format, c.convertArgs(a)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fprintln is a wrapper for fmt.Fprintln that treats each argument as if it
|
||||||
|
// passed with a Formatter interface returned by c.NewFormatter. See
|
||||||
|
// NewFormatter for formatting details.
|
||||||
|
//
|
||||||
|
// This function is shorthand for the following syntax:
|
||||||
|
//
|
||||||
|
// fmt.Fprintln(w, c.NewFormatter(a), c.NewFormatter(b))
|
||||||
|
func (c *ConfigState) Fprintln(w io.Writer, a ...interface{}) (n int, err error) {
|
||||||
|
return fmt.Fprintln(w, c.convertArgs(a)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Print is a wrapper for fmt.Print that treats each argument as if it were
|
||||||
|
// passed with a Formatter interface returned by c.NewFormatter. It returns
|
||||||
|
// the number of bytes written and any write error encountered. See
|
||||||
|
// NewFormatter for formatting details.
|
||||||
|
//
|
||||||
|
// This function is shorthand for the following syntax:
|
||||||
|
//
|
||||||
|
// fmt.Print(c.NewFormatter(a), c.NewFormatter(b))
|
||||||
|
func (c *ConfigState) Print(a ...interface{}) (n int, err error) {
|
||||||
|
return fmt.Print(c.convertArgs(a)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Printf is a wrapper for fmt.Printf that treats each argument as if it were
|
||||||
|
// passed with a Formatter interface returned by c.NewFormatter. It returns
|
||||||
|
// the number of bytes written and any write error encountered. See
|
||||||
|
// NewFormatter for formatting details.
|
||||||
|
//
|
||||||
|
// This function is shorthand for the following syntax:
|
||||||
|
//
|
||||||
|
// fmt.Printf(format, c.NewFormatter(a), c.NewFormatter(b))
|
||||||
|
func (c *ConfigState) Printf(format string, a ...interface{}) (n int, err error) {
|
||||||
|
return fmt.Printf(format, c.convertArgs(a)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Println is a wrapper for fmt.Println that treats each argument as if it were
|
||||||
|
// passed with a Formatter interface returned by c.NewFormatter. It returns
|
||||||
|
// the number of bytes written and any write error encountered. See
|
||||||
|
// NewFormatter for formatting details.
|
||||||
|
//
|
||||||
|
// This function is shorthand for the following syntax:
|
||||||
|
//
|
||||||
|
// fmt.Println(c.NewFormatter(a), c.NewFormatter(b))
|
||||||
|
func (c *ConfigState) Println(a ...interface{}) (n int, err error) {
|
||||||
|
return fmt.Println(c.convertArgs(a)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sprint is a wrapper for fmt.Sprint that treats each argument as if it were
|
||||||
|
// passed with a Formatter interface returned by c.NewFormatter. It returns
|
||||||
|
// the resulting string. See NewFormatter for formatting details.
|
||||||
|
//
|
||||||
|
// This function is shorthand for the following syntax:
|
||||||
|
//
|
||||||
|
// fmt.Sprint(c.NewFormatter(a), c.NewFormatter(b))
|
||||||
|
func (c *ConfigState) Sprint(a ...interface{}) string {
|
||||||
|
return fmt.Sprint(c.convertArgs(a)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sprintf is a wrapper for fmt.Sprintf that treats each argument as if it were
|
||||||
|
// passed with a Formatter interface returned by c.NewFormatter. It returns
|
||||||
|
// the resulting string. See NewFormatter for formatting details.
|
||||||
|
//
|
||||||
|
// This function is shorthand for the following syntax:
|
||||||
|
//
|
||||||
|
// fmt.Sprintf(format, c.NewFormatter(a), c.NewFormatter(b))
|
||||||
|
func (c *ConfigState) Sprintf(format string, a ...interface{}) string {
|
||||||
|
return fmt.Sprintf(format, c.convertArgs(a)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sprintln is a wrapper for fmt.Sprintln that treats each argument as if it
|
||||||
|
// were passed with a Formatter interface returned by c.NewFormatter. It
|
||||||
|
// returns the resulting string. See NewFormatter for formatting details.
|
||||||
|
//
|
||||||
|
// This function is shorthand for the following syntax:
|
||||||
|
//
|
||||||
|
// fmt.Sprintln(c.NewFormatter(a), c.NewFormatter(b))
|
||||||
|
func (c *ConfigState) Sprintln(a ...interface{}) string {
|
||||||
|
return fmt.Sprintln(c.convertArgs(a)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
NewFormatter returns a custom formatter that satisfies the fmt.Formatter
|
||||||
|
interface. As a result, it integrates cleanly with standard fmt package
|
||||||
|
printing functions. The formatter is useful for inline printing of smaller data
|
||||||
|
types similar to the standard %v format specifier.
|
||||||
|
|
||||||
|
The custom formatter only responds to the %v (most compact), %+v (adds pointer
|
||||||
|
addresses), %#v (adds types), and %#+v (adds types and pointer addresses) verb
|
||||||
|
combinations. Any other verbs such as %x and %q will be sent to the the
|
||||||
|
standard fmt package for formatting. In addition, the custom formatter ignores
|
||||||
|
the width and precision arguments (however they will still work on the format
|
||||||
|
specifiers not handled by the custom formatter).
|
||||||
|
|
||||||
|
Typically this function shouldn't be called directly. It is much easier to make
|
||||||
|
use of the custom formatter by calling one of the convenience functions such as
|
||||||
|
c.Printf, c.Println, or c.Printf.
|
||||||
|
*/
|
||||||
|
func (c *ConfigState) NewFormatter(v interface{}) fmt.Formatter {
|
||||||
|
return newFormatter(c, v)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fdump formats and displays the passed arguments to io.Writer w. It formats
|
||||||
|
// exactly the same as Dump.
|
||||||
|
func (c *ConfigState) Fdump(w io.Writer, a ...interface{}) {
|
||||||
|
fdump(c, w, a...)
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Dump displays the passed parameters to standard out with newlines, customizable
|
||||||
|
indentation, and additional debug information such as complete types and all
|
||||||
|
pointer addresses used to indirect to the final value. It provides the
|
||||||
|
following features over the built-in printing facilities provided by the fmt
|
||||||
|
package:
|
||||||
|
|
||||||
|
* Pointers are dereferenced and followed
|
||||||
|
* Circular data structures are detected and handled properly
|
||||||
|
* Custom Stringer/error interfaces are optionally invoked, including
|
||||||
|
on unexported types
|
||||||
|
* Custom types which only implement the Stringer/error interfaces via
|
||||||
|
a pointer receiver are optionally invoked when passing non-pointer
|
||||||
|
variables
|
||||||
|
* Byte arrays and slices are dumped like the hexdump -C command which
|
||||||
|
includes offsets, byte values in hex, and ASCII output
|
||||||
|
|
||||||
|
The configuration options are controlled by modifying the public members
|
||||||
|
of c. See ConfigState for options documentation.
|
||||||
|
|
||||||
|
See Fdump if you would prefer dumping to an arbitrary io.Writer or Sdump to
|
||||||
|
get the formatted result as a string.
|
||||||
|
*/
|
||||||
|
func (c *ConfigState) Dump(a ...interface{}) {
|
||||||
|
fdump(c, os.Stdout, a...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sdump returns a string with the passed arguments formatted exactly the same
|
||||||
|
// as Dump.
|
||||||
|
func (c *ConfigState) Sdump(a ...interface{}) string {
|
||||||
|
var buf bytes.Buffer
|
||||||
|
fdump(c, &buf, a...)
|
||||||
|
return buf.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
// convertArgs accepts a slice of arguments and returns a slice of the same
|
||||||
|
// length with each argument converted to a spew Formatter interface using
|
||||||
|
// the ConfigState associated with s.
|
||||||
|
func (c *ConfigState) convertArgs(args []interface{}) (formatters []interface{}) {
|
||||||
|
formatters = make([]interface{}, len(args))
|
||||||
|
for index, arg := range args {
|
||||||
|
formatters[index] = newFormatter(c, arg)
|
||||||
|
}
|
||||||
|
return formatters
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewDefaultConfig returns a ConfigState with the following default settings.
|
||||||
|
//
|
||||||
|
// Indent: " "
|
||||||
|
// MaxDepth: 0
|
||||||
|
// DisableMethods: false
|
||||||
|
// DisablePointerMethods: false
|
||||||
|
// ContinueOnMethod: false
|
||||||
|
// SortKeys: false
|
||||||
|
func NewDefaultConfig() *ConfigState {
|
||||||
|
return &ConfigState{Indent: " "}
|
||||||
|
}
|
211
vendor/github.com/davecgh/go-spew/spew/doc.go
generated
vendored
Normal file
211
vendor/github.com/davecgh/go-spew/spew/doc.go
generated
vendored
Normal file
|
@ -0,0 +1,211 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2013-2016 Dave Collins <dave@davec.name>
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
* copyright notice and this permission notice appear in all copies.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
Package spew implements a deep pretty printer for Go data structures to aid in
|
||||||
|
debugging.
|
||||||
|
|
||||||
|
A quick overview of the additional features spew provides over the built-in
|
||||||
|
printing facilities for Go data types are as follows:
|
||||||
|
|
||||||
|
* Pointers are dereferenced and followed
|
||||||
|
* Circular data structures are detected and handled properly
|
||||||
|
* Custom Stringer/error interfaces are optionally invoked, including
|
||||||
|
on unexported types
|
||||||
|
* Custom types which only implement the Stringer/error interfaces via
|
||||||
|
a pointer receiver are optionally invoked when passing non-pointer
|
||||||
|
variables
|
||||||
|
* Byte arrays and slices are dumped like the hexdump -C command which
|
||||||
|
includes offsets, byte values in hex, and ASCII output (only when using
|
||||||
|
Dump style)
|
||||||
|
|
||||||
|
There are two different approaches spew allows for dumping Go data structures:
|
||||||
|
|
||||||
|
* Dump style which prints with newlines, customizable indentation,
|
||||||
|
and additional debug information such as types and all pointer addresses
|
||||||
|
used to indirect to the final value
|
||||||
|
* A custom Formatter interface that integrates cleanly with the standard fmt
|
||||||
|
package and replaces %v, %+v, %#v, and %#+v to provide inline printing
|
||||||
|
similar to the default %v while providing the additional functionality
|
||||||
|
outlined above and passing unsupported format verbs such as %x and %q
|
||||||
|
along to fmt
|
||||||
|
|
||||||
|
Quick Start
|
||||||
|
|
||||||
|
This section demonstrates how to quickly get started with spew. See the
|
||||||
|
sections below for further details on formatting and configuration options.
|
||||||
|
|
||||||
|
To dump a variable with full newlines, indentation, type, and pointer
|
||||||
|
information use Dump, Fdump, or Sdump:
|
||||||
|
spew.Dump(myVar1, myVar2, ...)
|
||||||
|
spew.Fdump(someWriter, myVar1, myVar2, ...)
|
||||||
|
str := spew.Sdump(myVar1, myVar2, ...)
|
||||||
|
|
||||||
|
Alternatively, if you would prefer to use format strings with a compacted inline
|
||||||
|
printing style, use the convenience wrappers Printf, Fprintf, etc with
|
||||||
|
%v (most compact), %+v (adds pointer addresses), %#v (adds types), or
|
||||||
|
%#+v (adds types and pointer addresses):
|
||||||
|
spew.Printf("myVar1: %v -- myVar2: %+v", myVar1, myVar2)
|
||||||
|
spew.Printf("myVar3: %#v -- myVar4: %#+v", myVar3, myVar4)
|
||||||
|
spew.Fprintf(someWriter, "myVar1: %v -- myVar2: %+v", myVar1, myVar2)
|
||||||
|
spew.Fprintf(someWriter, "myVar3: %#v -- myVar4: %#+v", myVar3, myVar4)
|
||||||
|
|
||||||
|
Configuration Options
|
||||||
|
|
||||||
|
Configuration of spew is handled by fields in the ConfigState type. For
|
||||||
|
convenience, all of the top-level functions use a global state available
|
||||||
|
via the spew.Config global.
|
||||||
|
|
||||||
|
It is also possible to create a ConfigState instance that provides methods
|
||||||
|
equivalent to the top-level functions. This allows concurrent configuration
|
||||||
|
options. See the ConfigState documentation for more details.
|
||||||
|
|
||||||
|
The following configuration options are available:
|
||||||
|
* Indent
|
||||||
|
String to use for each indentation level for Dump functions.
|
||||||
|
It is a single space by default. A popular alternative is "\t".
|
||||||
|
|
||||||
|
* MaxDepth
|
||||||
|
Maximum number of levels to descend into nested data structures.
|
||||||
|
There is no limit by default.
|
||||||
|
|
||||||
|
* DisableMethods
|
||||||
|
Disables invocation of error and Stringer interface methods.
|
||||||
|
Method invocation is enabled by default.
|
||||||
|
|
||||||
|
* DisablePointerMethods
|
||||||
|
Disables invocation of error and Stringer interface methods on types
|
||||||
|
which only accept pointer receivers from non-pointer variables.
|
||||||
|
Pointer method invocation is enabled by default.
|
||||||
|
|
||||||
|
* DisablePointerAddresses
|
||||||
|
DisablePointerAddresses specifies whether to disable the printing of
|
||||||
|
pointer addresses. This is useful when diffing data structures in tests.
|
||||||
|
|
||||||
|
* DisableCapacities
|
||||||
|
DisableCapacities specifies whether to disable the printing of
|
||||||
|
capacities for arrays, slices, maps and channels. This is useful when
|
||||||
|
diffing data structures in tests.
|
||||||
|
|
||||||
|
* ContinueOnMethod
|
||||||
|
Enables recursion into types after invoking error and Stringer interface
|
||||||
|
methods. Recursion after method invocation is disabled by default.
|
||||||
|
|
||||||
|
* SortKeys
|
||||||
|
Specifies map keys should be sorted before being printed. Use
|
||||||
|
this to have a more deterministic, diffable output. Note that
|
||||||
|
only native types (bool, int, uint, floats, uintptr and string)
|
||||||
|
and types which implement error or Stringer interfaces are
|
||||||
|
supported with other types sorted according to the
|
||||||
|
reflect.Value.String() output which guarantees display
|
||||||
|
stability. Natural map order is used by default.
|
||||||
|
|
||||||
|
* SpewKeys
|
||||||
|
Specifies that, as a last resort attempt, map keys should be
|
||||||
|
spewed to strings and sorted by those strings. This is only
|
||||||
|
considered if SortKeys is true.
|
||||||
|
|
||||||
|
Dump Usage
|
||||||
|
|
||||||
|
Simply call spew.Dump with a list of variables you want to dump:
|
||||||
|
|
||||||
|
spew.Dump(myVar1, myVar2, ...)
|
||||||
|
|
||||||
|
You may also call spew.Fdump if you would prefer to output to an arbitrary
|
||||||
|
io.Writer. For example, to dump to standard error:
|
||||||
|
|
||||||
|
spew.Fdump(os.Stderr, myVar1, myVar2, ...)
|
||||||
|
|
||||||
|
A third option is to call spew.Sdump to get the formatted output as a string:
|
||||||
|
|
||||||
|
str := spew.Sdump(myVar1, myVar2, ...)
|
||||||
|
|
||||||
|
Sample Dump Output
|
||||||
|
|
||||||
|
See the Dump example for details on the setup of the types and variables being
|
||||||
|
shown here.
|
||||||
|
|
||||||
|
(main.Foo) {
|
||||||
|
unexportedField: (*main.Bar)(0xf84002e210)({
|
||||||
|
flag: (main.Flag) flagTwo,
|
||||||
|
data: (uintptr) <nil>
|
||||||
|
}),
|
||||||
|
ExportedField: (map[interface {}]interface {}) (len=1) {
|
||||||
|
(string) (len=3) "one": (bool) true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Byte (and uint8) arrays and slices are displayed uniquely like the hexdump -C
|
||||||
|
command as shown.
|
||||||
|
([]uint8) (len=32 cap=32) {
|
||||||
|
00000000 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 |............... |
|
||||||
|
00000010 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 |!"#$%&'()*+,-./0|
|
||||||
|
00000020 31 32 |12|
|
||||||
|
}
|
||||||
|
|
||||||
|
Custom Formatter
|
||||||
|
|
||||||
|
Spew provides a custom formatter that implements the fmt.Formatter interface
|
||||||
|
so that it integrates cleanly with standard fmt package printing functions. The
|
||||||
|
formatter is useful for inline printing of smaller data types similar to the
|
||||||
|
standard %v format specifier.
|
||||||
|
|
||||||
|
The custom formatter only responds to the %v (most compact), %+v (adds pointer
|
||||||
|
addresses), %#v (adds types), or %#+v (adds types and pointer addresses) verb
|
||||||
|
combinations. Any other verbs such as %x and %q will be sent to the the
|
||||||
|
standard fmt package for formatting. In addition, the custom formatter ignores
|
||||||
|
the width and precision arguments (however they will still work on the format
|
||||||
|
specifiers not handled by the custom formatter).
|
||||||
|
|
||||||
|
Custom Formatter Usage
|
||||||
|
|
||||||
|
The simplest way to make use of the spew custom formatter is to call one of the
|
||||||
|
convenience functions such as spew.Printf, spew.Println, or spew.Printf. The
|
||||||
|
functions have syntax you are most likely already familiar with:
|
||||||
|
|
||||||
|
spew.Printf("myVar1: %v -- myVar2: %+v", myVar1, myVar2)
|
||||||
|
spew.Printf("myVar3: %#v -- myVar4: %#+v", myVar3, myVar4)
|
||||||
|
spew.Println(myVar, myVar2)
|
||||||
|
spew.Fprintf(os.Stderr, "myVar1: %v -- myVar2: %+v", myVar1, myVar2)
|
||||||
|
spew.Fprintf(os.Stderr, "myVar3: %#v -- myVar4: %#+v", myVar3, myVar4)
|
||||||
|
|
||||||
|
See the Index for the full list convenience functions.
|
||||||
|
|
||||||
|
Sample Formatter Output
|
||||||
|
|
||||||
|
Double pointer to a uint8:
|
||||||
|
%v: <**>5
|
||||||
|
%+v: <**>(0xf8400420d0->0xf8400420c8)5
|
||||||
|
%#v: (**uint8)5
|
||||||
|
%#+v: (**uint8)(0xf8400420d0->0xf8400420c8)5
|
||||||
|
|
||||||
|
Pointer to circular struct with a uint8 field and a pointer to itself:
|
||||||
|
%v: <*>{1 <*><shown>}
|
||||||
|
%+v: <*>(0xf84003e260){ui8:1 c:<*>(0xf84003e260)<shown>}
|
||||||
|
%#v: (*main.circular){ui8:(uint8)1 c:(*main.circular)<shown>}
|
||||||
|
%#+v: (*main.circular)(0xf84003e260){ui8:(uint8)1 c:(*main.circular)(0xf84003e260)<shown>}
|
||||||
|
|
||||||
|
See the Printf example for details on the setup of variables being shown
|
||||||
|
here.
|
||||||
|
|
||||||
|
Errors
|
||||||
|
|
||||||
|
Since it is possible for custom Stringer/error interfaces to panic, spew
|
||||||
|
detects them and handles them internally by printing the panic information
|
||||||
|
inline with the output. Since spew is intended to provide deep pretty printing
|
||||||
|
capabilities on structures, it intentionally does not return any errors.
|
||||||
|
*/
|
||||||
|
package spew
|
509
vendor/github.com/davecgh/go-spew/spew/dump.go
generated
vendored
Normal file
509
vendor/github.com/davecgh/go-spew/spew/dump.go
generated
vendored
Normal file
|
@ -0,0 +1,509 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2013-2016 Dave Collins <dave@davec.name>
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
* copyright notice and this permission notice appear in all copies.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package spew
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/hex"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
"reflect"
|
||||||
|
"regexp"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// uint8Type is a reflect.Type representing a uint8. It is used to
|
||||||
|
// convert cgo types to uint8 slices for hexdumping.
|
||||||
|
uint8Type = reflect.TypeOf(uint8(0))
|
||||||
|
|
||||||
|
// cCharRE is a regular expression that matches a cgo char.
|
||||||
|
// It is used to detect character arrays to hexdump them.
|
||||||
|
cCharRE = regexp.MustCompile(`^.*\._Ctype_char$`)
|
||||||
|
|
||||||
|
// cUnsignedCharRE is a regular expression that matches a cgo unsigned
|
||||||
|
// char. It is used to detect unsigned character arrays to hexdump
|
||||||
|
// them.
|
||||||
|
cUnsignedCharRE = regexp.MustCompile(`^.*\._Ctype_unsignedchar$`)
|
||||||
|
|
||||||
|
// cUint8tCharRE is a regular expression that matches a cgo uint8_t.
|
||||||
|
// It is used to detect uint8_t arrays to hexdump them.
|
||||||
|
cUint8tCharRE = regexp.MustCompile(`^.*\._Ctype_uint8_t$`)
|
||||||
|
)
|
||||||
|
|
||||||
|
// dumpState contains information about the state of a dump operation.
|
||||||
|
type dumpState struct {
|
||||||
|
w io.Writer
|
||||||
|
depth int
|
||||||
|
pointers map[uintptr]int
|
||||||
|
ignoreNextType bool
|
||||||
|
ignoreNextIndent bool
|
||||||
|
cs *ConfigState
|
||||||
|
}
|
||||||
|
|
||||||
|
// indent performs indentation according to the depth level and cs.Indent
|
||||||
|
// option.
|
||||||
|
func (d *dumpState) indent() {
|
||||||
|
if d.ignoreNextIndent {
|
||||||
|
d.ignoreNextIndent = false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
d.w.Write(bytes.Repeat([]byte(d.cs.Indent), d.depth))
|
||||||
|
}
|
||||||
|
|
||||||
|
// unpackValue returns values inside of non-nil interfaces when possible.
|
||||||
|
// This is useful for data types like structs, arrays, slices, and maps which
|
||||||
|
// can contain varying types packed inside an interface.
|
||||||
|
func (d *dumpState) unpackValue(v reflect.Value) reflect.Value {
|
||||||
|
if v.Kind() == reflect.Interface && !v.IsNil() {
|
||||||
|
v = v.Elem()
|
||||||
|
}
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
|
// dumpPtr handles formatting of pointers by indirecting them as necessary.
|
||||||
|
func (d *dumpState) dumpPtr(v reflect.Value) {
|
||||||
|
// Remove pointers at or below the current depth from map used to detect
|
||||||
|
// circular refs.
|
||||||
|
for k, depth := range d.pointers {
|
||||||
|
if depth >= d.depth {
|
||||||
|
delete(d.pointers, k)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Keep list of all dereferenced pointers to show later.
|
||||||
|
pointerChain := make([]uintptr, 0)
|
||||||
|
|
||||||
|
// Figure out how many levels of indirection there are by dereferencing
|
||||||
|
// pointers and unpacking interfaces down the chain while detecting circular
|
||||||
|
// references.
|
||||||
|
nilFound := false
|
||||||
|
cycleFound := false
|
||||||
|
indirects := 0
|
||||||
|
ve := v
|
||||||
|
for ve.Kind() == reflect.Ptr {
|
||||||
|
if ve.IsNil() {
|
||||||
|
nilFound = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
indirects++
|
||||||
|
addr := ve.Pointer()
|
||||||
|
pointerChain = append(pointerChain, addr)
|
||||||
|
if pd, ok := d.pointers[addr]; ok && pd < d.depth {
|
||||||
|
cycleFound = true
|
||||||
|
indirects--
|
||||||
|
break
|
||||||
|
}
|
||||||
|
d.pointers[addr] = d.depth
|
||||||
|
|
||||||
|
ve = ve.Elem()
|
||||||
|
if ve.Kind() == reflect.Interface {
|
||||||
|
if ve.IsNil() {
|
||||||
|
nilFound = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
ve = ve.Elem()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Display type information.
|
||||||
|
d.w.Write(openParenBytes)
|
||||||
|
d.w.Write(bytes.Repeat(asteriskBytes, indirects))
|
||||||
|
d.w.Write([]byte(ve.Type().String()))
|
||||||
|
d.w.Write(closeParenBytes)
|
||||||
|
|
||||||
|
// Display pointer information.
|
||||||
|
if !d.cs.DisablePointerAddresses && len(pointerChain) > 0 {
|
||||||
|
d.w.Write(openParenBytes)
|
||||||
|
for i, addr := range pointerChain {
|
||||||
|
if i > 0 {
|
||||||
|
d.w.Write(pointerChainBytes)
|
||||||
|
}
|
||||||
|
printHexPtr(d.w, addr)
|
||||||
|
}
|
||||||
|
d.w.Write(closeParenBytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Display dereferenced value.
|
||||||
|
d.w.Write(openParenBytes)
|
||||||
|
switch {
|
||||||
|
case nilFound:
|
||||||
|
d.w.Write(nilAngleBytes)
|
||||||
|
|
||||||
|
case cycleFound:
|
||||||
|
d.w.Write(circularBytes)
|
||||||
|
|
||||||
|
default:
|
||||||
|
d.ignoreNextType = true
|
||||||
|
d.dump(ve)
|
||||||
|
}
|
||||||
|
d.w.Write(closeParenBytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
// dumpSlice handles formatting of arrays and slices. Byte (uint8 under
|
||||||
|
// reflection) arrays and slices are dumped in hexdump -C fashion.
|
||||||
|
func (d *dumpState) dumpSlice(v reflect.Value) {
|
||||||
|
// Determine whether this type should be hex dumped or not. Also,
|
||||||
|
// for types which should be hexdumped, try to use the underlying data
|
||||||
|
// first, then fall back to trying to convert them to a uint8 slice.
|
||||||
|
var buf []uint8
|
||||||
|
doConvert := false
|
||||||
|
doHexDump := false
|
||||||
|
numEntries := v.Len()
|
||||||
|
if numEntries > 0 {
|
||||||
|
vt := v.Index(0).Type()
|
||||||
|
vts := vt.String()
|
||||||
|
switch {
|
||||||
|
// C types that need to be converted.
|
||||||
|
case cCharRE.MatchString(vts):
|
||||||
|
fallthrough
|
||||||
|
case cUnsignedCharRE.MatchString(vts):
|
||||||
|
fallthrough
|
||||||
|
case cUint8tCharRE.MatchString(vts):
|
||||||
|
doConvert = true
|
||||||
|
|
||||||
|
// Try to use existing uint8 slices and fall back to converting
|
||||||
|
// and copying if that fails.
|
||||||
|
case vt.Kind() == reflect.Uint8:
|
||||||
|
// We need an addressable interface to convert the type
|
||||||
|
// to a byte slice. However, the reflect package won't
|
||||||
|
// give us an interface on certain things like
|
||||||
|
// unexported struct fields in order to enforce
|
||||||
|
// visibility rules. We use unsafe, when available, to
|
||||||
|
// bypass these restrictions since this package does not
|
||||||
|
// mutate the values.
|
||||||
|
vs := v
|
||||||
|
if !vs.CanInterface() || !vs.CanAddr() {
|
||||||
|
vs = unsafeReflectValue(vs)
|
||||||
|
}
|
||||||
|
if !UnsafeDisabled {
|
||||||
|
vs = vs.Slice(0, numEntries)
|
||||||
|
|
||||||
|
// Use the existing uint8 slice if it can be
|
||||||
|
// type asserted.
|
||||||
|
iface := vs.Interface()
|
||||||
|
if slice, ok := iface.([]uint8); ok {
|
||||||
|
buf = slice
|
||||||
|
doHexDump = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// The underlying data needs to be converted if it can't
|
||||||
|
// be type asserted to a uint8 slice.
|
||||||
|
doConvert = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy and convert the underlying type if needed.
|
||||||
|
if doConvert && vt.ConvertibleTo(uint8Type) {
|
||||||
|
// Convert and copy each element into a uint8 byte
|
||||||
|
// slice.
|
||||||
|
buf = make([]uint8, numEntries)
|
||||||
|
for i := 0; i < numEntries; i++ {
|
||||||
|
vv := v.Index(i)
|
||||||
|
buf[i] = uint8(vv.Convert(uint8Type).Uint())
|
||||||
|
}
|
||||||
|
doHexDump = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hexdump the entire slice as needed.
|
||||||
|
if doHexDump {
|
||||||
|
indent := strings.Repeat(d.cs.Indent, d.depth)
|
||||||
|
str := indent + hex.Dump(buf)
|
||||||
|
str = strings.Replace(str, "\n", "\n"+indent, -1)
|
||||||
|
str = strings.TrimRight(str, d.cs.Indent)
|
||||||
|
d.w.Write([]byte(str))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Recursively call dump for each item.
|
||||||
|
for i := 0; i < numEntries; i++ {
|
||||||
|
d.dump(d.unpackValue(v.Index(i)))
|
||||||
|
if i < (numEntries - 1) {
|
||||||
|
d.w.Write(commaNewlineBytes)
|
||||||
|
} else {
|
||||||
|
d.w.Write(newlineBytes)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// dump is the main workhorse for dumping a value. It uses the passed reflect
|
||||||
|
// value to figure out what kind of object we are dealing with and formats it
|
||||||
|
// appropriately. It is a recursive function, however circular data structures
|
||||||
|
// are detected and handled properly.
|
||||||
|
func (d *dumpState) dump(v reflect.Value) {
|
||||||
|
// Handle invalid reflect values immediately.
|
||||||
|
kind := v.Kind()
|
||||||
|
if kind == reflect.Invalid {
|
||||||
|
d.w.Write(invalidAngleBytes)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle pointers specially.
|
||||||
|
if kind == reflect.Ptr {
|
||||||
|
d.indent()
|
||||||
|
d.dumpPtr(v)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Print type information unless already handled elsewhere.
|
||||||
|
if !d.ignoreNextType {
|
||||||
|
d.indent()
|
||||||
|
d.w.Write(openParenBytes)
|
||||||
|
d.w.Write([]byte(v.Type().String()))
|
||||||
|
d.w.Write(closeParenBytes)
|
||||||
|
d.w.Write(spaceBytes)
|
||||||
|
}
|
||||||
|
d.ignoreNextType = false
|
||||||
|
|
||||||
|
// Display length and capacity if the built-in len and cap functions
|
||||||
|
// work with the value's kind and the len/cap itself is non-zero.
|
||||||
|
valueLen, valueCap := 0, 0
|
||||||
|
switch v.Kind() {
|
||||||
|
case reflect.Array, reflect.Slice, reflect.Chan:
|
||||||
|
valueLen, valueCap = v.Len(), v.Cap()
|
||||||
|
case reflect.Map, reflect.String:
|
||||||
|
valueLen = v.Len()
|
||||||
|
}
|
||||||
|
if valueLen != 0 || !d.cs.DisableCapacities && valueCap != 0 {
|
||||||
|
d.w.Write(openParenBytes)
|
||||||
|
if valueLen != 0 {
|
||||||
|
d.w.Write(lenEqualsBytes)
|
||||||
|
printInt(d.w, int64(valueLen), 10)
|
||||||
|
}
|
||||||
|
if !d.cs.DisableCapacities && valueCap != 0 {
|
||||||
|
if valueLen != 0 {
|
||||||
|
d.w.Write(spaceBytes)
|
||||||
|
}
|
||||||
|
d.w.Write(capEqualsBytes)
|
||||||
|
printInt(d.w, int64(valueCap), 10)
|
||||||
|
}
|
||||||
|
d.w.Write(closeParenBytes)
|
||||||
|
d.w.Write(spaceBytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Call Stringer/error interfaces if they exist and the handle methods flag
|
||||||
|
// is enabled
|
||||||
|
if !d.cs.DisableMethods {
|
||||||
|
if (kind != reflect.Invalid) && (kind != reflect.Interface) {
|
||||||
|
if handled := handleMethods(d.cs, d.w, v); handled {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch kind {
|
||||||
|
case reflect.Invalid:
|
||||||
|
// Do nothing. We should never get here since invalid has already
|
||||||
|
// been handled above.
|
||||||
|
|
||||||
|
case reflect.Bool:
|
||||||
|
printBool(d.w, v.Bool())
|
||||||
|
|
||||||
|
case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int:
|
||||||
|
printInt(d.w, v.Int(), 10)
|
||||||
|
|
||||||
|
case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint:
|
||||||
|
printUint(d.w, v.Uint(), 10)
|
||||||
|
|
||||||
|
case reflect.Float32:
|
||||||
|
printFloat(d.w, v.Float(), 32)
|
||||||
|
|
||||||
|
case reflect.Float64:
|
||||||
|
printFloat(d.w, v.Float(), 64)
|
||||||
|
|
||||||
|
case reflect.Complex64:
|
||||||
|
printComplex(d.w, v.Complex(), 32)
|
||||||
|
|
||||||
|
case reflect.Complex128:
|
||||||
|
printComplex(d.w, v.Complex(), 64)
|
||||||
|
|
||||||
|
case reflect.Slice:
|
||||||
|
if v.IsNil() {
|
||||||
|
d.w.Write(nilAngleBytes)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
fallthrough
|
||||||
|
|
||||||
|
case reflect.Array:
|
||||||
|
d.w.Write(openBraceNewlineBytes)
|
||||||
|
d.depth++
|
||||||
|
if (d.cs.MaxDepth != 0) && (d.depth > d.cs.MaxDepth) {
|
||||||
|
d.indent()
|
||||||
|
d.w.Write(maxNewlineBytes)
|
||||||
|
} else {
|
||||||
|
d.dumpSlice(v)
|
||||||
|
}
|
||||||
|
d.depth--
|
||||||
|
d.indent()
|
||||||
|
d.w.Write(closeBraceBytes)
|
||||||
|
|
||||||
|
case reflect.String:
|
||||||
|
d.w.Write([]byte(strconv.Quote(v.String())))
|
||||||
|
|
||||||
|
case reflect.Interface:
|
||||||
|
// The only time we should get here is for nil interfaces due to
|
||||||
|
// unpackValue calls.
|
||||||
|
if v.IsNil() {
|
||||||
|
d.w.Write(nilAngleBytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
case reflect.Ptr:
|
||||||
|
// Do nothing. We should never get here since pointers have already
|
||||||
|
// been handled above.
|
||||||
|
|
||||||
|
case reflect.Map:
|
||||||
|
// nil maps should be indicated as different than empty maps
|
||||||
|
if v.IsNil() {
|
||||||
|
d.w.Write(nilAngleBytes)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
d.w.Write(openBraceNewlineBytes)
|
||||||
|
d.depth++
|
||||||
|
if (d.cs.MaxDepth != 0) && (d.depth > d.cs.MaxDepth) {
|
||||||
|
d.indent()
|
||||||
|
d.w.Write(maxNewlineBytes)
|
||||||
|
} else {
|
||||||
|
numEntries := v.Len()
|
||||||
|
keys := v.MapKeys()
|
||||||
|
if d.cs.SortKeys {
|
||||||
|
sortValues(keys, d.cs)
|
||||||
|
}
|
||||||
|
for i, key := range keys {
|
||||||
|
d.dump(d.unpackValue(key))
|
||||||
|
d.w.Write(colonSpaceBytes)
|
||||||
|
d.ignoreNextIndent = true
|
||||||
|
d.dump(d.unpackValue(v.MapIndex(key)))
|
||||||
|
if i < (numEntries - 1) {
|
||||||
|
d.w.Write(commaNewlineBytes)
|
||||||
|
} else {
|
||||||
|
d.w.Write(newlineBytes)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
d.depth--
|
||||||
|
d.indent()
|
||||||
|
d.w.Write(closeBraceBytes)
|
||||||
|
|
||||||
|
case reflect.Struct:
|
||||||
|
d.w.Write(openBraceNewlineBytes)
|
||||||
|
d.depth++
|
||||||
|
if (d.cs.MaxDepth != 0) && (d.depth > d.cs.MaxDepth) {
|
||||||
|
d.indent()
|
||||||
|
d.w.Write(maxNewlineBytes)
|
||||||
|
} else {
|
||||||
|
vt := v.Type()
|
||||||
|
numFields := v.NumField()
|
||||||
|
for i := 0; i < numFields; i++ {
|
||||||
|
d.indent()
|
||||||
|
vtf := vt.Field(i)
|
||||||
|
d.w.Write([]byte(vtf.Name))
|
||||||
|
d.w.Write(colonSpaceBytes)
|
||||||
|
d.ignoreNextIndent = true
|
||||||
|
d.dump(d.unpackValue(v.Field(i)))
|
||||||
|
if i < (numFields - 1) {
|
||||||
|
d.w.Write(commaNewlineBytes)
|
||||||
|
} else {
|
||||||
|
d.w.Write(newlineBytes)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
d.depth--
|
||||||
|
d.indent()
|
||||||
|
d.w.Write(closeBraceBytes)
|
||||||
|
|
||||||
|
case reflect.Uintptr:
|
||||||
|
printHexPtr(d.w, uintptr(v.Uint()))
|
||||||
|
|
||||||
|
case reflect.UnsafePointer, reflect.Chan, reflect.Func:
|
||||||
|
printHexPtr(d.w, v.Pointer())
|
||||||
|
|
||||||
|
// There were not any other types at the time this code was written, but
|
||||||
|
// fall back to letting the default fmt package handle it in case any new
|
||||||
|
// types are added.
|
||||||
|
default:
|
||||||
|
if v.CanInterface() {
|
||||||
|
fmt.Fprintf(d.w, "%v", v.Interface())
|
||||||
|
} else {
|
||||||
|
fmt.Fprintf(d.w, "%v", v.String())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// fdump is a helper function to consolidate the logic from the various public
|
||||||
|
// methods which take varying writers and config states.
|
||||||
|
func fdump(cs *ConfigState, w io.Writer, a ...interface{}) {
|
||||||
|
for _, arg := range a {
|
||||||
|
if arg == nil {
|
||||||
|
w.Write(interfaceBytes)
|
||||||
|
w.Write(spaceBytes)
|
||||||
|
w.Write(nilAngleBytes)
|
||||||
|
w.Write(newlineBytes)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
d := dumpState{w: w, cs: cs}
|
||||||
|
d.pointers = make(map[uintptr]int)
|
||||||
|
d.dump(reflect.ValueOf(arg))
|
||||||
|
d.w.Write(newlineBytes)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fdump formats and displays the passed arguments to io.Writer w. It formats
|
||||||
|
// exactly the same as Dump.
|
||||||
|
func Fdump(w io.Writer, a ...interface{}) {
|
||||||
|
fdump(&Config, w, a...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sdump returns a string with the passed arguments formatted exactly the same
|
||||||
|
// as Dump.
|
||||||
|
func Sdump(a ...interface{}) string {
|
||||||
|
var buf bytes.Buffer
|
||||||
|
fdump(&Config, &buf, a...)
|
||||||
|
return buf.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Dump displays the passed parameters to standard out with newlines, customizable
|
||||||
|
indentation, and additional debug information such as complete types and all
|
||||||
|
pointer addresses used to indirect to the final value. It provides the
|
||||||
|
following features over the built-in printing facilities provided by the fmt
|
||||||
|
package:
|
||||||
|
|
||||||
|
* Pointers are dereferenced and followed
|
||||||
|
* Circular data structures are detected and handled properly
|
||||||
|
* Custom Stringer/error interfaces are optionally invoked, including
|
||||||
|
on unexported types
|
||||||
|
* Custom types which only implement the Stringer/error interfaces via
|
||||||
|
a pointer receiver are optionally invoked when passing non-pointer
|
||||||
|
variables
|
||||||
|
* Byte arrays and slices are dumped like the hexdump -C command which
|
||||||
|
includes offsets, byte values in hex, and ASCII output
|
||||||
|
|
||||||
|
The configuration options are controlled by an exported package global,
|
||||||
|
spew.Config. See ConfigState for options documentation.
|
||||||
|
|
||||||
|
See Fdump if you would prefer dumping to an arbitrary io.Writer or Sdump to
|
||||||
|
get the formatted result as a string.
|
||||||
|
*/
|
||||||
|
func Dump(a ...interface{}) {
|
||||||
|
fdump(&Config, os.Stdout, a...)
|
||||||
|
}
|
419
vendor/github.com/davecgh/go-spew/spew/format.go
generated
vendored
Normal file
419
vendor/github.com/davecgh/go-spew/spew/format.go
generated
vendored
Normal file
|
@ -0,0 +1,419 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2013-2016 Dave Collins <dave@davec.name>
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
* copyright notice and this permission notice appear in all copies.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package spew
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"reflect"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// supportedFlags is a list of all the character flags supported by fmt package.
|
||||||
|
const supportedFlags = "0-+# "
|
||||||
|
|
||||||
|
// formatState implements the fmt.Formatter interface and contains information
|
||||||
|
// about the state of a formatting operation. The NewFormatter function can
|
||||||
|
// be used to get a new Formatter which can be used directly as arguments
|
||||||
|
// in standard fmt package printing calls.
|
||||||
|
type formatState struct {
|
||||||
|
value interface{}
|
||||||
|
fs fmt.State
|
||||||
|
depth int
|
||||||
|
pointers map[uintptr]int
|
||||||
|
ignoreNextType bool
|
||||||
|
cs *ConfigState
|
||||||
|
}
|
||||||
|
|
||||||
|
// buildDefaultFormat recreates the original format string without precision
|
||||||
|
// and width information to pass in to fmt.Sprintf in the case of an
|
||||||
|
// unrecognized type. Unless new types are added to the language, this
|
||||||
|
// function won't ever be called.
|
||||||
|
func (f *formatState) buildDefaultFormat() (format string) {
|
||||||
|
buf := bytes.NewBuffer(percentBytes)
|
||||||
|
|
||||||
|
for _, flag := range supportedFlags {
|
||||||
|
if f.fs.Flag(int(flag)) {
|
||||||
|
buf.WriteRune(flag)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
buf.WriteRune('v')
|
||||||
|
|
||||||
|
format = buf.String()
|
||||||
|
return format
|
||||||
|
}
|
||||||
|
|
||||||
|
// constructOrigFormat recreates the original format string including precision
|
||||||
|
// and width information to pass along to the standard fmt package. This allows
|
||||||
|
// automatic deferral of all format strings this package doesn't support.
|
||||||
|
func (f *formatState) constructOrigFormat(verb rune) (format string) {
|
||||||
|
buf := bytes.NewBuffer(percentBytes)
|
||||||
|
|
||||||
|
for _, flag := range supportedFlags {
|
||||||
|
if f.fs.Flag(int(flag)) {
|
||||||
|
buf.WriteRune(flag)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if width, ok := f.fs.Width(); ok {
|
||||||
|
buf.WriteString(strconv.Itoa(width))
|
||||||
|
}
|
||||||
|
|
||||||
|
if precision, ok := f.fs.Precision(); ok {
|
||||||
|
buf.Write(precisionBytes)
|
||||||
|
buf.WriteString(strconv.Itoa(precision))
|
||||||
|
}
|
||||||
|
|
||||||
|
buf.WriteRune(verb)
|
||||||
|
|
||||||
|
format = buf.String()
|
||||||
|
return format
|
||||||
|
}
|
||||||
|
|
||||||
|
// unpackValue returns values inside of non-nil interfaces when possible and
|
||||||
|
// ensures that types for values which have been unpacked from an interface
|
||||||
|
// are displayed when the show types flag is also set.
|
||||||
|
// This is useful for data types like structs, arrays, slices, and maps which
|
||||||
|
// can contain varying types packed inside an interface.
|
||||||
|
func (f *formatState) unpackValue(v reflect.Value) reflect.Value {
|
||||||
|
if v.Kind() == reflect.Interface {
|
||||||
|
f.ignoreNextType = false
|
||||||
|
if !v.IsNil() {
|
||||||
|
v = v.Elem()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
|
// formatPtr handles formatting of pointers by indirecting them as necessary.
|
||||||
|
func (f *formatState) formatPtr(v reflect.Value) {
|
||||||
|
// Display nil if top level pointer is nil.
|
||||||
|
showTypes := f.fs.Flag('#')
|
||||||
|
if v.IsNil() && (!showTypes || f.ignoreNextType) {
|
||||||
|
f.fs.Write(nilAngleBytes)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove pointers at or below the current depth from map used to detect
|
||||||
|
// circular refs.
|
||||||
|
for k, depth := range f.pointers {
|
||||||
|
if depth >= f.depth {
|
||||||
|
delete(f.pointers, k)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Keep list of all dereferenced pointers to possibly show later.
|
||||||
|
pointerChain := make([]uintptr, 0)
|
||||||
|
|
||||||
|
// Figure out how many levels of indirection there are by derferencing
|
||||||
|
// pointers and unpacking interfaces down the chain while detecting circular
|
||||||
|
// references.
|
||||||
|
nilFound := false
|
||||||
|
cycleFound := false
|
||||||
|
indirects := 0
|
||||||
|
ve := v
|
||||||
|
for ve.Kind() == reflect.Ptr {
|
||||||
|
if ve.IsNil() {
|
||||||
|
nilFound = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
indirects++
|
||||||
|
addr := ve.Pointer()
|
||||||
|
pointerChain = append(pointerChain, addr)
|
||||||
|
if pd, ok := f.pointers[addr]; ok && pd < f.depth {
|
||||||
|
cycleFound = true
|
||||||
|
indirects--
|
||||||
|
break
|
||||||
|
}
|
||||||
|
f.pointers[addr] = f.depth
|
||||||
|
|
||||||
|
ve = ve.Elem()
|
||||||
|
if ve.Kind() == reflect.Interface {
|
||||||
|
if ve.IsNil() {
|
||||||
|
nilFound = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
ve = ve.Elem()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Display type or indirection level depending on flags.
|
||||||
|
if showTypes && !f.ignoreNextType {
|
||||||
|
f.fs.Write(openParenBytes)
|
||||||
|
f.fs.Write(bytes.Repeat(asteriskBytes, indirects))
|
||||||
|
f.fs.Write([]byte(ve.Type().String()))
|
||||||
|
f.fs.Write(closeParenBytes)
|
||||||
|
} else {
|
||||||
|
if nilFound || cycleFound {
|
||||||
|
indirects += strings.Count(ve.Type().String(), "*")
|
||||||
|
}
|
||||||
|
f.fs.Write(openAngleBytes)
|
||||||
|
f.fs.Write([]byte(strings.Repeat("*", indirects)))
|
||||||
|
f.fs.Write(closeAngleBytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Display pointer information depending on flags.
|
||||||
|
if f.fs.Flag('+') && (len(pointerChain) > 0) {
|
||||||
|
f.fs.Write(openParenBytes)
|
||||||
|
for i, addr := range pointerChain {
|
||||||
|
if i > 0 {
|
||||||
|
f.fs.Write(pointerChainBytes)
|
||||||
|
}
|
||||||
|
printHexPtr(f.fs, addr)
|
||||||
|
}
|
||||||
|
f.fs.Write(closeParenBytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Display dereferenced value.
|
||||||
|
switch {
|
||||||
|
case nilFound:
|
||||||
|
f.fs.Write(nilAngleBytes)
|
||||||
|
|
||||||
|
case cycleFound:
|
||||||
|
f.fs.Write(circularShortBytes)
|
||||||
|
|
||||||
|
default:
|
||||||
|
f.ignoreNextType = true
|
||||||
|
f.format(ve)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// format is the main workhorse for providing the Formatter interface. It
|
||||||
|
// uses the passed reflect value to figure out what kind of object we are
|
||||||
|
// dealing with and formats it appropriately. It is a recursive function,
|
||||||
|
// however circular data structures are detected and handled properly.
|
||||||
|
func (f *formatState) format(v reflect.Value) {
|
||||||
|
// Handle invalid reflect values immediately.
|
||||||
|
kind := v.Kind()
|
||||||
|
if kind == reflect.Invalid {
|
||||||
|
f.fs.Write(invalidAngleBytes)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle pointers specially.
|
||||||
|
if kind == reflect.Ptr {
|
||||||
|
f.formatPtr(v)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Print type information unless already handled elsewhere.
|
||||||
|
if !f.ignoreNextType && f.fs.Flag('#') {
|
||||||
|
f.fs.Write(openParenBytes)
|
||||||
|
f.fs.Write([]byte(v.Type().String()))
|
||||||
|
f.fs.Write(closeParenBytes)
|
||||||
|
}
|
||||||
|
f.ignoreNextType = false
|
||||||
|
|
||||||
|
// Call Stringer/error interfaces if they exist and the handle methods
|
||||||
|
// flag is enabled.
|
||||||
|
if !f.cs.DisableMethods {
|
||||||
|
if (kind != reflect.Invalid) && (kind != reflect.Interface) {
|
||||||
|
if handled := handleMethods(f.cs, f.fs, v); handled {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch kind {
|
||||||
|
case reflect.Invalid:
|
||||||
|
// Do nothing. We should never get here since invalid has already
|
||||||
|
// been handled above.
|
||||||
|
|
||||||
|
case reflect.Bool:
|
||||||
|
printBool(f.fs, v.Bool())
|
||||||
|
|
||||||
|
case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int:
|
||||||
|
printInt(f.fs, v.Int(), 10)
|
||||||
|
|
||||||
|
case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint:
|
||||||
|
printUint(f.fs, v.Uint(), 10)
|
||||||
|
|
||||||
|
case reflect.Float32:
|
||||||
|
printFloat(f.fs, v.Float(), 32)
|
||||||
|
|
||||||
|
case reflect.Float64:
|
||||||
|
printFloat(f.fs, v.Float(), 64)
|
||||||
|
|
||||||
|
case reflect.Complex64:
|
||||||
|
printComplex(f.fs, v.Complex(), 32)
|
||||||
|
|
||||||
|
case reflect.Complex128:
|
||||||
|
printComplex(f.fs, v.Complex(), 64)
|
||||||
|
|
||||||
|
case reflect.Slice:
|
||||||
|
if v.IsNil() {
|
||||||
|
f.fs.Write(nilAngleBytes)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
fallthrough
|
||||||
|
|
||||||
|
case reflect.Array:
|
||||||
|
f.fs.Write(openBracketBytes)
|
||||||
|
f.depth++
|
||||||
|
if (f.cs.MaxDepth != 0) && (f.depth > f.cs.MaxDepth) {
|
||||||
|
f.fs.Write(maxShortBytes)
|
||||||
|
} else {
|
||||||
|
numEntries := v.Len()
|
||||||
|
for i := 0; i < numEntries; i++ {
|
||||||
|
if i > 0 {
|
||||||
|
f.fs.Write(spaceBytes)
|
||||||
|
}
|
||||||
|
f.ignoreNextType = true
|
||||||
|
f.format(f.unpackValue(v.Index(i)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
f.depth--
|
||||||
|
f.fs.Write(closeBracketBytes)
|
||||||
|
|
||||||
|
case reflect.String:
|
||||||
|
f.fs.Write([]byte(v.String()))
|
||||||
|
|
||||||
|
case reflect.Interface:
|
||||||
|
// The only time we should get here is for nil interfaces due to
|
||||||
|
// unpackValue calls.
|
||||||
|
if v.IsNil() {
|
||||||
|
f.fs.Write(nilAngleBytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
case reflect.Ptr:
|
||||||
|
// Do nothing. We should never get here since pointers have already
|
||||||
|
// been handled above.
|
||||||
|
|
||||||
|
case reflect.Map:
|
||||||
|
// nil maps should be indicated as different than empty maps
|
||||||
|
if v.IsNil() {
|
||||||
|
f.fs.Write(nilAngleBytes)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
f.fs.Write(openMapBytes)
|
||||||
|
f.depth++
|
||||||
|
if (f.cs.MaxDepth != 0) && (f.depth > f.cs.MaxDepth) {
|
||||||
|
f.fs.Write(maxShortBytes)
|
||||||
|
} else {
|
||||||
|
keys := v.MapKeys()
|
||||||
|
if f.cs.SortKeys {
|
||||||
|
sortValues(keys, f.cs)
|
||||||
|
}
|
||||||
|
for i, key := range keys {
|
||||||
|
if i > 0 {
|
||||||
|
f.fs.Write(spaceBytes)
|
||||||
|
}
|
||||||
|
f.ignoreNextType = true
|
||||||
|
f.format(f.unpackValue(key))
|
||||||
|
f.fs.Write(colonBytes)
|
||||||
|
f.ignoreNextType = true
|
||||||
|
f.format(f.unpackValue(v.MapIndex(key)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
f.depth--
|
||||||
|
f.fs.Write(closeMapBytes)
|
||||||
|
|
||||||
|
case reflect.Struct:
|
||||||
|
numFields := v.NumField()
|
||||||
|
f.fs.Write(openBraceBytes)
|
||||||
|
f.depth++
|
||||||
|
if (f.cs.MaxDepth != 0) && (f.depth > f.cs.MaxDepth) {
|
||||||
|
f.fs.Write(maxShortBytes)
|
||||||
|
} else {
|
||||||
|
vt := v.Type()
|
||||||
|
for i := 0; i < numFields; i++ {
|
||||||
|
if i > 0 {
|
||||||
|
f.fs.Write(spaceBytes)
|
||||||
|
}
|
||||||
|
vtf := vt.Field(i)
|
||||||
|
if f.fs.Flag('+') || f.fs.Flag('#') {
|
||||||
|
f.fs.Write([]byte(vtf.Name))
|
||||||
|
f.fs.Write(colonBytes)
|
||||||
|
}
|
||||||
|
f.format(f.unpackValue(v.Field(i)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
f.depth--
|
||||||
|
f.fs.Write(closeBraceBytes)
|
||||||
|
|
||||||
|
case reflect.Uintptr:
|
||||||
|
printHexPtr(f.fs, uintptr(v.Uint()))
|
||||||
|
|
||||||
|
case reflect.UnsafePointer, reflect.Chan, reflect.Func:
|
||||||
|
printHexPtr(f.fs, v.Pointer())
|
||||||
|
|
||||||
|
// There were not any other types at the time this code was written, but
|
||||||
|
// fall back to letting the default fmt package handle it if any get added.
|
||||||
|
default:
|
||||||
|
format := f.buildDefaultFormat()
|
||||||
|
if v.CanInterface() {
|
||||||
|
fmt.Fprintf(f.fs, format, v.Interface())
|
||||||
|
} else {
|
||||||
|
fmt.Fprintf(f.fs, format, v.String())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Format satisfies the fmt.Formatter interface. See NewFormatter for usage
|
||||||
|
// details.
|
||||||
|
func (f *formatState) Format(fs fmt.State, verb rune) {
|
||||||
|
f.fs = fs
|
||||||
|
|
||||||
|
// Use standard formatting for verbs that are not v.
|
||||||
|
if verb != 'v' {
|
||||||
|
format := f.constructOrigFormat(verb)
|
||||||
|
fmt.Fprintf(fs, format, f.value)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if f.value == nil {
|
||||||
|
if fs.Flag('#') {
|
||||||
|
fs.Write(interfaceBytes)
|
||||||
|
}
|
||||||
|
fs.Write(nilAngleBytes)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
f.format(reflect.ValueOf(f.value))
|
||||||
|
}
|
||||||
|
|
||||||
|
// newFormatter is a helper function to consolidate the logic from the various
|
||||||
|
// public methods which take varying config states.
|
||||||
|
func newFormatter(cs *ConfigState, v interface{}) fmt.Formatter {
|
||||||
|
fs := &formatState{value: v, cs: cs}
|
||||||
|
fs.pointers = make(map[uintptr]int)
|
||||||
|
return fs
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
NewFormatter returns a custom formatter that satisfies the fmt.Formatter
|
||||||
|
interface. As a result, it integrates cleanly with standard fmt package
|
||||||
|
printing functions. The formatter is useful for inline printing of smaller data
|
||||||
|
types similar to the standard %v format specifier.
|
||||||
|
|
||||||
|
The custom formatter only responds to the %v (most compact), %+v (adds pointer
|
||||||
|
addresses), %#v (adds types), or %#+v (adds types and pointer addresses) verb
|
||||||
|
combinations. Any other verbs such as %x and %q will be sent to the the
|
||||||
|
standard fmt package for formatting. In addition, the custom formatter ignores
|
||||||
|
the width and precision arguments (however they will still work on the format
|
||||||
|
specifiers not handled by the custom formatter).
|
||||||
|
|
||||||
|
Typically this function shouldn't be called directly. It is much easier to make
|
||||||
|
use of the custom formatter by calling one of the convenience functions such as
|
||||||
|
Printf, Println, or Fprintf.
|
||||||
|
*/
|
||||||
|
func NewFormatter(v interface{}) fmt.Formatter {
|
||||||
|
return newFormatter(&Config, v)
|
||||||
|
}
|
148
vendor/github.com/davecgh/go-spew/spew/spew.go
generated
vendored
Normal file
148
vendor/github.com/davecgh/go-spew/spew/spew.go
generated
vendored
Normal file
|
@ -0,0 +1,148 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2013-2016 Dave Collins <dave@davec.name>
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
* copyright notice and this permission notice appear in all copies.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package spew
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Errorf is a wrapper for fmt.Errorf that treats each argument as if it were
|
||||||
|
// passed with a default Formatter interface returned by NewFormatter. It
|
||||||
|
// returns the formatted string as a value that satisfies error. See
|
||||||
|
// NewFormatter for formatting details.
|
||||||
|
//
|
||||||
|
// This function is shorthand for the following syntax:
|
||||||
|
//
|
||||||
|
// fmt.Errorf(format, spew.NewFormatter(a), spew.NewFormatter(b))
|
||||||
|
func Errorf(format string, a ...interface{}) (err error) {
|
||||||
|
return fmt.Errorf(format, convertArgs(a)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fprint is a wrapper for fmt.Fprint that treats each argument as if it were
|
||||||
|
// passed with a default Formatter interface returned by NewFormatter. It
|
||||||
|
// returns the number of bytes written and any write error encountered. See
|
||||||
|
// NewFormatter for formatting details.
|
||||||
|
//
|
||||||
|
// This function is shorthand for the following syntax:
|
||||||
|
//
|
||||||
|
// fmt.Fprint(w, spew.NewFormatter(a), spew.NewFormatter(b))
|
||||||
|
func Fprint(w io.Writer, a ...interface{}) (n int, err error) {
|
||||||
|
return fmt.Fprint(w, convertArgs(a)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fprintf is a wrapper for fmt.Fprintf that treats each argument as if it were
|
||||||
|
// passed with a default Formatter interface returned by NewFormatter. It
|
||||||
|
// returns the number of bytes written and any write error encountered. See
|
||||||
|
// NewFormatter for formatting details.
|
||||||
|
//
|
||||||
|
// This function is shorthand for the following syntax:
|
||||||
|
//
|
||||||
|
// fmt.Fprintf(w, format, spew.NewFormatter(a), spew.NewFormatter(b))
|
||||||
|
func Fprintf(w io.Writer, format string, a ...interface{}) (n int, err error) {
|
||||||
|
return fmt.Fprintf(w, format, convertArgs(a)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fprintln is a wrapper for fmt.Fprintln that treats each argument as if it
|
||||||
|
// passed with a default Formatter interface returned by NewFormatter. See
|
||||||
|
// NewFormatter for formatting details.
|
||||||
|
//
|
||||||
|
// This function is shorthand for the following syntax:
|
||||||
|
//
|
||||||
|
// fmt.Fprintln(w, spew.NewFormatter(a), spew.NewFormatter(b))
|
||||||
|
func Fprintln(w io.Writer, a ...interface{}) (n int, err error) {
|
||||||
|
return fmt.Fprintln(w, convertArgs(a)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Print is a wrapper for fmt.Print that treats each argument as if it were
|
||||||
|
// passed with a default Formatter interface returned by NewFormatter. It
|
||||||
|
// returns the number of bytes written and any write error encountered. See
|
||||||
|
// NewFormatter for formatting details.
|
||||||
|
//
|
||||||
|
// This function is shorthand for the following syntax:
|
||||||
|
//
|
||||||
|
// fmt.Print(spew.NewFormatter(a), spew.NewFormatter(b))
|
||||||
|
func Print(a ...interface{}) (n int, err error) {
|
||||||
|
return fmt.Print(convertArgs(a)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Printf is a wrapper for fmt.Printf that treats each argument as if it were
|
||||||
|
// passed with a default Formatter interface returned by NewFormatter. It
|
||||||
|
// returns the number of bytes written and any write error encountered. See
|
||||||
|
// NewFormatter for formatting details.
|
||||||
|
//
|
||||||
|
// This function is shorthand for the following syntax:
|
||||||
|
//
|
||||||
|
// fmt.Printf(format, spew.NewFormatter(a), spew.NewFormatter(b))
|
||||||
|
func Printf(format string, a ...interface{}) (n int, err error) {
|
||||||
|
return fmt.Printf(format, convertArgs(a)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Println is a wrapper for fmt.Println that treats each argument as if it were
|
||||||
|
// passed with a default Formatter interface returned by NewFormatter. It
|
||||||
|
// returns the number of bytes written and any write error encountered. See
|
||||||
|
// NewFormatter for formatting details.
|
||||||
|
//
|
||||||
|
// This function is shorthand for the following syntax:
|
||||||
|
//
|
||||||
|
// fmt.Println(spew.NewFormatter(a), spew.NewFormatter(b))
|
||||||
|
func Println(a ...interface{}) (n int, err error) {
|
||||||
|
return fmt.Println(convertArgs(a)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sprint is a wrapper for fmt.Sprint that treats each argument as if it were
|
||||||
|
// passed with a default Formatter interface returned by NewFormatter. It
|
||||||
|
// returns the resulting string. See NewFormatter for formatting details.
|
||||||
|
//
|
||||||
|
// This function is shorthand for the following syntax:
|
||||||
|
//
|
||||||
|
// fmt.Sprint(spew.NewFormatter(a), spew.NewFormatter(b))
|
||||||
|
func Sprint(a ...interface{}) string {
|
||||||
|
return fmt.Sprint(convertArgs(a)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sprintf is a wrapper for fmt.Sprintf that treats each argument as if it were
|
||||||
|
// passed with a default Formatter interface returned by NewFormatter. It
|
||||||
|
// returns the resulting string. See NewFormatter for formatting details.
|
||||||
|
//
|
||||||
|
// This function is shorthand for the following syntax:
|
||||||
|
//
|
||||||
|
// fmt.Sprintf(format, spew.NewFormatter(a), spew.NewFormatter(b))
|
||||||
|
func Sprintf(format string, a ...interface{}) string {
|
||||||
|
return fmt.Sprintf(format, convertArgs(a)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sprintln is a wrapper for fmt.Sprintln that treats each argument as if it
|
||||||
|
// were passed with a default Formatter interface returned by NewFormatter. It
|
||||||
|
// returns the resulting string. See NewFormatter for formatting details.
|
||||||
|
//
|
||||||
|
// This function is shorthand for the following syntax:
|
||||||
|
//
|
||||||
|
// fmt.Sprintln(spew.NewFormatter(a), spew.NewFormatter(b))
|
||||||
|
func Sprintln(a ...interface{}) string {
|
||||||
|
return fmt.Sprintln(convertArgs(a)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// convertArgs accepts a slice of arguments and returns a slice of the same
|
||||||
|
// length with each argument converted to a default spew Formatter interface.
|
||||||
|
func convertArgs(args []interface{}) (formatters []interface{}) {
|
||||||
|
formatters = make([]interface{}, len(args))
|
||||||
|
for index, arg := range args {
|
||||||
|
formatters[index] = NewFormatter(arg)
|
||||||
|
}
|
||||||
|
return formatters
|
||||||
|
}
|
12
vendor/modules.txt
vendored
Normal file
12
vendor/modules.txt
vendored
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
# github.com/d2r2/go-bh1750 v0.0.0-20181222061755-1195122364ab
|
||||||
|
## explicit
|
||||||
|
github.com/d2r2/go-bh1750
|
||||||
|
# github.com/d2r2/go-i2c v0.0.0-20191123181816-73a8a799d6bc
|
||||||
|
## explicit
|
||||||
|
github.com/d2r2/go-i2c
|
||||||
|
# github.com/d2r2/go-logger v0.0.0-20181221090742-9998a510495e
|
||||||
|
## explicit
|
||||||
|
github.com/d2r2/go-logger
|
||||||
|
# github.com/davecgh/go-spew v1.1.1
|
||||||
|
## explicit
|
||||||
|
github.com/davecgh/go-spew/spew
|
Loading…
Reference in a new issue