This commit is contained in:
Cadey Ratio 2018-07-01 20:38:18 +00:00
parent b0e0b10823
commit 6197f455f6
490 changed files with 20135 additions and 76608 deletions

99
Gopkg.lock generated
View File

@ -1,99 +0,0 @@
# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
[[projects]]
branch = "master"
name = "github.com/GeertJohan/go.rice"
packages = [".","embedded"]
revision = "c02ca9a983da5807ddf7d796784928f5be4afd09"
[[projects]]
branch = "master"
name = "github.com/Xe/gopreload"
packages = ["."]
revision = "a00a8beb369cafd88bb7b32f31fc4ff3219c3565"
[[projects]]
branch = "master"
name = "github.com/Xe/jsonfeed"
packages = ["."]
revision = "e21591505612b9064436351ffc9acddfa3b583e8"
[[projects]]
name = "github.com/Xe/ln"
packages = ["."]
revision = "466e05b2ef3e48ce08a367b6aaac09ee29a124e5"
version = "v0.1"
[[projects]]
branch = "master"
name = "github.com/daaku/go.zipexe"
packages = ["."]
revision = "a5fe2436ffcb3236e175e5149162b41cd28bd27d"
[[projects]]
name = "github.com/google/gops"
packages = ["agent","internal","signal"]
revision = "57e77c5c37da1f4e1af49f9d1fe760f146c1579e"
version = "v0.3.2"
[[projects]]
name = "github.com/gorilla/feeds"
packages = ["."]
revision = "4b936b5221c53c99fcd4b15ac0b8c38ff490ab89"
version = "v1.0.0"
[[projects]]
branch = "master"
name = "github.com/jtolds/qod"
packages = ["."]
revision = "3abb44dfc7ba8b5cdfdb634786f57e78c7004e1c"
[[projects]]
branch = "master"
name = "github.com/kardianos/osext"
packages = ["."]
revision = "ae77be60afb1dcacde03767a8c37337fad28ac14"
[[projects]]
name = "github.com/magefile/mage"
packages = ["mg","types"]
revision = "ab3ca2f6f85577d7ec82e0a6df721147a2e737f9"
version = "v2.0.1"
[[projects]]
name = "github.com/pkg/errors"
packages = ["."]
revision = "645ef00459ed84a119197bfb8d8205042c6df63d"
version = "v0.8.0"
[[projects]]
name = "github.com/russross/blackfriday"
packages = ["."]
revision = "cadec560ec52d93835bf2f15bd794700d3a2473b"
version = "v2.0.0"
[[projects]]
branch = "master"
name = "github.com/shurcooL/sanitized_anchor_name"
packages = ["."]
revision = "86672fcb3f950f35f2e675df2240550f2a50762f"
[[projects]]
branch = "master"
name = "github.com/tj/front"
packages = ["."]
revision = "739be213b0a1c496dccaf9e5df1514150c9548e4"
[[projects]]
branch = "v1"
name = "gopkg.in/yaml.v1"
packages = ["."]
revision = "9f9df34309c04878acc86042b16630b0f696e1de"
[solve-meta]
analyzer-name = "dep"
analyzer-version = 1
inputs-digest = "0689be1827bc408bc22bad70a56fe65f0d7986f4b7a01376fd4c9420f54aac18"
solver-name = "gps-cdcl"
solver-version = 1

View File

@ -1,71 +0,0 @@
# Gopkg.toml example
#
# Refer to https://github.com/golang/dep/blob/master/docs/Gopkg.toml.md
# for detailed Gopkg.toml documentation.
#
# required = ["github.com/user/thing/cmd/thing"]
# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"]
#
# [[constraint]]
# name = "github.com/user/project"
# version = "1.0.0"
#
# [[constraint]]
# name = "github.com/user/project2"
# branch = "dev"
# source = "github.com/myfork/project2"
#
# [[override]]
# name = "github.com/x/y"
# version = "2.4.0"
[[constraint]]
branch = "master"
name = "github.com/GeertJohan/go.rice"
[[constraint]]
branch = "master"
name = "github.com/Xe/gopreload"
[[constraint]]
branch = "master"
name = "github.com/Xe/jsonfeed"
[[constraint]]
name = "github.com/Xe/ln"
version = "0.1.0"
[[constraint]]
name = "github.com/google/gops"
version = "0.3.2"
[[constraint]]
name = "github.com/gorilla/feeds"
version = "1.0.0"
[[constraint]]
branch = "master"
name = "github.com/jtolds/qod"
[[constraint]]
name = "github.com/magefile/mage"
version = "2.0.1"
[[constraint]]
name = "github.com/pkg/errors"
version = "0.8.0"
[[constraint]]
name = "github.com/russross/blackfriday"
version = "2.0.0"
[[constraint]]
branch = "master"
name = "github.com/tj/front"
[metadata.heroku]
root-package = "github.com/Xe/site"
install = [ "." ]
ensure = "false"

22
go.mod Normal file
View File

@ -0,0 +1,22 @@
module github.com/Xe/site
require (
github.com/GeertJohan/go.rice v0.0.0-20170420135705-c02ca9a983da
github.com/Xe/gopreload v0.0.0-20170326043426-a00a8beb369c
github.com/Xe/jsonfeed v0.0.0-20170520170432-e21591505612
github.com/Xe/ln v0.0.0-20170921000907-466e05b2ef3e
github.com/daaku/go.zipexe v0.0.0-20150329023125-a5fe2436ffcb
github.com/google/gops v0.3.2
github.com/gorilla/feeds v1.0.0
github.com/jtolds/qod v0.0.0-20170925014538-3abb44dfc7ba
github.com/kr/pretty v0.1.0
github.com/magefile/mage v0.0.0-20171025021237-ab3ca2f6f855
github.com/pkg/errors v0.8.0
github.com/russross/blackfriday v0.0.0-20170806171014-cadec560ec52
github.com/shurcooL/sanitized_anchor_name v0.0.0-20170918181015-86672fcb3f95
github.com/st3fan/jsonfeed v0.0.0-20170519104842-498b2850d26b
github.com/stretchr/testify v1.2.2
github.com/tj/front v0.0.0-20170212063142-739be213b0a1
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127
gopkg.in/yaml.v1 v1.0.0-20140924161607-9f9df34309c0
)

18
go.modverify Normal file
View File

@ -0,0 +1,18 @@
github.com/Xe/gopreload v0.0.0-20170326043426-a00a8beb369c h1:lqTJqaoonxgJMvvfl1ukr/3qCEGWC0nQxzPezbJrhHs=
github.com/Xe/jsonfeed v0.0.0-20170520170432-e21591505612 h1:5cPld6YTMozzm3lK9VCnOErgoFbADM2hZc4KDu0YNKs=
github.com/Xe/ln v0.0.0-20170921000907-466e05b2ef3e h1:uMC/C/zBov+PItx2c6Vax4lt37X+2V5X7NWRcXsxuzE=
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
github.com/google/gops v0.3.2 h1:n9jMkrye8dh3WQ0IxG5dzLRIhQeZDZoGaj0D7T7x7hQ=
github.com/gorilla/feeds v1.0.0 h1:EbkEvaYf+PXhYNHS20heBG7Rl2X6Zy8l11ZBWAHkWqE=
github.com/kardianos/osext v0.0.0-20170510131534-ae77be60afb1 h1:PJPDf8OUfOK1bb/NeTKd4f1QXZItOX389VN3B6qC8ro=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/pkg/errors v0.8.0 h1:WdK/asTD0HN+q6hsWO3/vpuAkAr+tw6aNJNDFFf0+qw=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/russross/blackfriday v0.0.0-20170806171014-cadec560ec52 h1:xZ0R4UuR0EDx7m0OmvsqZaomfqCeYJ/PyLm94WLhnIM=
github.com/shurcooL/sanitized_anchor_name v0.0.0-20170918181015-86672fcb3f95 h1:/vdW8Cb7EXrkqWGufVMES1OH2sU9gKVb2n9/1y5NMBY=
github.com/st3fan/jsonfeed v0.0.0-20170519104842-498b2850d26b h1:i9Wk9W2bjrMvUf59rJKX4/lvZXy3L3lcX7g18c8AveU=
github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w=
github.com/tj/front v0.0.0-20170212063142-739be213b0a1 h1:lA+aPRvltlx2fwv/BnxyYSDQo3pIeqzHgMO5GvK0T9E=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
gopkg.in/yaml.v1 v1.0.0-20140924161607-9f9df34309c0 h1:POO/ycCATvegFmVuPpQzZFJ+pGZeX22Ufu6fibxDVjU=

View File

@ -1,8 +0,0 @@
/example/example
/example/example.exe
/rice/rice
/rice/rice.exe
*.rice-box.go
*.rice-box.syso
.wercker

View File

@ -1,19 +0,0 @@
language: go
go:
- master
- 1.x.x
- 1.8.x
- 1.7.x
- 1.6.x
- 1.5.x
install:
- go get -t ./...
- env
- if [ "${TRAVIS_GO_VERSION%.*}" != "1.5" ]; then go get github.com/golang/lint/golint; fi
script:
- go build -x ./...
- go test -cover ./...
- go vet ./...
- if [ "${TRAVIS_GO_VERSION%.*}" != "1.5" ]; then golint .; fi

View File

@ -1,4 +0,0 @@
Geert-Johan Riemer <geertjohan@geertjohan.net>
Paul Maddox <paul.maddox@gmail.com>
Vincent Petithory <vincent.petithory@gmail.com>

View File

@ -1,151 +0,0 @@
## go.rice
[![Build Status](https://travis-ci.org/GeertJohan/go.rice.png)](https://travis-ci.org/GeertJohan/go.rice)
[![Godoc](https://img.shields.io/badge/godoc-go.rice-blue.svg?style=flat-square)](https://godoc.org/github.com/GeertJohan/go.rice)
go.rice is a [Go](http://golang.org) package that makes working with resources such as html,js,css,images and templates very easy. During development `go.rice` will load required files directly from disk. Upon deployment it is easy to add all resource files to a executable using the `rice` tool, without changing the source code for your package. go.rice provides several methods to add resources to a binary.
### What does it do?
The first thing go.rice does is finding the correct absolute path for your resource files. Say you are executing go binary in your home directory, but your `html-files` are located in `$GOPATH/src/yourApplication/html-files`. `go.rice` will lookup the correct path for that directory (relative to the location of yourApplication). The only thing you have to do is include the resources using `rice.FindBox("html-files")`.
This only works when the source is available to the machine executing the binary. Which is always the case when the binary was installed with `go get` or `go install`. It might occur that you wish to simply provide a binary, without source. The `rice` tool analyses source code and finds call's to `rice.FindBox(..)` and adds the required directories to the executable binary. There are several methods to add these resources. You can 'embed' by generating go source code, or append the resource to the executable as zip file. In both cases `go.rice` will detect the embedded or appended resources and load those, instead of looking up files from disk.
### Installation
Use `go get` to install the package the `rice` tool.
```
go get github.com/GeertJohan/go.rice
go get github.com/GeertJohan/go.rice/rice
```
### Package usage
Import the package: `import "github.com/GeertJohan/go.rice"`
**Serving a static content folder over HTTP with a rice Box**
```go
http.Handle("/", http.FileServer(rice.MustFindBox("http-files").HTTPBox()))
http.ListenAndServe(":8080", nil)
```
**Service a static content folder over HTTP at a non-root location**
```go
box := rice.MustFindBox("cssfiles")
cssFileServer := http.StripPrefix("/css/", http.FileServer(box.HTTPBox()))
http.Handle("/css/", cssFileServer)
http.ListenAndServe(":8080", nil)
```
Note the *trailing slash* in `/css/` in both the call to
`http.StripPrefix` and `http.Handle`.
**Loading a template**
```go
// find a rice.Box
templateBox, err := rice.FindBox("example-templates")
if err != nil {
log.Fatal(err)
}
// get file contents as string
templateString, err := templateBox.String("message.tmpl")
if err != nil {
log.Fatal(err)
}
// parse and execute the template
tmplMessage, err := template.New("message").Parse(templateString)
if err != nil {
log.Fatal(err)
}
tmplMessage.Execute(os.Stdout, map[string]string{"Message": "Hello, world!"})
```
Never call `FindBox()` or `MustFindBox()` from an `init()` function, as the boxes might have not been loaded at that time.
### Tool usage
The `rice` tool lets you add the resources to a binary executable so the files are not loaded from the filesystem anymore. This creates a 'standalone' executable. There are several ways to add the resources to a binary, each has pro's and con's but all will work without requiring changes to the way you load the resources.
#### embed-go
**Embed resources by generating Go source code**
This method must be executed before building. It generates a single Go source file called *rice-box.go* for each package, that is compiled by the go compiler into the binary.
The downside with this option is that the generated go source files can become very large, which will slow down compilation and require lots of memory to compile.
Execute the following commands:
```
rice embed-go
go build
```
*A Note on Symbolic Links*: `embed-go` uses the `os.Walk` function
from the standard library. The `os.Walk` function does **not** follow
symbolic links. So, when creating a box, be aware that any symbolic
links inside your box's directory will not be followed. **However**,
if the box itself is a symbolic link, its actual location will be
resolved first and then walked. In summary, if your box location is a
symbolic link, it will be followed but none of the symbolic links in
the box will be followed.
#### embed-syso
**Embed resources by generating a coff .syso file and some .go source code**
** This method is experimental and should not be used for production systems just yet **
This method must be executed before building. It generates a COFF .syso file and Go source file that are compiled by the go compiler into the binary.
Execute the following commands:
```
rice embed-syso
go build
```
#### append
**Append resources to executable as zip file**
This method changes an already built executable. It appends the resources as zip file to the binary. It makes compilation a lot faster and can be used with large resource files.
Downsides for appending are that it requires `zip` to be installed and does not provide a working Seek method.
Run the following commands to create a standalone executable.
```
go build -o example
rice append --exec example
```
**Note: requires zip command to be installed**
On windows, install zip from http://gnuwin32.sourceforge.net/packages/zip.htm or cygwin/msys toolsets.
#### Help information
Run `rice -h` for information about all options.
You can run the -h option for each sub-command, e.g. `rice append -h`.
### Order of precedence
When opening a new box, the rice package tries to locate the resources in the following order:
- embedded in generated go source
- appended as zip
- 'live' from filesystem
### License
This project is licensed under a Simplified BSD license. Please read the [LICENSE file][license].
### TODO & Development
This package is not completed yet. Though it already provides working embedding, some important featuers are still missing.
- implement Readdir() correctly on virtualDir
- in-code TODO's
- find boxes in imported packages
Less important stuff:
- idea, os/arch dependent embeds. rice checks if embedding file has _os_arch or build flags. If box is not requested by file without buildflags, then the buildflags are applied to the embed file.
### Package documentation
You will find package documentation at [godoc.org/github.com/GeertJohan/go.rice][godoc].
[license]: https://github.com/GeertJohan/go.rice/blob/master/LICENSE
[godoc]: http://godoc.org/github.com/GeertJohan/go.rice

View File

@ -1,138 +0,0 @@
package rice
import (
"archive/zip"
"log"
"os"
"path/filepath"
"strings"
"time"
"github.com/daaku/go.zipexe"
"github.com/kardianos/osext"
)
// appendedBox defines an appended box
type appendedBox struct {
Name string // box name
Files map[string]*appendedFile // appended files (*zip.File) by full path
}
type appendedFile struct {
zipFile *zip.File
dir bool
dirInfo *appendedDirInfo
children []*appendedFile
content []byte
}
// appendedBoxes is a public register of appendes boxes
var appendedBoxes = make(map[string]*appendedBox)
func init() {
// find if exec is appended
thisFile, err := osext.Executable()
if err != nil {
return // not appended or cant find self executable
}
closer, rd, err := zipexe.OpenCloser(thisFile)
if err != nil {
return // not appended
}
defer closer.Close()
for _, f := range rd.File {
// get box and file name from f.Name
fileParts := strings.SplitN(strings.TrimLeft(filepath.ToSlash(f.Name), "/"), "/", 2)
boxName := fileParts[0]
var fileName string
if len(fileParts) > 1 {
fileName = fileParts[1]
}
// find box or create new one if doesn't exist
box := appendedBoxes[boxName]
if box == nil {
box = &appendedBox{
Name: boxName,
Files: make(map[string]*appendedFile),
}
appendedBoxes[boxName] = box
}
// create and add file to box
af := &appendedFile{
zipFile: f,
}
if f.Comment == "dir" {
af.dir = true
af.dirInfo = &appendedDirInfo{
name: filepath.Base(af.zipFile.Name),
//++ TODO: use zip modtime when that is set correctly: af.zipFile.ModTime()
time: time.Now(),
}
} else {
// this is a file, we need it's contents so we can create a bytes.Reader when the file is opened
// make a new byteslice
af.content = make([]byte, af.zipFile.FileInfo().Size())
// ignore reading empty files from zip (empty file still is a valid file to be read though!)
if len(af.content) > 0 {
// open io.ReadCloser
rc, err := af.zipFile.Open()
if err != nil {
af.content = nil // this will cause an error when the file is being opened or seeked (which is good)
// TODO: it's quite blunt to just log this stuff. but this is in init, so rice.Debug can't be changed yet..
log.Printf("error opening appended file %s: %v", af.zipFile.Name, err)
} else {
_, err = rc.Read(af.content)
rc.Close()
if err != nil {
af.content = nil // this will cause an error when the file is being opened or seeked (which is good)
// TODO: it's quite blunt to just log this stuff. but this is in init, so rice.Debug can't be changed yet..
log.Printf("error reading data for appended file %s: %v", af.zipFile.Name, err)
}
}
}
}
// add appendedFile to box file list
box.Files[fileName] = af
// add to parent dir (if any)
dirName := filepath.Dir(fileName)
if dirName == "." {
dirName = ""
}
if fileName != "" { // don't make box root dir a child of itself
if dir := box.Files[dirName]; dir != nil {
dir.children = append(dir.children, af)
}
}
}
}
// implements os.FileInfo.
// used for Readdir()
type appendedDirInfo struct {
name string
time time.Time
}
func (adi *appendedDirInfo) Name() string {
return adi.name
}
func (adi *appendedDirInfo) Size() int64 {
return 0
}
func (adi *appendedDirInfo) Mode() os.FileMode {
return os.ModeDir
}
func (adi *appendedDirInfo) ModTime() time.Time {
return adi.time
}
func (adi *appendedDirInfo) IsDir() bool {
return true
}
func (adi *appendedDirInfo) Sys() interface{} {
return nil
}

View File

@ -1,337 +0,0 @@
package rice
import (
"bytes"
"errors"
"fmt"
"io/ioutil"
"os"
"path/filepath"
"runtime"
"strings"
"time"
"github.com/GeertJohan/go.rice/embedded"
)
// Box abstracts a directory for resources/files.
// It can either load files from disk, or from embedded code (when `rice --embed` was ran).
type Box struct {
name string
absolutePath string
embed *embedded.EmbeddedBox
appendd *appendedBox
}
var defaultLocateOrder = []LocateMethod{LocateEmbedded, LocateAppended, LocateFS}
func findBox(name string, order []LocateMethod) (*Box, error) {
b := &Box{name: name}
// no support for absolute paths since gopath can be different on different machines.
// therefore, required box must be located relative to package requiring it.
if filepath.IsAbs(name) {
return nil, errors.New("given name/path is absolute")
}
var err error
for _, method := range order {
switch method {
case LocateEmbedded:
if embed := embedded.EmbeddedBoxes[name]; embed != nil {
b.embed = embed
return b, nil
}
case LocateAppended:
appendedBoxName := strings.Replace(name, `/`, `-`, -1)
if appendd := appendedBoxes[appendedBoxName]; appendd != nil {
b.appendd = appendd
return b, nil
}
case LocateFS:
// resolve absolute directory path
err := b.resolveAbsolutePathFromCaller()
if err != nil {
continue
}
// check if absolutePath exists on filesystem
info, err := os.Stat(b.absolutePath)
if err != nil {
continue
}
// check if absolutePath is actually a directory
if !info.IsDir() {
err = errors.New("given name/path is not a directory")
continue
}
return b, nil
case LocateWorkingDirectory:
// resolve absolute directory path
err := b.resolveAbsolutePathFromWorkingDirectory()
if err != nil {
continue
}
// check if absolutePath exists on filesystem
info, err := os.Stat(b.absolutePath)
if err != nil {
continue
}
// check if absolutePath is actually a directory
if !info.IsDir() {
err = errors.New("given name/path is not a directory")
continue
}
return b, nil
}
}
if err == nil {
err = fmt.Errorf("could not locate box %q", name)
}
return nil, err
}
// FindBox returns a Box instance for given name.
// When the given name is a relative path, it's base path will be the calling pkg/cmd's source root.
// When the given name is absolute, it's absolute. derp.
// Make sure the path doesn't contain any sensitive information as it might be placed into generated go source (embedded).
func FindBox(name string) (*Box, error) {
return findBox(name, defaultLocateOrder)
}
// MustFindBox returns a Box instance for given name, like FindBox does.
// It does not return an error, instead it panics when an error occurs.
func MustFindBox(name string) *Box {
box, err := findBox(name, defaultLocateOrder)
if err != nil {
panic(err)
}
return box
}
// This is injected as a mutable function literal so that we can mock it out in
// tests and return a fixed test file.
var resolveAbsolutePathFromCaller = func(name string, nStackFrames int) (string, error) {
_, callingGoFile, _, ok := runtime.Caller(nStackFrames)
if !ok {
return "", errors.New("couldn't find caller on stack")
}
// resolve to proper path
pkgDir := filepath.Dir(callingGoFile)
// fix for go cover
const coverPath = "_test/_obj_test"
if !filepath.IsAbs(pkgDir) {
if i := strings.Index(pkgDir, coverPath); i >= 0 {
pkgDir = pkgDir[:i] + pkgDir[i+len(coverPath):] // remove coverPath
pkgDir = filepath.Join(os.Getenv("GOPATH"), "src", pkgDir) // make absolute
}
}
return filepath.Join(pkgDir, name), nil
}
func (b *Box) resolveAbsolutePathFromCaller() error {
path, err := resolveAbsolutePathFromCaller(b.name, 4)
if err != nil {
return err
}
b.absolutePath = path
return nil
}
func (b *Box) resolveAbsolutePathFromWorkingDirectory() error {
path, err := os.Getwd()
if err != nil {
return err
}
b.absolutePath = filepath.Join(path, b.name)
return nil
}
// IsEmbedded indicates wether this box was embedded into the application
func (b *Box) IsEmbedded() bool {
return b.embed != nil
}
// IsAppended indicates wether this box was appended to the application
func (b *Box) IsAppended() bool {
return b.appendd != nil
}
// Time returns how actual the box is.
// When the box is embedded, it's value is saved in the embedding code.
// When the box is live, this methods returns time.Now()
func (b *Box) Time() time.Time {
if b.IsEmbedded() {
return b.embed.Time
}
//++ TODO: return time for appended box
return time.Now()
}
// Open opens a File from the box
// If there is an error, it will be of type *os.PathError.
func (b *Box) Open(name string) (*File, error) {
if Debug {
fmt.Printf("Open(%s)\n", name)
}
if b.IsEmbedded() {
if Debug {
fmt.Println("Box is embedded")
}
// trim prefix (paths are relative to box)
name = strings.TrimLeft(name, "/")
if Debug {
fmt.Printf("Trying %s\n", name)
}
// search for file
ef := b.embed.Files[name]
if ef == nil {
if Debug {
fmt.Println("Didn't find file in embed")
}
// file not found, try dir
ed := b.embed.Dirs[name]
if ed == nil {
if Debug {
fmt.Println("Didn't find dir in embed")
}
// dir not found, error out
return nil, &os.PathError{
Op: "open",
Path: name,
Err: os.ErrNotExist,
}
}
if Debug {
fmt.Println("Found dir. Returning virtual dir")
}
vd := newVirtualDir(ed)
return &File{virtualD: vd}, nil
}
// box is embedded
if Debug {
fmt.Println("Found file. Returning virtual file")
}
vf := newVirtualFile(ef)
return &File{virtualF: vf}, nil
}
if b.IsAppended() {
// trim prefix (paths are relative to box)
name = strings.TrimLeft(name, "/")
// search for file
appendedFile := b.appendd.Files[name]
if appendedFile == nil {
return nil, &os.PathError{
Op: "open",
Path: name,
Err: os.ErrNotExist,
}
}
// create new file
f := &File{
appendedF: appendedFile,
}
// if this file is a directory, we want to be able to read and seek
if !appendedFile.dir {
// looks like malformed data in zip, error now
if appendedFile.content == nil {
return nil, &os.PathError{
Op: "open",
Path: "name",
Err: errors.New("error reading data from zip file"),
}
}
// create new bytes.Reader
f.appendedFileReader = bytes.NewReader(appendedFile.content)
}
// all done
return f, nil
}
// perform os open
if Debug {
fmt.Printf("Using os.Open(%s)", filepath.Join(b.absolutePath, name))
}
file, err := os.Open(filepath.Join(b.absolutePath, name))
if err != nil {
return nil, err
}
return &File{realF: file}, nil
}
// Bytes returns the content of the file with given name as []byte.
func (b *Box) Bytes(name string) ([]byte, error) {
file, err := b.Open(name)
if err != nil {
return nil, err
}
defer file.Close()
content, err := ioutil.ReadAll(file)
if err != nil {
return nil, err
}
return content, nil
}
// MustBytes returns the content of the file with given name as []byte.
// panic's on error.
func (b *Box) MustBytes(name string) []byte {
bts, err := b.Bytes(name)
if err != nil {
panic(err)
}
return bts
}
// String returns the content of the file with given name as string.
func (b *Box) String(name string) (string, error) {
// check if box is embedded, optimized fast path
if b.IsEmbedded() {
// find file in embed
ef := b.embed.Files[name]
if ef == nil {
return "", os.ErrNotExist
}
// return as string
return ef.Content, nil
}
bts, err := b.Bytes(name)
if err != nil {
return "", err
}
return string(bts), nil
}
// MustString returns the content of the file with given name as string.
// panic's on error.
func (b *Box) MustString(name string) string {
str, err := b.String(name)
if err != nil {
panic(err)
}
return str
}
// Name returns the name of the box
func (b *Box) Name() string {
return b.name
}

View File

@ -1,39 +0,0 @@
package rice
// LocateMethod defines how a box is located.
type LocateMethod int
const (
LocateFS = LocateMethod(iota) // Locate on the filesystem according to package path.
LocateAppended // Locate boxes appended to the executable.
LocateEmbedded // Locate embedded boxes.
LocateWorkingDirectory // Locate on the binary working directory
)
// Config allows customizing the box lookup behavior.
type Config struct {
// LocateOrder defines the priority order that boxes are searched for. By
// default, the package global FindBox searches for embedded boxes first,
// then appended boxes, and then finally boxes on the filesystem. That
// search order may be customized by provided the ordered list here. Leaving
// out a particular method will omit that from the search space. For
// example, []LocateMethod{LocateEmbedded, LocateAppended} will never search
// the filesystem for boxes.
LocateOrder []LocateMethod
}
// FindBox searches for boxes using the LocateOrder of the config.
func (c *Config) FindBox(boxName string) (*Box, error) {
return findBox(boxName, c.LocateOrder)
}
// MustFindBox searches for boxes using the LocateOrder of the config, like
// FindBox does. It does not return an error, instead it panics when an error
// occurs.
func (c *Config) MustFindBox(boxName string) *Box {
box, err := findBox(boxName, c.LocateOrder)
if err != nil {
panic(err)
}
return box
}

View File

@ -1,136 +0,0 @@
package rice
import (
"fmt"
"io/ioutil"
"testing"
"github.com/GeertJohan/go.rice/embedded"
)
// For all test code in this package, define a set of test boxes.
var eb1 *embedded.EmbeddedBox
var ab1, ab2 *appendedBox
var fsb1, fsb2, fsb3 string // paths to filesystem boxes
func init() {
var err error
// Box1 exists in all three locations.
eb1 = &embedded.EmbeddedBox{Name: "box1"}
embedded.RegisterEmbeddedBox(eb1.Name, eb1)
ab1 = &appendedBox{Name: "box1"}
appendedBoxes["box1"] = ab1
fsb1, err = ioutil.TempDir("", "box1")
if err != nil {
panic(err)
}
// Box2 exists in only appended and FS.
ab2 = &appendedBox{Name: "box2"}
appendedBoxes["box2"] = ab2
fsb2, err = ioutil.TempDir("", "box2")
if err != nil {
panic(err)
}
// Box3 exists only on disk.
fsb3, err = ioutil.TempDir("", "box3")
if err != nil {
panic(err)
}
// Also, replace the default filesystem lookup path to directly support the
// on-disk temp directories.
resolveAbsolutePathFromCaller = func(name string, n int) (string, error) {
if name == "box1" {
return fsb1, nil
} else if name == "box2" {
return fsb2, nil
} else if name == "box3" {
return fsb3, nil
}
return "", fmt.Errorf("Unknown box name: %q", name)
}
}
func TestDefaultLookupOrder(t *testing.T) {
// Box1 exists in all three, so the default order should find the embedded.
b, err := FindBox("box1")
if err != nil {
t.Fatalf("Expected to find box1, got error: %v", err)
}
if b.embed != eb1 {
t.Fatalf("Expected to find embedded box, but got %#v", b)
}
// Box2 exists in appended and FS, so find the appended.
b2, err := FindBox("box2")
if err != nil {
t.Fatalf("Expected to find box2, got error: %v", err)
}
if b2.appendd != ab2 {
t.Fatalf("Expected to find appended box, but got %#v", b2)
}
// Box3 exists only on FS, so find it there.
b3, err := FindBox("box3")
if err != nil {
t.Fatalf("Expected to find box3, got error: %v", err)
}
if b3.absolutePath != fsb3 {
t.Fatalf("Expected to find FS box, but got %#v", b3)
}
}
func TestConfigLocateOrder(t *testing.T) {
cfg := Config{LocateOrder: []LocateMethod{LocateFS, LocateAppended, LocateEmbedded}}
fsb := []string{fsb1, fsb2, fsb3}
// All 3 boxes have a FS backend, so we should always find that.
for i, boxName := range []string{"box1", "box2", "box3"} {
b, err := cfg.FindBox(boxName)
if err != nil {
t.Fatalf("Expected to find %q, got error: %v", boxName, err)
}
if b.absolutePath != fsb[i] {
t.Fatalf("Expected to find FS box, but got %#v", b)
}
}
cfg.LocateOrder = []LocateMethod{LocateAppended, LocateFS, LocateEmbedded}
{
b, err := cfg.FindBox("box3")
if err != nil {
t.Fatalf("Expected to find box3, got error: %v", err)
}
if b.absolutePath != fsb3 {
t.Fatalf("Expected to find FS box, but got %#v", b)
}
}
{
b, err := cfg.FindBox("box2")
if err != nil {
t.Fatalf("Expected to find box2, got error: %v", err)
}
if b.appendd != ab2 {
t.Fatalf("Expected to find appended box, but got %#v", b)
}
}
// What if we don't list all the locate methods?
cfg.LocateOrder = []LocateMethod{LocateEmbedded}
{
b, err := cfg.FindBox("box2")
if err == nil {
t.Fatalf("Expected not to find box2, but something was found: %#v", b)
}
}
{
b, err := cfg.FindBox("box1")
if err != nil {
t.Fatalf("Expected to find box2, got error: %v", err)
}
if b.embed != eb1 {
t.Fatalf("Expected to find embedded box, but got %#v", b)
}
}
}

View File

@ -1,4 +0,0 @@
package rice
// Debug can be set to true to enable debugging.
var Debug = false

View File

@ -1,90 +0,0 @@
package rice
import (
"os"
"time"
"github.com/GeertJohan/go.rice/embedded"
)
// re-type to make exported methods invisible to user (godoc)
// they're not required for the user
// embeddedDirInfo implements os.FileInfo
type embeddedDirInfo embedded.EmbeddedDir
// Name returns the base name of the directory
// (implementing os.FileInfo)
func (ed *embeddedDirInfo) Name() string {
return ed.Filename
}
// Size always returns 0
// (implementing os.FileInfo)
func (ed *embeddedDirInfo) Size() int64 {
return 0
}
// Mode returns the file mode bits
// (implementing os.FileInfo)
func (ed *embeddedDirInfo) Mode() os.FileMode {
return os.FileMode(0555 | os.ModeDir) // dr-xr-xr-x
}
// ModTime returns the modification time
// (implementing os.FileInfo)
func (ed *embeddedDirInfo) ModTime() time.Time {
return ed.DirModTime
}
// IsDir returns the abbreviation for Mode().IsDir() (always true)
// (implementing os.FileInfo)
func (ed *embeddedDirInfo) IsDir() bool {
return true
}
// Sys returns the underlying data source (always nil)
// (implementing os.FileInfo)
func (ed *embeddedDirInfo) Sys() interface{} {
return nil
}
// re-type to make exported methods invisible to user (godoc)
// they're not required for the user
// embeddedFileInfo implements os.FileInfo
type embeddedFileInfo embedded.EmbeddedFile
// Name returns the base name of the file
// (implementing os.FileInfo)
func (ef *embeddedFileInfo) Name() string {
return ef.Filename
}
// Size returns the length in bytes for regular files; system-dependent for others
// (implementing os.FileInfo)
func (ef *embeddedFileInfo) Size() int64 {
return int64(len(ef.Content))
}
// Mode returns the file mode bits
// (implementing os.FileInfo)
func (ef *embeddedFileInfo) Mode() os.FileMode {
return os.FileMode(0555) // r-xr-xr-x
}
// ModTime returns the modification time
// (implementing os.FileInfo)
func (ef *embeddedFileInfo) ModTime() time.Time {
return ef.FileModTime
}
// IsDir returns the abbreviation for Mode().IsDir() (always false)
// (implementing os.FileInfo)
func (ef *embeddedFileInfo) IsDir() bool {
return false
}
// Sys returns the underlying data source (always nil)
// (implementing os.FileInfo)
func (ef *embeddedFileInfo) Sys() interface{} {
return nil
}

View File

@ -1,80 +0,0 @@
// Package embedded defines embedded data types that are shared between the go.rice package and generated code.
package embedded
import (
"fmt"
"path/filepath"
"strings"
"time"
)
const (
EmbedTypeGo = 0
EmbedTypeSyso = 1
)
// EmbeddedBox defines an embedded box
type EmbeddedBox struct {
Name string // box name
Time time.Time // embed time
EmbedType int // kind of embedding
Files map[string]*EmbeddedFile // ALL embedded files by full path
Dirs map[string]*EmbeddedDir // ALL embedded dirs by full path
}
// Link creates the ChildDirs and ChildFiles links in all EmbeddedDir's
func (e *EmbeddedBox) Link() {
for path, ed := range e.Dirs {
fmt.Println(path)
ed.ChildDirs = make([]*EmbeddedDir, 0)
ed.ChildFiles = make([]*EmbeddedFile, 0)
}
for path, ed := range e.Dirs {
parentDirpath, _ := filepath.Split(path)
if strings.HasSuffix(parentDirpath, "/") {
parentDirpath = parentDirpath[:len(parentDirpath)-1]
}
parentDir := e.Dirs[parentDirpath]
if parentDir == nil {
panic("parentDir `" + parentDirpath + "` is missing in embedded box")
}
parentDir.ChildDirs = append(parentDir.ChildDirs, ed)
}
for path, ef := range e.Files {
dirpath, _ := filepath.Split(path)
if strings.HasSuffix(dirpath, "/") {
dirpath = dirpath[:len(dirpath)-1]
}
dir := e.Dirs[dirpath]
if dir == nil {
panic("dir `" + dirpath + "` is missing in embedded box")
}
dir.ChildFiles = append(dir.ChildFiles, ef)
}
}
// EmbeddedDir is instanced in the code generated by the rice tool and contains all necicary information about an embedded file
type EmbeddedDir struct {
Filename string
DirModTime time.Time
ChildDirs []*EmbeddedDir // direct childs, as returned by virtualDir.Readdir()
ChildFiles []*EmbeddedFile // direct childs, as returned by virtualDir.Readdir()
}
// EmbeddedFile is instanced in the code generated by the rice tool and contains all necicary information about an embedded file
type EmbeddedFile struct {
Filename string // filename
FileModTime time.Time
Content string
}
// EmbeddedBoxes is a public register of embedded boxes
var EmbeddedBoxes = make(map[string]*EmbeddedBox)
// RegisterEmbeddedBox registers an EmbeddedBox
func RegisterEmbeddedBox(name string, box *EmbeddedBox) {
if _, exists := EmbeddedBoxes[name]; exists {
panic(fmt.Sprintf("EmbeddedBox with name `%s` exists already", name))
}
EmbeddedBoxes[name] = box
}

View File

@ -1,2 +0,0 @@
test content
break

Binary file not shown.

Before

Width:  |  Height:  |  Size: 52 KiB

View File

@ -1 +0,0 @@
I have a message for you: {{.Message}}

View File

@ -1,69 +0,0 @@
package main
import (
"encoding/hex"
"fmt"
"log"
"net/http"
"os"
"text/template"
"github.com/GeertJohan/go.rice"
"github.com/davecgh/go-spew/spew"
)
func main() {
conf := rice.Config{
LocateOrder: []rice.LocateMethod{rice.LocateEmbedded, rice.LocateAppended, rice.LocateFS},
}
box, err := conf.FindBox("example-files")
if err != nil {
log.Fatalf("error opening rice.Box: %s\n", err)
}
// spew.Dump(box)
contentString, err := box.String("file.txt")
if err != nil {
log.Fatalf("could not read file contents as string: %s\n", err)
}
log.Printf("Read some file contents as string:\n%s\n", contentString)
contentBytes, err := box.Bytes("file.txt")
if err != nil {
log.Fatalf("could not read file contents as byteSlice: %s\n", err)
}
log.Printf("Read some file contents as byteSlice:\n%s\n", hex.Dump(contentBytes))
file, err := box.Open("file.txt")
if err != nil {
log.Fatalf("could not open file: %s\n", err)
}
spew.Dump(file)
// find/create a rice.Box
templateBox, err := rice.FindBox("example-templates")
if err != nil {
log.Fatal(err)
}
// get file contents as string
templateString, err := templateBox.String("message.tmpl")
if err != nil {
log.Fatal(err)
}
// parse and execute the template
tmplMessage, err := template.New("message").Parse(templateString)
if err != nil {
log.Fatal(err)
}
tmplMessage.Execute(os.Stdout, map[string]string{"Message": "Hello, world!"})
http.Handle("/", http.FileServer(box.HTTPBox()))
go func() {
fmt.Println("Serving files on :8080, press ctrl-C to exit")
err := http.ListenAndServe(":8080", nil)
if err != nil {
log.Fatalf("error serving files: %v", err)
}
}()
select {}
}

View File

@ -1,144 +0,0 @@
package rice
import (
"bytes"
"errors"
"os"
"path/filepath"
)
// File implements the io.Reader, io.Seeker, io.Closer and http.File interfaces
type File struct {
// File abstracts file methods so the user doesn't see the difference between rice.virtualFile, rice.virtualDir and os.File
// TODO: maybe use internal File interface and four implementations: *os.File, appendedFile, virtualFile, virtualDir
// real file on disk
realF *os.File
// when embedded (go)
virtualF *virtualFile
virtualD *virtualDir
// when appended (zip)
appendedF *appendedFile
appendedFileReader *bytes.Reader
// TODO: is appendedFileReader subject of races? Might need a lock here..
}
// Close is like (*os.File).Close()
// Visit http://golang.org/pkg/os/#File.Close for more information
func (f *File) Close() error {
if f.appendedF != nil {
if f.appendedFileReader == nil {
return errors.New("already closed")
}
f.appendedFileReader = nil
return nil
}
if f.virtualF != nil {
return f.virtualF.close()
}
if f.virtualD != nil {
return f.virtualD.close()
}
return f.realF.Close()
}
// Stat is like (*os.File).Stat()
// Visit http://golang.org/pkg/os/#File.Stat for more information
func (f *File) Stat() (os.FileInfo, error) {
if f.appendedF != nil {
if f.appendedF.dir {
return f.appendedF.dirInfo, nil
}
if f.appendedFileReader == nil {
return nil, errors.New("file is closed")
}
return f.appendedF.zipFile.FileInfo(), nil
}
if f.virtualF != nil {
return f.virtualF.stat()
}
if f.virtualD != nil {
return f.virtualD.stat()
}
return f.realF.Stat()
}
// Readdir is like (*os.File).Readdir()
// Visit http://golang.org/pkg/os/#File.Readdir for more information
func (f *File) Readdir(count int) ([]os.FileInfo, error) {
if f.appendedF != nil {
if f.appendedF.dir {
fi := make([]os.FileInfo, 0, len(f.appendedF.children))
for _, childAppendedFile := range f.appendedF.children {
if childAppendedFile.dir {
fi = append(fi, childAppendedFile.dirInfo)
} else {
fi = append(fi, childAppendedFile.zipFile.FileInfo())
}
}
return fi, nil
}
//++ TODO: is os.ErrInvalid the correct error for Readdir on file?
return nil, os.ErrInvalid
}
if f.virtualF != nil {
return f.virtualF.readdir(count)
}
if f.virtualD != nil {
return f.virtualD.readdir(count)
}
return f.realF.Readdir(count)
}
// Read is like (*os.File).Read()
// Visit http://golang.org/pkg/os/#File.Read for more information
func (f *File) Read(bts []byte) (int, error) {
if f.appendedF != nil {
if f.appendedFileReader == nil {
return 0, &os.PathError{
Op: "read",
Path: filepath.Base(f.appendedF.zipFile.Name),
Err: errors.New("file is closed"),
}
}
if f.appendedF.dir {
return 0, &os.PathError{
Op: "read",
Path: filepath.Base(f.appendedF.zipFile.Name),
Err: errors.New("is a directory"),
}
}
return f.appendedFileReader.Read(bts)
}
if f.virtualF != nil {
return f.virtualF.read(bts)
}
if f.virtualD != nil {
return f.virtualD.read(bts)
}
return f.realF.Read(bts)
}
// Seek is like (*os.File).Seek()
// Visit http://golang.org/pkg/os/#File.Seek for more information
func (f *File) Seek(offset int64, whence int) (int64, error) {
if f.appendedF != nil {
if f.appendedFileReader == nil {
return 0, &os.PathError{
Op: "seek",
Path: filepath.Base(f.appendedF.zipFile.Name),
Err: errors.New("file is closed"),
}
}
return f.appendedFileReader.Seek(offset, whence)
}
if f.virtualF != nil {
return f.virtualF.seek(offset, whence)
}
if f.virtualD != nil {
return f.virtualD.seek(offset, whence)
}
return f.realF.Seek(offset, whence)
}

View File

@ -1,21 +0,0 @@
package rice
import (
"net/http"
)
// HTTPBox implements http.FileSystem which allows the use of Box with a http.FileServer.
// e.g.: http.Handle("/", http.FileServer(rice.MustFindBox("http-files").HTTPBox()))
type HTTPBox struct {
*Box
}
// HTTPBox creates a new HTTPBox from an existing Box
func (b *Box) HTTPBox() *HTTPBox {
return &HTTPBox{b}
}
// Open returns a File using the http.File interface
func (hb *HTTPBox) Open(name string) (http.File, error) {
return hb.Box.Open(name)
}

View File

@ -1,157 +0,0 @@
package main
import (
"archive/zip"
"fmt"
"go/build"
"io"
"os"
"path/filepath"
"strings"
"time"
zipexe "github.com/daaku/go.zipexe"
)
func operationAppend(pkgs []*build.Package) {
// create tmp zipfile
tmpZipfileName := filepath.Join(os.TempDir(), fmt.Sprintf("ricebox-%d-%s.zip", time.Now().Unix(), randomString(10)))
verbosef("Will create tmp zipfile: %s\n", tmpZipfileName)
tmpZipfile, err := os.Create(tmpZipfileName)
if err != nil {
fmt.Printf("Error creating tmp zipfile: %s\n", err)
os.Exit(1)
}
defer func() {
tmpZipfile.Close()
os.Remove(tmpZipfileName)
}()
// find abs path for binary file
binfileName, err := filepath.Abs(flags.Append.Executable)
if err != nil {
fmt.Printf("Error finding absolute path for executable to append: %s\n", err)
os.Exit(1)
}
verbosef("Will append to file: %s\n", binfileName)
// check that command doesn't already have zip appended
if rd, _ := zipexe.Open(binfileName); rd != nil {
fmt.Printf("Cannot append to already appended executable. Please remove %s and build a fresh one.\n", binfileName)
os.Exit(1)
}
// open binfile
binfile, err := os.OpenFile(binfileName, os.O_WRONLY, os.ModeAppend)
if err != nil {
fmt.Printf("Error: unable to open executable file: %s\n", err)
os.Exit(1)
}
defer binfile.Close()
binfileInfo, err := binfile.Stat()
if err != nil {
fmt.Printf("Error: unable to stat executable file: %s\n", err)
os.Exit(1)
}
// create zip.Writer
zipWriter := zip.NewWriter(tmpZipfile)
// write the zip offset into the zip data
zipWriter.SetOffset(binfileInfo.Size())
for _, pkg := range pkgs {
// find boxes for this command
boxMap := findBoxes(pkg)
// notify user when no calls to rice.FindBox are made (is this an error and therefore os.Exit(1) ?
if len(boxMap) == 0 {
fmt.Printf("no calls to rice.FindBox() or rice.MustFindBox() found in import path `%s`\n", pkg.ImportPath)
continue
}
verbosef("\n")
for boxname := range boxMap {
appendedBoxName := strings.Replace(boxname, `/`, `-`, -1)
// walk box path's and insert files
boxPath := filepath.Clean(filepath.Join(pkg.Dir, boxname))
filepath.Walk(boxPath, func(path string, info os.FileInfo, err error) error {
if info == nil {
fmt.Printf("Error: box \"%s\" not found on disk\n", path)
os.Exit(1)
}
// create zipFilename
zipFileName := filepath.Join(appendedBoxName, strings.TrimPrefix(path, boxPath))
// write directories as empty file with comment "dir"
if info.IsDir() {
_, err := zipWriter.CreateHeader(&zip.FileHeader{
Name: zipFileName,
Comment: "dir",
})
if err != nil {
fmt.Printf("Error creating dir in tmp zip: %s\n", err)
os.Exit(1)
}
return nil
}
// create zipFileWriter
zipFileHeader, err := zip.FileInfoHeader(info)
if err != nil {
fmt.Printf("Error creating zip FileHeader: %v\n", err)
os.Exit(1)
}
zipFileHeader.Name = zipFileName
zipFileWriter, err := zipWriter.CreateHeader(zipFileHeader)
if err != nil {
fmt.Printf("Error creating file in tmp zip: %s\n", err)
os.Exit(1)
}
srcFile, err := os.Open(path)
if err != nil {
fmt.Printf("Error opening file to append: %s\n", err)
os.Exit(1)
}
_, err = io.Copy(zipFileWriter, srcFile)
if err != nil {
fmt.Printf("Error copying file contents to zip: %s\n", err)
os.Exit(1)
}
srcFile.Close()
return nil
})
}
}
err = zipWriter.Close()
if err != nil {
fmt.Printf("Error closing tmp zipfile: %s\n", err)
os.Exit(1)
}
err = tmpZipfile.Sync()
if err != nil {
fmt.Printf("Error syncing tmp zipfile: %s\n", err)
os.Exit(1)
}
_, err = tmpZipfile.Seek(0, 0)
if err != nil {
fmt.Printf("Error seeking tmp zipfile: %s\n", err)
os.Exit(1)
}
_, err = binfile.Seek(0, 2)
if err != nil {
fmt.Printf("Error seeking bin file: %s\n", err)
os.Exit(1)
}
_, err = io.Copy(binfile, tmpZipfile)
if err != nil {
fmt.Printf("Error appending zipfile to executable: %s\n", err)
os.Exit(1)
}
}

View File

@ -1,33 +0,0 @@
package main
import (
"fmt"
"go/build"
"os"
"path/filepath"
"strings"
)
func operationClean(pkg *build.Package) {
filepath.Walk(pkg.Dir, func(filename string, info os.FileInfo, err error) error {
if err != nil {
fmt.Printf("error walking pkg dir to clean files: %v\n", err)
os.Exit(1)
}
if info.IsDir() {
return nil
}
verbosef("checking file '%s'\n", filename)
if filepath.Base(filename) == "rice-box.go" ||
strings.HasSuffix(filename, ".rice-box.go") ||
strings.HasSuffix(filename, ".rice-box.syso") {
err := os.Remove(filename)
if err != nil {
fmt.Printf("error removing file (%s): %s\n", filename, err)
os.Exit(-1)
}
verbosef("removed file '%s'\n", filename)
}
return nil
})
}

View File

@ -1,161 +0,0 @@
package main
import (
"bytes"
"fmt"
"go/build"
"go/format"
"io"
"io/ioutil"
"log"
"os"
"path/filepath"
"strings"
)
const boxFilename = "rice-box.go"
func writeBoxesGo(pkg *build.Package, out io.Writer) error {
boxMap := findBoxes(pkg)
// notify user when no calls to rice.FindBox are made (is this an error and therefore os.Exit(1) ?
if len(boxMap) == 0 {
fmt.Println("no calls to rice.FindBox() found")
return nil
}
verbosef("\n")
var boxes []*boxDataType
for boxname := range boxMap {
// find path and filename for this box
boxPath := filepath.Join(pkg.Dir, boxname)
// Check to see if the path for the box is a symbolic link. If so, simply
// box what the symbolic link points to. Note: the filepath.Walk function
// will NOT follow any nested symbolic links. This only handles the case
// where the root of the box is a symbolic link.
symPath, serr := os.Readlink(boxPath)
if serr == nil {
boxPath = symPath
}
// verbose info
verbosef("embedding box '%s' to '%s'\n", boxname, boxFilename)
// read box metadata
boxInfo, ierr := os.Stat(boxPath)
if ierr != nil {
return fmt.Errorf("Error: unable to access box at %s\n", boxPath)
}
// create box datastructure (used by template)
box := &boxDataType{
BoxName: boxname,
UnixNow: boxInfo.ModTime().Unix(),
Files: make([]*fileDataType, 0),
Dirs: make(map[string]*dirDataType),
}
if !boxInfo.IsDir() {
return fmt.Errorf("Error: Box %s must point to a directory but points to %s instead\n",
boxname, boxPath)
}
// fill box datastructure with file data
err := filepath.Walk(boxPath, func(path string, info os.FileInfo, err error) error {
if err != nil {
return fmt.Errorf("error walking box: %s\n", err)
}
filename := strings.TrimPrefix(path, boxPath)
filename = strings.Replace(filename, "\\", "/", -1)
filename = strings.TrimPrefix(filename, "/")
if info.IsDir() {
dirData := &dirDataType{
Identifier: "dir" + nextIdentifier(),
FileName: filename,
ModTime: info.ModTime().Unix(),
ChildFiles: make([]*fileDataType, 0),
ChildDirs: make([]*dirDataType, 0),
}
verbosef("\tincludes dir: '%s'\n", dirData.FileName)
box.Dirs[dirData.FileName] = dirData
// add tree entry (skip for root, it'll create a recursion)
if dirData.FileName != "" {
pathParts := strings.Split(dirData.FileName, "/")
parentDir := box.Dirs[strings.Join(pathParts[:len(pathParts)-1], "/")]
parentDir.ChildDirs = append(parentDir.ChildDirs, dirData)
}
} else {
fileData := &fileDataType{
Identifier: "file" + nextIdentifier(),
FileName: filename,
ModTime: info.ModTime().Unix(),
}
verbosef("\tincludes file: '%s'\n", fileData.FileName)
fileData.Content, err = ioutil.ReadFile(path)
if err != nil {
return fmt.Errorf("error reading file content while walking box: %s\n", err)
}
box.Files = append(box.Files, fileData)
// add tree entry
pathParts := strings.Split(fileData.FileName, "/")
parentDir := box.Dirs[strings.Join(pathParts[:len(pathParts)-1], "/")]
if parentDir == nil {
return fmt.Errorf("Error: parent of %s is not within the box\n", path)
}
parentDir.ChildFiles = append(parentDir.ChildFiles, fileData)
}
return nil
})
if err != nil {
return err
}
boxes = append(boxes, box)
}
embedSourceUnformated := bytes.NewBuffer(make([]byte, 0))
// execute template to buffer
err := tmplEmbeddedBox.Execute(
embedSourceUnformated,
embedFileDataType{pkg.Name, boxes},
)
if err != nil {
return fmt.Errorf("error writing embedded box to file (template execute): %s\n", err)
}
// format the source code
embedSource, err := format.Source(embedSourceUnformated.Bytes())
if err != nil {
return fmt.Errorf("error formatting embedSource: %s\n", err)
}
// write source to file
_, err = io.Copy(out, bytes.NewBuffer(embedSource))
if err != nil {
return fmt.Errorf("error writing embedSource to file: %s\n", err)
}
return nil
}
func operationEmbedGo(pkg *build.Package) {
// create go file for box
boxFile, err := os.Create(filepath.Join(pkg.Dir, boxFilename))
if err != nil {
log.Printf("error creating embedded box file: %s\n", err)
os.Exit(1)
}
defer boxFile.Close()
err = writeBoxesGo(pkg, boxFile)
if err != nil {
log.Printf("error creating embedded box file: %s\n", err)
os.Exit(1)
}
}

View File

@ -1,680 +0,0 @@
package main
import (
"bytes"
"fmt"
"go/ast"
"go/parser"
"go/token"
"path"
"path/filepath"
"strconv"
"strings"
"testing"
)
type registeredDir struct {
Filename string
ModTime int
ChildFiles []*registeredFile
ChildDirs []*registeredDir
}
type registeredFile struct {
Filename string
ModTime int
Content string
}
type registeredBox struct {
Name string
Time int
// key is path
Dirs map[string]*registeredDir
// key is path
Files map[string]*registeredFile
}
// isSimpleSelector returns true if expr is pkgName.ident
func isSimpleSelector(pkgName, ident string, expr ast.Expr) bool {
if sel, ok := expr.(*ast.SelectorExpr); ok {
if pkgIdent, ok := sel.X.(*ast.Ident); ok && pkgIdent.Name == pkgName && sel.Sel != nil && sel.Sel.Name == ident {
return true
}
}
return false
}
func isIdent(ident string, expr ast.Expr) bool {
if expr, ok := expr.(*ast.Ident); ok && expr.Name == ident {
return true
}
return false
}
func getIdentName(expr ast.Expr) (string, bool) {
if expr, ok := expr.(*ast.Ident); ok {
return expr.Name, true
}
return "", false
}
func getKey(expr *ast.KeyValueExpr) string {
if ident, ok := expr.Key.(*ast.Ident); ok {
return ident.Name
}
return ""
}
// parseModTime parses a time.Unix call, and returns the unix time.
func parseModTime(expr ast.Expr) (int, error) {
if expr, ok := expr.(*ast.CallExpr); ok {
if !isSimpleSelector("time", "Unix", expr.Fun) {
return 0, fmt.Errorf("ModTime is not time.Unix: %#v", expr.Fun)
}
if len(expr.Args) == 0 {
return 0, fmt.Errorf("not enough args to time.Unix")
}
arg0 := expr.Args[0]
if lit, ok := arg0.(*ast.BasicLit); ok && lit.Kind == token.INT {
return strconv.Atoi(lit.Value)
}
}
return 0, fmt.Errorf("not time.Unix: %#v", expr)
}
func parseString(expr ast.Expr) (string, error) {
if expr, ok := expr.(*ast.CallExpr); ok && isIdent("string", expr.Fun) && len(expr.Args) == 1 {
return parseString(expr.Args[0])
}
if lit, ok := expr.(*ast.BasicLit); ok && lit.Kind == token.STRING {
return strconv.Unquote(lit.Value)
}
return "", fmt.Errorf("not string: %#v", expr)
}
// parseDir parses an embedded.EmbeddedDir literal.
// It can be either a variable name or a composite literal.
// Returns nil if the literal is not embedded.EmbeddedDir.
func parseDir(expr ast.Expr, dirs map[string]*registeredDir, files map[string]*registeredFile) (*registeredDir, []error) {
if varName, ok := getIdentName(expr); ok {
dir, ok := dirs[varName]
if !ok {
return nil, []error{fmt.Errorf("unknown variable %v", varName)}
}
return dir, nil
}
lit, ok := expr.(*ast.CompositeLit)
if !ok {
return nil, []error{fmt.Errorf("dir is not a composite literal: %#v", expr)}
}
var errors []error
if !isSimpleSelector("embedded", "EmbeddedDir", lit.Type) {
return nil, nil
}
ret := &registeredDir{}
for _, el := range lit.Elts {
if el, ok := el.(*ast.KeyValueExpr); ok {
key := getKey(el)
if key == "" {
continue
}
switch key {
case "DirModTime":
var err error
ret.ModTime, err = parseModTime(el.Value)
if err != nil {
errors = append(errors, fmt.Errorf("DirModTime %s", err))
}
case "Filename":
var err error
ret.Filename, err = parseString(el.Value)
if err != nil {
errors = append(errors, fmt.Errorf("Filename %s", err))
}
case "ChildDirs":
var errors2 []error
ret.ChildDirs, errors2 = parseDirsSlice(el.Value, dirs, files)
errors = append(errors, errors2...)
case "ChildFiles":
var errors2 []error
ret.ChildFiles, errors2 = parseFilesSlice(el.Value, files)
errors = append(errors, errors2...)
default:
errors = append(errors, fmt.Errorf("Unknown field: %v: %#v", key, el.Value))
}
}
}
return ret, errors
}
// parseFile parses an embedded.EmbeddedFile literal.
// It can be either a variable name or a composite literal.
// Returns nil if the literal is not embedded.EmbeddedFile.
func parseFile(expr ast.Expr, files map[string]*registeredFile) (*registeredFile, []error) {
if varName, ok := getIdentName(expr); ok {
file, ok := files[varName]
if !ok {
return nil, []error{fmt.Errorf("unknown variable %v", varName)}
}
return file, nil
}
lit, ok := expr.(*ast.CompositeLit)
if !ok {
return nil, []error{fmt.Errorf("file is not a composite literal: %#v", expr)}
}
var errors []error
if !isSimpleSelector("embedded", "EmbeddedFile", lit.Type) {
return nil, nil
}
ret := &registeredFile{}
for _, el := range lit.Elts {
if el, ok := el.(*ast.KeyValueExpr); ok {
key := getKey(el)
if key == "" {
continue
}
switch key {
case "FileModTime":
var err error
ret.ModTime, err = parseModTime(el.Value)
if err != nil {
errors = append(errors, fmt.Errorf("DirModTime %s", err))
}
case "Filename":
var err error
ret.Filename, err = parseString(el.Value)
if err != nil {
errors = append(errors, fmt.Errorf("Filename %s", err))
}
case "Content":
var err error
ret.Content, err = parseString(el.Value)
if err != nil {
errors = append(errors, fmt.Errorf("Content %s", err))
}
default:
errors = append(errors, fmt.Errorf("Unknown field: %v: %#v", key, el.Value))
}
}
}
return ret, errors
}
func parseRegistration(lit *ast.CompositeLit, dirs map[string]*registeredDir, files map[string]*registeredFile) (*registeredBox, []error) {
var errors []error
if !isSimpleSelector("embedded", "EmbeddedBox", lit.Type) {
return nil, nil
}
ret := &registeredBox{
Dirs: make(map[string]*registeredDir),
Files: make(map[string]*registeredFile),
}
for _, el := range lit.Elts {
if el, ok := el.(*ast.KeyValueExpr); ok {
key := getKey(el)
if key == "" {
continue
}
switch key {
case "Time":
var err error
ret.Time, err = parseModTime(el.Value)
if err != nil {
errors = append(errors, fmt.Errorf("Time %s", err))
}
case "Name":
var err error
ret.Name, err = parseString(el.Value)
if err != nil {
errors = append(errors, fmt.Errorf("Name %s", err))
}
case "Dirs":
var errors2 []error
ret.Dirs, errors2 = parseDirsMap(el.Value, dirs, files)
errors = append(errors, errors2...)
case "Files":
var errors2 []error
ret.Files, errors2 = parseFilesMap(el.Value, files)
errors = append(errors, errors2...)
default:
errors = append(errors, fmt.Errorf("Unknown field: %v: %#v", key, el.Value))
}
}
}
return ret, errors
}
func parseDirsSlice(expr ast.Expr, dirs map[string]*registeredDir, files map[string]*registeredFile) (childDirs []*registeredDir, errors []error) {
valid := false
lit, ok := expr.(*ast.CompositeLit)
if ok {
if arrType, ok := lit.Type.(*ast.ArrayType); ok {
if star, ok := arrType.Elt.(*ast.StarExpr); ok {
if isSimpleSelector("embedded", "EmbeddedDir", star.X) {
valid = true
}
}
}
}
if !valid {
return nil, []error{fmt.Errorf("not a []*embedded.EmbeddedDir: %#v", expr)}
}
for _, el := range lit.Elts {
child, childErrors := parseDir(el, dirs, files)
errors = append(errors, childErrors...)
childDirs = append(childDirs, child)
}
return
}
func parseFilesSlice(expr ast.Expr, files map[string]*registeredFile) (childFiles []*registeredFile, errors []error) {
valid := false
lit, ok := expr.(*ast.CompositeLit)
if ok {
if arrType, ok := lit.Type.(*ast.ArrayType); ok {
if star, ok := arrType.Elt.(*ast.StarExpr); ok {
if isSimpleSelector("embedded", "EmbeddedFile", star.X) {
valid = true
}
}
}
}
if !valid {
return nil, []error{fmt.Errorf("not a []*embedded.EmbeddedFile: %#v", expr)}
}
for _, el := range lit.Elts {
child, childErrors := parseFile(el, files)
errors = append(errors, childErrors...)
childFiles = append(childFiles, child)
}
return
}
func parseDirsMap(expr ast.Expr, dirs map[string]*registeredDir, files map[string]*registeredFile) (childDirs map[string]*registeredDir, errors []error) {
valid := false
lit, ok := expr.(*ast.CompositeLit)
if ok {
if mapType, ok := lit.Type.(*ast.MapType); ok {
if star, ok := mapType.Value.(*ast.StarExpr); ok {
if isSimpleSelector("embedded", "EmbeddedDir", star.X) && isIdent("string", mapType.Key) {
valid = true
}
}
}
}
if !valid {
return nil, []error{fmt.Errorf("not a map[string]*embedded.EmbeddedDir: %#v", expr)}
}
childDirs = make(map[string]*registeredDir)
for _, el := range lit.Elts {
kv, ok := el.(*ast.KeyValueExpr)
if !ok {
errors = append(errors, fmt.Errorf("not a KeyValueExpr: %#v", el))
continue
}
key, err := parseString(kv.Key)
if err != nil {
errors = append(errors, fmt.Errorf("key %s", err))
continue
}
child, childErrors := parseDir(kv.Value, dirs, files)
errors = append(errors, childErrors...)
childDirs[key] = child
}
return
}
func parseFilesMap(expr ast.Expr, files map[string]*registeredFile) (childFiles map[string]*registeredFile, errors []error) {
valid := false
lit, ok := expr.(*ast.CompositeLit)
if ok {
if mapType, ok := lit.Type.(*ast.MapType); ok {
if star, ok := mapType.Value.(*ast.StarExpr); ok {
if isSimpleSelector("embedded", "EmbeddedFile", star.X) && isIdent("string", mapType.Key) {
valid = true
}
}
}
}
if !valid {
return nil, []error{fmt.Errorf("not a map[string]*embedded.EmbeddedFile: %#v", expr)}
}
childFiles = make(map[string]*registeredFile)
for _, el := range lit.Elts {
kv, ok := el.(*ast.KeyValueExpr)
if !ok {
errors = append(errors, fmt.Errorf("not a KeyValueExpr: %#v", el))
continue
}
key, err := parseString(kv.Key)
if err != nil {
errors = append(errors, fmt.Errorf("key %s", err))
continue
}
child, childErrors := parseFile(kv.Value, files)
errors = append(errors, childErrors...)
childFiles[key] = child
}
return
}
// unpoint returns the expression expr points to
// if expr is a & unary expression.
func unpoint(expr ast.Expr) ast.Expr {
if expr, ok := expr.(*ast.UnaryExpr); ok {
if expr.Op == token.AND {
return expr.X
}
}
return expr
}
func validateBox(t *testing.T, box *registeredBox, files []sourceFile) {
dirsToBeChecked := make(map[string]struct{})
filesToBeChecked := make(map[string]string)
for _, file := range files {
if !strings.HasPrefix(file.Name, box.Name) {
continue
}
pathParts := strings.Split(file.Name, "/")
dirs := pathParts[:len(pathParts)-1]
dirPath := ""
for _, dir := range dirs {
if dir != box.Name {
dirPath = path.Join(dirPath, dir)
}
dirsToBeChecked[dirPath] = struct{}{}
}
filesToBeChecked[path.Join(dirPath, pathParts[len(pathParts)-1])] = string(file.Contents)
}
if len(box.Files) != len(filesToBeChecked) {
t.Errorf("box %v has incorrect number of files; expected %v, got %v", box.Name, len(filesToBeChecked), len(box.Files))
}
if len(box.Dirs) != len(dirsToBeChecked) {
t.Errorf("box %v has incorrect number of dirs; expected %v, got %v", box.Name, len(dirsToBeChecked), len(box.Dirs))
}
for name, content := range filesToBeChecked {
f, ok := box.Files[name]
if !ok {
t.Errorf("file %v not present in box %v", name, box.Name)
continue
}
if f.Filename != name {
t.Errorf("box %v: filename mismatch: key: %v; Filename: %v", box.Name, name, f.Filename)
}
if f.Content != content {
t.Errorf("box %v: file %v content does not match: got %v, expected %v", box.Name, name, f.Content, content)
}
dirPath, _ := path.Split(name)
dirPath = strings.TrimSuffix(dirPath, "/")
dir, ok := box.Dirs[dirPath]
if !ok {
t.Errorf("directory %v not present in box %v", dirPath, box.Name)
continue
}
found := false
for _, file := range dir.ChildFiles {
if file == f {
found = true
}
}
if !found {
t.Errorf("file %v not found in directory %v in box %v", name, dirPath, box.Name)
continue
}
}
for name := range dirsToBeChecked {
d, ok := box.Dirs[name]
if !ok {
t.Errorf("directory %v not present in box %v", name, box.Name)
continue
}
if d.Filename != name {
t.Errorf("box %v: filename mismatch: key: %v; Filename: %v", box.Name, name, d.Filename)
}
if name != "" {
dirPath, _ := path.Split(name)
dirPath = strings.TrimSuffix(dirPath, "/")
dir, ok := box.Dirs[dirPath]
if !ok {
t.Errorf("directory %v not present in box %v", dirPath, box.Name)
continue
}
found := false
for _, dir := range dir.ChildDirs {
if dir == d {
found = true
}
}
if !found {
t.Errorf("directory %v not found in directory %v in box %v", name, dirPath, box.Name)
continue
}
}
}
}
func TestEmbedGo(t *testing.T) {
sourceFiles := []sourceFile{
{
"boxes.go",
[]byte(`package main
import (
"github.com/GeertJohan/go.rice"
)
func main() {
rice.MustFindBox("foo")
}
`),
},
{
"foo/test1.txt",
[]byte(`This is test 1`),
},
{
"foo/test2.txt",
[]byte(`This is test 2`),
},
{
"foo/bar/test1.txt",
[]byte(`This is test 1 in bar`),
},
{
"foo/bar/baz/test1.txt",
[]byte(`This is test 1 in bar/baz`),
},
{
"foo/bar/baz/backtick`.txt",
[]byte(`Backtick filename`),
},
{
"foo/bar/baz/\"quote\".txt",
[]byte(`double quoted filename`),
},
{
"foo/bar/baz/'quote'.txt",
[]byte(`single quoted filename`),
},
{
"foo/`/`/`.txt",
[]byte(`Backticks everywhere!`),
},
{
"foo/new\nline",
[]byte("File with newline in name. Yes, this is possible."),
},
}
pkg, cleanup, err := setUpTestPkg("foobar", sourceFiles)
defer cleanup()
if err != nil {
t.Error(err)
return
}
var buffer bytes.Buffer
err = writeBoxesGo(pkg, &buffer)
if err != nil {
t.Error(err)
return
}
t.Logf("Generated file: \n%s", buffer.String())
fset := token.NewFileSet()
f, err := parser.ParseFile(fset, filepath.Join(pkg.Dir, "rice-box.go"), &buffer, 0)
if err != nil {
t.Error(err)
return
}
var initFunc *ast.FuncDecl
for _, decl := range f.Decls {
if decl, ok := decl.(*ast.FuncDecl); ok && decl.Name != nil && decl.Name.Name == "init" {
initFunc = decl
break
}
}
if initFunc == nil {
t.Fatal("init function not found in generated file")
}
if initFunc.Body == nil {
t.Fatal("init function has no body in generated file")
}
var registrations []*ast.CallExpr
directories := make(map[string]*registeredDir)
files := make(map[string]*registeredFile)
_ = directories
_ = files
for _, stmt := range initFunc.Body.List {
if stmt, ok := stmt.(*ast.ExprStmt); ok {
if call, ok := stmt.X.(*ast.CallExpr); ok {
registrations = append(registrations, call)
}
continue
}
if stmt, ok := stmt.(*ast.AssignStmt); ok {
for i, rhs := range stmt.Rhs {
// Rhs can be EmbeddedDir or EmbeddedFile.
var literal *ast.CompositeLit
literal, ok := unpoint(rhs).(*ast.CompositeLit)
if !ok {
continue
}
if lhs, ok := stmt.Lhs[i].(*ast.Ident); ok {
// variable
edir, direrrs := parseDir(literal, directories, files)
efile, fileerrs := parseFile(literal, files)
abort := false
for _, err := range direrrs {
t.Error("error while parsing dir: ", err)
abort = true
}
for _, err := range fileerrs {
t.Error("error while parsing file: ", err)
abort = true
}
if abort {
return
}
if edir == nil && efile == nil {
continue
}
if edir != nil {
directories[lhs.Name] = edir
} else {
files[lhs.Name] = efile
}
} else if lhs, ok := stmt.Lhs[i].(*ast.SelectorExpr); ok {
selName, ok := getIdentName(lhs.Sel)
if !ok || selName != "ChildDirs" {
continue
}
varName, ok := getIdentName(lhs.X)
if !ok {
t.Fatalf("cannot parse ChildDirs assignment: %#v", lhs)
}
dir, ok := directories[varName]
if !ok {
t.Fatalf("variable %v not found", varName)
}
var errors []error
dir.ChildDirs, errors = parseDirsSlice(rhs, directories, files)
abort := false
for _, err := range errors {
t.Errorf("error parsing child dirs: %s", err)
abort = true
}
if abort {
return
}
}
}
}
}
if len(registrations) == 0 {
t.Fatal("could not find registration of embedded box")
}
boxes := make(map[string]*registeredBox)
for _, call := range registrations {
if isSimpleSelector("embedded", "RegisterEmbeddedBox", call.Fun) {
if len(call.Args) != 2 {
t.Fatalf("incorrect arguments to embedded.RegisterEmbeddedBox: %#v", call.Args)
}
boxArg := unpoint(call.Args[1])
name, err := parseString(call.Args[0])
if err != nil {
t.Fatalf("first argument to embedded.RegisterEmbeddedBox incorrect: %s", err)
}
boxLit, ok := boxArg.(*ast.CompositeLit)
if !ok {
t.Fatalf("second argument to embedded.RegisterEmbeddedBox is not a composite literal: %#v", boxArg)
}
abort := false
box, errors := parseRegistration(boxLit, directories, files)
for _, err := range errors {
t.Error("error while parsing box: ", err)
abort = true
}
if abort {
return
}
if box == nil {
t.Fatalf("second argument to embedded.RegisterEmbeddedBox is not an embedded.EmbeddedBox: %#v", boxArg)
}
if box.Name != name {
t.Fatalf("first argument to embedded.RegisterEmbeddedBox is not the same as the name in the second argument: %v, %#v", name, boxArg)
}
boxes[name] = box
}
}
// Validate that all boxes are present.
if _, ok := boxes["foo"]; !ok {
t.Error("box \"foo\" not found")
}
for _, box := range boxes {
validateBox(t, box, sourceFiles)
}
}

View File

@ -1,204 +0,0 @@
package main
import (
"bytes"
"encoding/gob"
"fmt"
"go/build"
"io"
"io/ioutil"
"os"
"path/filepath"
"regexp"
"strings"
"text/template"
"github.com/GeertJohan/go.rice/embedded"
"github.com/akavel/rsrc/coff"
)
type sizedReader struct {
*bytes.Reader
}
func (s sizedReader) Size() int64 {
return int64(s.Len())
}
var tmplEmbeddedSysoHelper *template.Template
func init() {
var err error
tmplEmbeddedSysoHelper, err = template.New("embeddedSysoHelper").Parse(`package {{.Package}}
// ############# GENERATED CODE #####################
// ## This file was generated by the rice tool.
// ## Do not edit unless you know what you're doing.
// ##################################################
// extern char _bricebox_{{.Symname}}[], _ericebox_{{.Symname}};
// int get_{{.Symname}}_length() {
// return &_ericebox_{{.Symname}} - _bricebox_{{.Symname}};
// }
import "C"
import (
"bytes"
"encoding/gob"
"github.com/GeertJohan/go.rice/embedded"
"unsafe"
)
func init() {
ptr := unsafe.Pointer(&C._bricebox_{{.Symname}})
bts := C.GoBytes(ptr, C.get_{{.Symname}}_length())
embeddedBox := &embedded.EmbeddedBox{}
err := gob.NewDecoder(bytes.NewReader(bts)).Decode(embeddedBox)
if err != nil {
panic("error decoding embedded box: "+err.Error())
}
embeddedBox.Link()
embedded.RegisterEmbeddedBox(embeddedBox.Name, embeddedBox)
}`)
if err != nil {
panic("could not parse template embeddedSysoHelper: " + err.Error())
}
}
type embeddedSysoHelperData struct {
Package string
Symname string
}
func operationEmbedSyso(pkg *build.Package) {
regexpSynameReplacer := regexp.MustCompile(`[^a-z0-9_]`)
boxMap := findBoxes(pkg)
// notify user when no calls to rice.FindBox are made (is this an error and therefore os.Exit(1) ?
if len(boxMap) == 0 {
fmt.Println("no calls to rice.FindBox() found")
return
}
verbosef("\n")
for boxname := range boxMap {
// find path and filename for this box
boxPath := filepath.Join(pkg.Dir, boxname)
boxFilename := strings.Replace(boxname, "/", "-", -1)
boxFilename = strings.Replace(boxFilename, "..", "back", -1)
boxFilename = strings.Replace(boxFilename, ".", "-", -1)
// verbose info
verbosef("embedding box '%s'\n", boxname)
verbosef("\tto file %s\n", boxFilename)
// read box metadata
boxInfo, ierr := os.Stat(boxPath)
if ierr != nil {
fmt.Printf("Error: unable to access box at %s\n", boxPath)
os.Exit(1)
}
// create box datastructure (used by template)
box := &embedded.EmbeddedBox{
Name: boxname,
Time: boxInfo.ModTime(),
EmbedType: embedded.EmbedTypeSyso,
Files: make(map[string]*embedded.EmbeddedFile),
Dirs: make(map[string]*embedded.EmbeddedDir),
}
// fill box datastructure with file data
filepath.Walk(boxPath, func(path string, info os.FileInfo, err error) error {
if err != nil {
fmt.Printf("error walking box: %s\n", err)
os.Exit(1)
}
filename := strings.TrimPrefix(path, boxPath)
filename = strings.Replace(filename, "\\", "/", -1)
filename = strings.TrimPrefix(filename, "/")
if info.IsDir() {
embeddedDir := &embedded.EmbeddedDir{
Filename: filename,
DirModTime: info.ModTime(),
}
verbosef("\tincludes dir: '%s'\n", embeddedDir.Filename)
box.Dirs[embeddedDir.Filename] = embeddedDir
// add tree entry (skip for root, it'll create a recursion)
if embeddedDir.Filename != "" {
pathParts := strings.Split(embeddedDir.Filename, "/")
parentDir := box.Dirs[strings.Join(pathParts[:len(pathParts)-1], "/")]
parentDir.ChildDirs = append(parentDir.ChildDirs, embeddedDir)
}
} else {
embeddedFile := &embedded.EmbeddedFile{
Filename: filename,
FileModTime: info.ModTime(),
Content: "",
}
verbosef("\tincludes file: '%s'\n", embeddedFile.Filename)
contentBytes, err := ioutil.ReadFile(path)
if err != nil {
fmt.Printf("error reading file content while walking box: %s\n", err)
os.Exit(1)
}
embeddedFile.Content = string(contentBytes)
box.Files[embeddedFile.Filename] = embeddedFile
}
return nil
})
// encode embedded box to gob file
boxGobBuf := &bytes.Buffer{}
err := gob.NewEncoder(boxGobBuf).Encode(box)
if err != nil {
fmt.Printf("error encoding box to gob: %v\n", err)
os.Exit(1)
}
verbosef("gob-encoded embeddedBox is %d bytes large\n", boxGobBuf.Len())
// write coff
symname := regexpSynameReplacer.ReplaceAllString(boxname, "_")
createCoffSyso(boxname, symname, "386", boxGobBuf.Bytes())
createCoffSyso(boxname, symname, "amd64", boxGobBuf.Bytes())
// write go
sysoHelperData := embeddedSysoHelperData{
Package: pkg.Name,
Symname: symname,
}
fileSysoHelper, err := os.Create(boxFilename + ".rice-box.go")
if err != nil {
fmt.Printf("error creating syso helper: %v\n", err)
os.Exit(1)
}
err = tmplEmbeddedSysoHelper.Execute(fileSysoHelper, sysoHelperData)
if err != nil {
fmt.Printf("error executing tmplEmbeddedSysoHelper: %v\n", err)
os.Exit(1)
}
}
}
func createCoffSyso(boxFilename string, symname string, arch string, data []byte) {
boxCoff := coff.NewRDATA()
switch arch {
case "386":
case "amd64":
boxCoff.FileHeader.Machine = 0x8664
default:
panic("invalid arch")
}
boxCoff.AddData("_bricebox_"+symname, sizedReader{bytes.NewReader(data)})
boxCoff.AddData("_ericebox_"+symname, io.NewSectionReader(strings.NewReader("\000\000"), 0, 2)) // TODO: why? copied from rsrc, which copied it from as-generated
boxCoff.Freeze()
err := writeCoff(boxCoff, boxFilename+"_"+arch+".rice-box.syso")
if err != nil {
fmt.Printf("error writing %s coff/.syso: %v\n", arch, err)
os.Exit(1)
}
}

View File

@ -1,150 +0,0 @@
package main
import (
"fmt"
"go/ast"
"go/build"
"go/parser"
"go/token"
"os"
"path/filepath"
"strings"
)
func badArgument(fileset *token.FileSet, p token.Pos) {
pos := fileset.Position(p)
filename := pos.Filename
base, err := os.Getwd()
if err == nil {
rpath, perr := filepath.Rel(base, pos.Filename)
if perr == nil {
filename = rpath
}
}
msg := fmt.Sprintf("%s:%d: Error: found call to rice.FindBox, "+
"but argument must be a string literal.\n", filename, pos.Line)
fmt.Println(msg)
os.Exit(1)
}
func findBoxes(pkg *build.Package) map[string]bool {
// create map of boxes to embed
var boxMap = make(map[string]bool)
// create one list of files for this package
filenames := make([]string, 0, len(pkg.GoFiles)+len(pkg.CgoFiles))
filenames = append(filenames, pkg.GoFiles...)
filenames = append(filenames, pkg.CgoFiles...)
// loop over files, search for rice.FindBox(..) calls
for _, filename := range filenames {
// find full filepath
fullpath := filepath.Join(pkg.Dir, filename)
if strings.HasSuffix(filename, "rice-box.go") {
// Ignore *.rice-box.go files
verbosef("skipping file %q\n", fullpath)
continue
}
verbosef("scanning file %q\n", fullpath)
fset := token.NewFileSet()
f, err := parser.ParseFile(fset, fullpath, nil, 0)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
var riceIsImported bool
ricePkgName := "rice"
for _, imp := range f.Imports {
if strings.HasSuffix(imp.Path.Value, "go.rice\"") {
if imp.Name != nil {
ricePkgName = imp.Name.Name
}
riceIsImported = true
break
}
}
if !riceIsImported {
// Rice wasn't imported, so we won't find a box.
continue
}
if ricePkgName == "_" {
// Rice pkg is unnamed, so we won't find a box.
continue
}
// Inspect AST, looking for calls to (Must)?FindBox.
// First parameter of the func must be a basic literal.
// Identifiers won't be resolved.
var nextIdentIsBoxFunc bool
var nextBasicLitParamIsBoxName bool
var boxCall token.Pos
var variableToRemember string
var validVariablesForBoxes map[string]bool = make(map[string]bool)
ast.Inspect(f, func(node ast.Node) bool {
if node == nil {
return false
}
switch x := node.(type) {
// this case fixes the var := func() style assignments, not assignments to vars declared separately from the assignment.
case *ast.AssignStmt:
var assign = node.(*ast.AssignStmt)
name, found := assign.Lhs[0].(*ast.Ident)
if found {
variableToRemember = name.Name
composite, first := assign.Rhs[0].(*ast.CompositeLit)
if first {
riceSelector, second := composite.Type.(*ast.SelectorExpr)
if second {
callCorrect := riceSelector.Sel.Name == "Config"
packageName, third := riceSelector.X.(*ast.Ident)
if third && callCorrect && packageName.Name == ricePkgName {
validVariablesForBoxes[name.Name] = true
verbosef("\tfound variable, saving to scan for boxes: %q\n", name.Name)
}
}
}
}
case *ast.Ident:
if nextIdentIsBoxFunc || ricePkgName == "." {
nextIdentIsBoxFunc = false
if x.Name == "FindBox" || x.Name == "MustFindBox" {
nextBasicLitParamIsBoxName = true
boxCall = x.Pos()
}
} else {
if x.Name == ricePkgName || validVariablesForBoxes[x.Name] {
nextIdentIsBoxFunc = true
}
}
case *ast.BasicLit:
if nextBasicLitParamIsBoxName {
if x.Kind == token.STRING {
nextBasicLitParamIsBoxName = false
// trim "" or ``
name := x.Value[1 : len(x.Value)-1]
boxMap[name] = true
verbosef("\tfound box %q\n", name)
} else {
badArgument(fset, boxCall)
}
}
default:
if nextIdentIsBoxFunc {
nextIdentIsBoxFunc = false
}
if nextBasicLitParamIsBoxName {
badArgument(fset, boxCall)
}
}
return true
})
}
return boxMap
}

View File

@ -1,302 +0,0 @@
package main
import (
"fmt"
"go/build"
"io/ioutil"
"os"
"path/filepath"
"testing"
)
type sourceFile struct {
Name string
Contents []byte
}
func expectBoxes(expected []string, actual map[string]bool) error {
if len(expected) != len(actual) {
return fmt.Errorf("expected %v, got %v", expected, actual)
}
for _, box := range expected {
if _, ok := actual[box]; !ok {
return fmt.Errorf("expected %v, got %v", expected, actual)
}
}
return nil
}
func setUpTestPkg(pkgName string, files []sourceFile) (*build.Package, func(), error) {
temp, err := ioutil.TempDir("", "go.rice-test")
if err != nil {
return nil, func() {}, err
}
cleanup := func() {
os.RemoveAll(temp)
}
dir := filepath.Join(temp, pkgName)
if err := os.Mkdir(dir, 0770); err != nil {
return nil, cleanup, err
}
for _, f := range files {
fullPath := filepath.Join(dir, f.Name)
if err := os.MkdirAll(filepath.Dir(fullPath), 0770); err != nil {
return nil, cleanup, err
}
if err := ioutil.WriteFile(fullPath, f.Contents, 0660); err != nil {
return nil, cleanup, err
}
}
pkg, err := build.ImportDir(dir, 0)
return pkg, cleanup, err
}
func TestFindOneBox(t *testing.T) {
pkg, cleanup, err := setUpTestPkg("foobar", []sourceFile{
{
"boxes.go",
[]byte(`package main
import (
"github.com/GeertJohan/go.rice"
)
func main() {
rice.MustFindBox("foo")
}
`),
},
})
defer cleanup()
if err != nil {
t.Error(err)
return
}
expectedBoxes := []string{"foo"}
boxMap := findBoxes(pkg)
if err := expectBoxes(expectedBoxes, boxMap); err != nil {
t.Error(err)
}
}
func TestFindOneBoxViaVariable(t *testing.T) {
pkg, cleanup, err := setUpTestPkg("foobar", []sourceFile{
{
"boxes.go",
[]byte(`package main
import (
"github.com/GeertJohan/go.rice"
)
func main() {
conf := rice.Config{
LocateOrder: []rice.LocateMethod{rice.LocateEmbedded, rice.LocateAppended, rice.LocateFS},
}
conf.MustFindBox("foo")
}
`),
},
})
defer cleanup()
if err != nil {
t.Error(err)
return
}
expectedBoxes := []string{"foo"}
boxMap := findBoxes(pkg)
if err := expectBoxes(expectedBoxes, boxMap); err != nil {
t.Error(err)
}
}
func TestFindMultipleBoxes(t *testing.T) {
pkg, cleanup, err := setUpTestPkg("foobar", []sourceFile{
{
"boxes.go",
[]byte(`package main
import (
"github.com/GeertJohan/go.rice"
)
func main() {
rice.MustFindBox("foo")
rice.MustFindBox("bar")
}
`),
},
})
defer cleanup()
if err != nil {
t.Error(err)
return
}
expectedBoxes := []string{"foo", "bar"}
boxMap := findBoxes(pkg)
if err := expectBoxes(expectedBoxes, boxMap); err != nil {
t.Error(err)
}
}
func TestNoBoxFoundIfRiceNotImported(t *testing.T) {
pkg, cleanup, err := setUpTestPkg("foobar", []sourceFile{
{
"boxes.go",
[]byte(`package main
type fakerice struct {}
func (fr fakerice) FindBox(s string) {
}
func main() {
rice := fakerice{}
rice.FindBox("foo")
}
`),
},
})
defer cleanup()
if err != nil {
t.Error(err)
return
}
boxMap := findBoxes(pkg)
if _, ok := boxMap["foo"]; ok {
t.Errorf("Unexpected box %q was found", "foo")
}
}
func TestUnrelatedBoxesAreNotFound(t *testing.T) {
pkg, cleanup, err := setUpTestPkg("foobar", []sourceFile{
{
"boxes.go",
[]byte(`package foobar
import (
_ "github.com/GeertJohan/go.rice"
)
type fakerice struct {}
func (fr fakerice) FindBox(s string) {
}
func FindBox(s string) {
}
func LoadBoxes() {
rice := fakerice{}
rice.FindBox("foo")
FindBox("bar")
}
`),
},
})
defer cleanup()
if err != nil {
t.Error(err)
return
}
boxMap := findBoxes(pkg)
for _, box := range []string{"foo", "bar"} {
if _, ok := boxMap[box]; ok {
t.Errorf("Unexpected box %q was found", box)
}
}
}
func TestMixGoodAndBadBoxes(t *testing.T) {
pkg, cleanup, err := setUpTestPkg("foobar", []sourceFile{
{
"boxes1.go",
[]byte(`package foobar
import (
_ "github.com/GeertJohan/go.rice"
)
type fakerice struct {}
func (fr fakerice) FindBox(s string) {
}
func FindBox(s string) {
}
func LoadBoxes1() {
rice := fakerice{}
rice.FindBox("foo")
FindBox("bar")
}
`),
},
{
"boxes2.go",
[]byte(`package foobar
import (
noodles "github.com/GeertJohan/go.rice"
)
func LoadBoxes2() {
FindBox("baz")
noodles.FindBox("veggies")
}
`),
},
{
"boxes3.go",
[]byte(`package foobar
import (
"github.com/GeertJohan/go.rice"
)
func LoadBoxes3() {
rice.FindBox("fish")
}
`),
},
{
"boxes4.go",
[]byte(`package foobar
import (
. "github.com/GeertJohan/go.rice"
)
func LoadBoxes3() {
MustFindBox("chicken")
}
`),
},
})
defer cleanup()
if err != nil {
t.Error(err)
return
}
boxMap := findBoxes(pkg)
for _, box := range []string{"foo", "bar", "baz"} {
if _, ok := boxMap[box]; ok {
t.Errorf("Unexpected box %q was found", box)
}
}
for _, box := range []string{"veggies", "fish", "chicken"} {
if _, ok := boxMap[box]; !ok {
t.Errorf("Expected box %q not found", box)
}
}
}

View File

@ -1,80 +0,0 @@
package main
import (
"fmt"
"go/build"
"os"
goflags "github.com/jessevdk/go-flags" // rename import to `goflags` (file scope) so we can use `var flags` (package scope)
)
// flags
var flags struct {
Verbose bool `long:"verbose" short:"v" description:"Show verbose debug information"`
ImportPaths []string `long:"import-path" short:"i" description:"Import path(s) to use. Using PWD when left empty. Specify multiple times for more import paths to append"`
Append struct {
Executable string `long:"exec" description:"Executable to append" required:"true"`
} `command:"append"`
EmbedGo struct{} `command:"embed-go" alias:"embed"`
EmbedSyso struct{} `command:"embed-syso"`
Clean struct{} `command:"clean"`
}
// flags parser
var flagsParser *goflags.Parser
// initFlags parses the given flags.
// when the user asks for help (-h or --help): the application exists with status 0
// when unexpected flags is given: the application exits with status 1
func parseArguments() {
// create flags parser in global var, for flagsParser.Active.Name (operation)
flagsParser = goflags.NewParser(&flags, goflags.Default)
// parse flags
args, err := flagsParser.Parse()
if err != nil {
// assert the err to be a flags.Error
flagError := err.(*goflags.Error)
if flagError.Type == goflags.ErrHelp {
// user asked for help on flags.
// program can exit successfully
os.Exit(0)
}
if flagError.Type == goflags.ErrUnknownFlag {
fmt.Println("Use --help to view available options.")
os.Exit(1)
}
if flagError.Type == goflags.ErrRequired {
os.Exit(1)
}
fmt.Printf("Error parsing flags: %s\n", err)
os.Exit(1)
}
// error on left-over arguments
if len(args) > 0 {
fmt.Printf("Unexpected arguments: %s\nUse --help to view available options.", args)
os.Exit(1)
}
// default ImportPath to pwd when not set
if len(flags.ImportPaths) == 0 {
pwd, err := os.Getwd()
if err != nil {
fmt.Printf("error getting pwd: %s\n", err)
os.Exit(1)
}
verbosef("using pwd as import path\n")
// find non-absolute path for this pwd
pkg, err := build.ImportDir(pwd, build.FindOnly)
if err != nil {
fmt.Printf("error using current directory as import path: %s\n", err)
os.Exit(1)
}
flags.ImportPaths = append(flags.ImportPaths, pkg.ImportPath)
verbosef("using import paths: %s\n", flags.ImportPaths)
return
}
}

View File

@ -1,14 +0,0 @@
package main
import (
"strconv"
"github.com/GeertJohan/go.incremental"
)
var identifierCount incremental.Uint64
func nextIdentifier() string {
num := identifierCount.Next()
return strconv.FormatUint(num, 36) // 0123456789abcdefghijklmnopqrstuvwxyz
}

View File

@ -1,68 +0,0 @@
package main
import (
"fmt"
"go/build"
"log"
"os"
)
func main() {
// parser arguments
parseArguments()
// find package for path
var pkgs []*build.Package
for _, importPath := range flags.ImportPaths {
pkg := pkgForPath(importPath)
pkgs = append(pkgs, pkg)
}
// switch on the operation to perform
switch flagsParser.Active.Name {
case "embed", "embed-go":
for _, pkg := range pkgs {
operationEmbedGo(pkg)
}
case "embed-syso":
log.Println("WARNING: embedding .syso is experimental..")
for _, pkg := range pkgs {
operationEmbedSyso(pkg)
}
case "append":
operationAppend(pkgs)
case "clean":
for _, pkg := range pkgs {
operationClean(pkg)
}
}
// all done
verbosef("\n")
verbosef("rice finished successfully\n")
}
// helper function to get *build.Package for given path
func pkgForPath(path string) *build.Package {
// get pwd for relative imports
pwd, err := os.Getwd()
if err != nil {
fmt.Printf("error getting pwd (required for relative imports): %s\n", err)
os.Exit(1)
}
// read full package information
pkg, err := build.Import(path, pwd, 0)
if err != nil {
fmt.Printf("error reading package: %s\n", err)
os.Exit(1)
}
return pkg
}
func verbosef(format string, stuff ...interface{}) {
if flags.Verbose {
log.Printf(format, stuff...)
}
}

View File

@ -1,98 +0,0 @@
package main
import (
"fmt"
"os"
"text/template"
)
var tmplEmbeddedBox *template.Template
func init() {
var err error
// parse embedded box template
tmplEmbeddedBox, err = template.New("embeddedBox").Parse(`package {{.Package}}
import (
"github.com/GeertJohan/go.rice/embedded"
"time"
)
{{range .Boxes}}
func init() {
// define files
{{range .Files}}{{.Identifier}} := &embedded.EmbeddedFile{
Filename: {{.FileName | printf "%q"}},
FileModTime: time.Unix({{.ModTime}}, 0),
Content: string({{.Content | printf "%q"}}),
}
{{end}}
// define dirs
{{range .Dirs}}{{.Identifier}} := &embedded.EmbeddedDir{
Filename: {{.FileName | printf "%q"}},
DirModTime: time.Unix({{.ModTime}}, 0),
ChildFiles: []*embedded.EmbeddedFile{
{{range .ChildFiles}}{{.Identifier}}, // {{.FileName | printf "%q"}}
{{end}}
},
}
{{end}}
// link ChildDirs
{{range .Dirs}}{{.Identifier}}.ChildDirs = []*embedded.EmbeddedDir{
{{range .ChildDirs}}{{.Identifier}}, // {{.FileName | printf "%q"}}
{{end}}
}
{{end}}
// register embeddedBox
embedded.RegisterEmbeddedBox(` + "`" + `{{.BoxName}}` + "`" + `, &embedded.EmbeddedBox{
Name: ` + "`" + `{{.BoxName}}` + "`" + `,
Time: time.Unix({{.UnixNow}}, 0),
Dirs: map[string]*embedded.EmbeddedDir{
{{range .Dirs}}{{.FileName | printf "%q"}}: {{.Identifier}},
{{end}}
},
Files: map[string]*embedded.EmbeddedFile{
{{range .Files}}{{.FileName | printf "%q"}}: {{.Identifier}},
{{end}}
},
})
}
{{end}}`)
if err != nil {
fmt.Printf("error parsing embedded box template: %s\n", err)
os.Exit(-1)
}
}
type embedFileDataType struct {
Package string
Boxes []*boxDataType
}
type boxDataType struct {
BoxName string
UnixNow int64
Files []*fileDataType
Dirs map[string]*dirDataType
}
type fileDataType struct {
Identifier string
FileName string
Content []byte
ModTime int64
}
type dirDataType struct {
Identifier string
FileName string
Content []byte
ModTime int64
ChildDirs []*dirDataType
ChildFiles []*fileDataType
}

View File

@ -1,22 +0,0 @@
package main
import (
"math/rand"
"time"
)
// randomString generates a pseudo-random alpha-numeric string with given length.
func randomString(length int) string {
rand.Seed(time.Now().UnixNano())
k := make([]rune, length)
for i := 0; i < length; i++ {
c := rand.Intn(35)
if c < 10 {
c += 48 // numbers (0-9) (0+48 == 48 == '0', 9+48 == 57 == '9')
} else {
c += 87 // lower case alphabets (a-z) (10+87 == 97 == 'a', 35+87 == 122 = 'z')
}
k[i] = rune(c)
}
return string(k)
}

View File

@ -1,42 +0,0 @@
package main
import (
"fmt"
"os"
"reflect"
"github.com/akavel/rsrc/binutil"
"github.com/akavel/rsrc/coff"
)
// copied from github.com/akavel/rsrc
// LICENSE: MIT
// Copyright 2013-2014 The rsrc Authors. (https://github.com/akavel/rsrc/blob/master/AUTHORS)
func writeCoff(coff *coff.Coff, fnameout string) error {
out, err := os.Create(fnameout)
if err != nil {
return err
}
defer out.Close()
w := binutil.Writer{W: out}
// write the resulting file to disk
binutil.Walk(coff, func(v reflect.Value, path string) error {
if binutil.Plain(v.Kind()) {
w.WriteLE(v.Interface())
return nil
}
vv, ok := v.Interface().(binutil.SizedReader)
if ok {
w.WriteFromSized(vv)
return binutil.WALK_SKIP
}
return nil
})
if w.Err != nil {
return fmt.Errorf("Error writing output file: %s", w.Err)
}
return nil
}

View File

@ -1,19 +0,0 @@
package rice
import "os"
// SortByName allows an array of os.FileInfo objects
// to be easily sorted by filename using sort.Sort(SortByName(array))
type SortByName []os.FileInfo
func (f SortByName) Len() int { return len(f) }
func (f SortByName) Less(i, j int) bool { return f[i].Name() < f[j].Name() }
func (f SortByName) Swap(i, j int) { f[i], f[j] = f[j], f[i] }
// SortByModified allows an array of os.FileInfo objects
// to be easily sorted by modified date using sort.Sort(SortByModified(array))
type SortByModified []os.FileInfo
func (f SortByModified) Len() int { return len(f) }
func (f SortByModified) Less(i, j int) bool { return f[i].ModTime().Unix() > f[j].ModTime().Unix() }
func (f SortByModified) Swap(i, j int) { f[i], f[j] = f[j], f[i] }

View File

@ -1,252 +0,0 @@
package rice
import (
"errors"
"io"
"os"
"path/filepath"
"sort"
"github.com/GeertJohan/go.rice/embedded"
)
//++ TODO: IDEA: merge virtualFile and virtualDir, this decreases work done by rice.File
// Error indicating some function is not implemented yet (but available to satisfy an interface)
var ErrNotImplemented = errors.New("not implemented yet")
// virtualFile is a 'stateful' virtual file.
// virtualFile wraps an *EmbeddedFile for a call to Box.Open() and virtualizes 'read cursor' (offset) and 'closing'.
// virtualFile is only internally visible and should be exposed through rice.File
type virtualFile struct {
*embedded.EmbeddedFile // the actual embedded file, embedded to obtain methods
offset int64 // read position on the virtual file
closed bool // closed when true
}
// create a new virtualFile for given EmbeddedFile
func newVirtualFile(ef *embedded.EmbeddedFile) *virtualFile {
vf := &virtualFile{
EmbeddedFile: ef,
offset: 0,
closed: false,
}
return vf
}
//++ TODO check for nil pointers in all these methods. When so: return os.PathError with Err: os.ErrInvalid
func (vf *virtualFile) close() error {
if vf.closed {
return &os.PathError{
Op: "close",
Path: vf.EmbeddedFile.Filename,
Err: errors.New("already closed"),
}
}
vf.EmbeddedFile = nil
vf.closed = true
return nil
}
func (vf *virtualFile) stat() (os.FileInfo, error) {
if vf.closed {
return nil, &os.PathError{
Op: "stat",
Path: vf.EmbeddedFile.Filename,
Err: errors.New("bad file descriptor"),
}
}
return (*embeddedFileInfo)(vf.EmbeddedFile), nil
}
func (vf *virtualFile) readdir(count int) ([]os.FileInfo, error) {
if vf.closed {
return nil, &os.PathError{
Op: "readdir",
Path: vf.EmbeddedFile.Filename,
Err: errors.New("bad file descriptor"),
}
}
//TODO: return proper error for a readdir() call on a file
return nil, ErrNotImplemented
}
func (vf *virtualFile) read(bts []byte) (int, error) {
if vf.closed {
return 0, &os.PathError{
Op: "read",
Path: vf.EmbeddedFile.Filename,
Err: errors.New("bad file descriptor"),
}
}
end := vf.offset + int64(len(bts))
if end >= int64(len(vf.Content)) {
// end of file, so return what we have + EOF
n := copy(bts, vf.Content[vf.offset:])
vf.offset = 0
return n, io.EOF
}
n := copy(bts, vf.Content[vf.offset:end])
vf.offset += int64(n)
return n, nil
}
func (vf *virtualFile) seek(offset int64, whence int) (int64, error) {
if vf.closed {
return 0, &os.PathError{
Op: "seek",
Path: vf.EmbeddedFile.Filename,
Err: errors.New("bad file descriptor"),
}
}
var e error
//++ TODO: check if this is correct implementation for seek
switch whence {
case os.SEEK_SET:
//++ check if new offset isn't out of bounds, set e when it is, then break out of switch
vf.offset = offset
case os.SEEK_CUR:
//++ check if new offset isn't out of bounds, set e when it is, then break out of switch
vf.offset += offset
case os.SEEK_END:
//++ check if new offset isn't out of bounds, set e when it is, then break out of switch
vf.offset = int64(len(vf.EmbeddedFile.Content)) - offset
}
if e != nil {
return 0, &os.PathError{
Op: "seek",
Path: vf.Filename,
Err: e,
}
}
return vf.offset, nil
}
// virtualDir is a 'stateful' virtual directory.
// virtualDir wraps an *EmbeddedDir for a call to Box.Open() and virtualizes 'closing'.
// virtualDir is only internally visible and should be exposed through rice.File
type virtualDir struct {
*embedded.EmbeddedDir
offset int // readdir position on the directory
closed bool
}
// create a new virtualDir for given EmbeddedDir
func newVirtualDir(ed *embedded.EmbeddedDir) *virtualDir {
vd := &virtualDir{
EmbeddedDir: ed,
offset: 0,
closed: false,
}
return vd
}
func (vd *virtualDir) close() error {
//++ TODO: needs sync mutex?
if vd.closed {
return &os.PathError{
Op: "close",
Path: vd.EmbeddedDir.Filename,
Err: errors.New("already closed"),
}
}
vd.closed = true
return nil
}
func (vd *virtualDir) stat() (os.FileInfo, error) {
if vd.closed {
return nil, &os.PathError{
Op: "stat",
Path: vd.EmbeddedDir.Filename,
Err: errors.New("bad file descriptor"),
}
}
return (*embeddedDirInfo)(vd.EmbeddedDir), nil
}
func (vd *virtualDir) readdir(n int) (fi []os.FileInfo, err error) {
if vd.closed {
return nil, &os.PathError{
Op: "readdir",
Path: vd.EmbeddedDir.Filename,
Err: errors.New("bad file descriptor"),
}
}
// Build up the array of our contents
var files []os.FileInfo
// Add the child directories
for _, child := range vd.ChildDirs {
child.Filename = filepath.Base(child.Filename)
files = append(files, (*embeddedDirInfo)(child))
}
// Add the child files
for _, child := range vd.ChildFiles {
child.Filename = filepath.Base(child.Filename)
files = append(files, (*embeddedFileInfo)(child))
}
// Sort it by filename (lexical order)
sort.Sort(SortByName(files))
// Return all contents if that's what is requested
if n <= 0 {
vd.offset = 0
return files, nil
}
// If user has requested past the end of our list
// return what we can and send an EOF
if vd.offset+n >= len(files) {
offset := vd.offset
vd.offset = 0
return files[offset:], io.EOF
}
offset := vd.offset
vd.offset += n
return files[offset : offset+n], nil
}
func (vd *virtualDir) read(bts []byte) (int, error) {
if vd.closed {
return 0, &os.PathError{
Op: "read",
Path: vd.EmbeddedDir.Filename,
Err: errors.New("bad file descriptor"),
}
}
return 0, &os.PathError{
Op: "read",
Path: vd.EmbeddedDir.Filename,
Err: errors.New("is a directory"),
}
}
func (vd *virtualDir) seek(offset int64, whence int) (int64, error) {
if vd.closed {
return 0, &os.PathError{
Op: "seek",
Path: vd.EmbeddedDir.Filename,
Err: errors.New("bad file descriptor"),
}
}
return 0, &os.PathError{
Op: "seek",
Path: vd.Filename,
Err: errors.New("is a directory"),
}
}

View File

@ -1,122 +0,0 @@
package rice
import (
"os"
"path/filepath"
"sort"
"strings"
)
// Walk is like filepath.Walk()
// Visit http://golang.org/pkg/path/filepath/#Walk for more information
func (b *Box) Walk(path string, walkFn filepath.WalkFunc) error {
pathFile, err := b.Open(path)
if err != nil {
return err
}
defer pathFile.Close()
pathInfo, err := pathFile.Stat()
if err != nil {
return err
}
if b.IsAppended() || b.IsEmbedded() {
return b.walk(path, pathInfo, walkFn)
}
// We don't have any embedded or appended box so use live filesystem mode
return filepath.Walk(b.absolutePath+string(os.PathSeparator)+path, func(path string, info os.FileInfo, err error) error {
// Strip out the box name from the returned paths
path = strings.TrimPrefix(path, b.absolutePath+string(os.PathSeparator))
return walkFn(path, info, err)
})
}
// walk recursively descends path.
// See walk() in $GOROOT/src/pkg/path/filepath/path.go
func (b *Box) walk(path string, info os.FileInfo, walkFn filepath.WalkFunc) error {
err := walkFn(path, info, nil)
if err != nil {
if info.IsDir() && err == filepath.SkipDir {
return nil
}
return err
}
if !info.IsDir() {
return nil
}
names, err := b.readDirNames(path)
if err != nil {
return walkFn(path, info, err)
}
for _, name := range names {
filename := filepath.Join(path, name)
fileObject, err := b.Open(filename)
if err != nil {
return err
}
defer fileObject.Close()
fileInfo, err := fileObject.Stat()
if err != nil {
if err := walkFn(filename, fileInfo, err); err != nil && err != filepath.SkipDir {
return err
}
} else {
err = b.walk(filename, fileInfo, walkFn)
if err != nil {
if !fileInfo.IsDir() || err != filepath.SkipDir {
return err
}
}
}
}
return nil
}
// readDirNames reads the directory named by path and returns a sorted list of directory entries.
// See readDirNames() in $GOROOT/pkg/path/filepath/path.go
func (b *Box) readDirNames(path string) ([]string, error) {
f, err := b.Open(path)
if err != nil {
return nil, err
}
defer f.Close()
stat, err := f.Stat()
if err != nil {
return nil, err
}
if !stat.IsDir() {
return nil, nil
}
infos, err := f.Readdir(0)
if err != nil {
return nil, err
}
var names []string
for _, info := range infos {
names = append(names, info.Name())
}
sort.Strings(names)
return names, nil
}

View File

@ -1,56 +0,0 @@
package main
import (
"flag"
"fmt"
"log"
"os"
"path/filepath"
_ "github.com/Xe/gopreload"
)
var (
pkgName = flag.String("pkg", "", "package to underscore import")
destPkgName = flag.String("dest", "", "destination package to generate")
)
const codeTemplate = `//+build go1.8
package main
import _ "$PACKAGE_PATH"`
func main() {
flag.Parse()
if *pkgName == "" || *destPkgName == "" {
log.Fatal("must set -pkg and -dest")
}
srcDir := filepath.Join(os.Getenv("GOPATH"), "src", *destPkgName)
err := os.MkdirAll(srcDir, os.ModePerm)
if err != nil {
log.Fatal(err)
}
fout, err := os.Create(srcDir + "/main.go")
if err != nil {
log.Fatal(err)
}
defer fout.Close()
codeBody := os.Expand(codeTemplate, func(s string) string {
if s == "PACKAGE_PATH" {
return *pkgName
}
return "no idea man"
})
fmt.Fprintln(fout, codeBody)
fmt.Println("To build this plugin: ")
fmt.Println(" $ go build -buildmode plugin -o /path/to/output.so " + *destPkgName)
}

View File

@ -1,5 +0,0 @@
//+build go1.8
package main
import _ "github.com/go-sql-driver/mysql"

View File

@ -1,5 +0,0 @@
//+build go1.8
package main
import _ "github.com/lib/pq"

View File

@ -1,5 +0,0 @@
//+build go1.8
package main
import _ "github.com/mattn/go-sqlite3"

View File

@ -1,56 +0,0 @@
# manhole
An opinionated HTTP manhole into Go processes.
## Assumptions This Package Makes
- Make each server instance have a unique HTTP port that is randomized by default.
This makes it very hard to accidentally route this manhole to the outside world.
If more assurance is required I personally suggest using [yubikey totp][yktotp],
but do research.
- Application code does not touch [`http.DefaultServeMux`][default-servemux]'. This is so that
administative control rods can be dynamically flipped in the case they are
needed.
- [pprof][pprof] endpoints added to `http.DefaultServeMux`. This allows easy
access to [pprof runtime tracing][pprof-tracing] to debug issues on long-running
applications like HTTP services.
- Make the manhole slightly inconvenient to put into place in production. This
helps make sure that this tool remains a debugging tool and not a part of a
long-term production rollout.
## Usage
Compile this as a plugin:
```console
$ go get -d github.com/Xe/gopreload/manhole
$ go build -buildmode plugin -o manhole.so github.com/Xe/gopreload/manhole
```
Then add [`gopreload`][gopreload] to your application:
```go
// gopreload.go
package main
/*
This file is separate to make it very easy to both add into an application, but
also very easy to remove.
*/
import _ "github.com/Xe/gopreload"
```
And at runtime add the `manhole.so` file you created earlier to the target system
somehow and add the following environment variable to its run configuration:
```sh
GO_PRELOAD=/path/to/manhole.so
```
---
[pprof]: https://godoc.org/net/http/pprof
[default-servemux]: https://godoc.org/net/http#pkg-variables
[yktotp]: https://github.com/GeertJohan/yubigo
[gopreload]: https://github.com/Xe/gopreload

View File

@ -1,22 +0,0 @@
package main
import (
"log"
"net"
"net/http"
_ "net/http/pprof"
"net/rpc"
)
func init() {
l, err := net.Listen("tcp", "127.0.0.2:0")
if err != nil {
log.Printf("manhole: cannot bind to 127.0.0.2:0: %v", err)
return
}
log.Printf("manhole: Now listening on http://%s", l.Addr())
rpc.HandleHTTP()
go http.Serve(l, nil)
}

View File

@ -1,55 +0,0 @@
package main
import (
"fmt"
"math/rand"
"net/http"
"runtime"
"time"
_ "github.com/Xe/gopreload"
"github.com/Xe/ln"
)
func main() {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
spew()
ln.Log(ln.F{"action": "gc_spew", "who": r.RemoteAddr})
fmt.Fprintln(w, "done")
})
http.ListenAndServe(":9184", nil)
}
func makeBuffer() []byte {
return make([]byte, rand.Intn(5000000)+5000000)
}
func spew() {
pool := make([][]byte, 20)
var m runtime.MemStats
makes := 0
for _ = range make([]struct{}, 50) {
b := makeBuffer()
makes += 1
i := rand.Intn(len(pool))
pool[i] = b
time.Sleep(time.Millisecond * 250)
bytes := 0
for i := 0; i < len(pool); i++ {
if pool[i] != nil {
bytes += len(pool[i])
}
}
runtime.ReadMemStats(&m)
fmt.Printf("%d,%d,%d,%d,%d,%d\n", m.HeapSys, bytes, m.HeapAlloc,
m.HeapIdle, m.HeapReleased, makes)
}
}

View File

@ -1,36 +0,0 @@
package main
import (
"runtime"
"time"
"github.com/Xe/ln"
)
func init() {
ln.Log(ln.F{
"action": "started_up",
"every": "20_seconds",
"what": "gc_metrics",
})
go func() {
for {
time.Sleep(20 * time.Second)
gatherMetrics()
}
}()
}
func gatherMetrics() {
stats := &runtime.MemStats{}
runtime.ReadMemStats(stats)
ln.Log(ln.F{
"gc-collections": stats.NumGC,
"gc-stw-pause-total": stats.PauseTotalNs,
"live-object-count": stats.Mallocs - stats.Frees,
"heap-bytes": stats.Alloc,
"stack-bytes": stats.StackInuse,
})
}

7
vendor/github.com/Xe/ln/ex/doc.go generated vendored
View File

@ -1,7 +0,0 @@
/*
Package ex is a set of extensions and middleware for ln.
This package will (inevitably) have a lot of third-party dependencies and
as such might be broken apart into other packages in the future.
*/
package ex

View File

@ -1,68 +0,0 @@
package ex
import (
"context"
"log"
"github.com/Xe/ln"
"golang.org/x/net/trace"
)
type goEventLogger struct {
ev trace.EventLog
}
// NewGoEventLogger will log ln information to a given trace.EventLog instance.
func NewGoEventLogger(ev trace.EventLog) ln.Filter {
return &goEventLogger{ev: ev}
}
func (gel *goEventLogger) Apply(ctx context.Context, e ln.Event) bool {
data, err := ln.DefaultFormatter.Format(ctx, e)
if err != nil {
log.Printf("wtf: error in log formatting: %v", err)
return false
}
if everr := e.Data["err"]; everr != nil {
gel.ev.Errorf("%s", string(data))
return true
}
gel.ev.Printf("%s", string(data))
return true
}
func (gel *goEventLogger) Close() { gel.ev.Finish() }
func (gel *goEventLogger) Run() {}
type sst string
func (s sst) String() string { return string(s) }
func goTraceLogger(ctx context.Context, e ln.Event) bool {
sp, ok := trace.FromContext(ctx)
if !ok {
return true // no trace in context
}
data, err := ln.DefaultFormatter.Format(ctx, e)
if err != nil {
log.Printf("wtf: error in log formatting: %v", err)
return false
}
if everr := e.Data["err"]; everr != nil {
sp.SetError()
}
sp.LazyLog(sst(string(data)), false)
return true
}
// NewGoTraceLogger will log ln information to a golang.org/x/net/trace.Trace
// if it is present in the context of ln calls.
func NewGoTraceLogger() ln.Filter {
return ln.FilterFunc(goTraceLogger)
}

36
vendor/github.com/Xe/ln/ex/http.go generated vendored
View File

@ -1,36 +0,0 @@
package ex
import (
"net"
"net/http"
"time"
"github.com/Xe/ln"
)
func HTTPLog(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
host, _, _ := net.SplitHostPort(r.RemoteAddr)
f := ln.F{
"remote_ip": host,
"x_forwarded_for": r.Header.Get("X-Forwarded-For"),
"path": r.URL.Path,
}
ctx := ln.WithF(r.Context(), f)
st := time.Now()
next.ServeHTTP(w, r.WithContext(ctx))
af := time.Now()
f["request_duration"] = af.Sub(st)
ws, ok := w.(interface {
Status() int
})
if ok {
f["status"] = ws.Status()
}
ln.Log(r.Context(), f)
})
}

25
vendor/github.com/Xe/ln/ex/l2met.go generated vendored
View File

@ -1,25 +0,0 @@
package ex
import (
"time"
"github.com/Xe/ln"
)
// This file deals with formatting of [l2met] style metrics.
// [l2met]: https://r.32k.io/l2met-introduction
// Counter formats a value as a metrics counter.
func Counter(name string, value int) ln.Fer {
return ln.F{"count#" + name: value}
}
// Gauge formats a value as a metrics gauge.
func Gauge(name string, value int) ln.Fer {
return ln.F{"gauge#" + name: value}
}
// Measure formats a value as a metrics measure.
func Measure(name string, ts time.Time) ln.Fer {
return ln.F{"measure#" + name: time.Since(ts)}
}

View File

@ -1,51 +0,0 @@
// +build ignore
package main
import (
"context"
"flag"
"net/http"
"time"
"github.com/Xe/ln"
"github.com/Xe/ln/ex"
"github.com/facebookgo/flagenv"
"golang.org/x/net/trace"
)
var (
port = flag.String("port", "2145", "http port to listen on")
tracingFamily = flag.String("trace-family", "ln example", "tracing family to use for x/net/trace")
)
func main() {
flagenv.Parse()
flag.Parse()
ln.DefaultLogger.Filters = append(ln.DefaultLogger.Filters, ex.NewGoTraceLogger())
http.HandleFunc("/", handleIndex)
http.ListenAndServe(":"+*port, middlewareSpan(ex.HTTPLog(http.DefaultServeMux)))
}
func middlewareSpan(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
sp := trace.New(*tracingFamily, "HTTP request")
defer sp.Finish()
ctx, cancel := context.WithTimeout(r.Context(), 30*time.Second)
defer cancel()
ctx = trace.NewContext(ctx, sp)
next.ServeHTTP(w, r.WithContext(ctx))
})
}
func handleIndex(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
ln.Log(ctx, ln.Action("index"), ln.F{"there_is": "no_danger"})
http.Error(w, "There is no danger citizen", http.StatusOK)
}

View File

@ -1,21 +0,0 @@
The MIT License (MIT)
Copyright © 2012-2015 Carlos Castillo
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.

View File

@ -1,5 +0,0 @@
go.zipexe
=========
This module was taken as-is from https://github.com/cookieo9/resources-go.
Documentation: https://godoc.org/github.com/daaku/go.zipexe

View File

@ -1,142 +0,0 @@
// Package zipexe attempts to open an executable binary file as a zip file.
package zipexe
import (
"archive/zip"
"debug/elf"
"debug/macho"
"debug/pe"
"errors"
"io"
"os"
)
// Opens a zip file by path.
func Open(path string) (*zip.Reader, error) {
_, rd, err := OpenCloser(path)
return rd, err
}
// OpenCloser is like Open but returns an additional Closer to avoid leaking open files.
func OpenCloser(path string) (io.Closer, *zip.Reader, error) {
file, err := os.Open(path)
if err != nil {
return nil, nil, err
}
finfo, err := file.Stat()
if err != nil {
return nil, nil, err
}
zr, err := NewReader(file, finfo.Size())
if err != nil {
return nil, nil, err
}
return file, zr, nil
}
// Open a zip file, specially handling various binaries that may have been
// augmented with zip data.
func NewReader(rda io.ReaderAt, size int64) (*zip.Reader, error) {
handlers := []func(io.ReaderAt, int64) (*zip.Reader, error){
zip.NewReader,
zipExeReaderMacho,
zipExeReaderElf,
zipExeReaderPe,
}
for _, handler := range handlers {
zfile, err := handler(rda, size)
if err == nil {
return zfile, nil
}
}
return nil, errors.New("Couldn't Open As Executable")
}
// zipExeReaderMacho treats the file as a Mach-O binary
// (Mac OS X / Darwin executable) and attempts to find a zip archive.
func zipExeReaderMacho(rda io.ReaderAt, size int64) (*zip.Reader, error) {
file, err := macho.NewFile(rda)
if err != nil {
return nil, err
}
var max int64
for _, load := range file.Loads {
seg, ok := load.(*macho.Segment)
if ok {
// Check if the segment contains a zip file
if zfile, err := zip.NewReader(seg, int64(seg.Filesz)); err == nil {
return zfile, nil
}
// Otherwise move end of file pointer
end := int64(seg.Offset + seg.Filesz)
if end > max {
max = end
}
}
}
// No zip file within binary, try appended to end
section := io.NewSectionReader(rda, max, size-max)
return zip.NewReader(section, section.Size())
}
// zipExeReaderPe treats the file as a Portable Exectuable binary
// (Windows executable) and attempts to find a zip archive.
func zipExeReaderPe(rda io.ReaderAt, size int64) (*zip.Reader, error) {
file, err := pe.NewFile(rda)
if err != nil {
return nil, err
}
var max int64
for _, sec := range file.Sections {
// Check if this section has a zip file
if zfile, err := zip.NewReader(sec, int64(sec.Size)); err == nil {
return zfile, nil
}
// Otherwise move end of file pointer
end := int64(sec.Offset + sec.Size)
if end > max {
max = end
}
}
// No zip file within binary, try appended to end
section := io.NewSectionReader(rda, max, size-max)
return zip.NewReader(section, section.Size())
}
// zipExeReaderElf treats the file as a ELF binary
// (linux/BSD/etc... executable) and attempts to find a zip archive.
func zipExeReaderElf(rda io.ReaderAt, size int64) (*zip.Reader, error) {
file, err := elf.NewFile(rda)
if err != nil {
return nil, err
}
var max int64
for _, sect := range file.Sections {
if sect.Type == elf.SHT_NOBITS {
continue
}
// Check if this section has a zip file
if zfile, err := zip.NewReader(sect, int64(sect.Size)); err == nil {
return zfile, nil
}
// Otherwise move end of file pointer
end := int64(sect.Offset + sect.Size)
if end > max {
max = end
}
}
// No zip file within binary, try appended to end
section := io.NewSectionReader(rda, max, size-max)
return zip.NewReader(section, section.Size())
}

152
vendor/github.com/davecgh/go-spew/spew/bypass.go generated vendored Normal file
View File

@ -0,0 +1,152 @@
// 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.
// +build !js,!appengine,!safe,!disableunsafe
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))
)
var (
// offsetPtr, offsetScalar, and offsetFlag are the offsets for the
// internal reflect.Value fields. These values are valid before golang
// commit ecccf07e7f9d which changed the format. The are also valid
// after commit 82f48826c6c7 which changed the format again to mirror
// the original format. Code in the init function updates these offsets
// as necessary.
offsetPtr = uintptr(ptrSize)
offsetScalar = uintptr(0)
offsetFlag = uintptr(ptrSize * 2)
// flagKindWidth and flagKindShift indicate various bits that the
// reflect package uses internally to track kind information.
//
// flagRO indicates whether or not the value field of a reflect.Value is
// read-only.
//
// flagIndir indicates whether the value field of a reflect.Value is
// the actual data or a pointer to the data.
//
// These values are valid before golang commit 90a7c3c86944 which
// changed their positions. Code in the init function updates these
// flags as necessary.
flagKindWidth = uintptr(5)
flagKindShift = uintptr(flagKindWidth - 1)
flagRO = uintptr(1 << 0)
flagIndir = uintptr(1 << 1)
)
func init() {
// Older versions of reflect.Value stored small integers directly in the
// ptr field (which is named val in the older versions). Versions
// between commits ecccf07e7f9d and 82f48826c6c7 added a new field named
// scalar for this purpose which unfortunately came before the flag
// field, so the offset of the flag field is different for those
// versions.
//
// This code constructs a new reflect.Value from a known small integer
// and checks if the size of the reflect.Value struct indicates it has
// the scalar field. When it does, the offsets are updated accordingly.
vv := reflect.ValueOf(0xf00)
if unsafe.Sizeof(vv) == (ptrSize * 4) {
offsetScalar = ptrSize * 2
offsetFlag = ptrSize * 3
}
// Commit 90a7c3c86944 changed the flag positions such that the low
// order bits are the kind. This code extracts the kind from the flags
// field and ensures it's the correct type. When it's not, the flag
// order has been changed to the newer format, so the flags are updated
// accordingly.
upf := unsafe.Pointer(uintptr(unsafe.Pointer(&vv)) + offsetFlag)
upfv := *(*uintptr)(upf)
flagKindMask := uintptr((1<<flagKindWidth - 1) << flagKindShift)
if (upfv&flagKindMask)>>flagKindShift != uintptr(reflect.Int) {
flagKindShift = 0
flagRO = 1 << 5
flagIndir = 1 << 6
// Commit adf9b30e5594 modified the flags to separate the
// flagRO flag into two bits which specifies whether or not the
// field is embedded. This causes flagIndir to move over a bit
// and means that flagRO is the combination of either of the
// original flagRO bit and the new bit.
//
// This code detects the change by extracting what used to be
// the indirect bit to ensure it's set. When it's not, the flag
// order has been changed to the newer format, so the flags are
// updated accordingly.
if upfv&flagIndir == 0 {
flagRO = 3 << 5
flagIndir = 1 << 7
}
}
}
// 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) (rv reflect.Value) {
indirects := 1
vt := v.Type()
upv := unsafe.Pointer(uintptr(unsafe.Pointer(&v)) + offsetPtr)
rvf := *(*uintptr)(unsafe.Pointer(uintptr(unsafe.Pointer(&v)) + offsetFlag))
if rvf&flagIndir != 0 {
vt = reflect.PtrTo(v.Type())
indirects++
} else if offsetScalar != 0 {
// The value is in the scalar field when it's not one of the
// reference types.
switch vt.Kind() {
case reflect.Uintptr:
case reflect.Chan:
case reflect.Func:
case reflect.Map:
case reflect.Ptr:
case reflect.UnsafePointer:
default:
upv = unsafe.Pointer(uintptr(unsafe.Pointer(&v)) +
offsetScalar)
}
}
pv := reflect.NewAt(vt, upv)
rv = pv
for i := 0; i < indirects; i++ {
rv = rv.Elem()
}
return rv
}

38
vendor/github.com/davecgh/go-spew/spew/bypasssafe.go generated vendored Normal file
View 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
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
View 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 hexidecimal 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))
}

298
vendor/github.com/davecgh/go-spew/spew/common_test.go generated vendored Normal file
View File

@ -0,0 +1,298 @@
/*
* 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_test
import (
"fmt"
"reflect"
"testing"
"github.com/davecgh/go-spew/spew"
)
// custom type to test Stinger interface on non-pointer receiver.
type stringer string
// String implements the Stringer interface for testing invocation of custom
// stringers on types with non-pointer receivers.
func (s stringer) String() string {
return "stringer " + string(s)
}
// custom type to test Stinger interface on pointer receiver.
type pstringer string
// String implements the Stringer interface for testing invocation of custom
// stringers on types with only pointer receivers.
func (s *pstringer) String() string {
return "stringer " + string(*s)
}
// xref1 and xref2 are cross referencing structs for testing circular reference
// detection.
type xref1 struct {
ps2 *xref2
}
type xref2 struct {
ps1 *xref1
}
// indirCir1, indirCir2, and indirCir3 are used to generate an indirect circular
// reference for testing detection.
type indirCir1 struct {
ps2 *indirCir2
}
type indirCir2 struct {
ps3 *indirCir3
}
type indirCir3 struct {
ps1 *indirCir1
}
// embed is used to test embedded structures.
type embed struct {
a string
}
// embedwrap is used to test embedded structures.
type embedwrap struct {
*embed
e *embed
}
// panicer is used to intentionally cause a panic for testing spew properly
// handles them
type panicer int
func (p panicer) String() string {
panic("test panic")
}
// customError is used to test custom error interface invocation.
type customError int
func (e customError) Error() string {
return fmt.Sprintf("error: %d", int(e))
}
// stringizeWants converts a slice of wanted test output into a format suitable
// for a test error message.
func stringizeWants(wants []string) string {
s := ""
for i, want := range wants {
if i > 0 {
s += fmt.Sprintf("want%d: %s", i+1, want)
} else {
s += "want: " + want
}
}
return s
}
// testFailed returns whether or not a test failed by checking if the result
// of the test is in the slice of wanted strings.
func testFailed(result string, wants []string) bool {
for _, want := range wants {
if result == want {
return false
}
}
return true
}
type sortableStruct struct {
x int
}
func (ss sortableStruct) String() string {
return fmt.Sprintf("ss.%d", ss.x)
}
type unsortableStruct struct {
x int
}
type sortTestCase struct {
input []reflect.Value
expected []reflect.Value
}
func helpTestSortValues(tests []sortTestCase, cs *spew.ConfigState, t *testing.T) {
getInterfaces := func(values []reflect.Value) []interface{} {
interfaces := []interface{}{}
for _, v := range values {
interfaces = append(interfaces, v.Interface())
}
return interfaces
}
for _, test := range tests {
spew.SortValues(test.input, cs)
// reflect.DeepEqual cannot really make sense of reflect.Value,
// probably because of all the pointer tricks. For instance,
// v(2.0) != v(2.0) on a 32-bits system. Turn them into interface{}
// instead.
input := getInterfaces(test.input)
expected := getInterfaces(test.expected)
if !reflect.DeepEqual(input, expected) {
t.Errorf("Sort mismatch:\n %v != %v", input, expected)
}
}
}
// TestSortValues ensures the sort functionality for relect.Value based sorting
// works as intended.
func TestSortValues(t *testing.T) {
v := reflect.ValueOf
a := v("a")
b := v("b")
c := v("c")
embedA := v(embed{"a"})
embedB := v(embed{"b"})
embedC := v(embed{"c"})
tests := []sortTestCase{
// No values.
{
[]reflect.Value{},
[]reflect.Value{},
},
// Bools.
{
[]reflect.Value{v(false), v(true), v(false)},
[]reflect.Value{v(false), v(false), v(true)},
},
// Ints.
{
[]reflect.Value{v(2), v(1), v(3)},
[]reflect.Value{v(1), v(2), v(3)},
},
// Uints.
{
[]reflect.Value{v(uint8(2)), v(uint8(1)), v(uint8(3))},
[]reflect.Value{v(uint8(1)), v(uint8(2)), v(uint8(3))},
},
// Floats.
{
[]reflect.Value{v(2.0), v(1.0), v(3.0)},
[]reflect.Value{v(1.0), v(2.0), v(3.0)},
},
// Strings.
{
[]reflect.Value{b, a, c},
[]reflect.Value{a, b, c},
},
// Array
{
[]reflect.Value{v([3]int{3, 2, 1}), v([3]int{1, 3, 2}), v([3]int{1, 2, 3})},
[]reflect.Value{v([3]int{1, 2, 3}), v([3]int{1, 3, 2}), v([3]int{3, 2, 1})},
},
// Uintptrs.
{
[]reflect.Value{v(uintptr(2)), v(uintptr(1)), v(uintptr(3))},
[]reflect.Value{v(uintptr(1)), v(uintptr(2)), v(uintptr(3))},
},
// SortableStructs.
{
// Note: not sorted - DisableMethods is set.
[]reflect.Value{v(sortableStruct{2}), v(sortableStruct{1}), v(sortableStruct{3})},
[]reflect.Value{v(sortableStruct{2}), v(sortableStruct{1}), v(sortableStruct{3})},
},
// UnsortableStructs.
{
// Note: not sorted - SpewKeys is false.
[]reflect.Value{v(unsortableStruct{2}), v(unsortableStruct{1}), v(unsortableStruct{3})},
[]reflect.Value{v(unsortableStruct{2}), v(unsortableStruct{1}), v(unsortableStruct{3})},
},
// Invalid.
{
[]reflect.Value{embedB, embedA, embedC},
[]reflect.Value{embedB, embedA, embedC},
},
}
cs := spew.ConfigState{DisableMethods: true, SpewKeys: false}
helpTestSortValues(tests, &cs, t)
}
// TestSortValuesWithMethods ensures the sort functionality for relect.Value
// based sorting works as intended when using string methods.
func TestSortValuesWithMethods(t *testing.T) {
v := reflect.ValueOf
a := v("a")
b := v("b")
c := v("c")
tests := []sortTestCase{
// Ints.
{
[]reflect.Value{v(2), v(1), v(3)},
[]reflect.Value{v(1), v(2), v(3)},
},
// Strings.
{
[]reflect.Value{b, a, c},
[]reflect.Value{a, b, c},
},
// SortableStructs.
{
[]reflect.Value{v(sortableStruct{2}), v(sortableStruct{1}), v(sortableStruct{3})},
[]reflect.Value{v(sortableStruct{1}), v(sortableStruct{2}), v(sortableStruct{3})},
},
// UnsortableStructs.
{
// Note: not sorted - SpewKeys is false.
[]reflect.Value{v(unsortableStruct{2}), v(unsortableStruct{1}), v(unsortableStruct{3})},
[]reflect.Value{v(unsortableStruct{2}), v(unsortableStruct{1}), v(unsortableStruct{3})},
},
}
cs := spew.ConfigState{DisableMethods: false, SpewKeys: false}
helpTestSortValues(tests, &cs, t)
}
// TestSortValuesWithSpew ensures the sort functionality for relect.Value
// based sorting works as intended when using spew to stringify keys.
func TestSortValuesWithSpew(t *testing.T) {
v := reflect.ValueOf
a := v("a")
b := v("b")
c := v("c")
tests := []sortTestCase{
// Ints.
{
[]reflect.Value{v(2), v(1), v(3)},
[]reflect.Value{v(1), v(2), v(3)},
},
// Strings.
{
[]reflect.Value{b, a, c},
[]reflect.Value{a, b, c},
},
// SortableStructs.
{
[]reflect.Value{v(sortableStruct{2}), v(sortableStruct{1}), v(sortableStruct{3})},
[]reflect.Value{v(sortableStruct{1}), v(sortableStruct{2}), v(sortableStruct{3})},
},
// UnsortableStructs.
{
[]reflect.Value{v(unsortableStruct{2}), v(unsortableStruct{1}), v(unsortableStruct{3})},
[]reflect.Value{v(unsortableStruct{1}), v(unsortableStruct{2}), v(unsortableStruct{3})},
},
}
cs := spew.ConfigState{DisableMethods: true, SpewKeys: true}
helpTestSortValues(tests, &cs, t)
}

306
vendor/github.com/davecgh/go-spew/spew/config.go generated vendored Normal file
View 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
View 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
View 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 == true:
d.w.Write(nilAngleBytes)
case cycleFound == true:
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...)
}

1042
vendor/github.com/davecgh/go-spew/spew/dump_test.go generated vendored Normal file

File diff suppressed because it is too large Load Diff

99
vendor/github.com/davecgh/go-spew/spew/dumpcgo_test.go generated vendored Normal file
View File

@ -0,0 +1,99 @@
// 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.
// NOTE: Due to the following build constraints, this file will only be compiled
// when both cgo is supported and "-tags testcgo" is added to the go test
// command line. This means the cgo tests are only added (and hence run) when
// specifially requested. This configuration is used because spew itself
// does not require cgo to run even though it does handle certain cgo types
// specially. Rather than forcing all clients to require cgo and an external
// C compiler just to run the tests, this scheme makes them optional.
// +build cgo,testcgo
package spew_test
import (
"fmt"
"github.com/davecgh/go-spew/spew/testdata"
)
func addCgoDumpTests() {
// C char pointer.
v := testdata.GetCgoCharPointer()
nv := testdata.GetCgoNullCharPointer()
pv := &v
vcAddr := fmt.Sprintf("%p", v)
vAddr := fmt.Sprintf("%p", pv)
pvAddr := fmt.Sprintf("%p", &pv)
vt := "*testdata._Ctype_char"
vs := "116"
addDumpTest(v, "("+vt+")("+vcAddr+")("+vs+")\n")
addDumpTest(pv, "(*"+vt+")("+vAddr+"->"+vcAddr+")("+vs+")\n")
addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+"->"+vcAddr+")("+vs+")\n")
addDumpTest(nv, "("+vt+")(<nil>)\n")
// C char array.
v2, v2l, v2c := testdata.GetCgoCharArray()
v2Len := fmt.Sprintf("%d", v2l)
v2Cap := fmt.Sprintf("%d", v2c)
v2t := "[6]testdata._Ctype_char"
v2s := "(len=" + v2Len + " cap=" + v2Cap + ") " +
"{\n 00000000 74 65 73 74 32 00 " +
" |test2.|\n}"
addDumpTest(v2, "("+v2t+") "+v2s+"\n")
// C unsigned char array.
v3, v3l, v3c := testdata.GetCgoUnsignedCharArray()
v3Len := fmt.Sprintf("%d", v3l)
v3Cap := fmt.Sprintf("%d", v3c)
v3t := "[6]testdata._Ctype_unsignedchar"
v3t2 := "[6]testdata._Ctype_uchar"
v3s := "(len=" + v3Len + " cap=" + v3Cap + ") " +
"{\n 00000000 74 65 73 74 33 00 " +
" |test3.|\n}"
addDumpTest(v3, "("+v3t+") "+v3s+"\n", "("+v3t2+") "+v3s+"\n")
// C signed char array.
v4, v4l, v4c := testdata.GetCgoSignedCharArray()
v4Len := fmt.Sprintf("%d", v4l)
v4Cap := fmt.Sprintf("%d", v4c)
v4t := "[6]testdata._Ctype_schar"
v4t2 := "testdata._Ctype_schar"
v4s := "(len=" + v4Len + " cap=" + v4Cap + ") " +
"{\n (" + v4t2 + ") 116,\n (" + v4t2 + ") 101,\n (" + v4t2 +
") 115,\n (" + v4t2 + ") 116,\n (" + v4t2 + ") 52,\n (" + v4t2 +
") 0\n}"
addDumpTest(v4, "("+v4t+") "+v4s+"\n")
// C uint8_t array.
v5, v5l, v5c := testdata.GetCgoUint8tArray()
v5Len := fmt.Sprintf("%d", v5l)
v5Cap := fmt.Sprintf("%d", v5c)
v5t := "[6]testdata._Ctype_uint8_t"
v5s := "(len=" + v5Len + " cap=" + v5Cap + ") " +
"{\n 00000000 74 65 73 74 35 00 " +
" |test5.|\n}"
addDumpTest(v5, "("+v5t+") "+v5s+"\n")
// C typedefed unsigned char array.
v6, v6l, v6c := testdata.GetCgoTypdefedUnsignedCharArray()
v6Len := fmt.Sprintf("%d", v6l)
v6Cap := fmt.Sprintf("%d", v6c)
v6t := "[6]testdata._Ctype_custom_uchar_t"
v6s := "(len=" + v6Len + " cap=" + v6Cap + ") " +
"{\n 00000000 74 65 73 74 36 00 " +
" |test6.|\n}"
addDumpTest(v6, "("+v6t+") "+v6s+"\n")
}

View File

@ -0,0 +1,26 @@
// Copyright (c) 2013 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 either cgo is not supported or "-tags testcgo" is not added to the go
// test command line. This file intentionally does not setup any cgo tests in
// this scenario.
// +build !cgo !testcgo
package spew_test
func addCgoDumpTests() {
// Don't add any tests for cgo since this file is only compiled when
// there should not be any cgo tests.
}

226
vendor/github.com/davecgh/go-spew/spew/example_test.go generated vendored Normal file
View File

@ -0,0 +1,226 @@
/*
* 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_test
import (
"fmt"
"github.com/davecgh/go-spew/spew"
)
type Flag int
const (
flagOne Flag = iota
flagTwo
)
var flagStrings = map[Flag]string{
flagOne: "flagOne",
flagTwo: "flagTwo",
}
func (f Flag) String() string {
if s, ok := flagStrings[f]; ok {
return s
}
return fmt.Sprintf("Unknown flag (%d)", int(f))
}
type Bar struct {
data uintptr
}
type Foo struct {
unexportedField Bar
ExportedField map[interface{}]interface{}
}
// This example demonstrates how to use Dump to dump variables to stdout.
func ExampleDump() {
// The following package level declarations are assumed for this example:
/*
type Flag int
const (
flagOne Flag = iota
flagTwo
)
var flagStrings = map[Flag]string{
flagOne: "flagOne",
flagTwo: "flagTwo",
}
func (f Flag) String() string {
if s, ok := flagStrings[f]; ok {
return s
}
return fmt.Sprintf("Unknown flag (%d)", int(f))
}
type Bar struct {
data uintptr
}
type Foo struct {
unexportedField Bar
ExportedField map[interface{}]interface{}
}
*/
// Setup some sample data structures for the example.
bar := Bar{uintptr(0)}
s1 := Foo{bar, map[interface{}]interface{}{"one": true}}
f := Flag(5)
b := []byte{
0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20,
0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30,
0x31, 0x32,
}
// Dump!
spew.Dump(s1, f, b)
// Output:
// (spew_test.Foo) {
// unexportedField: (spew_test.Bar) {
// data: (uintptr) <nil>
// },
// ExportedField: (map[interface {}]interface {}) (len=1) {
// (string) (len=3) "one": (bool) true
// }
// }
// (spew_test.Flag) Unknown flag (5)
// ([]uint8) (len=34 cap=34) {
// 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|
// }
//
}
// This example demonstrates how to use Printf to display a variable with a
// format string and inline formatting.
func ExamplePrintf() {
// Create a double pointer to a uint 8.
ui8 := uint8(5)
pui8 := &ui8
ppui8 := &pui8
// Create a circular data type.
type circular struct {
ui8 uint8
c *circular
}
c := circular{ui8: 1}
c.c = &c
// Print!
spew.Printf("ppui8: %v\n", ppui8)
spew.Printf("circular: %v\n", c)
// Output:
// ppui8: <**>5
// circular: {1 <*>{1 <*><shown>}}
}
// This example demonstrates how to use a ConfigState.
func ExampleConfigState() {
// Modify the indent level of the ConfigState only. The global
// configuration is not modified.
scs := spew.ConfigState{Indent: "\t"}
// Output using the ConfigState instance.
v := map[string]int{"one": 1}
scs.Printf("v: %v\n", v)
scs.Dump(v)
// Output:
// v: map[one:1]
// (map[string]int) (len=1) {
// (string) (len=3) "one": (int) 1
// }
}
// This example demonstrates how to use ConfigState.Dump to dump variables to
// stdout
func ExampleConfigState_Dump() {
// See the top-level Dump example for details on the types used in this
// example.
// Create two ConfigState instances with different indentation.
scs := spew.ConfigState{Indent: "\t"}
scs2 := spew.ConfigState{Indent: " "}
// Setup some sample data structures for the example.
bar := Bar{uintptr(0)}
s1 := Foo{bar, map[interface{}]interface{}{"one": true}}
// Dump using the ConfigState instances.
scs.Dump(s1)
scs2.Dump(s1)
// Output:
// (spew_test.Foo) {
// unexportedField: (spew_test.Bar) {
// data: (uintptr) <nil>
// },
// ExportedField: (map[interface {}]interface {}) (len=1) {
// (string) (len=3) "one": (bool) true
// }
// }
// (spew_test.Foo) {
// unexportedField: (spew_test.Bar) {
// data: (uintptr) <nil>
// },
// ExportedField: (map[interface {}]interface {}) (len=1) {
// (string) (len=3) "one": (bool) true
// }
// }
//
}
// This example demonstrates how to use ConfigState.Printf to display a variable
// with a format string and inline formatting.
func ExampleConfigState_Printf() {
// See the top-level Dump example for details on the types used in this
// example.
// Create two ConfigState instances and modify the method handling of the
// first ConfigState only.
scs := spew.NewDefaultConfig()
scs2 := spew.NewDefaultConfig()
scs.DisableMethods = true
// Alternatively
// scs := spew.ConfigState{Indent: " ", DisableMethods: true}
// scs2 := spew.ConfigState{Indent: " "}
// This is of type Flag which implements a Stringer and has raw value 1.
f := flagTwo
// Dump using the ConfigState instances.
scs.Printf("f: %v\n", f)
scs2.Printf("f: %v\n", f)
// Output:
// f: 1
// f: flagTwo
}

419
vendor/github.com/davecgh/go-spew/spew/format.go generated vendored Normal file
View 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 == true:
f.fs.Write(nilAngleBytes)
case cycleFound == true:
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)
}

1558
vendor/github.com/davecgh/go-spew/spew/format_test.go generated vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,87 @@
/*
* 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.
*/
/*
This test file is part of the spew package rather than than the spew_test
package because it needs access to internals to properly test certain cases
which are not possible via the public interface since they should never happen.
*/
package spew
import (
"bytes"
"reflect"
"testing"
)
// dummyFmtState implements a fake fmt.State to use for testing invalid
// reflect.Value handling. This is necessary because the fmt package catches
// invalid values before invoking the formatter on them.
type dummyFmtState struct {
bytes.Buffer
}
func (dfs *dummyFmtState) Flag(f int) bool {
if f == int('+') {
return true
}
return false
}
func (dfs *dummyFmtState) Precision() (int, bool) {
return 0, false
}
func (dfs *dummyFmtState) Width() (int, bool) {
return 0, false
}
// TestInvalidReflectValue ensures the dump and formatter code handles an
// invalid reflect value properly. This needs access to internal state since it
// should never happen in real code and therefore can't be tested via the public
// API.
func TestInvalidReflectValue(t *testing.T) {
i := 1
// Dump invalid reflect value.
v := new(reflect.Value)
buf := new(bytes.Buffer)
d := dumpState{w: buf, cs: &Config}
d.dump(*v)
s := buf.String()
want := "<invalid>"
if s != want {
t.Errorf("InvalidReflectValue #%d\n got: %s want: %s", i, s, want)
}
i++
// Formatter invalid reflect value.
buf2 := new(dummyFmtState)
f := formatState{value: *v, cs: &Config, fs: buf2}
f.format(*v)
s = buf2.String()
want = "<invalid>"
if s != want {
t.Errorf("InvalidReflectValue #%d got: %s want: %s", i, s, want)
}
}
// SortValues makes the internal sortValues function available to the test
// package.
func SortValues(values []reflect.Value, cs *ConfigState) {
sortValues(values, cs)
}

View File

@ -0,0 +1,102 @@
// 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.
// 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.
// +build !js,!appengine,!safe,!disableunsafe
/*
This test file is part of the spew package rather than than the spew_test
package because it needs access to internals to properly test certain cases
which are not possible via the public interface since they should never happen.
*/
package spew
import (
"bytes"
"reflect"
"testing"
"unsafe"
)
// changeKind uses unsafe to intentionally change the kind of a reflect.Value to
// the maximum kind value which does not exist. This is needed to test the
// fallback code which punts to the standard fmt library for new types that
// might get added to the language.
func changeKind(v *reflect.Value, readOnly bool) {
rvf := (*uintptr)(unsafe.Pointer(uintptr(unsafe.Pointer(v)) + offsetFlag))
*rvf = *rvf | ((1<<flagKindWidth - 1) << flagKindShift)
if readOnly {
*rvf |= flagRO
} else {
*rvf &= ^uintptr(flagRO)
}
}
// TestAddedReflectValue tests functionaly of the dump and formatter code which
// falls back to the standard fmt library for new types that might get added to
// the language.
func TestAddedReflectValue(t *testing.T) {
i := 1
// Dump using a reflect.Value that is exported.
v := reflect.ValueOf(int8(5))
changeKind(&v, false)
buf := new(bytes.Buffer)
d := dumpState{w: buf, cs: &Config}
d.dump(v)
s := buf.String()
want := "(int8) 5"
if s != want {
t.Errorf("TestAddedReflectValue #%d\n got: %s want: %s", i, s, want)
}
i++
// Dump using a reflect.Value that is not exported.
changeKind(&v, true)
buf.Reset()
d.dump(v)
s = buf.String()
want = "(int8) <int8 Value>"
if s != want {
t.Errorf("TestAddedReflectValue #%d\n got: %s want: %s", i, s, want)
}
i++
// Formatter using a reflect.Value that is exported.
changeKind(&v, false)
buf2 := new(dummyFmtState)
f := formatState{value: v, cs: &Config, fs: buf2}
f.format(v)
s = buf2.String()
want = "5"
if s != want {
t.Errorf("TestAddedReflectValue #%d got: %s want: %s", i, s, want)
}
i++
// Formatter using a reflect.Value that is not exported.
changeKind(&v, true)
buf2.Reset()
f = formatState{value: v, cs: &Config, fs: buf2}
f.format(v)
s = buf2.String()
want = "<int8 Value>"
if s != want {
t.Errorf("TestAddedReflectValue #%d got: %s want: %s", i, s, want)
}
}

148
vendor/github.com/davecgh/go-spew/spew/spew.go generated vendored Normal file
View 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
}

320
vendor/github.com/davecgh/go-spew/spew/spew_test.go generated vendored Normal file
View File

@ -0,0 +1,320 @@
/*
* 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_test
import (
"bytes"
"fmt"
"io/ioutil"
"os"
"testing"
"github.com/davecgh/go-spew/spew"
)
// spewFunc is used to identify which public function of the spew package or
// ConfigState a test applies to.
type spewFunc int
const (
fCSFdump spewFunc = iota
fCSFprint
fCSFprintf
fCSFprintln
fCSPrint
fCSPrintln
fCSSdump
fCSSprint
fCSSprintf
fCSSprintln
fCSErrorf
fCSNewFormatter
fErrorf
fFprint
fFprintln
fPrint
fPrintln
fSdump
fSprint
fSprintf
fSprintln
)
// Map of spewFunc values to names for pretty printing.
var spewFuncStrings = map[spewFunc]string{
fCSFdump: "ConfigState.Fdump",
fCSFprint: "ConfigState.Fprint",
fCSFprintf: "ConfigState.Fprintf",
fCSFprintln: "ConfigState.Fprintln",
fCSSdump: "ConfigState.Sdump",
fCSPrint: "ConfigState.Print",
fCSPrintln: "ConfigState.Println",
fCSSprint: "ConfigState.Sprint",
fCSSprintf: "ConfigState.Sprintf",
fCSSprintln: "ConfigState.Sprintln",
fCSErrorf: "ConfigState.Errorf",
fCSNewFormatter: "ConfigState.NewFormatter",
fErrorf: "spew.Errorf",
fFprint: "spew.Fprint",
fFprintln: "spew.Fprintln",
fPrint: "spew.Print",
fPrintln: "spew.Println",
fSdump: "spew.Sdump",
fSprint: "spew.Sprint",
fSprintf: "spew.Sprintf",
fSprintln: "spew.Sprintln",
}
func (f spewFunc) String() string {
if s, ok := spewFuncStrings[f]; ok {
return s
}
return fmt.Sprintf("Unknown spewFunc (%d)", int(f))
}
// spewTest is used to describe a test to be performed against the public
// functions of the spew package or ConfigState.
type spewTest struct {
cs *spew.ConfigState
f spewFunc
format string
in interface{}
want string
}
// spewTests houses the tests to be performed against the public functions of
// the spew package and ConfigState.
//
// These tests are only intended to ensure the public functions are exercised
// and are intentionally not exhaustive of types. The exhaustive type
// tests are handled in the dump and format tests.
var spewTests []spewTest
// redirStdout is a helper function to return the standard output from f as a
// byte slice.
func redirStdout(f func()) ([]byte, error) {
tempFile, err := ioutil.TempFile("", "ss-test")
if err != nil {
return nil, err
}
fileName := tempFile.Name()
defer os.Remove(fileName) // Ignore error
origStdout := os.Stdout
os.Stdout = tempFile
f()
os.Stdout = origStdout
tempFile.Close()
return ioutil.ReadFile(fileName)
}
func initSpewTests() {
// Config states with various settings.
scsDefault := spew.NewDefaultConfig()
scsNoMethods := &spew.ConfigState{Indent: " ", DisableMethods: true}
scsNoPmethods := &spew.ConfigState{Indent: " ", DisablePointerMethods: true}
scsMaxDepth := &spew.ConfigState{Indent: " ", MaxDepth: 1}
scsContinue := &spew.ConfigState{Indent: " ", ContinueOnMethod: true}
scsNoPtrAddr := &spew.ConfigState{DisablePointerAddresses: true}
scsNoCap := &spew.ConfigState{DisableCapacities: true}
// Variables for tests on types which implement Stringer interface with and
// without a pointer receiver.
ts := stringer("test")
tps := pstringer("test")
type ptrTester struct {
s *struct{}
}
tptr := &ptrTester{s: &struct{}{}}
// depthTester is used to test max depth handling for structs, array, slices
// and maps.
type depthTester struct {
ic indirCir1
arr [1]string
slice []string
m map[string]int
}
dt := depthTester{indirCir1{nil}, [1]string{"arr"}, []string{"slice"},
map[string]int{"one": 1}}
// Variable for tests on types which implement error interface.
te := customError(10)
spewTests = []spewTest{
{scsDefault, fCSFdump, "", int8(127), "(int8) 127\n"},
{scsDefault, fCSFprint, "", int16(32767), "32767"},
{scsDefault, fCSFprintf, "%v", int32(2147483647), "2147483647"},
{scsDefault, fCSFprintln, "", int(2147483647), "2147483647\n"},
{scsDefault, fCSPrint, "", int64(9223372036854775807), "9223372036854775807"},
{scsDefault, fCSPrintln, "", uint8(255), "255\n"},
{scsDefault, fCSSdump, "", uint8(64), "(uint8) 64\n"},
{scsDefault, fCSSprint, "", complex(1, 2), "(1+2i)"},
{scsDefault, fCSSprintf, "%v", complex(float32(3), 4), "(3+4i)"},
{scsDefault, fCSSprintln, "", complex(float64(5), 6), "(5+6i)\n"},
{scsDefault, fCSErrorf, "%#v", uint16(65535), "(uint16)65535"},
{scsDefault, fCSNewFormatter, "%v", uint32(4294967295), "4294967295"},
{scsDefault, fErrorf, "%v", uint64(18446744073709551615), "18446744073709551615"},
{scsDefault, fFprint, "", float32(3.14), "3.14"},
{scsDefault, fFprintln, "", float64(6.28), "6.28\n"},
{scsDefault, fPrint, "", true, "true"},
{scsDefault, fPrintln, "", false, "false\n"},
{scsDefault, fSdump, "", complex(-10, -20), "(complex128) (-10-20i)\n"},
{scsDefault, fSprint, "", complex(-1, -2), "(-1-2i)"},
{scsDefault, fSprintf, "%v", complex(float32(-3), -4), "(-3-4i)"},
{scsDefault, fSprintln, "", complex(float64(-5), -6), "(-5-6i)\n"},
{scsNoMethods, fCSFprint, "", ts, "test"},
{scsNoMethods, fCSFprint, "", &ts, "<*>test"},
{scsNoMethods, fCSFprint, "", tps, "test"},
{scsNoMethods, fCSFprint, "", &tps, "<*>test"},
{scsNoPmethods, fCSFprint, "", ts, "stringer test"},
{scsNoPmethods, fCSFprint, "", &ts, "<*>stringer test"},
{scsNoPmethods, fCSFprint, "", tps, "test"},
{scsNoPmethods, fCSFprint, "", &tps, "<*>stringer test"},
{scsMaxDepth, fCSFprint, "", dt, "{{<max>} [<max>] [<max>] map[<max>]}"},
{scsMaxDepth, fCSFdump, "", dt, "(spew_test.depthTester) {\n" +
" ic: (spew_test.indirCir1) {\n <max depth reached>\n },\n" +
" arr: ([1]string) (len=1 cap=1) {\n <max depth reached>\n },\n" +
" slice: ([]string) (len=1 cap=1) {\n <max depth reached>\n },\n" +
" m: (map[string]int) (len=1) {\n <max depth reached>\n }\n}\n"},
{scsContinue, fCSFprint, "", ts, "(stringer test) test"},
{scsContinue, fCSFdump, "", ts, "(spew_test.stringer) " +
"(len=4) (stringer test) \"test\"\n"},
{scsContinue, fCSFprint, "", te, "(error: 10) 10"},
{scsContinue, fCSFdump, "", te, "(spew_test.customError) " +
"(error: 10) 10\n"},
{scsNoPtrAddr, fCSFprint, "", tptr, "<*>{<*>{}}"},
{scsNoPtrAddr, fCSSdump, "", tptr, "(*spew_test.ptrTester)({\ns: (*struct {})({\n})\n})\n"},
{scsNoCap, fCSSdump, "", make([]string, 0, 10), "([]string) {\n}\n"},
{scsNoCap, fCSSdump, "", make([]string, 1, 10), "([]string) (len=1) {\n(string) \"\"\n}\n"},
}
}
// TestSpew executes all of the tests described by spewTests.
func TestSpew(t *testing.T) {
initSpewTests()
t.Logf("Running %d tests", len(spewTests))
for i, test := range spewTests {
buf := new(bytes.Buffer)
switch test.f {
case fCSFdump:
test.cs.Fdump(buf, test.in)
case fCSFprint:
test.cs.Fprint(buf, test.in)
case fCSFprintf:
test.cs.Fprintf(buf, test.format, test.in)
case fCSFprintln:
test.cs.Fprintln(buf, test.in)
case fCSPrint:
b, err := redirStdout(func() { test.cs.Print(test.in) })
if err != nil {
t.Errorf("%v #%d %v", test.f, i, err)
continue
}
buf.Write(b)
case fCSPrintln:
b, err := redirStdout(func() { test.cs.Println(test.in) })
if err != nil {
t.Errorf("%v #%d %v", test.f, i, err)
continue
}
buf.Write(b)
case fCSSdump:
str := test.cs.Sdump(test.in)
buf.WriteString(str)
case fCSSprint:
str := test.cs.Sprint(test.in)
buf.WriteString(str)
case fCSSprintf:
str := test.cs.Sprintf(test.format, test.in)
buf.WriteString(str)
case fCSSprintln:
str := test.cs.Sprintln(test.in)
buf.WriteString(str)
case fCSErrorf:
err := test.cs.Errorf(test.format, test.in)
buf.WriteString(err.Error())
case fCSNewFormatter:
fmt.Fprintf(buf, test.format, test.cs.NewFormatter(test.in))
case fErrorf:
err := spew.Errorf(test.format, test.in)
buf.WriteString(err.Error())
case fFprint:
spew.Fprint(buf, test.in)
case fFprintln:
spew.Fprintln(buf, test.in)
case fPrint:
b, err := redirStdout(func() { spew.Print(test.in) })
if err != nil {
t.Errorf("%v #%d %v", test.f, i, err)
continue
}
buf.Write(b)
case fPrintln:
b, err := redirStdout(func() { spew.Println(test.in) })
if err != nil {
t.Errorf("%v #%d %v", test.f, i, err)
continue
}
buf.Write(b)
case fSdump:
str := spew.Sdump(test.in)
buf.WriteString(str)
case fSprint:
str := spew.Sprint(test.in)
buf.WriteString(str)
case fSprintf:
str := spew.Sprintf(test.format, test.in)
buf.WriteString(str)
case fSprintln:
str := spew.Sprintln(test.in)
buf.WriteString(str)
default:
t.Errorf("%v #%d unrecognized function", test.f, i)
continue
}
s := buf.String()
if test.want != s {
t.Errorf("ConfigState #%d\n got: %s want: %s", i, s, test.want)
continue
}
}
}

View File

@ -0,0 +1,82 @@
// Copyright (c) 2013 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 both cgo is supported and "-tags testcgo" is added to the go test
// command line. This code should really only be in the dumpcgo_test.go file,
// but unfortunately Go will not allow cgo in test files, so this is a
// workaround to allow cgo types to be tested. This configuration is used
// because spew itself does not require cgo to run even though it does handle
// certain cgo types specially. Rather than forcing all clients to require cgo
// and an external C compiler just to run the tests, this scheme makes them
// optional.
// +build cgo,testcgo
package testdata
/*
#include <stdint.h>
typedef unsigned char custom_uchar_t;
char *ncp = 0;
char *cp = "test";
char ca[6] = {'t', 'e', 's', 't', '2', '\0'};
unsigned char uca[6] = {'t', 'e', 's', 't', '3', '\0'};
signed char sca[6] = {'t', 'e', 's', 't', '4', '\0'};
uint8_t ui8ta[6] = {'t', 'e', 's', 't', '5', '\0'};
custom_uchar_t tuca[6] = {'t', 'e', 's', 't', '6', '\0'};
*/
import "C"
// GetCgoNullCharPointer returns a null char pointer via cgo. This is only
// used for tests.
func GetCgoNullCharPointer() interface{} {
return C.ncp
}
// GetCgoCharPointer returns a char pointer via cgo. This is only used for
// tests.
func GetCgoCharPointer() interface{} {
return C.cp
}
// GetCgoCharArray returns a char array via cgo and the array's len and cap.
// This is only used for tests.
func GetCgoCharArray() (interface{}, int, int) {
return C.ca, len(C.ca), cap(C.ca)
}
// GetCgoUnsignedCharArray returns an unsigned char array via cgo and the
// array's len and cap. This is only used for tests.
func GetCgoUnsignedCharArray() (interface{}, int, int) {
return C.uca, len(C.uca), cap(C.uca)
}
// GetCgoSignedCharArray returns a signed char array via cgo and the array's len
// and cap. This is only used for tests.
func GetCgoSignedCharArray() (interface{}, int, int) {
return C.sca, len(C.sca), cap(C.sca)
}
// GetCgoUint8tArray returns a uint8_t array via cgo and the array's len and
// cap. This is only used for tests.
func GetCgoUint8tArray() (interface{}, int, int) {
return C.ui8ta, len(C.ui8ta), cap(C.ui8ta)
}
// GetCgoTypdefedUnsignedCharArray returns a typedefed unsigned char array via
// cgo and the array's len and cap. This is only used for tests.
func GetCgoTypdefedUnsignedCharArray() (interface{}, int, int) {
return C.tuca, len(C.tuca), cap(C.tuca)
}

View File

@ -1,15 +0,0 @@
# Golang CircleCI 2.0 configuration file
#
# Check https://circleci.com/docs/2.0/language-go/ for more details
version: 2
jobs:
build:
docker:
- image: circleci/golang:1.9
working_directory: /go/src/github.com/google/gops
steps:
- checkout
# specify any bash command here prefixed with `run: `
- run: go test -v ./...

View File

@ -1,33 +0,0 @@
# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
[[projects]]
branch = "master"
name = "github.com/kardianos/osext"
packages = ["."]
revision = "ae77be60afb1dcacde03767a8c37337fad28ac14"
[[projects]]
branch = "master"
name = "github.com/keybase/go-ps"
packages = [".","darwincgo"]
revision = "668c8856d9992f97248b3177d45743d2cc1068db"
[[projects]]
branch = "master"
name = "golang.org/x/arch"
packages = ["arm/armasm","ppc64/ppc64asm","x86/x86asm"]
revision = "f185940480d2c897e1ca8cf2f1be122e1258341b"
[[projects]]
name = "rsc.io/goversion"
packages = ["version"]
revision = "84cd9d26d7efce780a7aaafd0944961371da741f"
version = "v1.0.0"
[solve-meta]
analyzer-name = "dep"
analyzer-version = 1
inputs-digest = "4b494828d559e89fc1fe70b9bfdd0f5c8ad62ee16258a3b2bcf1028c140faa32"
solver-name = "gps-cdcl"
solver-version = 1

View File

@ -1,34 +0,0 @@
# Gopkg.toml example
#
# Refer to https://github.com/golang/dep/blob/master/docs/Gopkg.toml.md
# for detailed Gopkg.toml documentation.
#
# required = ["github.com/user/thing/cmd/thing"]
# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"]
#
# [[constraint]]
# name = "github.com/user/project"
# version = "1.0.0"
#
# [[constraint]]
# name = "github.com/user/project2"
# branch = "dev"
# source = "github.com/myfork/project2"
#
# [[override]]
# name = "github.com/x/y"
# version = "2.4.0"
[[constraint]]
branch = "master"
name = "github.com/kardianos/osext"
[[constraint]]
branch = "master"
name = "github.com/keybase/go-ps"
[[constraint]]
branch = "master"
name = "golang.org/x/arch"

View File

@ -1,27 +0,0 @@
Copyright (c) 2016 The Go Authors. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@ -1,150 +0,0 @@
# gops
[![Build status](https://circleci.com/gh/google/gops/tree/master.svg?style=shield&circle-token=2637dc1e57d5407ae250480a86a2e553a7d20482)](https://circleci.com/gh/google/gops)
[![GoDoc](https://godoc.org/github.com/google/gops/agent?status.svg)](https://godoc.org/github.com/google/gops/agent)
gops is a command to list and diagnose Go processes currently running on your system.
```
$ gops
983 uplink-soecks (/usr/local/bin/uplink-soecks)
52697 gops (/Users/jbd/bin/gops)
4132* foops (/Users/jbd/bin/foops)
51130 gocode (/Users/jbd/bin/gocode)
```
## Installation
```
$ go get -u github.com/google/gops
```
## Diagnostics
For processes that starts the diagnostics agent, gops can report
additional information such as the current stack trace, Go version, memory
stats, etc.
In order to start the diagnostics agent, see the [hello example](https://github.com/google/gops/blob/master/examples/hello/main.go).
``` go
package main
import (
"log"
"time"
"github.com/google/gops/agent"
)
func main() {
if err := agent.Listen(nil); err != nil {
log.Fatal(err)
}
time.Sleep(time.Hour)
}
```
### Manual
It is possible to use gops tool both in local and remote mode.
Local mode requires that you start the target binary as the same user that runs gops binary.
To use gops in a remote mode you need to know target's agent address.
In Local mode use process's PID as a target; in Remote mode target is a `host:port` combination.
#### 0. Listing all processes running locally
To print all go processes, run `gops` without arguments:
```sh
$ gops
983 uplink-soecks (/usr/local/bin/uplink-soecks)
52697 gops (/Users/jbd/bin/gops)
4132* foops (/Users/jbd/bin/foops)
51130 gocode (/Users/jbd/bin/gocode)
```
Note that processes running the agent are marked with `*` next to the PID (e.g. `4132*`).
#### $ gops stack (\<pid\>|\<addr\>)
In order to print the current stack trace from a target program, run the following command:
```sh
$ gops stack (<pid>|<addr>)
gops stack 85709
goroutine 8 [running]:
runtime/pprof.writeGoroutineStacks(0x13c7bc0, 0xc42000e008, 0xc420ec8520, 0xc420ec8520)
/Users/jbd/go/src/runtime/pprof/pprof.go:603 +0x79
runtime/pprof.writeGoroutine(0x13c7bc0, 0xc42000e008, 0x2, 0xc428f1c048, 0xc420ec8608)
/Users/jbd/go/src/runtime/pprof/pprof.go:592 +0x44
runtime/pprof.(*Profile).WriteTo(0x13eeda0, 0x13c7bc0, 0xc42000e008, 0x2, 0xc42000e008, 0x0)
/Users/jbd/go/src/runtime/pprof/pprof.go:302 +0x3b5
github.com/google/gops/agent.handle(0x13cd560, 0xc42000e008, 0xc420186000, 0x1, 0x1, 0x0, 0x0)
/Users/jbd/src/github.com/google/gops/agent/agent.go:150 +0x1b3
github.com/google/gops/agent.listen()
/Users/jbd/src/github.com/google/gops/agent/agent.go:113 +0x2b2
created by github.com/google/gops/agent.Listen
/Users/jbd/src/github.com/google/gops/agent/agent.go:94 +0x480
# ...
```
#### $ gops memstats (\<pid\>|\<addr\>)
To print the current memory stats, run the following command:
```sh
$ gops memstats (<pid>|<addr>)
```
#### $ gops gc (\<pid\>|\<addr\>)
If you want to force run garbage collection on the target program, run `gc`.
It will block until the GC is completed.
#### $ gops version (\<pid\>|\<addr\>)
gops reports the Go version the target program is built with, if you run the following:
```sh
$ gops version (<pid>|<addr>)
devel +6a3c6c0 Sat Jan 14 05:57:07 2017 +0000
```
#### $ gops stats (\<pid\>|\<addr\>)
To print the runtime statistics such as number of goroutines and `GOMAXPROCS`.
#### Profiling
##### Pprof
gops supports CPU and heap pprof profiles. After reading either heap or CPU profile,
it shells out to the `go tool pprof` and let you interatively examine the profiles.
To enter the CPU profile, run:
```sh
$ gops pprof-cpu (<pid>|<addr>)
```
To enter the heap profile, run:
```sh
$ gops pprof-heap (<pid>|<addr>)
```
##### Execution trace
gops allows you to start the runtime tracer for 5 seconds and examine the results.
```sh
$ gops trace (<pid>|<addr>)
```

185
vendor/github.com/google/gops/cmd.go generated vendored
View File

@ -1,185 +0,0 @@
package main
import (
"errors"
"fmt"
"io"
"io/ioutil"
"net"
"os"
"os/exec"
"strconv"
"strings"
"github.com/google/gops/internal"
"github.com/google/gops/signal"
)
var cmds = map[string](func(addr net.TCPAddr) error){
"stack": stackTrace,
"gc": gc,
"memstats": memStats,
"version": version,
"pprof-heap": pprofHeap,
"pprof-cpu": pprofCPU,
"stats": stats,
"trace": trace,
}
func stackTrace(addr net.TCPAddr) error {
return cmdWithPrint(addr, signal.StackTrace)
}
func gc(addr net.TCPAddr) error {
_, err := cmd(addr, signal.GC)
return err
}
func memStats(addr net.TCPAddr) error {
return cmdWithPrint(addr, signal.MemStats)
}
func version(addr net.TCPAddr) error {
return cmdWithPrint(addr, signal.Version)
}
func pprofHeap(addr net.TCPAddr) error {
return pprof(addr, signal.HeapProfile)
}
func pprofCPU(addr net.TCPAddr) error {
fmt.Println("Profiling CPU now, will take 30 secs...")
return pprof(addr, signal.CPUProfile)
}
func trace(addr net.TCPAddr) error {
fmt.Println("Tracing now, will take 5 secs...")
out, err := cmd(addr, signal.Trace)
if err != nil {
return err
}
if len(out) == 0 {
return errors.New("nothing has traced")
}
tmpfile, err := ioutil.TempFile("", "trace")
if err != nil {
return err
}
defer os.Remove(tmpfile.Name())
if err := ioutil.WriteFile(tmpfile.Name(), out, 0); err != nil {
return err
}
fmt.Printf("Trace dump saved to: %s\n", tmpfile.Name())
cmd := exec.Command("go", "tool", "trace", tmpfile.Name())
cmd.Env = os.Environ()
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
return cmd.Run()
}
func pprof(addr net.TCPAddr, p byte) error {
tmpDumpFile, err := ioutil.TempFile("", "profile")
if err != nil {
return err
}
{
out, err := cmd(addr, p)
if err != nil {
return err
}
if len(out) == 0 {
return errors.New("failed to read the profile")
}
defer os.Remove(tmpDumpFile.Name())
if err := ioutil.WriteFile(tmpDumpFile.Name(), out, 0); err != nil {
return err
}
}
// Download running binary
tmpBinFile, err := ioutil.TempFile("", "binary")
if err != nil {
return err
}
{
out, err := cmd(addr, signal.BinaryDump)
if err != nil {
return fmt.Errorf("failed to read the binary: %v", err)
}
if len(out) == 0 {
return errors.New("failed to read the binary")
}
defer os.Remove(tmpBinFile.Name())
if err := ioutil.WriteFile(tmpBinFile.Name(), out, 0); err != nil {
return err
}
}
fmt.Printf("Profiling dump saved to: %s\n", tmpDumpFile.Name())
fmt.Printf("Binary file saved to: %s\n", tmpBinFile.Name())
cmd := exec.Command("go", "tool", "pprof", tmpBinFile.Name(), tmpDumpFile.Name())
cmd.Env = os.Environ()
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
return cmd.Run()
}
func stats(addr net.TCPAddr) error {
return cmdWithPrint(addr, signal.Stats)
}
func cmdWithPrint(addr net.TCPAddr, c byte) error {
out, err := cmd(addr, c)
if err != nil {
return err
}
fmt.Printf("%s", out)
return nil
}
// targetToAddr tries to parse the target string, be it remote host:port
// or local process's PID.
func targetToAddr(target string) (*net.TCPAddr, error) {
if strings.Index(target, ":") != -1 {
// addr host:port passed
var err error
addr, err := net.ResolveTCPAddr("tcp", target)
if err != nil {
return nil, fmt.Errorf("couldn't parse dst address: %v", err)
}
return addr, nil
}
// try to find port by pid then, connect to local
pid, err := strconv.Atoi(target)
if err != nil {
return nil, fmt.Errorf("couldn't parse PID: %v", err)
}
port, err := internal.GetPort(pid)
addr, _ := net.ResolveTCPAddr("tcp", "127.0.0.1:"+port)
return addr, nil
}
func cmd(addr net.TCPAddr, c byte) ([]byte, error) {
conn, err := cmdLazy(addr, c)
if err != nil {
return nil, fmt.Errorf("couldn't get port by PID: %v", err)
}
all, err := ioutil.ReadAll(conn)
if err != nil {
return nil, err
}
return all, nil
}
func cmdLazy(addr net.TCPAddr, c byte) (io.Reader, error) {
conn, err := net.DialTCP("tcp", nil, &addr)
if err != nil {
return nil, err
}
if _, err := conn.Write([]byte{c}); err != nil {
return nil, err
}
return conn, nil
}

View File

@ -1,19 +0,0 @@
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package main
import (
"log"
"time"
"github.com/google/gops/agent"
)
func main() {
if err := agent.Listen(nil); err != nil {
log.Fatal(err)
}
time.Sleep(time.Hour)
}

View File

@ -1,112 +0,0 @@
// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package goprocess reports the Go processes running on a host.
package goprocess
import (
"os"
"sync"
goversion "rsc.io/goversion/version"
"github.com/google/gops/internal"
ps "github.com/keybase/go-ps"
)
// P represents a Go process.
type P struct {
PID int
PPID int
Exec string
Path string
BuildVersion string
Agent bool
}
// FindAll returns all the Go processes currently running on this host.
func FindAll() []P {
var results []P
pss, err := ps.Processes()
if err != nil {
return results
}
var wg sync.WaitGroup
wg.Add(len(pss))
for _, pr := range pss {
pr := pr
go func() {
defer wg.Done()
path, version, agent, ok, err := isGo(pr)
if err != nil {
// TODO(jbd): Return a list of errors.
}
if !ok {
return
}
results = append(results, P{
PID: pr.Pid(),
PPID: pr.PPid(),
Exec: pr.Executable(),
Path: path,
BuildVersion: version,
Agent: agent,
})
}()
}
wg.Wait()
return results
}
// Find finds info about the process identified with the given PID.
func Find(pid int) (p P, ok bool, err error) {
pr, err := ps.FindProcess(pid)
if err != nil {
return P{}, false, err
}
path, version, agent, ok, err := isGo(pr)
if !ok {
return P{}, false, nil
}
return P{
PID: pr.Pid(),
PPID: pr.PPid(),
Exec: pr.Executable(),
Path: path,
BuildVersion: version,
Agent: agent,
}, true, nil
}
// isGo looks up the runtime.buildVersion symbol
// in the process' binary and determines if the process
// if a Go process or not. If the process is a Go process,
// it reports PID, binary name and full path of the binary.
func isGo(pr ps.Process) (path, version string, agent, ok bool, err error) {
if pr.Pid() == 0 {
// ignore system process
return
}
path, err = pr.Path()
if err != nil {
return
}
var versionInfo goversion.Version
versionInfo, err = goversion.ReadExe(path)
if err != nil {
return
}
ok = true
version = versionInfo.Release
pidfile, err := internal.PIDFile(pr.Pid())
if err == nil {
_, err := os.Stat(pidfile)
agent = err == nil
}
return path, version, agent, ok, nil
}

View File

@ -1,600 +0,0 @@
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package dwarf generates DWARF debugging information.
// DWARF generation is split between the compiler and the linker,
// this package contains the shared code.
package dwarf
import (
"fmt"
)
// InfoPrefix is the prefix for all the symbols containing DWARF info entries.
const InfoPrefix = "go.info."
// Sym represents a symbol.
type Sym interface {
}
// A Var represents a local variable or a function parameter.
type Var struct {
Name string
Abbrev int // Either DW_ABRV_AUTO or DW_ABRV_PARAM
Offset int32
Type Sym
Link *Var
}
// A Context specifies how to add data to a Sym.
type Context interface {
PtrSize() int
AddInt(s Sym, size int, i int64)
AddBytes(s Sym, b []byte)
AddAddress(s Sym, t interface{}, ofs int64)
AddSectionOffset(s Sym, size int, t interface{}, ofs int64)
AddString(s Sym, v string)
SymValue(s Sym) int64
}
// AppendUleb128 appends v to b using DWARF's unsigned LEB128 encoding.
func AppendUleb128(b []byte, v uint64) []byte {
for {
c := uint8(v & 0x7f)
v >>= 7
if v != 0 {
c |= 0x80
}
b = append(b, c)
if c&0x80 == 0 {
break
}
}
return b
}
// AppendSleb128 appends v to b using DWARF's signed LEB128 encoding.
func AppendSleb128(b []byte, v int64) []byte {
for {
c := uint8(v & 0x7f)
s := uint8(v & 0x40)
v >>= 7
if (v != -1 || s == 0) && (v != 0 || s != 0) {
c |= 0x80
}
b = append(b, c)
if c&0x80 == 0 {
break
}
}
return b
}
var encbuf [20]byte
// AppendUleb128 appends v to s using DWARF's unsigned LEB128 encoding.
func Uleb128put(ctxt Context, s Sym, v int64) {
b := AppendUleb128(encbuf[:0], uint64(v))
ctxt.AddBytes(s, b)
}
// AppendUleb128 appends v to s using DWARF's signed LEB128 encoding.
func Sleb128put(ctxt Context, s Sym, v int64) {
b := AppendSleb128(encbuf[:0], v)
ctxt.AddBytes(s, b)
}
/*
* Defining Abbrevs. This is hardcoded, and there will be
* only a handful of them. The DWARF spec places no restriction on
* the ordering of attributes in the Abbrevs and DIEs, and we will
* always write them out in the order of declaration in the abbrev.
*/
type dwAttrForm struct {
attr uint16
form uint8
}
// Go-specific type attributes.
const (
DW_AT_go_kind = 0x2900
DW_AT_go_key = 0x2901
DW_AT_go_elem = 0x2902
DW_AT_internal_location = 253 // params and locals; not emitted
)
// Index into the abbrevs table below.
// Keep in sync with ispubname() and ispubtype() below.
// ispubtype considers >= NULLTYPE public
const (
DW_ABRV_NULL = iota
DW_ABRV_COMPUNIT
DW_ABRV_FUNCTION
DW_ABRV_VARIABLE
DW_ABRV_AUTO
DW_ABRV_PARAM
DW_ABRV_STRUCTFIELD
DW_ABRV_FUNCTYPEPARAM
DW_ABRV_DOTDOTDOT
DW_ABRV_ARRAYRANGE
DW_ABRV_NULLTYPE
DW_ABRV_BASETYPE
DW_ABRV_ARRAYTYPE
DW_ABRV_CHANTYPE
DW_ABRV_FUNCTYPE
DW_ABRV_IFACETYPE
DW_ABRV_MAPTYPE
DW_ABRV_PTRTYPE
DW_ABRV_BARE_PTRTYPE // only for void*, no DW_AT_type attr to please gdb 6.
DW_ABRV_SLICETYPE
DW_ABRV_STRINGTYPE
DW_ABRV_STRUCTTYPE
DW_ABRV_TYPEDECL
DW_NABRV
)
type dwAbbrev struct {
tag uint8
children uint8
attr []dwAttrForm
}
var abbrevs = [DW_NABRV]dwAbbrev{
/* The mandatory DW_ABRV_NULL entry. */
{0, 0, []dwAttrForm{}},
/* COMPUNIT */
{
DW_TAG_compile_unit,
DW_CHILDREN_yes,
[]dwAttrForm{
{DW_AT_name, DW_FORM_string},
{DW_AT_language, DW_FORM_data1},
{DW_AT_low_pc, DW_FORM_addr},
{DW_AT_high_pc, DW_FORM_addr},
{DW_AT_stmt_list, DW_FORM_data4},
{DW_AT_comp_dir, DW_FORM_string},
},
},
/* FUNCTION */
{
DW_TAG_subprogram,
DW_CHILDREN_yes,
[]dwAttrForm{
{DW_AT_name, DW_FORM_string},
{DW_AT_low_pc, DW_FORM_addr},
{DW_AT_high_pc, DW_FORM_addr},
{DW_AT_external, DW_FORM_flag},
},
},
/* VARIABLE */
{
DW_TAG_variable,
DW_CHILDREN_no,
[]dwAttrForm{
{DW_AT_name, DW_FORM_string},
{DW_AT_location, DW_FORM_block1},
{DW_AT_type, DW_FORM_ref_addr},
{DW_AT_external, DW_FORM_flag},
},
},
/* AUTO */
{
DW_TAG_variable,
DW_CHILDREN_no,
[]dwAttrForm{
{DW_AT_name, DW_FORM_string},
{DW_AT_location, DW_FORM_block1},
{DW_AT_type, DW_FORM_ref_addr},
},
},
/* PARAM */
{
DW_TAG_formal_parameter,
DW_CHILDREN_no,
[]dwAttrForm{
{DW_AT_name, DW_FORM_string},
{DW_AT_location, DW_FORM_block1},
{DW_AT_type, DW_FORM_ref_addr},
},
},
/* STRUCTFIELD */
{
DW_TAG_member,
DW_CHILDREN_no,
[]dwAttrForm{
{DW_AT_name, DW_FORM_string},
{DW_AT_data_member_location, DW_FORM_block1},
{DW_AT_type, DW_FORM_ref_addr},
},
},
/* FUNCTYPEPARAM */
{
DW_TAG_formal_parameter,
DW_CHILDREN_no,
// No name!
[]dwAttrForm{
{DW_AT_type, DW_FORM_ref_addr},
},
},
/* DOTDOTDOT */
{
DW_TAG_unspecified_parameters,
DW_CHILDREN_no,
[]dwAttrForm{},
},
/* ARRAYRANGE */
{
DW_TAG_subrange_type,
DW_CHILDREN_no,
// No name!
[]dwAttrForm{
{DW_AT_type, DW_FORM_ref_addr},
{DW_AT_count, DW_FORM_udata},
},
},
// Below here are the types considered public by ispubtype
/* NULLTYPE */
{
DW_TAG_unspecified_type,
DW_CHILDREN_no,
[]dwAttrForm{
{DW_AT_name, DW_FORM_string},
},
},
/* BASETYPE */
{
DW_TAG_base_type,
DW_CHILDREN_no,
[]dwAttrForm{
{DW_AT_name, DW_FORM_string},
{DW_AT_encoding, DW_FORM_data1},
{DW_AT_byte_size, DW_FORM_data1},
{DW_AT_go_kind, DW_FORM_data1},
},
},
/* ARRAYTYPE */
// child is subrange with upper bound
{
DW_TAG_array_type,
DW_CHILDREN_yes,
[]dwAttrForm{
{DW_AT_name, DW_FORM_string},
{DW_AT_type, DW_FORM_ref_addr},
{DW_AT_byte_size, DW_FORM_udata},
{DW_AT_go_kind, DW_FORM_data1},
},
},
/* CHANTYPE */
{
DW_TAG_typedef,
DW_CHILDREN_no,
[]dwAttrForm{
{DW_AT_name, DW_FORM_string},
{DW_AT_type, DW_FORM_ref_addr},
{DW_AT_go_kind, DW_FORM_data1},
{DW_AT_go_elem, DW_FORM_ref_addr},
},
},
/* FUNCTYPE */
{
DW_TAG_subroutine_type,
DW_CHILDREN_yes,
[]dwAttrForm{
{DW_AT_name, DW_FORM_string},
// {DW_AT_type, DW_FORM_ref_addr},
{DW_AT_go_kind, DW_FORM_data1},
},
},
/* IFACETYPE */
{
DW_TAG_typedef,
DW_CHILDREN_yes,
[]dwAttrForm{
{DW_AT_name, DW_FORM_string},
{DW_AT_type, DW_FORM_ref_addr},
{DW_AT_go_kind, DW_FORM_data1},
},
},
/* MAPTYPE */
{
DW_TAG_typedef,
DW_CHILDREN_no,
[]dwAttrForm{
{DW_AT_name, DW_FORM_string},
{DW_AT_type, DW_FORM_ref_addr},
{DW_AT_go_kind, DW_FORM_data1},
{DW_AT_go_key, DW_FORM_ref_addr},
{DW_AT_go_elem, DW_FORM_ref_addr},
},
},
/* PTRTYPE */
{
DW_TAG_pointer_type,
DW_CHILDREN_no,
[]dwAttrForm{
{DW_AT_name, DW_FORM_string},
{DW_AT_type, DW_FORM_ref_addr},
{DW_AT_go_kind, DW_FORM_data1},
},
},
/* BARE_PTRTYPE */
{
DW_TAG_pointer_type,
DW_CHILDREN_no,
[]dwAttrForm{
{DW_AT_name, DW_FORM_string},
},
},
/* SLICETYPE */
{
DW_TAG_structure_type,
DW_CHILDREN_yes,
[]dwAttrForm{
{DW_AT_name, DW_FORM_string},
{DW_AT_byte_size, DW_FORM_udata},
{DW_AT_go_kind, DW_FORM_data1},
{DW_AT_go_elem, DW_FORM_ref_addr},
},
},
/* STRINGTYPE */
{
DW_TAG_structure_type,
DW_CHILDREN_yes,
[]dwAttrForm{
{DW_AT_name, DW_FORM_string},
{DW_AT_byte_size, DW_FORM_udata},
{DW_AT_go_kind, DW_FORM_data1},
},
},
/* STRUCTTYPE */
{
DW_TAG_structure_type,
DW_CHILDREN_yes,
[]dwAttrForm{
{DW_AT_name, DW_FORM_string},
{DW_AT_byte_size, DW_FORM_udata},
{DW_AT_go_kind, DW_FORM_data1},
},
},
/* TYPEDECL */
{
DW_TAG_typedef,
DW_CHILDREN_no,
[]dwAttrForm{
{DW_AT_name, DW_FORM_string},
{DW_AT_type, DW_FORM_ref_addr},
},
},
}
// GetAbbrev returns the contents of the .debug_abbrev section.
func GetAbbrev() []byte {
var buf []byte
for i := 1; i < DW_NABRV; i++ {
// See section 7.5.3
buf = AppendUleb128(buf, uint64(i))
buf = AppendUleb128(buf, uint64(abbrevs[i].tag))
buf = append(buf, byte(abbrevs[i].children))
for _, f := range abbrevs[i].attr {
buf = AppendUleb128(buf, uint64(f.attr))
buf = AppendUleb128(buf, uint64(f.form))
}
buf = append(buf, 0, 0)
}
return append(buf, 0)
}
/*
* Debugging Information Entries and their attributes.
*/
// DWAttr represents an attribute of a DWDie.
//
// For DW_CLS_string and _block, value should contain the length, and
// data the data, for _reference, value is 0 and data is a DWDie* to
// the referenced instance, for all others, value is the whole thing
// and data is null.
type DWAttr struct {
Link *DWAttr
Atr uint16 // DW_AT_
Cls uint8 // DW_CLS_
Value int64
Data interface{}
}
// DWDie represents a DWARF debug info entry.
type DWDie struct {
Abbrev int
Link *DWDie
Child *DWDie
Attr *DWAttr
Sym Sym
}
func putattr(ctxt Context, s Sym, abbrev int, form int, cls int, value int64, data interface{}) error {
switch form {
case DW_FORM_addr: // address
ctxt.AddAddress(s, data, value)
case DW_FORM_block1: // block
if cls == DW_CLS_ADDRESS {
ctxt.AddInt(s, 1, int64(1+ctxt.PtrSize()))
ctxt.AddInt(s, 1, DW_OP_addr)
ctxt.AddAddress(s, data, 0)
break
}
value &= 0xff
ctxt.AddInt(s, 1, value)
p := data.([]byte)[:value]
ctxt.AddBytes(s, p)
case DW_FORM_block2: // block
value &= 0xffff
ctxt.AddInt(s, 2, value)
p := data.([]byte)[:value]
ctxt.AddBytes(s, p)
case DW_FORM_block4: // block
value &= 0xffffffff
ctxt.AddInt(s, 4, value)
p := data.([]byte)[:value]
ctxt.AddBytes(s, p)
case DW_FORM_block: // block
Uleb128put(ctxt, s, value)
p := data.([]byte)[:value]
ctxt.AddBytes(s, p)
case DW_FORM_data1: // constant
ctxt.AddInt(s, 1, value)
case DW_FORM_data2: // constant
ctxt.AddInt(s, 2, value)
case DW_FORM_data4: // constant, {line,loclist,mac,rangelist}ptr
if cls == DW_CLS_PTR { // DW_AT_stmt_list
ctxt.AddSectionOffset(s, 4, data, 0)
break
}
ctxt.AddInt(s, 4, value)
case DW_FORM_data8: // constant, {line,loclist,mac,rangelist}ptr
ctxt.AddInt(s, 8, value)
case DW_FORM_sdata: // constant
Sleb128put(ctxt, s, value)
case DW_FORM_udata: // constant
Uleb128put(ctxt, s, value)
case DW_FORM_string: // string
str := data.(string)
ctxt.AddString(s, str)
// TODO(ribrdb): verify padded strings are never used and remove this
for i := int64(len(str)); i < value; i++ {
ctxt.AddInt(s, 1, 0)
}
case DW_FORM_flag: // flag
if value != 0 {
ctxt.AddInt(s, 1, 1)
} else {
ctxt.AddInt(s, 1, 0)
}
// In DWARF 2 (which is what we claim to generate),
// the ref_addr is the same size as a normal address.
// In DWARF 3 it is always 32 bits, unless emitting a large
// (> 4 GB of debug info aka "64-bit") unit, which we don't implement.
case DW_FORM_ref_addr: // reference to a DIE in the .info section
if data == nil {
return fmt.Errorf("dwarf: null reference in %d", abbrev)
} else {
ctxt.AddSectionOffset(s, ctxt.PtrSize(), data, 0)
}
case DW_FORM_ref1, // reference within the compilation unit
DW_FORM_ref2, // reference
DW_FORM_ref4, // reference
DW_FORM_ref8, // reference
DW_FORM_ref_udata, // reference
DW_FORM_strp, // string
DW_FORM_indirect: // (see Section 7.5.3)
fallthrough
default:
return fmt.Errorf("dwarf: unsupported attribute form %d / class %d", form, cls)
}
return nil
}
// PutAttrs writes the attributes for a DIE to symbol 's'.
//
// Note that we can (and do) add arbitrary attributes to a DIE, but
// only the ones actually listed in the Abbrev will be written out.
func PutAttrs(ctxt Context, s Sym, abbrev int, attr *DWAttr) {
Outer:
for _, f := range abbrevs[abbrev].attr {
for ap := attr; ap != nil; ap = ap.Link {
if ap.Atr == f.attr {
putattr(ctxt, s, abbrev, int(f.form), int(ap.Cls), ap.Value, ap.Data)
continue Outer
}
}
putattr(ctxt, s, abbrev, int(f.form), 0, 0, nil)
}
}
// HasChildren returns true if 'die' uses an abbrev that supports children.
func HasChildren(die *DWDie) bool {
return abbrevs[die.Abbrev].children != 0
}
// PutFunc writes a DIE for a function to s.
// It also writes child DIEs for each variable in vars.
func PutFunc(ctxt Context, s Sym, name string, external bool, startPC Sym, size int64, vars *Var) {
Uleb128put(ctxt, s, DW_ABRV_FUNCTION)
putattr(ctxt, s, DW_ABRV_FUNCTION, DW_FORM_string, DW_CLS_STRING, int64(len(name)), name)
putattr(ctxt, s, DW_ABRV_FUNCTION, DW_FORM_addr, DW_CLS_ADDRESS, 0, startPC)
putattr(ctxt, s, DW_ABRV_FUNCTION, DW_FORM_addr, DW_CLS_ADDRESS, size+ctxt.SymValue(startPC), startPC)
var ev int64
if external {
ev = 1
}
putattr(ctxt, s, DW_ABRV_FUNCTION, DW_FORM_flag, DW_CLS_FLAG, ev, 0)
names := make(map[string]bool)
for v := vars; v != nil; v = v.Link {
var n string
if names[v.Name] {
n = fmt.Sprintf("%s#%d", v.Name, len(names))
} else {
n = v.Name
}
names[n] = true
Uleb128put(ctxt, s, int64(v.Abbrev))
putattr(ctxt, s, v.Abbrev, DW_FORM_string, DW_CLS_STRING, int64(len(n)), n)
loc := append(encbuf[:0], DW_OP_call_frame_cfa)
if v.Offset != 0 {
loc = append(loc, DW_OP_consts)
loc = AppendSleb128(loc, int64(v.Offset))
loc = append(loc, DW_OP_plus)
}
putattr(ctxt, s, v.Abbrev, DW_FORM_block1, DW_CLS_BLOCK, int64(len(loc)), loc)
putattr(ctxt, s, v.Abbrev, DW_FORM_ref_addr, DW_CLS_REFERENCE, 0, v.Type)
}
Uleb128put(ctxt, s, 0)
}

View File

@ -1,483 +0,0 @@
// Copyright 2010 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package dwarf
// Cut, pasted, tr-and-awk'ed from tables in
// http://dwarfstd.org/doc/Dwarf3.pdf
// Table 18
const (
DW_TAG_array_type = 0x01
DW_TAG_class_type = 0x02
DW_TAG_entry_point = 0x03
DW_TAG_enumeration_type = 0x04
DW_TAG_formal_parameter = 0x05
DW_TAG_imported_declaration = 0x08
DW_TAG_label = 0x0a
DW_TAG_lexical_block = 0x0b
DW_TAG_member = 0x0d
DW_TAG_pointer_type = 0x0f
DW_TAG_reference_type = 0x10
DW_TAG_compile_unit = 0x11
DW_TAG_string_type = 0x12
DW_TAG_structure_type = 0x13
DW_TAG_subroutine_type = 0x15
DW_TAG_typedef = 0x16
DW_TAG_union_type = 0x17
DW_TAG_unspecified_parameters = 0x18
DW_TAG_variant = 0x19
DW_TAG_common_block = 0x1a
DW_TAG_common_inclusion = 0x1b
DW_TAG_inheritance = 0x1c
DW_TAG_inlined_subroutine = 0x1d
DW_TAG_module = 0x1e
DW_TAG_ptr_to_member_type = 0x1f
DW_TAG_set_type = 0x20
DW_TAG_subrange_type = 0x21
DW_TAG_with_stmt = 0x22
DW_TAG_access_declaration = 0x23
DW_TAG_base_type = 0x24
DW_TAG_catch_block = 0x25
DW_TAG_const_type = 0x26
DW_TAG_constant = 0x27
DW_TAG_enumerator = 0x28
DW_TAG_file_type = 0x29
DW_TAG_friend = 0x2a
DW_TAG_namelist = 0x2b
DW_TAG_namelist_item = 0x2c
DW_TAG_packed_type = 0x2d
DW_TAG_subprogram = 0x2e
DW_TAG_template_type_parameter = 0x2f
DW_TAG_template_value_parameter = 0x30
DW_TAG_thrown_type = 0x31
DW_TAG_try_block = 0x32
DW_TAG_variant_part = 0x33
DW_TAG_variable = 0x34
DW_TAG_volatile_type = 0x35
// Dwarf3
DW_TAG_dwarf_procedure = 0x36
DW_TAG_restrict_type = 0x37
DW_TAG_interface_type = 0x38
DW_TAG_namespace = 0x39
DW_TAG_imported_module = 0x3a
DW_TAG_unspecified_type = 0x3b
DW_TAG_partial_unit = 0x3c
DW_TAG_imported_unit = 0x3d
DW_TAG_condition = 0x3f
DW_TAG_shared_type = 0x40
// Dwarf4
DW_TAG_type_unit = 0x41
DW_TAG_rvalue_reference_type = 0x42
DW_TAG_template_alias = 0x43
// User defined
DW_TAG_lo_user = 0x4080
DW_TAG_hi_user = 0xffff
)
// Table 19
const (
DW_CHILDREN_no = 0x00
DW_CHILDREN_yes = 0x01
)
// Not from the spec, but logically belongs here
const (
DW_CLS_ADDRESS = 0x01 + iota
DW_CLS_BLOCK
DW_CLS_CONSTANT
DW_CLS_FLAG
DW_CLS_PTR // lineptr, loclistptr, macptr, rangelistptr
DW_CLS_REFERENCE
DW_CLS_ADDRLOC
DW_CLS_STRING
)
// Table 20
const (
DW_AT_sibling = 0x01 // reference
DW_AT_location = 0x02 // block, loclistptr
DW_AT_name = 0x03 // string
DW_AT_ordering = 0x09 // constant
DW_AT_byte_size = 0x0b // block, constant, reference
DW_AT_bit_offset = 0x0c // block, constant, reference
DW_AT_bit_size = 0x0d // block, constant, reference
DW_AT_stmt_list = 0x10 // lineptr
DW_AT_low_pc = 0x11 // address
DW_AT_high_pc = 0x12 // address
DW_AT_language = 0x13 // constant
DW_AT_discr = 0x15 // reference
DW_AT_discr_value = 0x16 // constant
DW_AT_visibility = 0x17 // constant
DW_AT_import = 0x18 // reference
DW_AT_string_length = 0x19 // block, loclistptr
DW_AT_common_reference = 0x1a // reference
DW_AT_comp_dir = 0x1b // string
DW_AT_const_value = 0x1c // block, constant, string
DW_AT_containing_type = 0x1d // reference
DW_AT_default_value = 0x1e // reference
DW_AT_inline = 0x20 // constant
DW_AT_is_optional = 0x21 // flag
DW_AT_lower_bound = 0x22 // block, constant, reference
DW_AT_producer = 0x25 // string
DW_AT_prototyped = 0x27 // flag
DW_AT_return_addr = 0x2a // block, loclistptr
DW_AT_start_scope = 0x2c // constant
DW_AT_bit_stride = 0x2e // constant
DW_AT_upper_bound = 0x2f // block, constant, reference
DW_AT_abstract_origin = 0x31 // reference
DW_AT_accessibility = 0x32 // constant
DW_AT_address_class = 0x33 // constant
DW_AT_artificial = 0x34 // flag
DW_AT_base_types = 0x35 // reference
DW_AT_calling_convention = 0x36 // constant
DW_AT_count = 0x37 // block, constant, reference
DW_AT_data_member_location = 0x38 // block, constant, loclistptr
DW_AT_decl_column = 0x39 // constant
DW_AT_decl_file = 0x3a // constant
DW_AT_decl_line = 0x3b // constant
DW_AT_declaration = 0x3c // flag
DW_AT_discr_list = 0x3d // block
DW_AT_encoding = 0x3e // constant
DW_AT_external = 0x3f // flag
DW_AT_frame_base = 0x40 // block, loclistptr
DW_AT_friend = 0x41 // reference
DW_AT_identifier_case = 0x42 // constant
DW_AT_macro_info = 0x43 // macptr
DW_AT_namelist_item = 0x44 // block
DW_AT_priority = 0x45 // reference
DW_AT_segment = 0x46 // block, loclistptr
DW_AT_specification = 0x47 // reference
DW_AT_static_link = 0x48 // block, loclistptr
DW_AT_type = 0x49 // reference
DW_AT_use_location = 0x4a // block, loclistptr
DW_AT_variable_parameter = 0x4b // flag
DW_AT_virtuality = 0x4c // constant
DW_AT_vtable_elem_location = 0x4d // block, loclistptr
// Dwarf3
DW_AT_allocated = 0x4e // block, constant, reference
DW_AT_associated = 0x4f // block, constant, reference
DW_AT_data_location = 0x50 // block
DW_AT_byte_stride = 0x51 // block, constant, reference
DW_AT_entry_pc = 0x52 // address
DW_AT_use_UTF8 = 0x53 // flag
DW_AT_extension = 0x54 // reference
DW_AT_ranges = 0x55 // rangelistptr
DW_AT_trampoline = 0x56 // address, flag, reference, string
DW_AT_call_column = 0x57 // constant
DW_AT_call_file = 0x58 // constant
DW_AT_call_line = 0x59 // constant
DW_AT_description = 0x5a // string
DW_AT_binary_scale = 0x5b // constant
DW_AT_decimal_scale = 0x5c // constant
DW_AT_small = 0x5d // reference
DW_AT_decimal_sign = 0x5e // constant
DW_AT_digit_count = 0x5f // constant
DW_AT_picture_string = 0x60 // string
DW_AT_mutable = 0x61 // flag
DW_AT_threads_scaled = 0x62 // flag
DW_AT_explicit = 0x63 // flag
DW_AT_object_pointer = 0x64 // reference
DW_AT_endianity = 0x65 // constant
DW_AT_elemental = 0x66 // flag
DW_AT_pure = 0x67 // flag
DW_AT_recursive = 0x68 // flag
DW_AT_lo_user = 0x2000 // ---
DW_AT_hi_user = 0x3fff // ---
)
// Table 21
const (
DW_FORM_addr = 0x01 // address
DW_FORM_block2 = 0x03 // block
DW_FORM_block4 = 0x04 // block
DW_FORM_data2 = 0x05 // constant
DW_FORM_data4 = 0x06 // constant, lineptr, loclistptr, macptr, rangelistptr
DW_FORM_data8 = 0x07 // constant, lineptr, loclistptr, macptr, rangelistptr
DW_FORM_string = 0x08 // string
DW_FORM_block = 0x09 // block
DW_FORM_block1 = 0x0a // block
DW_FORM_data1 = 0x0b // constant
DW_FORM_flag = 0x0c // flag
DW_FORM_sdata = 0x0d // constant
DW_FORM_strp = 0x0e // string
DW_FORM_udata = 0x0f // constant
DW_FORM_ref_addr = 0x10 // reference
DW_FORM_ref1 = 0x11 // reference
DW_FORM_ref2 = 0x12 // reference
DW_FORM_ref4 = 0x13 // reference
DW_FORM_ref8 = 0x14 // reference
DW_FORM_ref_udata = 0x15 // reference
DW_FORM_indirect = 0x16 // (see Section 7.5.3)
)
// Table 24 (#operands, notes)
const (
DW_OP_addr = 0x03 // 1 constant address (size target specific)
DW_OP_deref = 0x06 // 0
DW_OP_const1u = 0x08 // 1 1-byte constant
DW_OP_const1s = 0x09 // 1 1-byte constant
DW_OP_const2u = 0x0a // 1 2-byte constant
DW_OP_const2s = 0x0b // 1 2-byte constant
DW_OP_const4u = 0x0c // 1 4-byte constant
DW_OP_const4s = 0x0d // 1 4-byte constant
DW_OP_const8u = 0x0e // 1 8-byte constant
DW_OP_const8s = 0x0f // 1 8-byte constant
DW_OP_constu = 0x10 // 1 ULEB128 constant
DW_OP_consts = 0x11 // 1 SLEB128 constant
DW_OP_dup = 0x12 // 0
DW_OP_drop = 0x13 // 0
DW_OP_over = 0x14 // 0
DW_OP_pick = 0x15 // 1 1-byte stack index
DW_OP_swap = 0x16 // 0
DW_OP_rot = 0x17 // 0
DW_OP_xderef = 0x18 // 0
DW_OP_abs = 0x19 // 0
DW_OP_and = 0x1a // 0
DW_OP_div = 0x1b // 0
DW_OP_minus = 0x1c // 0
DW_OP_mod = 0x1d // 0
DW_OP_mul = 0x1e // 0
DW_OP_neg = 0x1f // 0
DW_OP_not = 0x20 // 0
DW_OP_or = 0x21 // 0
DW_OP_plus = 0x22 // 0
DW_OP_plus_uconst = 0x23 // 1 ULEB128 addend
DW_OP_shl = 0x24 // 0
DW_OP_shr = 0x25 // 0
DW_OP_shra = 0x26 // 0
DW_OP_xor = 0x27 // 0
DW_OP_skip = 0x2f // 1 signed 2-byte constant
DW_OP_bra = 0x28 // 1 signed 2-byte constant
DW_OP_eq = 0x29 // 0
DW_OP_ge = 0x2a // 0
DW_OP_gt = 0x2b // 0
DW_OP_le = 0x2c // 0
DW_OP_lt = 0x2d // 0
DW_OP_ne = 0x2e // 0
DW_OP_lit0 = 0x30 // 0 ...
DW_OP_lit31 = 0x4f // 0 literals 0..31 = (DW_OP_lit0 + literal)
DW_OP_reg0 = 0x50 // 0 ..
DW_OP_reg31 = 0x6f // 0 reg 0..31 = (DW_OP_reg0 + regnum)
DW_OP_breg0 = 0x70 // 1 ...
DW_OP_breg31 = 0x8f // 1 SLEB128 offset base register 0..31 = (DW_OP_breg0 + regnum)
DW_OP_regx = 0x90 // 1 ULEB128 register
DW_OP_fbreg = 0x91 // 1 SLEB128 offset
DW_OP_bregx = 0x92 // 2 ULEB128 register followed by SLEB128 offset
DW_OP_piece = 0x93 // 1 ULEB128 size of piece addressed
DW_OP_deref_size = 0x94 // 1 1-byte size of data retrieved
DW_OP_xderef_size = 0x95 // 1 1-byte size of data retrieved
DW_OP_nop = 0x96 // 0
DW_OP_push_object_address = 0x97 // 0
DW_OP_call2 = 0x98 // 1 2-byte offset of DIE
DW_OP_call4 = 0x99 // 1 4-byte offset of DIE
DW_OP_call_ref = 0x9a // 1 4- or 8-byte offset of DIE
DW_OP_form_tls_address = 0x9b // 0
DW_OP_call_frame_cfa = 0x9c // 0
DW_OP_bit_piece = 0x9d // 2
DW_OP_lo_user = 0xe0
DW_OP_hi_user = 0xff
)
// Table 25
const (
DW_ATE_address = 0x01
DW_ATE_boolean = 0x02
DW_ATE_complex_float = 0x03
DW_ATE_float = 0x04
DW_ATE_signed = 0x05
DW_ATE_signed_char = 0x06
DW_ATE_unsigned = 0x07
DW_ATE_unsigned_char = 0x08
DW_ATE_imaginary_float = 0x09
DW_ATE_packed_decimal = 0x0a
DW_ATE_numeric_string = 0x0b
DW_ATE_edited = 0x0c
DW_ATE_signed_fixed = 0x0d
DW_ATE_unsigned_fixed = 0x0e
DW_ATE_decimal_float = 0x0f
DW_ATE_lo_user = 0x80
DW_ATE_hi_user = 0xff
)
// Table 26
const (
DW_DS_unsigned = 0x01
DW_DS_leading_overpunch = 0x02
DW_DS_trailing_overpunch = 0x03
DW_DS_leading_separate = 0x04
DW_DS_trailing_separate = 0x05
)
// Table 27
const (
DW_END_default = 0x00
DW_END_big = 0x01
DW_END_little = 0x02
DW_END_lo_user = 0x40
DW_END_hi_user = 0xff
)
// Table 28
const (
DW_ACCESS_public = 0x01
DW_ACCESS_protected = 0x02
DW_ACCESS_private = 0x03
)
// Table 29
const (
DW_VIS_local = 0x01
DW_VIS_exported = 0x02
DW_VIS_qualified = 0x03
)
// Table 30
const (
DW_VIRTUALITY_none = 0x00
DW_VIRTUALITY_virtual = 0x01
DW_VIRTUALITY_pure_virtual = 0x02
)
// Table 31
const (
DW_LANG_C89 = 0x0001
DW_LANG_C = 0x0002
DW_LANG_Ada83 = 0x0003
DW_LANG_C_plus_plus = 0x0004
DW_LANG_Cobol74 = 0x0005
DW_LANG_Cobol85 = 0x0006
DW_LANG_Fortran77 = 0x0007
DW_LANG_Fortran90 = 0x0008
DW_LANG_Pascal83 = 0x0009
DW_LANG_Modula2 = 0x000a
// Dwarf3
DW_LANG_Java = 0x000b
DW_LANG_C99 = 0x000c
DW_LANG_Ada95 = 0x000d
DW_LANG_Fortran95 = 0x000e
DW_LANG_PLI = 0x000f
DW_LANG_ObjC = 0x0010
DW_LANG_ObjC_plus_plus = 0x0011
DW_LANG_UPC = 0x0012
DW_LANG_D = 0x0013
// Dwarf4
DW_LANG_Python = 0x0014
// Dwarf5
DW_LANG_Go = 0x0016
DW_LANG_lo_user = 0x8000
DW_LANG_hi_user = 0xffff
)
// Table 32
const (
DW_ID_case_sensitive = 0x00
DW_ID_up_case = 0x01
DW_ID_down_case = 0x02
DW_ID_case_insensitive = 0x03
)
// Table 33
const (
DW_CC_normal = 0x01
DW_CC_program = 0x02
DW_CC_nocall = 0x03
DW_CC_lo_user = 0x40
DW_CC_hi_user = 0xff
)
// Table 34
const (
DW_INL_not_inlined = 0x00
DW_INL_inlined = 0x01
DW_INL_declared_not_inlined = 0x02
DW_INL_declared_inlined = 0x03
)
// Table 35
const (
DW_ORD_row_major = 0x00
DW_ORD_col_major = 0x01
)
// Table 36
const (
DW_DSC_label = 0x00
DW_DSC_range = 0x01
)
// Table 37
const (
DW_LNS_copy = 0x01
DW_LNS_advance_pc = 0x02
DW_LNS_advance_line = 0x03
DW_LNS_set_file = 0x04
DW_LNS_set_column = 0x05
DW_LNS_negate_stmt = 0x06
DW_LNS_set_basic_block = 0x07
DW_LNS_const_add_pc = 0x08
DW_LNS_fixed_advance_pc = 0x09
// Dwarf3
DW_LNS_set_prologue_end = 0x0a
DW_LNS_set_epilogue_begin = 0x0b
DW_LNS_set_isa = 0x0c
)
// Table 38
const (
DW_LNE_end_sequence = 0x01
DW_LNE_set_address = 0x02
DW_LNE_define_file = 0x03
DW_LNE_lo_user = 0x80
DW_LNE_hi_user = 0xff
)
// Table 39
const (
DW_MACINFO_define = 0x01
DW_MACINFO_undef = 0x02
DW_MACINFO_start_file = 0x03
DW_MACINFO_end_file = 0x04
DW_MACINFO_vendor_ext = 0xff
)
// Table 40.
const (
// operand,...
DW_CFA_nop = 0x00
DW_CFA_set_loc = 0x01 // address
DW_CFA_advance_loc1 = 0x02 // 1-byte delta
DW_CFA_advance_loc2 = 0x03 // 2-byte delta
DW_CFA_advance_loc4 = 0x04 // 4-byte delta
DW_CFA_offset_extended = 0x05 // ULEB128 register, ULEB128 offset
DW_CFA_restore_extended = 0x06 // ULEB128 register
DW_CFA_undefined = 0x07 // ULEB128 register
DW_CFA_same_value = 0x08 // ULEB128 register
DW_CFA_register = 0x09 // ULEB128 register, ULEB128 register
DW_CFA_remember_state = 0x0a
DW_CFA_restore_state = 0x0b
DW_CFA_def_cfa = 0x0c // ULEB128 register, ULEB128 offset
DW_CFA_def_cfa_register = 0x0d // ULEB128 register
DW_CFA_def_cfa_offset = 0x0e // ULEB128 offset
DW_CFA_def_cfa_expression = 0x0f // BLOCK
DW_CFA_expression = 0x10 // ULEB128 register, BLOCK
DW_CFA_offset_extended_sf = 0x11 // ULEB128 register, SLEB128 offset
DW_CFA_def_cfa_sf = 0x12 // ULEB128 register, SLEB128 offset
DW_CFA_def_cfa_offset_sf = 0x13 // SLEB128 offset
DW_CFA_val_offset = 0x14 // ULEB128, ULEB128
DW_CFA_val_offset_sf = 0x15 // ULEB128, SLEB128
DW_CFA_val_expression = 0x16 // ULEB128, BLOCK
DW_CFA_lo_user = 0x1c
DW_CFA_hi_user = 0x3f
// Opcodes that take an addend operand.
DW_CFA_advance_loc = 0x1 << 6 // +delta
DW_CFA_offset = 0x2 << 6 // +register (ULEB128 offset)
DW_CFA_restore = 0x3 << 6 // +register
)

View File

@ -1,714 +0,0 @@
// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package goobj implements reading of Go object files and archives.
//
// TODO(rsc): Decide where this package should live. (golang.org/issue/6932)
// TODO(rsc): Decide the appropriate integer types for various fields.
// TODO(rsc): Write tests. (File format still up in the air a little.)
package goobj
import (
"bufio"
"bytes"
"errors"
"fmt"
"io"
"strconv"
"strings"
"github.com/google/gops/internal/obj"
)
// A SymKind describes the kind of memory represented by a symbol.
type SymKind int
// This list is taken from include/link.h.
// Defined SymKind values.
// TODO(rsc): Give idiomatic Go names.
// TODO(rsc): Reduce the number of symbol types in the object files.
const (
// readonly, executable
STEXT = SymKind(obj.STEXT)
SELFRXSECT = SymKind(obj.SELFRXSECT)
// readonly, non-executable
STYPE = SymKind(obj.STYPE)
SSTRING = SymKind(obj.SSTRING)
SGOSTRING = SymKind(obj.SGOSTRING)
SGOFUNC = SymKind(obj.SGOFUNC)
SRODATA = SymKind(obj.SRODATA)
SFUNCTAB = SymKind(obj.SFUNCTAB)
STYPELINK = SymKind(obj.STYPELINK)
SITABLINK = SymKind(obj.SITABLINK)
SSYMTAB = SymKind(obj.SSYMTAB) // TODO: move to unmapped section
SPCLNTAB = SymKind(obj.SPCLNTAB)
SELFROSECT = SymKind(obj.SELFROSECT)
// writable, non-executable
SMACHOPLT = SymKind(obj.SMACHOPLT)
SELFSECT = SymKind(obj.SELFSECT)
SMACHO = SymKind(obj.SMACHO) // Mach-O __nl_symbol_ptr
SMACHOGOT = SymKind(obj.SMACHOGOT)
SWINDOWS = SymKind(obj.SWINDOWS)
SELFGOT = SymKind(obj.SELFGOT)
SNOPTRDATA = SymKind(obj.SNOPTRDATA)
SINITARR = SymKind(obj.SINITARR)
SDATA = SymKind(obj.SDATA)
SBSS = SymKind(obj.SBSS)
SNOPTRBSS = SymKind(obj.SNOPTRBSS)
STLSBSS = SymKind(obj.STLSBSS)
// not mapped
SXREF = SymKind(obj.SXREF)
SMACHOSYMSTR = SymKind(obj.SMACHOSYMSTR)
SMACHOSYMTAB = SymKind(obj.SMACHOSYMTAB)
SMACHOINDIRECTPLT = SymKind(obj.SMACHOINDIRECTPLT)
SMACHOINDIRECTGOT = SymKind(obj.SMACHOINDIRECTGOT)
SFILE = SymKind(obj.SFILE)
SFILEPATH = SymKind(obj.SFILEPATH)
SCONST = SymKind(obj.SCONST)
SDYNIMPORT = SymKind(obj.SDYNIMPORT)
SHOSTOBJ = SymKind(obj.SHOSTOBJ)
)
var symKindStrings = []string{
SBSS: "SBSS",
SCONST: "SCONST",
SDATA: "SDATA",
SDYNIMPORT: "SDYNIMPORT",
SELFROSECT: "SELFROSECT",
SELFRXSECT: "SELFRXSECT",
SELFSECT: "SELFSECT",
SFILE: "SFILE",
SFILEPATH: "SFILEPATH",
SFUNCTAB: "SFUNCTAB",
SGOFUNC: "SGOFUNC",
SGOSTRING: "SGOSTRING",
SHOSTOBJ: "SHOSTOBJ",
SINITARR: "SINITARR",
SMACHO: "SMACHO",
SMACHOGOT: "SMACHOGOT",
SMACHOINDIRECTGOT: "SMACHOINDIRECTGOT",
SMACHOINDIRECTPLT: "SMACHOINDIRECTPLT",
SMACHOPLT: "SMACHOPLT",
SMACHOSYMSTR: "SMACHOSYMSTR",
SMACHOSYMTAB: "SMACHOSYMTAB",
SNOPTRBSS: "SNOPTRBSS",
SNOPTRDATA: "SNOPTRDATA",
SPCLNTAB: "SPCLNTAB",
SRODATA: "SRODATA",
SSTRING: "SSTRING",
SSYMTAB: "SSYMTAB",
STEXT: "STEXT",
STLSBSS: "STLSBSS",
STYPE: "STYPE",
STYPELINK: "STYPELINK",
SITABLINK: "SITABLINK",
SWINDOWS: "SWINDOWS",
SXREF: "SXREF",
}
func (k SymKind) String() string {
if k < 0 || int(k) >= len(symKindStrings) {
return fmt.Sprintf("SymKind(%d)", k)
}
return symKindStrings[k]
}
// A Sym is a named symbol in an object file.
type Sym struct {
SymID // symbol identifier (name and version)
Kind SymKind // kind of symbol
DupOK bool // are duplicate definitions okay?
Size int // size of corresponding data
Type SymID // symbol for Go type information
Data Data // memory image of symbol
Reloc []Reloc // relocations to apply to Data
Func *Func // additional data for functions
}
// A SymID - the combination of Name and Version - uniquely identifies
// a symbol within a package.
type SymID struct {
// Name is the name of a symbol.
Name string
// Version is zero for symbols with global visibility.
// Symbols with only file visibility (such as file-level static
// declarations in C) have a non-zero version distinguishing
// a symbol in one file from a symbol of the same name
// in another file
Version int
}
func (s SymID) String() string {
if s.Version == 0 {
return s.Name
}
return fmt.Sprintf("%s<%d>", s.Name, s.Version)
}
// A Data is a reference to data stored in an object file.
// It records the offset and size of the data, so that a client can
// read the data only if necessary.
type Data struct {
Offset int64
Size int64
}
// A Reloc describes a relocation applied to a memory image to refer
// to an address within a particular symbol.
type Reloc struct {
// The bytes at [Offset, Offset+Size) within the containing Sym
// should be updated to refer to the address Add bytes after the start
// of the symbol Sym.
Offset int
Size int
Sym SymID
Add int
// The Type records the form of address expected in the bytes
// described by the previous fields: absolute, PC-relative, and so on.
// TODO(rsc): The interpretation of Type is not exposed by this package.
Type obj.RelocType
}
// A Var describes a variable in a function stack frame: a declared
// local variable, an input argument, or an output result.
type Var struct {
// The combination of Name, Kind, and Offset uniquely
// identifies a variable in a function stack frame.
// Using fewer of these - in particular, using only Name - does not.
Name string // Name of variable.
Kind int // TODO(rsc): Define meaning.
Offset int // Frame offset. TODO(rsc): Define meaning.
Type SymID // Go type for variable.
}
// Func contains additional per-symbol information specific to functions.
type Func struct {
Args int // size in bytes of argument frame: inputs and outputs
Frame int // size in bytes of local variable frame
Leaf bool // function omits save of link register (ARM)
NoSplit bool // function omits stack split prologue
Var []Var // detail about local variables
PCSP Data // PC → SP offset map
PCFile Data // PC → file number map (index into File)
PCLine Data // PC → line number map
PCData []Data // PC → runtime support data map
FuncData []FuncData // non-PC-specific runtime support data
File []string // paths indexed by PCFile
}
// TODO: Add PCData []byte and PCDataIter (similar to liblink).
// A FuncData is a single function-specific data value.
type FuncData struct {
Sym SymID // symbol holding data
Offset int64 // offset into symbol for funcdata pointer
}
// A Package is a parsed Go object file or archive defining a Go package.
type Package struct {
ImportPath string // import path denoting this package
Imports []string // packages imported by this package
SymRefs []SymID // list of symbol names and versions referred to by this pack
Syms []*Sym // symbols defined by this package
MaxVersion int // maximum Version in any SymID in Syms
Arch string // architecture
}
var (
archiveHeader = []byte("!<arch>\n")
archiveMagic = []byte("`\n")
goobjHeader = []byte("go objec") // truncated to size of archiveHeader
errCorruptArchive = errors.New("corrupt archive")
errTruncatedArchive = errors.New("truncated archive")
errCorruptObject = errors.New("corrupt object file")
errNotObject = errors.New("unrecognized object file format")
)
// An objReader is an object file reader.
type objReader struct {
p *Package
b *bufio.Reader
f io.ReadSeeker
err error
offset int64
dataOffset int64
limit int64
tmp [256]byte
pkgprefix string
}
// importPathToPrefix returns the prefix that will be used in the
// final symbol table for the given import path.
// We escape '%', '"', all control characters and non-ASCII bytes,
// and any '.' after the final slash.
//
// See ../../../cmd/ld/lib.c:/^pathtoprefix and
// ../../../cmd/gc/subr.c:/^pathtoprefix.
func importPathToPrefix(s string) string {
// find index of last slash, if any, or else -1.
// used for determining whether an index is after the last slash.
slash := strings.LastIndex(s, "/")
// check for chars that need escaping
n := 0
for r := 0; r < len(s); r++ {
if c := s[r]; c <= ' ' || (c == '.' && r > slash) || c == '%' || c == '"' || c >= 0x7F {
n++
}
}
// quick exit
if n == 0 {
return s
}
// escape
const hex = "0123456789abcdef"
p := make([]byte, 0, len(s)+2*n)
for r := 0; r < len(s); r++ {
if c := s[r]; c <= ' ' || (c == '.' && r > slash) || c == '%' || c == '"' || c >= 0x7F {
p = append(p, '%', hex[c>>4], hex[c&0xF])
} else {
p = append(p, c)
}
}
return string(p)
}
// init initializes r to read package p from f.
func (r *objReader) init(f io.ReadSeeker, p *Package) {
r.f = f
r.p = p
r.offset, _ = f.Seek(0, io.SeekCurrent)
r.limit, _ = f.Seek(0, io.SeekEnd)
f.Seek(r.offset, io.SeekStart)
r.b = bufio.NewReader(f)
r.pkgprefix = importPathToPrefix(p.ImportPath) + "."
}
// error records that an error occurred.
// It returns only the first error, so that an error
// caused by an earlier error does not discard information
// about the earlier error.
func (r *objReader) error(err error) error {
if r.err == nil {
if err == io.EOF {
err = io.ErrUnexpectedEOF
}
r.err = err
}
// panic("corrupt") // useful for debugging
return r.err
}
// readByte reads and returns a byte from the input file.
// On I/O error or EOF, it records the error but returns byte 0.
// A sequence of 0 bytes will eventually terminate any
// parsing state in the object file. In particular, it ends the
// reading of a varint.
func (r *objReader) readByte() byte {
if r.err != nil {
return 0
}
if r.offset >= r.limit {
r.error(io.ErrUnexpectedEOF)
return 0
}
b, err := r.b.ReadByte()
if err != nil {
if err == io.EOF {
err = io.ErrUnexpectedEOF
}
r.error(err)
b = 0
} else {
r.offset++
}
return b
}
// read reads exactly len(b) bytes from the input file.
// If an error occurs, read returns the error but also
// records it, so it is safe for callers to ignore the result
// as long as delaying the report is not a problem.
func (r *objReader) readFull(b []byte) error {
if r.err != nil {
return r.err
}
if r.offset+int64(len(b)) > r.limit {
return r.error(io.ErrUnexpectedEOF)
}
n, err := io.ReadFull(r.b, b)
r.offset += int64(n)
if err != nil {
return r.error(err)
}
return nil
}
// readInt reads a zigzag varint from the input file.
func (r *objReader) readInt() int {
var u uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
r.error(errCorruptObject)
return 0
}
c := r.readByte()
u |= uint64(c&0x7F) << shift
if c&0x80 == 0 {
break
}
}
v := int64(u>>1) ^ (int64(u) << 63 >> 63)
if int64(int(v)) != v {
r.error(errCorruptObject) // TODO
return 0
}
return int(v)
}
// readString reads a length-delimited string from the input file.
func (r *objReader) readString() string {
n := r.readInt()
buf := make([]byte, n)
r.readFull(buf)
return string(buf)
}
// readSymID reads a SymID from the input file.
func (r *objReader) readSymID() SymID {
i := r.readInt()
return r.p.SymRefs[i]
}
func (r *objReader) readRef() {
name, vers := r.readString(), r.readInt()
// In a symbol name in an object file, "". denotes the
// prefix for the package in which the object file has been found.
// Expand it.
name = strings.Replace(name, `"".`, r.pkgprefix, -1)
// An individual object file only records version 0 (extern) or 1 (static).
// To make static symbols unique across all files being read, we
// replace version 1 with the version corresponding to the current
// file number. The number is incremented on each call to parseObject.
if vers != 0 {
vers = r.p.MaxVersion
}
r.p.SymRefs = append(r.p.SymRefs, SymID{name, vers})
}
// readData reads a data reference from the input file.
func (r *objReader) readData() Data {
n := r.readInt()
d := Data{Offset: r.dataOffset, Size: int64(n)}
r.dataOffset += int64(n)
return d
}
// skip skips n bytes in the input.
func (r *objReader) skip(n int64) {
if n < 0 {
r.error(fmt.Errorf("debug/goobj: internal error: misuse of skip"))
}
if n < int64(len(r.tmp)) {
// Since the data is so small, a just reading from the buffered
// reader is better than flushing the buffer and seeking.
r.readFull(r.tmp[:n])
} else if n <= int64(r.b.Buffered()) {
// Even though the data is not small, it has already been read.
// Advance the buffer instead of seeking.
for n > int64(len(r.tmp)) {
r.readFull(r.tmp[:])
n -= int64(len(r.tmp))
}
r.readFull(r.tmp[:n])
} else {
// Seek, giving up buffered data.
_, err := r.f.Seek(r.offset+n, io.SeekStart)
if err != nil {
r.error(err)
}
r.offset += n
r.b.Reset(r.f)
}
}
// Parse parses an object file or archive from r,
// assuming that its import path is pkgpath.
func Parse(r io.ReadSeeker, pkgpath string) (*Package, error) {
if pkgpath == "" {
pkgpath = `""`
}
p := new(Package)
p.ImportPath = pkgpath
var rd objReader
rd.init(r, p)
err := rd.readFull(rd.tmp[:8])
if err != nil {
if err == io.EOF {
err = io.ErrUnexpectedEOF
}
return nil, err
}
switch {
default:
return nil, errNotObject
case bytes.Equal(rd.tmp[:8], archiveHeader):
if err := rd.parseArchive(); err != nil {
return nil, err
}
case bytes.Equal(rd.tmp[:8], goobjHeader):
if err := rd.parseObject(goobjHeader); err != nil {
return nil, err
}
}
return p, nil
}
// trimSpace removes trailing spaces from b and returns the corresponding string.
// This effectively parses the form used in archive headers.
func trimSpace(b []byte) string {
return string(bytes.TrimRight(b, " "))
}
// parseArchive parses a Unix archive of Go object files.
// TODO(rsc): Need to skip non-Go object files.
// TODO(rsc): Maybe record table of contents in r.p so that
// linker can avoid having code to parse archives too.
func (r *objReader) parseArchive() error {
for r.offset < r.limit {
if err := r.readFull(r.tmp[:60]); err != nil {
return err
}
data := r.tmp[:60]
// Each file is preceded by this text header (slice indices in first column):
// 0:16 name
// 16:28 date
// 28:34 uid
// 34:40 gid
// 40:48 mode
// 48:58 size
// 58:60 magic - `\n
// We only care about name, size, and magic.
// The fields are space-padded on the right.
// The size is in decimal.
// The file data - size bytes - follows the header.
// Headers are 2-byte aligned, so if size is odd, an extra padding
// byte sits between the file data and the next header.
// The file data that follows is padded to an even number of bytes:
// if size is odd, an extra padding byte is inserted betw the next header.
if len(data) < 60 {
return errTruncatedArchive
}
if !bytes.Equal(data[58:60], archiveMagic) {
return errCorruptArchive
}
name := trimSpace(data[0:16])
size, err := strconv.ParseInt(trimSpace(data[48:58]), 10, 64)
if err != nil {
return errCorruptArchive
}
data = data[60:]
fsize := size + size&1
if fsize < 0 || fsize < size {
return errCorruptArchive
}
switch name {
case "__.PKGDEF":
r.skip(size)
default:
oldLimit := r.limit
r.limit = r.offset + size
if err := r.parseObject(nil); err != nil {
return fmt.Errorf("parsing archive member %q: %v", name, err)
}
r.skip(r.limit - r.offset)
r.limit = oldLimit
}
if size&1 != 0 {
r.skip(1)
}
}
return nil
}
// parseObject parses a single Go object file.
// The prefix is the bytes already read from the file,
// typically in order to detect that this is an object file.
// The object file consists of a textual header ending in "\n!\n"
// and then the part we want to parse begins.
// The format of that part is defined in a comment at the top
// of src/liblink/objfile.c.
func (r *objReader) parseObject(prefix []byte) error {
r.p.MaxVersion++
h := make([]byte, 0, 256)
h = append(h, prefix...)
var c1, c2, c3 byte
for {
c1, c2, c3 = c2, c3, r.readByte()
h = append(h, c3)
// The new export format can contain 0 bytes.
// Don't consider them errors, only look for r.err != nil.
if r.err != nil {
return errCorruptObject
}
if c1 == '\n' && c2 == '!' && c3 == '\n' {
break
}
}
hs := strings.Fields(string(h))
if len(hs) >= 4 {
r.p.Arch = hs[3]
}
// TODO: extract OS + build ID if/when we need it
r.readFull(r.tmp[:8])
if !bytes.Equal(r.tmp[:8], []byte("\x00\x00go17ld")) {
return r.error(errCorruptObject)
}
b := r.readByte()
if b != 1 {
return r.error(errCorruptObject)
}
// Direct package dependencies.
for {
s := r.readString()
if s == "" {
break
}
r.p.Imports = append(r.p.Imports, s)
}
r.p.SymRefs = []SymID{{"", 0}}
for {
if b := r.readByte(); b != 0xfe {
if b != 0xff {
return r.error(errCorruptObject)
}
break
}
r.readRef()
}
dataLength := r.readInt()
r.readInt() // n relocations - ignore
r.readInt() // n pcdata - ignore
r.readInt() // n autom - ignore
r.readInt() // n funcdata - ignore
r.readInt() // n files - ignore
r.dataOffset = r.offset
r.skip(int64(dataLength))
// Symbols.
for {
if b := r.readByte(); b != 0xfe {
if b != 0xff {
return r.error(errCorruptObject)
}
break
}
typ := r.readInt()
s := &Sym{SymID: r.readSymID()}
r.p.Syms = append(r.p.Syms, s)
s.Kind = SymKind(typ)
flags := r.readInt()
s.DupOK = flags&1 != 0
s.Size = r.readInt()
s.Type = r.readSymID()
s.Data = r.readData()
s.Reloc = make([]Reloc, r.readInt())
for i := range s.Reloc {
rel := &s.Reloc[i]
rel.Offset = r.readInt()
rel.Size = r.readInt()
rel.Type = obj.RelocType(r.readInt())
rel.Add = r.readInt()
rel.Sym = r.readSymID()
}
if s.Kind == STEXT {
f := new(Func)
s.Func = f
f.Args = r.readInt()
f.Frame = r.readInt()
flags := r.readInt()
f.Leaf = flags&1 != 0
f.NoSplit = r.readInt() != 0
f.Var = make([]Var, r.readInt())
for i := range f.Var {
v := &f.Var[i]
v.Name = r.readSymID().Name
v.Offset = r.readInt()
v.Kind = r.readInt()
v.Type = r.readSymID()
}
f.PCSP = r.readData()
f.PCFile = r.readData()
f.PCLine = r.readData()
f.PCData = make([]Data, r.readInt())
for i := range f.PCData {
f.PCData[i] = r.readData()
}
f.FuncData = make([]FuncData, r.readInt())
for i := range f.FuncData {
f.FuncData[i].Sym = r.readSymID()
}
for i := range f.FuncData {
f.FuncData[i].Offset = int64(r.readInt()) // TODO
}
f.File = make([]string, r.readInt())
for i := range f.File {
f.File[i] = r.readSymID().Name
}
}
}
r.readFull(r.tmp[:7])
if !bytes.Equal(r.tmp[:7], []byte("\xffgo17ld")) {
return r.error(errCorruptObject)
}
return nil
}
func (r *Reloc) String(insnOffset uint64) string {
delta := r.Offset - int(insnOffset)
s := fmt.Sprintf("[%d:%d]%s", delta, delta+r.Size, r.Type)
if r.Sym.Name != "" {
if r.Add != 0 {
return fmt.Sprintf("%s:%s+%d", s, r.Sym.Name, r.Add)
}
return fmt.Sprintf("%s:%s", s, r.Sym.Name)
}
if r.Add != 0 {
return fmt.Sprintf("%s:%d", s, r.Add)
}
return s
}

View File

@ -1,28 +0,0 @@
// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package goobj
import "testing"
var importPathToPrefixTests = []struct {
in string
out string
}{
{"runtime", "runtime"},
{"sync/atomic", "sync/atomic"},
{"golang.org/x/tools/godoc", "golang.org/x/tools/godoc"},
{"foo.bar/baz.quux", "foo.bar/baz%2equux"},
{"", ""},
{"%foo%bar", "%25foo%25bar"},
{"\x01\x00\x7F☺", "%01%00%7f%e2%98%ba"},
}
func TestImportPathToPrefix(t *testing.T) {
for _, tt := range importPathToPrefixTests {
if out := importPathToPrefix(tt.in); out != tt.out {
t.Errorf("importPathToPrefix(%q) = %q, want %q", tt.in, out, tt.out)
}
}
}

View File

@ -1,27 +0,0 @@
// Code generated by "stringer -type AddrType cmd/internal/obj"; DO NOT EDIT
package obj
import "fmt"
const (
_AddrType_name_0 = "TYPE_NONE"
_AddrType_name_1 = "TYPE_BRANCHTYPE_TEXTSIZETYPE_MEMTYPE_CONSTTYPE_FCONSTTYPE_SCONSTTYPE_REGTYPE_ADDRTYPE_SHIFTTYPE_REGREGTYPE_REGREG2TYPE_INDIRTYPE_REGLIST"
)
var (
_AddrType_index_0 = [...]uint8{0, 9}
_AddrType_index_1 = [...]uint8{0, 11, 24, 32, 42, 53, 64, 72, 81, 91, 102, 114, 124, 136}
)
func (i AddrType) String() string {
switch {
case i == 0:
return _AddrType_name_0
case 6 <= i && i <= 18:
i -= 6
return _AddrType_name_1[_AddrType_index_1[i]:_AddrType_index_1[i+1]]
default:
return fmt.Sprintf("AddrType(%d)", i)
}
}

View File

@ -1,338 +0,0 @@
// Inferno utils/5c/5.out.h
// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/5c/5.out.h
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
// Portions Copyright © 1997-1999 Vita Nuova Limited
// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
// Portions Copyright © 2004,2006 Bruce Ellis
// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
// Portions Copyright © 2009 The Go Authors. All rights reserved.
//
// 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 arm
import "github.com/google/gops/internal/obj"
//go:generate go run ../stringer.go -i $GOFILE -o anames.go -p arm
const (
NSNAME = 8
NSYM = 50
NREG = 16
)
/* -1 disables use of REGARG */
const (
REGARG = -1
)
const (
REG_R0 = obj.RBaseARM + iota // must be 16-aligned
REG_R1
REG_R2
REG_R3
REG_R4
REG_R5
REG_R6
REG_R7
REG_R8
REG_R9
REG_R10
REG_R11
REG_R12
REG_R13
REG_R14
REG_R15
REG_F0 // must be 16-aligned
REG_F1
REG_F2
REG_F3
REG_F4
REG_F5
REG_F6
REG_F7
REG_F8
REG_F9
REG_F10
REG_F11
REG_F12
REG_F13
REG_F14
REG_F15
REG_FPSR // must be 2-aligned
REG_FPCR
REG_CPSR // must be 2-aligned
REG_SPSR
MAXREG
REGRET = REG_R0
/* compiler allocates R1 up as temps */
/* compiler allocates register variables R3 up */
/* compiler allocates external registers R10 down */
REGEXT = REG_R10
/* these two registers are declared in runtime.h */
REGG = REGEXT - 0
REGM = REGEXT - 1
REGCTXT = REG_R7
REGTMP = REG_R11
REGSP = REG_R13
REGLINK = REG_R14
REGPC = REG_R15
NFREG = 16
/* compiler allocates register variables F0 up */
/* compiler allocates external registers F7 down */
FREGRET = REG_F0
FREGEXT = REG_F7
FREGTMP = REG_F15
)
const (
C_NONE = iota
C_REG
C_REGREG
C_REGREG2
C_REGLIST
C_SHIFT
C_FREG
C_PSR
C_FCR
C_RCON /* 0xff rotated */
C_NCON /* ~RCON */
C_SCON /* 0xffff */
C_LCON
C_LCONADDR
C_ZFCON
C_SFCON
C_LFCON
C_RACON
C_LACON
C_SBRA
C_LBRA
C_HAUTO /* halfword insn offset (-0xff to 0xff) */
C_FAUTO /* float insn offset (0 to 0x3fc, word aligned) */
C_HFAUTO /* both H and F */
C_SAUTO /* -0xfff to 0xfff */
C_LAUTO
C_HOREG
C_FOREG
C_HFOREG
C_SOREG
C_ROREG
C_SROREG /* both nil and R */
C_LOREG
C_PC
C_SP
C_HREG
C_ADDR /* reference to relocatable address */
// TLS "var" in local exec mode: will become a constant offset from
// thread local base that is ultimately chosen by the program linker.
C_TLS_LE
// TLS "var" in initial exec mode: will become a memory address (chosen
// by the program linker) that the dynamic linker will fill with the
// offset from the thread local base.
C_TLS_IE
C_TEXTSIZE
C_GOK
C_NCLASS /* must be the last */
)
const (
AAND = obj.ABaseARM + obj.A_ARCHSPECIFIC + iota
AEOR
ASUB
ARSB
AADD
AADC
ASBC
ARSC
ATST
ATEQ
ACMP
ACMN
AORR
ABIC
AMVN
/*
* Do not reorder or fragment the conditional branch
* opcodes, or the predication code will break
*/
ABEQ
ABNE
ABCS
ABHS
ABCC
ABLO
ABMI
ABPL
ABVS
ABVC
ABHI
ABLS
ABGE
ABLT
ABGT
ABLE
AMOVWD
AMOVWF
AMOVDW
AMOVFW
AMOVFD
AMOVDF
AMOVF
AMOVD
ACMPF
ACMPD
AADDF
AADDD
ASUBF
ASUBD
AMULF
AMULD
ADIVF
ADIVD
ASQRTF
ASQRTD
AABSF
AABSD
ANEGF
ANEGD
ASRL
ASRA
ASLL
AMULU
ADIVU
AMUL
ADIV
AMOD
AMODU
AMOVB
AMOVBS
AMOVBU
AMOVH
AMOVHS
AMOVHU
AMOVW
AMOVM
ASWPBU
ASWPW
ARFE
ASWI
AMULA
AWORD
AMULL
AMULAL
AMULLU
AMULALU
ABX
ABXRET
ADWORD
ALDREX
ASTREX
ALDREXD
ASTREXD
APLD
ACLZ
AMULWT
AMULWB
AMULAWT
AMULAWB
ADATABUNDLE
ADATABUNDLEEND
AMRC // MRC/MCR
ALAST
// aliases
AB = obj.AJMP
ABL = obj.ACALL
)
/* scond byte */
const (
C_SCOND = (1 << 4) - 1
C_SBIT = 1 << 4
C_PBIT = 1 << 5
C_WBIT = 1 << 6
C_FBIT = 1 << 7 /* psr flags-only */
C_UBIT = 1 << 7 /* up bit, unsigned bit */
// These constants are the ARM condition codes encodings,
// XORed with 14 so that C_SCOND_NONE has value 0,
// so that a zeroed Prog.scond means "always execute".
C_SCOND_XOR = 14
C_SCOND_EQ = 0 ^ C_SCOND_XOR
C_SCOND_NE = 1 ^ C_SCOND_XOR
C_SCOND_HS = 2 ^ C_SCOND_XOR
C_SCOND_LO = 3 ^ C_SCOND_XOR
C_SCOND_MI = 4 ^ C_SCOND_XOR
C_SCOND_PL = 5 ^ C_SCOND_XOR
C_SCOND_VS = 6 ^ C_SCOND_XOR
C_SCOND_VC = 7 ^ C_SCOND_XOR
C_SCOND_HI = 8 ^ C_SCOND_XOR
C_SCOND_LS = 9 ^ C_SCOND_XOR
C_SCOND_GE = 10 ^ C_SCOND_XOR
C_SCOND_LT = 11 ^ C_SCOND_XOR
C_SCOND_GT = 12 ^ C_SCOND_XOR
C_SCOND_LE = 13 ^ C_SCOND_XOR
C_SCOND_NONE = 14 ^ C_SCOND_XOR
C_SCOND_NV = 15 ^ C_SCOND_XOR
/* D_SHIFT type */
SHIFT_LL = 0 << 5
SHIFT_LR = 1 << 5
SHIFT_AR = 2 << 5
SHIFT_RR = 3 << 5
)

View File

@ -1,108 +0,0 @@
// Generated by stringer -i a.out.go -o anames.go -p arm
// Do not edit.
package arm
import "github.com/google/gops/internal/obj"
var Anames = []string{
obj.A_ARCHSPECIFIC: "AND",
"EOR",
"SUB",
"RSB",
"ADD",
"ADC",
"SBC",
"RSC",
"TST",
"TEQ",
"CMP",
"CMN",
"ORR",
"BIC",
"MVN",
"BEQ",
"BNE",
"BCS",
"BHS",
"BCC",
"BLO",
"BMI",
"BPL",
"BVS",
"BVC",
"BHI",
"BLS",
"BGE",
"BLT",
"BGT",
"BLE",
"MOVWD",
"MOVWF",
"MOVDW",
"MOVFW",
"MOVFD",
"MOVDF",
"MOVF",
"MOVD",
"CMPF",
"CMPD",
"ADDF",
"ADDD",
"SUBF",
"SUBD",
"MULF",
"MULD",
"DIVF",
"DIVD",
"SQRTF",
"SQRTD",
"ABSF",
"ABSD",
"NEGF",
"NEGD",
"SRL",
"SRA",
"SLL",
"MULU",
"DIVU",
"MUL",
"DIV",
"MOD",
"MODU",
"MOVB",
"MOVBS",
"MOVBU",
"MOVH",
"MOVHS",
"MOVHU",
"MOVW",
"MOVM",
"SWPBU",
"SWPW",
"RFE",
"SWI",
"MULA",
"WORD",
"MULL",
"MULAL",
"MULLU",
"MULALU",
"BX",
"BXRET",
"DWORD",
"LDREX",
"STREX",
"LDREXD",
"STREXD",
"PLD",
"CLZ",
"MULWT",
"MULWB",
"MULAWT",
"MULAWB",
"DATABUNDLE",
"DATABUNDLEEND",
"MRC",
"LAST",
}

View File

@ -1,73 +0,0 @@
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package arm
var cnames5 = []string{
"NONE",
"REG",
"REGREG",
"REGREG2",
"REGLIST",
"SHIFT",
"FREG",
"PSR",
"FCR",
"RCON",
"NCON",
"SCON",
"LCON",
"LCONADDR",
"ZFCON",
"SFCON",
"LFCON",
"RACON",
"LACON",
"SBRA",
"LBRA",
"HAUTO",
"FAUTO",
"HFAUTO",
"SAUTO",
"LAUTO",
"HOREG",
"FOREG",
"HFOREG",
"SOREG",
"ROREG",
"SROREG",
"LOREG",
"PC",
"SP",
"HREG",
"ADDR",
"C_TLS_LE",
"C_TLS_IE",
"TEXTSIZE",
"GOK",
"NCLASS",
"SCOND = (1<<4)-1",
"SBIT = 1<<4",
"PBIT = 1<<5",
"WBIT = 1<<6",
"FBIT = 1<<7",
"UBIT = 1<<7",
"SCOND_XOR = 14",
"SCOND_EQ = 0 ^ C_SCOND_XOR",
"SCOND_NE = 1 ^ C_SCOND_XOR",
"SCOND_HS = 2 ^ C_SCOND_XOR",
"SCOND_LO = 3 ^ C_SCOND_XOR",
"SCOND_MI = 4 ^ C_SCOND_XOR",
"SCOND_PL = 5 ^ C_SCOND_XOR",
"SCOND_VS = 6 ^ C_SCOND_XOR",
"SCOND_VC = 7 ^ C_SCOND_XOR",
"SCOND_HI = 8 ^ C_SCOND_XOR",
"SCOND_LS = 9 ^ C_SCOND_XOR",
"SCOND_GE = 10 ^ C_SCOND_XOR",
"SCOND_LT = 11 ^ C_SCOND_XOR",
"SCOND_GT = 12 ^ C_SCOND_XOR",
"SCOND_LE = 13 ^ C_SCOND_XOR",
"SCOND_NONE = 14 ^ C_SCOND_XOR",
"SCOND_NV = 15 ^ C_SCOND_XOR",
}

File diff suppressed because it is too large Load Diff

View File

@ -1,84 +0,0 @@
// Inferno utils/5c/list.c
// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/5c/list.c
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
// Portions Copyright © 1997-1999 Vita Nuova Limited
// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
// Portions Copyright © 2004,2006 Bruce Ellis
// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
// Portions Copyright © 2009 The Go Authors. All rights reserved.
//
// 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 arm
import (
"fmt"
"github.com/google/gops/internal/obj"
)
func init() {
obj.RegisterRegister(obj.RBaseARM, MAXREG, Rconv)
obj.RegisterOpcode(obj.ABaseARM, Anames)
}
func Rconv(r int) string {
if r == 0 {
return "NONE"
}
if r == REGG {
// Special case.
return "g"
}
if REG_R0 <= r && r <= REG_R15 {
return fmt.Sprintf("R%d", r-REG_R0)
}
if REG_F0 <= r && r <= REG_F15 {
return fmt.Sprintf("F%d", r-REG_F0)
}
switch r {
case REG_FPSR:
return "FPSR"
case REG_FPCR:
return "FPCR"
case REG_CPSR:
return "CPSR"
case REG_SPSR:
return "SPSR"
}
return fmt.Sprintf("Rgok(%d)", r-obj.RBaseARM)
}
func DRconv(a int) string {
s := "C_??"
if a >= C_NONE && a <= C_NCLASS {
s = cnames5[a]
}
var fp string
fp += s
return fp
}

File diff suppressed because it is too large Load Diff

View File

@ -1,719 +0,0 @@
// cmd/7c/7.out.h from Vita Nuova.
// https://code.google.com/p/ken-cc/source/browse/src/cmd/7c/7.out.h
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
// Portions Copyright © 1997-1999 Vita Nuova Limited
// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
// Portions Copyright © 2004,2006 Bruce Ellis
// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
// Portions Copyright © 2009 The Go Authors. All rights reserved.
//
// 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 arm64
import "github.com/google/gops/internal/obj"
const (
NSNAME = 8
NSYM = 50
NREG = 32 /* number of general registers */
NFREG = 32 /* number of floating point registers */
)
// General purpose registers, kept in the low bits of Prog.Reg.
const (
// integer
REG_R0 = obj.RBaseARM64 + iota
REG_R1
REG_R2
REG_R3
REG_R4
REG_R5
REG_R6
REG_R7
REG_R8
REG_R9
REG_R10
REG_R11
REG_R12
REG_R13
REG_R14
REG_R15
REG_R16
REG_R17
REG_R18
REG_R19
REG_R20
REG_R21
REG_R22
REG_R23
REG_R24
REG_R25
REG_R26
REG_R27
REG_R28
REG_R29
REG_R30
REG_R31
// scalar floating point
REG_F0
REG_F1
REG_F2
REG_F3
REG_F4
REG_F5
REG_F6
REG_F7
REG_F8
REG_F9
REG_F10
REG_F11
REG_F12
REG_F13
REG_F14
REG_F15
REG_F16
REG_F17
REG_F18
REG_F19
REG_F20
REG_F21
REG_F22
REG_F23
REG_F24
REG_F25
REG_F26
REG_F27
REG_F28
REG_F29
REG_F30
REG_F31
// SIMD
REG_V0
REG_V1
REG_V2
REG_V3
REG_V4
REG_V5
REG_V6
REG_V7
REG_V8
REG_V9
REG_V10
REG_V11
REG_V12
REG_V13
REG_V14
REG_V15
REG_V16
REG_V17
REG_V18
REG_V19
REG_V20
REG_V21
REG_V22
REG_V23
REG_V24
REG_V25
REG_V26
REG_V27
REG_V28
REG_V29
REG_V30
REG_V31
// The EQ in
// CSET EQ, R0
// is encoded as TYPE_REG, even though it's not really a register.
COND_EQ
COND_NE
COND_HS
COND_LO
COND_MI
COND_PL
COND_VS
COND_VC
COND_HI
COND_LS
COND_GE
COND_LT
COND_GT
COND_LE
COND_AL
COND_NV
REG_RSP = REG_V31 + 32 // to differentiate ZR/SP, REG_RSP&0x1f = 31
)
// Not registers, but flags that can be combined with regular register
// constants to indicate extended register conversion. When checking,
// you should subtract obj.RBaseARM64 first. From this difference, bit 11
// indicates extended register, bits 8-10 select the conversion mode.
const REG_EXT = obj.RBaseARM64 + 1<<11
const (
REG_UXTB = REG_EXT + iota<<8
REG_UXTH
REG_UXTW
REG_UXTX
REG_SXTB
REG_SXTH
REG_SXTW
REG_SXTX
)
// Special registers, after subtracting obj.RBaseARM64, bit 12 indicates
// a special register and the low bits select the register.
const (
REG_SPECIAL = obj.RBaseARM64 + 1<<12 + iota
REG_DAIF
REG_NZCV
REG_FPSR
REG_FPCR
REG_SPSR_EL1
REG_ELR_EL1
REG_SPSR_EL2
REG_ELR_EL2
REG_CurrentEL
REG_SP_EL0
REG_SPSel
REG_DAIFSet
REG_DAIFClr
)
// Register assignments:
//
// compiler allocates R0 up as temps
// compiler allocates register variables R7-R25
// compiler allocates external registers R26 down
//
// compiler allocates register variables F7-F26
// compiler allocates external registers F26 down
const (
REGMIN = REG_R7 // register variables allocated from here to REGMAX
REGRT1 = REG_R16 // ARM64 IP0, for external linker, runtime, duffzero and duffcopy
REGRT2 = REG_R17 // ARM64 IP1, for external linker, runtime, duffcopy
REGPR = REG_R18 // ARM64 platform register, unused in the Go toolchain
REGMAX = REG_R25
REGCTXT = REG_R26 // environment for closures
REGTMP = REG_R27 // reserved for liblink
REGG = REG_R28 // G
REGFP = REG_R29 // frame pointer, unused in the Go toolchain
REGLINK = REG_R30
// ARM64 uses R31 as both stack pointer and zero register,
// depending on the instruction. To differentiate RSP from ZR,
// we use a different numeric value for REGZERO and REGSP.
REGZERO = REG_R31
REGSP = REG_RSP
FREGRET = REG_F0
FREGMIN = REG_F7 // first register variable
FREGMAX = REG_F26 // last register variable for 7g only
FREGEXT = REG_F26 // first external register
)
const (
BIG = 2048 - 8
)
const (
/* mark flags */
LABEL = 1 << iota
LEAF
FLOAT
BRANCH
LOAD
FCMP
SYNC
LIST
FOLL
NOSCHED
)
const (
C_NONE = iota
C_REG // R0..R30
C_RSP // R0..R30, RSP
C_FREG // F0..F31
C_VREG // V0..V31
C_PAIR // (Rn, Rm)
C_SHIFT // Rn<<2
C_EXTREG // Rn.UXTB<<3
C_SPR // REG_NZCV
C_COND // EQ, NE, etc
C_ZCON // $0 or ZR
C_ADDCON0 // 12-bit unsigned, unshifted
C_ADDCON // 12-bit unsigned, shifted left by 0 or 12
C_MOVCON // generated by a 16-bit constant, optionally inverted and/or shifted by multiple of 16
C_BITCON // bitfield and logical immediate masks
C_ABCON0 // could be C_ADDCON0 or C_BITCON
C_ABCON // could be C_ADDCON or C_BITCON
C_MBCON // could be C_MOVCON or C_BITCON
C_LCON // 32-bit constant
C_VCON // 64-bit constant
C_FCON // floating-point constant
C_VCONADDR // 64-bit memory address
C_AACON // ADDCON offset in auto constant $a(FP)
C_LACON // 32-bit offset in auto constant $a(FP)
C_AECON // ADDCON offset in extern constant $e(SB)
// TODO(aram): only one branch class should be enough
C_SBRA // for TYPE_BRANCH
C_LBRA
C_NPAUTO // -512 <= x < 0, 0 mod 8
C_NSAUTO // -256 <= x < 0
C_PSAUTO // 0 to 255
C_PPAUTO // 0 to 504, 0 mod 8
C_UAUTO4K // 0 to 4095
C_UAUTO8K // 0 to 8190, 0 mod 2
C_UAUTO16K // 0 to 16380, 0 mod 4
C_UAUTO32K // 0 to 32760, 0 mod 8
C_UAUTO64K // 0 to 65520, 0 mod 16
C_LAUTO // any other 32-bit constant
C_SEXT1 // 0 to 4095, direct
C_SEXT2 // 0 to 8190
C_SEXT4 // 0 to 16380
C_SEXT8 // 0 to 32760
C_SEXT16 // 0 to 65520
C_LEXT
// TODO(aram): s/AUTO/INDIR/
C_ZOREG // 0(R)
C_NPOREG // mirror NPAUTO, etc
C_NSOREG
C_PSOREG
C_PPOREG
C_UOREG4K
C_UOREG8K
C_UOREG16K
C_UOREG32K
C_UOREG64K
C_LOREG
C_ADDR // TODO(aram): explain difference from C_VCONADDR
// The GOT slot for a symbol in -dynlink mode.
C_GOTADDR
// TLS "var" in local exec mode: will become a constant offset from
// thread local base that is ultimately chosen by the program linker.
C_TLS_LE
// TLS "var" in initial exec mode: will become a memory address (chosen
// by the program linker) that the dynamic linker will fill with the
// offset from the thread local base.
C_TLS_IE
C_ROFF // register offset (including register extended)
C_GOK
C_TEXTSIZE
C_NCLASS // must be last
)
const (
C_XPRE = 1 << 6 // match arm.C_WBIT, so Prog.String know how to print it
C_XPOST = 1 << 5 // match arm.C_PBIT, so Prog.String know how to print it
)
//go:generate go run ../stringer.go -i $GOFILE -o anames.go -p arm64
const (
AADC = obj.ABaseARM64 + obj.A_ARCHSPECIFIC + iota
AADCS
AADCSW
AADCW
AADD
AADDS
AADDSW
AADDW
AADR
AADRP
AAND
AANDS
AANDSW
AANDW
AASR
AASRW
AAT
ABFI
ABFIW
ABFM
ABFMW
ABFXIL
ABFXILW
ABIC
ABICS
ABICSW
ABICW
ABRK
ACBNZ
ACBNZW
ACBZ
ACBZW
ACCMN
ACCMNW
ACCMP
ACCMPW
ACINC
ACINCW
ACINV
ACINVW
ACLREX
ACLS
ACLSW
ACLZ
ACLZW
ACMN
ACMNW
ACMP
ACMPW
ACNEG
ACNEGW
ACRC32B
ACRC32CB
ACRC32CH
ACRC32CW
ACRC32CX
ACRC32H
ACRC32W
ACRC32X
ACSEL
ACSELW
ACSET
ACSETM
ACSETMW
ACSETW
ACSINC
ACSINCW
ACSINV
ACSINVW
ACSNEG
ACSNEGW
ADC
ADCPS1
ADCPS2
ADCPS3
ADMB
ADRPS
ADSB
AEON
AEONW
AEOR
AEORW
AERET
AEXTR
AEXTRW
AHINT
AHLT
AHVC
AIC
AISB
ALDAR
ALDARB
ALDARH
ALDARW
ALDAXP
ALDAXPW
ALDAXR
ALDAXRB
ALDAXRH
ALDAXRW
ALDP
ALDXR
ALDXRB
ALDXRH
ALDXRW
ALDXP
ALDXPW
ALSL
ALSLW
ALSR
ALSRW
AMADD
AMADDW
AMNEG
AMNEGW
AMOVK
AMOVKW
AMOVN
AMOVNW
AMOVZ
AMOVZW
AMRS
AMSR
AMSUB
AMSUBW
AMUL
AMULW
AMVN
AMVNW
ANEG
ANEGS
ANEGSW
ANEGW
ANGC
ANGCS
ANGCSW
ANGCW
AORN
AORNW
AORR
AORRW
APRFM
APRFUM
ARBIT
ARBITW
AREM
AREMW
AREV
AREV16
AREV16W
AREV32
AREVW
AROR
ARORW
ASBC
ASBCS
ASBCSW
ASBCW
ASBFIZ
ASBFIZW
ASBFM
ASBFMW
ASBFX
ASBFXW
ASDIV
ASDIVW
ASEV
ASEVL
ASMADDL
ASMC
ASMNEGL
ASMSUBL
ASMULH
ASMULL
ASTXR
ASTXRB
ASTXRH
ASTXP
ASTXPW
ASTXRW
ASTLP
ASTLPW
ASTLR
ASTLRB
ASTLRH
ASTLRW
ASTLXP
ASTLXPW
ASTLXR
ASTLXRB
ASTLXRH
ASTLXRW
ASTP
ASUB
ASUBS
ASUBSW
ASUBW
ASVC
ASXTB
ASXTBW
ASXTH
ASXTHW
ASXTW
ASYS
ASYSL
ATBNZ
ATBZ
ATLBI
ATST
ATSTW
AUBFIZ
AUBFIZW
AUBFM
AUBFMW
AUBFX
AUBFXW
AUDIV
AUDIVW
AUMADDL
AUMNEGL
AUMSUBL
AUMULH
AUMULL
AUREM
AUREMW
AUXTB
AUXTH
AUXTW
AUXTBW
AUXTHW
AWFE
AWFI
AYIELD
AMOVB
AMOVBU
AMOVH
AMOVHU
AMOVW
AMOVWU
AMOVD
AMOVNP
AMOVNPW
AMOVP
AMOVPD
AMOVPQ
AMOVPS
AMOVPSW
AMOVPW
ABEQ
ABNE
ABCS
ABHS
ABCC
ABLO
ABMI
ABPL
ABVS
ABVC
ABHI
ABLS
ABGE
ABLT
ABGT
ABLE
AFABSD
AFABSS
AFADDD
AFADDS
AFCCMPD
AFCCMPED
AFCCMPS
AFCCMPES
AFCMPD
AFCMPED
AFCMPES
AFCMPS
AFCVTSD
AFCVTDS
AFCVTZSD
AFCVTZSDW
AFCVTZSS
AFCVTZSSW
AFCVTZUD
AFCVTZUDW
AFCVTZUS
AFCVTZUSW
AFDIVD
AFDIVS
AFMOVD
AFMOVS
AFMULD
AFMULS
AFNEGD
AFNEGS
AFSQRTD
AFSQRTS
AFSUBD
AFSUBS
ASCVTFD
ASCVTFS
ASCVTFWD
ASCVTFWS
AUCVTFD
AUCVTFS
AUCVTFWD
AUCVTFWS
AWORD
ADWORD
AFCSELS
AFCSELD
AFMAXS
AFMINS
AFMAXD
AFMIND
AFMAXNMS
AFMAXNMD
AFNMULS
AFNMULD
AFRINTNS
AFRINTND
AFRINTPS
AFRINTPD
AFRINTMS
AFRINTMD
AFRINTZS
AFRINTZD
AFRINTAS
AFRINTAD
AFRINTXS
AFRINTXD
AFRINTIS
AFRINTID
AFMADDS
AFMADDD
AFMSUBS
AFMSUBD
AFNMADDS
AFNMADDD
AFNMSUBS
AFNMSUBD
AFMINNMS
AFMINNMD
AFCVTDH
AFCVTHS
AFCVTHD
AFCVTSH
AAESD
AAESE
AAESIMC
AAESMC
ASHA1C
ASHA1H
ASHA1M
ASHA1P
ASHA1SU0
ASHA1SU1
ASHA256H
ASHA256H2
ASHA256SU0
ASHA256SU1
ALAST
AB = obj.AJMP
ABL = obj.ACALL
)
const (
// shift types
SHIFT_LL = 0 << 22
SHIFT_LR = 1 << 22
SHIFT_AR = 2 << 22
)

View File

@ -1,370 +0,0 @@
// Generated by stringer -i a.out.go -o anames.go -p arm64
// Do not edit.
package arm64
import "github.com/google/gops/internal/obj"
var Anames = []string{
obj.A_ARCHSPECIFIC: "ADC",
"ADCS",
"ADCSW",
"ADCW",
"ADD",
"ADDS",
"ADDSW",
"ADDW",
"ADR",
"ADRP",
"AND",
"ANDS",
"ANDSW",
"ANDW",
"ASR",
"ASRW",
"AT",
"BFI",
"BFIW",
"BFM",
"BFMW",
"BFXIL",
"BFXILW",
"BIC",
"BICS",
"BICSW",
"BICW",
"BRK",
"CBNZ",
"CBNZW",
"CBZ",
"CBZW",
"CCMN",
"CCMNW",
"CCMP",
"CCMPW",
"CINC",
"CINCW",
"CINV",
"CINVW",
"CLREX",
"CLS",
"CLSW",
"CLZ",
"CLZW",
"CMN",
"CMNW",
"CMP",
"CMPW",
"CNEG",
"CNEGW",
"CRC32B",
"CRC32CB",
"CRC32CH",
"CRC32CW",
"CRC32CX",
"CRC32H",
"CRC32W",
"CRC32X",
"CSEL",
"CSELW",
"CSET",
"CSETM",
"CSETMW",
"CSETW",
"CSINC",
"CSINCW",
"CSINV",
"CSINVW",
"CSNEG",
"CSNEGW",
"DC",
"DCPS1",
"DCPS2",
"DCPS3",
"DMB",
"DRPS",
"DSB",
"EON",
"EONW",
"EOR",
"EORW",
"ERET",
"EXTR",
"EXTRW",
"HINT",
"HLT",
"HVC",
"IC",
"ISB",
"LDAR",
"LDARB",
"LDARH",
"LDARW",
"LDAXP",
"LDAXPW",
"LDAXR",
"LDAXRB",
"LDAXRH",
"LDAXRW",
"LDP",
"LDXR",
"LDXRB",
"LDXRH",
"LDXRW",
"LDXP",
"LDXPW",
"LSL",
"LSLW",
"LSR",
"LSRW",
"MADD",
"MADDW",
"MNEG",
"MNEGW",
"MOVK",
"MOVKW",
"MOVN",
"MOVNW",
"MOVZ",
"MOVZW",
"MRS",
"MSR",
"MSUB",
"MSUBW",
"MUL",
"MULW",
"MVN",
"MVNW",
"NEG",
"NEGS",
"NEGSW",
"NEGW",
"NGC",
"NGCS",
"NGCSW",
"NGCW",
"ORN",
"ORNW",
"ORR",
"ORRW",
"PRFM",
"PRFUM",
"RBIT",
"RBITW",
"REM",
"REMW",
"REV",
"REV16",
"REV16W",
"REV32",
"REVW",
"ROR",
"RORW",
"SBC",
"SBCS",
"SBCSW",
"SBCW",
"SBFIZ",
"SBFIZW",
"SBFM",
"SBFMW",
"SBFX",
"SBFXW",
"SDIV",
"SDIVW",
"SEV",
"SEVL",
"SMADDL",
"SMC",
"SMNEGL",
"SMSUBL",
"SMULH",
"SMULL",
"STXR",
"STXRB",
"STXRH",
"STXP",
"STXPW",
"STXRW",
"STLP",
"STLPW",
"STLR",
"STLRB",
"STLRH",
"STLRW",
"STLXP",
"STLXPW",
"STLXR",
"STLXRB",
"STLXRH",
"STLXRW",
"STP",
"SUB",
"SUBS",
"SUBSW",
"SUBW",
"SVC",
"SXTB",
"SXTBW",
"SXTH",
"SXTHW",
"SXTW",
"SYS",
"SYSL",
"TBNZ",
"TBZ",
"TLBI",
"TST",
"TSTW",
"UBFIZ",
"UBFIZW",
"UBFM",
"UBFMW",
"UBFX",
"UBFXW",
"UDIV",
"UDIVW",
"UMADDL",
"UMNEGL",
"UMSUBL",
"UMULH",
"UMULL",
"UREM",
"UREMW",
"UXTB",
"UXTH",
"UXTW",
"UXTBW",
"UXTHW",
"WFE",
"WFI",
"YIELD",
"MOVB",
"MOVBU",
"MOVH",
"MOVHU",
"MOVW",
"MOVWU",
"MOVD",
"MOVNP",
"MOVNPW",
"MOVP",
"MOVPD",
"MOVPQ",
"MOVPS",
"MOVPSW",
"MOVPW",
"BEQ",
"BNE",
"BCS",
"BHS",
"BCC",
"BLO",
"BMI",
"BPL",
"BVS",
"BVC",
"BHI",
"BLS",
"BGE",
"BLT",
"BGT",
"BLE",
"FABSD",
"FABSS",
"FADDD",
"FADDS",
"FCCMPD",
"FCCMPED",
"FCCMPS",
"FCCMPES",
"FCMPD",
"FCMPED",
"FCMPES",
"FCMPS",
"FCVTSD",
"FCVTDS",
"FCVTZSD",
"FCVTZSDW",
"FCVTZSS",
"FCVTZSSW",
"FCVTZUD",
"FCVTZUDW",
"FCVTZUS",
"FCVTZUSW",
"FDIVD",
"FDIVS",
"FMOVD",
"FMOVS",
"FMULD",
"FMULS",
"FNEGD",
"FNEGS",
"FSQRTD",
"FSQRTS",
"FSUBD",
"FSUBS",
"SCVTFD",
"SCVTFS",
"SCVTFWD",
"SCVTFWS",
"UCVTFD",
"UCVTFS",
"UCVTFWD",
"UCVTFWS",
"WORD",
"DWORD",
"FCSELS",
"FCSELD",
"FMAXS",
"FMINS",
"FMAXD",
"FMIND",
"FMAXNMS",
"FMAXNMD",
"FNMULS",
"FNMULD",
"FRINTNS",
"FRINTND",
"FRINTPS",
"FRINTPD",
"FRINTMS",
"FRINTMD",
"FRINTZS",
"FRINTZD",
"FRINTAS",
"FRINTAD",
"FRINTXS",
"FRINTXD",
"FRINTIS",
"FRINTID",
"FMADDS",
"FMADDD",
"FMSUBS",
"FMSUBD",
"FNMADDS",
"FNMADDD",
"FNMSUBS",
"FNMSUBD",
"FMINNMS",
"FMINNMD",
"FCVTDH",
"FCVTHS",
"FCVTHD",
"FCVTSH",
"AESD",
"AESE",
"AESIMC",
"AESMC",
"SHA1C",
"SHA1H",
"SHA1M",
"SHA1P",
"SHA1SU0",
"SHA1SU1",
"SHA256H",
"SHA256H2",
"SHA256SU0",
"SHA256SU1",
"LAST",
}

View File

@ -1,70 +0,0 @@
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package arm64
var cnames7 = []string{
"NONE",
"REG",
"RSP",
"FREG",
"VREG",
"PAIR",
"SHIFT",
"EXTREG",
"SPR",
"COND",
"ZCON",
"ADDCON0",
"ADDCON",
"MOVCON",
"BITCON",
"ABCON0",
"ABCON",
"MBCON",
"LCON",
"VCON",
"FCON",
"VCONADDR",
"AACON",
"LACON",
"AECON",
"SBRA",
"LBRA",
"NPAUTO",
"NSAUTO",
"PSAUTO",
"PPAUTO",
"UAUTO4K",
"UAUTO8K",
"UAUTO16K",
"UAUTO32K",
"UAUTO64K",
"LAUTO",
"SEXT1",
"SEXT2",
"SEXT4",
"SEXT8",
"SEXT16",
"LEXT",
"ZOREG",
"NPOREG",
"NSOREG",
"PSOREG",
"PPOREG",
"UOREG4K",
"UOREG8K",
"UOREG16K",
"UOREG32K",
"UOREG64K",
"LOREG",
"ADDR",
"GOTADDR",
"TLS_LE",
"TLS_IE",
"ROFF",
"GOK",
"TEXTSIZE",
"NCLASS",
}

File diff suppressed because it is too large Load Diff

View File

@ -1,115 +0,0 @@
// cmd/7l/list.c and cmd/7l/sub.c from Vita Nuova.
// https://code.google.com/p/ken-cc/source/browse/
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
// Portions Copyright © 1997-1999 Vita Nuova Limited
// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
// Portions Copyright © 2004,2006 Bruce Ellis
// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
// Portions Copyright © 2009 The Go Authors. All rights reserved.
//
// 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 arm64
import (
"fmt"
"github.com/google/gops/internal/obj"
)
var strcond = [16]string{
"EQ",
"NE",
"HS",
"LO",
"MI",
"PL",
"VS",
"VC",
"HI",
"LS",
"GE",
"LT",
"GT",
"LE",
"AL",
"NV",
}
func init() {
obj.RegisterRegister(obj.RBaseARM64, REG_SPECIAL+1024, Rconv)
obj.RegisterOpcode(obj.ABaseARM64, Anames)
}
func Rconv(r int) string {
if r == REGG {
return "g"
}
switch {
case REG_R0 <= r && r <= REG_R30:
return fmt.Sprintf("R%d", r-REG_R0)
case r == REG_R31:
return "ZR"
case REG_F0 <= r && r <= REG_F31:
return fmt.Sprintf("F%d", r-REG_F0)
case REG_V0 <= r && r <= REG_V31:
return fmt.Sprintf("V%d", r-REG_V0)
case COND_EQ <= r && r <= COND_NV:
return strcond[r-COND_EQ]
case r == REGSP:
return "RSP"
case r == REG_DAIF:
return "DAIF"
case r == REG_NZCV:
return "NZCV"
case r == REG_FPSR:
return "FPSR"
case r == REG_FPCR:
return "FPCR"
case r == REG_SPSR_EL1:
return "SPSR_EL1"
case r == REG_ELR_EL1:
return "ELR_EL1"
case r == REG_SPSR_EL2:
return "SPSR_EL2"
case r == REG_ELR_EL2:
return "ELR_EL2"
case r == REG_CurrentEL:
return "CurrentEL"
case r == REG_SP_EL0:
return "SP_EL0"
case r == REG_SPSel:
return "SPSel"
case r == REG_DAIFSet:
return "DAIFSet"
case r == REG_DAIFClr:
return "DAIFClr"
}
return fmt.Sprintf("badreg(%d)", r)
}
func DRconv(a int) string {
if a >= C_NONE && a <= C_NCLASS {
return cnames7[a]
}
return "C_??"
}

File diff suppressed because it is too large Load Diff

View File

@ -1,190 +0,0 @@
// Derived from Inferno utils/6l/obj.c and utils/6l/span.c
// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/6l/obj.c
// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/6l/span.c
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
// Portions Copyright © 1997-1999 Vita Nuova Limited
// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
// Portions Copyright © 2004,2006 Bruce Ellis
// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
// Portions Copyright © 2009 The Go Authors. All rights reserved.
//
// 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 obj
import (
"log"
"math"
)
// Grow increases the length of s.P to lsiz.
func (s *LSym) Grow(lsiz int64) {
siz := int(lsiz)
if int64(siz) != lsiz {
log.Fatalf("LSym.Grow size %d too long", lsiz)
}
if len(s.P) >= siz {
return
}
// TODO(dfc) append cap-len at once, rather than
// one byte at a time.
for cap(s.P) < siz {
s.P = append(s.P[:cap(s.P)], 0)
}
s.P = s.P[:siz]
}
// GrowCap increases the capacity of s.P to c.
func (s *LSym) GrowCap(c int64) {
if int64(cap(s.P)) >= c {
return
}
if s.P == nil {
s.P = make([]byte, 0, c)
return
}
b := make([]byte, len(s.P), c)
copy(b, s.P)
s.P = b
}
// prepwrite prepares to write data of size siz into s at offset off.
func (s *LSym) prepwrite(ctxt *Link, off int64, siz int) {
if off < 0 || siz < 0 || off >= 1<<30 {
log.Fatalf("prepwrite: bad off=%d siz=%d", off, siz)
}
if s.Type == SBSS || s.Type == STLSBSS {
ctxt.Diag("cannot supply data for BSS var")
}
l := off + int64(siz)
s.Grow(l)
if l > s.Size {
s.Size = l
}
}
// WriteFloat32 writes f into s at offset off.
func (s *LSym) WriteFloat32(ctxt *Link, off int64, f float32) {
s.prepwrite(ctxt, off, 4)
ctxt.Arch.ByteOrder.PutUint32(s.P[off:], math.Float32bits(f))
}
// WriteFloat64 writes f into s at offset off.
func (s *LSym) WriteFloat64(ctxt *Link, off int64, f float64) {
s.prepwrite(ctxt, off, 8)
ctxt.Arch.ByteOrder.PutUint64(s.P[off:], math.Float64bits(f))
}
// WriteInt writes an integer i of size siz into s at offset off.
func (s *LSym) WriteInt(ctxt *Link, off int64, siz int, i int64) {
s.prepwrite(ctxt, off, siz)
switch siz {
default:
ctxt.Diag("WriteInt: bad integer size: %d", siz)
case 1:
s.P[off] = byte(i)
case 2:
ctxt.Arch.ByteOrder.PutUint16(s.P[off:], uint16(i))
case 4:
ctxt.Arch.ByteOrder.PutUint32(s.P[off:], uint32(i))
case 8:
ctxt.Arch.ByteOrder.PutUint64(s.P[off:], uint64(i))
}
}
// WriteAddr writes an address of size siz into s at offset off.
// rsym and roff specify the relocation for the address.
func (s *LSym) WriteAddr(ctxt *Link, off int64, siz int, rsym *LSym, roff int64) {
if siz != ctxt.Arch.PtrSize {
ctxt.Diag("WriteAddr: bad address size %d in %s", siz, s.Name)
}
s.prepwrite(ctxt, off, siz)
r := Addrel(s)
r.Off = int32(off)
if int64(r.Off) != off {
ctxt.Diag("WriteAddr: off overflow %d in %s", off, s.Name)
}
r.Siz = uint8(siz)
r.Sym = rsym
r.Type = R_ADDR
r.Add = roff
}
// WriteOff writes a 4 byte offset to rsym+roff into s at offset off.
// After linking the 4 bytes stored at s+off will be
// rsym+roff-(start of section that s is in).
func (s *LSym) WriteOff(ctxt *Link, off int64, rsym *LSym, roff int64) {
s.prepwrite(ctxt, off, 4)
r := Addrel(s)
r.Off = int32(off)
if int64(r.Off) != off {
ctxt.Diag("WriteOff: off overflow %d in %s", off, s.Name)
}
r.Siz = 4
r.Sym = rsym
r.Type = R_ADDROFF
r.Add = roff
}
// WriteString writes a string of size siz into s at offset off.
func (s *LSym) WriteString(ctxt *Link, off int64, siz int, str string) {
if siz < len(str) {
ctxt.Diag("WriteString: bad string size: %d < %d", siz, len(str))
}
s.prepwrite(ctxt, off, siz)
copy(s.P[off:off+int64(siz)], str)
}
// WriteBytes writes a slice of bytes into s at offset off.
func (s *LSym) WriteBytes(ctxt *Link, off int64, b []byte) int64 {
s.prepwrite(ctxt, off, len(b))
copy(s.P[off:], b)
return off + int64(len(b))
}
func Addrel(s *LSym) *Reloc {
s.R = append(s.R, Reloc{})
return &s.R[len(s.R)-1]
}
func Setuintxx(ctxt *Link, s *LSym, off int64, v uint64, wid int64) int64 {
if s.Type == 0 {
s.Type = SDATA
}
if s.Size < off+wid {
s.Size = off + wid
s.Grow(s.Size)
}
switch wid {
case 1:
s.P[off] = uint8(v)
case 2:
ctxt.Arch.ByteOrder.PutUint16(s.P[off:], uint16(v))
case 4:
ctxt.Arch.ByteOrder.PutUint32(s.P[off:], uint32(v))
case 8:
ctxt.Arch.ByteOrder.PutUint64(s.P[off:], v)
}
return off + wid
}

View File

@ -1,115 +0,0 @@
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package obj
import (
"flag"
"fmt"
"os"
"strconv"
)
func Flagfn2(string, string, func(string, string)) { panic("flag") }
func Flagcount(name, usage string, val *int) {
flag.Var((*count)(val), name, usage)
}
func Flagint32(name, usage string, val *int32) {
flag.Var((*int32Value)(val), name, usage)
}
func Flagint64(name, usage string, val *int64) {
flag.Int64Var(val, name, *val, usage)
}
func Flagstr(name, usage string, val *string) {
flag.StringVar(val, name, *val, usage)
}
func Flagfn0(name, usage string, f func()) {
flag.Var(fn0(f), name, usage)
}
func Flagfn1(name, usage string, f func(string)) {
flag.Var(fn1(f), name, usage)
}
func Flagprint(fd int) {
if fd == 1 {
flag.CommandLine.SetOutput(os.Stdout)
}
flag.PrintDefaults()
}
func Flagparse(usage func()) {
flag.Usage = usage
flag.Parse()
}
// count is a flag.Value that is like a flag.Bool and a flag.Int.
// If used as -name, it increments the count, but -name=x sets the count.
// Used for verbose flag -v.
type count int
func (c *count) String() string {
return fmt.Sprint(int(*c))
}
func (c *count) Set(s string) error {
switch s {
case "true":
*c++
case "false":
*c = 0
default:
n, err := strconv.Atoi(s)
if err != nil {
return fmt.Errorf("invalid count %q", s)
}
*c = count(n)
}
return nil
}
func (c *count) IsBoolFlag() bool {
return true
}
type int32Value int32
func (i *int32Value) Set(s string) error {
v, err := strconv.ParseInt(s, 0, 64)
*i = int32Value(v)
return err
}
func (i *int32Value) Get() interface{} { return int32(*i) }
func (i *int32Value) String() string { return fmt.Sprint(*i) }
type fn0 func()
func (f fn0) Set(s string) error {
f()
return nil
}
func (f fn0) Get() interface{} { return nil }
func (f fn0) String() string { return "" }
func (f fn0) IsBoolFlag() bool {
return true
}
type fn1 func(string)
func (f fn1) Set(s string) error {
f(s)
return nil
}
func (f fn1) String() string { return "" }

View File

@ -1,48 +0,0 @@
// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package obj
// This file defines the IDs for PCDATA and FUNCDATA instructions
// in Go binaries. It is included by assembly sources, so it must
// be written using #defines.
//
// The Go compiler also #includes this file, for now.
//
// symtab.go also contains a copy of these constants.
// Pseudo-assembly statements.
// GO_ARGS, GO_RESULTS_INITIALIZED, and NO_LOCAL_POINTERS are macros
// that communicate to the runtime information about the location and liveness
// of pointers in an assembly function's arguments, results, and stack frame.
// This communication is only required in assembly functions that make calls
// to other functions that might be preempted or grow the stack.
// NOSPLIT functions that make no calls do not need to use these macros.
// GO_ARGS indicates that the Go prototype for this assembly function
// defines the pointer map for the function's arguments.
// GO_ARGS should be the first instruction in a function that uses it.
// It can be omitted if there are no arguments at all.
// GO_ARGS is inserted implicitly by the linker for any function
// that also has a Go prototype and therefore is usually not necessary
// to write explicitly.
// GO_RESULTS_INITIALIZED indicates that the assembly function
// has initialized the stack space for its results and that those results
// should be considered live for the remainder of the function.
// NO_LOCAL_POINTERS indicates that the assembly function stores
// no pointers to heap objects in its local stack variables.
// ArgsSizeUnknown is set in Func.argsize to mark all functions
// whose argument size is unknown (C vararg functions, and
// assembly code without an explicit specification).
// This value is generated by the compiler, assembler, or linker.
const (
PCDATA_StackMapIndex = 0
FUNCDATA_ArgsPointerMaps = 0
FUNCDATA_LocalsPointerMaps = 1
ArgsSizeUnknown = -0x80000000
)

View File

@ -1,86 +0,0 @@
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package obj
import (
"fmt"
"os"
"strings"
)
// go-specific code shared across loaders (5l, 6l, 8l).
var (
framepointer_enabled int
Fieldtrack_enabled int
)
// Toolchain experiments.
// These are controlled by the GOEXPERIMENT environment
// variable recorded when the toolchain is built.
// This list is also known to cmd/gc.
var exper = []struct {
name string
val *int
}{
{"fieldtrack", &Fieldtrack_enabled},
{"framepointer", &framepointer_enabled},
}
func addexp(s string) {
// Could do general integer parsing here, but the runtime copy doesn't yet.
v := 1
name := s
if len(name) > 2 && name[:2] == "no" {
v = 0
name = name[2:]
}
for i := 0; i < len(exper); i++ {
if exper[i].name == name {
if exper[i].val != nil {
*exper[i].val = v
}
return
}
}
fmt.Printf("unknown experiment %s\n", s)
os.Exit(2)
}
func init() {
framepointer_enabled = 1 // default
for _, f := range strings.Split(goexperiment, ",") {
if f != "" {
addexp(f)
}
}
}
func Framepointer_enabled(goos, goarch string) bool {
return framepointer_enabled != 0 && goarch == "amd64" && goos != "nacl"
}
func Nopout(p *Prog) {
p.As = ANOP
p.Scond = 0
p.From = Addr{}
p.From3 = nil
p.Reg = 0
p.To = Addr{}
}
func Expstring() string {
buf := "X"
for i := range exper {
if *exper[i].val != 0 {
buf += "," + exper[i].name
}
}
if buf == "X" {
buf += ",none"
}
return "X:" + buf[2:]
}

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