Compare commits

...

121 Commits
v0.3.1 ... main

Author SHA1 Message Date
Vincent Batts 1adae81a54
Merge pull request #165 from vbatts/change-ci
Change ci
2021-09-14 10:06:35 -04:00
Vincent Batts 9de8611e15
README: change out badge of CI
Signed-off-by: Vincent Batts <vbatts@hashbangbash.com>
2021-09-14 10:00:24 -04:00
Vincent Batts d02dbc5725
trying out drone
This is lacking for a few reasons:
- multi-arch
- matrix of versions of golang

Signed-off-by: Vincent Batts <vbatts@hashbangbash.com>
2021-09-14 09:56:11 -04:00
Vincent Batts ae608839f1
long live travisCI
Signed-off-by: Vincent Batts <vbatts@hashbangbash.com>
2021-09-14 09:51:47 -04:00
Vincent Batts e8d42c3634
Merge pull request #161 from vbatts/go-mod
update and tidy go modules
2021-06-25 22:21:25 -04:00
Vincent Batts 8f06855856
vendor: update the vendored sources
Signed-off-by: Vincent Batts <vbatts@hashbangbash.com>
2021-06-25 22:19:26 -04:00
Vincent Batts 66fcc4c2f9
go.mod: tidy up
Signed-off-by: Vincent Batts <vbatts@hashbangbash.com>
2021-06-25 22:19:25 -04:00
Vincent Batts 8653fc588a
Merge pull request #162 from vbatts/github-action
github: add action for build and validation
2021-06-25 22:18:45 -04:00
Vincent Batts 0e749301e9
github: add action for build and validation
Signed-off-by: Vincent Batts <vbatts@hashbangbash.com>
2021-06-25 22:17:01 -04:00
Vincent Batts 4d95ad8fcf
go: update deps
Signed-off-by: Vincent Batts <vbatts@hashbangbash.com>
2021-01-25 13:47:02 -05:00
Vincent Batts 3d350a825e
Makefile: '[[' misinterpreted as a command
Signed-off-by: Vincent Batts <vbatts@hashbangbash.com>
2021-01-25 13:46:31 -05:00
Vincent Batts ced0ce3470
Merge pull request #160 from asellappen/master
Add poweron architecture ppc64le to travis build
2020-10-20 06:43:10 -04:00
Ubuntu f2de0fb1a3 Add poweron architecture ppc64le to travis build 2020-10-19 11:38:42 +00:00
Vincent Batts e34c4f37a7
version: bump master back to -dev
Signed-off-by: Vincent Batts <vbatts@hashbangbash.com>
2020-04-30 18:38:31 -04:00
Vincent Batts 2e000987c5
version: release v0.5.0
Signed-off-by: Vincent Batts <vbatts@hashbangbash.com>
2020-04-30 18:37:21 -04:00
Vincent Batts d6df813dbc
Merge pull request #155 from tych0/fix-new
compare: return the right delta
2020-04-02 14:31:40 -04:00
Tycho Andersen f0ebb0ab5b compare: return the right delta
Heh, copypasta error. Amazing I'm the first person who noticed this :)

Signed-off-by: Tycho Andersen <tycho@tycho.ws>
2020-04-02 12:03:07 -06:00
Vincent Batts 2b899d3655
Merge pull request #157 from vbatts/vendor
updating modules and vendor
2020-04-02 12:35:34 -04:00
Vincent Batts ba9a13f463
updating modules and vendor
Signed-off-by: Vincent Batts <vbatts@hashbangbash.com>
2020-04-02 12:31:06 -04:00
Vincent Batts f849a9299a
Merge pull request #156 from vbatts/go_versions
ci: fix dep failure, add go versions
2020-04-02 12:22:37 -04:00
Vincent Batts 6912c50eda
ci: fix dep failure, add go versions
including new version of golang. Switch to go1.14 for linting.
and remove the build of `dep`. We're on go modules for vendoring now.

Signed-off-by: Vincent Batts <vbatts@hashbangbash.com>
2020-04-02 12:08:52 -04:00
Vincent Batts 7ce6c9c696 vendor: switch to go modules and update deps
Signed-off-by: Vincent Batts <vbatts@hashbangbash.com>
2019-11-12 09:28:03 -05:00
Vincent Batts 8b6de6073c
Merge pull request #154 from vbatts/dep
vendor: convert from glide to dep
2019-01-22 04:47:25 +01:00
Vincent Batts 4885a690ee
travis: drop go1.8
with the update to `golang.org/x/crypto`, the commit
c7dcf104e3
depends on a stdlib package introduced in go1.9

Signed-off-by: Vincent Batts <vbatts@hashbangbash.com>
2019-01-21 22:39:43 -05:00
Vincent Batts 656cd41822
Makefile: don't use glide for testable paths
Signed-off-by: Vincent Batts <vbatts@hashbangbash.com>
2019-01-21 12:06:24 -05:00
Vincent Batts 9be05594fe
vendor: update sources
```shell
dep ensure -update
```

Signed-off-by: Vincent Batts <vbatts@hashbangbash.com>
2019-01-21 11:03:35 -05:00
Vincent Batts 94a6c46bde
vendor: convert from glide to dep
```shell
go get -u -v github.com/golang/dep
dep init
```

Signed-off-by: Vincent Batts <vbatts@hashbangbash.com>
2019-01-21 11:01:52 -05:00
Vincent Batts 134ba041d7
Merge pull request #152 from tych0/compare-same
compare: add CompareSame()
2019-01-17 13:42:23 -05:00
Tycho Andersen d8d43cd807 compare: add CompareSame()
I have a use case where I'd like to know the files that are the same in the
tree, as well as the differences.

I could do this with a separate walk and excluding the paths that were
different, but since mtree is already doing all of this for me, it makes
sense to include it here. I've added a new function so that the behavior
stays the same for existing users of Compare(), since I assume mostly this
will be slower given that most files stay the same. I'd be happy to merge
it into one, though.

Signed-off-by: Tycho Andersen <tycho@tycho.ws>
2019-01-14 14:12:08 -07:00
Vincent Batts 53e54ea2f7
Merge pull request #151 from vbatts/clean.00
check: remove unused TarCheck(), for Compare()
2018-12-10 11:36:56 -05:00
Vincent Batts 40f4ce8108
check: remove unused TarCheck(), for Compare()
Signed-off-by: Vincent Batts <vbatts@hashbangbash.com>
2018-12-10 11:26:12 -05:00
Vincent Batts abf4d54fb2 readme: travis build status
Signed-off-by: Vincent Batts <vbatts@hashbangbash.com>
2018-11-15 15:08:59 -05:00
Vincent Batts 367008df78
Merge pull request #149 from cyphar/casync-mtree-compare
entry: rework e.Path() handling for casync-mtree
2018-11-15 15:04:02 -05:00
Vincent Batts 4ae4c48dc0
Merge pull request #150 from vbatts/golint
travis, golint, and versions of golang!
2018-11-08 11:56:25 -05:00
Vincent Batts acd3fa49ea
travis, golint, and versions of golang!
Signed-off-by: Vincent Batts <vbatts@hashbangbash.com>
2018-11-08 11:50:04 -05:00
Aleksa Sarai 4766cebac0
entry: rework e.Path() handling for casync-mtree
The core issue comes about when you consider a trivial example of a path
like "./README". This path is lexically equivalent within mtree to
"README", but a simple string comparison will yield the wrong result.
Instead you need to lexically clean the path first (filepath.Clean isn't
enough here -- you need to prepend a "/" and then do filepath.Clean).

In gomtree we generate spec files in the same style of FreeBSD's
mtree(8), so you would be very hard-pressed to find an example of such
an inconsistency. However casync's mtree implementation does not
generate leading "./" for root paths which results in "missing" entries.

The implementation of CleanPath was written by me for umoci originally,
then later I copied it to runc for other uses, and now I've copied it
here. Since I'm the sole author I'm effectively dual-licensing it under
this project's license to avoid having to relicense go-mtree for no good
reason (or deal with the multiple-license hassle).

Signed-off-by: Aleksa Sarai <asarai@suse.de>
2018-09-15 00:18:31 +10:00
Vincent Batts 37d776ac40
cli.test: colorize the success/failure
updating and adding vendored source to do it

Signed-off-by: Vincent Batts <vbatts@hashbangbash.com>
2018-08-20 07:57:14 -04:00
Vincent Batts 03270d3d9e *.go: clean up variable names 2018-08-19 18:25:48 -04:00
Vincent Batts 2f374a383e Make: install tools target 2018-08-13 23:03:28 -04:00
Vincent Batts f34a2e0d2b test/cli: and a newline 2018-08-13 21:56:19 -04:00
Vincent Batts dce9629991 test/cli: add a success message 2018-08-13 21:54:55 -04:00
Vincent Batts 68a6d43233 test/cli: fixup for supporting OSX 2018-08-13 21:20:31 -04:00
Vincent Batts 1bcf4de08f
Merge pull request #148 from cyphar/compare-improvements
compare: allow nil newDh and oldDh
2018-05-31 12:30:39 -07:00
Aleksa Sarai be3abf053a
compare: allow nil newDh and oldDh
This allows people to create synthetic InodeDeltas, which is something
that umoci would like to be able to do in order to nicely create 'umoci
insert' layers.

Signed-off-by: Aleksa Sarai <asarai@suse.de>
2018-05-16 20:06:43 +10:00
Aleksa Sarai ffb4a05860
travis: update Go version
Signed-off-by: Aleksa Sarai <asarai@suse.de>
2018-05-16 20:06:42 +10:00
Vincent Batts 16da0f86ee
Merge pull request #147 from vbatts/casync
casync: adding a casync style mtree
2017-12-13 14:26:12 -05:00
Vincent Batts 144242ef1e
casync: adding a casync style mtree
This parses fine, but does not validate currently

Signed-off-by: Vincent Batts <vbatts@hashbangbash.com>
2017-12-13 14:20:29 -05:00
Vincent Batts 005af4d18f
Merge pull request #144 from wking/lowercase-sirupsen
vendor: Replace Sirupsen/logrus with sirupsen/logrus
2017-11-03 15:49:21 -04:00
W. Trevor King 72ac04e7ca vendor: Replace Sirupsen/logrus with sirupsen/logrus
With:

  $ git mv vendor/github.com/{S,s}irupsen
  $ sed -i 's/Sirupsen/sirupsen/g' $(git grep -l Sirupsen)

catching up with the upstream lowercasing [1,2,3,4].  Because of the
compatibility issues discussed in [3], some consumers may prefer to
use the old uppercase version until they have time to update their
other Logrus consumers to the new lowercase form.

[1]: https://github.com/sirupsen/logrus/blame/v1.0.3/README.md#L6
[2]: https://github.com/sirupsen/logrus/pull/384
[3]: https://github.com/sirupsen/logrus/issues/570#issuecomment-313933276
[4]: https://github.com/sirupsen/logrus/issues/553
2017-11-03 12:19:19 -07:00
Vincent Batts 03983e2cdc
version: master back to -dev
Signed-off-by: Vincent Batts <vbatts@hashbangbash.com>
2017-10-28 22:30:23 -04:00
Vincent Batts de69569d25
version: release 0.4.2
Signed-off-by: Vincent Batts <vbatts@hashbangbash.com>
2017-10-28 22:29:59 -04:00
Vincent Batts 2352d84626
Merge pull request #143 from vbatts/sha512256
keyword: include sha-2 512/256
2017-10-28 22:28:22 -04:00
Vincent Batts 3a0105dc85
keyword: include sha-2 512/256
Reference: https://github.com/systemd/casync/issues/101#issuecomment-340019721

Signed-off-by: Vincent Batts <vbatts@hashbangbash.com>
2017-10-28 22:16:03 -04:00
Vincent Batts a30ab86d71 Merge pull request #142 from tklauser/utimes-unix
Use UtimesNanoAt from golang.org/x/sys/unix
2017-10-23 10:08:33 -04:00
Tobias Klauser 3fe21921b5 *: use UtimesNanoAt from x/sys/unix
Use UtimesNanoAt from golang.org/x/sys/unix instead of manually crafting
the syscall.

Since UtimesNanoAt is provided for all unix-like OSes, factor out
lchtimes to its own file with appropriate build tags. This allows to
make use of it on darwin, dragonfly, freebsd, openbsd, netbsd and
solaris in addition to linux.

Signed-off-by: Tobias Klauser <tklauser@distanz.ch>
2017-10-20 12:31:55 +02:00
Tobias Klauser 7742183cd4 vendor: explicitly vendor golang.org/x/sys
Vendor golang.org/x/sys to get the UtimesNanoAt function defined for all
unix-like OSes. The function will be used in a successive commit.

This also re-vendors the other dependencies from glide.yaml.

Signed-off-by: Tobias Klauser <tklauser@distanz.ch>
2017-10-20 11:38:03 +02:00
Vincent Batts 8bcd48e401
bump master back to dev
Signed-off-by: Vincent Batts <vbatts@hashbangbash.com>
2017-09-29 11:43:50 -04:00
Vincent Batts 020cebaa52
release: v0.4.1
Signed-off-by: Vincent Batts <vbatts@hashbangbash.com>
2017-09-29 11:43:18 -04:00
Vincent Batts 7023b74563
vscode: adding IDE tasks
making it easier to have consistent build and test across machines with
vscode editor

Signed-off-by: Vincent Batts <vbatts@hashbangbash.com>
2017-09-29 11:38:12 -04:00
Vincent Batts 6fec2c6177 Merge pull request #141 from cyphar/xattr-correct-prefix-handling
compare: correctly use .Prefix() during comparisons
2017-09-29 11:33:45 -04:00
Aleksa Sarai 8e5c54f51d
compare: correctly use .Prefix() during comparisons
During the rework of how xattr fields are handled, the comparison code
was not correctly updated. As a result, changes to xattrs would not be
detected in any form. This was detected in the umoci integration suite.
In addition, fix the dh.UsedKeywords logic so auto-detection works
correctly with prefix-based xattrs.

Fixes: ed464af779 ("*: xattr can Update()")
Signed-off-by: Aleksa Sarai <asarai@suse.de>
2017-09-29 21:05:45 +10:00
Vincent Batts ba49f2f918
version: master back to -dev
Signed-off-by: Vincent Batts <vbatts@hashbangbash.com>
2017-06-30 15:44:18 -04:00
Vincent Batts 85fac2fc14
version: bump to v0.4.0
Signed-off-by: Vincent Batts <vbatts@hashbangbash.com>
2017-06-30 15:43:46 -04:00
Vincent Batts 2ede6ecf20 Merge pull request #138 from vbatts/match_update_behavior
*: update `-u` behavior
2017-06-30 15:42:06 -04:00
Vincent Batts f271d65127
cli.test: don't have `-k` in the print
Signed-off-by: Vincent Batts <vbatts@hashbangbash.com>
2017-06-30 15:34:53 -04:00
Vincent Batts 73be830998
*: update `-u` behavior
Fixes #16

In attempt to close https://github.com/vbatts/go-mtree/issues/16 I've
uncovered that the update was missing a function for symlink.
Additionally the update was not even opperating on the correct directory
hierarchy.

I've uncovered that os.Chtimes follows the symlink, and presumably only
Linux has an obscure way to set the mtime/atime on a symlink itself. So
I've made a custom lchtimes().

Also Mode follows through the symlink, and symlinks only ever have a
mode of 0777, so don't set them.

Lastly, directories need to have their mtime/atime set in a reverse
order after all other updates have been done. This is going to require
something like a `container/heap` to be unwound.

Also, each updateFunc will _only_ perform the update if it is needed. Much less
invasive this way.

Signed-off-by: Vincent Batts <vbatts@hashbangbash.com>
2017-06-30 15:34:44 -04:00
Vincent Batts a393e171c4 Merge pull request #139 from vbatts/lint
govis: comment for lint
2017-06-30 15:18:49 -04:00
Vincent Batts 04230dccdc
govis: comment for lint
Signed-off-by: Vincent Batts <vbatts@hashbangbash.com>
2017-06-30 15:06:50 -04:00
Vincent Batts 593cfb68b8 Merge pull request #136 from vbatts/updatefunc_sig
updatefunc: simplify the function signature
2017-06-26 14:45:45 -04:00
Vincent Batts 9408f0f4c0
updatefunc: simplify the function signature
Signed-off-by: Vincent Batts <vbatts@hashbangbash.com>
2017-06-26 14:24:10 -04:00
Vincent Batts 0b5038d0bc Merge pull request #135 from vbatts/xattr-updates
*: xattr can Update()
2017-06-26 14:14:00 -04:00
Vincent Batts ed464af779
*: xattr can Update()
This is a gnarly patchset that has been mashed together.
It uncovered that some aspects of Check were never really working
correctly for `xattr` keywords, but also the `Update()` had been left
undone for a while.

This includes some API changes around the `Keyword` and `KeyVal` types.

Also I would like to update the signature for the `UpdateKeywordFunc` to
just accept a `KeyVal` as an argugment, rather than a keyword AND the
value. with this context there would be no need to guess on the value of
what's passed to the xattr update function of whether it needs or
already is base64 encoded.

Signed-off-by: Vincent Batts <vbatts@hashbangbash.com>
2017-06-24 15:05:24 -04:00
Vincent Batts fb4ec19981 Merge pull request #134 from vbatts/vendor
vendor: updating dependencies
2017-06-24 14:52:17 -04:00
Vincent Batts 50d22c5135 vendor: updating dependencies
Signed-off-by: Vincent Batts <vbatts@hashbangbash.com>
2017-06-24 14:45:05 -04:00
Vincent Batts c5b7548e35 Merge pull request #133 from vbatts/keyval
keyval: cleaner struct functions
2017-06-24 07:09:27 -04:00
Vincent Batts 14721e6869 keyval: cleaner struct functions
KeyVal specific functions can be a part of the struct.
Also add tests and fix the NewValue functions for suffixes

Signed-off-by: Vincent Batts <vbatts@hashbangbash.com>
2017-06-24 07:01:29 -04:00
Vincent Batts 64ecdb40ec Merge pull request #132 from vbatts/no_nsec_in_test
fseval: not nanosecond for mock test
2017-06-15 23:11:47 -05:00
Vincent Batts 9533b02a8e fseval: not nanosecond for mock test
while testing on osx, it seems that it doesn't support nanoseconds so it
fails this check because the mockFsEval returns the nsec precision, but
the actual expected results is:

		        "old": "1337888911.288518233"
			"new": "1337888911.000000000"

Ideally there will be a way to detect when the fs supports nsecs

Signed-off-by: Vincent Batts <vbatts@hashbangbash.com>
2017-06-15 22:54:59 -05:00
Vincent Batts bc45166bfc Merge pull request #131 from vbatts/firmer_test_time
check: test times weren't different enough
2017-06-15 20:10:43 -05:00
Vincent Batts 0ee52f7faf check: test times weren't different enough
Signed-off-by: Vincent Batts <vbatts@hashbangbash.com>
2017-06-15 18:02:14 -05:00
Vincent Batts abdee6fe11 Merge pull request #129 from vbatts/fix_gname
keyword: add missing `gname` keyword functions
2017-06-15 12:42:29 -05:00
Vincent Batts bbedbb3eaa lookupGroupId: add implementation for go1.6
Signed-off-by: Vincent Batts <vbatts@hashbangbash.com>
2017-06-15 12:36:11 -05:00
Vincent Batts f09463164c Merge pull request #130 from vbatts/fix_block_device_value
keyworrd: fix block device value for `type=`
2017-06-15 12:08:27 -05:00
Vincent Batts 5db2376250 keyworrd: fix block device value for `type=`
Fixes: #127

Reported-by: Lennart Poettering lennart@poettering.net
Signed-off-by: Vincent Batts <vbatts@hashbangbash.com>
2017-06-15 11:51:26 -05:00
Vincent Batts 68651d77d6 keyword: add missing `gname` keyword functions
Fixes: #128

Reported-by: Lennart Poettering <lennart@poettering.net>
Signed-off-by: Vincent Batts <vbatts@hashbangbash.com>
2017-06-15 10:59:57 -05:00
Vincent Batts 469590a575 Merge pull request #126 from mjg59/master
test: Allow using an environment variable to override the test dir
2017-04-13 15:14:15 -04:00
Matthew Garrett cb1fb5dded test: Allow using an environment variable to override the test dir
Some build systems may not permit writing to . during build, so allow
that path to be overridden with an environment variable.
2017-04-13 11:35:01 -07:00
Vincent Batts 93776cd69e Merge pull request #125 from vbatts/restore
add an update/restore functionality
2017-03-17 12:51:27 -04:00
Vincent Batts fc5450ed71
*: add an update/restore functionality
This allows for restoring some attributes of files from the state in an
mtree Manifest

Reported-by: Matthew Garrett <Matthewgarrett@google.com>
Signed-off-by: Vincent Batts <vbatts@hashbangbash.com>
2017-03-17 12:42:57 -04:00
Vincent Batts 0b9f227e4e
README: adding a go report card
Signed-off-by: Vincent Batts <vbatts@hashbangbash.com>
2017-03-13 18:30:01 -04:00
Vincent Batts e359fa7d2d Merge pull request #124 from vbatts/comment_update
Comment update
2017-02-16 07:51:21 -08:00
Vincent Batts 6e336a525d
git: add an ignores
Signed-off-by: Vincent Batts <vbatts@hashbangbash.com>
2017-02-16 10:45:15 -05:00
Vincent Batts eca64ff621
walk: update the comment
Signed-off-by: Vincent Batts <vbatts@hashbangbash.com>
2017-02-16 10:44:52 -05:00
Vincent Batts f165f4b7cc Merge pull request #123 from cyphar/test-unicode-integration
test: cli: add unicode verification test
2017-02-15 17:42:38 -08:00
Aleksa Sarai f6c295f2e9
test: cli: add unicode verification test
This wraps up the govis changes. While umoci has much more hardcore
tests for unicode, this is done to ensure that go-mtree won't break
before its vendored into umoci.

Signed-off-by: Aleksa Sarai <asarai@suse.de>
2017-02-16 09:28:21 +11:00
Vincent Batts 711a89aa4c Merge pull request #122 from cyphar/remove-govis-travis
pkg: govis: remove travis-ci files
2017-02-15 13:37:36 -05:00
Aleksa Sarai 4ad871ca46
pkg: govis: remove travis-ci files
Since govis is now a subpackage, drop references to the project as a
govis package.

Signed-off-by: Aleksa Sarai <asarai@suse.de>
2017-02-16 05:18:02 +11:00
Vincent Batts 7b6f89f33d Merge pull request #121 from cyphar/switch-to-govis
*: switch everything to govis
2017-02-15 13:14:38 -05:00
Aleksa Sarai c5ec1c9f3a
*: switch everything to govis
Now that we have govis, move everything to using govis.{Vis,Unvis} and
then remove the cvis build tags (because that code no longer exists).

Signed-off-by: Aleksa Sarai <asarai@suse.de>
2017-02-16 03:21:43 +11:00
Aleksa Sarai 91d7ec8c89
subtree merge: cyphar/govis
govis is a reimplementation of vis(3) and unvis(3) specifically made to
be unicode aware. It was specifically rewritten to replace cvis and the
other go vis reimplementation we have in go-mtree.

Signed-off-by: Aleksa Sarai <asarai@suse.de>
2017-02-16 03:08:51 +11:00
Aleksa Sarai c889416068
*: fix go-vet errors
Signed-off-by: Aleksa Sarai <asarai@suse.de>
2017-02-16 03:08:07 +11:00
Aleksa Sarai c9551d5820
README: add travis-ci build
Signed-off-by: Aleksa Sarai <asarai@suse.de>
2017-02-16 01:11:32 +11:00
Aleksa Sarai cbe20d4292
govis: extend roundtrip testing
This is necessary to ensure that strings I don't have examples of work
properly. The same thing applies for double-encode and double-decode
usecases.

Signed-off-by: Aleksa Sarai <asarai@suse.de>
2017-02-16 01:07:51 +11:00
Aleksa Sarai 4045484afb
vis: rewrite to use byte slices
This results in all multi-byte characters to be encoded in a way that
naive unvis(3) implementations will not bork up the encoding. In
addition, it also ensures that the output of Vis will always be ASCII
*only*.

Also test far more cases in *_test.go when it comes to different flags,
and do far more tests to ensure that the output of Vis() makes sense.
These outputs come directly from vis(3) and so are useful regression
tests to ensure that the handling of Vis() is identical to the original.

Signed-off-by: Aleksa Sarai <asarai@suse.de>
2017-02-16 01:07:16 +11:00
Aleksa Sarai c2a9f1a56d
flags -> govis
Signed-off-by: Aleksa Sarai <asarai@suse.de>
2017-02-14 02:11:41 +11:00
Aleksa Sarai de223ffc92
unvis: implement meta and ctrl characters ('\M__' and '\^_')
While these characters are really weird to handle, here is a fairly
simple implementation that need some more testing (and a proper
secondary source to compare against).

Signed-off-by: Aleksa Sarai <asarai@suse.de>
2017-02-13 08:03:04 +11:00
Aleksa Sarai 7b16f3a307
travis: add .travis.yml
Signed-off-by: Aleksa Sarai <asarai@suse.de>
2017-02-13 07:43:24 +11:00
Aleksa Sarai 35708696fe
unvis: implement proper '\xff' and '\377' escape handling
In particular, previously such escape handling would break because we
would attempt to encode characters >0x7f as runes -- which would then
result in escapes that want to encode multi-byte characters breaking.

There's still some work necessary in Vis() to make it act sanely when it
comes to arbitrary bit streams. Not to mention that we need to figure
out what we actually want to do there...

Signed-off-by: Aleksa Sarai <asarai@suse.de>
2017-02-13 04:53:14 +11:00
Aleksa Sarai 3b18d38388
govis: add integration tests
Signed-off-by: Aleksa Sarai <asarai@suse.de>
2017-02-12 04:08:21 +11:00
Aleksa Sarai 44391840b6
vis: partial vis(3) port
This is a stopgap while I figure out how I should go about implementing
vis(3). It's also important to have some vis(3) implementation so I can
do integration tests on round-trips.

Signed-off-by: Aleksa Sarai <asarai@suse.de>
2017-02-12 04:07:37 +11:00
Aleksa Sarai cd1de45ba5
unvis: implement partial unvis(3) implementation
Also add some unit tests -- one of which currently fails due to ongoing
design discussion about how certain escape codes should be handled.

Signed-off-by: Aleksa Sarai <asarai@suse.de>
2017-02-12 04:06:25 +11:00
Aleksa Sarai 1e8de82690
*: license under Apache 2.0
Signed-off-by: Aleksa Sarai <asarai@suse.de>
2017-02-11 21:10:12 +11:00
Aleksa Sarai 4c009fc4b2
README: add stub readme
Signed-off-by: Aleksa Sarai <asarai@suse.de>
2017-02-11 21:09:06 +11:00
Aleksa Sarai 85e7fd2d50
initial commit
Signed-off-by: Aleksa Sarai <asarai@suse.de>
2017-02-11 21:07:17 +11:00
Vincent Batts 5685419c3e Merge pull request #119 from cyphar/unvis-utf8
unvis_go: leave unicode unchanged with Unvis()
2017-02-10 09:19:18 -06:00
Aleksa Sarai f6dd726b66
unvis_go: leave unicode unchanged with Unvis()
Because the original code for vis() was ported to Go using the []byte{}
notion, this causes issues for multi-rune bytes (which were not
correctly treated -- and caused loss of information).

Fix this by dealing with []rune instead, which better conveys the
concept at hand. In addition, add tests to ensure that this does not
happen again.

Though, we _really_ should move this code into a library which has a
better test suite -- and the parser itself should be reimplemented to be
less ... 80s.

Fixes: #118
Signed-off-by: Aleksa Sarai <asarai@suse.de>
2017-02-10 23:08:00 +11:00
Vincent Batts 0185fe9b62 Merge pull request #117 from vbatts/release
release: add some steps to remember
2017-01-23 15:06:15 -05:00
Vincent Batts 67b30e3e57
release: add some steps to remember
Signed-off-by: Vincent Batts <vbatts@hashbangbash.com>
2017-01-23 14:40:40 -05:00
Vincent Batts 1a3d369341 Merge pull request #116 from vbatts/stdin
gomtree: allow manifest to be provided on stdin
2017-01-20 13:17:52 -05:00
Vincent Batts 21a2577f01
gomtree: allow manifest to be provided on stdin
like `gomtree -c -p /tmp/dir1 -K sha1 | gomtree -p /tmp/dir2`

Signed-off-by: Vincent Batts <vbatts@hashbangbash.com>
2017-01-20 13:13:59 -05:00
Vincent Batts b7967864aa
cli.test: failing test on stdin manifest
behavior ought to be, when `-f <file>` is not provided, then expect the
manifest to be provided on stdin.
Currently gomtree just fails if there is no `-f` (and it is not `-c`)

Signed-off-by: Vincent Batts <vbatts@hashbangbash.com>
2017-01-20 13:08:15 -05:00
709 changed files with 182945 additions and 66887 deletions

View File

@ -1,19 +1,13 @@
language: go
go:
- 1.7.4
- 1.6.3
sudo: false
before_install:
kind: pipeline
name: default
steps:
steps:
- name: build
image: golang
commands:
- git config --global url."https://".insteadOf git://
- go get -u github.com/golang/lint/golint
- go get -u github.com/Masterminds/glide
- make install.tools
- mkdir -p $GOPATH/src/github.com/vbatts && ln -sf $(pwd) $GOPATH/src/github.com/vbatts/go-mtree
install: true
script:
- make validation
- make validation.tags
- make build.arches

28
.github/workflows/go.yml vendored Normal file
View File

@ -0,0 +1,28 @@
name: Go
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up Go
uses: actions/setup-go@v2
with:
go-version: 1.16
- name: Build
run: make
- name: Test
run: make validation
- name: Build.Arches
run: make build.arches

6
.gitignore vendored Normal file
View File

@ -0,0 +1,6 @@
*~
.cli.test
.lint
.test
.vet
gomtree

66
.vscode/tasks.json vendored Normal file
View File

@ -0,0 +1,66 @@
// Available variables which can be used inside of strings.
// ${workspaceRoot}: the root folder of the team
// ${file}: the current opened file
// ${fileBasename}: the current opened file's basename
// ${fileDirname}: the current opened file's dirname
// ${fileExtname}: the current opened file's extension
// ${cwd}: the current working directory of the spawned process
{
// See https://go.microsoft.com/fwlink/?LinkId=733558
// for the documentation about the tasks.json format
"version": "2.0.0",
"tasks": [
{
"taskName": "build",
"type": "shell",
"command": "time go build .",
"problemMatcher": [
"$go"
],
"group": {
"kind": "build",
"isDefault": true
},
"presentation": {
"echo": true,
"reveal": "silent",
"focus": true,
"panel": "shared"
}
},
{
"taskName": "build.arches",
"type": "shell",
"command": "make build.arches",
"problemMatcher": [
"$go"
],
"group": "build",
"presentation": {
"echo": true,
"reveal": "always",
"focus": true,
"panel": "shared"
}
},
{
"taskName": "test",
"command": "time go test -v .",
"type": "shell",
"group": {
"kind": "test",
"isDefault": true
},
"problemMatcher": [
"$go"
],
"presentation": {
"echo": true,
"reveal": "always",
"focus": true,
"panel": "shared"
}
}
]
}

View File

@ -4,10 +4,11 @@ BUILDPATH := github.com/vbatts/go-mtree/cmd/gomtree
CWD := $(shell pwd)
SOURCE_FILES := $(shell find . -type f -name "*.go")
CLEAN_FILES := *~
TAGS := cvis
TAGS :=
ARCHES := linux,386 linux,amd64 linux,arm linux,arm64 openbsd,amd64 windows,amd64 darwin,amd64
GO_VER := go1.14
default: build validation
default: build validation
.PHONY: validation
validation: .test .lint .vet .cli.test
@ -19,12 +20,13 @@ validation.tags: .test.tags .vet.tags .cli.test
test: .test
CLEAN_FILES += .test .test.tags
NO_VENDOR_DIR := $(shell find . -type f -name '*.go' ! -path './vendor*' ! -path './.git*' ! -path './.vscode*' -exec dirname "{}" \; | sort -u)
.test: $(SOURCE_FILES)
go test -v $$(glide novendor) && touch $@
go test -v $(NO_VENDOR_DIR) && touch $@
.test.tags: $(SOURCE_FILES)
set -e ; for tag in $(TAGS) ; do go test -tags $$tag -v $$(glide novendor) ; done && touch $@
set -e ; for tag in $(TAGS) ; do go test -tags $$tag -v $(NO_VENDOR_DIR) ; done && touch $@
.PHONY: lint
lint: .lint
@ -32,7 +34,11 @@ lint: .lint
CLEAN_FILES += .lint
.lint: $(SOURCE_FILES)
set -e ; for dir in $$(glide novendor) ; do golint -set_exit_status $$dir ; done && touch $@
@if [ "$(findstring $(GO_VER),$(shell go version))" != "" ] ; then \
set -e ; for dir in $(NO_VENDOR_DIR) ; do golint -set_exit_status $$dir ; done && touch $@ \
else \
touch $@ ; \
fi
.PHONY: vet
vet: .vet .vet.tags
@ -40,10 +46,10 @@ vet: .vet .vet.tags
CLEAN_FILES += .vet .vet.tags
.vet: $(SOURCE_FILES)
go vet $$(glide novendor) && touch $@
go vet $(NO_VENDOR_DIR) && touch $@
.vet.tags: $(SOURCE_FILES)
set -e ; for tag in $(TAGS) ; do go vet -tags $$tag -v $$(glide novendor) ; done && touch $@
set -e ; for tag in $(TAGS) ; do go vet -tags $$tag -v $(NO_VENDOR_DIR) ; done && touch $@
.PHONY: cli.test
cli.test: .cli.test
@ -62,6 +68,12 @@ build: $(BUILD)
$(BUILD): $(SOURCE_FILES)
go build -o $(BUILD) $(BUILDPATH)
install.tools:
@go get -u github.com/fatih/color ; \
if [ "$(findstring $(GO_VER),$(shell go version))" != "" ] ; then \
go get -u golang.org/x/lint/golint ;\
fi
./bin:
mkdir -p $@

View File

@ -1,5 +1,7 @@
# go-mtree
[![Go Report Card](https://goreportcard.com/badge/github.com/vbatts/go-mtree)](https://goreportcard.com/report/github.com/vbatts/go-mtree)
`mtree` is a filesystem hierarchy validation tooling and format.
This is a library and simple cli tool for [mtree(8)][mtree(8)] support.

View File

@ -18,13 +18,3 @@ func Check(root string, dh *DirectoryHierarchy, keywords []Keyword, fs FsEval) (
return Compare(dh, newDh, keywords)
}
// TarCheck is the tar equivalent of checking a file hierarchy spec against a
// tar stream to determine if files have been changed. This is precisely
// equivalent to Compare(dh, tarDH, keywords).
func TarCheck(tarDH, dh *DirectoryHierarchy, keywords []Keyword) ([]InodeDelta, error) {
if keywords == nil {
return Compare(dh, tarDH, dh.UsedKeywords())
}
return Compare(dh, tarDH, keywords)
}

View File

@ -12,7 +12,7 @@ import (
// simple walk of current directory, and imediately check it.
// may not be parallelizable.
func TestCheck(t *testing.T) {
dh, err := Walk(".", nil, append(DefaultKeywords, "sha1"), nil)
dh, err := Walk(".", nil, append(DefaultKeywords, []Keyword{"sha1", "xattr"}...), nil)
if err != nil {
t.Fatal(err)
}
@ -58,8 +58,8 @@ func TestCheckKeywords(t *testing.T) {
}
// Touch a file, so the mtime changes.
now := time.Now()
if err := os.Chtimes(tmpfn, now, now); err != nil {
newtime := time.Date(2006, time.February, 1, 3, 4, 5, 0, time.UTC)
if err := os.Chtimes(tmpfn, newtime, newtime); err != nil {
t.Fatal(err)
}

View File

@ -7,21 +7,22 @@ import (
"fmt"
"io"
"io/ioutil"
"log"
"os"
"strings"
"github.com/sirupsen/logrus"
"github.com/vbatts/go-mtree"
)
var (
// Flags common with mtree(8)
flCreate = flag.Bool("c", false, "create a directory hierarchy spec")
flFile = flag.String("f", "", "directory hierarchy spec to validate")
flPath = flag.String("p", "", "root path that the hierarchy spec is relative to")
flAddKeywords = flag.String("K", "", "Add the specified (delimited by comma or space) keywords to the current set of keywords")
flUseKeywords = flag.String("k", "", "Use the specified (delimited by comma or space) keywords as the current set of keywords")
flDirectoryOnly = flag.Bool("d", false, "Ignore everything except directory type files")
flCreate = flag.Bool("c", false, "create a directory hierarchy spec")
flFile = flag.String("f", "", "directory hierarchy spec to validate")
flPath = flag.String("p", "", "root path that the hierarchy spec is relative to")
flAddKeywords = flag.String("K", "", "Add the specified (delimited by comma or space) keywords to the current set of keywords")
flUseKeywords = flag.String("k", "", "Use the specified (delimited by comma or space) keywords as the current set of keywords")
flDirectoryOnly = flag.Bool("d", false, "Ignore everything except directory type files")
flUpdateAttributes = flag.Bool("u", false, "Modify the owner, group, permissions and xattrs of files, symbolic links and devices, to match the provided specification. This is not compatible with '-T'.")
// Flags unique to gomtree
flListKeywords = flag.Bool("list-keywords", false, "List the keywords available")
@ -36,7 +37,7 @@ var (
func main() {
// so that defers cleanly exec
if err := app(); err != nil {
log.Fatal(err)
logrus.Fatal(err)
}
}
@ -45,6 +46,7 @@ func app() error {
if *flDebug {
os.Setenv("DEBUG", "1")
logrus.SetLevel(logrus.DebugLevel)
}
if *flVersion {
@ -208,6 +210,12 @@ func app() error {
excludes = append(excludes, mtree.ExcludeNonDirectories)
}
// -u
// Failing early here. Processing is done below.
if *flUpdateAttributes && *flTar != "" {
return fmt.Errorf("ERROR: -u can not be used with -T")
}
// -T <tar file>
if *flTar != "" {
var input io.Reader
@ -242,6 +250,43 @@ func app() error {
}
}
// -u
if *flUpdateAttributes && stateDh != nil {
// -u
// this comes before the next case, intentionally.
result, err := mtree.Update(rootPath, specDh, mtree.DefaultUpdateKeywords, nil)
if err != nil {
return err
}
if result != nil && len(result) > 0 {
fmt.Printf("%#v\n", result)
}
var res []mtree.InodeDelta
// only check the keywords that we just updated
res, err = mtree.Check(rootPath, specDh, mtree.DefaultUpdateKeywords, nil)
if err != nil {
return err
}
if res != nil {
out := formatFunc(res)
if _, err := os.Stdout.Write([]byte(out)); err != nil {
return err
}
// TODO: This should be a flag. Allowing files to be added and
// removed and still returning "it's all good" is simply
// unsafe IMO.
for _, diff := range res {
if diff.Type() == mtree.Modified {
return fmt.Errorf("mainfest validation failed")
}
}
}
return nil
}
// -c
if *flCreate {
fh := os.Stdout
@ -257,10 +302,22 @@ func app() error {
return nil
}
// no spec manifest has been provided yet, so look for it on stdin
if specDh == nil {
// load the hierarchy
specDh, err = mtree.ParseSpec(os.Stdin)
if err != nil {
return err
}
// We can't check against more fields than in the specKeywords list, so
// currentKeywords can only have a subset of specKeywords.
specKeywords = specDh.UsedKeywords()
}
// This is a validation.
if specDh != nil && stateDh != nil {
var res []mtree.InodeDelta
res, err = mtree.Compare(specDh, stateDh, currentKeywords)
if err != nil {
return err

View File

@ -29,6 +29,14 @@ const (
// have different values (or have not been set in one of the
// manifests).
Modified DifferenceType = "modified"
// Same represents the case where two files are the same. These are
// only generated from CompareSame().
Same DifferenceType = "same"
// ErrorDifference represents an attempted update to the values of
// a keyword that failed
ErrorDifference DifferenceType = "errored"
)
// These functions return *type from the parameter. It's just shorthand, to
@ -126,6 +134,7 @@ type KeyDelta struct {
name Keyword
old string
new string
err error // used for update delta results
}
// Type returns the type of discrepancy encountered when comparing this key
@ -152,10 +161,10 @@ func (k KeyDelta) Old() *string {
// New returns the value of the KeyDeltaVal entry in the "new" DirectoryHierarchy
// (as determined by the ordering of parameters to Compare). Returns nil if
// there was no entry in the "old" DirectoryHierarchy.
// there was no entry in the "new" DirectoryHierarchy.
func (k KeyDelta) New() *string {
if k.diff == Modified || k.diff == Extra {
return sPtr(k.old)
return sPtr(k.new)
}
return nil
}
@ -192,7 +201,7 @@ func compareEntry(oldEntry, newEntry Entry) ([]KeyDelta, error) {
for _, kv := range oldKeys {
key := kv.Keyword()
// only add this diff if the new keys has this keyword
if key != "tar_time" && key != "time" && key != "xattr" && HasKeyword(newKeys, key) == emptyKV {
if key != "tar_time" && key != "time" && key.Prefix() != "xattr" && len(HasKeyword(newKeys, key)) == 0 {
continue
}
@ -211,7 +220,7 @@ func compareEntry(oldEntry, newEntry Entry) ([]KeyDelta, error) {
for _, kv := range newKeys {
key := kv.Keyword()
// only add this diff if the old keys has this keyword
if key != "tar_time" && key != "time" && key != "xattr" && HasKeyword(oldKeys, key) == emptyKV {
if key != "tar_time" && key != "time" && key.Prefix() != "xattr" && len(HasKeyword(oldKeys, key)) == 0 {
continue
}
@ -294,7 +303,7 @@ func compareEntry(oldEntry, newEntry Entry) ([]KeyDelta, error) {
// Modified
default:
if !KeyValEqual(*diff.Old, *diff.New) {
if !diff.Old.Equal(*diff.New) {
results = append(results, KeyDelta{
diff: Modified,
name: name,
@ -308,21 +317,8 @@ func compareEntry(oldEntry, newEntry Entry) ([]KeyDelta, error) {
return results, nil
}
// Compare compares two directory hierarchy manifests, and returns the
// list of discrepancies between the two. All of the entries in the
// manifest are considered, with differences being generated for
// RelativeType and FullType entries. Differences in structure (such as
// the way /set and /unset are written) are not considered to be
// discrepancies. The list of differences are all filesystem objects.
//
// keys controls which keys will be compared, but if keys is nil then all
// possible keys will be compared between the two manifests (allowing for
// missing entries and the like). A missing or extra key is treated as a
// Modified type.
//
// NB: The order of the parameters matters (old, new) because Extra and
// Missing are considered as different discrepancy types.
func Compare(oldDh, newDh *DirectoryHierarchy, keys []Keyword) ([]InodeDelta, error) {
// compare is the actual workhorse for Compare() and CompareSame()
func compare(oldDh, newDh *DirectoryHierarchy, keys []Keyword, same bool) ([]InodeDelta, error) {
// Represents the new and old states for an entry.
type stateT struct {
Old *Entry
@ -333,43 +329,47 @@ func Compare(oldDh, newDh *DirectoryHierarchy, keys []Keyword) ([]InodeDelta, er
// map to make sure we don't start comparing unrelated entries.
diffs := map[string]*stateT{}
// First, iterate over the old hierarchy.
for _, e := range oldDh.Entries {
if e.Type == RelativeType || e.Type == FullType {
path, err := e.Path()
if err != nil {
return nil, err
}
// First, iterate over the old hierarchy. If nil, pretend it's empty.
if oldDh != nil {
for _, e := range oldDh.Entries {
if e.Type == RelativeType || e.Type == FullType {
path, err := e.Path()
if err != nil {
return nil, err
}
// Cannot take &kv because it's the iterator.
copy := new(Entry)
*copy = e
// Cannot take &kv because it's the iterator.
cEntry := new(Entry)
*cEntry = e
_, ok := diffs[path]
if !ok {
diffs[path] = &stateT{}
_, ok := diffs[path]
if !ok {
diffs[path] = &stateT{}
}
diffs[path].Old = cEntry
}
diffs[path].Old = copy
}
}
// Then, iterate over the new hierarchy.
for _, e := range newDh.Entries {
if e.Type == RelativeType || e.Type == FullType {
path, err := e.Path()
if err != nil {
return nil, err
}
// Then, iterate over the new hierarchy. If nil, pretend it's empty.
if newDh != nil {
for _, e := range newDh.Entries {
if e.Type == RelativeType || e.Type == FullType {
path, err := e.Path()
if err != nil {
return nil, err
}
// Cannot take &kv because it's the iterator.
copy := new(Entry)
*copy = e
// Cannot take &kv because it's the iterator.
cEntry := new(Entry)
*cEntry = e
_, ok := diffs[path]
if !ok {
diffs[path] = &stateT{}
_, ok := diffs[path]
if !ok {
diffs[path] = &stateT{}
}
diffs[path].New = cEntry
}
diffs[path].New = copy
}
}
@ -409,7 +409,7 @@ func Compare(oldDh, newDh *DirectoryHierarchy, keys []Keyword) ([]InodeDelta, er
if keys != nil {
var filterChanged []KeyDelta
for _, keyDiff := range changed {
if InKeywordSlice(keyDiff.name, keys) {
if InKeywordSlice(keyDiff.name.Prefix(), keys) {
filterChanged = append(filterChanged, keyDiff)
}
}
@ -425,9 +425,47 @@ func Compare(oldDh, newDh *DirectoryHierarchy, keys []Keyword) ([]InodeDelta, er
new: *diff.New,
keys: changed,
})
} else if same {
// this means that nothing changed, i.e. that
// the files are the same.
results = append(results, InodeDelta{
diff: Same,
path: path,
old: *diff.Old,
new: *diff.New,
keys: changed,
})
}
}
}
return results, nil
}
// Compare compares two directory hierarchy manifests, and returns the
// list of discrepancies between the two. All of the entries in the
// manifest are considered, with differences being generated for
// RelativeType and FullType entries. Differences in structure (such as
// the way /set and /unset are written) are not considered to be
// discrepancies. The list of differences are all filesystem objects.
//
// keys controls which keys will be compared, but if keys is nil then all
// possible keys will be compared between the two manifests (allowing for
// missing entries and the like). A missing or extra key is treated as a
// Modified type.
//
// If oldDh or newDh are empty, we assume they are a hierarchy that is
// completely empty. This is purely for helping callers create synthetic
// InodeDeltas.
//
// NB: The order of the parameters matters (old, new) because Extra and
// Missing are considered as different discrepancy types.
func Compare(oldDh, newDh *DirectoryHierarchy, keys []Keyword) ([]InodeDelta, error) {
return compare(oldDh, newDh, keys, false)
}
// CompareSame is the same as Compare, except it also includes the entries
// that are the same with a Same DifferenceType.
func CompareSame(oldDh, newDh *DirectoryHierarchy, keys []Keyword) ([]InodeDelta, error) {
return compare(oldDh, newDh, keys, true)
}

View File

@ -1,15 +0,0 @@
// +build cgo,!govis
package cvis
import "testing"
// The resulting string of Vis output could potentially be four times longer than
// the original. Vis must handle this possibility.
func TestVisLength(t *testing.T) {
testString := "All work and no play makes Jack a dull boy\n"
for i := 0; i < 20; i++ {
Vis(testString, DefaultVisFlags)
testString = testString + testString
}
}

View File

@ -1,293 +0,0 @@
/*-
* Copyright (c) 1989, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 4. Neither the name of the University 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 REGENTS 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 REGENTS 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.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)unvis.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
#include <sys/cdefs.h>
#include <sys/types.h>
#include <ctype.h>
#include "vis.h"
/*
* decode driven by state machine
*/
#define S_GROUND 0 /* haven't seen escape char */
#define S_START 1 /* start decoding special sequence */
#define S_META 2 /* metachar started (M) */
#define S_META1 3 /* metachar more, regular char (-) */
#define S_CTRL 4 /* control char started (^) */
#define S_OCTAL2 5 /* octal digit 2 */
#define S_OCTAL3 6 /* octal digit 3 */
#define S_HEX2 7 /* hex digit 2 */
#define S_HTTP 0x080 /* %HEXHEX escape */
#define isoctal(c) (((u_char)(c)) >= '0' && ((u_char)(c)) <= '7')
#define ishex(c) ((((u_char)(c)) >= '0' && ((u_char)(c)) <= '9') || (((u_char)(c)) >= 'a' && ((u_char)(c)) <= 'f'))
/*
* unvis - decode characters previously encoded by vis
*/
int
unvis(char *cp, int c, int *astate, int flag)
{
if (flag & UNVIS_END) {
if (*astate == S_OCTAL2 || *astate == S_OCTAL3) {
*astate = S_GROUND;
return (UNVIS_VALID);
}
return (*astate == S_GROUND ? UNVIS_NOCHAR : UNVIS_SYNBAD);
}
switch (*astate & ~S_HTTP) {
case S_GROUND:
*cp = 0;
if (c == '\\') {
*astate = S_START;
return (0);
}
if (flag & VIS_HTTPSTYLE && c == '%') {
*astate = S_START | S_HTTP;
return (0);
}
*cp = c;
return (UNVIS_VALID);
case S_START:
if (*astate & S_HTTP) {
if (ishex(tolower(c))) {
*cp = isdigit(c) ? (c - '0') : (tolower(c) - 'a');
*astate = S_HEX2;
return (0);
}
}
switch(c) {
case '\\':
*cp = c;
*astate = S_GROUND;
return (UNVIS_VALID);
case '0': case '1': case '2': case '3':
case '4': case '5': case '6': case '7':
*cp = (c - '0');
*astate = S_OCTAL2;
return (0);
case 'M':
*cp = 0200;
*astate = S_META;
return (0);
case '^':
*astate = S_CTRL;
return (0);
case 'n':
*cp = '\n';
*astate = S_GROUND;
return (UNVIS_VALID);
case 'r':
*cp = '\r';
*astate = S_GROUND;
return (UNVIS_VALID);
case 'b':
*cp = '\b';
*astate = S_GROUND;
return (UNVIS_VALID);
case 'a':
*cp = '\007';
*astate = S_GROUND;
return (UNVIS_VALID);
case 'v':
*cp = '\v';
*astate = S_GROUND;
return (UNVIS_VALID);
case 't':
*cp = '\t';
*astate = S_GROUND;
return (UNVIS_VALID);
case 'f':
*cp = '\f';
*astate = S_GROUND;
return (UNVIS_VALID);
case 's':
*cp = ' ';
*astate = S_GROUND;
return (UNVIS_VALID);
case 'E':
*cp = '\033';
*astate = S_GROUND;
return (UNVIS_VALID);
case '\n':
/*
* hidden newline
*/
*astate = S_GROUND;
return (UNVIS_NOCHAR);
case '$':
/*
* hidden marker
*/
*astate = S_GROUND;
return (UNVIS_NOCHAR);
}
*astate = S_GROUND;
return (UNVIS_SYNBAD);
case S_META:
if (c == '-')
*astate = S_META1;
else if (c == '^')
*astate = S_CTRL;
else {
*astate = S_GROUND;
return (UNVIS_SYNBAD);
}
return (0);
case S_META1:
*astate = S_GROUND;
*cp |= c;
return (UNVIS_VALID);
case S_CTRL:
if (c == '?')
*cp |= 0177;
else
*cp |= c & 037;
*astate = S_GROUND;
return (UNVIS_VALID);
case S_OCTAL2: /* second possible octal digit */
if (isoctal(c)) {
/*
* yes - and maybe a third
*/
*cp = (*cp << 3) + (c - '0');
*astate = S_OCTAL3;
return (0);
}
/*
* no - done with current sequence, push back passed char
*/
*astate = S_GROUND;
return (UNVIS_VALIDPUSH);
case S_OCTAL3: /* third possible octal digit */
*astate = S_GROUND;
if (isoctal(c)) {
*cp = (*cp << 3) + (c - '0');
return (UNVIS_VALID);
}
/*
* we were done, push back passed char
*/
return (UNVIS_VALIDPUSH);
case S_HEX2: /* second mandatory hex digit */
if (ishex(tolower(c))) {
*cp = (isdigit(c) ? (*cp << 4) + (c - '0') : (*cp << 4) + (tolower(c) - 'a' + 10));
}
*astate = S_GROUND;
return (UNVIS_VALID);
default:
/*
* decoder in unknown state - (probably uninitialized)
*/
*astate = S_GROUND;
return (UNVIS_SYNBAD);
}
}
/*
* strunvis - decode src into dst
*
* Number of chars decoded into dst is returned, -1 on error.
* Dst is null terminated.
*/
int
strunvis(char *dst, const char *src)
{
char c;
char *start = dst;
int state = 0;
while ( (c = *src++) ) {
again:
switch (unvis(dst, c, &state, 0)) {
case UNVIS_VALID:
dst++;
break;
case UNVIS_VALIDPUSH:
dst++;
goto again;
case 0:
case UNVIS_NOCHAR:
break;
default:
return (-1);
}
}
if (unvis(dst, c, &state, UNVIS_END) == UNVIS_VALID)
dst++;
*dst = '\0';
return (dst - start);
}
int
strunvisx(char *dst, const char *src, int flag)
{
char c;
char *start = dst;
int state = 0;
while ( (c = *src++) ) {
again:
switch (unvis(dst, c, &state, flag)) {
case UNVIS_VALID:
dst++;
break;
case UNVIS_VALIDPUSH:
dst++;
goto again;
case 0:
case UNVIS_NOCHAR:
break;
default:
return (-1);
}
}
if (unvis(dst, c, &state, UNVIS_END) == UNVIS_VALID)
dst++;
*dst = '\0';
return (dst - start);
}

View File

@ -1,22 +0,0 @@
package cvis
// #include "vis.h"
// #include <stdlib.h>
import "C"
import (
"fmt"
"unsafe"
)
// Unvis decodes the Vis() string encoding
func Unvis(src string) (string, error) {
cDst, cSrc := C.CString(string(make([]byte, len(src)+1))), C.CString(src)
defer C.free(unsafe.Pointer(cDst))
defer C.free(unsafe.Pointer(cSrc))
ret := C.strunvis(cDst, cSrc)
// TODO(vbatts) this needs to be confirmed against UnvisError
if ret == -1 {
return "", fmt.Errorf("failed to decode: %q", src)
}
return C.GoString(cDst), nil
}

View File

@ -1,202 +0,0 @@
/*-
* Copyright (c) 1989, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 4. Neither the name of the University 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 REGENTS 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 REGENTS 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.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)vis.c 8.1 (Berkeley) 7/19/93";
#endif /* LIBC_SCCS and not lint */
#include <sys/cdefs.h>
#include <sys/types.h>
#include <limits.h>
#include <ctype.h>
#include <stdio.h>
#include "vis.h"
#define isoctal(c) (((u_char)(c)) >= '0' && ((u_char)(c)) <= '7')
/*
* vis - visually encode characters
*/
char *
vis(dst, c, flag, nextc)
char *dst;
int c, nextc;
int flag;
{
c = (unsigned char)c;
if (flag & VIS_HTTPSTYLE) {
/* Described in RFC 1808 */
if (!(isalnum(c) /* alpha-numeric */
/* safe */
|| c == '$' || c == '-' || c == '_' || c == '.' || c == '+'
/* extra */
|| c == '!' || c == '*' || c == '\'' || c == '('
|| c == ')' || c == ',')) {
*dst++ = '%';
snprintf(dst, 4, (c < 16 ? "0%X" : "%X"), c);
dst += 2;
goto done;
}
}
if ((flag & VIS_GLOB) &&
(c == '*' || c == '?' || c == '[' || c == '#'))
;
else if (isgraph(c) ||
((flag & VIS_SP) == 0 && c == ' ') ||
((flag & VIS_TAB) == 0 && c == '\t') ||
((flag & VIS_NL) == 0 && c == '\n') ||
((flag & VIS_SAFE) && (c == '\b' || c == '\007' || c == '\r'))) {
*dst++ = c;
if (c == '\\' && (flag & VIS_NOSLASH) == 0)
*dst++ = '\\';
*dst = '\0';
return (dst);
}
if (flag & VIS_CSTYLE) {
switch(c) {
case '\n':
*dst++ = '\\';
*dst++ = 'n';
goto done;
case '\r':
*dst++ = '\\';
*dst++ = 'r';
goto done;
case '\b':
*dst++ = '\\';
*dst++ = 'b';
goto done;
case '\a':
*dst++ = '\\';
*dst++ = 'a';
goto done;
case '\v':
*dst++ = '\\';
*dst++ = 'v';
goto done;
case '\t':
*dst++ = '\\';
*dst++ = 't';
goto done;
case '\f':
*dst++ = '\\';
*dst++ = 'f';
goto done;
case ' ':
*dst++ = '\\';
*dst++ = 's';
goto done;
case '\0':
*dst++ = '\\';
*dst++ = '0';
if (isoctal(nextc)) {
*dst++ = '0';
*dst++ = '0';
}
goto done;
}
}
if (((c & 0177) == ' ') || isgraph(c) || (flag & VIS_OCTAL)) {
*dst++ = '\\';
*dst++ = ((u_char)c >> 6 & 07) + '0';
*dst++ = ((u_char)c >> 3 & 07) + '0';
*dst++ = ((u_char)c & 07) + '0';
goto done;
}
if ((flag & VIS_NOSLASH) == 0)
*dst++ = '\\';
if (c & 0200) {
c &= 0177;
*dst++ = 'M';
}
if (iscntrl(c)) {
*dst++ = '^';
if (c == 0177)
*dst++ = '?';
else
*dst++ = c + '@';
} else {
*dst++ = '-';
*dst++ = c;
}
done:
*dst = '\0';
return (dst);
}
/*
* strvis, strvisx - visually encode characters from src into dst
*
* Dst must be 4 times the size of src to account for possible
* expansion. The length of dst, not including the trailing NUL,
* is returned.
*
* Strvisx encodes exactly len bytes from src into dst.
* This is useful for encoding a block of data.
*/
int
strvis(dst, src, flag)
char *dst;
const char *src;
int flag;
{
char c;
char *start;
for (start = dst; (c = *src); )
dst = vis(dst, c, flag, *++src);
*dst = '\0';
return (dst - start);
}
int
strvisx(dst, src, len, flag)
char *dst;
const char *src;
size_t len;
int flag;
{
int c;
char *start;
for (start = dst; len > 1; len--) {
c = *src;
dst = vis(dst, c, flag, *++src);
}
if (len)
dst = vis(dst, *src, flag, '\0');
*dst = '\0';
return (dst - start);
}

View File

@ -1,28 +0,0 @@
package cvis
// #include "vis.h"
// #include <stdlib.h>
import "C"
import (
"fmt"
"math"
"unsafe"
)
// Vis is a wrapper around the C implementation
func Vis(src string, flags int) (string, error) {
// dst needs to be 4 times the length of str, must check appropriate size
if uint32(len(src)*4+1) >= math.MaxUint32/4 {
return "", fmt.Errorf("failed to encode: %q", src)
}
dst := string(make([]byte, 4*len(src)+1))
cDst, cSrc := C.CString(dst), C.CString(src)
defer C.free(unsafe.Pointer(cDst))
defer C.free(unsafe.Pointer(cSrc))
C.strvis(cDst, cSrc, C.int(flags))
return C.GoString(cDst), nil
}
// DefaultVisFlags are the common flags used in mtree string encoding
var DefaultVisFlags = C.VIS_WHITE | C.VIS_OCTAL | C.VIS_GLOB

View File

@ -1,90 +0,0 @@
/*-
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University 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 REGENTS 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 REGENTS 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.
*
* @(#)vis.h 8.1 (Berkeley) 6/2/93
* $FreeBSD$
*/
#ifndef _VIS_H_
#define _VIS_H_
#include <sys/types.h>
/*
* to select alternate encoding format
*/
#define VIS_OCTAL 0x01 /* use octal \ddd format */
#define VIS_CSTYLE 0x02 /* use \[nrft0..] where appropriate */
/*
* to alter set of characters encoded (default is to encode all
* non-graphic except space, tab, and newline).
*/
#define VIS_SP 0x04 /* also encode space */
#define VIS_TAB 0x08 /* also encode tab */
#define VIS_NL 0x10 /* also encode newline */
#define VIS_WHITE (VIS_SP | VIS_TAB | VIS_NL)
#define VIS_SAFE 0x20 /* only encode "unsafe" characters */
/*
* other
*/
#define VIS_NOSLASH 0x40 /* inhibit printing '\' */
#define VIS_HTTPSTYLE 0x80 /* http-style escape % HEX HEX */
#define VIS_GLOB 0x100 /* encode glob(3) magics */
/*
* unvis return codes
*/
#define UNVIS_VALID 1 /* character valid */
#define UNVIS_VALIDPUSH 2 /* character valid, push back passed char */
#define UNVIS_NOCHAR 3 /* valid sequence, no character produced */
#define UNVIS_SYNBAD -1 /* unrecognized escape sequence */
#define UNVIS_ERROR -2 /* decoder in unknown state (unrecoverable) */
/*
* unvis flags
*/
#define UNVIS_END 1 /* no more characters */
#include <sys/cdefs.h>
__BEGIN_DECLS
char *vis(char *, int, int, int);
int strvis(char *, const char *, int);
int strvisx(char *, const char *, size_t, int);
int strunvis(char *, const char *);
int strunvisx(char *, const char *, int);
int unvis(char *, int, int *, int);
__END_DECLS
#endif /* !_VIS_H_ */

View File

@ -1,18 +0,0 @@
package mtree
import (
"fmt"
"os"
"time"
)
// DebugOutput is the where DEBUG output is written
var DebugOutput = os.Stderr
// Debugf does formatted output to DebugOutput, only if DEBUG environment variable is set
func Debugf(format string, a ...interface{}) (n int, err error) {
if os.Getenv("DEBUG") != "" {
return fmt.Fprintf(DebugOutput, "[%d] [DEBUG] %s\n", time.Now().UnixNano(), fmt.Sprintf(format, a...))
}
return 0, nil
}

View File

@ -2,8 +2,11 @@ package mtree
import (
"fmt"
"os"
"path/filepath"
"strings"
"github.com/vbatts/go-mtree/pkg/govis"
)
type byPos []Entry
@ -47,7 +50,7 @@ func (e Entry) Descend(filename string) *Entry {
func (e Entry) Find(filepath string) *Entry {
resultnode := &e
for _, path := range strings.Split(filepath, "/") {
encoded, err := Vis(path, DefaultVisFlags)
encoded, err := govis.Vis(path, DefaultVisFlags)
if err != nil {
return nil
}
@ -65,21 +68,55 @@ func (e Entry) Ascend() *Entry {
return e.Parent
}
// CleanPath makes a path safe for use with filepath.Join. This is done by not
// only cleaning the path, but also (if the path is relative) adding a leading
// '/' and cleaning it (then removing the leading '/'). This ensures that a
// path resulting from prepending another path will always resolve to lexically
// be a subdirectory of the prefixed path. This is all done lexically, so paths
// that include symlinks won't be safe as a result of using CleanPath.
//
// This code was copied from runc/libcontainer/utils/utils.go. It was
// originally written by myself, so I am dual-licensing it for the purpose of
// this project.
func CleanPath(path string) string {
// Deal with empty strings nicely.
if path == "" {
return ""
}
// Ensure that all paths are cleaned (especially problematic ones like
// "/../../../../../" which can cause lots of issues).
path = filepath.Clean(path)
// If the path isn't absolute, we need to do more processing to fix paths
// such as "../../../../<etc>/some/path". We also shouldn't convert absolute
// paths to relative ones.
if !filepath.IsAbs(path) {
path = filepath.Clean(string(os.PathSeparator) + path)
// This can't fail, as (by definition) all paths are relative to root.
path, _ = filepath.Rel(string(os.PathSeparator), path)
}
// Clean the path again for good measure.
return filepath.Clean(path)
}
// Path provides the full path of the file, despite RelativeType or FullType. It
// will be in Unvis'd form.
func (e Entry) Path() (string, error) {
decodedName, err := Unvis(e.Name)
decodedName, err := govis.Unvis(e.Name, DefaultVisFlags)
if err != nil {
return "", err
}
decodedName = CleanPath(decodedName)
if e.Parent == nil || e.Type == FullType {
return filepath.Clean(decodedName), nil
return decodedName, nil
}
parentName, err := e.Parent.Path()
if err != nil {
return "", err
}
return filepath.Clean(filepath.Join(parentName, decodedName)), nil
return CleanPath(filepath.Join(parentName, decodedName)), nil
}
// String joins a file with its associated keywords. The file name will be the
@ -110,6 +147,16 @@ func (e Entry) AllKeys() []KeyVal {
return e.Keywords
}
// IsDir checks the type= value for this entry on whether it is a directory
func (e Entry) IsDir() bool {
for _, kv := range e.AllKeys() {
if kv.Keyword().Prefix() == "type" {
return kv.Value() == "dir"
}
}
return false
}
// EntryType are the formats of lines in an mtree spec file
type EntryType int

View File

@ -1,6 +1,7 @@
package mtree
import (
"encoding/json"
"io/ioutil"
"os"
"path/filepath"
@ -8,7 +9,7 @@ import (
"time"
)
var mockTime = time.Unix(1337888823, 88288518233)
var mockTime = time.Unix(1337888823, 0)
// Here be some dodgy testing. In particular, we have to mess around with some
// of the FsEval functions. In particular, we change all of the FileInfos to a
@ -155,6 +156,11 @@ func TestCheckFsEval(t *testing.T) {
t.Fatal(err)
}
if len(res) > 0 {
t.Errorf("%#v", res)
buf, err := json.MarshalIndent(res, "", " ")
if err != nil {
t.Errorf("%#v", res)
} else {
t.Errorf("%s", buf)
}
}
}

8
glide.lock generated
View File

@ -1,8 +0,0 @@
hash: 90db837f2d27de645d9f48fa1be54b4f9d83f0cb9343ce98fa61e1b55b2828b5
updated: 2017-01-19T17:18:33.464668206-05:00
imports:
- name: golang.org/x/crypto
version: b8a2a83acfe6e6770b75de42d5ff4c67596675c0
subpackages:
- ripemd160
testImports: []

View File

@ -1,8 +0,0 @@
package: github.com/vbatts/go-mtree
homepage: https://github.com/vbatts/go-mtree
license: BSD-3-Clause
description: File systems verification utility and library, in likeness of mtree(8)
import:
- package: golang.org/x/crypto
subpackages:
- ripemd160

11
go.mod Normal file
View File

@ -0,0 +1,11 @@
module github.com/vbatts/go-mtree
go 1.13
require (
github.com/davecgh/go-spew v1.1.1
github.com/fatih/color v1.12.0 // indirect
github.com/sirupsen/logrus v1.7.0
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c
)

26
go.sum Normal file
View File

@ -0,0 +1,26 @@
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/fatih/color v1.12.0 h1:mRhaKNwANqRgUBGKmnI5ZxEk7QXmjQeCcuYFMX2bfcc=
github.com/fatih/color v1.12.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM=
github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8=
github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/sirupsen/logrus v1.7.0 h1:ShrD1U9pZB12TX0cVy0DtePoCH97K8EtX+mg7ZARUtM=
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad h1:DN0cp81fZ3njFcrLCytUHRSUkqBjfTo4Tx9RJTWs0EY=
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c h1:VwygUrnw9jn88c4u8GD3rZQbqrP/tgas88tPUbBxQrk=
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=

View File

@ -36,7 +36,7 @@ func (dh DirectoryHierarchy) UsedKeywords() []Keyword {
if e.Type != SpecialType || e.Name == "/set" {
kvs := e.Keywords
for _, kv := range kvs {
kw := KeyVal(kv).Keyword()
kw := KeyVal(kv).Keyword().Prefix()
if !InKeywordSlice(kw, usedkeywords) {
usedkeywords = append(usedkeywords, KeywordSynonym(string(kw)))
}

View File

@ -20,6 +20,19 @@ var checklist = []struct {
.COMMIT_EDITMSG.un~ size=1006 mode=0644 time=1479325423.450468662 sha1digest=dead0face
.TAG_EDITMSG.un~ size=1069 mode=0600 time=1471362316.801317529 sha256digest=dead0face
`, set: []Keyword{"size", "mode", "time", "sha256digest"}},
{blob: `
# user: cyphar
# machine: ryuk
# tree: xattr
# date: Fri Sep 29 21:00:41 2017
# keywords: size,type,uid,gid,mode,link,nlink,time,xattr
# .
/set type=file nlink=1 mode=0664 uid=1000 gid=100 xattr.user.kira=SSdsbCB0YWtlIGEgcG90YXRvIGNoaXAuLi4gYW5kIGVhdCBpdCE=
. size=8 type=dir mode=0755 time=1506666472.255992830
file size=0 mode=0644 time=1506666472.255992830 xattr.user.something=dGVzdA==
..
`, set: []Keyword{"size", "type", "uid", "gid", "mode", "nlink", "time", "xattr"}},
}
func TestUsedKeywords(t *testing.T) {

View File

@ -11,6 +11,7 @@ import (
"io"
"os"
"github.com/vbatts/go-mtree/pkg/govis"
"golang.org/x/crypto/ripemd160"
)
@ -20,34 +21,37 @@ import (
// io.Reader `r` is to the file stream for the file payload. While this
// function takes an io.Reader, the caller needs to reset it to the beginning
// for each new KeywordFunc
type KeywordFunc func(path string, info os.FileInfo, r io.Reader) (KeyVal, error)
type KeywordFunc func(path string, info os.FileInfo, r io.Reader) ([]KeyVal, error)
var (
// KeywordFuncs is the map of all keywords (and the functions to produce them)
KeywordFuncs = map[Keyword]KeywordFunc{
"size": sizeKeywordFunc, // The size, in bytes, of the file
"type": typeKeywordFunc, // The type of the file
"time": timeKeywordFunc, // The last modification time of the file
"link": linkKeywordFunc, // The target of the symbolic link when type=link
"uid": uidKeywordFunc, // The file owner as a numeric value
"gid": gidKeywordFunc, // The file group as a numeric value
"nlink": nlinkKeywordFunc, // The number of hard links the file is expected to have
"uname": unameKeywordFunc, // The file owner as a symbolic name
"mode": modeKeywordFunc, // The current file's permissions as a numeric (octal) or symbolic value
"cksum": cksumKeywordFunc, // The checksum of the file using the default algorithm specified by the cksum(1) utility
"md5": hasherKeywordFunc("md5digest", md5.New), // The MD5 message digest of the file
"md5digest": hasherKeywordFunc("md5digest", md5.New), // A synonym for `md5`
"rmd160": hasherKeywordFunc("ripemd160digest", ripemd160.New), // The RIPEMD160 message digest of the file
"rmd160digest": hasherKeywordFunc("ripemd160digest", ripemd160.New), // A synonym for `rmd160`
"ripemd160digest": hasherKeywordFunc("ripemd160digest", ripemd160.New), // A synonym for `rmd160`
"sha1": hasherKeywordFunc("sha1digest", sha1.New), // The SHA1 message digest of the file
"sha1digest": hasherKeywordFunc("sha1digest", sha1.New), // A synonym for `sha1`
"sha256": hasherKeywordFunc("sha256digest", sha256.New), // The SHA256 message digest of the file
"sha256digest": hasherKeywordFunc("sha256digest", sha256.New), // A synonym for `sha256`
"sha384": hasherKeywordFunc("sha384digest", sha512.New384), // The SHA384 message digest of the file
"sha384digest": hasherKeywordFunc("sha384digest", sha512.New384), // A synonym for `sha384`
"sha512": hasherKeywordFunc("sha512digest", sha512.New), // The SHA512 message digest of the file
"sha512digest": hasherKeywordFunc("sha512digest", sha512.New), // A synonym for `sha512`
"size": sizeKeywordFunc, // The size, in bytes, of the file
"type": typeKeywordFunc, // The type of the file
"time": timeKeywordFunc, // The last modification time of the file
"link": linkKeywordFunc, // The target of the symbolic link when type=link
"uid": uidKeywordFunc, // The file owner as a numeric value
"gid": gidKeywordFunc, // The file group as a numeric value
"nlink": nlinkKeywordFunc, // The number of hard links the file is expected to have
"uname": unameKeywordFunc, // The file owner as a symbolic name
"gname": gnameKeywordFunc, // The file group as a symbolic name
"mode": modeKeywordFunc, // The current file's permissions as a numeric (octal) or symbolic value
"cksum": cksumKeywordFunc, // The checksum of the file using the default algorithm specified by the cksum(1) utility
"md5": hasherKeywordFunc("md5digest", md5.New), // The MD5 message digest of the file
"md5digest": hasherKeywordFunc("md5digest", md5.New), // A synonym for `md5`
"rmd160": hasherKeywordFunc("ripemd160digest", ripemd160.New), // The RIPEMD160 message digest of the file
"rmd160digest": hasherKeywordFunc("ripemd160digest", ripemd160.New), // A synonym for `rmd160`
"ripemd160digest": hasherKeywordFunc("ripemd160digest", ripemd160.New), // A synonym for `rmd160`
"sha1": hasherKeywordFunc("sha1digest", sha1.New), // The SHA1 message digest of the file
"sha1digest": hasherKeywordFunc("sha1digest", sha1.New), // A synonym for `sha1`
"sha256": hasherKeywordFunc("sha256digest", sha256.New), // The SHA256 message digest of the file
"sha256digest": hasherKeywordFunc("sha256digest", sha256.New), // A synonym for `sha256`
"sha384": hasherKeywordFunc("sha384digest", sha512.New384), // The SHA384 message digest of the file
"sha384digest": hasherKeywordFunc("sha384digest", sha512.New384), // A synonym for `sha384`
"sha512": hasherKeywordFunc("sha512digest", sha512.New), // The SHA512 message digest of the file
"sha512digest": hasherKeywordFunc("sha512digest", sha512.New), // A synonym for `sha512`
"sha512256": hasherKeywordFunc("sha512digest", sha512.New512_256), // The SHA512/256 message digest of the file
"sha512256digest": hasherKeywordFunc("sha512digest", sha512.New512_256), // A synonym for `sha512256`
"flags": flagsKeywordFunc, // NOTE: this is a noop, but here to support the presence of the "flags" keyword.
@ -65,7 +69,7 @@ var (
}
)
var (
modeKeywordFunc = func(path string, info os.FileInfo, r io.Reader) (KeyVal, error) {
modeKeywordFunc = func(path string, info os.FileInfo, r io.Reader) ([]KeyVal, error) {
permissions := info.Mode().Perm()
if os.ModeSetuid&info.Mode() > 0 {
permissions |= (1 << 11)
@ -76,93 +80,93 @@ var (
if os.ModeSticky&info.Mode() > 0 {
permissions |= (1 << 9)
}
return KeyVal(fmt.Sprintf("mode=%#o", permissions)), nil
return []KeyVal{KeyVal(fmt.Sprintf("mode=%#o", permissions))}, nil
}
sizeKeywordFunc = func(path string, info os.FileInfo, r io.Reader) (KeyVal, error) {
sizeKeywordFunc = func(path string, info os.FileInfo, r io.Reader) ([]KeyVal, error) {
if sys, ok := info.Sys().(*tar.Header); ok {
if sys.Typeflag == tar.TypeSymlink {
return KeyVal(fmt.Sprintf("size=%d", len(sys.Linkname))), nil
return []KeyVal{KeyVal(fmt.Sprintf("size=%d", len(sys.Linkname)))}, nil
}
}
return KeyVal(fmt.Sprintf("size=%d", info.Size())), nil
return []KeyVal{KeyVal(fmt.Sprintf("size=%d", info.Size()))}, nil
}
cksumKeywordFunc = func(path string, info os.FileInfo, r io.Reader) (KeyVal, error) {
cksumKeywordFunc = func(path string, info os.FileInfo, r io.Reader) ([]KeyVal, error) {
if !info.Mode().IsRegular() {
return emptyKV, nil
return nil, nil
}
sum, _, err := cksum(r)
if err != nil {
return emptyKV, err
return nil, err
}
return KeyVal(fmt.Sprintf("cksum=%d", sum)), nil
return []KeyVal{KeyVal(fmt.Sprintf("cksum=%d", sum))}, nil
}
hasherKeywordFunc = func(name string, newHash func() hash.Hash) KeywordFunc {
return func(path string, info os.FileInfo, r io.Reader) (KeyVal, error) {
return func(path string, info os.FileInfo, r io.Reader) ([]KeyVal, error) {
if !info.Mode().IsRegular() {
return emptyKV, nil
return nil, nil
}
h := newHash()
if _, err := io.Copy(h, r); err != nil {
return emptyKV, err
return nil, err
}
return KeyVal(fmt.Sprintf("%s=%x", KeywordSynonym(name), h.Sum(nil))), nil
return []KeyVal{KeyVal(fmt.Sprintf("%s=%x", KeywordSynonym(name), h.Sum(nil)))}, nil
}
}
tartimeKeywordFunc = func(path string, info os.FileInfo, r io.Reader) (KeyVal, error) {
return KeyVal(fmt.Sprintf("tar_time=%d.%9.9d", info.ModTime().Unix(), 0)), nil
tartimeKeywordFunc = func(path string, info os.FileInfo, r io.Reader) ([]KeyVal, error) {
return []KeyVal{KeyVal(fmt.Sprintf("tar_time=%d.%9.9d", info.ModTime().Unix(), 0))}, nil
}
timeKeywordFunc = func(path string, info os.FileInfo, r io.Reader) (KeyVal, error) {
timeKeywordFunc = func(path string, info os.FileInfo, r io.Reader) ([]KeyVal, error) {
tSec := info.ModTime().Unix()
tNano := info.ModTime().Nanosecond()
return KeyVal(fmt.Sprintf("time=%d.%9.9d", tSec, tNano)), nil
return []KeyVal{KeyVal(fmt.Sprintf("time=%d.%9.9d", tSec, tNano))}, nil
}
linkKeywordFunc = func(path string, info os.FileInfo, r io.Reader) (KeyVal, error) {
linkKeywordFunc = func(path string, info os.FileInfo, r io.Reader) ([]KeyVal, error) {
if sys, ok := info.Sys().(*tar.Header); ok {
if sys.Linkname != "" {
linkname, err := Vis(sys.Linkname, DefaultVisFlags)
linkname, err := govis.Vis(sys.Linkname, DefaultVisFlags)
if err != nil {
return emptyKV, err
return nil, nil
}
return KeyVal(fmt.Sprintf("link=%s", linkname)), nil
return []KeyVal{KeyVal(fmt.Sprintf("link=%s", linkname))}, nil
}
return emptyKV, nil
return nil, nil
}
if info.Mode()&os.ModeSymlink != 0 {
str, err := os.Readlink(path)
if err != nil {
return emptyKV, err
return nil, nil
}
linkname, err := Vis(str, DefaultVisFlags)
linkname, err := govis.Vis(str, DefaultVisFlags)
if err != nil {
return emptyKV, err
return nil, nil
}
return KeyVal(fmt.Sprintf("link=%s", linkname)), nil
return []KeyVal{KeyVal(fmt.Sprintf("link=%s", linkname))}, nil
}
return emptyKV, nil
return nil, nil
}
typeKeywordFunc = func(path string, info os.FileInfo, r io.Reader) (KeyVal, error) {
typeKeywordFunc = func(path string, info os.FileInfo, r io.Reader) ([]KeyVal, error) {
if info.Mode().IsDir() {
return "type=dir", nil
return []KeyVal{"type=dir"}, nil
}
if info.Mode().IsRegular() {
return "type=file", nil
return []KeyVal{"type=file"}, nil
}
if info.Mode()&os.ModeSocket != 0 {
return "type=socket", nil
return []KeyVal{"type=socket"}, nil
}
if info.Mode()&os.ModeSymlink != 0 {
return "type=link", nil
return []KeyVal{"type=link"}, nil
}
if info.Mode()&os.ModeNamedPipe != 0 {
return "type=fifo", nil
return []KeyVal{"type=fifo"}, nil
}
if info.Mode()&os.ModeDevice != 0 {
if info.Mode()&os.ModeCharDevice != 0 {
return "type=char", nil
return []KeyVal{"type=char"}, nil
}
return "type=device", nil
return []KeyVal{"type=block"}, nil
}
return emptyKV, nil
return nil, nil
}
)

69
keywordfuncs_bsd.go Normal file
View File

@ -0,0 +1,69 @@
// +build darwin freebsd netbsd openbsd
package mtree
import (
"archive/tar"
"fmt"
"io"
"os"
"os/user"
"syscall"
)
var (
flagsKeywordFunc = func(path string, info os.FileInfo, r io.Reader) ([]KeyVal, error) {
// ideally this will pull in from here https://www.freebsd.org/cgi/man.cgi?query=chflags&sektion=2
return nil, nil
}
unameKeywordFunc = func(path string, info os.FileInfo, r io.Reader) ([]KeyVal, error) {
if hdr, ok := info.Sys().(*tar.Header); ok {
return []KeyVal{KeyVal(fmt.Sprintf("uname=%s", hdr.Uname))}, nil
}
stat := info.Sys().(*syscall.Stat_t)
u, err := user.LookupId(fmt.Sprintf("%d", stat.Uid))
if err != nil {
return nil, err
}
return []KeyVal{KeyVal(fmt.Sprintf("uname=%s", u.Username))}, nil
}
gnameKeywordFunc = func(path string, info os.FileInfo, r io.Reader) ([]KeyVal, error) {
if hdr, ok := info.Sys().(*tar.Header); ok {
return []KeyVal{KeyVal(fmt.Sprintf("gname=%s", hdr.Gname))}, nil
}
stat := info.Sys().(*syscall.Stat_t)
g, err := lookupGroupID(fmt.Sprintf("%d", stat.Gid))
if err != nil {
return nil, err
}
return []KeyVal{KeyVal(fmt.Sprintf("gname=%s", g.Name))}, nil
}
uidKeywordFunc = func(path string, info os.FileInfo, r io.Reader) ([]KeyVal, error) {
if hdr, ok := info.Sys().(*tar.Header); ok {
return []KeyVal{KeyVal(fmt.Sprintf("uid=%d", hdr.Uid))}, nil
}
stat := info.Sys().(*syscall.Stat_t)
return []KeyVal{KeyVal(fmt.Sprintf("uid=%d", stat.Uid))}, nil
}
gidKeywordFunc = func(path string, info os.FileInfo, r io.Reader) ([]KeyVal, error) {
if hdr, ok := info.Sys().(*tar.Header); ok {
return []KeyVal{KeyVal(fmt.Sprintf("gid=%d", hdr.Gid))}, nil
}
if stat, ok := info.Sys().(*syscall.Stat_t); ok {
return []KeyVal{KeyVal(fmt.Sprintf("gid=%d", stat.Gid))}, nil
}
return nil, nil
}
nlinkKeywordFunc = func(path string, info os.FileInfo, r io.Reader) ([]KeyVal, error) {
if stat, ok := info.Sys().(*syscall.Stat_t); ok {
return []KeyVal{KeyVal(fmt.Sprintf("nlink=%d", stat.Nlink))}, nil
}
return nil, nil
}
xattrKeywordFunc = func(path string, info os.FileInfo, r io.Reader) ([]KeyVal, error) {
return nil, nil
}
)

View File

@ -9,87 +9,99 @@ import (
"io"
"os"
"os/user"
"strings"
"syscall"
"github.com/vbatts/go-mtree/pkg/govis"
"github.com/vbatts/go-mtree/xattr"
)
var (
// this is bsd specific https://www.freebsd.org/cgi/man.cgi?query=chflags&sektion=2
flagsKeywordFunc = func(path string, info os.FileInfo, r io.Reader) (KeyVal, error) {
return emptyKV, nil
flagsKeywordFunc = func(path string, info os.FileInfo, r io.Reader) ([]KeyVal, error) {
return nil, nil
}
unameKeywordFunc = func(path string, info os.FileInfo, r io.Reader) (KeyVal, error) {
unameKeywordFunc = func(path string, info os.FileInfo, r io.Reader) ([]KeyVal, error) {
if hdr, ok := info.Sys().(*tar.Header); ok {
return KeyVal(fmt.Sprintf("uname=%s", hdr.Uname)), nil
return []KeyVal{KeyVal(fmt.Sprintf("uname=%s", hdr.Uname))}, nil
}
stat := info.Sys().(*syscall.Stat_t)
u, err := user.LookupId(fmt.Sprintf("%d", stat.Uid))
if err != nil {
return emptyKV, err
return nil, nil
}
return KeyVal(fmt.Sprintf("uname=%s", u.Username)), nil
return []KeyVal{KeyVal(fmt.Sprintf("uname=%s", u.Username))}, nil
}
uidKeywordFunc = func(path string, info os.FileInfo, r io.Reader) (KeyVal, error) {
gnameKeywordFunc = func(path string, info os.FileInfo, r io.Reader) ([]KeyVal, error) {
if hdr, ok := info.Sys().(*tar.Header); ok {
return KeyVal(fmt.Sprintf("uid=%d", hdr.Uid)), nil
return []KeyVal{KeyVal(fmt.Sprintf("gname=%s", hdr.Gname))}, nil
}
stat := info.Sys().(*syscall.Stat_t)
g, err := lookupGroupID(fmt.Sprintf("%d", stat.Gid))
if err != nil {
return nil, nil
}
return []KeyVal{KeyVal(fmt.Sprintf("gname=%s", g.Name))}, nil
}
uidKeywordFunc = func(path string, info os.FileInfo, r io.Reader) ([]KeyVal, error) {
if hdr, ok := info.Sys().(*tar.Header); ok {
return []KeyVal{KeyVal(fmt.Sprintf("uid=%d", hdr.Uid))}, nil
}
stat := info.Sys().(*syscall.Stat_t)
return KeyVal(fmt.Sprintf("uid=%d", stat.Uid)), nil
return []KeyVal{KeyVal(fmt.Sprintf("uid=%d", stat.Uid))}, nil
}
gidKeywordFunc = func(path string, info os.FileInfo, r io.Reader) (KeyVal, error) {
gidKeywordFunc = func(path string, info os.FileInfo, r io.Reader) ([]KeyVal, error) {
if hdr, ok := info.Sys().(*tar.Header); ok {
return KeyVal(fmt.Sprintf("gid=%d", hdr.Gid)), nil
return []KeyVal{KeyVal(fmt.Sprintf("gid=%d", hdr.Gid))}, nil
}
if stat, ok := info.Sys().(*syscall.Stat_t); ok {
return KeyVal(fmt.Sprintf("gid=%d", stat.Gid)), nil
return []KeyVal{KeyVal(fmt.Sprintf("gid=%d", stat.Gid))}, nil
}
return emptyKV, nil
return nil, nil
}
nlinkKeywordFunc = func(path string, info os.FileInfo, r io.Reader) (KeyVal, error) {
nlinkKeywordFunc = func(path string, info os.FileInfo, r io.Reader) ([]KeyVal, error) {
if stat, ok := info.Sys().(*syscall.Stat_t); ok {
return KeyVal(fmt.Sprintf("nlink=%d", stat.Nlink)), nil
return []KeyVal{KeyVal(fmt.Sprintf("nlink=%d", stat.Nlink))}, nil
}
return emptyKV, nil
return nil, nil
}
xattrKeywordFunc = func(path string, info os.FileInfo, r io.Reader) (KeyVal, error) {
xattrKeywordFunc = func(path string, info os.FileInfo, r io.Reader) ([]KeyVal, error) {
if hdr, ok := info.Sys().(*tar.Header); ok {
if len(hdr.Xattrs) == 0 {
return emptyKV, nil
return nil, nil
}
klist := []KeyVal{}
for k, v := range hdr.Xattrs {
encKey, err := Vis(k, DefaultVisFlags)
encKey, err := govis.Vis(k, DefaultVisFlags)
if err != nil {
return emptyKV, err
return nil, nil
}
klist = append(klist, KeyVal(fmt.Sprintf("xattr.%s=%s", encKey, base64.StdEncoding.EncodeToString([]byte(v)))))
}
return KeyVal(strings.Join(KeyValToString(klist), " ")), nil
return klist, nil
}
if !info.Mode().IsRegular() && !info.Mode().IsDir() {
return emptyKV, nil
return nil, nil
}
xlist, err := xattr.List(path)
if err != nil {
return emptyKV, err
return nil, nil
}
klist := make([]KeyVal, len(xlist))
for i := range xlist {
data, err := xattr.Get(path, xlist[i])
if err != nil {
return emptyKV, err
return nil, nil
}
encKey, err := Vis(xlist[i], DefaultVisFlags)
encKey, err := govis.Vis(xlist[i], DefaultVisFlags)
if err != nil {
return emptyKV, err
return nil, nil
}
klist[i] = KeyVal(fmt.Sprintf("xattr.%s=%s", encKey, base64.StdEncoding.EncodeToString(data)))
}
return KeyVal(strings.Join(KeyValToString(klist), " ")), nil
return klist, nil
}
)

View File

@ -11,31 +11,37 @@ import (
var (
// this is bsd specific https://www.freebsd.org/cgi/man.cgi?query=chflags&sektion=2
flagsKeywordFunc = func(path string, info os.FileInfo, r io.Reader) (KeyVal, error) {
return emptyKV, nil
flagsKeywordFunc = func(path string, info os.FileInfo, r io.Reader) ([]KeyVal, error) {
return nil, nil
}
unameKeywordFunc = func(path string, info os.FileInfo, r io.Reader) (KeyVal, error) {
unameKeywordFunc = func(path string, info os.FileInfo, r io.Reader) ([]KeyVal, error) {
if hdr, ok := info.Sys().(*tar.Header); ok {
return KeyVal(fmt.Sprintf("uname=%s", hdr.Uname)), nil
return []KeyVal{KeyVal(fmt.Sprintf("uname=%s", hdr.Uname))}, nil
}
return emptyKV, nil
return nil, nil
}
uidKeywordFunc = func(path string, info os.FileInfo, r io.Reader) (KeyVal, error) {
gnameKeywordFunc = func(path string, info os.FileInfo, r io.Reader) ([]KeyVal, error) {
if hdr, ok := info.Sys().(*tar.Header); ok {
return KeyVal(fmt.Sprintf("uid=%d", hdr.Uid)), nil
return []KeyVal{KeyVal(fmt.Sprintf("gname=%s", hdr.Gname))}, nil
}
return emptyKV, nil
return nil, nil
}
gidKeywordFunc = func(path string, info os.FileInfo, r io.Reader) (KeyVal, error) {
uidKeywordFunc = func(path string, info os.FileInfo, r io.Reader) ([]KeyVal, error) {
if hdr, ok := info.Sys().(*tar.Header); ok {
return KeyVal(fmt.Sprintf("gid=%d", hdr.Gid)), nil
return []KeyVal{KeyVal(fmt.Sprintf("uid=%d", hdr.Uid))}, nil
}
return emptyKV, nil
return nil, nil
}
nlinkKeywordFunc = func(path string, info os.FileInfo, r io.Reader) (KeyVal, error) {
return emptyKV, nil
gidKeywordFunc = func(path string, info os.FileInfo, r io.Reader) ([]KeyVal, error) {
if hdr, ok := info.Sys().(*tar.Header); ok {
return []KeyVal{KeyVal(fmt.Sprintf("gid=%d", hdr.Gid))}, nil
}
return nil, nil
}
xattrKeywordFunc = func(path string, info os.FileInfo, r io.Reader) (KeyVal, error) {
return emptyKV, nil
nlinkKeywordFunc = func(path string, info os.FileInfo, r io.Reader) ([]KeyVal, error) {
return nil, nil
}
xattrKeywordFunc = func(path string, info os.FileInfo, r io.Reader) ([]KeyVal, error) {
return nil, nil
}
)

View File

@ -3,12 +3,40 @@ package mtree
import (
"fmt"
"strings"
"github.com/vbatts/go-mtree/pkg/govis"
)
// DefaultVisFlags is the set of Vis flags used when encoding filenames and
// other similar entries.
const DefaultVisFlags govis.VisFlag = govis.VisWhite | govis.VisOctal | govis.VisGlob
// Keyword is the string name of a keyword, with some convenience functions for
// determining whether it is a default or bsd standard keyword.
// It first portion before the "="
type Keyword string
// Prefix is the portion of the keyword before a first "." (if present).
//
// Primarly for the xattr use-case, where the keyword `xattr.security.selinux` would have a Suffix of `security.selinux`.
func (k Keyword) Prefix() Keyword {
if strings.Contains(string(k), ".") {
return Keyword(strings.SplitN(string(k), ".", 2)[0])
}
return k
}
// Suffix is the portion of the keyword after a first ".".
// This is an option feature.
//
// Primarly for the xattr use-case, where the keyword `xattr.security.selinux` would have a Suffix of `security.selinux`.
func (k Keyword) Suffix() string {
if strings.Contains(string(k), ".") {
return strings.SplitN(string(k), ".", 2)[1]
}
return string(k)
}
// Default returns whether this keyword is in the default set of keywords
func (k Keyword) Default() bool {
return InKeywordSlice(k, DefaultKeywords)
@ -87,24 +115,7 @@ func (kv KeyVal) Keyword() Keyword {
if !strings.Contains(string(kv), "=") {
return Keyword("")
}
chunks := strings.SplitN(strings.TrimSpace(string(kv)), "=", 2)[0]
if !strings.Contains(chunks, ".") {
return Keyword(chunks)
}
return Keyword(strings.SplitN(chunks, ".", 2)[0])
}
// KeywordSuffix is really only used for xattr, as the keyword is a prefix to
// the xattr "namespace.key"
func (kv KeyVal) KeywordSuffix() string {
if !strings.Contains(string(kv), "=") {
return ""
}
chunks := strings.SplitN(strings.TrimSpace(string(kv)), "=", 2)[0]
if !strings.Contains(chunks, ".") {
return ""
}
return strings.SplitN(chunks, ".", 2)[1]
return Keyword(strings.SplitN(strings.TrimSpace(string(kv)), "=", 2)[0])
}
// Value is the data/value portion of "keyword=value"
@ -115,25 +126,34 @@ func (kv KeyVal) Value() string {
return strings.SplitN(strings.TrimSpace(string(kv)), "=", 2)[1]
}
// ChangeValue changes the value of a KeyVal
func (kv KeyVal) ChangeValue(newval string) string {
return fmt.Sprintf("%s=%s", kv.Keyword(), newval)
// NewValue returns a new KeyVal with the newval
func (kv KeyVal) NewValue(newval string) KeyVal {
return KeyVal(fmt.Sprintf("%s=%s", kv.Keyword(), newval))
}
// KeyValEqual returns whether two KeyVal are equivalent. This takes
// Equal returns whether two KeyVal are equivalent. This takes
// care of certain odd cases such as tar_mtime, and should be used over
// using == comparisons directly unless you really know what you're
// doing.
func KeyValEqual(a, b KeyVal) bool {
func (kv KeyVal) Equal(b KeyVal) bool {
// TODO: Implement handling of tar_mtime.
return a.Keyword() == b.Keyword() && a.Value() == b.Value()
return kv.Keyword() == b.Keyword() && kv.Value() == b.Value()
}
// keyvalSelector takes an array of KeyVal ("keyword=value") and filters out that only the set of keywords
func keywordPrefixes(kvset []Keyword) []Keyword {
kvs := []Keyword{}
for _, kv := range kvset {
kvs = append(kvs, kv.Prefix())
}
return kvs
}
// keyvalSelector takes an array of KeyVal ("keyword=value") and filters out
// that only the set of keywords
func keyvalSelector(keyval []KeyVal, keyset []Keyword) []KeyVal {
retList := []KeyVal{}
for _, kv := range keyval {
if InKeywordSlice(kv.Keyword(), keyset) {
if InKeywordSlice(kv.Keyword().Prefix(), keywordPrefixes(keyset)) {
retList = append(retList, kv)
}
}
@ -162,23 +182,23 @@ func keyValCopy(set []KeyVal) []KeyVal {
// Has the "keyword" present in the list of KeyVal, and returns the
// corresponding KeyVal, else an empty string.
func Has(keyvals []KeyVal, keyword string) KeyVal {
func Has(keyvals []KeyVal, keyword string) []KeyVal {
return HasKeyword(keyvals, Keyword(keyword))
}
// HasKeyword the "keyword" present in the list of KeyVal, and returns the
// corresponding KeyVal, else an empty string.
func HasKeyword(keyvals []KeyVal, keyword Keyword) KeyVal {
// This match is done on the Prefix of the keyword only.
func HasKeyword(keyvals []KeyVal, keyword Keyword) []KeyVal {
kvs := []KeyVal{}
for i := range keyvals {
if keyvals[i].Keyword() == keyword {
return keyvals[i]
if keyvals[i].Keyword().Prefix() == keyword.Prefix() {
kvs = append(kvs, keyvals[i])
}
}
return emptyKV
return kvs
}
var emptyKV = KeyVal("")
// MergeSet takes the current setKeyVals, and then applies the entryKeyVals
// such that the entry's values win. The union is returned.
func MergeSet(setKeyVals, entryKeyVals []string) []KeyVal {
@ -194,8 +214,11 @@ func MergeKeyValSet(setKeyVals, entryKeyVals []KeyVal) []KeyVal {
seenKeywords := []Keyword{}
for i := range retList {
word := retList[i].Keyword()
if ekv := HasKeyword(entryKeyVals, word); ekv != emptyKV {
retList[i] = ekv
for _, kv := range HasKeyword(entryKeyVals, word) {
// match on the keyword prefix and suffix here
if kv.Keyword() == word {
retList[i] = kv
}
}
seenKeywords = append(seenKeywords, word)
}
@ -236,7 +259,6 @@ var (
// BsdKeywords is the set of keywords that is only in the upstream FreeBSD mtree
BsdKeywords = []Keyword{
"cksum",
"device",
"flags", // this one is really mostly BSD specific ...
"ignore",
"gid",
@ -294,6 +316,8 @@ func KeywordSynonym(name string) Keyword {
retname = "sha384digest"
case "sha512":
retname = "sha512digest"
case "sha512256":
retname = "sha512256digest"
case "xattrs":
retname = "xattr"
default:

View File

@ -1,57 +0,0 @@
// +build darwin freebsd netbsd openbsd
package mtree
import (
"archive/tar"
"fmt"
"io"
"os"
"os/user"
"syscall"
)
var (
flagsKeywordFunc = func(path string, info os.FileInfo, r io.Reader) (KeyVal, error) {
// ideally this will pull in from here https://www.freebsd.org/cgi/man.cgi?query=chflags&sektion=2
return emptyKV, nil
}
unameKeywordFunc = func(path string, info os.FileInfo, r io.Reader) (KeyVal, error) {
if hdr, ok := info.Sys().(*tar.Header); ok {
return KeyVal(fmt.Sprintf("uname=%s", hdr.Uname)), nil
}
stat := info.Sys().(*syscall.Stat_t)
u, err := user.LookupId(fmt.Sprintf("%d", stat.Uid))
if err != nil {
return emptyKV, err
}
return KeyVal(fmt.Sprintf("uname=%s", u.Username)), nil
}
uidKeywordFunc = func(path string, info os.FileInfo, r io.Reader) (KeyVal, error) {
if hdr, ok := info.Sys().(*tar.Header); ok {
return KeyVal(fmt.Sprintf("uid=%d", hdr.Uid)), nil
}
stat := info.Sys().(*syscall.Stat_t)
return KeyVal(fmt.Sprintf("uid=%d", stat.Uid)), nil
}
gidKeywordFunc = func(path string, info os.FileInfo, r io.Reader) (KeyVal, error) {
if hdr, ok := info.Sys().(*tar.Header); ok {
return KeyVal(fmt.Sprintf("gid=%d", hdr.Gid)), nil
}
if stat, ok := info.Sys().(*syscall.Stat_t); ok {
return KeyVal(fmt.Sprintf("gid=%d", stat.Gid)), nil
}
return emptyKV, nil
}
nlinkKeywordFunc = func(path string, info os.FileInfo, r io.Reader) (KeyVal, error) {
if stat, ok := info.Sys().(*syscall.Stat_t); ok {
return KeyVal(fmt.Sprintf("nlink=%d", stat.Nlink)), nil
}
return emptyKV, nil
}
xattrKeywordFunc = func(path string, info os.FileInfo, r io.Reader) (KeyVal, error) {
return emptyKV, nil
}
)

View File

@ -13,9 +13,14 @@ import (
)
func TestXattr(t *testing.T) {
// a bit dirty to create/destory a directory in cwd, but often /tmp is
// mounted tmpfs and doesn't support xattrs
dir, err := ioutil.TempDir(".", "test.xattrs.")
testDir, present := os.LookupEnv("MTREE_TESTDIR")
if present == false {
// a bit dirty to create/destory a directory in cwd,
// but often /tmp is mounted tmpfs and doesn't support
// xattrs
testDir = "."
}
dir, err := ioutil.TempDir(testDir, "test.xattrs.")
if err != nil {
t.Fatal(err)
}
@ -46,12 +51,12 @@ func TestXattr(t *testing.T) {
t.Fatal(err)
}
// Check the directory
str, err := xattrKeywordFunc(dir, dirstat, nil)
kvs, err := xattrKeywordFunc(dir, dirstat, nil)
if err != nil {
t.Error(err)
}
if str == "" {
t.Errorf("expected a keyval; got %q", str)
if len(kvs) == 0 {
t.Errorf("expected a keyval; got none")
}
filestat, err := fh.Stat()
@ -59,12 +64,12 @@ func TestXattr(t *testing.T) {
t.Fatal(err)
}
// Check the regular file
str, err = xattrKeywordFunc(filepath.Join(dir, "file"), filestat, fh)
kvs, err = xattrKeywordFunc(filepath.Join(dir, "file"), filestat, fh)
if err != nil {
t.Error(err)
}
if str == "" {
t.Errorf("expected a keyval; got %q", str)
if len(kvs) == 0 {
t.Errorf("expected a keyval; got none")
}
linkstat, err := os.Lstat(filepath.Join(dir, "symlink"))

View File

@ -7,6 +7,47 @@ import (
"time"
)
func TestKeyValRoundtrip(t *testing.T) {
kv := KeyVal("xattr.security.selinux=dW5jb25maW5lZF91Om9iamVjdF9yOnVzZXJfaG9tZV90OnMwAA==")
expected := "xattr.security.selinux"
got := string(kv.Keyword())
if got != expected {
t.Errorf("expected %q; got %q", expected, got)
}
expected = "xattr"
got = string(kv.Keyword().Prefix())
if got != expected {
t.Errorf("expected %q; got %q", expected, got)
}
expected = "security.selinux"
got = kv.Keyword().Suffix()
if got != expected {
t.Errorf("expected %q; got %q", expected, got)
}
expected = "dW5jb25maW5lZF91Om9iamVjdF9yOnVzZXJfaG9tZV90OnMwAA=="
got = kv.Value()
if got != expected {
t.Errorf("expected %q; got %q", expected, got)
}
expected = "xattr.security.selinux=farts"
got = string(kv.NewValue("farts"))
if got != expected {
t.Errorf("expected %q; got %q", expected, got)
}
expected = "xattr.security.selinux=farts"
kv1 := KeyVal(got)
kv2 := kv.NewValue("farts")
if !kv2.Equal(kv1) {
t.Errorf("expected equality of %q and %q", kv1, kv2)
}
}
type fakeFileInfo struct {
mtime time.Time
}
@ -61,8 +102,11 @@ func TestKeywordsTimeNano(t *testing.T) {
if err != nil {
t.Errorf("unexpected error while parsing '%q': %q", mtime, err)
}
if expected != got {
t.Errorf("keyword didn't match, expected '%s' got '%s'", expected, got)
if len(got) != 1 {
t.Errorf("expected 1 KeyVal, but got %d", len(got))
}
if expected != got[0] {
t.Errorf("keyword didn't match, expected '%s' got '%s'", expected, got[0])
}
}
}
@ -88,8 +132,11 @@ func TestKeywordsTimeTar(t *testing.T) {
if err != nil {
t.Errorf("unexpected error while parsing '%q': %q", mtime, err)
}
if expected != got {
t.Errorf("keyword didn't match, expected '%s' got '%s'", expected, got)
if len(got) != 1 {
t.Errorf("expected 1 KeyVal, but got %d", len(got))
}
if expected != got[0] {
t.Errorf("keyword didn't match, expected '%s' got '%s'", expected, got[0])
}
}
}

22
lchtimes_unix.go Normal file
View File

@ -0,0 +1,22 @@
// +build darwin dragonfly freebsd openbsd linux netbsd solaris
package mtree
import (
"os"
"time"
"golang.org/x/sys/unix"
)
func lchtimes(name string, atime time.Time, mtime time.Time) error {
utimes := []unix.Timespec{
unix.NsecToTimespec(atime.UnixNano()),
unix.NsecToTimespec(mtime.UnixNano()),
}
if e := unix.UtimesNanoAt(unix.AT_FDCWD, name, utimes, unix.AT_SYMLINK_NOFOLLOW); e != nil {
return &os.PathError{Op: "chtimes", Path: name, Err: e}
}
return nil
}

11
lchtimes_unsupported.go Normal file
View File

@ -0,0 +1,11 @@
// +build windows
package mtree
import (
"time"
)
func lchtimes(name string, atime time.Time, mtime time.Time) error {
return nil
}

9
lookup_new.go Normal file
View File

@ -0,0 +1,9 @@
// +build go1.7
package mtree
import (
"os/user"
)
var lookupGroupID = user.LookupGroupId

102
lookup_old.go Normal file
View File

@ -0,0 +1,102 @@
// +build !go1.7
package mtree
import (
"bufio"
"bytes"
"io"
"os"
"strconv"
"strings"
)
const groupFile = "/etc/group"
var colon = []byte{':'}
// Group represents a grouping of users.
//
// On POSIX systems Gid contains a decimal number representing the group ID.
type Group struct {
Gid string // group ID
Name string // group name
}
func lookupGroupID(id string) (*Group, error) {
f, err := os.Open(groupFile)
if err != nil {
return nil, err
}
defer f.Close()
return findGroupID(id, f)
}
func findGroupID(id string, r io.Reader) (*Group, error) {
if v, err := readColonFile(r, matchGroupIndexValue(id, 2)); err != nil {
return nil, err
} else if v != nil {
return v.(*Group), nil
}
return nil, UnknownGroupIDError(id)
}
// lineFunc returns a value, an error, or (nil, nil) to skip the row.
type lineFunc func(line []byte) (v interface{}, err error)
// readColonFile parses r as an /etc/group or /etc/passwd style file, running
// fn for each row. readColonFile returns a value, an error, or (nil, nil) if
// the end of the file is reached without a match.
func readColonFile(r io.Reader, fn lineFunc) (v interface{}, err error) {
bs := bufio.NewScanner(r)
for bs.Scan() {
line := bs.Bytes()
// There's no spec for /etc/passwd or /etc/group, but we try to follow
// the same rules as the glibc parser, which allows comments and blank
// space at the beginning of a line.
line = bytes.TrimSpace(line)
if len(line) == 0 || line[0] == '#' {
continue
}
v, err = fn(line)
if v != nil || err != nil {
return
}
}
return nil, bs.Err()
}
func matchGroupIndexValue(value string, idx int) lineFunc {
var leadColon string
if idx > 0 {
leadColon = ":"
}
substr := []byte(leadColon + value + ":")
return func(line []byte) (v interface{}, err error) {
if !bytes.Contains(line, substr) || bytes.Count(line, colon) < 3 {
return
}
// wheel:*:0:root
parts := strings.SplitN(string(line), ":", 4)
if len(parts) < 4 || parts[0] == "" || parts[idx] != value ||
// If the file contains +foo and you search for "foo", glibc
// returns an "invalid argument" error. Similarly, if you search
// for a gid for a row where the group name starts with "+" or "-",
// glibc fails to find the record.
parts[0][0] == '+' || parts[0][0] == '-' {
return
}
if _, err := strconv.Atoi(parts[2]); err != nil {
return nil, nil
}
return &Group{Name: parts[0], Gid: parts[2]}, nil
}
}
// UnknownGroupIDError is returned by LookupGroupId when
// a group cannot be found.
type UnknownGroupIDError string
func (e UnknownGroupIDError) Error() string {
return "group: unknown groupid " + string(e)
}

View File

@ -4,25 +4,48 @@ import (
"io/ioutil"
"os"
"testing"
"github.com/davecgh/go-spew/spew"
)
var (
testFiles = []string{"testdata/source.mtree"}
numEntries = map[EntryType]int{
FullType: 0,
RelativeType: 45,
CommentType: 37,
SpecialType: 7,
DotDotType: 17,
BlankType: 34,
testFiles = []struct {
Name string
Counts map[EntryType]int
Len int64
}{
{
Name: "testdata/source.mtree",
Counts: map[EntryType]int{
FullType: 0,
RelativeType: 45,
CommentType: 37,
SpecialType: 7,
DotDotType: 17,
BlankType: 34,
},
Len: int64(7887),
},
{
Name: "testdata/source.casync-mtree",
Counts: map[EntryType]int{
FullType: 744,
RelativeType: 56,
CommentType: 37,
SpecialType: 7,
DotDotType: 17,
BlankType: 34,
},
Len: int64(168439),
},
}
expectedLength = int64(7887)
)
func TestParser(t *testing.T) {
for _, file := range testFiles {
for i, tf := range testFiles {
_ = i
func() {
fh, err := os.Open(file)
fh, err := os.Open(tf.Name)
if err != nil {
t.Error(err)
return
@ -33,8 +56,17 @@ func TestParser(t *testing.T) {
if err != nil {
t.Error(err)
}
if i == 1 {
spew.Dump(dh)
//buf, err := xml.MarshalIndent(dh, "", " ")
//if err == nil {
//t.Error(string(buf))
//}
}
gotNums := countTypes(dh)
for typ, num := range numEntries {
for typ, num := range tf.Counts {
if gNum, ok := gotNums[typ]; ok {
if num != gNum {
t.Errorf("for type %s: expected %d, got %d", typ, num, gNum)
@ -46,8 +78,8 @@ func TestParser(t *testing.T) {
if err != nil {
t.Error(err)
}
if i != expectedLength {
t.Errorf("expected to write %d, but wrote %d", expectedLength, i)
if i != tf.Len {
t.Errorf("expected to write %d, but wrote %d", tf.Len, i)
}
}()

202
pkg/govis/COPYING Normal file
View File

@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

27
pkg/govis/README.md Normal file
View File

@ -0,0 +1,27 @@
## `govis` ##
`govis` is a BSD-compatible `vis(3)` and `unvis(3)` encoding implementation
that is unicode aware and written in Go. None of this code comes from the
original BSD code, nor does it come from `go-mtree`'s port of said code.
Because 80s BSD code is not very nice to read.
### License ###
`govis` is licensed under the Apache 2.0 license.
```
govis: unicode aware vis(3) encoding implementation
Copyright (C) 2017 SUSE LLC.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
```

39
pkg/govis/govis.go Normal file
View File

@ -0,0 +1,39 @@
/*
* govis: unicode aware vis(3) encoding implementation
* Copyright (C) 2017 SUSE LLC.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package govis
// VisFlag manipulates how the characters are encoded/decoded
type VisFlag uint
// vis() has a variety of flags when deciding what encodings to use. While
// mtree only uses one set of flags, implementing them all is necessary in
// order to have compatibility with BSD's vis() and unvis() commands.
const (
VisOctal VisFlag = (1 << iota) // VIS_OCTAL: Use octal \ddd format.
VisCStyle // VIS_CSTYLE: Use \[nrft0..] where appropriate.
VisSpace // VIS_SP: Also encode space.
VisTab // VIS_TAB: Also encode tab.
VisNewline // VIS_NL: Also encode newline.
VisSafe // VIS_SAFE: Encode unsafe characters.
VisNoSlash // VIS_NOSLASH: Inhibit printing '\'.
VisHTTPStyle // VIS_HTTPSTYLE: HTTP-style escape %xx.
VisGlob // VIS_GLOB: Encode glob(3) magics.
visMask VisFlag = (1 << iota) - 1 // Mask of all flags.
VisWhite VisFlag = (VisSpace | VisTab | VisNewline)
)

194
pkg/govis/govis_test.go Normal file
View File

@ -0,0 +1,194 @@
/*
* govis: unicode aware vis(3) encoding implementation
* Copyright (C) 2017 SUSE LLC.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package govis
import (
"bytes"
"crypto/rand"
"testing"
)
const DefaultVisFlags = VisWhite | VisOctal | VisGlob
func TestRandomVisUnvis(t *testing.T) {
// Randomly generate N strings.
const N = 100
for i := 0; i < N; i++ {
testBytes := make([]byte, 256)
if n, err := rand.Read(testBytes); n != cap(testBytes) || err != nil {
t.Fatalf("could not read enough bytes: err=%v n=%d", err, n)
}
test := string(testBytes)
for flag := VisFlag(0); flag <= visMask; flag++ {
// VisNoSlash is frankly just a dumb flag, and it is impossible for us
// to actually preserve things in a round-trip.
if flag&VisNoSlash == VisNoSlash {
continue
}
enc, err := Vis(test, flag)
if err != nil {
t.Errorf("unexpected error doing vis(%q, %b): %s", test, flag, err)
continue
}
dec, err := Unvis(enc, flag)
if err != nil {
t.Errorf("unexpected error doing unvis(%q, %b): %s", enc, flag, err)
continue
}
if dec != test {
t.Errorf("roundtrip failed: unvis(vis(%q, %b) = %q, %b) = %q", test, flag, enc, flag, dec)
}
}
}
}
func TestRandomVisVisUnvisUnvis(t *testing.T) {
// Randomly generate N strings.
const N = 100
for i := 0; i < N; i++ {
testBytes := make([]byte, 256)
if n, err := rand.Read(testBytes); n != cap(testBytes) || err != nil {
t.Fatalf("could not read enough bytes: err=%v n=%d", err, n)
}
test := string(testBytes)
for flag := VisFlag(0); flag <= visMask; flag++ {
// VisNoSlash is frankly just a dumb flag, and it is impossible for us
// to actually preserve things in a round-trip.
if flag&VisNoSlash == VisNoSlash {
continue
}
enc, err := Vis(test, flag)
if err != nil {
t.Errorf("unexpected error doing vis(%q, %b): %s", test, flag, err)
continue
}
enc2, err := Vis(enc, flag)
if err != nil {
t.Errorf("unexpected error doing vis(%q, %b): %s", enc, flag, err)
continue
}
dec, err := Unvis(enc2, flag)
if err != nil {
t.Errorf("unexpected error doing unvis(%q, %b): %s", enc2, flag, err)
continue
}
dec2, err := Unvis(dec, flag)
if err != nil {
t.Errorf("unexpected error doing unvis(%q, %b): %s", dec, flag, err)
continue
}
if dec2 != test {
t.Errorf("roundtrip failed: unvis(unvis(vis(vis(%q) = %q) = %q) = %q, %b) = %q", test, enc, enc2, dec, flag, dec2)
}
}
}
}
func TestVisUnvis(t *testing.T) {
for flag := VisFlag(0); flag <= visMask; flag++ {
// VisNoSlash is frankly just a dumb flag, and it is impossible for us
// to actually preserve things in a round-trip.
if flag&VisNoSlash == VisNoSlash {
continue
}
// Round-trip testing.
for _, test := range []string{
"",
"hello world",
"THIS\\IS_A_TEST1234",
"this.is.a.normal_string",
"AC_Ra\u00edz_Certic\u00e1mara_S.A..pem",
"NetLock_Arany_=Class_Gold=_F\u0151tan\u00fas\u00edtv\u00e1ny.pem",
"T\u00dcB\u0130TAK_UEKAE_K\u00f6k_Sertifika_Hizmet_Sa\u011flay\u0131c\u0131s\u0131_-_S\u00fcr\u00fcm_3.pem",
"hello world [ this string needs=enco ding! ]",
"even \n more encoding necessary\a\a ",
"\024 <-- some more weird characters --> \u4f60\u597d\uff0c\u4e16\u754c",
"\\xff\\n double encoding is also great fun \\x",
"AC_Ra\\M-C\\M--z_Certic\\M-C\\M-!mara_S.A..pem",
"z^i3i$\u00d3\u008anqgh5/t\u00e5<86>\u00b2kzla\\e^lv\u00df\u0093nv\u00df\u00aea|3}\u00d8\u0088\u00d6\u0084",
`z^i3i$\M-C\M^S\M-B\M^Jnqgh5/t\M-C\M-%<86>\M-B\M-2kzla\\e^lv\M-C\M^_\M-B\M^Snv\M-C\M^_\M-B\M-.a|3}\M-C\M^X\M-B\M^H\M-C\M^V\M-B\M^D`,
"@?e1xs+.R_Kjo]7s8pgRP:*nXCE4{!c",
"62_\u00c6\u00c62\u00ae\u00b7m\u00db\u00c3r^\u00bfp\u00c6u'q\u00fbc2\u00f0u\u00b8\u00dd\u00e8v\u00ff\u00b0\u00dc\u00c2\u00f53\u00db-k\u00f2sd4\\p\u00da\u00a6\u00d3\u00eea<\u00e6s{\u00a0p\u00f0\u00ffj\u00e0\u00e8\u00b8\u00b8\u00bc\u00fcb",
`62_\M-C\M^F\M-C\M^F2\M-B\M-.\M-B\M-7m\M-C\M^[\M-C\M^Cr^\M-B\M-?p\M-C\M^Fu'q\M-C\M-;c2\M-C\M-0u\M-B\M-8\M-C\M^]\M-C\M-(v\M-C\M-?\M-B\M-0\M-C\M^\\M-C\M^B\M-C\M-53\M-C\M^[-k\M-C\M-2sd4\\p\M-C\M^Z\M-B\M-&\M-C\M^S\M-C\M-.a<\M-C\M-&s{\M-B\240p\M-C\M-0\M-C\M-?j\M-C\240\M-C\M-(\M-B\M-8\M-B\M-8\M-B\M-<\M-C\M-<b`,
"\u9003\"9v1)T798|o;fly jnKX\u0489Be=",
`\M-i\M^@\M^C"9v1)T798|o;fly jnKX\M-R\M^IBe=`,
"'3Ze\u050e|\u02del\u069du-Rpct4+Z5b={@_{b",
`'3Ze\M-T\M^N|\M-K\M^^l\M-Z\M^]u-Rpct4+Z5b={@_{b`,
"1\u00c6\u00abTcz+Vda?)k1%\\\"P;`po`h",
`1%C3%86%C2%ABTcz+Vda%3F)k1%25%5C%22P%3B%60po%60h`,
} {
enc, err := Vis(test, flag)
if err != nil {
t.Errorf("unexpected error doing vis(%q, %b): %s", test, flag, err)
continue
}
dec, err := Unvis(enc, flag)
if err != nil {
t.Errorf("unexpected error doing unvis(%q, %b): %s", enc, flag, err)
continue
}
if dec != test {
t.Errorf("roundtrip failed: unvis(vis(%q, %b) = %q, %b) = %q", test, flag, enc, flag, dec)
}
}
}
}
func TestByteStrings(t *testing.T) {
// It's important to make sure that we don't mess around with the layout of
// bytes when doing a round-trip. Otherwise we risk outputting visually
// identical but bit-stream non-identical strings (causing much confusion
// when trying to access such files).
for _, test := range [][]byte{
[]byte("This is a man in business suit levitating: \U0001f574"),
{0x7f, 0x17, 0x01, 0x33},
// TODO: Test arbitrary byte streams like the one below. Currently this
// fails because Vis() is messing around with it (converting it
// to a rune and spacing it out).
//{'\xef', '\xae', 'h', '\077', 'k'},
} {
testString := string(test)
enc, err := Vis(testString, DefaultVisFlags)
if err != nil {
t.Errorf("unexpected error doing vis(%q): %s", test, err)
continue
}
dec, err := Unvis(enc, DefaultVisFlags)
if err != nil {
t.Errorf("unexpected error doing unvis(%q): %s", enc, err)
continue
}
decBytes := []byte(dec)
if dec != testString {
t.Errorf("roundtrip failed [string comparison]: unvis(vis(%q) = %q) = %q", test, enc, dec)
}
if !bytes.Equal(decBytes, test) {
t.Errorf("roundtrip failed [byte comparison]: unvis(vis(%q) = %q) = %q", test, enc, dec)
}
}
}

294
pkg/govis/unvis.go Normal file
View File

@ -0,0 +1,294 @@
/*
* govis: unicode aware vis(3) encoding implementation
* Copyright (C) 2017 SUSE LLC.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package govis
import (
"fmt"
"strconv"
"unicode"
)
// unvisParser stores the current state of the token parser.
type unvisParser struct {
tokens []rune
idx int
flag VisFlag
}
// Next moves the index to the next character.
func (p *unvisParser) Next() {
p.idx++
}
// Peek gets the current token.
func (p *unvisParser) Peek() (rune, error) {
if p.idx >= len(p.tokens) {
return unicode.ReplacementChar, fmt.Errorf("tried to read past end of token list")
}
return p.tokens[p.idx], nil
}
// End returns whether all of the tokens have been consumed.
func (p *unvisParser) End() bool {
return p.idx >= len(p.tokens)
}
func newParser(input string, flag VisFlag) *unvisParser {
return &unvisParser{
tokens: []rune(input),
idx: 0,
flag: flag,
}
}
// While a recursive descent parser is overkill for parsing simple escape
// codes, this is IMO much easier to read than the ugly 80s coroutine code used
// by the original unvis(3) parser. Here's the EBNF for an unvis sequence:
//
// <input> ::= (<rune>)*
// <rune> ::= ("\" <escape-sequence>) | ("%" <escape-hex>) | <plain-rune>
// <plain-rune> ::= any rune
// <escape-sequence> ::= ("x" <escape-hex>) | ("M" <escape-meta>) | ("^" <escape-ctrl) | <escape-cstyle> | <escape-octal>
// <escape-meta> ::= ("-" <escape-meta1>) | ("^" <escape-ctrl>)
// <escape-meta1> ::= any rune
// <escape-ctrl> ::= "?" | any rune
// <escape-cstyle> ::= "\" | "n" | "r" | "b" | "a" | "v" | "t" | "f"
// <escape-hex> ::= [0-9a-f] [0-9a-f]
// <escape-octal> ::= [0-7] ([0-7] ([0-7])?)?
func unvisPlainRune(p *unvisParser) ([]byte, error) {
ch, err := p.Peek()
if err != nil {
return nil, fmt.Errorf("plain rune: %c", ch)
}
p.Next()
// XXX: Maybe we should not be converting to runes and then back to strings
// here. Are we sure that the byte-for-byte representation is the
// same? If the bytes change, then using these strings for paths will
// break...
str := string(ch)
return []byte(str), nil
}
func unvisEscapeCStyle(p *unvisParser) ([]byte, error) {
ch, err := p.Peek()
if err != nil {
return nil, fmt.Errorf("escape hex: %s", err)
}
output := ""
switch ch {
case 'n':
output = "\n"
case 'r':
output = "\r"
case 'b':
output = "\b"
case 'a':
output = "\x07"
case 'v':
output = "\v"
case 't':
output = "\t"
case 'f':
output = "\f"
case 's':
output = " "
case 'E':
output = "\x1b"
case '\n':
// Hidden newline.
case '$':
// Hidden marker.
default:
// XXX: We should probably allow falling through and return "\" here...
return nil, fmt.Errorf("escape cstyle: unknown escape character: %q", ch)
}
p.Next()
return []byte(output), nil
}
func unvisEscapeDigits(p *unvisParser, base int, force bool) ([]byte, error) {
var code int
for i := int(0xFF); i > 0; i /= base {
ch, err := p.Peek()
if err != nil {
if !force && i != 0xFF {
break
}
return nil, fmt.Errorf("escape base %d: %s", base, err)
}
digit, err := strconv.ParseInt(string(ch), base, 8)
if err != nil {
if !force && i != 0xFF {
break
}
return nil, fmt.Errorf("escape base %d: could not parse digit: %s", base, err)
}
code = (code * base) + int(digit)
p.Next()
}
if code > unicode.MaxLatin1 {
return nil, fmt.Errorf("escape base %d: code %q outside latin-1 encoding", base, code)
}
char := byte(code & 0xFF)
return []byte{char}, nil
}
func unvisEscapeCtrl(p *unvisParser, mask byte) ([]byte, error) {
ch, err := p.Peek()
if err != nil {
return nil, fmt.Errorf("escape ctrl: %s", err)
}
if ch > unicode.MaxLatin1 {
return nil, fmt.Errorf("escape ctrl: code %q outside latin-1 encoding", ch)
}
char := byte(ch) & 0x1f
if ch == '?' {
char = 0x7f
}
p.Next()
return []byte{mask | char}, nil
}
func unvisEscapeMeta(p *unvisParser) ([]byte, error) {
ch, err := p.Peek()
if err != nil {
return nil, fmt.Errorf("escape meta: %s", err)
}
mask := byte(0x80)
switch ch {
case '^':
// The same as "\^..." except we apply a mask.
p.Next()
return unvisEscapeCtrl(p, mask)
case '-':
p.Next()
ch, err := p.Peek()
if err != nil {
return nil, fmt.Errorf("escape meta1: %s", err)
}
if ch > unicode.MaxLatin1 {
return nil, fmt.Errorf("escape meta1: code %q outside latin-1 encoding", ch)
}
// Add mask to character.
p.Next()
return []byte{mask | byte(ch)}, nil
}
return nil, fmt.Errorf("escape meta: unknown escape char: %s", err)
}
func unvisEscapeSequence(p *unvisParser) ([]byte, error) {
ch, err := p.Peek()
if err != nil {
return nil, fmt.Errorf("escape sequence: %s", err)
}
switch ch {
case '\\':
p.Next()
return []byte("\\"), nil
case '0', '1', '2', '3', '4', '5', '6', '7':
return unvisEscapeDigits(p, 8, false)
case 'x':
p.Next()
return unvisEscapeDigits(p, 16, true)
case '^':
p.Next()
return unvisEscapeCtrl(p, 0x00)
case 'M':
p.Next()
return unvisEscapeMeta(p)
default:
return unvisEscapeCStyle(p)
}
}
func unvisRune(p *unvisParser) ([]byte, error) {
ch, err := p.Peek()
if err != nil {
return nil, fmt.Errorf("rune: %s", err)
}
switch ch {
case '\\':
p.Next()
return unvisEscapeSequence(p)
case '%':
// % HEX HEX only applies to HTTPStyle encodings.
if p.flag&VisHTTPStyle == VisHTTPStyle {
p.Next()
return unvisEscapeDigits(p, 16, true)
}
fallthrough
default:
return unvisPlainRune(p)
}
}
func unvis(p *unvisParser) (string, error) {
var output []byte
for !p.End() {
ch, err := unvisRune(p)
if err != nil {
return "", fmt.Errorf("input: %s", err)
}
output = append(output, ch...)
}
return string(output), nil
}
// Unvis takes a string formatted with the given Vis flags (though only the
// VisHTTPStyle flag is checked) and output the un-encoded version of the
// encoded string. An error is returned if any escape sequences in the input
// string were invalid.
func Unvis(input string, flag VisFlag) (string, error) {
// TODO: Check all of the VisFlag bits.
p := newParser(input, flag)
output, err := unvis(p)
if err != nil {
return "", fmt.Errorf("unvis: %s", err)
}
if !p.End() {
return "", fmt.Errorf("unvis: trailing characters at end of input")
}
return output, nil
}

166
pkg/govis/unvis_test.go Normal file
View File

@ -0,0 +1,166 @@
/*
* govis: unicode aware vis(3) encoding implementation
* Copyright (C) 2017 SUSE LLC.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package govis
import (
"testing"
)
func TestUnvisError(t *testing.T) {
for _, test := range []string{
// Octal escape codes allow you to specify invalid byte values.
"\\777",
"\\420\\322\\455",
"\\652\\233",
} {
got, err := Unvis(test, DefaultVisFlags)
if err == nil {
t.Errorf("expected unvis(%q) to give an error, got %q", test, got)
}
}
}
func TestUnvisCStyleEscape(t *testing.T) {
for _, test := range []struct {
input string
expected string
}{
{"", ""},
{"\\n\\v\\t\\s", "\n\v\t "},
{"\\\\n\\tt", "\\n\tt"},
{"\\b", "\b"},
{"\\r\\b\\n", "\r\b\n"},
{"\\a\\a\\b", "\x07\x07\b"},
{"\\f\\s\\E", "\f \x1b"},
// Hidden markers. They actually aren't generated by vis(3) but for
// some reason, they're supported...
{"test\\\ning", "testing"},
{"test\\$\\$ing", "testing"},
} {
got, err := Unvis(test.input, DefaultVisFlags)
if err != nil {
t.Errorf("unexpected error doing unvis(%q): %q", test.input, err)
continue
}
if got != test.expected {
t.Errorf("expected unvis(%q) = %q, got %q", test.input, test.expected, got)
}
}
}
func TestUnvisMetaEscape(t *testing.T) {
for _, test := range []struct {
input string
expected string
}{
{"", ""},
{"\\M^ ?\\^ ", "\x80?\x00"},
{"\\M- ?\\^?", "\xa0?\x7f"},
{"\\M-x butterfly\\M^?", "\xf8 butterfly\xff"},
{"\\M^X steady-hand \\^& needle", "\x98 steady-hand \x06 needle"},
// TODO: Add some more of these tests, but I need to have some
// secondary source to verify these outputs properly.
} {
got, err := Unvis(test.input, DefaultVisFlags)
if err != nil {
t.Errorf("unexpected error doing unvis(%q): %q", test.input, err)
continue
}
if got != test.expected {
t.Errorf("expected unvis(%q) = %q, got %q", test.input, test.expected, got)
}
}
}
func TestUnvisOctalEscape(t *testing.T) {
for _, test := range []struct {
input string
expected string
}{
{"", ""},
{"\\1", "\001"},
{"\\01\\02\\3", "\001\002\003"},
{"\\001\\023\\32", "\001\023\032"},
{"this is a test\\0k1\\133", "this is a test\000k1\133"},
{"\\170YET\\01another test\\1\\\\82", "\170YET\001another test\001\\82"},
{"\\177MORE tests\\09a", "\177MORE tests\x009a"},
{"\\\\710more\\1215testing", "\\710more\1215testing"},
// Make sure that decoding unicode works properly, when it's been encoded as single bytes.
{"\\360\\237\\225\\264", "\U0001f574"},
{"T\\303\\234B\\304\\260TAK_UEKAE_K\\303\\266k_Sertifika_Hizmet_Sa\\304\\237lay\\304\\261c\\304\\261s\\304\\261_-_S\\303\\274r\\303\\274m_3.pem", "TÜBİTAK_UEKAE_Kök_Sertifika_Hizmet_Sağlayıcısı_-_Sürüm_3.pem"},
// Some invalid characters...
{"\\377\\2\\225\\264", "\xff\x02\x95\xb4"},
} {
got, err := Unvis(test.input, DefaultVisFlags)
if err != nil {
t.Errorf("unexpected error doing unvis(%q): %q", test.input, err)
continue
}
if got != test.expected {
t.Errorf("expected unvis(%q) = %q, got %q", test.input, test.expected, got)
}
}
}
func TestUnvisHexEscape(t *testing.T) {
for _, test := range []struct {
input string
expected string
}{
{"", ""},
{"\\x01", "\x01"},
{"\\x01\\x02\\x7a", "\x01\x02\x7a"},
{"this is a test\\x13\\x52\\x6f", "this is a test\x13\x52\x6f"},
{"\\x170YET\\x01a\\x22nother test\\x11", "\x170YET\x01a\x22nother test\x11"},
{"\\\\x007more\\\\x215testing", "\\x007more\\x215testing"},
// Make sure that decoding unicode works properly, when it's been encoded as single bytes.
{"\\xf0\\x9f\\x95\\xb4", "\U0001f574"},
{"T\\xc3\\x9cB\\xc4\\xb0TAK_UEKAE_K\\xc3\\xb6k_Sertifika_Hizmet_Sa\\xc4\\x9flay\\xc4\\xb1c\\xc4\\xb1s\\xc4\\xb1_-_S\\xc3\\xbcr\\xc3\\xbcm_3.pem", "TÜBİTAK_UEKAE_Kök_Sertifika_Hizmet_Sağlayıcısı_-_Sürüm_3.pem"},
// Some invalid characters...
{"\\xff\\x02\\x95\\xb4", "\xff\x02\x95\xb4"},
} {
got, err := Unvis(test.input, DefaultVisFlags)
if err != nil {
t.Errorf("unexpected error doing unvis(%q): %q", test.input, err)
continue
}
if got != test.expected {
t.Errorf("expected unvis(%q) = %q, got %q", test.input, test.expected, got)
}
}
}
func TestUnvisUnicode(t *testing.T) {
// Ensure that unicode strings are not messed up by Unvis.
for _, test := range []string{
"",
"this.is.a.normal_string",
"AC_Raíz_Certicámara_S.A..pem",
"NetLock_Arany_=Class_Gold=_Főtanúsítvány.pem",
"TÜBİTAK_UEKAE_Kök_Sertifika_Hizmet_Sağlayıcısı_-_Sürüm_3.pem",
} {
got, err := Unvis(test, DefaultVisFlags)
if err != nil {
t.Errorf("unexpected error doing unvis(%q): %s", test, err)
continue
}
if got != test {
t.Errorf("expected %q to be unchanged, got %q", test, got)
}
}
}

177
pkg/govis/vis.go Normal file
View File

@ -0,0 +1,177 @@
/*
* govis: unicode aware vis(3) encoding implementation
* Copyright (C) 2017 SUSE LLC.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package govis
import (
"fmt"
"unicode"
)
func isunsafe(ch rune) bool {
return ch == '\b' || ch == '\007' || ch == '\r'
}
func isglob(ch rune) bool {
return ch == '*' || ch == '?' || ch == '[' || ch == '#'
}
// ishttp is defined by RFC 1808.
func ishttp(ch rune) bool {
// RFC1808 does not really consider characters outside of ASCII, so just to
// be safe always treat characters outside the ASCII character set as "not
// HTTP".
if ch > unicode.MaxASCII {
return false
}
return unicode.IsDigit(ch) || unicode.IsLetter(ch) ||
// Safe characters.
ch == '$' || ch == '-' || ch == '_' || ch == '.' || ch == '+' ||
// Extra characters.
ch == '!' || ch == '*' || ch == '\'' || ch == '(' ||
ch == ')' || ch == ','
}
func isgraph(ch rune) bool {
return unicode.IsGraphic(ch) && !unicode.IsSpace(ch) && ch <= unicode.MaxASCII
}
// vis converts a single *byte* into its encoding. While Go supports the
// concept of runes (and thus native utf-8 parsing), in order to make sure that
// the bit-stream will be completely maintained through an Unvis(Vis(...))
// round-trip. The downside is that Vis() will never output unicode -- but on
// the plus side this is actually a benefit on the encoding side (it will
// always work with the simple unvis(3) implementation). It also means that we
// don't have to worry about different multi-byte encodings.
func vis(b byte, flag VisFlag) (string, error) {
// Treat the single-byte character as a rune.
ch := rune(b)
// XXX: This is quite a horrible thing to support.
if flag&VisHTTPStyle == VisHTTPStyle {
if !ishttp(ch) {
return "%" + fmt.Sprintf("%.2X", ch), nil
}
}
// Figure out if the character doesn't need to be encoded. Effectively, we
// encode most "normal" (graphical) characters as themselves unless we have
// been specifically asked not to. Note though that we *ALWAYS* encode
// everything outside ASCII.
// TODO: Switch this to much more logical code.
if ch > unicode.MaxASCII {
/* ... */
} else if flag&VisGlob == VisGlob && isglob(ch) {
/* ... */
} else if isgraph(ch) ||
(flag&VisSpace != VisSpace && ch == ' ') ||
(flag&VisTab != VisTab && ch == '\t') ||
(flag&VisNewline != VisNewline && ch == '\n') ||
(flag&VisSafe != 0 && isunsafe(ch)) {
encoded := string(ch)
if ch == '\\' && flag&VisNoSlash == 0 {
encoded += "\\"
}
return encoded, nil
}
// Try to use C-style escapes first.
if flag&VisCStyle == VisCStyle {
switch ch {
case ' ':
return "\\s", nil
case '\n':
return "\\n", nil
case '\r':
return "\\r", nil
case '\b':
return "\\b", nil
case '\a':
return "\\a", nil
case '\v':
return "\\v", nil
case '\t':
return "\\t", nil
case '\f':
return "\\f", nil
case '\x00':
// Output octal just to be safe.
return "\\000", nil
}
}
// For graphical characters we generate octal output (and also if it's
// being forced by the caller's flags). Also spaces should always be
// encoded as octal.
if flag&VisOctal == VisOctal || isgraph(ch) || ch&0x7f == ' ' {
// Always output three-character octal just to be safe.
return fmt.Sprintf("\\%.3o", ch), nil
}
// Now we have to output meta or ctrl escapes. As far as I can tell, this
// is not actually defined by any standard -- so this logic is basically
// copied from the original vis(3) implementation. Hopefully nobody
// actually relies on this (octal and hex are better).
encoded := ""
if flag&VisNoSlash == 0 {
encoded += "\\"
}
// Meta characters have 0x80 set, but are otherwise identical to control
// characters.
if b&0x80 != 0 {
b &= 0x7f
encoded += "M"
}
if unicode.IsControl(rune(b)) {
encoded += "^"
if b == 0x7f {
encoded += "?"
} else {
encoded += fmt.Sprintf("%c", b+'@')
}
} else {
encoded += fmt.Sprintf("-%c", b)
}
return encoded, nil
}
// Vis encodes the provided string to a BSD-compatible encoding using BSD's
// vis() flags. However, it will correctly handle multi-byte encoding (which is
// not done properly by BSD's vis implementation).
func Vis(src string, flag VisFlag) (string, error) {
if flag&visMask != flag {
return "", fmt.Errorf("vis: flag %q contains unknown or unsupported flags", flag)
}
output := ""
for _, ch := range []byte(src) {
encodedCh, err := vis(ch, flag)
if err != nil {
return "", err
}
output += encodedCh
}
return output, nil
}

127
pkg/govis/vis_test.go Normal file
View File

@ -0,0 +1,127 @@
/*
* govis: unicode aware vis(3) encoding implementation
* Copyright (C) 2017 SUSE LLC.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package govis
import (
"testing"
)
func TestVisUnchanged(t *testing.T) {
for _, test := range []struct {
input string
flag VisFlag
}{
{"", DefaultVisFlags},
{"helloworld", DefaultVisFlags},
{"THIS_IS_A_TEST1234", DefaultVisFlags},
{"SomeEncodingsAreCool", DefaultVisFlags},
{"spaces are totally safe", DefaultVisFlags &^ VisSpace},
{"tabs\tare\talso\tsafe!!", DefaultVisFlags &^ VisTab},
{"just\a\atrustme\r\b\b!!", DefaultVisFlags | VisSafe},
} {
enc, err := Vis(test.input, test.flag)
if err != nil {
t.Errorf("unexpected error with %q: %s", test, err)
}
if enc != test.input {
t.Errorf("expected encoding of %q (flag=%q) to be unchanged, got %q", test.input, test.flag, enc)
}
}
}
func TestVisFlags(t *testing.T) {
for _, test := range []struct {
input string
output string
flag VisFlag
}{
// Default
{"AC_Ra\u00edz_Certic\u00e1mara_S.A..pem", "AC_Ra\\M-C\\M--z_Certic\\M-C\\M-!mara_S.A..pem", 0},
{"z^i3i$\u00d3\u008anqgh5/t\u00e5<86>\u00b2kzla\\e^lv\u00df\u0093nv\u00df\u00aea|3}\u00d8\u0088\u00d6\u0084", `z^i3i$\M-C\M^S\M-B\M^Jnqgh5/t\M-C\M-%<86>\M-B\M-2kzla\\e^lv\M-C\M^_\M-B\M^Snv\M-C\M^_\M-B\M-.a|3}\M-C\M^X\M-B\M^H\M-C\M^V\M-B\M^D`, 0},
{"@?e1xs+.R_Kjo]7s8pgRP:*nXCE4{!c", "@?e1xs+.R_Kjo]7s8pgRP:*nXCE4{!c", 0},
{"62_\u00c6\u00c62\u00ae\u00b7m\u00db\u00c3r^\u00bfp\u00c6u'q\u00fbc2\u00f0u\u00b8\u00dd\u00e8v\u00ff\u00b0\u00dc\u00c2\u00f53\u00db-k\u00f2sd4\\p\u00da\u00a6\u00d3\u00eea<\u00e6s{\u00a0p\u00f0\u00ffj\u00e0\u00e8\u00b8\u00b8\u00bc\u00fcb", `62_\M-C\M^F\M-C\M^F2\M-B\M-.\M-B\M-7m\M-C\M^[\M-C\M^Cr^\M-B\M-?p\M-C\M^Fu'q\M-C\M-;c2\M-C\M-0u\M-B\M-8\M-C\M^]\M-C\M-(v\M-C\M-?\M-B\M-0\M-C\M^\\M-C\M^B\M-C\M-53\M-C\M^[-k\M-C\M-2sd4\\p\M-C\M^Z\M-B\M-&\M-C\M^S\M-C\M-.a<\M-C\M-&s{\M-B\240p\M-C\M-0\M-C\M-?j\M-C\240\M-C\M-(\M-B\M-8\M-B\M-8\M-B\M-<\M-C\M-<b`, 0},
{"\u9003\"9v1)T798|o;fly jnKX\u0489Be=", `\M-i\M^@\M^C"9v1)T798|o;fly jnKX\M-R\M^IBe=`, 0},
// VisOctal
{"", "", VisOctal},
{"\022", "\\022", VisOctal},
{"\n \t", "\\012\\040\t", VisNewline | VisSpace | VisOctal},
{"\x12\f\a\n\v\b \U00012312", "\\022\\014\\007\n\\013\\010 \\360\\222\\214\\222", VisOctal},
{"AC_Ra\u00edz_Certic\u00e1mara_S.A..pem", "AC_Ra\\303\\255z_Certic\\303\\241mara_S.A..pem", VisOctal},
{"z^i3i$\u00d3\u008anqgh5/t\u00e5<86>\u00b2kzla\\e^lv\u00df\u0093nv\u00df\u00aea|3}\u00d8\u0088\u00d6\u0084", `z^i3i$\303\223\302\212nqgh5/t\303\245<86>\302\262kzla\\e^lv\303\237\302\223nv\303\237\302\256a|3}\303\230\302\210\303\226\302\204`, VisOctal},
{"62_\u00c6\u00c62\u00ae\u00b7m\u00db\u00c3r^\u00bfp\u00c6u'q\u00fbc2\u00f0u\u00b8\u00dd\u00e8v\u00ff\u00b0\u00dc\u00c2\u00f53\u00db-k\u00f2sd4\\p\u00da\u00a6\u00d3\u00eea<\u00e6s{\u00a0p\u00f0\u00ffj\u00e0\u00e8\u00b8\u00b8\u00bc\u00fcb", `62_\303\206\303\2062\302\256\302\267m\303\233\303\203r^\302\277p\303\206u'q\303\273c2\303\260u\302\270\303\235\303\250v\303\277\302\260\303\234\303\202\303\2653\303\233-k\303\262sd4\\p\303\232\302\246\303\223\303\256a<\303\246s{\302\240p\303\260\303\277j\303\240\303\250\302\270\302\270\302\274\303\274b`, VisOctal},
{"\u9003\"9v1)T798|o;fly jnKX\u0489Be=", `\351\200\203"9v1)T798|o;fly jnKX\322\211Be=`, VisOctal},
// VisCStyle
{"\x00 \f \a \n\v\b \r \t\r", "\\000 \\f \\a \n\\v\\b \\r \t\\r", VisCStyle},
{"\t \n\v\b", "\\t \n\\v\\b", VisTab | VisCStyle},
{"\n\v\t ", "\n\\v\t\\s\\s\\s", VisSpace | VisCStyle},
{"\n \n ", "\\n \\n ", VisNewline | VisCStyle},
{"z^i3i$\u00d3\u008anqgh5/t\u00e5<86>\u00b2kzla\\e^lv\u00df\u0093nv\u00df\u00aea|3}\u00d8\u0088\u00d6\u0084", `z^i3i$\M-C\M^S\M-B\M^Jnqgh5/t\M-C\M-%<86>\M-B\M-2kzla\\e^lv\M-C\M^_\M-B\M^Snv\M-C\M^_\M-B\M-.a|3}\M-C\M^X\M-B\M^H\M-C\M^V\M-B\M^D`, VisCStyle},
{"62_\u00c6\u00c62\u00ae\u00b7m\u00db\u00c3r^\u00bfp\u00c6u'q\u00fbc2\u00f0u\u00b8\u00dd\u00e8v\u00ff\u00b0\u00dc\u00c2\u00f53\u00db-k\u00f2sd4\\p\u00da\u00a6\u00d3\u00eea<\u00e6s{\u00a0p\u00f0\u00ffj\u00e0\u00e8\u00b8\u00b8\u00bc\u00fcb", `62_\M-C\M^F\M-C\M^F2\M-B\M-.\M-B\M-7m\M-C\M^[\M-C\M^Cr^\M-B\M-?p\M-C\M^Fu'q\M-C\M-;c2\M-C\M-0u\M-B\M-8\M-C\M^]\M-C\M-(v\M-C\M-?\M-B\M-0\M-C\M^\\M-C\M^B\M-C\M-53\M-C\M^[-k\M-C\M-2sd4\\p\M-C\M^Z\M-B\M-&\M-C\M^S\M-C\M-.a<\M-C\M-&s{\M-B\240p\M-C\M-0\M-C\M-?j\M-C\240\M-C\M-(\M-B\M-8\M-B\M-8\M-B\M-<\M-C\M-<b`, VisCStyle},
{"\u9003\"9v1)T798|o;fly jnKX\u0489Be=", `\M-i\M^@\M^C"9v1)T798|o;fly\sjnKX\M-R\M^IBe=`, VisCStyle | VisSpace},
// VisSpace
{" ", `\040\040`, VisSpace},
{"\t \t", "\t\\040\t", VisSpace},
{"\\040 plenty of characters here ", `\\040\040\040\040plenty\040of\040characters\040here\040\040\040`, VisSpace},
{"Js9L\u00cd\u00b2o?4824y'$|P}FIr%mW /KL9$]~", `Js9L\M-C\M^M\M-B\M-2o?4824y'$|P}FIr%mW\040/KL9$]~`, VisWhite},
{"1\u00c6\u00abTcz+Vda?)k1%\\\"P;`po`h", `1\M-C\M^F\M-B\M-+Tcz+Vda?)k1%\\"P;` + "`po`" + `h`, VisWhite},
{"\u9003\"9v1)T798|o;fly jnKX\u0489Be=", `\M-i\M^@\M^C"9v1)T798|o;fly\040jnKX\M-R\M^IBe=`, VisSpace},
// VisTab
{"\t \v", "\\^I \\^K", VisTab},
{"\t \v", "\\011 \\013", VisTab | VisOctal},
// VisNewline
{"\t\n \v\r\n", "\t\\^J \\^K\\^M\\^J", VisNewline},
{"\t\n \v\r\n", "\t\\012 \\013\\015\\012", VisNewline | VisOctal},
// VisSafe
// VisHTTPStyle
{"\x12\f\a\n\v\b \U00012312", `%12%0C%07%0A%0B%08%20%20%F0%92%8C%92`, VisHTTPStyle},
{"1\u00c6\u00abTcz+Vda?)k1%\\\"P;`po`h", `1%C3%86%C2%ABTcz+Vda%3F)k1%25%5C%22P%3B%60po%60h`, VisHTTPStyle},
{"62_\u00c6\u00c62\u00ae\u00b7m\u00db\u00c3r^\u00bfp\u00c6u'q\u00fbc2\u00f0u\u00b8\u00dd\u00e8v\u00ff\u00b0\u00dc\u00c2\u00f53\u00db-k\u00f2sd4\\p\u00da\u00a6\u00d3\u00eea<\u00e6s{\u00a0p\u00f0\u00ffj\u00e0\u00e8\u00b8\u00b8\u00bc\u00fcb", `62_%C3%86%C3%862%C2%AE%C2%B7m%C3%9B%C3%83r%5E%C2%BFp%C3%86u'q%C3%BBc2%C3%B0u%C2%B8%C3%9D%C3%A8v%C3%BF%C2%B0%C3%9C%C3%82%C3%B53%C3%9B-k%C3%B2sd4%5Cp%C3%9A%C2%A6%C3%93%C3%AEa%3C%C3%A6s%7B%C2%A0p%C3%B0%C3%BFj%C3%A0%C3%A8%C2%B8%C2%B8%C2%BC%C3%BCb`, VisHTTPStyle},
{"'3Ze\u050e|\u02del\u069du-Rpct4+Z5b={@_{b", `'3Ze%D4%8E%7C%CB%9El%DA%9Du-Rpct4+Z5b%3D%7B%40_%7Bb`, VisHTTPStyle},
// VisGlob
{"cat /proc/**/status | grep '[pid]' ;; # cool code here", `cat /proc/\052\052/status | grep '\133pid]' ;; \043 cool code here`, VisGlob},
{"@?e1xs+.R_Kjo]7s8pgRP:*nXCE4{!c", `@\077e1xs+.R_Kjo]7s8pgRP:\052nXCE4{!c`, VisGlob},
{"62_\u00c6\u00c62\u00ae\u00b7m\u00db\u00c3r^\u00bfp\u00c6u'q\u00fbc2\u00f0u\u00b8\u00dd\u00e8v\u00ff\u00b0\u00dc\u00c2\u00f53\u00db-k\u00f2sd4\\p\u00da\u00a6\u00d3\u00eea<\u00e6s{\u00a0p\u00f0\u00ffj\u00e0\u00e8\u00b8\u00b8\u00bc\u00fcb", `62_\M-C\M^F\M-C\M^F2\M-B\M-.\M-B\M-7m\M-C\M^[\M-C\M^Cr^\M-B\M-?p\M-C\M^Fu'q\M-C\M-;c2\M-C\M-0u\M-B\M-8\M-C\M^]\M-C\M-(v\M-C\M-?\M-B\M-0\M-C\M^\\M-C\M^B\M-C\M-53\M-C\M^[-k\M-C\M-2sd4\\p\M-C\M^Z\M-B\M-&\M-C\M^S\M-C\M-.a<\M-C\M-&s{\M-B\240p\M-C\M-0\M-C\M-?j\M-C\240\M-C\M-(\M-B\M-8\M-B\M-8\M-B\M-<\M-C\M-<b`, VisGlob},
{"62_\u00c6\u00c62\u00ae\u00b7m\u00db\u00c3r^\u00bfp\u00c6u'q\u00fbc2\u00f0u\u00b8\u00dd\u00e8v\u00ff\u00b0\u00dc\u00c2\u00f53\u00db-k\u00f2sd4\\p\u00da\u00a6\u00d3\u00eea<\u00e6s{\u00a0p\u00f0\u00ffj\u00e0\u00e8\u00b8\u00b8\u00bc\u00fcb", `62_\303\206\303\2062\302\256\302\267m\303\233\303\203r^\302\277p\303\206u'q\303\273c2\303\260u\302\270\303\235\303\250v\303\277\302\260\303\234\303\202\303\2653\303\233-k\303\262sd4\\p\303\232\302\246\303\223\303\256a<\303\246s{\302\240p\303\260\303\277j\303\240\303\250\302\270\302\270\302\274\303\274b`, VisGlob | VisOctal},
{"'3Ze\u050e|\u02del\u069du-Rpct4+Z5b={@_{b", `'3Ze\M-T\M^N|\M-K\M^^l\M-Z\M^]u-Rpct4+Z5b={@_{b`, VisGlob},
{"'3Ze\u050e|\u02del\u069du-Rpct4+Z5b={@_{b", `'3Ze\324\216|\313\236l\332\235u-Rpct4+Z5b={@_{b`, VisGlob | VisOctal},
} {
enc, err := Vis(test.input, test.flag)
if err != nil {
t.Errorf("unexpected error with %q: %s", test, err)
}
if enc != test.output {
t.Errorf("expected vis(%q, flag=%b) = %q, got %q", test.input, test.flag, test.output, enc)
}
}
}
func TestVisChanged(t *testing.T) {
for _, test := range []string{
"hello world",
"THIS\\IS_A_TEST1234",
"AC_Ra\u00edz_Certic\u00e1mara_S.A..pem",
} {
enc, err := Vis(test, DefaultVisFlags)
if err != nil {
t.Errorf("unexpected error with %q: %s", test, err)
}
if enc == test {
t.Errorf("expected encoding of %q to be changed", test)
}
}
}

11
releases.md Normal file
View File

@ -0,0 +1,11 @@
# How to do releases:
* Create a changeset with an update to `version.go`
- this commit will be tagged
- add another commit putting it back with '-dev' appended
* gpg sign the commit with an incremented version, like 'vX.Y.Z'
* Push the tag
* Create a "release" from the tag on github
- include the binaries from `make build.arches`
- write about notable changes, and their contributors
- PRs merged for the release

18
stat_unix.go Normal file
View File

@ -0,0 +1,18 @@
// +build !windows
package mtree
import (
"os"
"syscall"
)
func statIsUID(stat os.FileInfo, uid int) bool {
statT := stat.Sys().(*syscall.Stat_t)
return statT.Uid == uint32(uid)
}
func statIsGID(stat os.FileInfo, gid int) bool {
statT := stat.Sys().(*syscall.Stat_t)
return statT.Gid == uint32(gid)
}

12
stat_windows.go Normal file
View File

@ -0,0 +1,12 @@
// +build windows
package mtree
import "os"
func statIsUID(stat os.FileInfo, uid int) bool {
return false
}
func statIsGID(stat os.FileInfo, uid int) bool {
return false
}

44
tar.go
View File

@ -5,10 +5,12 @@ import (
"fmt"
"io"
"io/ioutil"
"log"
"os"
"path/filepath"
"strings"
"github.com/sirupsen/logrus"
"github.com/vbatts/go-mtree/pkg/govis"
)
// Streamer creates a file hierarchy out of a tar stream
@ -128,7 +130,7 @@ hdrloop:
return
}
// Alright, it's either file or directory
encodedName, err := Vis(filepath.Base(hdr.Name), DefaultVisFlags)
encodedName, err := govis.Vis(filepath.Base(hdr.Name), DefaultVisFlags)
if err != nil {
tmpFile.Close()
os.Remove(tmpFile.Name())
@ -142,16 +144,16 @@ hdrloop:
// Keep track of which files are hardlinks so we can resolve them later
if hdr.Typeflag == tar.TypeLink {
linkFunc := KeywordFuncs["link"]
kv, err := linkFunc(hdr.Name, hdr.FileInfo(), nil)
keyFunc := KeywordFuncs["link"]
kvs, err := keyFunc(hdr.Name, hdr.FileInfo(), nil)
if err != nil {
log.Println(err)
break
logrus.Warn(err)
break // XXX is breaking an okay thing to do here?
}
linkname, err := Unvis(KeyVal(kv).Value())
linkname, err := govis.Unvis(KeyVal(kvs[0]).Value(), DefaultVisFlags)
if err != nil {
log.Println(err)
break
logrus.Warn(err)
break // XXX is breaking an okay thing to do here?
}
if _, ok := ts.hardlinks[linkname]; !ok {
ts.hardlinks[linkname] = []string{hdr.Name}
@ -162,19 +164,19 @@ hdrloop:
// now collect keywords on the file
for _, keyword := range ts.keywords {
if keyFunc, ok := KeywordFuncs[keyword]; ok {
if keyFunc, ok := KeywordFuncs[keyword.Prefix()]; ok {
// We can't extract directories on to disk, so "size" keyword
// is irrelevant for now
if hdr.FileInfo().IsDir() && keyword == "size" {
continue
}
val, err := keyFunc(hdr.Name, hdr.FileInfo(), tmpFile)
kvs, err := keyFunc(hdr.Name, hdr.FileInfo(), tmpFile)
if err != nil {
ts.setErr(err)
}
// for good measure, check that we actually get a value for a keyword
if val != "" {
e.Keywords = append(e.Keywords, val)
if len(kvs) > 0 && kvs[0] != "" {
e.Keywords = append(e.Keywords, kvs[0])
}
// don't forget to reset the reader
@ -194,13 +196,15 @@ hdrloop:
Type: SpecialType,
}
for _, setKW := range SetKeywords {
if keyFunc, ok := KeywordFuncs[setKW]; ok {
val, err := keyFunc(hdr.Name, hdr.FileInfo(), tmpFile)
if keyFunc, ok := KeywordFuncs[setKW.Prefix()]; ok {
kvs, err := keyFunc(hdr.Name, hdr.FileInfo(), tmpFile)
if err != nil {
ts.setErr(err)
}
if val != "" {
s.Keywords = append(s.Keywords, val)
for _, kv := range kvs {
if kv != "" {
s.Keywords = append(s.Keywords, kv)
}
}
if _, err := tmpFile.Seek(0, 0); err != nil {
tmpFile.Close()
@ -248,7 +252,7 @@ func populateTree(root, e *Entry, hdr *tar.Header) error {
dirNames := strings.Split(wd, "/")
parent := root
for _, name := range dirNames[:] {
encoded, err := Vis(name, DefaultVisFlags)
encoded, err := govis.Vis(name, DefaultVisFlags)
if err != nil {
return err
}
@ -381,7 +385,7 @@ func resolveHardlinks(root *Entry, hardlinks map[string][]string, countlinks boo
if seen, ok := originals[base]; !ok {
basefile = root.Find(base)
if basefile == nil {
log.Printf("%s does not exist in this tree\n", base)
logrus.Printf("%s does not exist in this tree\n", base)
continue
}
originals[base] = basefile
@ -391,7 +395,7 @@ func resolveHardlinks(root *Entry, hardlinks map[string][]string, countlinks boo
for _, link := range links {
linkfile := root.Find(link)
if linkfile == nil {
log.Printf("%s does not exist in this tree\n", link)
logrus.Printf("%s does not exist in this tree\n", link)
continue
}
linkfile.Keywords = basefile.Keywords

View File

@ -6,6 +6,7 @@ import (
"io"
"io/ioutil"
"os"
"path/filepath"
"syscall"
"testing"
"time"
@ -78,11 +79,16 @@ func TestTar(t *testing.T) {
t.Fatal("expected a DirectoryHierarchy struct, but got nil")
}
fh, err = os.Create("./testdata/test.mtree")
testDir, present := os.LookupEnv("MTREE_TESTDIR")
if present == false {
testDir = "."
}
testPath := filepath.Join(testDir, "test.mtree")
fh, err = os.Create(testPath)
if err != nil {
t.Fatal(err)
}
defer os.Remove("./testdata/test.mtree")
defer os.Remove(testPath)
// put output of tar walk into test.mtree
_, err = tdh.WriteTo(fh)
@ -92,7 +98,7 @@ func TestTar(t *testing.T) {
fh.Close()
// now simulate gomtree -T testdata/test.tar -f testdata/test.mtree
fh, err = os.Open("./testdata/test.mtree")
fh, err = os.Open(testPath)
if err != nil {
t.Fatal(err)
}
@ -103,7 +109,7 @@ func TestTar(t *testing.T) {
t.Fatal(err)
}
res, err := TarCheck(tdh, dh, append(DefaultKeywords, "sha1"))
res, err := Compare(tdh, dh, append(DefaultKeywords, "sha1"))
if err != nil {
t.Fatal(err)
}
@ -158,7 +164,7 @@ func TestArchiveCreation(t *testing.T) {
}
// Test the tar manifest against itself
res, err = TarCheck(tdh, tdh, []Keyword{"sha1"})
res, err = Compare(tdh, tdh, []Keyword{"sha1"})
if err != nil {
t.Fatal(err)
}
@ -174,7 +180,7 @@ func TestArchiveCreation(t *testing.T) {
if err != nil {
t.Fatal(err)
}
res, err = TarCheck(tdh, dh, []Keyword{"sha1"})
res, err = Compare(tdh, dh, []Keyword{"sha1"})
if err != nil {
t.Fatal(err)
}
@ -212,7 +218,7 @@ func TestTreeTraversal(t *testing.T) {
t.Fatal(err)
}
res, err := TarCheck(tdh, tdh, []Keyword{"sha1"})
res, err := Compare(tdh, tdh, []Keyword{"sha1"})
if err != nil {
t.Fatal(err)
}

View File

@ -1,3 +1,5 @@
// +build ignore
package main
import (
@ -5,10 +7,14 @@ import (
"fmt"
"os"
"os/exec"
"github.com/fatih/color"
)
func main() {
flag.Parse()
green := color.New(color.FgGreen).SprintFunc()
red := color.New(color.FgRed).SprintFunc()
failed := 0
for _, arg := range flag.Args() {
@ -20,11 +26,12 @@ func main() {
cmd.Stdout = os.Stdout
if err := cmd.Run(); err != nil {
failed++
fmt.Fprintf(os.Stderr, "FAILED: %s\n", arg)
fmt.Fprintf(os.Stderr, red("FAILED: %s\n"), arg)
}
}
if failed > 0 {
fmt.Fprintf(os.Stderr, "%d FAILED tests\n", failed)
fmt.Fprintf(os.Stderr, red("%d FAILED tests\n"), failed)
os.Exit(1)
}
fmt.Fprintf(os.Stdout, green("SUCCESS: no cli tests failed\n"))
}

View File

@ -3,8 +3,8 @@ set -e
name=$(basename $0)
root="$(dirname $(dirname $(dirname $0)))"
gomtree=$(readlink -f ${root}/gomtree)
t=$(mktemp -t -d go-mtree.XXXXXX)
gomtree=$(go run ${root}/test/realpath.go ${root}/gomtree)
t=$(mktemp -d -t go-mtree.XXXXXX)
echo "[${name}] Running in ${t}"
# This test is for basic running check of manifest, and check against tar and file system
@ -12,33 +12,33 @@ echo "[${name}] Running in ${t}"
pushd ${root}
git archive --format=tar HEAD^{tree} . > ${t}/${name}.tar
git archive --format=tar -o "${t}/${name}.tar" HEAD^{tree}
prev_umask=$(umask)
umask 0 # this is so the tar command can set the mode's properly
mkdir -p ${t}/extract
tar -C ${t}/extract/ -xf ${t}/${name}.tar
tar -C ${t}/extract/ -xf "${t}/${name}.tar"
umask ${prev_umask}
# create manifest from tar
${gomtree} -K sha256digest -c -T ${t}/${name}.tar > ${t}/${name}.mtree
${gomtree} -K sha256digest -c -T "${t}/${name}.tar" > "${t}/${name}.mtree"
# check tar-manifest against the tar
${gomtree} -f ${t}/${name}.mtree -T ${t}/${name}.tar
${gomtree} -f ${t}/${name}.mtree -T "${t}/${name}.tar"
# check tar-manifest against the filesystem
# git archive makes the uid/gid as 0, so don't check them for this test
${gomtree} -k size,sha256digest,mode,type -f ${t}/${name}.mtree -p ${t}/extract/
${gomtree} -k size,sha256digest,mode,type -f "${t}/${name}.mtree" -p ${t}/extract/
# create a manifest from filesystem
${gomtree} -K sha256digest -c -p ${t}/extract/ > ${t}/${name}.mtree
${gomtree} -K sha256digest -c -p "${t}/extract/" > "${t}/${name}.mtree"
# check filesystem-manifest against the filesystem
${gomtree} -f ${t}/${name}.mtree -p ${t}/extract/
${gomtree} -f "${t}/${name}.mtree" -p "${t}/extract/"
# check filesystem-manifest against the tar
# git archive makes the uid/gid as 0, so don't check them for this test
${gomtree} -k size,sha256digest,mode,type -f ${t}/${name}.mtree -T ${t}/${name}.tar
${gomtree} -k size,sha256digest,mode,type -f "${t}/${name}.mtree" -T "${t}/${name}.tar"
popd
rm -rf ${t}

View File

@ -3,8 +3,8 @@ set -e
name=$(basename $0)
root="$(dirname $(dirname $(dirname $0)))"
gomtree=$(readlink -f ${root}/gomtree)
t=$(mktemp -t -d go-mtree.XXXXXX)
gomtree=$(go run ${root}/test/realpath.go ${root}/gomtree)
t=$(mktemp -d -t go-mtree.XXXXXX)
echo "[${name}] Running in ${t}"
# This test is for basic running check of manifest, and check against tar and file system

View File

@ -3,10 +3,10 @@ set -e
name=$(basename $0)
root="$(dirname $(dirname $(dirname $0)))"
gomtree=$(readlink -f ${root}/gomtree)
t=$(mktemp -t -d go-mtree.XXXXXX)
gomtree=$(go run ${root}/test/realpath.go ${root}/gomtree)
t=$(mktemp -d -t go-mtree.XXXXXX)
setfattr -n user.has.xattrs -v "true" "${t}" || exit 0
setfattr -n user.has.xattrs -v "true" "${t}" || exit 0
echo "[${name}] Running in ${t}"

View File

@ -4,8 +4,8 @@ set -e
name=$(basename $0)
root="$(dirname $(dirname $(dirname $0)))"
gomtree=$(readlink -f ${root}/gomtree)
t=$(mktemp -t -d go-mtree.XXXXXX)
gomtree=$(go run ${root}/test/realpath.go ${root}/gomtree)
t=$(mktemp -d -t go-mtree.XXXXXX)
echo "[${name}] Running in ${t}"

View File

@ -3,8 +3,8 @@ set -e
name=$(basename $0)
root="$(dirname $(dirname $(dirname $0)))"
gomtree=$(readlink -f ${root}/gomtree)
t=$(mktemp -t -d go-mtree.XXXXXX)
gomtree=$(go run ${root}/test/realpath.go ${root}/gomtree)
t=$(mktemp -d -t go-mtree.XXXXXX)
echo "[${name}] Running in ${t}"

View File

@ -3,8 +3,8 @@ set -e
name=$(basename $0)
root="$(dirname $(dirname $(dirname $0)))"
gomtree=$(readlink -f ${root}/gomtree)
t=$(mktemp -t -d go-mtree.XXXXXX)
gomtree=$(go run ${root}/test/realpath.go ${root}/gomtree)
t=$(mktemp -d -t go-mtree.XXXXXX)
echo "[${name}] Running in ${t}"
# This test is for basic running check of manifest, and check against tar and file system

View File

@ -3,9 +3,9 @@ set -e
name=$(basename $0)
root="$(dirname $(dirname $(dirname $0)))"
gomtree=$(readlink -f ${root}/gomtree)
left=$(mktemp -t -d go-mtree.XXXXXX)
right=$(mktemp -t -d go-mtree.XXXXXX)
gomtree=$(go run ${root}/test/realpath.go ${root}/gomtree)
left=$(mktemp -d -t go-mtree.XXXXXX)
right=$(mktemp -d -t go-mtree.XXXXXX)
echo "[${name}] Running in ${left} and ${right}"

22
test/cli/0008.sh Normal file
View File

@ -0,0 +1,22 @@
#!/bin/bash
set -e
name=$(basename $0)
root="$(dirname $(dirname $(dirname $0)))"
gomtree=$(go run ${root}/test/realpath.go ${root}/gomtree)
t=$(mktemp -d /tmp/go-mtree.XXXXXX)
echo "[${name}] Running in ${t}"
pushd ${root}
mkdir -p ${t}/extract
git archive --format=tar HEAD^{tree} . | tar -C ${t}/extract/ -x
${gomtree} -K sha256digest -c -p ${t}/extract/ > ${t}/${name}.mtree
## This is a use-case for checking a directory, but by reading the manifest from stdin
## since the `-f` flag is not provided.
cat ${t}/${name}.mtree | ${gomtree} -p ${t}/extract/
popd
rm -rf ${t}

33
test/cli/0009.sh Normal file
View File

@ -0,0 +1,33 @@
#!/bin/bash
set -e
name=$(basename $0)
root="$(dirname $(dirname $(dirname $0)))"
gomtree=$(go run ${root}/test/realpath.go ${root}/gomtree)
t=$(mktemp -d -t go-mtree.XXXXXX)
echo "[${name}] Running in ${t}"
pushd ${root}
# Create some unicode files.
mkdir ${t}/root
echo "some data" > "${t}/root/$(printf 'this file has \u042a some unicode !!')"
echo "more data" > "${t}/root/$(printf 'even more \x07 unicode \ua4ff characters \udead\ubeef\ucafe')"
mkdir -p "${t}/root/$(printf '\024 <-- some more weird characters --> \u4f60\u597d\uff0c\u4e16\u754c')"
ln -s "$(printf '62_\u00c6\u00c62\u00ae\u00b7m\u00db\u00c3r^\u00bfp\u00c6u"q\u00fbc2\u00f0u\u00b8\u00dd\u00e8v\u00ff\u00b0\u00dc\u00c2\u00f53\u00db')" "${t}/root/$(printf 'k\u00f2sd4\\p\u00da\u00a6\u00d3\u00eea<\u00e6s{\u00a0p\u00f0\u00ffj\u00e0\u00e8\u00b8\u00b8\u00bc\u00fcb')"
printf 'some lovely data 62_\u00c6\u00c62\u00ae\u00b7m\u00db\u00c3r' > "${t}/root/$(printf 'T\u00dcB\u0130TAK_UEKAE_K\u00f6k_Sertifika_Hizmet_Sa\u011flay\u0131c\u0131s\u0131_-_S\u00fcr\u00fcm_3.pem')"
# Create manifest and check it against the same root.
${gomtree} -k uid,gid,size,type,link,nlink,sha256digest -c -p ${t}/root > ${t}/root.mtree
${gomtree} -k uid,gid,size,type,link,nlink,sha256digest -f ${t}/root.mtree -p ${t}/root
# Modify it and make sure that it successfully figures out what changed.
echo "othe data" > "${t}/root/$(printf 'this file has \u042a some unicode !!')"
! ${gomtree} -k uid,gid,size,type,link,nlink,sha256digest -f ${t}/root.mtree -p ${t}/root
echo "some data" > "${t}/root/$(printf 'this file has \u042a some unicode !!')"
${gomtree} -k uid,gid,size,type,link,nlink,sha256digest -f ${t}/root.mtree -p ${t}/root
popd
rm -rf ${t}

3
test/doc.go Normal file
View File

@ -0,0 +1,3 @@
package test
// place holder for test helpers

22
test/realpath.go Normal file
View File

@ -0,0 +1,22 @@
// +build ignore
package main
import (
"flag"
"fmt"
"os"
"path/filepath"
)
func main() {
flag.Parse()
for _, arg := range flag.Args() {
path, err := filepath.Abs(arg)
if err != nil {
fmt.Fprint(os.Stderr, err)
os.Exit(1)
}
fmt.Printf("%s", path)
}
}

800
testdata/source.casync-mtree vendored Normal file
View File

@ -0,0 +1,800 @@
. type=dir mode=0775 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1513088963.690901011
.git type=dir mode=0775 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1513089565.023874273
.git/FETCH_HEAD type=file mode=0664 size=0 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1513089402.952611958 sha512256digest=c672b8d1ef56ed28ab87c3622c5114069bdd3ad7b8f9737498d0c01ecef0967a
.git/HEAD type=file mode=0664 size=23 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.419901036 sha512256digest=459551401449a0555a2c1a1ef57f17eab8b70afccd1ae2fb089e1fe216d92041
.git/branches type=dir mode=0775 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512773804.793867723
.git/config type=file mode=0664 size=259 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.420901030 sha512256digest=18c4f2a977a0a6fb1039082eea88c34a7722f711f9bb40141eeae811077511ea
.git/description type=file mode=0664 size=73 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512773804.794867807 sha512256digest=52f9f7b626fcc7377e618c29c72d2adfb40659bad81aa9cabe69b1ef7e48ec15
.git/hooks type=dir mode=0775 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512773804.794867807
.git/hooks/applypatch-msg.sample type=file mode=0775 size=478 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512773804.793867723 sha512256digest=50e4870022c7e5ea0c9fd2556b9de3ea9741e5cc6bbca86d7749532e091f94aa
.git/hooks/commit-msg.sample type=file mode=0775 size=896 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512773804.793867723 sha512256digest=b131f0eacbaf7d6f5e45bc59413bedebc000006554d37d0f6387f94bff3d7ba4
.git/hooks/post-update.sample type=file mode=0775 size=189 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512773804.793867723 sha512256digest=a861e78221dd2aee9ef902e918279d18d5776f45ff2f08f2d6d85def3e879c20
.git/hooks/pre-applypatch.sample type=file mode=0775 size=424 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512773804.793867723 sha512256digest=ef5dc4dd0d72149edaa2240740936d256c30fa43f0f175c3e03db7684d8b1a5d
.git/hooks/pre-commit.sample type=file mode=0775 size=1642 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512773804.793867723 sha512256digest=ac3a75622c41756863cfb0e6a5eac2f9247e0aa2de287fcebf3fd059bfe7b423
.git/hooks/pre-push.sample type=file mode=0775 size=1348 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512773804.793867723 sha512256digest=5cb63a560e7dab995cdffe1fcd1b7ddbadc434b0e5adae360e0d5daa79e41bd5
.git/hooks/pre-rebase.sample type=file mode=0775 size=4898 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512773804.794867807 sha512256digest=575537b3286d2ffcf1f129cb674b49e995b6f3843b32fb213c8372d59fd588f8
.git/hooks/pre-receive.sample type=file mode=0775 size=544 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512773804.794867807 sha512256digest=3c068c42aee0de45188ba1180c447f9b9387c1551ee486caba4511e8b40f7573
.git/hooks/prepare-commit-msg.sample type=file mode=0775 size=1239 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512773804.794867807 sha512256digest=9d96b773060e0260d7d7face6b1daee38ec0ad977a0f74f9d45520905e3f830e
.git/hooks/update.sample type=file mode=0775 size=3610 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512773804.794867807 sha512256digest=7990f12495cee686e19080c5633b7cd18a40fdca1120be1a6128937f5568aac0
.git/index type=file mode=0664 size=76425 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1513087136.393593011 sha512256digest=83b6bbe228b1b181ef87269fd937adc615bf7f18940697807d864dff3f95b66b
.git/info type=dir mode=0775 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512773804.794867807
.git/info/exclude type=file mode=0664 size=240 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512773804.794867807 sha512256digest=b5a32a7a25ad2254f517806d1600ff2498e2f91fe501cb54f9dd517e9693bf7c
.git/logs type=dir mode=0775 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.419901036
.git/logs/HEAD type=file mode=0664 size=186 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.419901036 sha512256digest=6ba5a37eb3a8363ce228172998c9120800d2099e59ff0365f8095e437c4e7e72
.git/logs/refs type=dir mode=0775 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.419901036
.git/logs/refs/heads type=dir mode=0775 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.420901030
.git/logs/refs/heads/master type=file mode=0664 size=186 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.420901030 sha512256digest=6ba5a37eb3a8363ce228172998c9120800d2099e59ff0365f8095e437c4e7e72
.git/logs/refs/remotes type=dir mode=0775 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.418901041
.git/logs/refs/remotes/origin type=dir mode=0775 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.418901041
.git/logs/refs/remotes/origin/HEAD type=file mode=0664 size=186 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.419901036 sha512256digest=6ba5a37eb3a8363ce228172998c9120800d2099e59ff0365f8095e437c4e7e72
.git/objects type=dir mode=0775 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512773804.794867807
.git/objects/info type=dir mode=0775 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512773804.794867807
.git/objects/pack type=dir mode=0775 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.420901030
.git/objects/pack/pack-6002ca434fbc0435338603c137c716144940e3ac.idx type=file mode=0444 size=64128 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774393.883903855 sha512256digest=22029d26bebf556cfc42e05b2803631e69913316cfdc4f93f81bf0b811422965
.git/objects/pack/pack-6002ca434fbc0435338603c137c716144940e3ac.pack type=file mode=0444 size=2847104 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774393.883903855 sha512256digest=edcbdb76328491490433392cc9d73473d7ed3c4b9d730071eadafff7bcbbe322
.git/packed-refs type=file mode=0664 size=980 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.418901041 sha512256digest=64272b5a7707bc9de1644ffe9f4ea331e0b27edfe2afa46051765d650e4f027d
.git/refs type=dir mode=0775 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.418901041
.git/refs/heads type=dir mode=0775 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.420901030
.git/refs/heads/master type=file mode=0664 size=41 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.419901036 sha512256digest=ff968619a51a3545a1b690defeb0e496221e87f44d7842f21e4479cd8323e2b3
.git/refs/remotes type=dir mode=0775 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.418901041
.git/refs/remotes/origin type=dir mode=0775 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.419901036
.git/refs/remotes/origin/HEAD type=file mode=0664 size=32 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.419901036 sha512256digest=59c99dd84367c1f79cc6e2fc932283a596ed1351f89a378f473bf223a1bce4a6
.git/refs/tags type=dir mode=0775 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512773804.794867807
.gitignore type=file mode=0664 size=38 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.422901020 sha512256digest=da309c361a1906cf290acfe3f9737761809f4651398f51e8ba3b595ce3890d8a
.travis.yml type=file mode=0664 size=418 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.422901020 sha512256digest=4cc236b9fd00e9e1d7e77c06d5387fc78b88d37fcc138a97f889afea77237809
.vscode type=dir mode=0775 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.422901020
.vscode/tasks.json type=file mode=0664 size=1903 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.422901020 sha512256digest=0f618420497f07ab3c52fb914a2a017f9c8f6cecb827139000d83d3924945bba
LICENSE type=file mode=0664 size=1502 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.422901020 sha512256digest=a38c5d130d16a578fadb5b64272dfa21bc3ee81a170ddfaef602c889ad0e5f47
Makefile type=file mode=0664 size=1842 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.422901020 sha512256digest=bee7d37dc3d204d42316f6970ec8394cac8797f41fd033230543c669ae65eb10
README.md type=file mode=0664 size=6458 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.423901015 sha512256digest=a0f4fff9726af7e296dbacde210abb160f8d3ffe3a13eac3eae315804fbefdf7
Session.vim type=file mode=0644 size=6088 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1513025969.072229243 sha512256digest=ac49e25a69333d34faa213ea419bba40afc971880e6433a031ad93b7e91cda73
check.go type=file mode=0664 size=1066 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.423901015 sha512256digest=36d6f22adfdb787d2c66dcc7847339146c0e9b239bbdd6e36628264b0a9f6bfb
check_test.go type=file mode=0664 size=6668 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.423901015 sha512256digest=dc8562fc88ab21aa1e1c2eb77caa0c07bedf0801d8e2cb315cab71c4d63b0de0
cksum.go type=file mode=0664 size=727 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.423901015 sha512256digest=a16b170014a48532ee0fe3ea61bbe6a45cfd20a984bcceaed0c71524652fe4d3
cksum_test.go type=file mode=0664 size=606 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.423901015 sha512256digest=ff9857d71266a4939b453900155da931122e35187500535d826656a15ad9ba41
cmd type=dir mode=0775 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.423901015
cmd/gomtree type=dir mode=0775 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.423901015
cmd/gomtree/main.go type=file mode=0664 size=12826 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.423901015 sha512256digest=81195682a5fbdd6a324e2cfa7c61ddf9e14eea6d92c3133da4a858ffadadf6b0
compare.go type=file mode=0664 size=12077 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.423901015 sha512256digest=e0a79e38e03830d965271f4b37dbc6567998a277011437dfb270fb39030b8147
compare_test.go type=file mode=0664 size=10837 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.423901015 sha512256digest=39d0b9638b0b869cf20310a5b0e16ae979b690f3e795eafc1da4502c86c3d601
creator.go type=file mode=0664 size=188 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.423901015 sha512256digest=ef1e8b19255cdc090719bcd947937555c7454b36df7ca501be9c617f1d66d693
entry.go type=file mode=0664 size=4645 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.423901015 sha512256digest=e267d8bcb083acacf43318a038cb50a6fff4658f1c7cfb2d3ebd881d294647b4
fseval.go type=file mode=0664 size=1903 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.423901015 sha512256digest=aa0911e07f7607ce3e4912e37109400d17a905837975f4da48cb225af347afb1
fseval_test.go type=file mode=0664 size=3692 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.423901015 sha512256digest=337e96a382b8a1d4c6fc8c3b57bb5c5598f2de52c33017ddbd9087a8a8cdb235
glide.lock type=file mode=0664 size=455 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.423901015 sha512256digest=1ef63ba5b06290869c7bcf6bfa225fc646645f293d6b8b84844359e10a71d9dd
glide.yaml type=file mode=0664 size=415 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.423901015 sha512256digest=1ca9b54955195442592840664081368529c919ae2d1d7dabbb2bf6c236ba443d
hierarchy.go type=file mode=0664 size=1109 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.423901015 sha512256digest=25d9d887b37972e923656c907a72a0ab40f525704657ed51718b15b1d9030b08
hierarchy_test.go type=file mode=0664 size=1427 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.423901015 sha512256digest=cbb37bbaa235cb30670af42d5ae1fff018eee4d97d83628670cc85cda0a8eec8
keywordfunc.go type=file mode=0664 size=7790 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.424901009 sha512256digest=972ef809068af40d0f4d931c179c09e3387652e493ff3badcdb1336ad03c0034
keywordfuncs_bsd.go type=file mode=0664 size=2167 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.424901009 sha512256digest=3d5442bc82156768131be11b491f0a196cb40ef4845026ffef230047c10a84dc
keywordfuncs_linux.go type=file mode=0664 size=3129 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.424901009 sha512256digest=774f8189932431f2903fcc292e7bc6bb0e0e478fcd0d18d21710398fa196de84
keywordfuncs_unsupported.go type=file mode=0664 size=1440 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.424901009 sha512256digest=4062bfa6539d920fd470c459cf91b903135ee41384d4addcd0635c1b8b248fd8
keywords.go type=file mode=0664 size=8255 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.424901009 sha512256digest=1bd20d1919c02036b8f969c73e0dc391dcc9fef5f003b5c5da36b434e4640b15
keywords_linux_test.go type=file mode=0664 size=1777 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.424901009 sha512256digest=6b009753d97b46d3dd7d0209b1866d0da50327c102ef9becb1a80a5d770b4008
keywords_test.go type=file mode=0664 size=4084 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.424901009 sha512256digest=c6fe584af730c805033c85db2a422b608f7cf034fe1d5bac732a354676328cb3
lchtimes_unix.go type=file mode=0664 size=484 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.424901009 sha512256digest=56cf8545358550958badaa966a41e5a07cbd15138d42e19997936e7ae6c330cd
lchtimes_unsupported.go type=file mode=0664 size=137 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.424901009 sha512256digest=a0d24dbf1ffe27dce9e2dcd72c2189c0ba8d9b445fb1d6efea3ef6f43372b141
lookup_new.go type=file mode=0664 size=94 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.424901009 sha512256digest=98317093a5e1d05d3829935c4c68ac09887fff4ad9257760d6cb80051ec6c793
lookup_old.go type=file mode=0664 size=2670 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.424901009 sha512256digest=3d4410b652c64fb4079e7219435aa2de828d7ef0cec2a8dabe9c3e95709c5cba
mtree_test.go type=file mode=0664 size=1628 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1513089487.302748479 sha512256digest=b205a894416221a6459b1f57688007b6ea29a7e25ee07f867acb16ca4481b281
parse.go type=file mode=0664 size=2404 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.424901009 sha512256digest=dacb3ab6f3a2c2a84ee1eef603f2943561c905947bd75dd8711a944bd646a75a
pkg type=dir mode=0775 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.424901009
pkg/govis type=dir mode=0775 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.425901004
pkg/govis/COPYING type=file mode=0664 size=11358 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.424901009 sha512256digest=84e99c21df3d69d6bcb82420dc1c5ab9e877aa19ca516fa2644cd2f1e6c35840
pkg/govis/README.md type=file mode=0664 size=966 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.424901009 sha512256digest=e84c3fc90fec0e85d707689c7859535ddced586627d42281a8f33d89698c77ed
pkg/govis/govis.go type=file mode=0664 size=1784 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.424901009 sha512256digest=d942950dfa287f81605b726e95e995db1e309c2ad211d236648eeab5b6840b49
pkg/govis/govis_test.go type=file mode=0664 size=6727 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.424901009 sha512256digest=9a75d86c248a307c026b311fb0513a689138d3806137b342ed255d4f9ce166c2
pkg/govis/unvis.go type=file mode=0664 size=6889 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.424901009 sha512256digest=eeba6c37bb098970d1ecbf53aa32ecd3d161ca5ed52e6ca0d1e7280495f3082a
pkg/govis/unvis_test.go type=file mode=0664 size=5302 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.424901009 sha512256digest=d995e7aa0846ab698cbd4b3ae0aa54d0b1bf628def1e76689ab2d908e4113097
pkg/govis/vis.go type=file mode=0664 size=5034 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.425901004 sha512256digest=4ff0d8874456bafff63d14227a56732fe8296993eb7ff827d2c3388174c7c040
pkg/govis/vis_test.go type=file mode=0664 size=8862 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.425901004 sha512256digest=b93c8a5d205abb50a8bda7ed9101011856d664d3abee187a8d223ccfaf0bce32
releases.md type=file mode=0664 size=422 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.425901004 sha512256digest=67b517b1725f58d3f5680d33f303825d15e651df6644f7ebfc7f8c6822069c82
stat_unix.go type=file mode=0664 size=311 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.425901004 sha512256digest=031b6589306025dde40c3bc9502bd8e01900550ded8f63a92ee2d1dbeefcb6d8
stat_windows.go type=file mode=0664 size=177 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.425901004 sha512256digest=5478d5912535771b76cfce0d4f8b6629d745cb4d7c76060b42f6ca9422da7307
tar.go type=file mode=0664 size=12908 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.425901004 sha512256digest=6e108ec0cce2c4845db2280aa0e800ced879a9263a91d5bb9d1c346386e58cfc
tar_test.go type=file mode=0664 size=9332 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.425901004 sha512256digest=5da79852086430337df7f87266e290d4888dc78a39e139d38a4bc96957bd9b5b
test type=dir mode=0775 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.425901004
test/cli type=dir mode=0775 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.425901004
test/cli/0001.sh type=file mode=0664 size=1340 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.425901004 sha512256digest=7c78b4d73ec17dbf77a1af6903fe2347fc3841f7dbb15cbd6a1bbc8b133350b3
test/cli/0002.sh type=file mode=0664 size=614 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.425901004 sha512256digest=1ef56e3423025f1eb7bbf965abd99399498cd5804c9983815bc13ca638336ca5
test/cli/0003.sh type=file mode=0664 size=995 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.425901004 sha512256digest=e9dc80a37f6ffb633024b394c621cb7f49e06828400703bfd1044b4f6776921c
test/cli/0004.sh type=file mode=0664 size=660 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.425901004 sha512256digest=22fad78aa558af47ca5839966cb5d49320ee8fd23b7414e26d7871991a29fcd0
test/cli/0005.sh type=file mode=0664 size=440 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.425901004 sha512256digest=e9a705d3fb58f37655070a29749c955d89c5f5897d20df63e8703aa046285121
test/cli/0006.sh type=file mode=0664 size=860 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.425901004 sha512256digest=fe5c5b969ae47ebf00855cb163acd2ee8e73fd0ce4506aab74315b1aecf8ddda
test/cli/0007.sh type=file mode=0664 size=454 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.425901004 sha512256digest=cedf7d50bd3d774d5d286148ac363e548e1b2bc39718cc3775c1e5018b196baf
test/cli/0008.sh type=file mode=0664 size=562 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.425901004 sha512256digest=1f0947e3f92c24a607c91d8e6bc4ca7a5d919fe860f5a8759b40fe966302ef16
test/cli/0009.sh type=file mode=0664 size=1683 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.425901004 sha512256digest=31ced90180929e0bb3297b196cd927644038e9c446d8fe85e6ceafa839264abe
test/cli.go type=file mode=0664 size=508 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.425901004 sha512256digest=7058ca6366fdf79c23531a4b4cb22bef2dc6de24ba0ef08ac9fd5ef4974341ab
testdata type=dir mode=0775 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1513088963.690901011
testdata/collection type=dir mode=0775 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.426900999
testdata/collection/dir1 type=dir mode=0775 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.426900999
testdata/collection/dir1/file1 type=file mode=0664 size=0 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.426900999 sha512256digest=c672b8d1ef56ed28ab87c3622c5114069bdd3ad7b8f9737498d0c01ecef0967a
testdata/collection/dir2 type=dir mode=0775 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.426900999
testdata/collection/dir2/file2 type=file mode=0664 size=0 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.426900999 sha512256digest=c672b8d1ef56ed28ab87c3622c5114069bdd3ad7b8f9737498d0c01ecef0967a
testdata/collection/dir3 type=dir mode=0775 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.426900999
testdata/collection/dir3/file3 type=file mode=0664 size=0 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.426900999 sha512256digest=c672b8d1ef56ed28ab87c3622c5114069bdd3ad7b8f9737498d0c01ecef0967a
testdata/collection/dir4 type=dir mode=0775 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.426900999
testdata/collection/dir4/file4 type=file mode=0664 size=0 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.426900999 sha512256digest=c672b8d1ef56ed28ab87c3622c5114069bdd3ad7b8f9737498d0c01ecef0967a
testdata/collection/dir5 type=dir mode=0775 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.426900999
testdata/collection/dir5/dir6 type=dir mode=0775 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.426900999
testdata/collection/dir5/dir6/dir7 type=dir mode=0775 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.426900999
testdata/collection/dir5/dir6/dir7/lonelyfile type=file mode=0664 size=0 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.426900999 sha512256digest=c672b8d1ef56ed28ab87c3622c5114069bdd3ad7b8f9737498d0c01ecef0967a
testdata/collection/file1 type=file mode=0664 size=3 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.426900999 sha512256digest=f1015369e7da404777803c72d48afdbe3a0d1bd2c5feb2a9d5b3db5ac78e9b9c
testdata/collection/file2 type=file mode=0664 size=6 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.426900999 sha512256digest=7f3f0c0d5219f51459578305ed2bbc198588758da85d08024c79c1195d1cd611
testdata/collection/file3 type=file mode=0664 size=12 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.426900999 sha512256digest=1b88acd5ac9d970535991a5fbfbe6c1c5ca3434cea31cd8f9fc7de83e798e678
testdata/collection.tar type=file mode=0664 size=10240 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.425901004 sha512256digest=9d5eed555694f1de43a60a1f5b282d0e63b20edda06cbd10430edde8b74803ad
testdata/dirwithbrokenlink type=dir mode=0775 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.426900999
testdata/dirwithbrokenlink/\040file\040with\040spaces\040 type=file mode=0664 size=0 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.426900999 sha512256digest=c672b8d1ef56ed28ab87c3622c5114069bdd3ad7b8f9737498d0c01ecef0967a
testdata/dirwithbrokenlink/deepdir type=dir mode=0775 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.426900999
testdata/dirwithbrokenlink/deepdir/dir3 type=dir mode=0775 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.426900999
testdata/dirwithbrokenlink/deepdir/dir3/dir4 type=dir mode=0775 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.426900999
testdata/dirwithbrokenlink/deepdir/dir3/dir4/deepfile type=file mode=0664 size=0 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.426900999 sha512256digest=c672b8d1ef56ed28ab87c3622c5114069bdd3ad7b8f9737498d0c01ecef0967a
testdata/dirwithbrokenlink/deepdir/dir3/dir4/dir5 type=dir mode=0775 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.426900999
testdata/dirwithbrokenlink/deepdir/dir3/dir4/dir5/dir6 type=dir mode=0775 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.426900999
testdata/dirwithbrokenlink/deepdir/dir3/dir4/dir5/dir6/deeperfile type=file mode=0664 size=19 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.426900999 sha512256digest=b3b48f5ca2cfd0f9426432fbaaedb57ad2750b1bfe3235c712098e8953b96fbb
testdata/dirwithbrokenlink/deepdir/dir3/dir4/dir5/dir7 type=dir mode=0775 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.426900999
testdata/dirwithbrokenlink/deepdir/dir3/dir4/dir5/dir7/deeperfile type=file mode=0664 size=15 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.426900999 sha512256digest=c2c4f516ee9fef3b2ecf1e2aba9c3f4d4d793d5b7140532da6ba5468f69a5f4f
testdata/dirwithbrokenlink/deepdir/dir3/file type=file mode=0664 size=0 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.426900999 sha512256digest=c672b8d1ef56ed28ab87c3622c5114069bdd3ad7b8f9737498d0c01ecef0967a
testdata/dirwithbrokenlink/deepdir/dir3/file6 type=file mode=0664 size=0 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.426900999 sha512256digest=c672b8d1ef56ed28ab87c3622c5114069bdd3ad7b8f9737498d0c01ecef0967a
testdata/dirwithbrokenlink/deepdir/dir3/file7 type=file mode=0664 size=0 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.426900999 sha512256digest=c672b8d1ef56ed28ab87c3622c5114069bdd3ad7b8f9737498d0c01ecef0967a
testdata/dirwithbrokenlink/deepdir/this_is_a_file type=file mode=0664 size=0 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.426900999 sha512256digest=c672b8d1ef56ed28ab87c3622c5114069bdd3ad7b8f9737498d0c01ecef0967a
testdata/dirwithbrokenlink/dir1 type=dir mode=0775 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.426900999
testdata/dirwithbrokenlink/dir1/.hiddenfile type=file mode=0664 size=0 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.426900999 sha512256digest=c672b8d1ef56ed28ab87c3622c5114069bdd3ad7b8f9737498d0c01ecef0967a
testdata/dirwithbrokenlink/dir1/badlink type=link mode=0777 link=badfile uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.426900999
testdata/dirwithbrokenlink/dir1/dir2 type=dir mode=0775 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.426900999
testdata/dirwithbrokenlink/dir1/dir2/.hidden type=dir mode=0775 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.426900999
testdata/dirwithbrokenlink/dir1/dir2/.hidden/goodlink type=link mode=0777 link=../../goodfile uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.426900999
testdata/dirwithbrokenlink/dir1/goodfile type=file mode=0664 size=10 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.426900999 sha512256digest=3b69a4f25d23a1a184f5d32e7d8a5a1e19f1062cefe57fd1ccc7dfd9c702fd8d
testdata/dirwithbrokenlink/file1 type=file mode=0664 size=0 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.426900999 sha512256digest=c672b8d1ef56ed28ab87c3622c5114069bdd3ad7b8f9737498d0c01ecef0967a
testdata/dirwithbrokenlink/file2 type=file mode=0664 size=0 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.426900999 sha512256digest=c672b8d1ef56ed28ab87c3622c5114069bdd3ad7b8f9737498d0c01ecef0967a
testdata/hardlinks.tar type=file mode=0664 size=10240 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.426900999 sha512256digest=33d43be8aa1f5ad9ff90ac2c3ba732f89de25fef7ee6cc6233bce2cf8e7b7a92
testdata/singlefile type=dir mode=0775 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.427900993
testdata/singlefile/dir2 type=dir mode=0775 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.427900993
testdata/singlefile/dir2/dir3 type=dir mode=0775 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.427900993
testdata/singlefile/dir2/dir3/file type=file mode=0664 size=0 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.427900993 sha512256digest=c672b8d1ef56ed28ab87c3622c5114069bdd3ad7b8f9737498d0c01ecef0967a
testdata/singlefile.tar type=file mode=0664 size=10240 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.427900993 sha512256digest=c06b6d2223c9a35951d9e6cbbaea9a46565ca3ae7bba1339051019681820a39c
testdata/source.mtree type=file mode=0664 size=9110 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.427900993 sha512256digest=ae80aea4b907dcd2ac567a201f39694e18b0f6cef76f71a154f5581446f33945
testdata/test.tar type=file mode=0664 size=20480 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.428900988 sha512256digest=f5624efd93b66b7bd144bdb2a7dc1f0af833bbfd23f0691a671a53704e620a9b
testdata/traversal type=dir mode=0775 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.428900988
testdata/traversal/dir2 type=dir mode=0775 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.428900988
testdata/traversal/dir2/dir3 type=dir mode=0775 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.428900988
testdata/traversal/dir2/dir3/actualdir1 type=dir mode=0775 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.428900988
testdata/traversal/dir2/dir3/actualdir1/file1 type=file mode=0664 size=0 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.428900988 sha512256digest=c672b8d1ef56ed28ab87c3622c5114069bdd3ad7b8f9737498d0c01ecef0967a
testdata/traversal/dir2/dir3/actualdir1/file2 type=file mode=0664 size=0 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.428900988 sha512256digest=c672b8d1ef56ed28ab87c3622c5114069bdd3ad7b8f9737498d0c01ecef0967a
testdata/traversal/dir2/dir3/actualdir2 type=dir mode=0775 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.428900988
testdata/traversal/dir2/dir3/actualdir2/a type=file mode=0664 size=6 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.428900988 sha512256digest=7f3f0c0d5219f51459578305ed2bbc198588758da85d08024c79c1195d1cd611
testdata/traversal/dir2/dir3/actualdir2/b type=file mode=0664 size=4 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.428900988 sha512256digest=9e591fb9c0c021fd8639eb5a44fa29e62835381c94cfd0d7db3ebef83fc2ce18
testdata/traversal/dir2/dir3/actualdir2/c type=file mode=0664 size=12 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.428900988 sha512256digest=1b88acd5ac9d970535991a5fbfbe6c1c5ca3434cea31cd8f9fc7de83e798e678
testdata/traversal/dir2/dir3/file type=file mode=0664 size=0 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.428900988 sha512256digest=c672b8d1ef56ed28ab87c3622c5114069bdd3ad7b8f9737498d0c01ecef0967a
testdata/traversal/dir2/dir3/file3 type=file mode=0664 size=0 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.428900988 sha512256digest=c672b8d1ef56ed28ab87c3622c5114069bdd3ad7b8f9737498d0c01ecef0967a
testdata/traversal.tar type=file mode=0664 size=10240 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.428900988 sha512256digest=a69da7826437471c45c2ca6fad6860835ac2c5df5f652380bf316b2d0580a4aa
testdata/xattr.casync-mtree type=file mode=0664 size=28672 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1513089579.719898057 sha512256digest=d51e93315715b31a254cd21d1bb028bab6b9dec2653f4f7ba6557f89a7e5a153
update.go type=file mode=0664 size=3865 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.429900983 sha512256digest=f0bfc79f2f0dde387139117c6a1e5d5aa69c06aac233d53b0fc2be1e55cfba32
update_linux_test.go type=file mode=0664 size=2330 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.429900983 sha512256digest=c708daffa3d4c4869df009891af3c18a9b6ba6b200a28bed45b567b116dd117a
update_test.go type=file mode=0664 size=2848 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.429900983 sha512256digest=b5e0093cecd9f799fbebd651a3c63b159079bd86e31e02b1329078f78dd7219b
updatefuncs.go type=file mode=0664 size=5049 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.429900983 sha512256digest=b8a066b3544f745eb6233978f4322f9da15e30e9e009bcfd738a07f4ff12ef88
updatefuncs_linux.go type=file mode=0664 size=391 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.429900983 sha512256digest=de5d27e36de90d33f9efac533330f3cafb302cb1886ce63970107985dc2ab67b
updatefuncs_unsupported.go type=file mode=0664 size=151 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.429900983 sha512256digest=adec393ac2f40975877645a58fb43b01c5b94090f70bec2470b9b30efc9c821a
vendor type=dir mode=0775 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.431900972
vendor/github.com type=dir mode=0775 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.429900983
vendor/github.com/sirupsen type=dir mode=0775 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.429900983
vendor/github.com/sirupsen/logrus type=dir mode=0775 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.431900972
vendor/github.com/sirupsen/logrus/.gitignore type=file mode=0664 size=7 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.429900983 sha512256digest=004bbd91c2e11a52b6c11ef24a5c2578e653b9d25e60f28b077fb11b3b06af75
vendor/github.com/sirupsen/logrus/.travis.yml type=file mode=0664 size=313 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.429900983 sha512256digest=e7e6345826dfa1b3624659022f1e768ccfe3e9e16834dd8e7a443591fddc8ac5
vendor/github.com/sirupsen/logrus/CHANGELOG.md type=file mode=0664 size=2509 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.429900983 sha512256digest=49b7c9aec18b26e851c301f273001ddf6d6cefc3633b025b5391bcc88c4524f1
vendor/github.com/sirupsen/logrus/LICENSE type=file mode=0664 size=1082 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.429900983 sha512256digest=f163519149dc1ca924d74e9d228bee482ea4c939c89d7e9c53aa5c48b9e1bce5
vendor/github.com/sirupsen/logrus/README.md type=file mode=0664 size=22063 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.429900983 sha512256digest=29672a4ceb7a04cbb54b8c425d70d05bc2633597037bb8617259d74b0d381de5
vendor/github.com/sirupsen/logrus/alt_exit.go type=file mode=0664 size=2246 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.429900983 sha512256digest=707edd5510b2aa3780fcfd6fcf51471f5c9c9aee00b84814d1a6498847abe548
vendor/github.com/sirupsen/logrus/alt_exit_test.go type=file mode=0664 size=1623 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.429900983 sha512256digest=36cbdb077b1389d44178a47fa507c2acf008f4306785696ba8f6557ef9ef569e
vendor/github.com/sirupsen/logrus/appveyor.yml type=file mode=0664 size=281 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.429900983 sha512256digest=ca5a031100d1f288ebf376a86f63c66ee092c560a569d8a43344b39ade7278b1
vendor/github.com/sirupsen/logrus/doc.go type=file mode=0664 size=586 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.429900983 sha512256digest=80339eeb074e45314d9e38ec03e08fa587124f713483bf96de4246f3e5742d3a
vendor/github.com/sirupsen/logrus/entry.go type=file mode=0664 size=6963 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.429900983 sha512256digest=42adbbdf08f60a86e7415f160a0d69c0507d8cef72de4f449d750f4174be819e
vendor/github.com/sirupsen/logrus/entry_test.go type=file mode=0664 size=1459 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.429900983 sha512256digest=a729abde18f325b18ca396e22598bd0f51ccc677624e7fc1d27a832b8ab96370
vendor/github.com/sirupsen/logrus/example_basic_test.go type=file mode=0664 size=2042 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.429900983 sha512256digest=c8ea083f4a98401602895fa178ea5b74acd1b32a70236ba2e361d97eb75372cb
vendor/github.com/sirupsen/logrus/example_hook_test.go type=file mode=0664 size=1001 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.429900983 sha512256digest=195cffcc9c4483ce0e4920803cc8bb9924045d39807c7495979e658825ef6cf7
vendor/github.com/sirupsen/logrus/exported.go type=file mode=0664 size=4880 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.430900978 sha512256digest=e229a9b34fb85ae1920db8e421dba771d7128cdc6712838fb3876a212b5c504b
vendor/github.com/sirupsen/logrus/formatter.go type=file mode=0664 size=1368 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.430900978 sha512256digest=cc8189494c6cae97fbe5e7dde3c9e9dcde2d1d8398b28271264949173d6e58c7
vendor/github.com/sirupsen/logrus/formatter_bench_test.go type=file mode=0664 size=2143 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.430900978 sha512256digest=e4db7f602a583206c8d730a826d0766263b2ea28838c129af21a967ff197bbcc
vendor/github.com/sirupsen/logrus/hook_test.go type=file mode=0664 size=2128 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.430900978 sha512256digest=8e050faa00cf410935bc0f7191ab3a9635e276e9bb865163d6d6ece954009e8d
vendor/github.com/sirupsen/logrus/hooks type=dir mode=0775 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.430900978
vendor/github.com/sirupsen/logrus/hooks/syslog type=dir mode=0775 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.430900978
vendor/github.com/sirupsen/logrus/hooks/syslog/README.md type=file mode=0664 size=926 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.430900978 sha512256digest=7f829c411b7ba02a3a07c022eeb012198b7502f5d832a97e910e3fdd0b79cc31
vendor/github.com/sirupsen/logrus/hooks/syslog/syslog.go type=file mode=0664 size=1311 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.430900978 sha512256digest=7237f9f92f9a7df0d434ca5186689a5a7334df38579e661db54037fd14af4128
vendor/github.com/sirupsen/logrus/hooks/syslog/syslog_test.go type=file mode=0664 size=533 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.430900978 sha512256digest=3d54002343235ab97738a8d2480bf9d602ac337951e62faac706456064d60ebe
vendor/github.com/sirupsen/logrus/hooks/test type=dir mode=0775 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.430900978
vendor/github.com/sirupsen/logrus/hooks/test/test.go type=file mode=0664 size=2096 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.430900978 sha512256digest=0c4d6b7f985f366c427bca638347676dc3838c24f7aedc56b2e62df69156be1e
vendor/github.com/sirupsen/logrus/hooks/test/test_test.go type=file mode=0664 size=907 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.430900978 sha512256digest=9af8e14bec05237f73a048e3e77155315d223a8c5fb40d9c8e1f4602a743d2db
vendor/github.com/sirupsen/logrus/hooks.go type=file mode=0664 size=1101 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.430900978 sha512256digest=5708f971359b96da0b6d72189fe2d678b10048d3b023eadd7497b42d950ceb47
vendor/github.com/sirupsen/logrus/json_formatter.go type=file mode=0664 size=1885 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.430900978 sha512256digest=f049f1fb554fc95cae2a86a1103b1fdc098ac6cf1d65e41b62acb866fef18acd
vendor/github.com/sirupsen/logrus/json_formatter_test.go type=file mode=0664 size=4492 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.430900978 sha512256digest=fdb45612b177b289fd2e35d4dd8af009e167f8b9e01acc641f6d84100d084af8
vendor/github.com/sirupsen/logrus/logger.go type=file mode=0664 size=7946 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.430900978 sha512256digest=00b348ea5157129bdbab52c5bddad4f3d8895a7d7d83c173c1c53ab64a7b6b4f
vendor/github.com/sirupsen/logrus/logger_bench_test.go type=file mode=0664 size=1344 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.430900978 sha512256digest=ca5ccdae3164b30d0ed27ad002b60be443e459f0354b5f044b39e5644b8b118f
vendor/github.com/sirupsen/logrus/logrus.go type=file mode=0664 size=3667 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.430900978 sha512256digest=0a890ae067dc1c3f045787919c61d8297dc5b93834fcc39e8a30303b93acd680
vendor/github.com/sirupsen/logrus/logrus_test.go type=file mode=0664 size=9160 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.430900978 sha512256digest=2417c7d6f8397020046b12b868124cb22ea00456d60daceac1572f4593eed03d
vendor/github.com/sirupsen/logrus/terminal_bsd.go type=file mode=0664 size=186 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.430900978 sha512256digest=588ed9e26de1dc3f7de02f746a0975a292a54929183df26232f8181b91cd17b5
vendor/github.com/sirupsen/logrus/terminal_linux.go type=file mode=0664 size=320 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.430900978 sha512256digest=745de29db1cd82e46345904126f4175a05ba4d1646e40940f78fa5281a1c8a8b
vendor/github.com/sirupsen/logrus/text_formatter.go type=file mode=0664 size=4349 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.430900978 sha512256digest=f8c203f7e13ee9ca132d07a29ae243105f3776b2a03a4c28170f9d43f97a56be
vendor/github.com/sirupsen/logrus/text_formatter_test.go type=file mode=0664 size=3726 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.431900972 sha512256digest=49dbdae1731e825fff63074bc1b92906bdb7a47db5c753b44bcd02cc7e918eba
vendor/github.com/sirupsen/logrus/writer.go type=file mode=0664 size=1269 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.431900972 sha512256digest=a40e7c61fc44d312f71d0fe7ffd07d79098909c9c2d121631205e2e7259e262e
vendor/golang.org type=dir mode=0775 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.431900972
vendor/golang.org/x type=dir mode=0775 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.445900899
vendor/golang.org/x/crypto type=dir mode=0775 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.445900899
vendor/golang.org/x/crypto/.gitattributes type=file mode=0664 size=345 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.431900972 sha512256digest=121f311806f70b4e9278a7a7178bbb73cb8afc0ce20d6134f24cf6a9f637cf85
vendor/golang.org/x/crypto/.gitignore type=file mode=0664 size=84 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.431900972 sha512256digest=c1bc3cda1eb014d25dbebe52e50c7231f60762092811d111e2b60b2a847984d5
vendor/golang.org/x/crypto/AUTHORS type=file mode=0664 size=173 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.431900972 sha512256digest=2e6b61f243b5f5e42e480c2d4588f1538ff08617ce66c01e99589333d4199a2e
vendor/golang.org/x/crypto/CONTRIBUTING.md type=file mode=0664 size=1031 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.431900972 sha512256digest=9f99f8daf18ff8de732527ac23231c253c9800139002bf2b03250fce7372fdfb
vendor/golang.org/x/crypto/CONTRIBUTORS type=file mode=0664 size=170 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.431900972 sha512256digest=261a74c469ed7777fd933f3cd1544b351d162ad51d5cedb570aab4da0fbc62d7
vendor/golang.org/x/crypto/LICENSE type=file mode=0664 size=1479 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.431900972 sha512256digest=ea1cff0ac6655ef2801edc8f18ba083c7fae87b0fb0c542ea1d9628e46992f19
vendor/golang.org/x/crypto/PATENTS type=file mode=0664 size=1303 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.431900972 sha512256digest=2ea07f77ca1c22dc417acfa6942f0faf5f545f44bca4c9387dab0e6e5ca442af
vendor/golang.org/x/crypto/README type=file mode=0664 size=145 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.431900972 sha512256digest=0ac9ce2faeed2023c29348f068fab8049c29403430d37a0be5132b0bf762f8b9
vendor/golang.org/x/crypto/bcrypt type=dir mode=0775 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.431900972
vendor/golang.org/x/crypto/bcrypt/base64.go type=file mode=0664 size=817 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.431900972 sha512256digest=44021e633e2cb964c43373d30380f1efacf8b115a5e3419697a3decd3d1e336a
vendor/golang.org/x/crypto/bcrypt/bcrypt.go type=file mode=0664 size=7880 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.431900972 sha512256digest=ddd672a8e6874c38ea15edc4b962e0a3ede43e090ef7f6f8199c6a0c7d37400d
vendor/golang.org/x/crypto/bcrypt/bcrypt_test.go type=file mode=0664 size=6372 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.431900972 sha512256digest=cd047b3a9a3d46c20774c10439572842c6270dcd7d48ee8c5fae8e12ce15491a
vendor/golang.org/x/crypto/blowfish type=dir mode=0775 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.431900972
vendor/golang.org/x/crypto/blowfish/block.go type=file mode=0664 size=6161 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.431900972 sha512256digest=895b2605173026d2a411c25bdcacaec1793d31d5d5cdd84c4126a1887b47f058
vendor/golang.org/x/crypto/blowfish/blowfish_test.go type=file mode=0664 size=10197 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.431900972 sha512256digest=3683841d3b3eb3fc63fa79353f94a889e19e32b08c3b9e04e20e60c0f628717b
vendor/golang.org/x/crypto/blowfish/cipher.go type=file mode=0664 size=3109 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.431900972 sha512256digest=c99ed894413ef3a4fed02a8f0cf6606bbd7975e93b956f60b05adb435c250d87
vendor/golang.org/x/crypto/blowfish/const.go type=file mode=0664 size=13131 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.431900972 sha512256digest=496b0f019d93c6bd67e526f7fe118619e2b7a1c7c308476d057c71776b1a22fc
vendor/golang.org/x/crypto/bn256 type=dir mode=0775 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.432900967
vendor/golang.org/x/crypto/bn256/bn256.go type=file mode=0664 size=9621 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.432900967 sha512256digest=9ff55812c49b84d5f07c63259b6ff6a5dce62ccd66d3e6b7f791995e8311054b
vendor/golang.org/x/crypto/bn256/bn256_test.go type=file mode=0664 size=6696 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.432900967 sha512256digest=a93b06fb3af2e227c99a7e2132e173de17e33343aa14d1343322276976966cb5
vendor/golang.org/x/crypto/bn256/constants.go type=file mode=0664 size=2472 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.432900967 sha512256digest=5df09cc395bc759610a4e8b135f77a27026160cdb7b8c878b27763efc4fb3c7d
vendor/golang.org/x/crypto/bn256/curve.go type=file mode=0664 size=5477 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.432900967 sha512256digest=e71600cb0f39d7fbad38eee3baee48eba90e223592846634b483d68a5d38b992
vendor/golang.org/x/crypto/bn256/example_test.go type=file mode=0664 size=1163 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.432900967 sha512256digest=69a4f1428227126eb577faff064fb8cbf2226598523e21306cf09252931030ee
vendor/golang.org/x/crypto/bn256/gfp12.go type=file mode=0664 size=3645 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.432900967 sha512256digest=2e0c360c93c85f2caeb396a3b886524c9e0be65a0eb7123b5acd07131d6bf2c1
vendor/golang.org/x/crypto/bn256/gfp2.go type=file mode=0664 size=3792 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.432900967 sha512256digest=911f33cfa4e32c62faa65ebe0af7b54edcbbfd50375209f14273fe35ce6a405f
vendor/golang.org/x/crypto/bn256/gfp6.go type=file mode=0664 size=5777 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.432900967 sha512256digest=e4b37174a01be9bbf18ef0b058452de8a733266fe2793e1dfe9967ddb0563515
vendor/golang.org/x/crypto/bn256/optate.go type=file mode=0664 size=8667 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.432900967 sha512256digest=06e551794879e82a39a69f2eb74844f55bd36d20924e3a7380d7be58c960a872
vendor/golang.org/x/crypto/bn256/twist.go type=file mode=0664 size=5306 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.432900967 sha512256digest=5f78e24a835bd60ebd5af4d556ac1108f4f361300d7069aa4d242c028fb76cb3
vendor/golang.org/x/crypto/cast5 type=dir mode=0775 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.432900967
vendor/golang.org/x/crypto/cast5/cast5.go type=file mode=0664 size=32541 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.432900967 sha512256digest=c36e5698d13994bd8e27e4b7a15ff063db1c1fd4b3fc4d86920958df9167a4f3
vendor/golang.org/x/crypto/cast5/cast5_test.go type=file mode=0664 size=2624 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.432900967 sha512256digest=6088d6e97f054dff9ce1480afae0b91aa248e73a48faf1c6acf210d2b8557098
vendor/golang.org/x/crypto/curve25519 type=dir mode=0775 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.433900962
vendor/golang.org/x/crypto/curve25519/const_amd64.s type=file mode=0664 size=597 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.432900967 sha512256digest=8d7059b5263f3e64abb06e8e1d4abf8315f2a0c16495e84f69424a2630721006
vendor/golang.org/x/crypto/curve25519/cswap_amd64.s type=file mode=0664 size=1541 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.432900967 sha512256digest=37da1fbe15113a31497643b79165687a7e4163afc0ac0ea36c3d7628de7d3078
vendor/golang.org/x/crypto/curve25519/curve25519.go type=file mode=0664 size=22032 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.432900967 sha512256digest=2e24c7ca245ecd4d9b656338a801c3fab5875b7dc8eb7f0ad14062346b077d4d
vendor/golang.org/x/crypto/curve25519/curve25519_test.go type=file mode=0664 size=605 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.433900962 sha512256digest=53ef3c52714a7c3f9901b53f22c6dd4b3691b6471a588e55e78105adb71b7b4c
vendor/golang.org/x/crypto/curve25519/doc.go type=file mode=0664 size=1043 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.433900962 sha512256digest=e668799e8efdfb7b1a0f706346ed658e36513bfbef63f7191b79f35b9e6475b3
vendor/golang.org/x/crypto/curve25519/freeze_amd64.s type=file mode=0664 size=1540 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.433900962 sha512256digest=83cece5a83eff41c06d265e07de0c79b8cea0f0eba2a54c0c92980eb88cc241e
vendor/golang.org/x/crypto/curve25519/ladderstep_amd64.s type=file mode=0664 size=20422 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.433900962 sha512256digest=2009f13488ed4b547210c86886f5dd840c15427d1067eb2d856b20e088430aa8
vendor/golang.org/x/crypto/curve25519/mont25519_amd64.go type=file mode=0664 size=5262 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.433900962 sha512256digest=cdf4d03529d6a11d2cec2309fa920524a90f2c4fbb0eaeafdf396982fb30d32c
vendor/golang.org/x/crypto/curve25519/mul_amd64.s type=file mode=0664 size=2869 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.433900962 sha512256digest=8bb1581d8282d94dbf37983f7fa2778690fa9b37027404ead7efe8672b037d91
vendor/golang.org/x/crypto/curve25519/square_amd64.s type=file mode=0664 size=2349 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.433900962 sha512256digest=cc7355e0f4f3c1624276af40d2e100b7897510f2ae95be56a025df1a489a54ce
vendor/golang.org/x/crypto/hkdf type=dir mode=0775 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.433900962
vendor/golang.org/x/crypto/hkdf/example_test.go type=file mode=0664 size=1498 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.433900962 sha512256digest=e4044f70276a817e4595b1b5dd8bc89bb0764bc586c069d34c0f488418427b35
vendor/golang.org/x/crypto/hkdf/hkdf.go type=file mode=0664 size=1837 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.433900962 sha512256digest=10cc33ce4c7bcba4145bb235a8400564b4a632cfd081feede850100af33ac7af
vendor/golang.org/x/crypto/hkdf/hkdf_test.go type=file mode=0664 size=10871 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.433900962 sha512256digest=0aac96303c4b2e30ed07cc01d2d81e13c943454cad859a2265b6b5b94b03ad7c
vendor/golang.org/x/crypto/md4 type=dir mode=0775 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.433900962
vendor/golang.org/x/crypto/md4/md4.go type=file mode=0664 size=2124 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.433900962 sha512256digest=198ecc800bb0b351aa4f2cdf2fb490c720038e7bed43c2b64f2e8e8fde22ca78
vendor/golang.org/x/crypto/md4/md4_test.go type=file mode=0664 size=3307 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.433900962 sha512256digest=95a1a27481451dadb75aa8418636ab99f59d42ea72bf7fd14a402dbb042b5d4f
vendor/golang.org/x/crypto/md4/md4block.go type=file mode=0664 size=2036 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.433900962 sha512256digest=5a7049b30a80f749120670f187e71f5affd5333f8d2d8d8c4e47b935c3e43463
vendor/golang.org/x/crypto/nacl type=dir mode=0775 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.433900962
vendor/golang.org/x/crypto/nacl/box type=dir mode=0775 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.433900962
vendor/golang.org/x/crypto/nacl/box/box.go type=file mode=0664 size=3264 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.433900962 sha512256digest=dd140b441292a6c700a07ed5ec5a97f0be88b863a067840c7cfc67c13cf80ce4
vendor/golang.org/x/crypto/nacl/box/box_test.go type=file mode=0664 size=1904 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.433900962 sha512256digest=1869dc20e30b0f6288c60b15c3cb896c1132f2303339f5d110e03bb6d0b75704
vendor/golang.org/x/crypto/nacl/secretbox type=dir mode=0775 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.433900962
vendor/golang.org/x/crypto/nacl/secretbox/secretbox.go type=file mode=0664 size=4747 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.433900962 sha512256digest=44472e52cac37ba9fbc929e02cf9d130ded2ed1bb98feecb351c4c5d3b28262d
vendor/golang.org/x/crypto/nacl/secretbox/secretbox_test.go type=file mode=0664 size=2065 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.433900962 sha512256digest=8ce4c36c2bb550845f13ff92668e20bedb2be0025a8fb75c2530f618de9586ad
vendor/golang.org/x/crypto/ocsp type=dir mode=0775 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.434900957
vendor/golang.org/x/crypto/ocsp/ocsp.go type=file mode=0664 size=17554 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.434900957 sha512256digest=f4e66e3d111b30cbdc478ca68b4ebe6640a97266559d91a652db2e9e93b4418f
vendor/golang.org/x/crypto/ocsp/ocsp_test.go type=file mode=0664 size=23500 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.434900957 sha512256digest=85e9086879f3109d028909b97fecab89c09dc1ed50cf421fe7522ca04e948c12
vendor/golang.org/x/crypto/openpgp type=dir mode=0775 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.437900941
vendor/golang.org/x/crypto/openpgp/armor type=dir mode=0775 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.434900957
vendor/golang.org/x/crypto/openpgp/armor/armor.go type=file mode=0664 size=5026 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.434900957 sha512256digest=fd714e357b5ef7bab37830118cbdefbbec8eb283913eaa5f24be348a3347dc27
vendor/golang.org/x/crypto/openpgp/armor/armor_test.go type=file mode=0664 size=3102 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.434900957 sha512256digest=e261040ae16f64903cde837945ad3a81474a3b72a0f7551f6318830a1044ac70
vendor/golang.org/x/crypto/openpgp/armor/encode.go type=file mode=0664 size=3392 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.434900957 sha512256digest=7266294573e174cfb78e571a00cbb3e8d2f91908b80730eb066b8c2c7d87d9dc
vendor/golang.org/x/crypto/openpgp/canonical_text.go type=file mode=0664 size=1143 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.434900957 sha512256digest=4a3bfa165a78aa099605613e2b520985dbda9500c1c5e4a73a27114ff07e7a25
vendor/golang.org/x/crypto/openpgp/canonical_text_test.go type=file mode=0664 size=1202 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.434900957 sha512256digest=e531fddb89427fdaa50f1f6b56d3651bae5a0317f1253a9d881c8eaa3112f4c3
vendor/golang.org/x/crypto/openpgp/clearsign type=dir mode=0775 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.434900957
vendor/golang.org/x/crypto/openpgp/clearsign/clearsign.go type=file mode=0664 size=9457 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.434900957 sha512256digest=9bbff408119e071e5769be5882fd381cc0c464e3508b09e947a87617abdca76e
vendor/golang.org/x/crypto/openpgp/clearsign/clearsign_test.go type=file mode=0664 size=6104 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.434900957 sha512256digest=e381a011f4d710751cefd0f64cde30d8b275e82bf649c37b0bd67442f7f8c628
vendor/golang.org/x/crypto/openpgp/elgamal type=dir mode=0775 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.434900957
vendor/golang.org/x/crypto/openpgp/elgamal/elgamal.go type=file mode=0664 size=3543 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.434900957 sha512256digest=5c619abe82ea4d6b6e7533dabb23edfbf94b22502966883f302a8976aa089039
vendor/golang.org/x/crypto/openpgp/elgamal/elgamal_test.go type=file mode=0664 size=1589 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.434900957 sha512256digest=9cd4fe1b7d0d992d30a0657f238fcf0633d39df2dda7b80fdcbe5a415f90715f
vendor/golang.org/x/crypto/openpgp/errors type=dir mode=0775 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.435900952
vendor/golang.org/x/crypto/openpgp/errors/errors.go type=file mode=0664 size=1883 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.435900952 sha512256digest=da67ae346387c702f5cf9276a898e59c023522a00b6ac0b7d892ed2c78becd2e
vendor/golang.org/x/crypto/openpgp/keys.go type=file mode=0664 size=17806 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.435900952 sha512256digest=1a56374663da077c59b9be83b06cc3f2dce34fc6d622d0a7e3fb028f9266d694
vendor/golang.org/x/crypto/openpgp/keys_test.go type=file mode=0664 size=20358 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.435900952 sha512256digest=2186d10ac7393e1d76ad96d270b79757a8d8653a232da9539218951f3cd827f8
vendor/golang.org/x/crypto/openpgp/packet type=dir mode=0775 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.437900941
vendor/golang.org/x/crypto/openpgp/packet/compressed.go type=file mode=0664 size=3289 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.435900952 sha512256digest=adecbe682175746c0b3cc99301427af62feb7ff4d64c1ffc780811635e735a07
vendor/golang.org/x/crypto/openpgp/packet/compressed_test.go type=file mode=0664 size=897 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.435900952 sha512256digest=05b50262a8d4c64c1eaa50c7af7b63f783040e5de10786767ef69964ef7cf3d7
vendor/golang.org/x/crypto/openpgp/packet/config.go type=file mode=0664 size=2440 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.435900952 sha512256digest=00a82226c5f090c6eeb281dc7d403ef738d223e8d524429ea7ae201ae0e06c75
vendor/golang.org/x/crypto/openpgp/packet/encrypted_key.go type=file mode=0664 size=5166 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.435900952 sha512256digest=8bd50af79b58eb0b211111c59cb0a05723d9e0a08775536931402e55a65bc4ce
vendor/golang.org/x/crypto/openpgp/packet/encrypted_key_test.go type=file mode=0664 size=3564 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.435900952 sha512256digest=080566cfe10ab282aefa8ade0388f647e0ef5d5711c531011981d28d0afafbdc
vendor/golang.org/x/crypto/openpgp/packet/literal.go type=file mode=0664 size=1924 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.435900952 sha512256digest=996ba9ab21f2be954d24293920637763ce51b7fbdd9c79bebebf275e8d934add
vendor/golang.org/x/crypto/openpgp/packet/ocfb.go type=file mode=0664 size=3707 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.435900952 sha512256digest=65ba916f7d9281cc8c03c6052c07e31e1843b7462cb37e750e5692d0ab669041
vendor/golang.org/x/crypto/openpgp/packet/ocfb_test.go type=file mode=0664 size=1269 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.435900952 sha512256digest=f8dcff932881b568ecc34f6e147b000182704f07b17658c4d1ed28d70cab81d8
vendor/golang.org/x/crypto/openpgp/packet/one_pass_signature.go type=file mode=0664 size=1778 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.435900952 sha512256digest=9aed3906d54e5efe91f32aa2659de0776a71610411e5bb53d971c4a6cde29451
vendor/golang.org/x/crypto/openpgp/packet/opaque.go type=file mode=0664 size=4094 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.435900952 sha512256digest=64ae0e8f3c05a6a4e1c0fadc7a3dff3f61c0ac9a860d69b61a58dddad5717940
vendor/golang.org/x/crypto/openpgp/packet/opaque_test.go type=file mode=0664 size=2501 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.435900952 sha512256digest=0cfc6c1af52fc37cc846e7e0cf6c010047282e11bd6582f6be5b8d60f9f1a34f
vendor/golang.org/x/crypto/openpgp/packet/packet.go type=file mode=0664 size=13568 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.435900952 sha512256digest=148d34e2e129a6b5f5b14cbd1a2111647aef73c0305fe02f1518ba35efe16d6b
vendor/golang.org/x/crypto/openpgp/packet/packet_test.go type=file mode=0664 size=6342 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.436900946 sha512256digest=f5ddc5664c217d6edae5172fa5f6fdb40d8973577a87e00d2b5fc6ec4ebf69c4
vendor/golang.org/x/crypto/openpgp/packet/private_key.go type=file mode=0664 size=6917 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.436900946 sha512256digest=736844634714bbf73107bfd732e1da57111bb3ce218da32d917f1e839f3a73dd
vendor/golang.org/x/crypto/openpgp/packet/private_key_test.go type=file mode=0664 size=3102 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.436900946 sha512256digest=2c0d6b7879839aaeb264bec35d1a82324ea63c8e54575466a715391690d8070f
vendor/golang.org/x/crypto/openpgp/packet/public_key.go type=file mode=0664 size=19380 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.436900946 sha512256digest=22d25c31bbc85b9835e712cb38204579c51f3e5e153f01e917aa7728eac7a469
vendor/golang.org/x/crypto/openpgp/packet/public_key_test.go type=file mode=0664 size=8170 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.436900946 sha512256digest=a03f67f13a9237e6d15bbede91ccb84d06e82b2eb552a17fc6c72124c47be8b8
vendor/golang.org/x/crypto/openpgp/packet/public_key_v3.go type=file mode=0664 size=8001 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.436900946 sha512256digest=a1e5e33772018db138a971699b329191c6911700bf8eb945f6402bbc09a39a46
vendor/golang.org/x/crypto/openpgp/packet/public_key_v3_test.go type=file mode=0664 size=2366 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.436900946 sha512256digest=83569fd6889935de5cebace9ca2c9b7eabf7df08ec88857eb8b1fece963b5a08
vendor/golang.org/x/crypto/openpgp/packet/reader.go type=file mode=0664 size=1508 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.436900946 sha512256digest=381c0747bcda0beca356b8d0334ef78b463c04c8fcf1af17c020b475571174c3
vendor/golang.org/x/crypto/openpgp/packet/signature.go type=file mode=0664 size=19847 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.436900946 sha512256digest=00603958d0cc55177125789ff43f93bc859ae8dff577ae5d8610bcfab24ae2a2
vendor/golang.org/x/crypto/openpgp/packet/signature_test.go type=file mode=0664 size=1625 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.436900946 sha512256digest=50f7af45db15cb6b161743f87403fdbda207642de457eaaebae128c130550039
vendor/golang.org/x/crypto/openpgp/packet/signature_v3.go type=file mode=0664 size=3936 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.436900946 sha512256digest=8b4ff517dc9c1736ea8ff0cfc75c27352cc559f58eb75cea9182d847ecb38b3b
vendor/golang.org/x/crypto/openpgp/packet/signature_v3_test.go type=file mode=0664 size=2768 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.436900946 sha512256digest=eaa81e4b4060c33f827dfd606a74a66bd0650c72db23ee269d31da958ae454d2
vendor/golang.org/x/crypto/openpgp/packet/symmetric_key_encrypted.go type=file mode=0664 size=4736 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.436900946 sha512256digest=591057f74c8e6ddb10cdd376b4643cd9fdc24b6b6c1466319ff66274e1ad1463
vendor/golang.org/x/crypto/openpgp/packet/symmetric_key_encrypted_test.go type=file mode=0664 size=2464 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.436900946 sha512256digest=d3d0f9559db93771161657b268eafa6de1e10b28109735913755ee89d9fe717e
vendor/golang.org/x/crypto/openpgp/packet/symmetrically_encrypted.go type=file mode=0664 size=7244 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.436900946 sha512256digest=1103b66704f3a5de5cddad6ffa2a2ee957e6392b9737676a87549cf1c212525b
vendor/golang.org/x/crypto/openpgp/packet/symmetrically_encrypted_test.go type=file mode=0664 size=2811 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.437900941 sha512256digest=c89d1f8b13174327621f0cbf286a71e67c6b31e1e2ac37c66b1c6269eb2d1835
vendor/golang.org/x/crypto/openpgp/packet/userattribute.go type=file mode=0664 size=2534 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.437900941 sha512256digest=1df2601d86a3a7445f056a6d0cefb98c8f3a4a195e359b69703fad3868d94460
vendor/golang.org/x/crypto/openpgp/packet/userattribute_test.go type=file mode=0664 size=5873 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.437900941 sha512256digest=9491f937bb41e35da2c67f9e4a3ac1c18b735d85d48494dfb3daebb2b2052b5c
vendor/golang.org/x/crypto/openpgp/packet/userid.go type=file mode=0664 size=3518 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.437900941 sha512256digest=a6a4cdb224eff2e9713b00d5f6d582a5ad0440ed9250a4983511bce2b4f5fc0e
vendor/golang.org/x/crypto/openpgp/packet/userid_test.go type=file mode=0664 size=2308 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.437900941 sha512256digest=3e8f041dc105a2d807bf2634e384ab814a778538f6d82d5af95b8b777ffddf68
vendor/golang.org/x/crypto/openpgp/read.go type=file mode=0664 size=13011 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.437900941 sha512256digest=4b42631372013dccdcf71ba38486d471c34488c38985e44e9abc4ce91a14e1ad
vendor/golang.org/x/crypto/openpgp/read_test.go type=file mode=0664 size=35594 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.437900941 sha512256digest=d28d4c839d61daa75ca7cb21b7875f84e61cadaa0840a088c1407eac8b5bafac
vendor/golang.org/x/crypto/openpgp/s2k type=dir mode=0775 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.437900941
vendor/golang.org/x/crypto/openpgp/s2k/s2k.go type=file mode=0664 size=7191 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.437900941 sha512256digest=e605aac7209f947fac16b9dcf88bd439d84664b472976cda5ddcdaf738a83ab5
vendor/golang.org/x/crypto/openpgp/s2k/s2k_test.go type=file mode=0664 size=3244 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.437900941 sha512256digest=982e06de36758a70d17db7a1ac412ac30668e469372cc388b0374e537109ad16
vendor/golang.org/x/crypto/openpgp/write.go type=file mode=0664 size=11569 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.437900941 sha512256digest=0053b773963b78dc0202155677dc09906ef6e7bc1f70fc53935fd6e95c1cf1da
vendor/golang.org/x/crypto/openpgp/write_test.go type=file mode=0664 size=5769 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.437900941 sha512256digest=6452bddf4da69773644d31fccdfee40da8d70e35d4439947bd48732a7214a79f
vendor/golang.org/x/crypto/otr type=dir mode=0775 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.438900936
vendor/golang.org/x/crypto/otr/libotr_test_helper.c type=file mode=0664 size=5538 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.437900941 sha512256digest=4d83e23d963cb62e04f9939e1d4d347ef2bd70cc1fda8e6fa659fe8dee266e8a
vendor/golang.org/x/crypto/otr/otr.go type=file mode=0664 size=35866 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.438900936 sha512256digest=1726c522c18197e8cfa6052b1bfe54038faeca2fdb49a593c6edff446cd3ab2e
vendor/golang.org/x/crypto/otr/otr_test.go type=file mode=0664 size=12128 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.438900936 sha512256digest=8732ddf210b53102f7040b02ee3943215bcb3f69269874d4db5d1c0d86d40a45
vendor/golang.org/x/crypto/otr/smp.go type=file mode=0664 size=11982 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.438900936 sha512256digest=468f2cb9f1bf77631d1eb7c96bbc4a574bda0b38b8db41572db534a8ccf76ee7
vendor/golang.org/x/crypto/pbkdf2 type=dir mode=0775 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.438900936
vendor/golang.org/x/crypto/pbkdf2/pbkdf2.go type=file mode=0664 size=2484 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.438900936 sha512256digest=e4327789933349b342bc7e78ca8819563f51f6676095aacd1ab9e47e2b5b126e
vendor/golang.org/x/crypto/pbkdf2/pbkdf2_test.go type=file mode=0664 size=3261 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.438900936 sha512256digest=b73297d2911a29e1ba5d8784c9dc17dd6dc6f8289fbe287e6d204a3714676982
vendor/golang.org/x/crypto/poly1305 type=dir mode=0775 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.438900936
vendor/golang.org/x/crypto/poly1305/const_amd64.s type=file mode=0664 size=1585 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.438900936 sha512256digest=868380bb86c6df5d26d1ac3d2875b093b18b8f88a9def5615d51da76e086c604
vendor/golang.org/x/crypto/poly1305/poly1305.go type=file mode=0664 size=1280 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.438900936 sha512256digest=374d648ea2f6c58d942ba38a88dc060d3aa484364383c36fbcab54e0fab8fd13
vendor/golang.org/x/crypto/poly1305/poly1305_amd64.s type=file mode=0664 size=8501 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.438900936 sha512256digest=d58606faf9490f1de48fa186129b1c6deada09b29807156fede97fa1b4411ad8
vendor/golang.org/x/crypto/poly1305/poly1305_test.go type=file mode=0664 size=1548 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.438900936 sha512256digest=7d5e1af6be7fe92af67f49b67e6677ec9b0f4b1e128e7312a5e101cefc683095
vendor/golang.org/x/crypto/poly1305/sum_amd64.go type=file mode=0664 size=690 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.438900936 sha512256digest=2a77e9768db8741fc9d523e2d35893c09167caca46a18312ad5e9d63dd77e0b9
vendor/golang.org/x/crypto/poly1305/sum_ref.go type=file mode=0664 size=20830 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.438900936 sha512256digest=9d61336ce2b45e30daa00573ffee77a7fb098dc6e195da6266b390dec067d6dd
vendor/golang.org/x/crypto/ripemd160 type=dir mode=0775 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.438900936
vendor/golang.org/x/crypto/ripemd160/ripemd160.go type=file mode=0664 size=2476 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.438900936 sha512256digest=eb2bffaae443aef72931d6bd212aecd0be13349f675b7e6f4f9800cde40e8bb1
vendor/golang.org/x/crypto/ripemd160/ripemd160_test.go type=file mode=0664 size=1791 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.438900936 sha512256digest=10141ac7e5b05e08e4e1866646f7df2df55e9fe95f1dde32b106987d0b0b0480
vendor/golang.org/x/crypto/ripemd160/ripemd160block.go type=file mode=0664 size=4257 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.438900936 sha512256digest=b9f1981e13546cc75bfb1db199fba960388718176950c5857508dc3a9fd8c997
vendor/golang.org/x/crypto/salsa20 type=dir mode=0775 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.439900931
vendor/golang.org/x/crypto/salsa20/salsa type=dir mode=0775 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.439900931
vendor/golang.org/x/crypto/salsa20/salsa/hsalsa20.go type=file mode=0664 size=4098 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.439900931 sha512256digest=a08dc45427b8ff5b1f3ac216b4b7e21c6739afc2d0ae4d18a70a8f7cc8b6e352
vendor/golang.org/x/crypto/salsa20/salsa/salsa2020_amd64.s type=file mode=0664 size=13929 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.439900931 sha512256digest=ca7bc54db396ea5222791c76ba9a95572d09e91861aeb48664faa84ea346d53c
vendor/golang.org/x/crypto/salsa20/salsa/salsa208.go type=file mode=0664 size=4983 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.439900931 sha512256digest=9825dfd3b0ccb54e5900e62595ac931ef987e7319aa19217edb7c1a473074ea4
vendor/golang.org/x/crypto/salsa20/salsa/salsa20_amd64.go type=file mode=0664 size=763 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.439900931 sha512256digest=f551fd3a1a02b4f47a62fc7e2af30ac1b23dc49d6e8977f6f7bdf2dc1db9627d
vendor/golang.org/x/crypto/salsa20/salsa/salsa20_ref.go type=file mode=0664 size=5752 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.439900931 sha512256digest=d8b188cbf0ba29e6945f334b1103bb8b2e146cd4f82413208633c51006d4aca8
vendor/golang.org/x/crypto/salsa20/salsa/salsa_test.go type=file mode=0664 size=1149 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.439900931 sha512256digest=53026559296b4a3776bc81922b0c3fe5ef4e5835a0d62874b566108c2080a6e2
vendor/golang.org/x/crypto/salsa20/salsa20.go type=file mode=0664 size=1919 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.439900931 sha512256digest=2620142a4713ab1a21da3ff76edfe9c115cf2dc2db8307b9f208fa96f5280780
vendor/golang.org/x/crypto/salsa20/salsa20_test.go type=file mode=0664 size=3771 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.439900931 sha512256digest=6ff0e6274b13e84f03e7d96f745f5839b566d02a43b39a232cf430da682b852f
vendor/golang.org/x/crypto/scrypt type=dir mode=0775 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.439900931
vendor/golang.org/x/crypto/scrypt/scrypt.go type=file mode=0664 size=5866 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.439900931 sha512256digest=47d016aa178d7e4195a8351dbe9015c26aac1b89a375ae5b98d15ea5f67b8b79
vendor/golang.org/x/crypto/scrypt/scrypt_test.go type=file mode=0664 size=4455 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.439900931 sha512256digest=ee694200743f2fd4bc26f4ae4368cbd307b49399d1e1e2c9bfe195e7ce296b4a
vendor/golang.org/x/crypto/sha3 type=dir mode=0775 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.440900925
vendor/golang.org/x/crypto/sha3/doc.go type=file mode=0664 size=3190 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.439900931 sha512256digest=af288b26f47e4f23bfd02a0e907315dfa4a60269189c640ef75ddaf2e5c5169f
vendor/golang.org/x/crypto/sha3/hashes.go type=file mode=0664 size=1909 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.439900931 sha512256digest=e292f93708072e3e09bb21049046c8e2edea434f6679eb85137c2835ed406b95
vendor/golang.org/x/crypto/sha3/keccakf.go type=file mode=0664 size=9920 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.439900931 sha512256digest=64ef19e0d0b7504d6123fcd375b7dd33394484ec73b26a7db785740bf79cc053
vendor/golang.org/x/crypto/sha3/register.go type=file mode=0664 size=413 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.439900931 sha512256digest=b73fb07d6b614529c74265aee400e404e973955e3bc979707061d6ebdb7c8b14
vendor/golang.org/x/crypto/sha3/sha3.go type=file mode=0664 size=5821 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.439900931 sha512256digest=5793dbb766e0ae6d54a40098e9cdfab28300525f6365431f7d36f6b32d43b265
vendor/golang.org/x/crypto/sha3/sha3_test.go type=file mode=0664 size=8887 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.439900931 sha512256digest=0d7139bbc4eff00afc1b5bbb940c8f42ce7eb660bbc4da7abb95443c9a5e8a33
vendor/golang.org/x/crypto/sha3/shake.go type=file mode=0664 size=1847 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.439900931 sha512256digest=3c48cd175445e52f95bfa9e874564bad0f548eaf57aafab2355f05bfbe535880
vendor/golang.org/x/crypto/sha3/testdata type=dir mode=0775 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.439900931
vendor/golang.org/x/crypto/sha3/testdata/keccakKats.json.deflate type=file mode=0664 size=521342 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.440900925 sha512256digest=e1c6d2c9f1b72c3cb256ed89d792b5d45d9918b0be9167e18c087a1bea40a1c7
vendor/golang.org/x/crypto/sha3/xor.go type=file mode=0664 size=397 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.440900925 sha512256digest=e9715de8a4cb248f43844a9f7be46f108d63f4cc4b86da447359edec12721dda
vendor/golang.org/x/crypto/sha3/xor_generic.go type=file mode=0664 size=680 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.440900925 sha512256digest=929eb30da60b8fb2b8bad6fcb3576475f25f70fba1a0d6a8130a0fed732c54cc
vendor/golang.org/x/crypto/sha3/xor_unaligned.go type=file mode=0664 size=1066 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.440900925 sha512256digest=08f85fd66c354189243f1dc99c00282fb105b7e2b3d40055cc73a6f1382a66a2
vendor/golang.org/x/crypto/ssh type=dir mode=0775 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.445900899
vendor/golang.org/x/crypto/ssh/agent type=dir mode=0775 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.441900920
vendor/golang.org/x/crypto/ssh/agent/client.go type=file mode=0664 size=13381 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.440900925 sha512256digest=f0cf9fec51893c03e7e4894c0bdb53e473e2190faf6956ab2d68b68c5c6c01ea
vendor/golang.org/x/crypto/ssh/agent/client_test.go type=file mode=0664 size=6902 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.440900925 sha512256digest=a1e796a312222c67871b658d365d7820a0022dcff66a0998f2d2474c9e5ca814
vendor/golang.org/x/crypto/ssh/agent/forward.go type=file mode=0664 size=2214 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.441900920 sha512256digest=e631ebeaf66b3071580abd406bc662fb68d208557c0f95fe2d51529ac60db2ea
vendor/golang.org/x/crypto/ssh/agent/keyring.go type=file mode=0664 size=3636 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.441900920 sha512256digest=2850e7217bfe6a03a7579dbb8f431eb4a01d5bd5ff2bf00e297e730b330547a6
vendor/golang.org/x/crypto/ssh/agent/server.go type=file mode=0664 size=4451 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.441900920 sha512256digest=e02ea70abbb9b3f5ccf8fa80df2e8632611f1a595f51eff438bf78402e7fc0dc
vendor/golang.org/x/crypto/ssh/agent/server_test.go type=file mode=0664 size=1646 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.441900920 sha512256digest=eee9c87cd6b27f9815964bb42c034b60b465da7d2a75b583dcb33bec1e384155
vendor/golang.org/x/crypto/ssh/agent/testdata_test.go type=file mode=0664 size=2223 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.441900920 sha512256digest=ce5d6a9d303ce20d7db0cef98fc4fdf33e28029c10403be48c433eef1da48bfe
vendor/golang.org/x/crypto/ssh/benchmark_test.go type=file mode=0664 size=2240 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.441900920 sha512256digest=cacb493253628206c39e6971ba955347736f6770c13aa8e680f9321dfb165c14
vendor/golang.org/x/crypto/ssh/buffer.go type=file mode=0664 size=2198 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.441900920 sha512256digest=824c0c8e8f221a68a105bb08a3eb1c3d9f3849fe0485b571029e94c79133d7ed
vendor/golang.org/x/crypto/ssh/buffer_test.go type=file mode=0664 size=2220 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.441900920 sha512256digest=5ae9c9646f732ef5ec86e7d9768327e9f5e35e2c4fd1ae78373390de0131267e
vendor/golang.org/x/crypto/ssh/certs.go type=file mode=0664 size=12773 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.441900920 sha512256digest=5dddd8a2d3d212015434995d9d50279771cbcaf549a3531280b9acecc893bcd9
vendor/golang.org/x/crypto/ssh/certs_test.go type=file mode=0664 size=4632 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.441900920 sha512256digest=df67d08e8abee28ef6ec5e6886956559c6d283716b43da2a6d98ad47d64de277
vendor/golang.org/x/crypto/ssh/channel.go type=file mode=0664 size=16003 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.441900920 sha512256digest=5883b21db7cf6bac7544353fa856d4751e5b6ef7f6e6afb55947344cd2b74787
vendor/golang.org/x/crypto/ssh/cipher.go type=file mode=0664 size=8992 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.441900920 sha512256digest=1f9628e738d59032d159b67f2ce49feeec056f095bfe62b08e67c507c3a5ac26
vendor/golang.org/x/crypto/ssh/cipher_test.go type=file mode=0664 size=1395 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.441900920 sha512256digest=0179df5b60e6a8080e4b31a45e6f4345fb8f4dc8f4cee7bc9ae99826afeeb108
vendor/golang.org/x/crypto/ssh/client.go type=file mode=0664 size=6054 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.441900920 sha512256digest=d30f0d102026bb78cb7d8013ae974c8fee1281d0f6b7270b18c76175ec7b9244
vendor/golang.org/x/crypto/ssh/client_auth.go type=file mode=0664 size=11942 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.442900915 sha512256digest=6914b2e6396f7ef7072783cbded541cae898eda0758a61e9667e0bfd62fe10ad
vendor/golang.org/x/crypto/ssh/client_auth_test.go type=file mode=0664 size=10085 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.442900915 sha512256digest=d7b67bfec3559ccb5d7a811da5567c44bea404a8dade62e10bca21f047785588
vendor/golang.org/x/crypto/ssh/client_test.go type=file mode=0664 size=969 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.442900915 sha512256digest=8271743ef8df9d930d98e895e3d65ab558d3c6c5203445f7bfb58c81a35ea031
vendor/golang.org/x/crypto/ssh/common.go type=file mode=0664 size=9173 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.442900915 sha512256digest=9a8f921bd96313452816683dc0d1b1974f3130275080df236369feb88e1f84f7
vendor/golang.org/x/crypto/ssh/connection.go type=file mode=0664 size=3457 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.442900915 sha512256digest=811635959bfe6c462844d501b5c9784a100ee99d9742a74989ccb7e88f5b98b1
vendor/golang.org/x/crypto/ssh/doc.go type=file mode=0664 size=771 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.442900915 sha512256digest=5ec367435a18dfdece2fea6f2ee3694bfb9d04724bfa745c9eb0fbc26114225e
vendor/golang.org/x/crypto/ssh/example_test.go type=file mode=0664 size=5530 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.442900915 sha512256digest=f822ecf3a659336d45e16e78ac296ff0e8e785443cd1f7f1d99e9ea1d01c6a9c
vendor/golang.org/x/crypto/ssh/handshake.go type=file mode=0664 size=9852 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.442900915 sha512256digest=fb21b28cab3bbfc6909905318125dd8c1f4107a8c3967d4e71ece7f7fbd47b11
vendor/golang.org/x/crypto/ssh/handshake_test.go type=file mode=0664 size=7343 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.442900915 sha512256digest=5597f84d0eaf571a593a2894a0ea4378d13b6deabf2e173bd351c2a6283500c9
vendor/golang.org/x/crypto/ssh/kex.go type=file mode=0664 size=10119 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.442900915 sha512256digest=54ff5406781208f812ebd48b5abd4830d607b7860b6805535a34f0cd7a12bdde
vendor/golang.org/x/crypto/ssh/kex_test.go type=file mode=0664 size=1048 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.442900915 sha512256digest=0f699b3226d66922f91f1f61855e5ae8a13c35a364ef84dd296a8de0ce08ad0c
vendor/golang.org/x/crypto/ssh/keys.go type=file mode=0664 size=15079 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.443900909 sha512256digest=f0ff3e0127bb3dab71fbcd390d80147d3a58c02076d4a19387e04b293a985247
vendor/golang.org/x/crypto/ssh/keys_test.go type=file mode=0664 size=8724 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.443900909 sha512256digest=9c453fc0419b8e7d9e45b42e08958f7816a2671a5be4181a2a89c5391eaa1faa
vendor/golang.org/x/crypto/ssh/mac.go type=file mode=0664 size=1088 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.443900909 sha512256digest=1ec064847ffa0c8559d0fdc2427a7758800b7628721a6a27b5b0ca0fc281aa45
vendor/golang.org/x/crypto/ssh/mempipe_test.go type=file mode=0664 size=2020 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.443900909 sha512256digest=b5531caedc0a29970ab0b8b138b0da7452e8f548eafb86cb531a647e8e758dcc
vendor/golang.org/x/crypto/ssh/messages.go type=file mode=0664 size=16798 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.443900909 sha512256digest=2ca5a71322c6d54b3bce36c1f71b4432b5301ca0d8c264d0e9629437d87d6f27
vendor/golang.org/x/crypto/ssh/messages_test.go type=file mode=0664 size=5236 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.443900909 sha512256digest=54e422acfe5043cbd4e51bd0eaa8ac95a8c9316536d9fc2d3c4389957bfd6ba1
vendor/golang.org/x/crypto/ssh/mux.go type=file mode=0664 size=7977 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.443900909 sha512256digest=20cc881c08d1895a3726903e325f57b0a7a9f05173fef90f283c1bd952915558
vendor/golang.org/x/crypto/ssh/mux_test.go type=file mode=0664 size=11321 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.443900909 sha512256digest=a41bba8d62eee12dd424381fad56b20c7a19d90d027280a31199bdfcb0ad71ca
vendor/golang.org/x/crypto/ssh/server.go type=file mode=0664 size=14515 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.443900909 sha512256digest=510d9f14aa556c282c776ef8208b4bfe587cd3a5382bc8554ae2e9b024f004f2
vendor/golang.org/x/crypto/ssh/session.go type=file mode=0664 size=14236 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.443900909 sha512256digest=d25a238f4a7a1c572ff862572dc714cb8e880c88ee5d762a36f2e22d59354d57
vendor/golang.org/x/crypto/ssh/session_test.go type=file mode=0664 size=17398 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.444900904 sha512256digest=2e6dff4f32b5894c0fcac7f1fcf98f99a892189149fab6693d627a3462f088e2
vendor/golang.org/x/crypto/ssh/tcpip.go type=file mode=0664 size=10469 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.444900904 sha512256digest=e254e27950bf25e48b6181acabe242942cb89eac6968b910e5ce8a09a42a7253
vendor/golang.org/x/crypto/ssh/tcpip_test.go type=file mode=0664 size=496 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.444900904 sha512256digest=8d5211a3008ca53f120be7988d5f15071a96a968db72d21a9304e9ddc0b1a9d8
vendor/golang.org/x/crypto/ssh/terminal type=dir mode=0775 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.444900904
vendor/golang.org/x/crypto/ssh/terminal/terminal.go type=file mode=0664 size=20992 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.444900904 sha512256digest=9da93725ad97cb0b7984fdec297dc30db5c8172a2b31ccc177cc74299fea822e
vendor/golang.org/x/crypto/ssh/terminal/terminal_test.go type=file mode=0664 size=5334 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.444900904 sha512256digest=c9037e9bb9f3f70177437fcb09679e01916b3b83e33c0251d3cc3432bfecd8ae
vendor/golang.org/x/crypto/ssh/terminal/util.go type=file mode=0664 size=4025 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.444900904 sha512256digest=01d19c877d21a1ff519f6a056b3595a6bcfeb83f5cc03731344cb54aa6304cf2
vendor/golang.org/x/crypto/ssh/terminal/util_bsd.go type=file mode=0664 size=332 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.444900904 sha512256digest=7bce0ed5ed05201c9a7ca18f5073473633730ac2d1bad9a12ff10fc3c7e92fa7
vendor/golang.org/x/crypto/ssh/terminal/util_linux.go type=file mode=0664 size=457 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.444900904 sha512256digest=82819f84cebea56c71d7c24967ebbd2bef70998637cc62ca3f6d5f35e6a762d8
vendor/golang.org/x/crypto/ssh/terminal/util_windows.go type=file mode=0664 size=4423 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.444900904 sha512256digest=2b0d8fdaab4bbae108661eeb457f518bcf80d48cf67fb30cb9bae142c5aff17b
vendor/golang.org/x/crypto/ssh/test type=dir mode=0775 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.444900904
vendor/golang.org/x/crypto/ssh/test/agent_unix_test.go type=file mode=0664 size=1271 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.444900904 sha512256digest=bbbcefe888ef99fc65b74f91b65a7b096193333fdac3dcca2a90170b87f52756
vendor/golang.org/x/crypto/ssh/test/cert_test.go type=file mode=0664 size=1096 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.444900904 sha512256digest=8b54dbb9c3bcaec5e60f8cd236022e623dab8331018077779ceab532f43b5c87
vendor/golang.org/x/crypto/ssh/test/doc.go type=file mode=0664 size=309 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.444900904 sha512256digest=f76d97f2da6554ee7f72617707e38419f05b2a5527fcc7993a19b2f6d51939e2
vendor/golang.org/x/crypto/ssh/test/forward_unix_test.go type=file mode=0664 size=3297 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.444900904 sha512256digest=fa6d2a1d93fbefd55d8179b63f22d7a9ab31d1f25fcf8da863e62199c7f6301a
vendor/golang.org/x/crypto/ssh/test/session_test.go type=file mode=0664 size=7075 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.444900904 sha512256digest=922e4fa0837c9c067eef33c6da1f36726bc9a761380e40a44625d6431c380f56
vendor/golang.org/x/crypto/ssh/test/tcpip_test.go type=file mode=0664 size=791 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.444900904 sha512256digest=5cbfc65be04f9191137589879bfc14350cbbfdd504642b08c37522472853a899
vendor/golang.org/x/crypto/ssh/test/test_unix_test.go type=file mode=0664 size=5877 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.444900904 sha512256digest=4e7660d40f097c87d9ab815a7bc2ea6bf2470fbd7a14f19c23244974408e5d16
vendor/golang.org/x/crypto/ssh/test/testdata_test.go type=file mode=0664 size=2222 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.444900904 sha512256digest=d586900390d00c0c02cfac0cf2b32a371c7cc36ef6f0dea8023979ab154febec
vendor/golang.org/x/crypto/ssh/testdata type=dir mode=0775 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.445900899
vendor/golang.org/x/crypto/ssh/testdata/doc.go type=file mode=0664 size=418 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.445900899 sha512256digest=24b5b64697da8d1742f071127c836efe4a0a4834589b1c5bb376741d51478f10
vendor/golang.org/x/crypto/ssh/testdata/keys.go type=file mode=0664 size=1916 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.445900899 sha512256digest=19a366ead0a070dd9f01411b02b3fd6fdf4bed6b3ed613dd1665d6fe79afb675
vendor/golang.org/x/crypto/ssh/testdata_test.go type=file mode=0664 size=2158 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.445900899 sha512256digest=fac0ad360dd0f1a99bde8cb772ba9b906a66facddc6e18f8146444fc192fccaf
vendor/golang.org/x/crypto/ssh/transport.go type=file mode=0664 size=8703 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.445900899 sha512256digest=3ccccff7d8faf1623e75a548fda6517d0871cce2f82b15a0abb1cf4773684009
vendor/golang.org/x/crypto/ssh/transport_test.go type=file mode=0664 size=2581 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.445900899 sha512256digest=e128680809ae8ced7c8b5bd5e58aa4cc813f67c96b47737aec050376f37ea8e1
vendor/golang.org/x/crypto/twofish type=dir mode=0775 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.445900899
vendor/golang.org/x/crypto/twofish/twofish.go type=file mode=0664 size=11966 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.445900899 sha512256digest=36212f712cd64514191deafcb83cc0c03c98352e8a9e8d808318e41d1e6fffb4
vendor/golang.org/x/crypto/twofish/twofish_test.go type=file mode=0664 size=4851 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.445900899 sha512256digest=cacd3e89572a5f5ab2c981dbc3151b6cb7a29567e7de4a9c6a7d3635486f3224
vendor/golang.org/x/crypto/xtea type=dir mode=0775 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.445900899
vendor/golang.org/x/crypto/xtea/block.go type=file mode=0664 size=1807 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.445900899 sha512256digest=c34c9ca0e5e39db0ee2ca0b19278176979e8eaef082bd610e5c55bb1befb09bb
vendor/golang.org/x/crypto/xtea/cipher.go type=file mode=0664 size=2436 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.445900899 sha512256digest=77780a45a1a5a3fc72807552bd9ebc5e7d1bf8d34dafbe1c818c439f252c48ce
vendor/golang.org/x/crypto/xtea/xtea_test.go type=file mode=0664 size=7417 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.445900899 sha512256digest=eaf72d92ac9c3bd17af55ce576ab48641af2d4ef138231800f9daddc4ad298b4
vendor/golang.org/x/crypto/xts type=dir mode=0775 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.445900899
vendor/golang.org/x/crypto/xts/xts.go type=file mode=0664 size=4500 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.445900899 sha512256digest=b13eeec77e4f1290c5a6819ced5dbc0a90499961fa3738441679450f064c5abf
vendor/golang.org/x/crypto/xts/xts_test.go type=file mode=0664 size=8511 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.445900899 sha512256digest=b03cbba79c93ad20dedd41dc2416634da95dafd4cb1fded45e37c1e72f43357f
vendor/golang.org/x/sys type=dir mode=0775 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.467900783
vendor/golang.org/x/sys/.gitattributes type=file mode=0664 size=345 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.445900899 sha512256digest=121f311806f70b4e9278a7a7178bbb73cb8afc0ce20d6134f24cf6a9f637cf85
vendor/golang.org/x/sys/.gitignore type=file mode=0664 size=84 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.445900899 sha512256digest=c1bc3cda1eb014d25dbebe52e50c7231f60762092811d111e2b60b2a847984d5
vendor/golang.org/x/sys/AUTHORS type=file mode=0664 size=173 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.445900899 sha512256digest=2e6b61f243b5f5e42e480c2d4588f1538ff08617ce66c01e99589333d4199a2e
vendor/golang.org/x/sys/CONTRIBUTING.md type=file mode=0664 size=1031 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.445900899 sha512256digest=9f99f8daf18ff8de732527ac23231c253c9800139002bf2b03250fce7372fdfb
vendor/golang.org/x/sys/CONTRIBUTORS type=file mode=0664 size=170 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.446900894 sha512256digest=261a74c469ed7777fd933f3cd1544b351d162ad51d5cedb570aab4da0fbc62d7
vendor/golang.org/x/sys/LICENSE type=file mode=0664 size=1479 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.446900894 sha512256digest=ea1cff0ac6655ef2801edc8f18ba083c7fae87b0fb0c542ea1d9628e46992f19
vendor/golang.org/x/sys/PATENTS type=file mode=0664 size=1303 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.446900894 sha512256digest=2ea07f77ca1c22dc417acfa6942f0faf5f545f44bca4c9387dab0e6e5ca442af
vendor/golang.org/x/sys/README.md type=file mode=0664 size=628 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.446900894 sha512256digest=4181c831648424320a2021eabe96ba5dd22b4ea951fe7adce5d5826ce05f005e
vendor/golang.org/x/sys/codereview.cfg type=file mode=0664 size=21 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.446900894 sha512256digest=6c7d6dcbcc4c211ab4c82aa98d2b61bf9c5fcbc72e607e6800eb85d3af3c6b1a
vendor/golang.org/x/sys/plan9 type=dir mode=0775 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.447900888
vendor/golang.org/x/sys/plan9/asm.s type=file mode=0664 size=215 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.446900894 sha512256digest=5a3d197e8fabcda93134bcc11c5bdb171a6df3c4b01587cafb92b96cdcb4a8fa
vendor/golang.org/x/sys/plan9/asm_plan9_386.s type=file mode=0664 size=702 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.446900894 sha512256digest=22ba41e4bef8ee9849a1f995db164ffc5fa32e730923ce754017bcb35c4a063d
vendor/golang.org/x/sys/plan9/asm_plan9_amd64.s type=file mode=0664 size=704 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.446900894 sha512256digest=f75d590eab0ea207a360d6d211053d4f4c0f968dc7cc7c11ae06cf82db367022
vendor/golang.org/x/sys/plan9/const_plan9.go type=file mode=0664 size=1004 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.446900894 sha512256digest=4dad6553dd157eedfe97742d095e19b018d9d184e0d9d8422380793a960e9082
vendor/golang.org/x/sys/plan9/dir_plan9.go type=file mode=0664 size=5734 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.446900894 sha512256digest=206de341d6fc697b39175f3a1e5075768c32a48c65e3f60245e006eceba5628d
vendor/golang.org/x/sys/plan9/env_plan9.go type=file mode=0664 size=489 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.446900894 sha512256digest=34cd7e466b514dc08f4d27b2013512251f922bd8f61f5061e5ffd2f5ceacd153
vendor/golang.org/x/sys/plan9/env_unset.go type=file mode=0664 size=307 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.446900894 sha512256digest=13fb763dd3caaa775e66ab434f8da4c08c31331246dee76ee1382682a7fd7f87
vendor/golang.org/x/sys/plan9/errors_plan9.go type=file mode=0664 size=1566 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.446900894 sha512256digest=3c668aec0f76b7f92911f18e86c8f92c4b441f64bdcf9fbefc452f0f6e4cca58
vendor/golang.org/x/sys/plan9/mkall.sh type=file mode=0775 size=4168 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.446900894 sha512256digest=cddd84a6e5b34f35544710f9c04ab57209bd82ff60ec62fed903a3f1864f302c
vendor/golang.org/x/sys/plan9/mkerrors.sh type=file mode=0775 size=6072 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.446900894 sha512256digest=e6e3e69647827ab44983cae89884bf4fea84cc834224f0f794fb305048d02923
vendor/golang.org/x/sys/plan9/mksyscall.pl type=file mode=0775 size=8021 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.446900894 sha512256digest=3b35c22a555900734ba4dde0a3d526429aef479e1b22c17a7da9937a8543d3ce
vendor/golang.org/x/sys/plan9/mksysnum_plan9.sh type=file mode=0775 size=459 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.446900894 sha512256digest=e0d11c3df396de0fe85337441832431bf5d68d225a81663d89c11ac8aff0c1c8
vendor/golang.org/x/sys/plan9/pwd_go15_plan9.go type=file mode=0664 size=372 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.446900894 sha512256digest=83789ed1a05a8a89640f3e2e3a34a5767db34c9cb67cd887d23d85328ba7ae2d
vendor/golang.org/x/sys/plan9/pwd_plan9.go type=file mode=0664 size=412 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.446900894 sha512256digest=21b0d0b25128d2f05ad887b3f2a36980b50c30659b7afb267d50ebdaf247f3e6
vendor/golang.org/x/sys/plan9/race.go type=file mode=0664 size=584 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.446900894 sha512256digest=55e9443d6e17a1fd16548deab237b97309181fc5d8178945c80e7fe31fc773bf
vendor/golang.org/x/sys/plan9/race0.go type=file mode=0664 size=447 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.446900894 sha512256digest=95d252584ca609d6c95dabf4e55f45b82eb1bbf4f8baf08dc101965282d38502
vendor/golang.org/x/sys/plan9/str.go type=file mode=0664 size=499 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.446900894 sha512256digest=cb3e9d88c984ca1df8e389478d118fde3daf8bef24b899cd0c514681b775a014
vendor/golang.org/x/sys/plan9/syscall.go type=file mode=0664 size=2532 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.447900888 sha512256digest=29d56098a10fb715a78c7e721d917c997858b0522b7620b1fb715d87d58d99be
vendor/golang.org/x/sys/plan9/syscall_plan9.go type=file mode=0664 size=7182 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.447900888 sha512256digest=1f341831c56d56bc6b551697fd34c141bcc48c986bef9f5d95065fbbd4954d23
vendor/golang.org/x/sys/plan9/syscall_test.go type=file mode=0664 size=782 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.447900888 sha512256digest=801d44414ede88e0edd6d5aadbffb3e1c1bbf0064482362c16be80dbfd762829
vendor/golang.org/x/sys/plan9/zsyscall_plan9_386.go type=file mode=0664 size=6539 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.447900888 sha512256digest=754df0ad7ec30111f18c0dd6f25be38db868c018517b418fefbbb93aa8a2d131
vendor/golang.org/x/sys/plan9/zsyscall_plan9_amd64.go type=file mode=0664 size=6539 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.447900888 sha512256digest=754df0ad7ec30111f18c0dd6f25be38db868c018517b418fefbbb93aa8a2d131
vendor/golang.org/x/sys/plan9/zsysnum_plan9.go type=file mode=0664 size=1057 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.447900888 sha512256digest=98b81b36ae64287761f468dd265073d3ef00fbffd959c726cedae03dfc582c0e
vendor/golang.org/x/sys/unix type=dir mode=0775 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.467900783
vendor/golang.org/x/sys/unix/.gitignore type=file mode=0664 size=6 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.447900888 sha512256digest=1793186c7cc109798a73b563d7e04d626a832a2de511b47b91adbe2ccac72cc9
vendor/golang.org/x/sys/unix/README.md type=file mode=0664 size=8271 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.447900888 sha512256digest=89d4796bb14f104b6b537db55d1227024b8a497f69c65732a91a603462cb9ad6
vendor/golang.org/x/sys/unix/asm_darwin_386.s type=file mode=0664 size=675 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.447900888 sha512256digest=726d7e55ddedbf9c6cf9bbcadd5aad631e81afd4b87d14a3f1ae0ef86e42d470
vendor/golang.org/x/sys/unix/asm_darwin_amd64.s type=file mode=0664 size=678 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.447900888 sha512256digest=ec946919220894a801322261a56193f02134dceb6f4e2d95e2bcada391802d99
vendor/golang.org/x/sys/unix/asm_darwin_arm.s type=file mode=0664 size=686 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.447900888 sha512256digest=aba41df4736ad5cf04990b4a69e385752b2e471823672fcd981b70bb0b5656a5
vendor/golang.org/x/sys/unix/asm_darwin_arm64.s type=file mode=0664 size=691 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.447900888 sha512256digest=f8e8e3e17de0dee99358680292805ffd69d3183ad00b73f5072c9225ab2b6227
vendor/golang.org/x/sys/unix/asm_dragonfly_amd64.s type=file mode=0664 size=681 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.447900888 sha512256digest=dd2e709a396b4b3673456d4b6e9f307b52e96d50c3663e7e0cef6890fd126262
vendor/golang.org/x/sys/unix/asm_freebsd_386.s type=file mode=0664 size=676 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.447900888 sha512256digest=170cf69100db944eb055beb7144c3e4b3a43012b661f5b587044085cb081f471
vendor/golang.org/x/sys/unix/asm_freebsd_amd64.s type=file mode=0664 size=679 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.447900888 sha512256digest=74d959abf910b671bb9d5e96cf8fa1aeaf7ca256d30d33d1c1d2a99e4c2cb7e3
vendor/golang.org/x/sys/unix/asm_freebsd_arm.s type=file mode=0664 size=666 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.447900888 sha512256digest=0d34b34692ea2b2685ff9734874efe562d60eee613863ae1779c977a60b4f6c0
vendor/golang.org/x/sys/unix/asm_linux_386.s type=file mode=0664 size=797 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.447900888 sha512256digest=9428798ab945dacc931a7ae180a024024d09813dd25b504b8b7b4c602fe50f20
vendor/golang.org/x/sys/unix/asm_linux_amd64.s type=file mode=0664 size=677 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.447900888 sha512256digest=f67b38dcda396c7a22e2e8e01e0140dafb50d2cfc5192e024209a9072d9f85e4
vendor/golang.org/x/sys/unix/asm_linux_arm.s type=file mode=0664 size=649 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.447900888 sha512256digest=b233d7ccf7cea17a8ac70792ddc90cc44de4c093ece28a24df58a443d01b0247
vendor/golang.org/x/sys/unix/asm_linux_arm64.s type=file mode=0664 size=591 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.448900883 sha512256digest=687a1f04da242234b2da964cff7760b8342a790714cea57ecf3f893eeb463a0d
vendor/golang.org/x/sys/unix/asm_linux_mips64x.s type=file mode=0664 size=650 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.448900883 sha512256digest=24e16b2816b8d2c41175442855da8ecd128be257983c5b272fee02406c6a0645
vendor/golang.org/x/sys/unix/asm_linux_mipsx.s type=file mode=0664 size=706 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.448900883 sha512256digest=eb204c30e3cd4d40bc2575a805f481723cb16d7ad1686bc6af26b45e837066c4
vendor/golang.org/x/sys/unix/asm_linux_ppc64x.s type=file mode=0664 size=643 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.448900883 sha512256digest=692e2be4962a6c6ff289b4a02d4060521a2a5a48db8a65be10df4f424b34e8ef
vendor/golang.org/x/sys/unix/asm_linux_s390x.s type=file mode=0664 size=635 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.448900883 sha512256digest=14dbb2e6754cef06aaef3eddc20eaaab03ed351676277dc89481fae30fb0a297
vendor/golang.org/x/sys/unix/asm_netbsd_386.s type=file mode=0664 size=675 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.448900883 sha512256digest=2c8fe2f54ba73c855e63cba8e1504a24e5ce227f8481476875a62e0201b74973
vendor/golang.org/x/sys/unix/asm_netbsd_amd64.s type=file mode=0664 size=678 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.448900883 sha512256digest=28ce95cab4f28b2092414dd84a4585518bbcca9b9463f95f1b085ccfa53f58be
vendor/golang.org/x/sys/unix/asm_netbsd_arm.s type=file mode=0664 size=665 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.448900883 sha512256digest=e8c0f5836faa5fd8f9fb2aa79e003a2b2b2da394005e6f290b813b9ed1dcd069
vendor/golang.org/x/sys/unix/asm_openbsd_386.s type=file mode=0664 size=676 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.448900883 sha512256digest=2941230ba6460c420d518a7e27ccac530b8b0d32ff30fe1ee8ab2a17fbb7f539
vendor/golang.org/x/sys/unix/asm_openbsd_amd64.s type=file mode=0664 size=679 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.448900883 sha512256digest=57b818fcb687ce814d466ad5acd30521b6d7e10d5a911255fafd7653198ce31b
vendor/golang.org/x/sys/unix/asm_openbsd_arm.s type=file mode=0664 size=666 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.448900883 sha512256digest=dbd94d1bd5d04c7649ccf9707768f7d84289acd010d91a843c630865382fcd4a
vendor/golang.org/x/sys/unix/asm_solaris_amd64.s type=file mode=0664 size=426 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.448900883 sha512256digest=3590238b4e35decd6b5711639be9c39f5695d5c9ef80066d5cdd9b381ceae9e0
vendor/golang.org/x/sys/unix/bluetooth_linux.go type=file mode=0664 size=655 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.448900883 sha512256digest=1030f9b73bad872abc822c99c2108640448b1f7c03cb3db7bf4b2f789b889880
vendor/golang.org/x/sys/unix/cap_freebsd.go type=file mode=0664 size=5182 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.448900883 sha512256digest=ae588894492046820482fd5f96d17df2ee54f4d8017d35288fa738c09312c17c
vendor/golang.org/x/sys/unix/constants.go type=file mode=0664 size=285 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.448900883 sha512256digest=226650163c679eb604fefed06d54064935afa764d1c71b176d357410137538de
vendor/golang.org/x/sys/unix/creds_test.go type=file mode=0664 size=3321 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.448900883 sha512256digest=a3a20f89c28e87d8177d8d36e5d90f81bfd74a5e4e8478a2428d69c41f911fe5
vendor/golang.org/x/sys/unix/dev_darwin.go type=file mode=0664 size=747 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.448900883 sha512256digest=cdfe857262a7bd5392c46560ca6053aa5ec3598a48bc23fac45b157a743ea1a2
vendor/golang.org/x/sys/unix/dev_darwin_test.go type=file mode=0664 size=1314 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.448900883 sha512256digest=b9960e3cd2a6250876c8085444bfd614ccd0c8b7685ad119613ffd59c58df9e4
vendor/golang.org/x/sys/unix/dev_dragonfly.go type=file mode=0664 size=1030 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.448900883 sha512256digest=d22f6b9fb00bba13993cb6a509063a08bfe1a50dbb87d7ae9a0e176c0e5d85a8
vendor/golang.org/x/sys/unix/dev_dragonfly_test.go type=file mode=0664 size=1302 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.448900883 sha512256digest=6aaa03562474c04427fbd3e2f4100c8a7a8407d98315331bea0b4c4111f6826d
vendor/golang.org/x/sys/unix/dev_freebsd.go type=file mode=0664 size=1013 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.448900883 sha512256digest=6cc8187f528496d2b80427f63870b4815411c93d38032b8234b5d0f14f44e9c1
vendor/golang.org/x/sys/unix/dev_linux.go type=file mode=0664 size=1579 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.448900883 sha512256digest=a494207bd423324ebc0da5715705ed36316826f1b438a373895e7238965b6af0
vendor/golang.org/x/sys/unix/dev_linux_test.go type=file mode=0664 size=1381 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.448900883 sha512256digest=6d237daeea888bacd345b866e8fec3a01681917c9939b2627039bbd1512a3a20
vendor/golang.org/x/sys/unix/dev_netbsd.go type=file mode=0664 size=913 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.448900883 sha512256digest=31f2d12ec605526c215bb1e4ef33493edce83d85465e4f8eb124180e9aaa62b1
vendor/golang.org/x/sys/unix/dev_netbsd_test.go type=file mode=0664 size=1303 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.448900883 sha512256digest=7d0f5c5a0ccec8fca4db6c881d8a2bce2e9d6b9946622dff603fa31ccd4350bd
vendor/golang.org/x/sys/unix/dev_openbsd.go type=file mode=0664 size=918 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.448900883 sha512256digest=a7105d3970f060444f792032fa6abb1b665eaf16affe402f7104638924bf4586
vendor/golang.org/x/sys/unix/dev_openbsd_test.go type=file mode=0664 size=1358 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.448900883 sha512256digest=1550df1cd7ab5733ce3518c28543653cf038240a1d194496e96d5d11aaeab5ad
vendor/golang.org/x/sys/unix/dev_solaris_test.go type=file mode=0664 size=1291 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.448900883 sha512256digest=5a4430134bbd0ac48b5be8b9e26b6e1c33af7f6945420269f0804f648bde78a8
vendor/golang.org/x/sys/unix/dirent.go type=file mode=0664 size=3057 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.449900878 sha512256digest=8d5d612436e8689fe1ef6ca7765dc222ed34fffba91695d297c1eefaba57e8c0
vendor/golang.org/x/sys/unix/endian_big.go type=file mode=0664 size=236 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.449900878 sha512256digest=98f588e96ba180389c63564ce258a1b28c994254efc8e9f0bcb4fc38e0b766ae
vendor/golang.org/x/sys/unix/endian_little.go type=file mode=0664 size=266 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.449900878 sha512256digest=44e5449191c33c3c060922c3b22bf4acb42e3f69cf2e69b1636d75cf7176e2a8
vendor/golang.org/x/sys/unix/env_unix.go type=file mode=0664 size=546 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.449900878 sha512256digest=661bcc5bd8869a15493c501d7ec418c1ac284104b88bff972791a46dee7da169
vendor/golang.org/x/sys/unix/env_unset.go type=file mode=0664 size=306 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.449900878 sha512256digest=9226f64ef3bfd65d64b7429cee4e005217b7394986f9437e835215a61d75b0d3
vendor/golang.org/x/sys/unix/errors_freebsd_386.go type=file mode=0664 size=9407 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.449900878 sha512256digest=6fc461195892bfb1d33962525df409b3146510bfb15c08dcf3b0d80fe092f866
vendor/golang.org/x/sys/unix/errors_freebsd_amd64.go type=file mode=0664 size=9407 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.450900873 sha512256digest=f692cb9906d464200afc73286693be255103c3d678c95b5c56e8053392aa310f
vendor/golang.org/x/sys/unix/errors_freebsd_arm.go type=file mode=0664 size=9037 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.451900867 sha512256digest=54ce31d5caa959c92c18969837a4f7a3367022dc2737a252ca40e03cc69b8e96
vendor/golang.org/x/sys/unix/export_test.go type=file mode=0664 size=256 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.451900867 sha512256digest=2d27fd7d03cb3f04853298cbb97c38c7f091e13d66ab125a06bf9a1af04d501c
vendor/golang.org/x/sys/unix/file_unix.go type=file mode=0664 size=614 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.451900867 sha512256digest=09f51f620292bf32fc719e0b5dfba865bb21fdfe616ecfa1f657deb4b89b01d5
vendor/golang.org/x/sys/unix/flock.go type=file mode=0664 size=695 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.451900867 sha512256digest=6f8716b07a762d2fec17e039d151c696f79a2ff785b869876225e49dd4f7fecd
vendor/golang.org/x/sys/unix/flock_linux_32bit.go type=file mode=0664 size=388 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.451900867 sha512256digest=b70a7ed1969b483abd3092542c733e49cfa438f5812355d46a1e79638cbf2ff0
vendor/golang.org/x/sys/unix/gccgo.go type=file mode=0664 size=1541 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.451900867 sha512256digest=5c4a055bb1739f79743979bcb1434756c8f88c999105d08efcabe721c09ae92d
vendor/golang.org/x/sys/unix/gccgo_c.c type=file mode=0664 size=1014 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.451900867 sha512256digest=d0cf40675ee3a585699e7b87b2f5226014a05b0ecafa0eafc118b76ed94460e4
vendor/golang.org/x/sys/unix/gccgo_linux_amd64.go type=file mode=0664 size=430 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.451900867 sha512256digest=4f17fad3cf09feab7b51390bc0d5658279e52eaf364c2f09d2a3cdf3d972bd93
vendor/golang.org/x/sys/unix/linux type=dir mode=0775 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.451900867
vendor/golang.org/x/sys/unix/linux/Dockerfile type=file mode=0664 size=2088 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.451900867 sha512256digest=b1cdee4ca2e3c4ea900d74a214ccf9933459dadb8e77ea4dae2e1d9c989fccf5
vendor/golang.org/x/sys/unix/linux/mkall.go type=file mode=0664 size=10396 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.451900867 sha512256digest=f07d3398f2737c77d3eafabd67e123fbd67bd9f169aad1c510b768b1db56cddb
vendor/golang.org/x/sys/unix/linux/mksysnum.pl type=file mode=0775 size=1988 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.451900867 sha512256digest=7dc0702eb661cd3b34ff193a268efd1e5303874e27dbe98591b55003da9beae6
vendor/golang.org/x/sys/unix/linux/types.go type=file mode=0664 size=15985 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.451900867 sha512256digest=9e4e427155e5dc58c6befaa68306ccc5362d7ea4df2111b02695e784f4c62ebc
vendor/golang.org/x/sys/unix/mkall.sh type=file mode=0775 size=6474 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.451900867 sha512256digest=63dd2f0784095b4c8e034b4f77a0ebe2626402760fcddb56708aa4adbe669764
vendor/golang.org/x/sys/unix/mkerrors.sh type=file mode=0775 size=13831 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.451900867 sha512256digest=85fb5a9f405d302ae8bfb6b860216d2dde9f8ad1fccf7be90a27c54fe6fb28ac
vendor/golang.org/x/sys/unix/mkpost.go type=file mode=0664 size=2631 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.451900867 sha512256digest=f7503cd4d657be68ad4b27f072199a4922abcabd388bf913cf89fe372f55d0e9
vendor/golang.org/x/sys/unix/mksyscall.pl type=file mode=0775 size=8238 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.451900867 sha512256digest=615490be180ba5c249d5a058450f41ef2e313f9dc65101500300e42d5558ad11
vendor/golang.org/x/sys/unix/mksyscall_solaris.pl type=file mode=0775 size=7108 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.451900867 sha512256digest=9c9819f91d9a011e9153f73da3f3274a3f9b0f3c6b39cc6e7eb4f6af198ec429
vendor/golang.org/x/sys/unix/mksysctl_openbsd.pl type=file mode=0775 size=5320 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.451900867 sha512256digest=d4b831d026acb1140a375f8f372523f0c2e253e3cc90b31a78f3ab7830eadede
vendor/golang.org/x/sys/unix/mksysnum_darwin.pl type=file mode=0775 size=751 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.451900867 sha512256digest=914efb2614e12d6e0a4c84f90965acb3c95ab0cfd288ca1c5970c934f93837e7
vendor/golang.org/x/sys/unix/mksysnum_dragonfly.pl type=file mode=0775 size=1039 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.451900867 sha512256digest=78d7f62dcb67c3cea6737b60f785320da2172ca5a9b991f65549e9d5492dfe50
vendor/golang.org/x/sys/unix/mksysnum_freebsd.pl type=file mode=0775 size=1041 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.452900862 sha512256digest=e5b9363a3a8a7ae6226791d186ef18d7fd97f1688ec6cec6a2af999c8526bc75
vendor/golang.org/x/sys/unix/mksysnum_netbsd.pl type=file mode=0775 size=1227 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.452900862 sha512256digest=94956e55a1dd70e86770e79d7f4d5b9d7f4f5b736d20985a1c2fa56d56ae987e
vendor/golang.org/x/sys/unix/mksysnum_openbsd.pl type=file mode=0775 size=1044 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.452900862 sha512256digest=965e4c689cb205ff7751d8725876c27b5e28093e54df670fe3618b48de498fad
vendor/golang.org/x/sys/unix/mmap_unix_test.go type=file mode=0664 size=844 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.452900862 sha512256digest=be10e286da104abc70f545f80f2bdf0d55b813961e7e26dcbf1859a15fcef5f5
vendor/golang.org/x/sys/unix/openbsd_pledge.go type=file mode=0664 size=889 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.452900862 sha512256digest=80567386299b0a684ae97d442f0f6ad8bfc857278a789bd180d6227d0996519a
vendor/golang.org/x/sys/unix/openbsd_test.go type=file mode=0664 size=2504 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.452900862 sha512256digest=8068ce28ec3caa3b3fa253e3a189cd6606f3783c58b37ce64868dd3a7d1b2f41
vendor/golang.org/x/sys/unix/pagesize_unix.go type=file mode=0664 size=364 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.452900862 sha512256digest=4e6f8f46f385e2042e25990999224cdba1cc244ec3015a3e776f6e1c9d73875f
vendor/golang.org/x/sys/unix/race.go type=file mode=0664 size=608 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.452900862 sha512256digest=8dc91f6210f0e238fcaf7f86b553e934510ac6c75ce91bdd203d7676b328ebab
vendor/golang.org/x/sys/unix/race0.go type=file mode=0664 size=506 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.452900862 sha512256digest=96dd85162b94b9f524d30d2eff3bd2e54d4ed10d91f995aa1284c6f885646bb2
vendor/golang.org/x/sys/unix/sockcmsg_linux.go type=file mode=0664 size=1072 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.452900862 sha512256digest=bf0d5db8b7493fc034c430fcfb4766417e8e1a7508c5c61bf7328fd38d78319f
vendor/golang.org/x/sys/unix/sockcmsg_unix.go type=file mode=0664 size=3004 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.452900862 sha512256digest=7447109f9cbbb656603d308640c10ea9dc9a6624ac15505061bce0de01493237
vendor/golang.org/x/sys/unix/str.go type=file mode=0664 size=611 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.452900862 sha512256digest=e866bc1a11f3c577f6aabd7938872dbf41b1397616ce5bfb8909f638a0f71000
vendor/golang.org/x/sys/unix/syscall.go type=file mode=0664 size=2473 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.452900862 sha512256digest=105fcb77117a424f60f49b34dc5704af19cfea69c30a2028e5eae6694b91668e
vendor/golang.org/x/sys/unix/syscall_bsd.go type=file mode=0664 size=16412 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.452900862 sha512256digest=0e4d9ee5c5f6eb0439c12adf6f10acdca195b7cf98414142cac45ac3c182c22e
vendor/golang.org/x/sys/unix/syscall_bsd_test.go type=file mode=0664 size=1303 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.452900862 sha512256digest=19be54172834153be6b2c4f34e52b3d3f01ca4e61ab5c26da468b298e7f63aee
vendor/golang.org/x/sys/unix/syscall_darwin.go type=file mode=0664 size=14402 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.452900862 sha512256digest=ea6c694a516dc46df716e4766b8ae289007316201f95c4a3af14153b0c1d3068
vendor/golang.org/x/sys/unix/syscall_darwin_386.go type=file mode=0664 size=1894 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.452900862 sha512256digest=129cf0ea8786a9565e45c6fd26a8c3b403cdd35c3727c2549794c3570f8939b3
vendor/golang.org/x/sys/unix/syscall_darwin_amd64.go type=file mode=0664 size=1842 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.452900862 sha512256digest=9caa8d9d1f56fd7608ebf5f7155ab4627e8d39280e7a05a534ab83e1e34c7c4e
vendor/golang.org/x/sys/unix/syscall_darwin_arm.go type=file mode=0664 size=1700 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.452900862 sha512256digest=fbe3117680c808a16306792195dcd2c8800ec83f95abeef305e57e001f47a551
vendor/golang.org/x/sys/unix/syscall_darwin_arm64.go type=file mode=0664 size=1849 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.452900862 sha512256digest=2ca5636a82e97bcae9513a7f8b22407347bff8db57ddb0c4fa62b9200d6901f6
vendor/golang.org/x/sys/unix/syscall_dragonfly.go type=file mode=0664 size=10661 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.453900857 sha512256digest=9fa9eb3d3bffd845f80e382fe2f7ae12cb6cb6335f15968b0264ed78ac87f59b
vendor/golang.org/x/sys/unix/syscall_dragonfly_amd64.go type=file mode=0664 size=1362 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.453900857 sha512256digest=9b98e533283c20fdf289d378ed094a25d5d920177f4249be0e285b8790edf169
vendor/golang.org/x/sys/unix/syscall_freebsd.go type=file mode=0664 size=18984 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.453900857 sha512256digest=fa308081980b38bcae99d9336d68a57a5e405717a3fc3bf287e3d47466bf0eb7
vendor/golang.org/x/sys/unix/syscall_freebsd_386.go type=file mode=0664 size=1400 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.453900857 sha512256digest=63e7a69c785d52d9971b56301bbd643ae25f15fe2714af0bba63d228f38ee2ec
vendor/golang.org/x/sys/unix/syscall_freebsd_amd64.go type=file mode=0664 size=1360 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.453900857 sha512256digest=53165dacd7642909b00fac1562322f1f9c6dddfc4893d14d20202a4d0ea6c4ff
vendor/golang.org/x/sys/unix/syscall_freebsd_arm.go type=file mode=0664 size=1379 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.453900857 sha512256digest=7392bee062164a2c1c7a58c6e234e069b621e34e9526a75c375d52dd8061b581
vendor/golang.org/x/sys/unix/syscall_freebsd_test.go type=file mode=0664 size=7071 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.453900857 sha512256digest=83beba3058fbfcc62ee365664098affbd4026f62a9633995f43e1b319748507f
vendor/golang.org/x/sys/unix/syscall_linux.go type=file mode=0664 size=42337 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.453900857 sha512256digest=4a669a12101a434a4827c7beab6ff6dd69870dd02b51ed835401d1191e946a83
vendor/golang.org/x/sys/unix/syscall_linux_386.go type=file mode=0664 size=11026 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.453900857 sha512256digest=f9292452892c5c9b530799d150410896293b71c5daaea8b9f730e596169e6626
vendor/golang.org/x/sys/unix/syscall_linux_amd64.go type=file mode=0664 size=5238 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.453900857 sha512256digest=eff154f2580f743e1deb3c5e772d990e588a112b77dcb2bf5e7cac6362570cb6
vendor/golang.org/x/sys/unix/syscall_linux_amd64_gc.go type=file mode=0664 size=297 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.453900857 sha512256digest=2de31b70481346aa26eabefedd55c255d897057031f117dc67283126b1ca86f7
vendor/golang.org/x/sys/unix/syscall_linux_arm.go type=file mode=0664 size=7748 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.453900857 sha512256digest=d4e69a5cdc3862c3b359cb7ae760f7bd1c040c7263e2c4923cbf19576aa83efc
vendor/golang.org/x/sys/unix/syscall_linux_arm64.go type=file mode=0664 size=6022 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.453900857 sha512256digest=6b65045f06e4cd07588e93bf6192eefee02836a6df663ac607fa470c81b2f444
vendor/golang.org/x/sys/unix/syscall_linux_mips64x.go type=file mode=0664 size=6287 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.453900857 sha512256digest=af605829a33d9c4641f38da8eedf83bf470b81819a0ce7389da8f98fe76df2bd
vendor/golang.org/x/sys/unix/syscall_linux_mipsx.go type=file mode=0664 size=7022 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.454900852 sha512256digest=67221ce149fa75aba755dca6b05c1e1851970bedc2a735a1e0ababf538781618
vendor/golang.org/x/sys/unix/syscall_linux_ppc64x.go type=file mode=0664 size=4996 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.454900852 sha512256digest=b237b58fd9d190e6dfb9bc3a1ef4146a01152953a419d0e25969f6a2098b0d51
vendor/golang.org/x/sys/unix/syscall_linux_s390x.go type=file mode=0664 size=9951 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.454900852 sha512256digest=f7435ad0eef255574c86faf1457d38d6c25cb6cf5b81c4d5d785666c473404ac
vendor/golang.org/x/sys/unix/syscall_linux_sparc64.go type=file mode=0664 size=5115 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.454900852 sha512256digest=c85ef216ba3f9d8ed038f50d0be1ce5df683b940faa9bb042f2eee4c92abb75b
vendor/golang.org/x/sys/unix/syscall_linux_test.go type=file mode=0664 size=4802 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.454900852 sha512256digest=b2d63724d8ea6361a1dd883b846e088e812e7f6fb8bfb9fe8de85f549ac1306d
vendor/golang.org/x/sys/unix/syscall_netbsd.go type=file mode=0664 size=11241 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.454900852 sha512256digest=ac46c9fe0fbf79ac20f3efbe3c577a7b60f061b3606e99691dd2dc5d7720848a
vendor/golang.org/x/sys/unix/syscall_netbsd_386.go type=file mode=0664 size=912 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.454900852 sha512256digest=9da2c69933b98eb81fd581694d6588826320e336e140e4dd2c893abb8729c008
vendor/golang.org/x/sys/unix/syscall_netbsd_amd64.go type=file mode=0664 size=914 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.454900852 sha512256digest=3de21a18511954cacfe1ed2df2c8c5ef23c00c54cbd07a6d38c4ed4fdb92359c
vendor/golang.org/x/sys/unix/syscall_netbsd_arm.go type=file mode=0664 size=912 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.454900852 sha512256digest=3b01b576d4646af34ecb3dcd731d8ce4f622770c9529292bc610a4a7d56898b0
vendor/golang.org/x/sys/unix/syscall_no_getwd.go type=file mode=0664 size=301 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.454900852 sha512256digest=9b650a395b572244827e9fb8f5f4b247b1ec8ac99aeb3168c88714daf0ee4263
vendor/golang.org/x/sys/unix/syscall_openbsd.go type=file mode=0664 size=7605 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.454900852 sha512256digest=c32af07cf02dac38ffda73c11e9bc700ad25f3fc5938c1dbda8edc5ec5d0b081
vendor/golang.org/x/sys/unix/syscall_openbsd_386.go type=file mode=0664 size=912 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.454900852 sha512256digest=c18a20eded970b5ade02f631d6ce778981d7813841227b952ea451b1aab7acff
vendor/golang.org/x/sys/unix/syscall_openbsd_amd64.go type=file mode=0664 size=886 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.454900852 sha512256digest=3aa8446604313927f241cd5bf15f3ba1976a2228f60c7d127eae1e31f61c78e2
vendor/golang.org/x/sys/unix/syscall_openbsd_arm.go type=file mode=0664 size=912 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.454900852 sha512256digest=eabf9ae74565592ebcea748db2645a91ec5954fb9c002e59a83b1b985d35771e
vendor/golang.org/x/sys/unix/syscall_solaris.go type=file mode=0664 size=20369 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.454900852 sha512256digest=53d6595ad46ace1758496fe3de4a8fa9ae49567dd56735e6c34b664b504d355b
vendor/golang.org/x/sys/unix/syscall_solaris_amd64.go type=file mode=0664 size=842 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.454900852 sha512256digest=dd5eebc32ff0c38d41738cdf9c968698370335d652d955f2e047a67fbbe8bdbb
vendor/golang.org/x/sys/unix/syscall_solaris_test.go type=file mode=0664 size=692 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.454900852 sha512256digest=47fc7b857f1b6cad4f89c30c2b9221bddeb588ed69562b5200484ccbd0f533ae
vendor/golang.org/x/sys/unix/syscall_test.go type=file mode=0664 size=1085 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.454900852 sha512256digest=e7f53a051857dc28a36968e80916fd51f3f7a5ec68128d73677de215823f835b
vendor/golang.org/x/sys/unix/syscall_unix.go type=file mode=0664 size=6739 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.454900852 sha512256digest=af6e0879d0339ccc0a682dddd82ba2d9a2723a4f7eef85c0d5db7ca365a91551
vendor/golang.org/x/sys/unix/syscall_unix_gc.go type=file mode=0664 size=606 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.454900852 sha512256digest=e26eb2003583c1b39b4bbf2cce40efd46186717cb76a1baefd7afb5cd1193e3b
vendor/golang.org/x/sys/unix/syscall_unix_test.go type=file mode=0664 size=8586 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.454900852 sha512256digest=122d71e217d0bfe6d9902e6da38cb5f1cf883e92be9c6031d785f2739dcf61e4
vendor/golang.org/x/sys/unix/types_darwin.go type=file mode=0664 size=5260 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.455900846 sha512256digest=7db87818277ea2692e348fab5d2947c0024f641a0f4fabfc5e3d1f7e5f9110e4
vendor/golang.org/x/sys/unix/types_dragonfly.go type=file mode=0664 size=5117 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.455900846 sha512256digest=c458d5be72f8c2fab144ede0d57e32fde2d47784684e670a86216f93688ee8b1
vendor/golang.org/x/sys/unix/types_freebsd.go type=file mode=0664 size=8237 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.455900846 sha512256digest=519ceed197f54aaf2be3fec476cdb3368d49829b98edbdee499ee50a09a9713e
vendor/golang.org/x/sys/unix/types_netbsd.go type=file mode=0664 size=4840 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.455900846 sha512256digest=b8f297577459faccf04bfc7d6eefc2e194e7f7a9533df36d94bb3f0619f0b81e
vendor/golang.org/x/sys/unix/types_openbsd.go type=file mode=0664 size=5110 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.455900846 sha512256digest=7e50488eeeeef3677d374ee767a44d397092c8e08c22ef29b0d8584084524ec3
vendor/golang.org/x/sys/unix/types_solaris.go type=file mode=0664 size=5518 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.455900846 sha512256digest=f0247afd6cb889629d0911a0b723cff193f8a903975304a58a7d68430538d748
vendor/golang.org/x/sys/unix/zerrors_darwin_386.go type=file mode=0664 size=68231 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.455900846 sha512256digest=a33eab019d5ccca084ac0b47a2017b4c0afe182f95a73b1876af95d8a95a24fe
vendor/golang.org/x/sys/unix/zerrors_darwin_amd64.go type=file mode=0664 size=68233 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.455900846 sha512256digest=0b33099abaf9c17a4b503726242048d2ae0f9fead8c8a9e72a04433bfb517b20
vendor/golang.org/x/sys/unix/zerrors_darwin_arm.go type=file mode=0664 size=68221 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.455900846 sha512256digest=f3d204933352bb8b93397aa24b122b2295a6c630e81abe4c5c80eebf25ca3874
vendor/golang.org/x/sys/unix/zerrors_darwin_arm64.go type=file mode=0664 size=68233 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.456900841 sha512256digest=632cab198b9b4221cd7f019baeeb51d669498c20459ce8f7c218fad29ee1431e
vendor/golang.org/x/sys/unix/zerrors_dragonfly_amd64.go type=file mode=0664 size=63577 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.456900841 sha512256digest=274f5185e212d88c23c92211cdc1e6d21d33749cb66a6b11caf5247d0bba5146
vendor/golang.org/x/sys/unix/zerrors_freebsd_386.go type=file mode=0664 size=68239 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.456900841 sha512256digest=6370d1cbdbd2822263643ab854a6d778e535efe70b70eb7377daedaaf13dc17e
vendor/golang.org/x/sys/unix/zerrors_freebsd_amd64.go type=file mode=0664 size=68291 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.456900841 sha512256digest=688c406dcf94d3ef10362fdeaa70c2aba4173874608daa2f826e25a5494a59a3
vendor/golang.org/x/sys/unix/zerrors_freebsd_arm.go type=file mode=0664 size=68597 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.457900836 sha512256digest=4b0c8e80f9d02f5624f0d923d1ad736473e10a6253dd63300938c25c9a21a915
vendor/golang.org/x/sys/unix/zerrors_linux_386.go type=file mode=0664 size=97027 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.457900836 sha512256digest=a7644f0d89abe85929d9b559077b6e5195551cfe04fc4cac2bec5ee3608aebf9
vendor/golang.org/x/sys/unix/zerrors_linux_amd64.go type=file mode=0664 size=97065 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.457900836 sha512256digest=c8cbc2603231f3031c1b088be5fd8d1f8a3053294b3fed96ff1d5270c41b64a8
vendor/golang.org/x/sys/unix/zerrors_linux_arm.go type=file mode=0664 size=97251 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.457900836 sha512256digest=f1df67cf7e1f51b6611c46c15cd2d5f0ccf52469845b949a6baac6074987d0c3
vendor/golang.org/x/sys/unix/zerrors_linux_arm64.go type=file mode=0664 size=96646 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.457900836 sha512256digest=1e771c581c2bc2fbed8bd31ab565279316d1aff64e263f44f53e876f1335bc97
vendor/golang.org/x/sys/unix/zerrors_linux_mips.go type=file mode=0664 size=97708 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.457900836 sha512256digest=e84e872372021ae4f68cad00bd733439277c2a0138cc52b72c7716295e94bedc
vendor/golang.org/x/sys/unix/zerrors_linux_mips64.go type=file mode=0664 size=97695 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.458900830 sha512256digest=139793b02799b4dec2e8092dfdac401a811d2a584346d7609aa96b1b40c2c7b9
vendor/golang.org/x/sys/unix/zerrors_linux_mips64le.go type=file mode=0664 size=97697 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.458900830 sha512256digest=b761cc77d4df5ba0eeb09ad814eea95e60527384026fed2853c0ee8502863502
vendor/golang.org/x/sys/unix/zerrors_linux_mipsle.go type=file mode=0664 size=97710 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.458900830 sha512256digest=d103223fd93b4adbfec0112410433f152104a141e08af6a935db9b51be4a548b
vendor/golang.org/x/sys/unix/zerrors_linux_ppc64.go type=file mode=0664 size=99998 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.458900830 sha512256digest=56ed15af23a0dab5293d80829146e4ba4fe4e59bb03e51c62870e4830b07cbbb
vendor/golang.org/x/sys/unix/zerrors_linux_ppc64le.go type=file mode=0664 size=100000 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.458900830 sha512256digest=bdcb442e3b0e2e10d775f68b1193440005ad6df5f72915167e32039f830b7c44
vendor/golang.org/x/sys/unix/zerrors_linux_s390x.go type=file mode=0664 size=99869 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.458900830 sha512256digest=f45253fe17e10e54a854489b6f9639efd8bf6bf8bc3216518365ea55cfe637db
vendor/golang.org/x/sys/unix/zerrors_linux_sparc64.go type=file mode=0664 size=85936 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.458900830 sha512256digest=a828bcbef60831441c9cd00adf9eb3cc394215b1a3f54c662858f99a96ff595e
vendor/golang.org/x/sys/unix/zerrors_netbsd_386.go type=file mode=0664 size=70116 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.459900825 sha512256digest=297a3d8d5122e49d512edac795448344a864fe7f37fa08173a7d582432ae5d46
vendor/golang.org/x/sys/unix/zerrors_netbsd_amd64.go type=file mode=0664 size=69698 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.459900825 sha512256digest=89306c2c8bd2c274f8c8340ab22ca11a2a1fa287437ad2fc9de95948ca80757d
vendor/golang.org/x/sys/unix/zerrors_netbsd_arm.go type=file mode=0664 size=69229 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.459900825 sha512256digest=b39f894f1fa33682ce96ea3e6c2914761d08c7860a140e99174cbc7802b55eb4
vendor/golang.org/x/sys/unix/zerrors_openbsd_386.go type=file mode=0664 size=64910 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.459900825 sha512256digest=74a535ae53c0705d19df8a24417d538779c7850692057fa19b7fe9565af6f6a1
vendor/golang.org/x/sys/unix/zerrors_openbsd_amd64.go type=file mode=0664 size=64866 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.459900825 sha512256digest=7f688c7b98a03330fcdb9edb862f015debaaf1ac306daa0804c91fc81f8d2c45
vendor/golang.org/x/sys/unix/zerrors_openbsd_arm.go type=file mode=0664 size=64986 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.459900825 sha512256digest=90f59fe6b5039b204ddf528a716edb62692fdf5ec14cee26e97907792e24c74e
vendor/golang.org/x/sys/unix/zerrors_solaris_amd64.go type=file mode=0664 size=55962 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.460900820 sha512256digest=7bc25fa518a08c9714731f10c67d5a5e27bc2eeb92cf558cd076f5210ed9e6db
vendor/golang.org/x/sys/unix/zsyscall_darwin_386.go type=file mode=0664 size=38195 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.460900820 sha512256digest=443808e7c6eb58eba34b01052820d465a522c7b7d097f043617def471f1147fc
vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.go type=file mode=0664 size=38048 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.460900820 sha512256digest=f1ecaa7daed979f46aaeaf6a1f28fd3eaf26cd4324996ef0373a7609b3cd26dd
vendor/golang.org/x/sys/unix/zsyscall_darwin_arm.go type=file mode=0664 size=38188 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.460900820 sha512256digest=57153855d62f86ccf8a6d6db363331c6029eeabf464f09e7309e4664cf208b60
vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.go type=file mode=0664 size=38048 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.460900820 sha512256digest=853d6cda427e1498cfa5f78384f6b981aa6cfab2fe6de56182a304441986b063
vendor/golang.org/x/sys/unix/zsyscall_dragonfly_amd64.go type=file mode=0664 size=34135 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.460900820 sha512256digest=f842c5256c4ff8b23f31ed27be09bc5dab493c2ecf6f7635f8afe760c4019ef7
vendor/golang.org/x/sys/unix/zsyscall_freebsd_386.go type=file mode=0664 size=45674 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.460900820 sha512256digest=435e7c5c2697ebd765574e0a23928170771f3d41f98ec8ce51da1b7483d84dfb
vendor/golang.org/x/sys/unix/zsyscall_freebsd_amd64.go type=file mode=0664 size=45491 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.460900820 sha512256digest=88b1a5d562da338b7cf49fc9e049732a4d908b20beb8e537c2b23c1aac3fb8f2
vendor/golang.org/x/sys/unix/zsyscall_freebsd_arm.go type=file mode=0664 size=45708 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.460900820 sha512256digest=a1ab37154ae91e251ec89abf2fa962a5e968dd6fbabc73df147362b264c23a9c
vendor/golang.org/x/sys/unix/zsyscall_linux_386.go type=file mode=0664 size=47539 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.461900815 sha512256digest=1d6cdaddbfbfff8cf0b91199d3279dd4fcc00ea02c567bb61d6644c874765ae8
vendor/golang.org/x/sys/unix/zsyscall_linux_amd64.go type=file mode=0664 size=52740 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.461900815 sha512256digest=0286f20cdd76406e013fd105e108ff24c5face6760b234dba6a16493f6c22e7a
vendor/golang.org/x/sys/unix/zsyscall_linux_arm.go type=file mode=0664 size=50716 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.461900815 sha512256digest=7dcd28210157bce72c6d7a7d1714c01e0f56d3a295ee1d0b3df98cea3c30ff97
vendor/golang.org/x/sys/unix/zsyscall_linux_arm64.go type=file mode=0664 size=49734 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.461900815 sha512256digest=2fa70856a5f0e76b3f156e96396398d4369f5b9348622e24f69554460a1029af
vendor/golang.org/x/sys/unix/zsyscall_linux_mips.go type=file mode=0664 size=52082 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.461900815 sha512256digest=d8dcbbadbb2520889bf68fb67090977f8ab5f7cc7043357411b58cdf2398933e
vendor/golang.org/x/sys/unix/zsyscall_linux_mips64.go type=file mode=0664 size=51395 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.461900815 sha512256digest=b199f9b6172da6b70229faa4b1a9fc7b6356f5fc5765263738c7cb05f6499198
vendor/golang.org/x/sys/unix/zsyscall_linux_mips64le.go type=file mode=0664 size=51399 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.461900815 sha512256digest=f78c0195de90b72579c5d3465637111a74367eb75cd73c7a2a7514c45fa6c2eb
vendor/golang.org/x/sys/unix/zsyscall_linux_mipsle.go type=file mode=0664 size=52086 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.461900815 sha512256digest=5ad282683095915c99a9e33447e18d07693a728f844f006d931c145e533b6bae
vendor/golang.org/x/sys/unix/zsyscall_linux_ppc64.go type=file mode=0664 size=52934 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.461900815 sha512256digest=bc14c21964f5fd05c75bf0e9ebb0279a3fba9d66a37f41e3a5138e4437bf3d93
vendor/golang.org/x/sys/unix/zsyscall_linux_ppc64le.go type=file mode=0664 size=52938 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.461900815 sha512256digest=0f75dcb00c83a30131cb57e37e58b6a1f542c00a3fe6ea1e0b2b241f48fe61e8
vendor/golang.org/x/sys/unix/zsyscall_linux_s390x.go type=file mode=0664 size=46874 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.461900815 sha512256digest=b743a983a377d31a24a9ba7ef5d31354fc3527d4dce84e54cdedd03aadabefb4
vendor/golang.org/x/sys/unix/zsyscall_linux_sparc64.go type=file mode=0664 size=44728 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.461900815 sha512256digest=f26dc211f14c4f8035b73612982dfd90834e1c09aa989de65154962758dd6ffe
vendor/golang.org/x/sys/unix/zsyscall_netbsd_386.go type=file mode=0664 size=31891 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.461900815 sha512256digest=af9cdf91fe2c36164de4fa3ed038f14038bec076fc54af956fa25ea77457f9bd
vendor/golang.org/x/sys/unix/zsyscall_netbsd_amd64.go type=file mode=0664 size=31743 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.461900815 sha512256digest=e8b00003195ca4250a18778ec1f0ae164656b837d962d994325f3677f7f4b9dc
vendor/golang.org/x/sys/unix/zsyscall_netbsd_arm.go type=file mode=0664 size=31896 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.461900815 sha512256digest=fdd1119582f350c753b2e6e7540190ac30a8b54ebe10d622f25bd18ca80bbe1f
vendor/golang.org/x/sys/unix/zsyscall_openbsd_386.go type=file mode=0664 size=33300 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.461900815 sha512256digest=af635b3c4882ea5048da47441941aa0b3242d0476d810125ec467697eff2f97b
vendor/golang.org/x/sys/unix/zsyscall_openbsd_amd64.go type=file mode=0664 size=33152 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.462900809 sha512256digest=3d9a34af2dd1e304e24a37ffa2488241c8afd94e5ca3f4e79622b87c56cd59f0
vendor/golang.org/x/sys/unix/zsyscall_openbsd_arm.go type=file mode=0664 size=33305 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.462900809 sha512256digest=0faea38dd503903cad40a920c758c98f59f2ee4e4bb6a6beba6b1e801b454523
vendor/golang.org/x/sys/unix/zsyscall_solaris_amd64.go type=file mode=0664 size=44500 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.462900809 sha512256digest=3be412f7aa291690f4e12b92d23d7cbfa6ef6fe5bfb036f005a084af067a9f83
vendor/golang.org/x/sys/unix/zsysctl_openbsd_386.go type=file mode=0664 size=11986 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.462900809 sha512256digest=a0c871c1d9e2b175b93338b07b244b2bb654e9cdb0aa387994718f254db61ff1
vendor/golang.org/x/sys/unix/zsysctl_openbsd_amd64.go type=file mode=0664 size=11986 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.462900809 sha512256digest=a0c871c1d9e2b175b93338b07b244b2bb654e9cdb0aa387994718f254db61ff1
vendor/golang.org/x/sys/unix/zsysctl_openbsd_arm.go type=file mode=0664 size=11986 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.462900809 sha512256digest=a0c871c1d9e2b175b93338b07b244b2bb654e9cdb0aa387994718f254db61ff1
vendor/golang.org/x/sys/unix/zsysnum_darwin_386.go type=file mode=0664 size=16506 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.462900809 sha512256digest=8bb84085428dfac3401a645f60f1aca81a630e1bd6522f3c53f71fd431f2f829
vendor/golang.org/x/sys/unix/zsysnum_darwin_amd64.go type=file mode=0664 size=16508 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.462900809 sha512256digest=d9e8603cbdebe2f35133bb0fb2768d0ff5ce0f1f1d178990c2057fb320f0c49c
vendor/golang.org/x/sys/unix/zsysnum_darwin_arm.go type=file mode=0664 size=17697 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.462900809 sha512256digest=983db0f2fe7a6f5922d2b4dd42f0cbc00a8a464e3b5ac8129d2b6089441a62e9
vendor/golang.org/x/sys/unix/zsysnum_darwin_arm64.go type=file mode=0664 size=17699 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.462900809 sha512256digest=72b479827976db9d5aebf663b48839db56fd41a94ffacf70376ee40059eae328
vendor/golang.org/x/sys/unix/zsysnum_dragonfly_amd64.go type=file mode=0664 size=24161 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.462900809 sha512256digest=c4db2065890efb27ea9db44a0ceab42791790c2e9e5bb4bdd74248f3943ff1c8
vendor/golang.org/x/sys/unix/zsysnum_freebsd_386.go type=file mode=0664 size=25623 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.463900804 sha512256digest=5befa2680b15e9981e291beee40a6c56011837762a178ccd2b84eab0cc2ac449
vendor/golang.org/x/sys/unix/zsysnum_freebsd_amd64.go type=file mode=0664 size=25625 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.463900804 sha512256digest=3bdaa06622d436e79530094aa65b7462bcbef6897aca55776c7c18a25bd6ba07
vendor/golang.org/x/sys/unix/zsysnum_freebsd_arm.go type=file mode=0664 size=25623 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.463900804 sha512256digest=d04d1424746505e05e78a5155505691350370aed2ed6acab41b2b434f3709966
vendor/golang.org/x/sys/unix/zsysnum_linux_386.go type=file mode=0664 size=13047 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.463900804 sha512256digest=384144a3c9d1c9f6dd219b109de7ccde43923991861e11021daf64bb27270aeb
vendor/golang.org/x/sys/unix/zsysnum_linux_amd64.go type=file mode=0664 size=11417 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.463900804 sha512256digest=4bdb0e2b3c39c24b57c48aee35723a44b46342e6c2a193b11642f831fcdbbb3c
vendor/golang.org/x/sys/unix/zsysnum_linux_arm.go type=file mode=0664 size=12117 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.463900804 sha512256digest=ab9ab2be4786115536692e1431f393151dd3da1c846f555843feec037365132f
vendor/golang.org/x/sys/unix/zsysnum_linux_arm64.go type=file mode=0664 size=9522 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.463900804 sha512256digest=696ef2e52734bce58c25268c45067ed77e483f66f7397cdfc340847af3d8556e
vendor/golang.org/x/sys/unix/zsysnum_linux_mips.go type=file mode=0664 size=13009 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.464900799 sha512256digest=fb453ef4ada8f4892c1db1f43bf01cd5406f062ad86d9aa8aa54fb92f830a47d
vendor/golang.org/x/sys/unix/zsysnum_linux_mips64.go type=file mode=0664 size=11611 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.464900799 sha512256digest=5204b369474c7ba523004c70e5724e4c197e7eb3f727362fc20bd2aa93555fea
vendor/golang.org/x/sys/unix/zsysnum_linux_mips64le.go type=file mode=0664 size=11613 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.464900799 sha512256digest=32a81f707bfc9d0a53455a1725777c513e375546750e856a999a4a0271194a94
vendor/golang.org/x/sys/unix/zsysnum_linux_mipsle.go type=file mode=0664 size=13011 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.464900799 sha512256digest=336125faeb15c94f43be6da4e9fedcf2d7137e033a82673caf3323d134f8842e
vendor/golang.org/x/sys/unix/zsysnum_linux_ppc64.go type=file mode=0664 size=12364 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.464900799 sha512256digest=9f9fe29f18a395d5da8074653f10edc4afe5765cc481ff7a156dee4de34340b0
vendor/golang.org/x/sys/unix/zsysnum_linux_ppc64le.go type=file mode=0664 size=12366 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.464900799 sha512256digest=e2c59480adfee1d1721f2da613118404f90db1fdcc7f80866c4e092ac90f7b35
vendor/golang.org/x/sys/unix/zsysnum_linux_s390x.go type=file mode=0664 size=11153 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.464900799 sha512256digest=3077e58a29f985f51fe6626aa80ee9b07183cbfd253ccd26d5555aeb50bb1dc8
vendor/golang.org/x/sys/unix/zsysnum_linux_sparc64.go type=file mode=0664 size=11627 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.464900799 sha512256digest=8e3d19f3484b31cb0b74ce3065dc8a9b764bc1236dc107be1b0b1a746868d597
vendor/golang.org/x/sys/unix/zsysnum_netbsd_386.go type=file mode=0664 size=26249 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.464900799 sha512256digest=84a1d3577ad9efbe15b119880e06e523ef4e5c165b7b3aa8ae04c466e40f95a2
vendor/golang.org/x/sys/unix/zsysnum_netbsd_amd64.go type=file mode=0664 size=26251 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.465900794 sha512256digest=e7605c55181ca00e586d289d1b9da3bbc33d91020ed62409daee31cd471b50fd
vendor/golang.org/x/sys/unix/zsysnum_netbsd_arm.go type=file mode=0664 size=26249 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.465900794 sha512256digest=0f2f8b61509acb907b7cc465aea6f6e08a9929977f124ff438db5b4fabb1081e
vendor/golang.org/x/sys/unix/zsysnum_openbsd_386.go type=file mode=0664 size=14343 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.465900794 sha512256digest=d026eadf38e09541256531e745cd1a967315820ca65a65ecb16626f4603f2279
vendor/golang.org/x/sys/unix/zsysnum_openbsd_amd64.go type=file mode=0664 size=14345 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.465900794 sha512256digest=f11c85cbaff35c6e1b159e4ad8bbce97b11bbfe074ca7dceab0cf83f7eabefa2
vendor/golang.org/x/sys/unix/zsysnum_openbsd_arm.go type=file mode=0664 size=14801 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.465900794 sha512256digest=b898bdbeb639b162a12137983f468c9d206799ae149d3dae992e641aeaca8de4
vendor/golang.org/x/sys/unix/zsysnum_solaris_amd64.go type=file mode=0664 size=286 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.465900794 sha512256digest=4b85545ec2b0afb73065697d583003bf81e69ea63a33bd7740c8e0511f046e53
vendor/golang.org/x/sys/unix/ztypes_darwin_386.go type=file mode=0664 size=7088 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.465900794 sha512256digest=69965aa975a8e17796805a7fbea4480658e444c273c7cc857023384a810518fe
vendor/golang.org/x/sys/unix/ztypes_darwin_amd64.go type=file mode=0664 size=7303 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.465900794 sha512256digest=5a735e0dc5d072c148be8660cd0f35511437e52f410bc708bb66f57993a1c3a3
vendor/golang.org/x/sys/unix/ztypes_darwin_arm.go type=file mode=0664 size=7106 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.465900794 sha512256digest=04a311a5a756f9cbce2e5d33df4dc40ad1c8da5679ae31fb1ae3ba2a777cdfc2
vendor/golang.org/x/sys/unix/ztypes_darwin_arm64.go type=file mode=0664 size=7255 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.465900794 sha512256digest=d1c31d0c1156152e53536386e5d2edd89f0677dcfc9229a863203224cd1a8795
vendor/golang.org/x/sys/unix/ztypes_dragonfly_amd64.go type=file mode=0664 size=6879 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.465900794 sha512256digest=a17ace91aac6fde3b41b7926a0dbc2d01c4cff28bdc9d5bfa15259040d0aa8cd
vendor/golang.org/x/sys/unix/ztypes_freebsd_386.go type=file mode=0664 size=8383 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.465900794 sha512256digest=8850b6f1b199085dcc3de01d287bacb6d3bdf5894a14ddbb0e6bed8745034ef7
vendor/golang.org/x/sys/unix/ztypes_freebsd_amd64.go type=file mode=0664 size=8468 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.465900794 sha512256digest=d713c13a0c3e7d19262650e11d861acd2622a391b675060e192b229f110482d8
vendor/golang.org/x/sys/unix/ztypes_freebsd_arm.go type=file mode=0664 size=8493 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.465900794 sha512256digest=322972bda83d28989ceeead12e68e8e4836cdaac34e6e86d3129877a497d5240
vendor/golang.org/x/sys/unix/ztypes_linux_386.go type=file mode=0664 size=14896 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.466900789 sha512256digest=94965019a6ce7f0b46f1296ec4098097ca3f1a7aee8f1ad4ef3aad3b32854949
vendor/golang.org/x/sys/unix/ztypes_linux_amd64.go type=file mode=0664 size=15241 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.466900789 sha512256digest=d09df8d55f52d9eba83a7c567ac43e1193c262779d148b418494a78759925972
vendor/golang.org/x/sys/unix/ztypes_linux_arm.go type=file mode=0664 size=14779 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.466900789 sha512256digest=6815aa38db25fd7c3a1fed293155c5c4e366a846819acd66821ee93bc14dfe15
vendor/golang.org/x/sys/unix/ztypes_linux_arm64.go type=file mode=0664 size=14885 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.466900789 sha512256digest=0934597c25d70bd1ce3a8e9e6d4106010ead862f02961b36ea2d7a2846cbeb50
vendor/golang.org/x/sys/unix/ztypes_linux_mips.go type=file mode=0664 size=14824 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.466900789 sha512256digest=aeff3c297f6dcc31b56500b2fa0f4d8cfce5b21c97fd0eb6e2bde5686b2c6a05
vendor/golang.org/x/sys/unix/ztypes_linux_mips64.go type=file mode=0664 size=14923 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.466900789 sha512256digest=d25acc07a832ce49268a62b80d72cdf2d09b52443ff2146889d28b88f8972645
vendor/golang.org/x/sys/unix/ztypes_linux_mips64le.go type=file mode=0664 size=14925 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.466900789 sha512256digest=f5b23e69e3ef24e24f91cb3fafcac3352dbfe2f60c62d1ec9775b89a6ea7dae1
vendor/golang.org/x/sys/unix/ztypes_linux_mipsle.go type=file mode=0664 size=14826 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.466900789 sha512256digest=10e4781078ff4926592c06821be99cf8eacb59de85c56171912d4c3264b31d59
vendor/golang.org/x/sys/unix/ztypes_linux_ppc64.go type=file mode=0664 size=15076 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.466900789 sha512256digest=6fd0a0437c2332a23cfcd58d06cee89eb2ec66e66bf615897b1c6b249e393dfb
vendor/golang.org/x/sys/unix/ztypes_linux_ppc64le.go type=file mode=0664 size=15078 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.466900789 sha512256digest=a75abe109b487b24cc01e9f1982c5671cfd3462a4875e8720bb7601a1cea1da6
vendor/golang.org/x/sys/unix/ztypes_linux_s390x.go type=file mode=0664 size=15353 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.466900789 sha512256digest=a6d2c1f7c8ff1b70f58ba7a17c17eae4e44fc259eafab56102f8b0240d423360
vendor/golang.org/x/sys/unix/ztypes_linux_sparc64.go type=file mode=0664 size=11442 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.466900789 sha512256digest=9409f66d6e47bf33d1e8ddaf86f7f931f8dea3f091ab19540ab3c73dd28155e5
vendor/golang.org/x/sys/unix/ztypes_netbsd_386.go type=file mode=0664 size=6093 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.466900789 sha512256digest=03965e5a6240c60f14cf6ecf63d7b1a34673ca7323aa6f0c90a0d2b2a9dccc66
vendor/golang.org/x/sys/unix/ztypes_netbsd_amd64.go type=file mode=0664 size=6279 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.466900789 sha512256digest=e5ed42e7b340581a58b038218a2bbe4c46d6ed672849205fb1bdb2116c8e1aca
vendor/golang.org/x/sys/unix/ztypes_netbsd_arm.go type=file mode=0664 size=6238 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.467900783 sha512256digest=ac531f076071cfe8cfa7d515fdb3bfef55358a24816a4c52021c9fcd6463fe3a
vendor/golang.org/x/sys/unix/ztypes_openbsd_386.go type=file mode=0664 size=6861 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.467900783 sha512256digest=72ba3a6f0d9a00a37bb1ab4163b193d200bcc45943fdb783eeff98b6a54bd0b3
vendor/golang.org/x/sys/unix/ztypes_openbsd_amd64.go type=file mode=0664 size=7022 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.467900783 sha512256digest=5766a6597832c64b111be726303f6a3a3261948b9d8cf67aae806a4c03c905fb
vendor/golang.org/x/sys/unix/ztypes_openbsd_arm.go type=file mode=0664 size=6770 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.467900783 sha512256digest=7d5aaa31bf85ff3eb5bd5d71c4ea8b31edfc361ef8d31c70d228aef328b1ece7
vendor/golang.org/x/sys/unix/ztypes_solaris_amd64.go type=file mode=0664 size=6722 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.467900783 sha512256digest=ffb709cf263ae56f2c67637b85c4a7c5b63d2acfc3fcfa007f98846a296835bd
vendor/golang.org/x/sys/windows type=dir mode=0775 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.470900767
vendor/golang.org/x/sys/windows/asm_windows_386.s type=file mode=0664 size=378 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.467900783 sha512256digest=58d393e4c02842ed863c42538a6a2b8149b4957a0f7933e7dc0d50d98803c001
vendor/golang.org/x/sys/windows/asm_windows_amd64.s type=file mode=0664 size=381 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.467900783 sha512256digest=ba022694d8c21b99c77b61b21a2c25f36eed4180681d51c152e05c8fa200f852
vendor/golang.org/x/sys/windows/dll_windows.go type=file mode=0664 size=11128 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.467900783 sha512256digest=3520d5dad0515ac5d4a345a78fc64c24862f711c56265228046e25b5b4d455a9
vendor/golang.org/x/sys/windows/env_unset.go type=file mode=0664 size=327 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.467900783 sha512256digest=2973b09180689676b7ded3c4c8574fb88a3e35812f4cd1d115ec6551c690e5bb
vendor/golang.org/x/sys/windows/env_windows.go type=file mode=0664 size=487 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.467900783 sha512256digest=dd755498ee242619fcaa30f27afd53aa41245eddfbcc1df6c6b93c50f8f157c3
vendor/golang.org/x/sys/windows/eventlog.go type=file mode=0664 size=824 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.467900783 sha512256digest=a2f8a51099e77875823323aa622d46d972efc715c5652256488a5b31d6a646ac
vendor/golang.org/x/sys/windows/exec_windows.go type=file mode=0664 size=1949 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.467900783 sha512256digest=ed4923e4c075c4201ed62d12a915e7cad454ed431cac75d48d99daf75acbaa78
vendor/golang.org/x/sys/windows/memory_windows.go type=file mode=0664 size=706 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.467900783 sha512256digest=76cd0d0ffdd3978293f5fc1292ae25af7330e6ec2411c395ebe6541b66ea53cf
vendor/golang.org/x/sys/windows/mksyscall.go type=file mode=0664 size=330 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.467900783 sha512256digest=5c16a267d957527960bddf522ea5f5094ed02f04f3d0b3e6758f549857e59e16
vendor/golang.org/x/sys/windows/race.go type=file mode=0664 size=588 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.467900783 sha512256digest=f1320e01be7935bd2dd971edc95e8be8eda5fc34fdedb0719c3f9a4ed76d95b8
vendor/golang.org/x/sys/windows/race0.go type=file mode=0664 size=451 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.467900783 sha512256digest=809559ba2984e20400dab18202bf0405a5bc8806bb835e81af6625ad9c4fb1fc
vendor/golang.org/x/sys/windows/registry type=dir mode=0775 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.468900778
vendor/golang.org/x/sys/windows/registry/export_test.go type=file mode=0664 size=311 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.467900783 sha512256digest=3ce47dd70187cde02063100515b4b23382a95cc3ba23ab925838c7c5e2bfb108
vendor/golang.org/x/sys/windows/registry/key.go type=file mode=0664 size=6149 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.467900783 sha512256digest=cf61d3cd1c5be251a0ff761e282b6b12582b8fcd119f3c76c56fbe43c9ea2bda
vendor/golang.org/x/sys/windows/registry/mksyscall.go type=file mode=0664 size=279 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.467900783 sha512256digest=fc241ec3bd3c3226e2b57b990c103c747bea998281d1150d8cb659ede8a53d43
vendor/golang.org/x/sys/windows/registry/registry_test.go type=file mode=0664 size=21613 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.467900783 sha512256digest=ce43c79f6978a97c7e518a0b01da47077500bd82bc49ba8db93effd306476708
vendor/golang.org/x/sys/windows/registry/syscall.go type=file mode=0664 size=1672 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.468900778 sha512256digest=696b9d5331bb99d6bcd07a9d7901575cd7551ff17c22281b635dd7b5db764de0
vendor/golang.org/x/sys/windows/registry/value.go type=file mode=0664 size=11659 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.468900778 sha512256digest=cc3f5ec0613f4b19142d45df90ae671f76f37103d25b81a2e619179e992b9d9d
vendor/golang.org/x/sys/windows/registry/zsyscall_windows.go type=file mode=0664 size=4497 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.468900778 sha512256digest=d83b6e21f7d505089d8dc0203f7a67e46f7b480253b0948abacafc066bfcb41c
vendor/golang.org/x/sys/windows/security_windows.go type=file mode=0664 size=12717 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.468900778 sha512256digest=5dbd8c3c6b49a23bcbc5c6cb9e178b8838817c89b1b2d55eee481a6636481748
vendor/golang.org/x/sys/windows/service.go type=file mode=0664 size=6760 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.468900778 sha512256digest=9f548a44ae665f1e2be6798cd0c08004705d9c24511d60579082725c762c4c75
vendor/golang.org/x/sys/windows/str.go type=file mode=0664 size=503 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.468900778 sha512256digest=6a1dd05563d1850a61182fc8abb2985a7139423cdc07bd3bb417925af804d8c1
vendor/golang.org/x/sys/windows/svc type=dir mode=0775 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.469900773
vendor/golang.org/x/sys/windows/svc/debug type=dir mode=0775 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.468900778
vendor/golang.org/x/sys/windows/svc/debug/log.go type=file mode=0664 size=1434 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.468900778 sha512256digest=36f6b32913126cce77be4bfe994f606c14aaf45aff421fe4fb8b0f5fe3e5d2dd
vendor/golang.org/x/sys/windows/svc/debug/service.go type=file mode=0664 size=1013 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.468900778 sha512256digest=d76bb6933e48c64b9573721547d7129e656b89221f80e07a2ef3748420bd6d3b
vendor/golang.org/x/sys/windows/svc/event.go type=file mode=0664 size=979 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.468900778 sha512256digest=94c5b43479f0a3201bf5ae95e326e1b96593dc0edf92f9e1100839e66f84d588
vendor/golang.org/x/sys/windows/svc/eventlog type=dir mode=0775 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.468900778
vendor/golang.org/x/sys/windows/svc/eventlog/install.go type=file mode=0664 size=2341 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.468900778 sha512256digest=5cf5daa0e431195eb4350cfece36376a962b135f6ef1bae422517dc8ed6115c7
vendor/golang.org/x/sys/windows/svc/eventlog/log.go type=file mode=0664 size=2041 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.468900778 sha512256digest=8a504aca519496a4f5b79c5fa60fa8aac7fecf299c63716fdabd83ba213da53f
vendor/golang.org/x/sys/windows/svc/eventlog/log_test.go type=file mode=0664 size=1061 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.468900778 sha512256digest=c393876238b289f5d349ab32c307ba716ffc30f3e423eed5b6a15db3aa375c6d
vendor/golang.org/x/sys/windows/svc/example type=dir mode=0775 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.469900773
vendor/golang.org/x/sys/windows/svc/example/beep.go type=file mode=0664 size=477 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.468900778 sha512256digest=b943a452e5d817683380ea39c7b8845d04928334ae8990ee80d2cf1d0980d5da
vendor/golang.org/x/sys/windows/svc/example/install.go type=file mode=0664 size=1835 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.468900778 sha512256digest=ae2446a0cfe3ac3ebcc68c7b3455f16fb4df626a98ceeae643f8102d59d16347
vendor/golang.org/x/sys/windows/svc/example/main.go type=file mode=0664 size=1769 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.468900778 sha512256digest=3ce3c4e311f0dc882cdb1686fa88ce26263b3822379db527bd04ba058a23ddb1
vendor/golang.org/x/sys/windows/svc/example/manage.go type=file mode=0664 size=1396 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.469900773 sha512256digest=64659105feeb84f1ff677e29552b6bcf16e8dc1bddb30888b3cb106ce8e5042c
vendor/golang.org/x/sys/windows/svc/example/service.go type=file mode=0664 size=2027 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.469900773 sha512256digest=f84055875f8674a647cb8edf49f1cdc35cd0e88544fe6f7856a4a347d897c7d9
vendor/golang.org/x/sys/windows/svc/go12.c type=file mode=0664 size=497 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.469900773 sha512256digest=b6cd9fe0b0cb80022aeb239ef013e8ac37e9fa5330d2451b4b92c565529365cf
vendor/golang.org/x/sys/windows/svc/go12.go type=file mode=0664 size=257 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.469900773 sha512256digest=7ed60f81776941804a4235d3328e3c1f05ff25f535d194dd2eb3d149f4774ffb
vendor/golang.org/x/sys/windows/svc/go13.go type=file mode=0664 size=863 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.469900773 sha512256digest=9e4c8e9803004e778509b7a4728313b1a789f02bf8906171af2fd80d752f6626
vendor/golang.org/x/sys/windows/svc/mgr type=dir mode=0775 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.469900773
vendor/golang.org/x/sys/windows/svc/mgr/config.go type=file mode=0664 size=3939 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.469900773 sha512256digest=69bf2a714f7d6f62db674c9e18ad00214b90c0ffb13116149ee9f0d43ec4b261
vendor/golang.org/x/sys/windows/svc/mgr/mgr.go type=file mode=0664 size=4455 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.469900773 sha512256digest=83687c4dd83faa67ef8db09a153c56845c4010a4dd05401f0a3fdc0f681c3c24
vendor/golang.org/x/sys/windows/svc/mgr/mgr_test.go type=file mode=0664 size=3908 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.469900773 sha512256digest=825a2145e522294fddf0d37ae4175df3b1bbb1acfa61de94cd1c9522cb54ff98
vendor/golang.org/x/sys/windows/svc/mgr/service.go type=file mode=0664 size=1791 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.469900773 sha512256digest=1b0977a1347a7989286d32f6358debe8c6517e5e38d11cdaf388ef3f92fb6b9b
vendor/golang.org/x/sys/windows/svc/security.go type=file mode=0664 size=1553 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.469900773 sha512256digest=05774567b99190dcfaa1198fc818d3a9f0586bcf40527c14c7d4019f8800e3c0
vendor/golang.org/x/sys/windows/svc/service.go type=file mode=0664 size=10848 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.469900773 sha512256digest=91aa0a8eec292418bb2e45609fd9536370fb31d413119663779a29a7c0fa5369
vendor/golang.org/x/sys/windows/svc/svc_test.go type=file mode=0664 size=2638 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.469900773 sha512256digest=cda7e9488d951a5d278c51a45d595ae597167c240aadfcc997f2c564be94c955
vendor/golang.org/x/sys/windows/svc/sys_386.s type=file mode=0664 size=1241 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.469900773 sha512256digest=44892d02d381297466df500895f6ba5991202947c45bb736d8e566f144912e25
vendor/golang.org/x/sys/windows/svc/sys_amd64.s type=file mode=0664 size=1031 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.469900773 sha512256digest=1530d9d362cf67b5abcbbae7b7e244843b0089b50ae376d86070d31ce17c4d36
vendor/golang.org/x/sys/windows/syscall.go type=file mode=0664 size=2407 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.469900773 sha512256digest=129c8714171a4cce55aa92caba4a590881062aa00646e048abd78f97c4e88f4c
vendor/golang.org/x/sys/windows/syscall_test.go type=file mode=0664 size=1433 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.469900773 sha512256digest=8efdb25b14f6699769f13f16a3703f166b2a18a6d8dbe836d1188e259674b48a
vendor/golang.org/x/sys/windows/syscall_windows.go type=file mode=0664 size=38971 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.469900773 sha512256digest=9f24c38c3d96ac08f3a3e6acc64fe165a544305a8acd26ead6d4a71ad45a1bdf
vendor/golang.org/x/sys/windows/syscall_windows_test.go type=file mode=0664 size=2857 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.469900773 sha512256digest=94530256b93cfadc7561335221b443298fe5780a6c4e83386986d0cf04b6e577
vendor/golang.org/x/sys/windows/types_windows.go type=file mode=0664 size=31549 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.470900767 sha512256digest=3f82ee167ab35b67c63619c544e47a05e2d26af92761d799ad5d1d6d99e73294
vendor/golang.org/x/sys/windows/types_windows_386.go type=file mode=0664 size=478 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.470900767 sha512256digest=8bb43554de9c8339edfac4c58130193448c774660c9659cb1ae49c2710e6d547
vendor/golang.org/x/sys/windows/types_windows_amd64.go type=file mode=0664 size=478 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.470900767 sha512256digest=25469d12b697e94aa4eb902b8643f5fec03108885e1521d470623237962ec497
vendor/golang.org/x/sys/windows/zsyscall_windows.go type=file mode=0664 size=81066 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.470900767 sha512256digest=f6c866585ffde0cc4ebedd64b2ea42ef6af9624880c353409ada4d868b895db0
version.go type=file mode=0664 size=624 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.470900767 sha512256digest=8653b2bc3523c290f6bd998bb29865c0165ad4e85aaccd0816a34287dc0e04d1
walk.go type=file mode=0664 size=10410 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.470900767 sha512256digest=d398fe4bb1bb9af39442dd6f695fa2fc66302ebbcb5bc1adb6418b2f3d5f9ed3
walk_test.go type=file mode=0664 size=1156 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1513088893.904788061 sha512256digest=227e25157b95da02017dab4d2dcff4199f356219cfc622228a6fe0535a41ab1c
xattr type=dir mode=0775 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.470900767
xattr/xattr.go type=file mode=0664 size=984 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.470900767 sha512256digest=a2700b603df30c3b0a91bdcf9045e64aea42f62647b0128ea154f51a0c48991e
xattr/xattr_test.go type=file mode=0664 size=859 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.470900767 sha512256digest=91294ea554801b75f6a9e33c268807c9620b531eb813ea24512dd4eeaf0592e4
xattr/xattr_unsupported.go type=file mode=0664 size=509 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.470900767 sha512256digest=81ced06a1cdf88c4936d10bbf8d46edc2d42dc26efeed3691ddbeeb469865f8a
xattr/xattr_unsupported_test.go type=file mode=0664 size=877 uid=1000 gid=1000 uname=vbatts gname=vbatts time=1512774394.470900767 sha512256digest=46605a03a985c7a3a4ab1a488f81382db4865f77b90b6a2b32693af39a8e1fba

View File

@ -1,7 +0,0 @@
package mtree
// Unvis is a wrapper for the C implementation of unvis, which decodes a string
// that potentially has characters that are encoded with Vis
func Unvis(src string) (string, error) {
return unvis(src)
}

View File

@ -1,11 +0,0 @@
// +build cgo,cvis
package mtree
import (
"github.com/vbatts/go-mtree/cvis"
)
func unvis(src string) (string, error) {
return cvis.Unvis(src)
}

View File

@ -1,228 +0,0 @@
// +build !cvis
package mtree
import "unicode"
func unvis(src string) (string, error) {
dst := &[]byte{}
var s state
for i, r := range src {
again:
err := unvisRune(dst, r, &s, 0)
switch err {
case unvisValid:
break
case unvisValidPush:
goto again
case unvisNone:
fallthrough
case unvisNochar:
break
default:
return "", err
}
if i == len(src)-1 {
unvisRune(dst, r, &s, unvisEnd)
}
}
return string(*dst), nil
}
func unvisRune(dst *[]byte, r rune, s *state, flags VisFlag) error {
if (flags & unvisEnd) != 0 {
if *s == stateOctal2 || *s == stateOctal3 {
*s = stateGround
return unvisValid
}
if *s == stateGround {
return unvisNochar
}
return unvisErrSynbad
}
switch *s & ^stateHTTP {
case stateGround:
if r == '\\' {
*s = stateStart
return unvisNone
}
if flags&VisHttpstyle != 0 && r == '%' {
*s = stateStart | stateHTTP
return unvisNone
}
*dst = append(*dst, byte(r))
return unvisValid
case stateStart:
if *s&stateHTTP != 0 && ishex(unicode.ToLower(r)) {
if unicode.IsNumber(r) {
*dst = append(*dst, byte(r-'0'))
} else {
*dst = append(*dst, byte(unicode.ToLower(r)-'a'))
}
*s = stateHex2
return unvisNone
}
switch r {
case '\\':
*s = stateGround
*dst = append(*dst, byte(r))
return unvisValid
case '0':
fallthrough
case '1':
fallthrough
case '2':
fallthrough
case '3':
fallthrough
case '4':
fallthrough
case '5':
fallthrough
case '6':
fallthrough
case '7':
*s = stateOctal2
*dst = append(*dst, byte(r-'0'))
return unvisNone
case 'M':
*s = stateMeta
*dst = append(*dst, 0200)
return unvisNone
case '^':
*s = stateCtrl
return unvisNone
case 'n':
*s = stateGround
*dst = append(*dst, '\n')
return unvisValid
case 'r':
*s = stateGround
*dst = append(*dst, '\r')
return unvisValid
case 'b':
*s = stateGround
*dst = append(*dst, '\b')
return unvisValid
case 'a':
*s = stateGround
*dst = append(*dst, '\007')
return unvisValid
case 'v':
*s = stateGround
*dst = append(*dst, '\v')
return unvisValid
case 't':
*s = stateGround
*dst = append(*dst, '\t')
return unvisValid
case 'f':
*s = stateGround
*dst = append(*dst, '\f')
return unvisValid
case 's':
*s = stateGround
*dst = append(*dst, ' ')
return unvisValid
case 'E':
*s = stateGround
*dst = append(*dst, '\033')
return unvisValid
case '\n':
// hidden newline
*s = stateGround
return unvisNochar
case '$':
// hidden marker
*s = stateGround
return unvisNochar
}
*s = stateGround
return unvisErrSynbad
case stateMeta:
if r == '-' {
*s = stateMeta1
} else if r == '^' {
*s = stateCtrl
} else {
*s = stateGround
return unvisErrSynbad
}
return unvisNone
case stateMeta1:
*s = stateGround
dp := *dst
dp[len(dp)-1] |= byte(r)
return unvisValid
case stateCtrl:
dp := *dst
if r == '?' {
dp[len(dp)-1] |= 0177
} else {
dp[len(dp)-1] |= byte(r & 037)
}
*s = stateGround
return unvisValid
case stateOctal2:
if isoctal(r) {
dp := *dst
if len(dp) > 0 {
last := dp[len(dp)-1]
dp[len(dp)-1] = (last << 3) + byte(r-'0')
} else {
dp = append(dp, byte((0<<3)+(r-'0')))
}
*s = stateOctal3
return unvisNone
}
*s = stateGround
return unvisValidPush
case stateOctal3:
*s = stateGround
if isoctal(r) {
dp := *dst
if len(dp) > 0 {
last := dp[len(dp)-1]
dp[len(dp)-1] = (last << 3) + byte(r-'0')
} else {
dp = append(dp, (0<<3)+byte(r-'0'))
}
return unvisValid
}
return unvisValidPush
case stateHex2:
if ishex(unicode.ToLower(r)) {
last := byte(0)
dp := *dst
if len(dp) > 0 {
last = dp[len(dp)-1]
}
if unicode.IsNumber(r) {
dp = append(dp, (last<<4)+byte(r-'0'))
} else {
dp = append(dp, (last<<4)+byte(unicode.ToLower(r)-'a'+10))
}
}
*s = stateGround
return unvisValid
}
*s = stateGround
return unvisErrSynbad
}
type state int
const (
stateGround state = iota /* haven't seen escape char */
stateStart /* start decoding special sequence */
stateMeta /* metachar started (M) */
stateMeta1 /* metachar more, regular char (-) */
stateCtrl /* control char started (^) */
stateOctal2 /* octal digit 2 */
stateOctal3 /* octal digit 3 */
stateHex2 /* hex digit 2 */
stateHTTP state = 0x080 /* %HEXHEX escape */
)

View File

@ -1,45 +0,0 @@
package mtree
import "testing"
type runeCheck func(rune) bool
func TestUnvisHelpers(t *testing.T) {
testset := []struct {
R rune
Check runeCheck
Expect bool
}{
{'a', ishex, true},
{'A', ishex, true},
{'z', ishex, false},
{'Z', ishex, false},
{'G', ishex, false},
{'1', ishex, true},
{'0', ishex, true},
{'9', ishex, true},
{'0', isoctal, true},
{'3', isoctal, true},
{'7', isoctal, true},
{'9', isoctal, false},
{'a', isoctal, false},
{'z', isoctal, false},
{'3', isalnum, true},
{'a', isalnum, true},
{';', isalnum, false},
{'!', isalnum, false},
{' ', isalnum, false},
{'3', isgraph, true},
{'a', isgraph, true},
{';', isgraph, true},
{'!', isgraph, true},
{' ', isgraph, false},
}
for i, ts := range testset {
got := ts.Check(ts.R)
if got != ts.Expect {
t.Errorf("%d: %q expected: %t; got %t", i, string(ts.R), ts.Expect, got)
}
}
}

154
update.go Normal file
View File

@ -0,0 +1,154 @@
package mtree
import (
"container/heap"
"os"
"sort"
"github.com/sirupsen/logrus"
)
// DefaultUpdateKeywords is the default set of keywords that can take updates to the files on disk
var DefaultUpdateKeywords = []Keyword{
"uid",
"gid",
"mode",
"xattr",
"link",
"time",
}
// Update attempts to set the attributes of root directory path, given the values of `keywords` in dh DirectoryHierarchy.
func Update(root string, dh *DirectoryHierarchy, keywords []Keyword, fs FsEval) ([]InodeDelta, error) {
creator := dhCreator{DH: dh}
curDir, err := os.Getwd()
if err == nil {
defer os.Chdir(curDir)
}
if err := os.Chdir(root); err != nil {
return nil, err
}
sort.Sort(byPos(creator.DH.Entries))
// This is for deferring the update of mtimes of directories, to unwind them
// in a most specific path first
h := &pathUpdateHeap{}
heap.Init(h)
results := []InodeDelta{}
for i, e := range creator.DH.Entries {
switch e.Type {
case SpecialType:
if e.Name == "/set" {
creator.curSet = &creator.DH.Entries[i]
} else if e.Name == "/unset" {
creator.curSet = nil
}
logrus.Debugf("%#v", e)
continue
case RelativeType, FullType:
e.Set = creator.curSet
pathname, err := e.Path()
if err != nil {
return nil, err
}
// filter the keywords to update on the file, from the keywords available for this entry:
var kvToUpdate []KeyVal
kvToUpdate = keyvalSelector(e.AllKeys(), keywords)
logrus.Debugf("kvToUpdate(%q): %#v", pathname, kvToUpdate)
for _, kv := range kvToUpdate {
if !InKeywordSlice(kv.Keyword().Prefix(), keywordPrefixes(keywords)) {
continue
}
logrus.Debugf("finding function for %q (%q)", kv.Keyword(), kv.Keyword().Prefix())
ukFunc, ok := UpdateKeywordFuncs[kv.Keyword().Prefix()]
if !ok {
logrus.Debugf("no UpdateKeywordFunc for %s; skipping", kv.Keyword())
continue
}
// TODO check for the type=dir of the entry as well
if kv.Keyword().Prefix() == "time" && e.IsDir() {
heap.Push(h, pathUpdate{
Path: pathname,
E: e,
KV: kv,
Func: ukFunc,
})
continue
}
if _, err := ukFunc(pathname, kv); err != nil {
results = append(results, InodeDelta{
diff: ErrorDifference,
path: pathname,
old: e,
keys: []KeyDelta{
{
diff: ErrorDifference,
name: kv.Keyword(),
err: err,
},
}})
}
// XXX really would be great to have a Check() or Compare() right here,
// to compare each entry as it is encountered, rather than just running
// Check() on this path after the whole update is finished.
}
}
}
for h.Len() > 0 {
pu := heap.Pop(h).(pathUpdate)
if _, err := pu.Func(pu.Path, pu.KV); err != nil {
results = append(results, InodeDelta{
diff: ErrorDifference,
path: pu.Path,
old: pu.E,
keys: []KeyDelta{
{
diff: ErrorDifference,
name: pu.KV.Keyword(),
err: err,
},
}})
}
}
return results, nil
}
type pathUpdateHeap []pathUpdate
func (h pathUpdateHeap) Len() int { return len(h) }
func (h pathUpdateHeap) Swap(i, j int) { h[i], h[j] = h[j], h[i] }
// This may end up looking backwards, but for container/heap, Less evaluates
// the negative priority. So when popping members of the array, it will be
// sorted by least. For this use-case, we want the most-qualified-name popped
// first (the longest path name), such that "." is the last entry popped.
func (h pathUpdateHeap) Less(i, j int) bool {
return len(h[i].Path) > len(h[j].Path)
}
func (h *pathUpdateHeap) Push(x interface{}) {
*h = append(*h, x.(pathUpdate))
}
func (h *pathUpdateHeap) Pop() interface{} {
old := *h
n := len(old)
x := old[n-1]
*h = old[0 : n-1]
return x
}
type pathUpdate struct {
Path string
E Entry
KV KeyVal
Func UpdateKeywordFunc
}

94
update_linux_test.go Normal file
View File

@ -0,0 +1,94 @@
package mtree
import (
"encoding/json"
"fmt"
"io/ioutil"
"os"
"path/filepath"
"testing"
"github.com/vbatts/go-mtree/xattr"
)
func init() {
//logrus.SetLevel(logrus.DebugLevel)
}
func TestXattrUpdate(t *testing.T) {
content := []byte("I know half of you half as well as I ought to")
// a bit dirty to create/destory a directory in cwd, but often /tmp is
// mounted tmpfs and doesn't support xattrs
dir, err := ioutil.TempDir(".", "test.xattr.restore.")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(dir) // clean up
tmpfn := filepath.Join(dir, "tmpfile")
if err := ioutil.WriteFile(tmpfn, content, 0666); err != nil {
t.Fatal(err)
}
if err := xattr.Set(dir, "user.test", []byte("directory")); err != nil {
t.Skip(fmt.Sprintf("skipping: %q does not support xattrs", dir))
}
if err := xattr.Set(tmpfn, "user.test", []byte("regular file")); err != nil {
t.Fatal(err)
}
// Walk this tempdir
dh, err := Walk(dir, nil, append(DefaultKeywords, []Keyword{"xattr", "sha1"}...), nil)
if err != nil {
t.Fatal(err)
}
// Now check that we're sane
res, err := Check(dir, dh, nil, nil)
if err != nil {
t.Fatal(err)
}
if len(res) != 0 {
t.Errorf("expecting no failures, but got %q", res)
}
if err := xattr.Set(tmpfn, "user.test", []byte("let it fly")); err != nil {
t.Fatal(err)
}
// Now check that we fail the check
res, err = Check(dir, dh, nil, nil)
if err != nil {
t.Fatal(err)
}
if len(res) == 0 {
t.Error("expected failures (like xattrs), but got none")
}
// restore the xattrs to original
res, err = Update(dir, dh, append(DefaultUpdateKeywords, "xattr"), nil)
if err != nil {
t.Error(err)
}
if len(res) != 0 {
t.Errorf("expecting no failures, but got %q", res)
}
// Now check that we're sane again
res, err = Check(dir, dh, nil, nil)
if err != nil {
t.Fatal(err)
}
if len(res) != 0 {
// pretty this shit up
buf, err := json.MarshalIndent(res, "", " ")
if err != nil {
t.Errorf("expecting no failures, but got %q", res)
} else {
t.Errorf("expecting no failures, but got %s", string(buf))
}
}
// TODO make a test for xattr here. Likely in the user space for privileges. Even still this may be prone to error for some tmpfs don't act right with xattrs. :-\
// I'd hate to have to t.Skip() a test rather than fail alltogether.
}

136
update_test.go Normal file
View File

@ -0,0 +1,136 @@
// +build go1.7
package mtree
import (
"container/heap"
"encoding/json"
"io/ioutil"
"os"
"os/user"
"path/filepath"
"strconv"
"testing"
"time"
"github.com/sirupsen/logrus"
)
func init() {
logrus.SetLevel(logrus.DebugLevel)
}
func TestUpdate(t *testing.T) {
content := []byte("I know half of you half as well as I ought to")
dir, err := ioutil.TempDir("", "test-check-keywords")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(dir) // clean up
tmpfn := filepath.Join(dir, "tmpfile")
if err := ioutil.WriteFile(tmpfn, content, 0666); err != nil {
t.Fatal(err)
}
// Walk this tempdir
dh, err := Walk(dir, nil, append(DefaultKeywords, "sha1"), nil)
if err != nil {
t.Fatal(err)
}
// Touch a file, so the mtime changes.
now := time.Now()
if err := os.Chtimes(tmpfn, now, now); err != nil {
t.Fatal(err)
}
if err := os.Chmod(tmpfn, os.FileMode(0600)); err != nil {
t.Fatal(err)
}
// Changing user is a little tough, but the group can be changed by a limited user to any group that the user is a member of. So just choose one that is not the current main group.
u, err := user.Current()
if err != nil {
t.Fatal(err)
}
ugroups, err := u.GroupIds()
if err != nil {
t.Fatal(err)
}
for _, ugroup := range ugroups {
if ugroup == u.Gid {
continue
}
gid, err := strconv.Atoi(ugroup)
if err != nil {
t.Fatal(ugroup)
}
if err := os.Lchown(tmpfn, -1, gid); err != nil {
t.Fatal(err)
}
}
// Check for sanity. This ought to have failures
res, err := Check(dir, dh, nil, nil)
if err != nil {
t.Fatal(err)
}
if len(res) == 0 {
t.Error("expected failures (like mtimes), but got none")
}
//dh.WriteTo(os.Stdout)
res, err = Update(dir, dh, DefaultUpdateKeywords, nil)
if err != nil {
t.Error(err)
}
if len(res) > 0 {
// pretty this shit up
buf, err := json.MarshalIndent(res, "", " ")
if err != nil {
t.Errorf("%#v", res)
}
t.Error(string(buf))
}
// Now check that we're sane again
res, err = Check(dir, dh, nil, nil)
if err != nil {
t.Fatal(err)
}
// should have no failures now
if len(res) > 0 {
// pretty this shit up
buf, err := json.MarshalIndent(res, "", " ")
if err != nil {
t.Errorf("%#v", res)
} else {
t.Error(string(buf))
}
}
}
func TestPathUpdateHeap(t *testing.T) {
h := &pathUpdateHeap{
pathUpdate{Path: "not/the/longest"},
pathUpdate{Path: "almost/the/longest"},
pathUpdate{Path: "."},
pathUpdate{Path: "short"},
}
heap.Init(h)
v := "this/is/one/is/def/the/longest"
heap.Push(h, pathUpdate{Path: v})
longest := len(v)
var p string
for h.Len() > 0 {
p = heap.Pop(h).(pathUpdate).Path
if len(p) > longest {
t.Errorf("expected next path to be shorter, but it was not %q is longer than %d", p, longest)
}
}
if p != "." {
t.Errorf("expected \".\" to be the last, but got %q", p)
}
}

201
updatefuncs.go Normal file
View File

@ -0,0 +1,201 @@
package mtree
import (
"fmt"
"os"
"strconv"
"strings"
"time"
"github.com/sirupsen/logrus"
"github.com/vbatts/go-mtree/pkg/govis"
)
// UpdateKeywordFunc is the signature for a function that will restore a file's
// attributes. Where path is relative path to the file, and value to be
// restored to.
type UpdateKeywordFunc func(path string, kv KeyVal) (os.FileInfo, error)
// UpdateKeywordFuncs is the registered list of functions to update file attributes.
// Keyed by the keyword as it would show up in the manifest
var UpdateKeywordFuncs = map[Keyword]UpdateKeywordFunc{
"mode": modeUpdateKeywordFunc,
"time": timeUpdateKeywordFunc,
"tar_time": tartimeUpdateKeywordFunc,
"uid": uidUpdateKeywordFunc,
"gid": gidUpdateKeywordFunc,
"xattr": xattrUpdateKeywordFunc,
"link": linkUpdateKeywordFunc,
}
func uidUpdateKeywordFunc(path string, kv KeyVal) (os.FileInfo, error) {
uid, err := strconv.Atoi(kv.Value())
if err != nil {
return nil, err
}
stat, err := os.Lstat(path)
if err != nil {
return nil, err
}
if statIsUID(stat, uid) {
return stat, nil
}
if err := os.Lchown(path, uid, -1); err != nil {
return nil, err
}
return os.Lstat(path)
}
func gidUpdateKeywordFunc(path string, kv KeyVal) (os.FileInfo, error) {
gid, err := strconv.Atoi(kv.Value())
if err != nil {
return nil, err
}
stat, err := os.Lstat(path)
if err != nil {
return nil, err
}
if statIsGID(stat, gid) {
return stat, nil
}
if err := os.Lchown(path, -1, gid); err != nil {
return nil, err
}
return os.Lstat(path)
}
func modeUpdateKeywordFunc(path string, kv KeyVal) (os.FileInfo, error) {
info, err := os.Lstat(path)
if err != nil {
return nil, err
}
// don't set mode on symlinks, as it passes through to the backing file
if info.Mode()&os.ModeSymlink != 0 {
return info, nil
}
vmode, err := strconv.ParseInt(kv.Value(), 8, 32)
if err != nil {
return nil, err
}
stat, err := os.Lstat(path)
if err != nil {
return nil, err
}
if stat.Mode() == os.FileMode(vmode) {
return stat, nil
}
logrus.Debugf("path: %q, kv.Value(): %q, vmode: %o", path, kv.Value(), vmode)
if err := os.Chmod(path, os.FileMode(vmode)); err != nil {
return nil, err
}
return os.Lstat(path)
}
// since tar_time will only be second level precision, then when restoring the
// filepath from a tar_time, then compare the seconds first and only Chtimes if
// the seconds value is different.
func tartimeUpdateKeywordFunc(path string, kv KeyVal) (os.FileInfo, error) {
info, err := os.Lstat(path)
if err != nil {
return nil, err
}
v := strings.SplitN(kv.Value(), ".", 2)
if len(v) != 2 {
return nil, fmt.Errorf("expected a number like 1469104727.000000000")
}
sec, err := strconv.ParseInt(v[0], 10, 64)
if err != nil {
return nil, fmt.Errorf("expected seconds, but got %q", v[0])
}
// if the seconds are the same, don't do anything, because the file might
// have nanosecond value, and if using tar_time it would zero it out.
if info.ModTime().Unix() == sec {
return info, nil
}
vtime := time.Unix(sec, 0)
// if times are same then don't modify anything
// comparing Unix, since it does not include Nano seconds
if info.ModTime().Unix() == vtime.Unix() {
return info, nil
}
// symlinks are strange and most of the time passes through to the backing file
if info.Mode()&os.ModeSymlink != 0 {
if err := lchtimes(path, vtime, vtime); err != nil {
return nil, err
}
} else if err := os.Chtimes(path, vtime, vtime); err != nil {
return nil, err
}
return os.Lstat(path)
}
// this is nano second precision
func timeUpdateKeywordFunc(path string, kv KeyVal) (os.FileInfo, error) {
info, err := os.Lstat(path)
if err != nil {
return nil, err
}
v := strings.SplitN(kv.Value(), ".", 2)
if len(v) != 2 {
return nil, fmt.Errorf("expected a number like 1469104727.871937272")
}
nsec, err := strconv.ParseInt(v[0]+v[1], 10, 64)
if err != nil {
return nil, fmt.Errorf("expected nano seconds, but got %q", v[0]+v[1])
}
logrus.Debugf("arg: %q; nsec: %d", v[0]+v[1], nsec)
vtime := time.Unix(0, nsec)
// if times are same then don't modify anything
if info.ModTime().Equal(vtime) {
return info, nil
}
// symlinks are strange and most of the time passes through to the backing file
if info.Mode()&os.ModeSymlink != 0 {
if err := lchtimes(path, vtime, vtime); err != nil {
return nil, err
}
} else if err := os.Chtimes(path, vtime, vtime); err != nil {
return nil, err
}
return os.Lstat(path)
}
func linkUpdateKeywordFunc(path string, kv KeyVal) (os.FileInfo, error) {
linkname, err := govis.Unvis(kv.Value(), DefaultVisFlags)
if err != nil {
return nil, err
}
got, err := os.Readlink(path)
if err != nil {
return nil, err
}
if got == linkname {
return os.Lstat(path)
}
logrus.Debugf("linkUpdateKeywordFunc: removing %q to link to %q", path, linkname)
if err := os.Remove(path); err != nil {
return nil, err
}
if err := os.Symlink(linkname, path); err != nil {
return nil, err
}
return os.Lstat(path)
}

21
updatefuncs_linux.go Normal file
View File

@ -0,0 +1,21 @@
// +build linux
package mtree
import (
"encoding/base64"
"os"
"github.com/vbatts/go-mtree/xattr"
)
func xattrUpdateKeywordFunc(path string, kv KeyVal) (os.FileInfo, error) {
buf, err := base64.StdEncoding.DecodeString(kv.Value())
if err != nil {
return nil, err
}
if err := xattr.Set(path, kv.Keyword().Suffix(), buf); err != nil {
return nil, err
}
return os.Lstat(path)
}

View File

@ -0,0 +1,11 @@
// +build !linux
package mtree
import (
"os"
)
func xattrUpdateKeywordFunc(path string, kv KeyVal) (os.FileInfo, error) {
return os.Lstat(path)
}

15
vendor/github.com/davecgh/go-spew/LICENSE generated vendored Normal file
View File

@ -0,0 +1,15 @@
ISC License
Copyright (c) 2012-2016 Dave Collins <dave@davec.name>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

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

@ -0,0 +1,145 @@
// Copyright (c) 2015-2016 Dave Collins <dave@davec.name>
//
// Permission to use, copy, modify, and distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
// NOTE: Due to the following build constraints, this file will only be compiled
// when the code is not running on Google App Engine, compiled by GopherJS, and
// "-tags safe" is not added to the go build command line. The "disableunsafe"
// tag is deprecated and thus should not be used.
// Go versions prior to 1.4 are disabled because they use a different layout
// for interfaces which make the implementation of unsafeReflectValue more complex.
// +build !js,!appengine,!safe,!disableunsafe,go1.4
package spew
import (
"reflect"
"unsafe"
)
const (
// UnsafeDisabled is a build-time constant which specifies whether or
// not access to the unsafe package is available.
UnsafeDisabled = false
// ptrSize is the size of a pointer on the current arch.
ptrSize = unsafe.Sizeof((*byte)(nil))
)
type flag uintptr
var (
// flagRO indicates whether the value field of a reflect.Value
// is read-only.
flagRO flag
// flagAddr indicates whether the address of the reflect.Value's
// value may be taken.
flagAddr flag
)
// flagKindMask holds the bits that make up the kind
// part of the flags field. In all the supported versions,
// it is in the lower 5 bits.
const flagKindMask = flag(0x1f)
// Different versions of Go have used different
// bit layouts for the flags type. This table
// records the known combinations.
var okFlags = []struct {
ro, addr flag
}{{
// From Go 1.4 to 1.5
ro: 1 << 5,
addr: 1 << 7,
}, {
// Up to Go tip.
ro: 1<<5 | 1<<6,
addr: 1 << 8,
}}
var flagValOffset = func() uintptr {
field, ok := reflect.TypeOf(reflect.Value{}).FieldByName("flag")
if !ok {
panic("reflect.Value has no flag field")
}
return field.Offset
}()
// flagField returns a pointer to the flag field of a reflect.Value.
func flagField(v *reflect.Value) *flag {
return (*flag)(unsafe.Pointer(uintptr(unsafe.Pointer(v)) + flagValOffset))
}
// unsafeReflectValue converts the passed reflect.Value into a one that bypasses
// the typical safety restrictions preventing access to unaddressable and
// unexported data. It works by digging the raw pointer to the underlying
// value out of the protected value and generating a new unprotected (unsafe)
// reflect.Value to it.
//
// This allows us to check for implementations of the Stringer and error
// interfaces to be used for pretty printing ordinarily unaddressable and
// inaccessible values such as unexported struct fields.
func unsafeReflectValue(v reflect.Value) reflect.Value {
if !v.IsValid() || (v.CanInterface() && v.CanAddr()) {
return v
}
flagFieldPtr := flagField(&v)
*flagFieldPtr &^= flagRO
*flagFieldPtr |= flagAddr
return v
}
// Sanity checks against future reflect package changes
// to the type or semantics of the Value.flag field.
func init() {
field, ok := reflect.TypeOf(reflect.Value{}).FieldByName("flag")
if !ok {
panic("reflect.Value has no flag field")
}
if field.Type.Kind() != reflect.TypeOf(flag(0)).Kind() {
panic("reflect.Value flag field has changed kind")
}
type t0 int
var t struct {
A t0
// t0 will have flagEmbedRO set.
t0
// a will have flagStickyRO set
a t0
}
vA := reflect.ValueOf(t).FieldByName("A")
va := reflect.ValueOf(t).FieldByName("a")
vt0 := reflect.ValueOf(t).FieldByName("t0")
// Infer flagRO from the difference between the flags
// for the (otherwise identical) fields in t.
flagPublic := *flagField(&vA)
flagWithRO := *flagField(&va) | *flagField(&vt0)
flagRO = flagPublic ^ flagWithRO
// Infer flagAddr from the difference between a value
// taken from a pointer and not.
vPtrA := reflect.ValueOf(&t).Elem().FieldByName("A")
flagNoPtr := *flagField(&vA)
flagPtr := *flagField(&vPtrA)
flagAddr = flagNoPtr ^ flagPtr
// Check that the inferred flags tally with one of the known versions.
for _, f := range okFlags {
if flagRO == f.ro && flagAddr == f.addr {
return
}
}
panic("reflect.Value read-only flag has changed semantics")
}

38
vendor/github.com/davecgh/go-spew/spew/bypasssafe.go generated vendored Normal file
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 !go1.4
package spew
import "reflect"
const (
// UnsafeDisabled is a build-time constant which specifies whether or
// not access to the unsafe package is available.
UnsafeDisabled = true
)
// unsafeReflectValue typically converts the passed reflect.Value into a one
// that bypasses the typical safety restrictions preventing access to
// unaddressable and unexported data. However, doing this relies on access to
// the unsafe package. This is a stub version which simply returns the passed
// reflect.Value when the unsafe package is not available.
func unsafeReflectValue(v reflect.Value) reflect.Value {
return v
}

341
vendor/github.com/davecgh/go-spew/spew/common.go generated vendored Normal file
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 hexadecimal with a leading '0x'
// prefix to Writer w.
func printHexPtr(w io.Writer, p uintptr) {
// Null pointer.
num := uint64(p)
if num == 0 {
w.Write(nilAngleBytes)
return
}
// Max uint64 is 16 bytes in hex + 2 bytes for '0x' prefix
buf := make([]byte, 18)
// It's simpler to construct the hex string right to left.
base := uint64(16)
i := len(buf) - 1
for num >= base {
buf[i] = hexDigits[num%base]
num /= base
i--
}
buf[i] = hexDigits[num]
// Add '0x' prefix.
i--
buf[i] = 'x'
i--
buf[i] = '0'
// Strip unused leading bytes.
buf = buf[i:]
w.Write(buf)
}
// valuesSorter implements sort.Interface to allow a slice of reflect.Value
// elements to be sorted.
type valuesSorter struct {
values []reflect.Value
strings []string // either nil or same len and values
cs *ConfigState
}
// newValuesSorter initializes a valuesSorter instance, which holds a set of
// surrogate keys on which the data should be sorted. It uses flags in
// ConfigState to decide if and how to populate those surrogate keys.
func newValuesSorter(values []reflect.Value, cs *ConfigState) sort.Interface {
vs := &valuesSorter{values: values, cs: cs}
if canSortSimply(vs.values[0].Kind()) {
return vs
}
if !cs.DisableMethods {
vs.strings = make([]string, len(values))
for i := range vs.values {
b := bytes.Buffer{}
if !handleMethods(cs, &b, vs.values[i]) {
vs.strings = nil
break
}
vs.strings[i] = b.String()
}
}
if vs.strings == nil && cs.SpewKeys {
vs.strings = make([]string, len(values))
for i := range vs.values {
vs.strings[i] = Sprintf("%#v", vs.values[i].Interface())
}
}
return vs
}
// canSortSimply tests whether a reflect.Kind is a primitive that can be sorted
// directly, or whether it should be considered for sorting by surrogate keys
// (if the ConfigState allows it).
func canSortSimply(kind reflect.Kind) bool {
// This switch parallels valueSortLess, except for the default case.
switch kind {
case reflect.Bool:
return true
case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int:
return true
case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint:
return true
case reflect.Float32, reflect.Float64:
return true
case reflect.String:
return true
case reflect.Uintptr:
return true
case reflect.Array:
return true
}
return false
}
// Len returns the number of values in the slice. It is part of the
// sort.Interface implementation.
func (s *valuesSorter) Len() int {
return len(s.values)
}
// Swap swaps the values at the passed indices. It is part of the
// sort.Interface implementation.
func (s *valuesSorter) Swap(i, j int) {
s.values[i], s.values[j] = s.values[j], s.values[i]
if s.strings != nil {
s.strings[i], s.strings[j] = s.strings[j], s.strings[i]
}
}
// valueSortLess returns whether the first value should sort before the second
// value. It is used by valueSorter.Less as part of the sort.Interface
// implementation.
func valueSortLess(a, b reflect.Value) bool {
switch a.Kind() {
case reflect.Bool:
return !a.Bool() && b.Bool()
case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int:
return a.Int() < b.Int()
case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint:
return a.Uint() < b.Uint()
case reflect.Float32, reflect.Float64:
return a.Float() < b.Float()
case reflect.String:
return a.String() < b.String()
case reflect.Uintptr:
return a.Uint() < b.Uint()
case reflect.Array:
// Compare the contents of both arrays.
l := a.Len()
for i := 0; i < l; i++ {
av := a.Index(i)
bv := b.Index(i)
if av.Interface() == bv.Interface() {
continue
}
return valueSortLess(av, bv)
}
}
return a.String() < b.String()
}
// Less returns whether the value at index i should sort before the
// value at index j. It is part of the sort.Interface implementation.
func (s *valuesSorter) Less(i, j int) bool {
if s.strings == nil {
return valueSortLess(s.values[i], s.values[j])
}
return s.strings[i] < s.strings[j]
}
// sortValues is a sort function that handles both native types and any type that
// can be converted to error or Stringer. Other inputs are sorted according to
// their Value.String() value to ensure display stability.
func sortValues(values []reflect.Value, cs *ConfigState) {
if len(values) == 0 {
return
}
sort.Sort(newValuesSorter(values, cs))
}

306
vendor/github.com/davecgh/go-spew/spew/config.go generated vendored Normal file
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:
d.w.Write(nilAngleBytes)
case cycleFound:
d.w.Write(circularBytes)
default:
d.ignoreNextType = true
d.dump(ve)
}
d.w.Write(closeParenBytes)
}
// dumpSlice handles formatting of arrays and slices. Byte (uint8 under
// reflection) arrays and slices are dumped in hexdump -C fashion.
func (d *dumpState) dumpSlice(v reflect.Value) {
// Determine whether this type should be hex dumped or not. Also,
// for types which should be hexdumped, try to use the underlying data
// first, then fall back to trying to convert them to a uint8 slice.
var buf []uint8
doConvert := false
doHexDump := false
numEntries := v.Len()
if numEntries > 0 {
vt := v.Index(0).Type()
vts := vt.String()
switch {
// C types that need to be converted.
case cCharRE.MatchString(vts):
fallthrough
case cUnsignedCharRE.MatchString(vts):
fallthrough
case cUint8tCharRE.MatchString(vts):
doConvert = true
// Try to use existing uint8 slices and fall back to converting
// and copying if that fails.
case vt.Kind() == reflect.Uint8:
// We need an addressable interface to convert the type
// to a byte slice. However, the reflect package won't
// give us an interface on certain things like
// unexported struct fields in order to enforce
// visibility rules. We use unsafe, when available, to
// bypass these restrictions since this package does not
// mutate the values.
vs := v
if !vs.CanInterface() || !vs.CanAddr() {
vs = unsafeReflectValue(vs)
}
if !UnsafeDisabled {
vs = vs.Slice(0, numEntries)
// Use the existing uint8 slice if it can be
// type asserted.
iface := vs.Interface()
if slice, ok := iface.([]uint8); ok {
buf = slice
doHexDump = true
break
}
}
// The underlying data needs to be converted if it can't
// be type asserted to a uint8 slice.
doConvert = true
}
// Copy and convert the underlying type if needed.
if doConvert && vt.ConvertibleTo(uint8Type) {
// Convert and copy each element into a uint8 byte
// slice.
buf = make([]uint8, numEntries)
for i := 0; i < numEntries; i++ {
vv := v.Index(i)
buf[i] = uint8(vv.Convert(uint8Type).Uint())
}
doHexDump = true
}
}
// Hexdump the entire slice as needed.
if doHexDump {
indent := strings.Repeat(d.cs.Indent, d.depth)
str := indent + hex.Dump(buf)
str = strings.Replace(str, "\n", "\n"+indent, -1)
str = strings.TrimRight(str, d.cs.Indent)
d.w.Write([]byte(str))
return
}
// Recursively call dump for each item.
for i := 0; i < numEntries; i++ {
d.dump(d.unpackValue(v.Index(i)))
if i < (numEntries - 1) {
d.w.Write(commaNewlineBytes)
} else {
d.w.Write(newlineBytes)
}
}
}
// dump is the main workhorse for dumping a value. It uses the passed reflect
// value to figure out what kind of object we are dealing with and formats it
// appropriately. It is a recursive function, however circular data structures
// are detected and handled properly.
func (d *dumpState) dump(v reflect.Value) {
// Handle invalid reflect values immediately.
kind := v.Kind()
if kind == reflect.Invalid {
d.w.Write(invalidAngleBytes)
return
}
// Handle pointers specially.
if kind == reflect.Ptr {
d.indent()
d.dumpPtr(v)
return
}
// Print type information unless already handled elsewhere.
if !d.ignoreNextType {
d.indent()
d.w.Write(openParenBytes)
d.w.Write([]byte(v.Type().String()))
d.w.Write(closeParenBytes)
d.w.Write(spaceBytes)
}
d.ignoreNextType = false
// Display length and capacity if the built-in len and cap functions
// work with the value's kind and the len/cap itself is non-zero.
valueLen, valueCap := 0, 0
switch v.Kind() {
case reflect.Array, reflect.Slice, reflect.Chan:
valueLen, valueCap = v.Len(), v.Cap()
case reflect.Map, reflect.String:
valueLen = v.Len()
}
if valueLen != 0 || !d.cs.DisableCapacities && valueCap != 0 {
d.w.Write(openParenBytes)
if valueLen != 0 {
d.w.Write(lenEqualsBytes)
printInt(d.w, int64(valueLen), 10)
}
if !d.cs.DisableCapacities && valueCap != 0 {
if valueLen != 0 {
d.w.Write(spaceBytes)
}
d.w.Write(capEqualsBytes)
printInt(d.w, int64(valueCap), 10)
}
d.w.Write(closeParenBytes)
d.w.Write(spaceBytes)
}
// Call Stringer/error interfaces if they exist and the handle methods flag
// is enabled
if !d.cs.DisableMethods {
if (kind != reflect.Invalid) && (kind != reflect.Interface) {
if handled := handleMethods(d.cs, d.w, v); handled {
return
}
}
}
switch kind {
case reflect.Invalid:
// Do nothing. We should never get here since invalid has already
// been handled above.
case reflect.Bool:
printBool(d.w, v.Bool())
case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int:
printInt(d.w, v.Int(), 10)
case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint:
printUint(d.w, v.Uint(), 10)
case reflect.Float32:
printFloat(d.w, v.Float(), 32)
case reflect.Float64:
printFloat(d.w, v.Float(), 64)
case reflect.Complex64:
printComplex(d.w, v.Complex(), 32)
case reflect.Complex128:
printComplex(d.w, v.Complex(), 64)
case reflect.Slice:
if v.IsNil() {
d.w.Write(nilAngleBytes)
break
}
fallthrough
case reflect.Array:
d.w.Write(openBraceNewlineBytes)
d.depth++
if (d.cs.MaxDepth != 0) && (d.depth > d.cs.MaxDepth) {
d.indent()
d.w.Write(maxNewlineBytes)
} else {
d.dumpSlice(v)
}
d.depth--
d.indent()
d.w.Write(closeBraceBytes)
case reflect.String:
d.w.Write([]byte(strconv.Quote(v.String())))
case reflect.Interface:
// The only time we should get here is for nil interfaces due to
// unpackValue calls.
if v.IsNil() {
d.w.Write(nilAngleBytes)
}
case reflect.Ptr:
// Do nothing. We should never get here since pointers have already
// been handled above.
case reflect.Map:
// nil maps should be indicated as different than empty maps
if v.IsNil() {
d.w.Write(nilAngleBytes)
break
}
d.w.Write(openBraceNewlineBytes)
d.depth++
if (d.cs.MaxDepth != 0) && (d.depth > d.cs.MaxDepth) {
d.indent()
d.w.Write(maxNewlineBytes)
} else {
numEntries := v.Len()
keys := v.MapKeys()
if d.cs.SortKeys {
sortValues(keys, d.cs)
}
for i, key := range keys {
d.dump(d.unpackValue(key))
d.w.Write(colonSpaceBytes)
d.ignoreNextIndent = true
d.dump(d.unpackValue(v.MapIndex(key)))
if i < (numEntries - 1) {
d.w.Write(commaNewlineBytes)
} else {
d.w.Write(newlineBytes)
}
}
}
d.depth--
d.indent()
d.w.Write(closeBraceBytes)
case reflect.Struct:
d.w.Write(openBraceNewlineBytes)
d.depth++
if (d.cs.MaxDepth != 0) && (d.depth > d.cs.MaxDepth) {
d.indent()
d.w.Write(maxNewlineBytes)
} else {
vt := v.Type()
numFields := v.NumField()
for i := 0; i < numFields; i++ {
d.indent()
vtf := vt.Field(i)
d.w.Write([]byte(vtf.Name))
d.w.Write(colonSpaceBytes)
d.ignoreNextIndent = true
d.dump(d.unpackValue(v.Field(i)))
if i < (numFields - 1) {
d.w.Write(commaNewlineBytes)
} else {
d.w.Write(newlineBytes)
}
}
}
d.depth--
d.indent()
d.w.Write(closeBraceBytes)
case reflect.Uintptr:
printHexPtr(d.w, uintptr(v.Uint()))
case reflect.UnsafePointer, reflect.Chan, reflect.Func:
printHexPtr(d.w, v.Pointer())
// There were not any other types at the time this code was written, but
// fall back to letting the default fmt package handle it in case any new
// types are added.
default:
if v.CanInterface() {
fmt.Fprintf(d.w, "%v", v.Interface())
} else {
fmt.Fprintf(d.w, "%v", v.String())
}
}
}
// fdump is a helper function to consolidate the logic from the various public
// methods which take varying writers and config states.
func fdump(cs *ConfigState, w io.Writer, a ...interface{}) {
for _, arg := range a {
if arg == nil {
w.Write(interfaceBytes)
w.Write(spaceBytes)
w.Write(nilAngleBytes)
w.Write(newlineBytes)
continue
}
d := dumpState{w: w, cs: cs}
d.pointers = make(map[uintptr]int)
d.dump(reflect.ValueOf(arg))
d.w.Write(newlineBytes)
}
}
// Fdump formats and displays the passed arguments to io.Writer w. It formats
// exactly the same as Dump.
func Fdump(w io.Writer, a ...interface{}) {
fdump(&Config, w, a...)
}
// Sdump returns a string with the passed arguments formatted exactly the same
// as Dump.
func Sdump(a ...interface{}) string {
var buf bytes.Buffer
fdump(&Config, &buf, a...)
return buf.String()
}
/*
Dump displays the passed parameters to standard out with newlines, customizable
indentation, and additional debug information such as complete types and all
pointer addresses used to indirect to the final value. It provides the
following features over the built-in printing facilities provided by the fmt
package:
* Pointers are dereferenced and followed
* Circular data structures are detected and handled properly
* Custom Stringer/error interfaces are optionally invoked, including
on unexported types
* Custom types which only implement the Stringer/error interfaces via
a pointer receiver are optionally invoked when passing non-pointer
variables
* Byte arrays and slices are dumped like the hexdump -C command which
includes offsets, byte values in hex, and ASCII output
The configuration options are controlled by an exported package global,
spew.Config. See ConfigState for options documentation.
See Fdump if you would prefer dumping to an arbitrary io.Writer or Sdump to
get the formatted result as a string.
*/
func Dump(a ...interface{}) {
fdump(&Config, os.Stdout, a...)
}

419
vendor/github.com/davecgh/go-spew/spew/format.go generated vendored Normal file
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:
f.fs.Write(nilAngleBytes)
case cycleFound:
f.fs.Write(circularShortBytes)
default:
f.ignoreNextType = true
f.format(ve)
}
}
// format is the main workhorse for providing the Formatter interface. It
// uses the passed reflect value to figure out what kind of object we are
// dealing with and formats it appropriately. It is a recursive function,
// however circular data structures are detected and handled properly.
func (f *formatState) format(v reflect.Value) {
// Handle invalid reflect values immediately.
kind := v.Kind()
if kind == reflect.Invalid {
f.fs.Write(invalidAngleBytes)
return
}
// Handle pointers specially.
if kind == reflect.Ptr {
f.formatPtr(v)
return
}
// Print type information unless already handled elsewhere.
if !f.ignoreNextType && f.fs.Flag('#') {
f.fs.Write(openParenBytes)
f.fs.Write([]byte(v.Type().String()))
f.fs.Write(closeParenBytes)
}
f.ignoreNextType = false
// Call Stringer/error interfaces if they exist and the handle methods
// flag is enabled.
if !f.cs.DisableMethods {
if (kind != reflect.Invalid) && (kind != reflect.Interface) {
if handled := handleMethods(f.cs, f.fs, v); handled {
return
}
}
}
switch kind {
case reflect.Invalid:
// Do nothing. We should never get here since invalid has already
// been handled above.
case reflect.Bool:
printBool(f.fs, v.Bool())
case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int:
printInt(f.fs, v.Int(), 10)
case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint:
printUint(f.fs, v.Uint(), 10)
case reflect.Float32:
printFloat(f.fs, v.Float(), 32)
case reflect.Float64:
printFloat(f.fs, v.Float(), 64)
case reflect.Complex64:
printComplex(f.fs, v.Complex(), 32)
case reflect.Complex128:
printComplex(f.fs, v.Complex(), 64)
case reflect.Slice:
if v.IsNil() {
f.fs.Write(nilAngleBytes)
break
}
fallthrough
case reflect.Array:
f.fs.Write(openBracketBytes)
f.depth++
if (f.cs.MaxDepth != 0) && (f.depth > f.cs.MaxDepth) {
f.fs.Write(maxShortBytes)
} else {
numEntries := v.Len()
for i := 0; i < numEntries; i++ {
if i > 0 {
f.fs.Write(spaceBytes)
}
f.ignoreNextType = true
f.format(f.unpackValue(v.Index(i)))
}
}
f.depth--
f.fs.Write(closeBracketBytes)
case reflect.String:
f.fs.Write([]byte(v.String()))
case reflect.Interface:
// The only time we should get here is for nil interfaces due to
// unpackValue calls.
if v.IsNil() {
f.fs.Write(nilAngleBytes)
}
case reflect.Ptr:
// Do nothing. We should never get here since pointers have already
// been handled above.
case reflect.Map:
// nil maps should be indicated as different than empty maps
if v.IsNil() {
f.fs.Write(nilAngleBytes)
break
}
f.fs.Write(openMapBytes)
f.depth++
if (f.cs.MaxDepth != 0) && (f.depth > f.cs.MaxDepth) {
f.fs.Write(maxShortBytes)
} else {
keys := v.MapKeys()
if f.cs.SortKeys {
sortValues(keys, f.cs)
}
for i, key := range keys {
if i > 0 {
f.fs.Write(spaceBytes)
}
f.ignoreNextType = true
f.format(f.unpackValue(key))
f.fs.Write(colonBytes)
f.ignoreNextType = true
f.format(f.unpackValue(v.MapIndex(key)))
}
}
f.depth--
f.fs.Write(closeMapBytes)
case reflect.Struct:
numFields := v.NumField()
f.fs.Write(openBraceBytes)
f.depth++
if (f.cs.MaxDepth != 0) && (f.depth > f.cs.MaxDepth) {
f.fs.Write(maxShortBytes)
} else {
vt := v.Type()
for i := 0; i < numFields; i++ {
if i > 0 {
f.fs.Write(spaceBytes)
}
vtf := vt.Field(i)
if f.fs.Flag('+') || f.fs.Flag('#') {
f.fs.Write([]byte(vtf.Name))
f.fs.Write(colonBytes)
}
f.format(f.unpackValue(v.Field(i)))
}
}
f.depth--
f.fs.Write(closeBraceBytes)
case reflect.Uintptr:
printHexPtr(f.fs, uintptr(v.Uint()))
case reflect.UnsafePointer, reflect.Chan, reflect.Func:
printHexPtr(f.fs, v.Pointer())
// There were not any other types at the time this code was written, but
// fall back to letting the default fmt package handle it if any get added.
default:
format := f.buildDefaultFormat()
if v.CanInterface() {
fmt.Fprintf(f.fs, format, v.Interface())
} else {
fmt.Fprintf(f.fs, format, v.String())
}
}
}
// Format satisfies the fmt.Formatter interface. See NewFormatter for usage
// details.
func (f *formatState) Format(fs fmt.State, verb rune) {
f.fs = fs
// Use standard formatting for verbs that are not v.
if verb != 'v' {
format := f.constructOrigFormat(verb)
fmt.Fprintf(fs, format, f.value)
return
}
if f.value == nil {
if fs.Flag('#') {
fs.Write(interfaceBytes)
}
fs.Write(nilAngleBytes)
return
}
f.format(reflect.ValueOf(f.value))
}
// newFormatter is a helper function to consolidate the logic from the various
// public methods which take varying config states.
func newFormatter(cs *ConfigState, v interface{}) fmt.Formatter {
fs := &formatState{value: v, cs: cs}
fs.pointers = make(map[uintptr]int)
return fs
}
/*
NewFormatter returns a custom formatter that satisfies the fmt.Formatter
interface. As a result, it integrates cleanly with standard fmt package
printing functions. The formatter is useful for inline printing of smaller data
types similar to the standard %v format specifier.
The custom formatter only responds to the %v (most compact), %+v (adds pointer
addresses), %#v (adds types), or %#+v (adds types and pointer addresses) verb
combinations. Any other verbs such as %x and %q will be sent to the the
standard fmt package for formatting. In addition, the custom formatter ignores
the width and precision arguments (however they will still work on the format
specifiers not handled by the custom formatter).
Typically this function shouldn't be called directly. It is much easier to make
use of the custom formatter by calling one of the convenience functions such as
Printf, Println, or Fprintf.
*/
func NewFormatter(v interface{}) fmt.Formatter {
return newFormatter(&Config, v)
}

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

4
vendor/github.com/sirupsen/logrus/.gitignore generated vendored Normal file
View File

@ -0,0 +1,4 @@
logrus
vendor
.idea/

40
vendor/github.com/sirupsen/logrus/.golangci.yml generated vendored Normal file
View File

@ -0,0 +1,40 @@
run:
# do not run on test files yet
tests: false
# all available settings of specific linters
linters-settings:
errcheck:
# report about not checking of errors in type assetions: `a := b.(MyStruct)`;
# default is false: such cases aren't reported by default.
check-type-assertions: false
# report about assignment of errors to blank identifier: `num, _ := strconv.Atoi(numStr)`;
# default is false: such cases aren't reported by default.
check-blank: false
lll:
line-length: 100
tab-width: 4
prealloc:
simple: false
range-loops: false
for-loops: false
whitespace:
multi-if: false # Enforces newlines (or comments) after every multi-line if statement
multi-func: false # Enforces newlines (or comments) after every multi-line function signature
linters:
enable:
- megacheck
- govet
disable:
- maligned
- prealloc
disable-all: false
presets:
- bugs
- unused
fast: false

17
vendor/github.com/sirupsen/logrus/.travis.yml generated vendored Normal file
View File

@ -0,0 +1,17 @@
language: go
go_import_path: github.com/sirupsen/logrus
git:
depth: 1
env:
- GO111MODULE=on
go: [1.13.x, 1.14.x]
os: [linux, osx]
install:
- ./travis/install.sh
script:
- ./travis/cross_build.sh
- ./travis/lint.sh
- export GOMAXPROCS=4
- export GORACE=halt_on_error=1
- go test -race -v ./...
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then go test -race -v -tags appengine ./... ; fi

223
vendor/github.com/sirupsen/logrus/CHANGELOG.md generated vendored Normal file
View File

@ -0,0 +1,223 @@
# 1.6.0
Fixes:
* end of line cleanup
* revert the entry concurrency bug fix whic leads to deadlock under some circumstances
* update dependency on go-windows-terminal-sequences to fix a crash with go 1.14
Features:
* add an option to the `TextFormatter` to completely disable fields quoting
# 1.5.0
Code quality:
* add golangci linter run on travis
Fixes:
* add mutex for hooks concurrent access on `Entry` data
* caller function field for go1.14
* fix build issue for gopherjs target
Feature:
* add an hooks/writer sub-package whose goal is to split output on different stream depending on the trace level
* add a `DisableHTMLEscape` option in the `JSONFormatter`
* add `ForceQuote` and `PadLevelText` options in the `TextFormatter`
# 1.4.2
* Fixes build break for plan9, nacl, solaris
# 1.4.1
This new release introduces:
* Enhance TextFormatter to not print caller information when they are empty (#944)
* Remove dependency on golang.org/x/crypto (#932, #943)
Fixes:
* Fix Entry.WithContext method to return a copy of the initial entry (#941)
# 1.4.0
This new release introduces:
* Add `DeferExitHandler`, similar to `RegisterExitHandler` but prepending the handler to the list of handlers (semantically like `defer`) (#848).
* Add `CallerPrettyfier` to `JSONFormatter` and `TextFormatter` (#909, #911)
* Add `Entry.WithContext()` and `Entry.Context`, to set a context on entries to be used e.g. in hooks (#919).
Fixes:
* Fix wrong method calls `Logger.Print` and `Logger.Warningln` (#893).
* Update `Entry.Logf` to not do string formatting unless the log level is enabled (#903)
* Fix infinite recursion on unknown `Level.String()` (#907)
* Fix race condition in `getCaller` (#916).
# 1.3.0
This new release introduces:
* Log, Logf, Logln functions for Logger and Entry that take a Level
Fixes:
* Building prometheus node_exporter on AIX (#840)
* Race condition in TextFormatter (#468)
* Travis CI import path (#868)
* Remove coloured output on Windows (#862)
* Pointer to func as field in JSONFormatter (#870)
* Properly marshal Levels (#873)
# 1.2.0
This new release introduces:
* A new method `SetReportCaller` in the `Logger` to enable the file, line and calling function from which the trace has been issued
* A new trace level named `Trace` whose level is below `Debug`
* A configurable exit function to be called upon a Fatal trace
* The `Level` object now implements `encoding.TextUnmarshaler` interface
# 1.1.1
This is a bug fix release.
* fix the build break on Solaris
* don't drop a whole trace in JSONFormatter when a field param is a function pointer which can not be serialized
# 1.1.0
This new release introduces:
* several fixes:
* a fix for a race condition on entry formatting
* proper cleanup of previously used entries before putting them back in the pool
* the extra new line at the end of message in text formatter has been removed
* a new global public API to check if a level is activated: IsLevelEnabled
* the following methods have been added to the Logger object
* IsLevelEnabled
* SetFormatter
* SetOutput
* ReplaceHooks
* introduction of go module
* an indent configuration for the json formatter
* output colour support for windows
* the field sort function is now configurable for text formatter
* the CLICOLOR and CLICOLOR\_FORCE environment variable support in text formater
# 1.0.6
This new release introduces:
* a new api WithTime which allows to easily force the time of the log entry
which is mostly useful for logger wrapper
* a fix reverting the immutability of the entry given as parameter to the hooks
a new configuration field of the json formatter in order to put all the fields
in a nested dictionnary
* a new SetOutput method in the Logger
* a new configuration of the textformatter to configure the name of the default keys
* a new configuration of the text formatter to disable the level truncation
# 1.0.5
* Fix hooks race (#707)
* Fix panic deadlock (#695)
# 1.0.4
* Fix race when adding hooks (#612)
* Fix terminal check in AppEngine (#635)
# 1.0.3
* Replace example files with testable examples
# 1.0.2
* bug: quote non-string values in text formatter (#583)
* Make (*Logger) SetLevel a public method
# 1.0.1
* bug: fix escaping in text formatter (#575)
# 1.0.0
* Officially changed name to lower-case
* bug: colors on Windows 10 (#541)
* bug: fix race in accessing level (#512)
# 0.11.5
* feature: add writer and writerlevel to entry (#372)
# 0.11.4
* bug: fix undefined variable on solaris (#493)
# 0.11.3
* formatter: configure quoting of empty values (#484)
* formatter: configure quoting character (default is `"`) (#484)
* bug: fix not importing io correctly in non-linux environments (#481)
# 0.11.2
* bug: fix windows terminal detection (#476)
# 0.11.1
* bug: fix tty detection with custom out (#471)
# 0.11.0
* performance: Use bufferpool to allocate (#370)
* terminal: terminal detection for app-engine (#343)
* feature: exit handler (#375)
# 0.10.0
* feature: Add a test hook (#180)
* feature: `ParseLevel` is now case-insensitive (#326)
* feature: `FieldLogger` interface that generalizes `Logger` and `Entry` (#308)
* performance: avoid re-allocations on `WithFields` (#335)
# 0.9.0
* logrus/text_formatter: don't emit empty msg
* logrus/hooks/airbrake: move out of main repository
* logrus/hooks/sentry: move out of main repository
* logrus/hooks/papertrail: move out of main repository
* logrus/hooks/bugsnag: move out of main repository
* logrus/core: run tests with `-race`
* logrus/core: detect TTY based on `stderr`
* logrus/core: support `WithError` on logger
* logrus/core: Solaris support
# 0.8.7
* logrus/core: fix possible race (#216)
* logrus/doc: small typo fixes and doc improvements
# 0.8.6
* hooks/raven: allow passing an initialized client
# 0.8.5
* logrus/core: revert #208
# 0.8.4
* formatter/text: fix data race (#218)
# 0.8.3
* logrus/core: fix entry log level (#208)
* logrus/core: improve performance of text formatter by 40%
* logrus/core: expose `LevelHooks` type
* logrus/core: add support for DragonflyBSD and NetBSD
* formatter/text: print structs more verbosely
# 0.8.2
* logrus: fix more Fatal family functions
# 0.8.1
* logrus: fix not exiting on `Fatalf` and `Fatalln`
# 0.8.0
* logrus: defaults to stderr instead of stdout
* hooks/sentry: add special field for `*http.Request`
* formatter/text: ignore Windows for colors
# 0.7.3
* formatter/\*: allow configuration of timestamp layout
# 0.7.2
* formatter/text: Add configuration option for time format (#158)

21
vendor/github.com/sirupsen/logrus/LICENSE generated vendored Normal file
View File

@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2014 Simon Eskildsen
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

513
vendor/github.com/sirupsen/logrus/README.md generated vendored Normal file
View File

@ -0,0 +1,513 @@
# Logrus <img src="http://i.imgur.com/hTeVwmJ.png" width="40" height="40" alt=":walrus:" class="emoji" title=":walrus:"/> [![Build Status](https://travis-ci.org/sirupsen/logrus.svg?branch=master)](https://travis-ci.org/sirupsen/logrus) [![GoDoc](https://godoc.org/github.com/sirupsen/logrus?status.svg)](https://godoc.org/github.com/sirupsen/logrus)
Logrus is a structured logger for Go (golang), completely API compatible with
the standard library logger.
**Logrus is in maintenance-mode.** We will not be introducing new features. It's
simply too hard to do in a way that won't break many people's projects, which is
the last thing you want from your Logging library (again...).
This does not mean Logrus is dead. Logrus will continue to be maintained for
security, (backwards compatible) bug fixes, and performance (where we are
limited by the interface).
I believe Logrus' biggest contribution is to have played a part in today's
widespread use of structured logging in Golang. There doesn't seem to be a
reason to do a major, breaking iteration into Logrus V2, since the fantastic Go
community has built those independently. Many fantastic alternatives have sprung
up. Logrus would look like those, had it been re-designed with what we know
about structured logging in Go today. Check out, for example,
[Zerolog][zerolog], [Zap][zap], and [Apex][apex].
[zerolog]: https://github.com/rs/zerolog
[zap]: https://github.com/uber-go/zap
[apex]: https://github.com/apex/log
**Seeing weird case-sensitive problems?** It's in the past been possible to
import Logrus as both upper- and lower-case. Due to the Go package environment,
this caused issues in the community and we needed a standard. Some environments
experienced problems with the upper-case variant, so the lower-case was decided.
Everything using `logrus` will need to use the lower-case:
`github.com/sirupsen/logrus`. Any package that isn't, should be changed.
To fix Glide, see [these
comments](https://github.com/sirupsen/logrus/issues/553#issuecomment-306591437).
For an in-depth explanation of the casing issue, see [this
comment](https://github.com/sirupsen/logrus/issues/570#issuecomment-313933276).
Nicely color-coded in development (when a TTY is attached, otherwise just
plain text):
![Colored](http://i.imgur.com/PY7qMwd.png)
With `log.SetFormatter(&log.JSONFormatter{})`, for easy parsing by logstash
or Splunk:
```json
{"animal":"walrus","level":"info","msg":"A group of walrus emerges from the
ocean","size":10,"time":"2014-03-10 19:57:38.562264131 -0400 EDT"}
{"level":"warning","msg":"The group's number increased tremendously!",
"number":122,"omg":true,"time":"2014-03-10 19:57:38.562471297 -0400 EDT"}
{"animal":"walrus","level":"info","msg":"A giant walrus appears!",
"size":10,"time":"2014-03-10 19:57:38.562500591 -0400 EDT"}
{"animal":"walrus","level":"info","msg":"Tremendously sized cow enters the ocean.",
"size":9,"time":"2014-03-10 19:57:38.562527896 -0400 EDT"}
{"level":"fatal","msg":"The ice breaks!","number":100,"omg":true,
"time":"2014-03-10 19:57:38.562543128 -0400 EDT"}
```
With the default `log.SetFormatter(&log.TextFormatter{})` when a TTY is not
attached, the output is compatible with the
[logfmt](http://godoc.org/github.com/kr/logfmt) format:
```text
time="2015-03-26T01:27:38-04:00" level=debug msg="Started observing beach" animal=walrus number=8
time="2015-03-26T01:27:38-04:00" level=info msg="A group of walrus emerges from the ocean" animal=walrus size=10
time="2015-03-26T01:27:38-04:00" level=warning msg="The group's number increased tremendously!" number=122 omg=true
time="2015-03-26T01:27:38-04:00" level=debug msg="Temperature changes" temperature=-4
time="2015-03-26T01:27:38-04:00" level=panic msg="It's over 9000!" animal=orca size=9009
time="2015-03-26T01:27:38-04:00" level=fatal msg="The ice breaks!" err=&{0x2082280c0 map[animal:orca size:9009] 2015-03-26 01:27:38.441574009 -0400 EDT panic It's over 9000!} number=100 omg=true
```
To ensure this behaviour even if a TTY is attached, set your formatter as follows:
```go
log.SetFormatter(&log.TextFormatter{
DisableColors: true,
FullTimestamp: true,
})
```
#### Logging Method Name
If you wish to add the calling method as a field, instruct the logger via:
```go
log.SetReportCaller(true)
```
This adds the caller as 'method' like so:
```json
{"animal":"penguin","level":"fatal","method":"github.com/sirupsen/arcticcreatures.migrate","msg":"a penguin swims by",
"time":"2014-03-10 19:57:38.562543129 -0400 EDT"}
```
```text
time="2015-03-26T01:27:38-04:00" level=fatal method=github.com/sirupsen/arcticcreatures.migrate msg="a penguin swims by" animal=penguin
```
Note that this does add measurable overhead - the cost will depend on the version of Go, but is
between 20 and 40% in recent tests with 1.6 and 1.7. You can validate this in your
environment via benchmarks:
```
go test -bench=.*CallerTracing
```
#### Case-sensitivity
The organization's name was changed to lower-case--and this will not be changed
back. If you are getting import conflicts due to case sensitivity, please use
the lower-case import: `github.com/sirupsen/logrus`.
#### Example
The simplest way to use Logrus is simply the package-level exported logger:
```go
package main
import (
log "github.com/sirupsen/logrus"
)
func main() {
log.WithFields(log.Fields{
"animal": "walrus",
}).Info("A walrus appears")
}
```
Note that it's completely api-compatible with the stdlib logger, so you can
replace your `log` imports everywhere with `log "github.com/sirupsen/logrus"`
and you'll now have the flexibility of Logrus. You can customize it all you
want:
```go
package main
import (
"os"
log "github.com/sirupsen/logrus"
)
func init() {
// Log as JSON instead of the default ASCII formatter.
log.SetFormatter(&log.JSONFormatter{})
// Output to stdout instead of the default stderr
// Can be any io.Writer, see below for File example
log.SetOutput(os.Stdout)
// Only log the warning severity or above.
log.SetLevel(log.WarnLevel)
}
func main() {
log.WithFields(log.Fields{
"animal": "walrus",
"size": 10,
}).Info("A group of walrus emerges from the ocean")
log.WithFields(log.Fields{
"omg": true,
"number": 122,
}).Warn("The group's number increased tremendously!")
log.WithFields(log.Fields{
"omg": true,
"number": 100,
}).Fatal("The ice breaks!")
// A common pattern is to re-use fields between logging statements by re-using
// the logrus.Entry returned from WithFields()
contextLogger := log.WithFields(log.Fields{
"common": "this is a common field",
"other": "I also should be logged always",
})
contextLogger.Info("I'll be logged with common and other field")
contextLogger.Info("Me too")
}
```
For more advanced usage such as logging to multiple locations from the same
application, you can also create an instance of the `logrus` Logger:
```go
package main
import (
"os"
"github.com/sirupsen/logrus"
)
// Create a new instance of the logger. You can have any number of instances.
var log = logrus.New()
func main() {
// The API for setting attributes is a little different than the package level
// exported logger. See Godoc.
log.Out = os.Stdout
// You could set this to any `io.Writer` such as a file
// file, err := os.OpenFile("logrus.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
// if err == nil {
// log.Out = file
// } else {
// log.Info("Failed to log to file, using default stderr")
// }
log.WithFields(logrus.Fields{
"animal": "walrus",
"size": 10,
}).Info("A group of walrus emerges from the ocean")
}
```
#### Fields
Logrus encourages careful, structured logging through logging fields instead of
long, unparseable error messages. For example, instead of: `log.Fatalf("Failed
to send event %s to topic %s with key %d")`, you should log the much more
discoverable:
```go
log.WithFields(log.Fields{
"event": event,
"topic": topic,
"key": key,
}).Fatal("Failed to send event")
```
We've found this API forces you to think about logging in a way that produces
much more useful logging messages. We've been in countless situations where just
a single added field to a log statement that was already there would've saved us
hours. The `WithFields` call is optional.
In general, with Logrus using any of the `printf`-family functions should be
seen as a hint you should add a field, however, you can still use the
`printf`-family functions with Logrus.
#### Default Fields
Often it's helpful to have fields _always_ attached to log statements in an
application or parts of one. For example, you may want to always log the
`request_id` and `user_ip` in the context of a request. Instead of writing
`log.WithFields(log.Fields{"request_id": request_id, "user_ip": user_ip})` on
every line, you can create a `logrus.Entry` to pass around instead:
```go
requestLogger := log.WithFields(log.Fields{"request_id": request_id, "user_ip": user_ip})
requestLogger.Info("something happened on that request") # will log request_id and user_ip
requestLogger.Warn("something not great happened")
```
#### Hooks
You can add hooks for logging levels. For example to send errors to an exception
tracking service on `Error`, `Fatal` and `Panic`, info to StatsD or log to
multiple places simultaneously, e.g. syslog.
Logrus comes with [built-in hooks](hooks/). Add those, or your custom hook, in
`init`:
```go
import (
log "github.com/sirupsen/logrus"
"gopkg.in/gemnasium/logrus-airbrake-hook.v2" // the package is named "airbrake"
logrus_syslog "github.com/sirupsen/logrus/hooks/syslog"
"log/syslog"
)
func init() {
// Use the Airbrake hook to report errors that have Error severity or above to
// an exception tracker. You can create custom hooks, see the Hooks section.
log.AddHook(airbrake.NewHook(123, "xyz", "production"))
hook, err := logrus_syslog.NewSyslogHook("udp", "localhost:514", syslog.LOG_INFO, "")
if err != nil {
log.Error("Unable to connect to local syslog daemon")
} else {
log.AddHook(hook)
}
}
```
Note: Syslog hook also support connecting to local syslog (Ex. "/dev/log" or "/var/run/syslog" or "/var/run/log"). For the detail, please check the [syslog hook README](hooks/syslog/README.md).
A list of currently known service hooks can be found in this wiki [page](https://github.com/sirupsen/logrus/wiki/Hooks)
#### Level logging
Logrus has seven logging levels: Trace, Debug, Info, Warning, Error, Fatal and Panic.
```go
log.Trace("Something very low level.")
log.Debug("Useful debugging information.")
log.Info("Something noteworthy happened!")
log.Warn("You should probably take a look at this.")
log.Error("Something failed but I'm not quitting.")
// Calls os.Exit(1) after logging
log.Fatal("Bye.")
// Calls panic() after logging
log.Panic("I'm bailing.")
```
You can set the logging level on a `Logger`, then it will only log entries with
that severity or anything above it:
```go
// Will log anything that is info or above (warn, error, fatal, panic). Default.
log.SetLevel(log.InfoLevel)
```
It may be useful to set `log.Level = logrus.DebugLevel` in a debug or verbose
environment if your application has that.
#### Entries
Besides the fields added with `WithField` or `WithFields` some fields are
automatically added to all logging events:
1. `time`. The timestamp when the entry was created.
2. `msg`. The logging message passed to `{Info,Warn,Error,Fatal,Panic}` after
the `AddFields` call. E.g. `Failed to send event.`
3. `level`. The logging level. E.g. `info`.
#### Environments
Logrus has no notion of environment.
If you wish for hooks and formatters to only be used in specific environments,
you should handle that yourself. For example, if your application has a global
variable `Environment`, which is a string representation of the environment you
could do:
```go
import (
log "github.com/sirupsen/logrus"
)
init() {
// do something here to set environment depending on an environment variable
// or command-line flag
if Environment == "production" {
log.SetFormatter(&log.JSONFormatter{})
} else {
// The TextFormatter is default, you don't actually have to do this.
log.SetFormatter(&log.TextFormatter{})
}
}
```
This configuration is how `logrus` was intended to be used, but JSON in
production is mostly only useful if you do log aggregation with tools like
Splunk or Logstash.
#### Formatters
The built-in logging formatters are:
* `logrus.TextFormatter`. Logs the event in colors if stdout is a tty, otherwise
without colors.
* *Note:* to force colored output when there is no TTY, set the `ForceColors`
field to `true`. To force no colored output even if there is a TTY set the
`DisableColors` field to `true`. For Windows, see
[github.com/mattn/go-colorable](https://github.com/mattn/go-colorable).
* When colors are enabled, levels are truncated to 4 characters by default. To disable
truncation set the `DisableLevelTruncation` field to `true`.
* When outputting to a TTY, it's often helpful to visually scan down a column where all the levels are the same width. Setting the `PadLevelText` field to `true` enables this behavior, by adding padding to the level text.
* All options are listed in the [generated docs](https://godoc.org/github.com/sirupsen/logrus#TextFormatter).
* `logrus.JSONFormatter`. Logs fields as JSON.
* All options are listed in the [generated docs](https://godoc.org/github.com/sirupsen/logrus#JSONFormatter).
Third party logging formatters:
* [`FluentdFormatter`](https://github.com/joonix/log). Formats entries that can be parsed by Kubernetes and Google Container Engine.
* [`GELF`](https://github.com/fabienm/go-logrus-formatters). Formats entries so they comply to Graylog's [GELF 1.1 specification](http://docs.graylog.org/en/2.4/pages/gelf.html).
* [`logstash`](https://github.com/bshuster-repo/logrus-logstash-hook). Logs fields as [Logstash](http://logstash.net) Events.
* [`prefixed`](https://github.com/x-cray/logrus-prefixed-formatter). Displays log entry source along with alternative layout.
* [`zalgo`](https://github.com/aybabtme/logzalgo). Invoking the Power of Zalgo.
* [`nested-logrus-formatter`](https://github.com/antonfisher/nested-logrus-formatter). Converts logrus fields to a nested structure.
* [`powerful-logrus-formatter`](https://github.com/zput/zxcTool). get fileName, log's line number and the latest function's name when print log; Sava log to files.
* [`caption-json-formatter`](https://github.com/nolleh/caption_json_formatter). logrus's message json formatter with human-readable caption added.
You can define your formatter by implementing the `Formatter` interface,
requiring a `Format` method. `Format` takes an `*Entry`. `entry.Data` is a
`Fields` type (`map[string]interface{}`) with all your fields as well as the
default ones (see Entries section above):
```go
type MyJSONFormatter struct {
}
log.SetFormatter(new(MyJSONFormatter))
func (f *MyJSONFormatter) Format(entry *Entry) ([]byte, error) {
// Note this doesn't include Time, Level and Message which are available on
// the Entry. Consult `godoc` on information about those fields or read the
// source of the official loggers.
serialized, err := json.Marshal(entry.Data)
if err != nil {
return nil, fmt.Errorf("Failed to marshal fields to JSON, %v", err)
}
return append(serialized, '\n'), nil
}
```
#### Logger as an `io.Writer`
Logrus can be transformed into an `io.Writer`. That writer is the end of an `io.Pipe` and it is your responsibility to close it.
```go
w := logger.Writer()
defer w.Close()
srv := http.Server{
// create a stdlib log.Logger that writes to
// logrus.Logger.
ErrorLog: log.New(w, "", 0),
}
```
Each line written to that writer will be printed the usual way, using formatters
and hooks. The level for those entries is `info`.
This means that we can override the standard library logger easily:
```go
logger := logrus.New()
logger.Formatter = &logrus.JSONFormatter{}
// Use logrus for standard log output
// Note that `log` here references stdlib's log
// Not logrus imported under the name `log`.
log.SetOutput(logger.Writer())
```
#### Rotation
Log rotation is not provided with Logrus. Log rotation should be done by an
external program (like `logrotate(8)`) that can compress and delete old log
entries. It should not be a feature of the application-level logger.
#### Tools
| Tool | Description |
| ---- | ----------- |
|[Logrus Mate](https://github.com/gogap/logrus_mate)|Logrus mate is a tool for Logrus to manage loggers, you can initial logger's level, hook and formatter by config file, the logger will be generated with different configs in different environments.|
|[Logrus Viper Helper](https://github.com/heirko/go-contrib/tree/master/logrusHelper)|An Helper around Logrus to wrap with spf13/Viper to load configuration with fangs! And to simplify Logrus configuration use some behavior of [Logrus Mate](https://github.com/gogap/logrus_mate). [sample](https://github.com/heirko/iris-contrib/blob/master/middleware/logrus-logger/example) |
#### Testing
Logrus has a built in facility for asserting the presence of log messages. This is implemented through the `test` hook and provides:
* decorators for existing logger (`test.NewLocal` and `test.NewGlobal`) which basically just adds the `test` hook
* a test logger (`test.NewNullLogger`) that just records log messages (and does not output any):
```go
import(
"github.com/sirupsen/logrus"
"github.com/sirupsen/logrus/hooks/test"
"github.com/stretchr/testify/assert"
"testing"
)
func TestSomething(t*testing.T){
logger, hook := test.NewNullLogger()
logger.Error("Helloerror")
assert.Equal(t, 1, len(hook.Entries))
assert.Equal(t, logrus.ErrorLevel, hook.LastEntry().Level)
assert.Equal(t, "Helloerror", hook.LastEntry().Message)
hook.Reset()
assert.Nil(t, hook.LastEntry())
}
```
#### Fatal handlers
Logrus can register one or more functions that will be called when any `fatal`
level message is logged. The registered handlers will be executed before
logrus performs an `os.Exit(1)`. This behavior may be helpful if callers need
to gracefully shutdown. Unlike a `panic("Something went wrong...")` call which can be intercepted with a deferred `recover` a call to `os.Exit(1)` can not be intercepted.
```
...
handler := func() {
// gracefully shutdown something...
}
logrus.RegisterExitHandler(handler)
...
```
#### Thread safety
By default, Logger is protected by a mutex for concurrent writes. The mutex is held when calling hooks and writing logs.
If you are sure such locking is not needed, you can call logger.SetNoLock() to disable the locking.
Situation when locking is not needed includes:
* You have no hooks registered, or hooks calling is already thread-safe.
* Writing to logger.Out is already thread-safe, for example:
1) logger.Out is protected by locks.
2) logger.Out is an os.File handler opened with `O_APPEND` flag, and every write is smaller than 4k. (This allows multi-thread/multi-process writing)
(Refer to http://www.notthewizard.com/2014/06/17/are-files-appends-really-atomic/)

76
vendor/github.com/sirupsen/logrus/alt_exit.go generated vendored Normal file
View File

@ -0,0 +1,76 @@
package logrus
// The following code was sourced and modified from the
// https://github.com/tebeka/atexit package governed by the following license:
//
// Copyright (c) 2012 Miki Tebeka <miki.tebeka@gmail.com>.
//
// 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.
import (
"fmt"
"os"
)
var handlers = []func(){}
func runHandler(handler func()) {
defer func() {
if err := recover(); err != nil {
fmt.Fprintln(os.Stderr, "Error: Logrus exit handler error:", err)
}
}()
handler()
}
func runHandlers() {
for _, handler := range handlers {
runHandler(handler)
}
}
// Exit runs all the Logrus atexit handlers and then terminates the program using os.Exit(code)
func Exit(code int) {
runHandlers()
os.Exit(code)
}
// RegisterExitHandler appends a Logrus Exit handler to the list of handlers,
// call logrus.Exit to invoke all handlers. The handlers will also be invoked when
// any Fatal log entry is made.
//
// This method is useful when a caller wishes to use logrus to log a fatal
// message but also needs to gracefully shutdown. An example usecase could be
// closing database connections, or sending a alert that the application is
// closing.
func RegisterExitHandler(handler func()) {
handlers = append(handlers, handler)
}
// DeferExitHandler prepends a Logrus Exit handler to the list of handlers,
// call logrus.Exit to invoke all handlers. The handlers will also be invoked when
// any Fatal log entry is made.
//
// This method is useful when a caller wishes to use logrus to log a fatal
// message but also needs to gracefully shutdown. An example usecase could be
// closing database connections, or sending a alert that the application is
// closing.
func DeferExitHandler(handler func()) {
handlers = append([]func(){handler}, handlers...)
}

14
vendor/github.com/sirupsen/logrus/appveyor.yml generated vendored Normal file
View File

@ -0,0 +1,14 @@
version: "{build}"
platform: x64
clone_folder: c:\gopath\src\github.com\sirupsen\logrus
environment:
GOPATH: c:\gopath
branches:
only:
- master
install:
- set PATH=%GOPATH%\bin;c:\go\bin;%PATH%
- go version
build_script:
- go get -t
- go test

52
vendor/github.com/sirupsen/logrus/buffer_pool.go generated vendored Normal file
View File

@ -0,0 +1,52 @@
package logrus
import (
"bytes"
"sync"
)
var (
bufferPool BufferPool
)
type BufferPool interface {
Put(*bytes.Buffer)
Get() *bytes.Buffer
}
type defaultPool struct {
pool *sync.Pool
}
func (p *defaultPool) Put(buf *bytes.Buffer) {
p.pool.Put(buf)
}
func (p *defaultPool) Get() *bytes.Buffer {
return p.pool.Get().(*bytes.Buffer)
}
func getBuffer() *bytes.Buffer {
return bufferPool.Get()
}
func putBuffer(buf *bytes.Buffer) {
buf.Reset()
bufferPool.Put(buf)
}
// SetBufferPool allows to replace the default logrus buffer pool
// to better meets the specific needs of an application.
func SetBufferPool(bp BufferPool) {
bufferPool = bp
}
func init() {
SetBufferPool(&defaultPool{
pool: &sync.Pool{
New: func() interface{} {
return new(bytes.Buffer)
},
},
})
}

26
vendor/github.com/sirupsen/logrus/doc.go generated vendored Normal file
View File

@ -0,0 +1,26 @@
/*
Package logrus is a structured logger for Go, completely API compatible with the standard library logger.
The simplest way to use Logrus is simply the package-level exported logger:
package main
import (
log "github.com/sirupsen/logrus"
)
func main() {
log.WithFields(log.Fields{
"animal": "walrus",
"number": 1,
"size": 10,
}).Info("A walrus appears")
}
Output:
time="2015-09-07T08:48:33Z" level=info msg="A walrus appears" animal=walrus number=1 size=10
For a full guide visit https://github.com/sirupsen/logrus
*/
package logrus

422
vendor/github.com/sirupsen/logrus/entry.go generated vendored Normal file
View File

@ -0,0 +1,422 @@
package logrus
import (
"bytes"
"context"
"fmt"
"os"
"reflect"
"runtime"
"strings"
"sync"
"time"
)
var (
// qualified package name, cached at first use
logrusPackage string
// Positions in the call stack when tracing to report the calling method
minimumCallerDepth int
// Used for caller information initialisation
callerInitOnce sync.Once
)
const (
maximumCallerDepth int = 25
knownLogrusFrames int = 4
)
func init() {
// start at the bottom of the stack before the package-name cache is primed
minimumCallerDepth = 1
}
// Defines the key when adding errors using WithError.
var ErrorKey = "error"
// An entry is the final or intermediate Logrus logging entry. It contains all
// the fields passed with WithField{,s}. It's finally logged when Trace, Debug,
// Info, Warn, Error, Fatal or Panic is called on it. These objects can be
// reused and passed around as much as you wish to avoid field duplication.
type Entry struct {
Logger *Logger
// Contains all the fields set by the user.
Data Fields
// Time at which the log entry was created
Time time.Time
// Level the log entry was logged at: Trace, Debug, Info, Warn, Error, Fatal or Panic
// This field will be set on entry firing and the value will be equal to the one in Logger struct field.
Level Level
// Calling method, with package name
Caller *runtime.Frame
// Message passed to Trace, Debug, Info, Warn, Error, Fatal or Panic
Message string
// When formatter is called in entry.log(), a Buffer may be set to entry
Buffer *bytes.Buffer
// Contains the context set by the user. Useful for hook processing etc.
Context context.Context
// err may contain a field formatting error
err string
}
func NewEntry(logger *Logger) *Entry {
return &Entry{
Logger: logger,
// Default is three fields, plus one optional. Give a little extra room.
Data: make(Fields, 6),
}
}
// Returns the bytes representation of this entry from the formatter.
func (entry *Entry) Bytes() ([]byte, error) {
return entry.Logger.Formatter.Format(entry)
}
// Returns the string representation from the reader and ultimately the
// formatter.
func (entry *Entry) String() (string, error) {
serialized, err := entry.Bytes()
if err != nil {
return "", err
}
str := string(serialized)
return str, nil
}
// Add an error as single field (using the key defined in ErrorKey) to the Entry.
func (entry *Entry) WithError(err error) *Entry {
return entry.WithField(ErrorKey, err)
}
// Add a context to the Entry.
func (entry *Entry) WithContext(ctx context.Context) *Entry {
dataCopy := make(Fields, len(entry.Data))
for k, v := range entry.Data {
dataCopy[k] = v
}
return &Entry{Logger: entry.Logger, Data: dataCopy, Time: entry.Time, err: entry.err, Context: ctx}
}
// Add a single field to the Entry.
func (entry *Entry) WithField(key string, value interface{}) *Entry {
return entry.WithFields(Fields{key: value})
}
// Add a map of fields to the Entry.
func (entry *Entry) WithFields(fields Fields) *Entry {
data := make(Fields, len(entry.Data)+len(fields))
for k, v := range entry.Data {
data[k] = v
}
fieldErr := entry.err
for k, v := range fields {
isErrField := false
if t := reflect.TypeOf(v); t != nil {
switch t.Kind() {
case reflect.Func:
isErrField = true
case reflect.Ptr:
isErrField = t.Elem().Kind() == reflect.Func
}
}
if isErrField {
tmp := fmt.Sprintf("can not add field %q", k)
if fieldErr != "" {
fieldErr = entry.err + ", " + tmp
} else {
fieldErr = tmp
}
} else {
data[k] = v
}
}
return &Entry{Logger: entry.Logger, Data: data, Time: entry.Time, err: fieldErr, Context: entry.Context}
}
// Overrides the time of the Entry.
func (entry *Entry) WithTime(t time.Time) *Entry {
dataCopy := make(Fields, len(entry.Data))
for k, v := range entry.Data {
dataCopy[k] = v
}
return &Entry{Logger: entry.Logger, Data: dataCopy, Time: t, err: entry.err, Context: entry.Context}
}
// getPackageName reduces a fully qualified function name to the package name
// There really ought to be to be a better way...
func getPackageName(f string) string {
for {
lastPeriod := strings.LastIndex(f, ".")
lastSlash := strings.LastIndex(f, "/")
if lastPeriod > lastSlash {
f = f[:lastPeriod]
} else {
break
}
}
return f
}
// getCaller retrieves the name of the first non-logrus calling function
func getCaller() *runtime.Frame {
// cache this package's fully-qualified name
callerInitOnce.Do(func() {
pcs := make([]uintptr, maximumCallerDepth)
_ = runtime.Callers(0, pcs)
// dynamic get the package name and the minimum caller depth
for i := 0; i < maximumCallerDepth; i++ {
funcName := runtime.FuncForPC(pcs[i]).Name()
if strings.Contains(funcName, "getCaller") {
logrusPackage = getPackageName(funcName)
break
}
}
minimumCallerDepth = knownLogrusFrames
})
// Restrict the lookback frames to avoid runaway lookups
pcs := make([]uintptr, maximumCallerDepth)
depth := runtime.Callers(minimumCallerDepth, pcs)
frames := runtime.CallersFrames(pcs[:depth])
for f, again := frames.Next(); again; f, again = frames.Next() {
pkg := getPackageName(f.Function)
// If the caller isn't part of this package, we're done
if pkg != logrusPackage {
return &f //nolint:scopelint
}
}
// if we got here, we failed to find the caller's context
return nil
}
func (entry Entry) HasCaller() (has bool) {
return entry.Logger != nil &&
entry.Logger.ReportCaller &&
entry.Caller != nil
}
// This function is not declared with a pointer value because otherwise
// race conditions will occur when using multiple goroutines
func (entry Entry) log(level Level, msg string) {
var buffer *bytes.Buffer
// Default to now, but allow users to override if they want.
//
// We don't have to worry about polluting future calls to Entry#log()
// with this assignment because this function is declared with a
// non-pointer receiver.
if entry.Time.IsZero() {
entry.Time = time.Now()
}
entry.Level = level
entry.Message = msg
entry.Logger.mu.Lock()
if entry.Logger.ReportCaller {
entry.Caller = getCaller()
}
entry.Logger.mu.Unlock()
entry.fireHooks()
buffer = getBuffer()
defer func() {
entry.Buffer = nil
putBuffer(buffer)
}()
buffer.Reset()
entry.Buffer = buffer
entry.write()
entry.Buffer = nil
// To avoid Entry#log() returning a value that only would make sense for
// panic() to use in Entry#Panic(), we avoid the allocation by checking
// directly here.
if level <= PanicLevel {
panic(&entry)
}
}
func (entry *Entry) fireHooks() {
entry.Logger.mu.Lock()
defer entry.Logger.mu.Unlock()
err := entry.Logger.Hooks.Fire(entry.Level, entry)
if err != nil {
fmt.Fprintf(os.Stderr, "Failed to fire hook: %v\n", err)
}
}
func (entry *Entry) write() {
entry.Logger.mu.Lock()
defer entry.Logger.mu.Unlock()
serialized, err := entry.Logger.Formatter.Format(entry)
if err != nil {
fmt.Fprintf(os.Stderr, "Failed to obtain reader, %v\n", err)
return
}
if _, err = entry.Logger.Out.Write(serialized); err != nil {
fmt.Fprintf(os.Stderr, "Failed to write to log, %v\n", err)
}
}
func (entry *Entry) Log(level Level, args ...interface{}) {
if entry.Logger.IsLevelEnabled(level) {
entry.log(level, fmt.Sprint(args...))
}
}
func (entry *Entry) Trace(args ...interface{}) {
entry.Log(TraceLevel, args...)
}
func (entry *Entry) Debug(args ...interface{}) {
entry.Log(DebugLevel, args...)
}
func (entry *Entry) Print(args ...interface{}) {
entry.Info(args...)
}
func (entry *Entry) Info(args ...interface{}) {
entry.Log(InfoLevel, args...)
}
func (entry *Entry) Warn(args ...interface{}) {
entry.Log(WarnLevel, args...)
}
func (entry *Entry) Warning(args ...interface{}) {
entry.Warn(args...)
}
func (entry *Entry) Error(args ...interface{}) {
entry.Log(ErrorLevel, args...)
}
func (entry *Entry) Fatal(args ...interface{}) {
entry.Log(FatalLevel, args...)
entry.Logger.Exit(1)
}
func (entry *Entry) Panic(args ...interface{}) {
entry.Log(PanicLevel, args...)
panic(fmt.Sprint(args...))
}
// Entry Printf family functions
func (entry *Entry) Logf(level Level, format string, args ...interface{}) {
if entry.Logger.IsLevelEnabled(level) {
entry.Log(level, fmt.Sprintf(format, args...))
}
}
func (entry *Entry) Tracef(format string, args ...interface{}) {
entry.Logf(TraceLevel, format, args...)
}
func (entry *Entry) Debugf(format string, args ...interface{}) {
entry.Logf(DebugLevel, format, args...)
}
func (entry *Entry) Infof(format string, args ...interface{}) {
entry.Logf(InfoLevel, format, args...)
}
func (entry *Entry) Printf(format string, args ...interface{}) {
entry.Infof(format, args...)
}
func (entry *Entry) Warnf(format string, args ...interface{}) {
entry.Logf(WarnLevel, format, args...)
}
func (entry *Entry) Warningf(format string, args ...interface{}) {
entry.Warnf(format, args...)
}
func (entry *Entry) Errorf(format string, args ...interface{}) {
entry.Logf(ErrorLevel, format, args...)
}
func (entry *Entry) Fatalf(format string, args ...interface{}) {
entry.Logf(FatalLevel, format, args...)
entry.Logger.Exit(1)
}
func (entry *Entry) Panicf(format string, args ...interface{}) {
entry.Logf(PanicLevel, format, args...)
}
// Entry Println family functions
func (entry *Entry) Logln(level Level, args ...interface{}) {
if entry.Logger.IsLevelEnabled(level) {
entry.Log(level, entry.sprintlnn(args...))
}
}
func (entry *Entry) Traceln(args ...interface{}) {
entry.Logln(TraceLevel, args...)
}
func (entry *Entry) Debugln(args ...interface{}) {
entry.Logln(DebugLevel, args...)
}
func (entry *Entry) Infoln(args ...interface{}) {
entry.Logln(InfoLevel, args...)
}
func (entry *Entry) Println(args ...interface{}) {
entry.Infoln(args...)
}
func (entry *Entry) Warnln(args ...interface{}) {
entry.Logln(WarnLevel, args...)
}
func (entry *Entry) Warningln(args ...interface{}) {
entry.Warnln(args...)
}
func (entry *Entry) Errorln(args ...interface{}) {
entry.Logln(ErrorLevel, args...)
}
func (entry *Entry) Fatalln(args ...interface{}) {
entry.Logln(FatalLevel, args...)
entry.Logger.Exit(1)
}
func (entry *Entry) Panicln(args ...interface{}) {
entry.Logln(PanicLevel, args...)
}
// Sprintlnn => Sprint no newline. This is to get the behavior of how
// fmt.Sprintln where spaces are always added between operands, regardless of
// their type. Instead of vendoring the Sprintln implementation to spare a
// string allocation, we do the simplest thing.
func (entry *Entry) sprintlnn(args ...interface{}) string {
msg := fmt.Sprintln(args...)
return msg[:len(msg)-1]
}

270
vendor/github.com/sirupsen/logrus/exported.go generated vendored Normal file
View File

@ -0,0 +1,270 @@
package logrus
import (
"context"
"io"
"time"
)
var (
// std is the name of the standard logger in stdlib `log`
std = New()
)
func StandardLogger() *Logger {
return std
}
// SetOutput sets the standard logger output.
func SetOutput(out io.Writer) {
std.SetOutput(out)
}
// SetFormatter sets the standard logger formatter.
func SetFormatter(formatter Formatter) {
std.SetFormatter(formatter)
}
// SetReportCaller sets whether the standard logger will include the calling
// method as a field.
func SetReportCaller(include bool) {
std.SetReportCaller(include)
}
// SetLevel sets the standard logger level.
func SetLevel(level Level) {
std.SetLevel(level)
}
// GetLevel returns the standard logger level.
func GetLevel() Level {
return std.GetLevel()
}
// IsLevelEnabled checks if the log level of the standard logger is greater than the level param
func IsLevelEnabled(level Level) bool {
return std.IsLevelEnabled(level)
}
// AddHook adds a hook to the standard logger hooks.
func AddHook(hook Hook) {
std.AddHook(hook)
}
// WithError creates an entry from the standard logger and adds an error to it, using the value defined in ErrorKey as key.
func WithError(err error) *Entry {
return std.WithField(ErrorKey, err)
}
// WithContext creates an entry from the standard logger and adds a context to it.
func WithContext(ctx context.Context) *Entry {
return std.WithContext(ctx)
}
// WithField creates an entry from the standard logger and adds a field to
// it. If you want multiple fields, use `WithFields`.
//
// Note that it doesn't log until you call Debug, Print, Info, Warn, Fatal
// or Panic on the Entry it returns.
func WithField(key string, value interface{}) *Entry {
return std.WithField(key, value)
}
// WithFields creates an entry from the standard logger and adds multiple
// fields to it. This is simply a helper for `WithField`, invoking it
// once for each field.
//
// Note that it doesn't log until you call Debug, Print, Info, Warn, Fatal
// or Panic on the Entry it returns.
func WithFields(fields Fields) *Entry {
return std.WithFields(fields)
}
// WithTime creates an entry from the standard logger and overrides the time of
// logs generated with it.
//
// Note that it doesn't log until you call Debug, Print, Info, Warn, Fatal
// or Panic on the Entry it returns.
func WithTime(t time.Time) *Entry {
return std.WithTime(t)
}
// Trace logs a message at level Trace on the standard logger.
func Trace(args ...interface{}) {
std.Trace(args...)
}
// Debug logs a message at level Debug on the standard logger.
func Debug(args ...interface{}) {
std.Debug(args...)
}
// Print logs a message at level Info on the standard logger.
func Print(args ...interface{}) {
std.Print(args...)
}
// Info logs a message at level Info on the standard logger.
func Info(args ...interface{}) {
std.Info(args...)
}
// Warn logs a message at level Warn on the standard logger.
func Warn(args ...interface{}) {
std.Warn(args...)
}
// Warning logs a message at level Warn on the standard logger.
func Warning(args ...interface{}) {
std.Warning(args...)
}
// Error logs a message at level Error on the standard logger.
func Error(args ...interface{}) {
std.Error(args...)
}
// Panic logs a message at level Panic on the standard logger.
func Panic(args ...interface{}) {
std.Panic(args...)
}
// Fatal logs a message at level Fatal on the standard logger then the process will exit with status set to 1.
func Fatal(args ...interface{}) {
std.Fatal(args...)
}
// TraceFn logs a message from a func at level Trace on the standard logger.
func TraceFn(fn LogFunction) {
std.TraceFn(fn)
}
// DebugFn logs a message from a func at level Debug on the standard logger.
func DebugFn(fn LogFunction) {
std.DebugFn(fn)
}
// PrintFn logs a message from a func at level Info on the standard logger.
func PrintFn(fn LogFunction) {
std.PrintFn(fn)
}
// InfoFn logs a message from a func at level Info on the standard logger.
func InfoFn(fn LogFunction) {
std.InfoFn(fn)
}
// WarnFn logs a message from a func at level Warn on the standard logger.
func WarnFn(fn LogFunction) {
std.WarnFn(fn)
}
// WarningFn logs a message from a func at level Warn on the standard logger.
func WarningFn(fn LogFunction) {
std.WarningFn(fn)
}
// ErrorFn logs a message from a func at level Error on the standard logger.
func ErrorFn(fn LogFunction) {
std.ErrorFn(fn)
}
// PanicFn logs a message from a func at level Panic on the standard logger.
func PanicFn(fn LogFunction) {
std.PanicFn(fn)
}
// FatalFn logs a message from a func at level Fatal on the standard logger then the process will exit with status set to 1.
func FatalFn(fn LogFunction) {
std.FatalFn(fn)
}
// Tracef logs a message at level Trace on the standard logger.
func Tracef(format string, args ...interface{}) {
std.Tracef(format, args...)
}
// Debugf logs a message at level Debug on the standard logger.
func Debugf(format string, args ...interface{}) {
std.Debugf(format, args...)
}
// Printf logs a message at level Info on the standard logger.
func Printf(format string, args ...interface{}) {
std.Printf(format, args...)
}
// Infof logs a message at level Info on the standard logger.
func Infof(format string, args ...interface{}) {
std.Infof(format, args...)
}
// Warnf logs a message at level Warn on the standard logger.
func Warnf(format string, args ...interface{}) {
std.Warnf(format, args...)
}
// Warningf logs a message at level Warn on the standard logger.
func Warningf(format string, args ...interface{}) {
std.Warningf(format, args...)
}
// Errorf logs a message at level Error on the standard logger.
func Errorf(format string, args ...interface{}) {
std.Errorf(format, args...)
}
// Panicf logs a message at level Panic on the standard logger.
func Panicf(format string, args ...interface{}) {
std.Panicf(format, args...)
}
// Fatalf logs a message at level Fatal on the standard logger then the process will exit with status set to 1.
func Fatalf(format string, args ...interface{}) {
std.Fatalf(format, args...)
}
// Traceln logs a message at level Trace on the standard logger.
func Traceln(args ...interface{}) {
std.Traceln(args...)
}
// Debugln logs a message at level Debug on the standard logger.
func Debugln(args ...interface{}) {
std.Debugln(args...)
}
// Println logs a message at level Info on the standard logger.
func Println(args ...interface{}) {
std.Println(args...)
}
// Infoln logs a message at level Info on the standard logger.
func Infoln(args ...interface{}) {
std.Infoln(args...)
}
// Warnln logs a message at level Warn on the standard logger.
func Warnln(args ...interface{}) {
std.Warnln(args...)
}
// Warningln logs a message at level Warn on the standard logger.
func Warningln(args ...interface{}) {
std.Warningln(args...)
}
// Errorln logs a message at level Error on the standard logger.
func Errorln(args ...interface{}) {
std.Errorln(args...)
}
// Panicln logs a message at level Panic on the standard logger.
func Panicln(args ...interface{}) {
std.Panicln(args...)
}
// Fatalln logs a message at level Fatal on the standard logger then the process will exit with status set to 1.
func Fatalln(args ...interface{}) {
std.Fatalln(args...)
}

78
vendor/github.com/sirupsen/logrus/formatter.go generated vendored Normal file
View File

@ -0,0 +1,78 @@
package logrus
import "time"
// Default key names for the default fields
const (
defaultTimestampFormat = time.RFC3339
FieldKeyMsg = "msg"
FieldKeyLevel = "level"
FieldKeyTime = "time"
FieldKeyLogrusError = "logrus_error"
FieldKeyFunc = "func"
FieldKeyFile = "file"
)
// The Formatter interface is used to implement a custom Formatter. It takes an
// `Entry`. It exposes all the fields, including the default ones:
//
// * `entry.Data["msg"]`. The message passed from Info, Warn, Error ..
// * `entry.Data["time"]`. The timestamp.
// * `entry.Data["level"]. The level the entry was logged at.
//
// Any additional fields added with `WithField` or `WithFields` are also in
// `entry.Data`. Format is expected to return an array of bytes which are then
// logged to `logger.Out`.
type Formatter interface {
Format(*Entry) ([]byte, error)
}
// This is to not silently overwrite `time`, `msg`, `func` and `level` fields when
// dumping it. If this code wasn't there doing:
//
// logrus.WithField("level", 1).Info("hello")
//
// Would just silently drop the user provided level. Instead with this code
// it'll logged as:
//
// {"level": "info", "fields.level": 1, "msg": "hello", "time": "..."}
//
// It's not exported because it's still using Data in an opinionated way. It's to
// avoid code duplication between the two default formatters.
func prefixFieldClashes(data Fields, fieldMap FieldMap, reportCaller bool) {
timeKey := fieldMap.resolve(FieldKeyTime)
if t, ok := data[timeKey]; ok {
data["fields."+timeKey] = t
delete(data, timeKey)
}
msgKey := fieldMap.resolve(FieldKeyMsg)
if m, ok := data[msgKey]; ok {
data["fields."+msgKey] = m
delete(data, msgKey)
}
levelKey := fieldMap.resolve(FieldKeyLevel)
if l, ok := data[levelKey]; ok {
data["fields."+levelKey] = l
delete(data, levelKey)
}
logrusErrKey := fieldMap.resolve(FieldKeyLogrusError)
if l, ok := data[logrusErrKey]; ok {
data["fields."+logrusErrKey] = l
delete(data, logrusErrKey)
}
// If reportCaller is not set, 'func' will not conflict.
if reportCaller {
funcKey := fieldMap.resolve(FieldKeyFunc)
if l, ok := data[funcKey]; ok {
data["fields."+funcKey] = l
}
fileKey := fieldMap.resolve(FieldKeyFile)
if l, ok := data[fileKey]; ok {
data["fields."+fileKey] = l
}
}
}

10
vendor/github.com/sirupsen/logrus/go.mod generated vendored Normal file
View File

@ -0,0 +1,10 @@
module github.com/sirupsen/logrus
require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/stretchr/testify v1.2.2
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037
)
go 1.13

10
vendor/github.com/sirupsen/logrus/go.sum generated vendored Normal file
View File

@ -0,0 +1,10 @@
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894 h1:Cz4ceDQGXuKRnVBDTS23GTn/pU5OE2C0WrNTOYK1Uuc=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037 h1:YyJpGZS1sBuBCzLAR1VEpK193GlqGZbnPFnPV/5Rsb4=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=

34
vendor/github.com/sirupsen/logrus/hooks.go generated vendored Normal file
View File

@ -0,0 +1,34 @@
package logrus
// A hook to be fired when logging on the logging levels returned from
// `Levels()` on your implementation of the interface. Note that this is not
// fired in a goroutine or a channel with workers, you should handle such
// functionality yourself if your call is non-blocking and you don't wish for
// the logging calls for levels returned from `Levels()` to block.
type Hook interface {
Levels() []Level
Fire(*Entry) error
}
// Internal type for storing the hooks on a logger instance.
type LevelHooks map[Level][]Hook
// Add a hook to an instance of logger. This is called with
// `log.Hooks.Add(new(MyHook))` where `MyHook` implements the `Hook` interface.
func (hooks LevelHooks) Add(hook Hook) {
for _, level := range hook.Levels() {
hooks[level] = append(hooks[level], hook)
}
}
// Fire all the hooks for the passed level. Used by `entry.log` to fire
// appropriate hooks for a log entry.
func (hooks LevelHooks) Fire(level Level, entry *Entry) error {
for _, hook := range hooks[level] {
if err := hook.Fire(entry); err != nil {
return err
}
}
return nil
}

125
vendor/github.com/sirupsen/logrus/json_formatter.go generated vendored Normal file
View File

@ -0,0 +1,125 @@
package logrus
import (
"bytes"
"encoding/json"
"fmt"
"runtime"
)
type fieldKey string
// FieldMap allows customization of the key names for default fields.
type FieldMap map[fieldKey]string
func (f FieldMap) resolve(key fieldKey) string {
if k, ok := f[key]; ok {
return k
}
return string(key)
}
// JSONFormatter formats logs into parsable json
type JSONFormatter struct {
// TimestampFormat sets the format used for marshaling timestamps.
TimestampFormat string
// DisableTimestamp allows disabling automatic timestamps in output
DisableTimestamp bool
// DisableHTMLEscape allows disabling html escaping in output
DisableHTMLEscape bool
// DataKey allows users to put all the log entry parameters into a nested dictionary at a given key.
DataKey string
// FieldMap allows users to customize the names of keys for default fields.
// As an example:
// formatter := &JSONFormatter{
// FieldMap: FieldMap{
// FieldKeyTime: "@timestamp",
// FieldKeyLevel: "@level",
// FieldKeyMsg: "@message",
// FieldKeyFunc: "@caller",
// },
// }
FieldMap FieldMap
// CallerPrettyfier can be set by the user to modify the content
// of the function and file keys in the json data when ReportCaller is
// activated. If any of the returned value is the empty string the
// corresponding key will be removed from json fields.
CallerPrettyfier func(*runtime.Frame) (function string, file string)
// PrettyPrint will indent all json logs
PrettyPrint bool
}
// Format renders a single log entry
func (f *JSONFormatter) Format(entry *Entry) ([]byte, error) {
data := make(Fields, len(entry.Data)+4)
for k, v := range entry.Data {
switch v := v.(type) {
case error:
// Otherwise errors are ignored by `encoding/json`
// https://github.com/sirupsen/logrus/issues/137
data[k] = v.Error()
default:
data[k] = v
}
}
if f.DataKey != "" {
newData := make(Fields, 4)
newData[f.DataKey] = data
data = newData
}
prefixFieldClashes(data, f.FieldMap, entry.HasCaller())
timestampFormat := f.TimestampFormat
if timestampFormat == "" {
timestampFormat = defaultTimestampFormat
}
if entry.err != "" {
data[f.FieldMap.resolve(FieldKeyLogrusError)] = entry.err
}
if !f.DisableTimestamp {
data[f.FieldMap.resolve(FieldKeyTime)] = entry.Time.Format(timestampFormat)
}
data[f.FieldMap.resolve(FieldKeyMsg)] = entry.Message
data[f.FieldMap.resolve(FieldKeyLevel)] = entry.Level.String()
if entry.HasCaller() {
funcVal := entry.Caller.Function
fileVal := fmt.Sprintf("%s:%d", entry.Caller.File, entry.Caller.Line)
if f.CallerPrettyfier != nil {
funcVal, fileVal = f.CallerPrettyfier(entry.Caller)
}
if funcVal != "" {
data[f.FieldMap.resolve(FieldKeyFunc)] = funcVal
}
if fileVal != "" {
data[f.FieldMap.resolve(FieldKeyFile)] = fileVal
}
}
var b *bytes.Buffer
if entry.Buffer != nil {
b = entry.Buffer
} else {
b = &bytes.Buffer{}
}
encoder := json.NewEncoder(b)
encoder.SetEscapeHTML(!f.DisableHTMLEscape)
if f.PrettyPrint {
encoder.SetIndent("", " ")
}
if err := encoder.Encode(data); err != nil {
return nil, fmt.Errorf("failed to marshal fields to JSON, %v", err)
}
return b.Bytes(), nil
}

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