Imported Upstream version 2.5.0 upstream/2.5.0
authorhyokeun <hyokeun.jeon@samsung.com>
Fri, 21 Dec 2018 05:52:24 +0000 (14:52 +0900)
committerhyokeun <hyokeun.jeon@samsung.com>
Fri, 21 Dec 2018 05:52:24 +0000 (14:52 +0900)
341 files changed:
.gitignore
.travis.yml
CHANGELOG.md
CONTRIBUTING.md
Makefile
README.md
appveyor.yml
commands/command_checkout.go
commands/command_ls_files.go
commands/command_migrate.go
commands/command_migrate_export.go [new file with mode: 0644]
commands/command_migrate_import.go
commands/command_migrate_info.go
commands/command_push.go
commands/command_status.go
commands/command_track.go
commands/uploader.go
config/config.go
config/git_fetcher.go
config/version.go
debian/changelog
debian/rules
docs/man/git-lfs-checkout.1.ronn
docs/man/git-lfs-config.5.ronn
docs/man/git-lfs-migrate.1.ronn
docs/man/git-lfs-track.1.ronn
docs/man/git-lfs.1.ronn
fs/fs.go
fs/fs_test.go [new file with mode: 0644]
git/attribs.go
git/git.go
git/git_test.go
git/gitattr/attr.go [new file with mode: 0644]
git/gitattr/attr_test.go [new file with mode: 0644]
git/gitattr/tree.go [new file with mode: 0644]
git/gitattr/tree_test.go [new file with mode: 0644]
git/githistory/fixtures_test.go
git/githistory/ref_updater.go
git/githistory/rewriter.go
git/githistory/rewriter_test.go
glide.lock
glide.yaml
lfs/gitfilter_smudge.go
lfs/gitscanner.go
lfs/gitscanner_refs.go
lfs/lfs.go
lfs/lfs_test.go
lfs/scanner_git_test.go
lfsapi/client.go
lfsapi/creds.go
lfsapi/endpoint.go
lfsapi/endpoint_finder.go
lfsapi/endpoint_finder_test.go
lfsapi/lfsapi.go
lfsapi/proxy.go
lfsapi/ssh.go
rpm/SPECS/git-lfs.spec
rpm/build_rpms.bsh
script/bootstrap [deleted file]
script/build.go [deleted file]
script/cibuild
script/fmt [deleted file]
script/genmakefile/genmakefile.go [deleted file]
script/install.sh [moved from script/install.sh.example with 100% similarity]
script/integration [deleted file]
script/integration.go [deleted file]
script/lint [deleted file]
script/man [deleted file]
script/release
script/release.go
script/run [deleted file]
script/script.go
script/test [deleted file]
script/update-version [deleted file]
script/vendor [deleted file]
t/Makefile [new file with mode: 0644]
t/README.md [new file with mode: 0644]
t/cmd/git-credential-lfsnoop.go [moved from test/cmd/git-credential-lfsnoop.go with 100% similarity]
t/cmd/git-credential-lfstest.go [moved from test/cmd/git-credential-lfstest.go with 100% similarity]
t/cmd/lfs-askpass.go [moved from test/cmd/lfs-askpass.go with 100% similarity]
t/cmd/lfs-ssh-echo.go [moved from test/cmd/lfs-ssh-echo.go with 100% similarity]
t/cmd/lfs-ssh-proxy-test.go [moved from test/cmd/lfs-ssh-proxy-test.go with 100% similarity]
t/cmd/lfstest-count-tests.go [new file with mode: 0644]
t/cmd/lfstest-customadapter.go [moved from test/cmd/lfstest-customadapter.go with 100% similarity]
t/cmd/lfstest-gitserver.go [moved from test/cmd/lfstest-gitserver.go with 99% similarity]
t/cmd/lfstest-standalonecustomadapter.go [moved from test/cmd/lfstest-standalonecustomadapter.go with 100% similarity]
t/cmd/lfstest-testutils.go [moved from test/cmd/lfstest-testutils.go with 88% similarity]
t/cmd/util/testutils.go [moved from test/testutils.go with 99% similarity]
t/fixtures/migrate.sh [moved from test/test-migrate-fixtures.sh with 50% similarity]
t/git-lfs-test-server-api/.gitignore [new file with mode: 0644]
t/git-lfs-test-server-api/README.md [moved from test/git-lfs-test-server-api/README.md with 100% similarity]
t/git-lfs-test-server-api/main.go [moved from test/git-lfs-test-server-api/main.go with 94% similarity]
t/git-lfs-test-server-api/testdownload.go [moved from test/git-lfs-test-server-api/testdownload.go with 100% similarity]
t/git-lfs-test-server-api/testupload.go [moved from test/git-lfs-test-server-api/testupload.go with 100% similarity]
t/t-askpass.sh [moved from test/test-askpass.sh with 78% similarity]
t/t-batch-error-handling.sh [moved from test/test-batch-error-handling.sh with 98% similarity]
t/t-batch-retries.sh [moved from test/test-batch-retries.sh with 98% similarity]
t/t-batch-transfer.sh [moved from test/test-batch-transfer.sh with 99% similarity]
t/t-batch-unknown-oids.sh [moved from test/test-batch-unknown-oids.sh with 95% similarity]
t/t-checkout.sh [moved from test/test-checkout.sh with 85% similarity]
t/t-chunked-transfer-encoding.sh [moved from test/test-chunked-transfer-encoding.sh with 98% similarity]
t/t-clean.sh [moved from test/test-clean.sh with 99% similarity]
t/t-clone-deprecated.sh [moved from test/test-clone-deprecated.sh with 93% similarity]
t/t-clone.sh [moved from test/test-clone.sh with 99% similarity]
t/t-commit-delete-push.sh [moved from test/test-commit-delete-push.sh with 97% similarity]
t/t-config.sh [moved from test/test-config.sh with 99% similarity]
t/t-credentials-no-prompt.sh [moved from test/test-credentials-no-prompt.sh with 97% similarity]
t/t-credentials.sh [moved from test/test-credentials.sh with 98% similarity]
t/t-custom-transfers.sh [moved from test/test-custom-transfers.sh with 99% similarity]
t/t-duplicate-oids.sh [moved from test/test-duplicate-oids.sh with 97% similarity]
t/t-env.sh [moved from test/test-env.sh with 94% similarity]
t/t-expired.sh [moved from test/test-expired.sh with 97% similarity]
t/t-ext.sh [moved from test/test-ext.sh with 97% similarity]
t/t-extra-header.sh [moved from test/test-extra-header.sh with 98% similarity]
t/t-fetch-include.sh [moved from test/test-fetch-include.sh with 98% similarity]
t/t-fetch-paths.sh [moved from test/test-fetch-paths.sh with 98% similarity]
t/t-fetch-recent.sh [moved from test/test-fetch-recent.sh with 99% similarity]
t/t-fetch-refspec.sh [moved from test/test-fetch-refspec.sh with 98% similarity]
t/t-fetch.sh [moved from test/test-fetch.sh with 99% similarity]
t/t-filter-branch.sh [moved from test/test-filter-branch.sh with 96% similarity]
t/t-filter-process.sh [moved from test/test-filter-process.sh with 98% similarity]
t/t-fsck.sh [moved from test/test-fsck.sh with 98% similarity]
t/t-happy-path.sh [moved from test/test-happy-path.sh with 99% similarity]
t/t-install-custom-hooks-path-unsupported.sh [moved from test/test-install-custom-hooks-path-unsupported.sh with 95% similarity]
t/t-install-custom-hooks-path.sh [moved from test/test-install-custom-hooks-path.sh with 96% similarity]
t/t-install.sh [moved from test/test-install.sh with 99% similarity]
t/t-lock.sh [moved from test/test-lock.sh with 99% similarity]
t/t-locks.sh [moved from test/test-locks.sh with 99% similarity]
t/t-logs.sh [moved from test/test-logs.sh with 92% similarity]
t/t-ls-files.sh [moved from test/test-ls-files.sh with 90% similarity]
t/t-malformed-pointers.sh [moved from test/test-malformed-pointers.sh with 98% similarity]
t/t-mergetool.sh [moved from test/test-mergetool.sh with 96% similarity]
t/t-migrate-export.sh [new file with mode: 0755]
t/t-migrate-fixup.sh [new file with mode: 0755]
t/t-migrate-import-no-rewrite.sh [new file with mode: 0755]
t/t-migrate-import.sh [moved from test/test-migrate-import.sh with 85% similarity]
t/t-migrate-info.sh [moved from test/test-migrate-info.sh with 99% similarity]
t/t-object-authenticated.sh [moved from test/test-object-authenticated.sh with 94% similarity]
t/t-pointer.sh [moved from test/test-pointer.sh with 98% similarity]
t/t-post-checkout.sh [moved from test/test-post-checkout.sh with 99% similarity]
t/t-post-commit.sh [moved from test/test-post-commit.sh with 98% similarity]
t/t-post-merge.sh [moved from test/test-post-merge.sh with 98% similarity]
t/t-pre-push.sh [moved from test/test-pre-push.sh with 99% similarity]
t/t-progress-meter.sh [moved from test/test-progress-meter.sh with 94% similarity]
t/t-progress.sh [moved from test/test-progress.sh with 97% similarity]
t/t-prune-worktree.sh [moved from test/test-prune-worktree.sh with 99% similarity]
t/t-prune.sh [moved from test/test-prune.sh with 99% similarity]
t/t-pull.sh [moved from test/test-pull.sh with 97% similarity]
t/t-push-bad-dns.sh [moved from test/test-push-bad-dns.sh with 95% similarity]
t/t-push-failures-local.sh [new file with mode: 0755]
t/t-push-failures-remote.sh [moved from test/test-push-failures.sh with 98% similarity]
t/t-push-file-with-branch-name.sh [moved from test/test-push-file-with-branch-name.sh with 93% similarity]
t/t-push.sh [moved from test/test-push.sh with 85% similarity]
t/t-reference-clone.sh [moved from test/test-reference-clone.sh with 98% similarity]
t/t-resume-http-range.sh [moved from test/test-resume-http-range.sh with 98% similarity]
t/t-resume-tus.sh [moved from test/test-resume-tus.sh with 98% similarity]
t/t-smudge.sh [moved from test/test-smudge.sh with 99% similarity]
t/t-ssh.sh [moved from test/test-ssh.sh with 95% similarity]
t/t-status.sh [moved from test/test-status.sh with 94% similarity]
t/t-submodule-lfsconfig.sh [moved from test/test-submodule-lfsconfig.sh with 98% similarity]
t/t-submodule.sh [moved from test/test-submodule.sh with 98% similarity]
t/t-track-attrs.sh [moved from test/test-track-attrs.sh with 95% similarity]
t/t-track-wildcards.sh [moved from test/test-track-wildcards.sh with 98% similarity, mode: 0755]
t/t-track.sh [moved from test/test-track.sh with 93% similarity]
t/t-uninstall.sh [moved from test/test-uninstall.sh with 99% similarity]
t/t-unlock.sh [moved from test/test-unlock.sh with 99% similarity]
t/t-untrack.sh [moved from test/test-untrack.sh with 98% similarity]
t/t-unusual-filenames.sh [moved from test/test-unusual-filenames.sh with 94% similarity]
t/t-update.sh [moved from test/test-update.sh with 99% similarity]
t/t-verify.sh [moved from test/test-verify.sh with 98% similarity]
t/t-version.sh [moved from test/test-version.sh with 93% similarity]
t/t-worktree.sh [moved from test/test-worktree.sh with 94% similarity]
t/t-zero-len-file.sh [moved from test/test-zero-len-file.sh with 97% similarity]
t/test-alternates.sh [new file with mode: 0755]
t/testenv.sh [moved from test/testenv.sh with 92% similarity]
t/testhelpers.sh [moved from test/testhelpers.sh with 83% similarity]
t/testlib.sh [moved from test/testlib.sh with 79% similarity]
test/README.md [deleted file]
test/git-lfs-test-server-api/.gitignore [deleted file]
test/test-push-missing.sh [deleted file]
tq/basic_upload.go
tq/meter.go
tq/transfer.go
vendor/github.com/git-lfs/gitobj/LICENSE.md [new file with mode: 0644]
vendor/github.com/git-lfs/gitobj/README.md [new file with mode: 0644]
vendor/github.com/git-lfs/gitobj/blob.go [moved from git/odb/blob.go with 69% similarity]
vendor/github.com/git-lfs/gitobj/blob_test.go [moved from git/odb/blob_test.go with 99% similarity]
vendor/github.com/git-lfs/gitobj/commit.go [moved from git/odb/commit.go with 95% similarity]
vendor/github.com/git-lfs/gitobj/commit_test.go [moved from git/odb/commit_test.go with 99% similarity]
vendor/github.com/git-lfs/gitobj/errors.go [moved from git/odb/errors.go with 80% similarity]
vendor/github.com/git-lfs/gitobj/errors_test.go [moved from git/odb/errors_test.go with 64% similarity]
vendor/github.com/git-lfs/gitobj/file_storer.go [moved from git/odb/file_storer.go with 95% similarity]
vendor/github.com/git-lfs/gitobj/glide.lock [new file with mode: 0644]
vendor/github.com/git-lfs/gitobj/glide.yaml [new file with mode: 0644]
vendor/github.com/git-lfs/gitobj/memory_storer.go [moved from git/odb/memory_storer.go with 99% similarity]
vendor/github.com/git-lfs/gitobj/memory_storer_test.go [moved from git/odb/memory_storer_test.go with 99% similarity]
vendor/github.com/git-lfs/gitobj/object.go [moved from git/odb/object.go with 98% similarity]
vendor/github.com/git-lfs/gitobj/object_db.go [moved from git/odb/object_db.go with 96% similarity]
vendor/github.com/git-lfs/gitobj/object_db_test.go [moved from git/odb/object_db_test.go with 96% similarity]
vendor/github.com/git-lfs/gitobj/object_reader.go [moved from git/odb/object_reader.go with 97% similarity]
vendor/github.com/git-lfs/gitobj/object_reader_test.go [moved from git/odb/object_reader_test.go with 98% similarity]
vendor/github.com/git-lfs/gitobj/object_type.go [moved from git/odb/object_type.go with 98% similarity]
vendor/github.com/git-lfs/gitobj/object_type_test.go [moved from git/odb/object_type_test.go with 98% similarity]
vendor/github.com/git-lfs/gitobj/object_writer.go [moved from git/odb/object_writer.go with 96% similarity]
vendor/github.com/git-lfs/gitobj/object_writer_test.go [moved from git/odb/object_writer_test.go with 93% similarity]
vendor/github.com/git-lfs/gitobj/pack/bounds.go [moved from git/odb/pack/bounds.go with 98% similarity]
vendor/github.com/git-lfs/gitobj/pack/bounds_test.go [moved from git/odb/pack/bounds_test.go with 100% similarity]
vendor/github.com/git-lfs/gitobj/pack/chain.go [moved from git/odb/pack/chain.go with 100% similarity]
vendor/github.com/git-lfs/gitobj/pack/chain_base.go [moved from git/odb/pack/chain_base.go with 100% similarity]
vendor/github.com/git-lfs/gitobj/pack/chain_base_test.go [moved from git/odb/pack/chain_base_test.go with 100% similarity]
vendor/github.com/git-lfs/gitobj/pack/chain_delta.go [moved from git/odb/pack/chain_delta.go with 94% similarity]
vendor/github.com/git-lfs/gitobj/pack/chain_delta_test.go [moved from git/odb/pack/chain_delta_test.go with 94% similarity]
vendor/github.com/git-lfs/gitobj/pack/chain_test.go [moved from git/odb/pack/chain_test.go with 100% similarity]
vendor/github.com/git-lfs/gitobj/pack/errors.go [moved from git/odb/pack/errors.go with 83% similarity]
vendor/github.com/git-lfs/gitobj/pack/errors_test.go [moved from git/odb/pack/errors_test.go with 73% similarity]
vendor/github.com/git-lfs/gitobj/pack/index.go [moved from git/odb/pack/index.go with 97% similarity]
vendor/github.com/git-lfs/gitobj/pack/index_decode.go [moved from git/odb/pack/index_decode.go with 97% similarity]
vendor/github.com/git-lfs/gitobj/pack/index_decode_test.go [moved from git/odb/pack/index_decode_test.go with 96% similarity]
vendor/github.com/git-lfs/gitobj/pack/index_entry.go [moved from git/odb/pack/index_entry.go with 100% similarity]
vendor/github.com/git-lfs/gitobj/pack/index_test.go [moved from git/odb/pack/index_test.go with 97% similarity]
vendor/github.com/git-lfs/gitobj/pack/index_v1.go [moved from git/odb/pack/index_v1.go with 100% similarity]
vendor/github.com/git-lfs/gitobj/pack/index_v1_test.go [moved from git/odb/pack/index_v1_test.go with 100% similarity]
vendor/github.com/git-lfs/gitobj/pack/index_v2.go [moved from git/odb/pack/index_v2.go with 100% similarity]
vendor/github.com/git-lfs/gitobj/pack/index_v2_test.go [moved from git/odb/pack/index_v2_test.go with 100% similarity]
vendor/github.com/git-lfs/gitobj/pack/index_version.go [moved from git/odb/pack/index_version.go with 84% similarity]
vendor/github.com/git-lfs/gitobj/pack/io.go [moved from git/odb/pack/io.go with 100% similarity]
vendor/github.com/git-lfs/gitobj/pack/io_test.go [moved from git/odb/pack/io_test.go with 90% similarity]
vendor/github.com/git-lfs/gitobj/pack/object.go [moved from git/odb/pack/object.go with 100% similarity]
vendor/github.com/git-lfs/gitobj/pack/object_test.go [moved from git/odb/pack/object_test.go with 88% similarity]
vendor/github.com/git-lfs/gitobj/pack/packfile.go [moved from git/odb/pack/packfile.go with 97% similarity]
vendor/github.com/git-lfs/gitobj/pack/packfile_decode.go [moved from git/odb/pack/packfile_decode.go with 94% similarity]
vendor/github.com/git-lfs/gitobj/pack/packfile_decode_test.go [moved from git/odb/pack/packfile_decode_test.go with 100% similarity]
vendor/github.com/git-lfs/gitobj/pack/packfile_test.go [moved from git/odb/pack/packfile_test.go with 97% similarity]
vendor/github.com/git-lfs/gitobj/pack/set.go [moved from git/odb/pack/set.go with 100% similarity]
vendor/github.com/git-lfs/gitobj/pack/set_test.go [moved from git/odb/pack/set_test.go with 100% similarity]
vendor/github.com/git-lfs/gitobj/pack/type.go [moved from git/odb/pack/type.go with 85% similarity]
vendor/github.com/git-lfs/gitobj/pack/type_test.go [moved from git/odb/pack/type_test.go with 91% similarity]
vendor/github.com/git-lfs/gitobj/storer.go [moved from git/odb/storer.go with 97% similarity]
vendor/github.com/git-lfs/gitobj/tag.go [moved from git/odb/tag.go with 90% similarity]
vendor/github.com/git-lfs/gitobj/tag_test.go [moved from git/odb/tag_test.go with 99% similarity]
vendor/github.com/git-lfs/gitobj/tree.go [moved from git/odb/tree.go with 98% similarity]
vendor/github.com/git-lfs/gitobj/tree_test.go [moved from git/odb/tree_test.go with 98% similarity]
vendor/github.com/git-lfs/gitobj/vendor/github.com/davecgh/go-spew/.gitignore [new file with mode: 0644]
vendor/github.com/git-lfs/gitobj/vendor/github.com/davecgh/go-spew/.travis.yml [new file with mode: 0644]
vendor/github.com/git-lfs/gitobj/vendor/github.com/davecgh/go-spew/LICENSE [new file with mode: 0644]
vendor/github.com/git-lfs/gitobj/vendor/github.com/davecgh/go-spew/README.md [new file with mode: 0644]
vendor/github.com/git-lfs/gitobj/vendor/github.com/davecgh/go-spew/cov_report.sh [new file with mode: 0644]
vendor/github.com/git-lfs/gitobj/vendor/github.com/davecgh/go-spew/spew/bypass.go [new file with mode: 0644]
vendor/github.com/git-lfs/gitobj/vendor/github.com/davecgh/go-spew/spew/bypasssafe.go [new file with mode: 0644]
vendor/github.com/git-lfs/gitobj/vendor/github.com/davecgh/go-spew/spew/common.go [new file with mode: 0644]
vendor/github.com/git-lfs/gitobj/vendor/github.com/davecgh/go-spew/spew/common_test.go [new file with mode: 0644]
vendor/github.com/git-lfs/gitobj/vendor/github.com/davecgh/go-spew/spew/config.go [new file with mode: 0644]
vendor/github.com/git-lfs/gitobj/vendor/github.com/davecgh/go-spew/spew/doc.go [new file with mode: 0644]
vendor/github.com/git-lfs/gitobj/vendor/github.com/davecgh/go-spew/spew/dump.go [new file with mode: 0644]
vendor/github.com/git-lfs/gitobj/vendor/github.com/davecgh/go-spew/spew/dump_test.go [new file with mode: 0644]
vendor/github.com/git-lfs/gitobj/vendor/github.com/davecgh/go-spew/spew/dumpcgo_test.go [new file with mode: 0644]
vendor/github.com/git-lfs/gitobj/vendor/github.com/davecgh/go-spew/spew/dumpnocgo_test.go [new file with mode: 0644]
vendor/github.com/git-lfs/gitobj/vendor/github.com/davecgh/go-spew/spew/example_test.go [new file with mode: 0644]
vendor/github.com/git-lfs/gitobj/vendor/github.com/davecgh/go-spew/spew/format.go [new file with mode: 0644]
vendor/github.com/git-lfs/gitobj/vendor/github.com/davecgh/go-spew/spew/format_test.go [new file with mode: 0644]
vendor/github.com/git-lfs/gitobj/vendor/github.com/davecgh/go-spew/spew/internal_test.go [new file with mode: 0644]
vendor/github.com/git-lfs/gitobj/vendor/github.com/davecgh/go-spew/spew/internalunsafe_test.go [new file with mode: 0644]
vendor/github.com/git-lfs/gitobj/vendor/github.com/davecgh/go-spew/spew/spew.go [new file with mode: 0644]
vendor/github.com/git-lfs/gitobj/vendor/github.com/davecgh/go-spew/spew/spew_test.go [new file with mode: 0644]
vendor/github.com/git-lfs/gitobj/vendor/github.com/davecgh/go-spew/spew/testdata/dumpcgo.go [new file with mode: 0644]
vendor/github.com/git-lfs/gitobj/vendor/github.com/davecgh/go-spew/test_coverage.txt [new file with mode: 0644]
vendor/github.com/git-lfs/gitobj/vendor/github.com/pmezard/go-difflib/.travis.yml [new file with mode: 0644]
vendor/github.com/git-lfs/gitobj/vendor/github.com/pmezard/go-difflib/LICENSE [new file with mode: 0644]
vendor/github.com/git-lfs/gitobj/vendor/github.com/pmezard/go-difflib/README.md [new file with mode: 0644]
vendor/github.com/git-lfs/gitobj/vendor/github.com/pmezard/go-difflib/difflib/difflib.go [new file with mode: 0644]
vendor/github.com/git-lfs/gitobj/vendor/github.com/pmezard/go-difflib/difflib/difflib_test.go [new file with mode: 0644]
vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/.gitignore [new file with mode: 0644]
vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/.travis.yml [new file with mode: 0644]
vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/Godeps/Godeps.json [new file with mode: 0644]
vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/Godeps/Readme [new file with mode: 0644]
vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/LICENCE.txt [new file with mode: 0644]
vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/LICENSE [new file with mode: 0644]
vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/README.md [new file with mode: 0644]
vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/_codegen/main.go [new file with mode: 0644]
vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/assert/assertion_forward.go [new file with mode: 0644]
vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/assert/assertion_forward.go.tmpl [new file with mode: 0644]
vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/assert/assertions.go [new file with mode: 0644]
vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/assert/assertions_test.go [new file with mode: 0644]
vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/assert/doc.go [new file with mode: 0644]
vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/assert/errors.go [new file with mode: 0644]
vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/assert/forward_assertions.go [new file with mode: 0644]
vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/assert/forward_assertions_test.go [new file with mode: 0644]
vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/assert/http_assertions.go [new file with mode: 0644]
vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/assert/http_assertions_test.go [new file with mode: 0644]
vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/doc.go [new file with mode: 0644]
vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/http/doc.go [new file with mode: 0644]
vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/http/test_response_writer.go [new file with mode: 0644]
vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/http/test_round_tripper.go [new file with mode: 0644]
vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/mock/doc.go [new file with mode: 0644]
vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/mock/mock.go [new file with mode: 0644]
vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/mock/mock_test.go [new file with mode: 0644]
vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/package_test.go [new file with mode: 0644]
vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/require/doc.go [new file with mode: 0644]
vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/require/forward_requirements.go [new file with mode: 0644]
vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/require/forward_requirements_test.go [new file with mode: 0644]
vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/require/require.go [new file with mode: 0644]
vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/require/require.go.tmpl [new file with mode: 0644]
vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/require/require_forward.go [new file with mode: 0644]
vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/require/require_forward.go.tmpl [new file with mode: 0644]
vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/require/requirements.go [new file with mode: 0644]
vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/require/requirements_test.go [new file with mode: 0644]
vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/suite/doc.go [new file with mode: 0644]
vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/suite/interfaces.go [new file with mode: 0644]
vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/suite/suite.go [new file with mode: 0644]
vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/suite/suite_test.go [new file with mode: 0644]
vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/vendor/github.com/davecgh/go-spew/LICENSE [new file with mode: 0644]
vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/vendor/github.com/davecgh/go-spew/spew/bypass.go [new file with mode: 0644]
vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/vendor/github.com/davecgh/go-spew/spew/bypasssafe.go [new file with mode: 0644]
vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/vendor/github.com/davecgh/go-spew/spew/common.go [new file with mode: 0644]
vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/vendor/github.com/davecgh/go-spew/spew/config.go [new file with mode: 0644]
vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/vendor/github.com/davecgh/go-spew/spew/doc.go [new file with mode: 0644]
vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/vendor/github.com/davecgh/go-spew/spew/dump.go [new file with mode: 0644]
vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/vendor/github.com/davecgh/go-spew/spew/format.go [new file with mode: 0644]
vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/vendor/github.com/davecgh/go-spew/spew/spew.go [new file with mode: 0644]
vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/vendor/github.com/pmezard/go-difflib/LICENSE [new file with mode: 0644]
vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/vendor/github.com/pmezard/go-difflib/difflib/difflib.go [new file with mode: 0644]
vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/vendor/github.com/stretchr/objx/.gitignore [new file with mode: 0644]
vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/vendor/github.com/stretchr/objx/LICENSE.md [new file with mode: 0644]
vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/vendor/github.com/stretchr/objx/README.md [new file with mode: 0644]
vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/vendor/github.com/stretchr/objx/accessors.go [new file with mode: 0644]
vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/vendor/github.com/stretchr/objx/codegen/array-access.txt [new file with mode: 0644]
vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/vendor/github.com/stretchr/objx/codegen/index.html [new file with mode: 0644]
vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/vendor/github.com/stretchr/objx/codegen/template.txt [new file with mode: 0644]
vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/vendor/github.com/stretchr/objx/codegen/types_list.txt [new file with mode: 0644]
vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/vendor/github.com/stretchr/objx/constants.go [new file with mode: 0644]
vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/vendor/github.com/stretchr/objx/conversions.go [new file with mode: 0644]
vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/vendor/github.com/stretchr/objx/doc.go [new file with mode: 0644]
vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/vendor/github.com/stretchr/objx/map.go [new file with mode: 0644]
vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/vendor/github.com/stretchr/objx/mutations.go [new file with mode: 0644]
vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/vendor/github.com/stretchr/objx/security.go [new file with mode: 0644]
vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/vendor/github.com/stretchr/objx/tests.go [new file with mode: 0644]
vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/vendor/github.com/stretchr/objx/type_specific_codegen.go [new file with mode: 0644]
vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/vendor/github.com/stretchr/objx/value.go [new file with mode: 0644]
vendor/github.com/git-lfs/wildmatch/wildmatch.go
vendor/github.com/git-lfs/wildmatch/wildmatch_test.go
versioninfo.json

index 525c4e0..e7d06a7 100644 (file)
@@ -8,7 +8,9 @@ man/*
 
 *.test
 tmp
-test/remote
+t/remote
+t/test_count
+t/test_count.lock
 
 debian/git-lfs/
 debian/*.log
index 0064f33..048fb3b 100644 (file)
@@ -1,7 +1,7 @@
 # http://docs.travis-ci.com/user/languages/go/
 language: go
 
-go: 1.8.3
+go: 1.10.3
 
 os:
   - linux
index 0ba431c..4c24d01 100644 (file)
@@ -1,5 +1,68 @@
 # Git LFS Changelog
 
+## 2.5.0 (26 July, 2018)
+
+This release adds three new migration modes, updated developer ergonomics, and
+a handful of bug fixes to Git LFS.
+
+We would like to extend a special thanks to the following open-source
+contributors:
+
+* @calavera for fixing a broken Go test and adding support for custom
+  Content-Type headers in #3137 and #3138.
+* @cbuehlmann for adding support for encoded character names in filepaths via
+  #3093.
+* @larsxschneider for changing the default value of lfs.allowincompletepush in
+  #3109.
+* @NoEffex for supporting TTL in SSH-based authentication tokens via #2867.
+* @ssgelm for adding 'go generate' to our Debian packages via #3083.
+
+### Features
+
+* Makefile: replace many scripts with make targets #3144 (@ttaylorr)
+* {.travis,appveyor}.yml: upgrade to Go 1.10.3 #3146 (@ttaylorr)
+* t: run tests using prove #3125 (@ttaylorr)
+* commands/migrate: infer wildmatches with --fixup #3114 (@ttaylorr)
+* Retry SSH resolution 5 times #2934 (@stanhu)
+* Implement `migrate export` subcommand #3084 (@PastelMobileSuit)
+* Add `--no-rewrite` flag to `migrate import` command #3029 (@PastelMobileSuit)
+
+### Bugs
+
+* t: fix contains_same_elements() fn #3145 (@PastelMobileSuit)
+* commands: warn if working copy is dirty #3124 (@ttaylorr)
+* Ensure provided remote takes precedence over configured pushRemote #3139 (@PastelMobileSuit)
+* Fix proxy unit tests. #3138 (@calavera)
+* commands/command_migrate.go: loosen meaning of '--everything' #3121 (@ttaylorr)
+* lfsapi: don't query askpass for given creds #3126 (@PastelMobileSuit)
+* config/git_fetcher.go: mark 'lfs.allowincompletepush' as safe #3113 (@ttaylorr)
+* fs: support multiple object alternates #3116 (@ttaylorr)
+* commands/checkout: checkout over read-only files #3120 (@ttaylorr)
+* test/testhelpers.sh: look for 64 character SHA-256's #3119 (@ttaylorr)
+* config/config.go: case-insensitive error search #3098 (@ttaylorr)
+* Encoded characters in pathnames #3093 (@cbuehlmann)
+* Support default TTL for authentication tokens acquired via SSH #2867 (@NoEffex)
+* commands/status.go: relative paths outside of root #3080 (@ttaylorr)
+* Run `go generate` on commands in deb build #3083 (@ssgelm)
+* lfsapi: prefer proxying from gitconfig before environment #3062 (@ttaylorr)
+* commands/track: respect global- and system-level gitattributes #3076 (@ttaylorr)
+* git/git.go: pass --multiple to git-fetch(1) when appropriate #3063 (@ttaylorr)
+* commands/checkout: fix inaccurate messaging #3055 (@ttaylorr)
+* commands/migrate: do not migrate empty commits #3054 (@ttaylorr)
+* git/odb: retain trailing newlines in commit messages #3053 (@ttaylorr)
+
+### Misc
+
+* Set original file content type on basic upload. #3137 (@calavera)
+* README.md: Git for Windows ships LFS by default #3112 (@larsxschneider)
+* change lfs.allowincompletepush default from true to false  #3109 (@larsxschneider)
+* *: replace git/odb with vendored copy #3108 (@ttaylorr)
+* test/test-ls-files.sh: skip on CircleCI #3101 (@ttaylorr)
+* lfsapi/ssh.go: use zero-value sentinels #3099 (@ttaylorr)
+* README.md: add link to installation wiki page #3075 (@ttaylorr)
+* docs/man/git-lfs.1.ronn: update casing and missing commands #3059 (@ttaylorr)
+* commands/checkout: mark 'git lfs checkout' as deprecated #3056 (@ttaylorr)
+
 ## 2.4.2 (28 May, 2018)
 
 ### Bugs
index 166d091..1b4739e 100644 (file)
@@ -58,8 +58,8 @@ In general, contributors should develop on branches based off of `master` and pu
 ## Submitting a pull request
 
 0. [Fork][] and clone the repository
-0. Configure and install the dependencies: `script/bootstrap`
-0. Make sure the tests pass on your machine: `script/test`
+0. Configure and install the dependencies: `make`
+0. Make sure the tests pass on your machine: `make test`
 0. Create a new branch based on `master`: `git checkout -b <my-branch-name> master`
 0. Make your change, add tests, and make sure the tests still pass
 0. Push to your fork and [submit a pull request][pr] from your branch to `master`
@@ -107,18 +107,18 @@ your projects in a specific directory, you can symlink it from `$GOPATH`:
     $ cd ~/path/to/your/projects
     $ ln -s $GOPATH/src/github.com/git-lfs/git-lfs
 
-From here, run `script/bootstrap` to build Git LFS in the `./bin` directory.
-Before submitting changes, be sure to run the Go tests and the shell integration
+From here, run `make` to build Git LFS in the `./bin` directory. Before
+submitting changes, be sure to run the Go tests and the shell integration
 tests:
 
-    $ script/test        # runs just the Go tests
-    $ script/integration # runs the shell tests in ./test
+    $ make test          # runs just the Go tests
+    $ cd t && make test  # runs the shell tests in ./test
     $ script/cibuild     # runs everything, with verbose debug output
 
 ## Updating 3rd party packages
 
 0. Update `glide.yaml`.
-0. Run `script/vendor` to update the code in the `vendor` directory.
+0. Run `make vendor` to update the code in the `vendor` directory.
 0. Commit the change.  Git LFS vendors the full source code in the repository.
 0. Submit a pull request.
 
@@ -128,11 +128,11 @@ If you are the current maintainer:
 
 * Create a [new draft Release](https://github.com/git-lfs/git-lfs/releases/new).
 List any changes with links to related PRs.
-* Make sure your local dependencies are up to date: `script/bootstrap`
+* Make sure your local dependencies are up to date: `make vendor`
 * Ensure that tests are green: `script/cibuild`
 * Bump the version in `lfs/lfs.go`, [like this](https://github.com/git-lfs/git-lfs/commit/dd17828e4a6f2394cbba8621037199dc28f046e8).
 * Add the new version to the top of CHANGELOG.md
-* Build for all platforms with `script/bootstrap -all` (you need Go setup for
+* Build for all platforms with `make release` (you need Go setup for
 cross compiling with Mac, Linux, FreeBSD, and Windows support).
 * Test the command locally.  The compiled version will be in `bin/releases/{os}-{arch}/git-lfs-{version}/git-lfs`
 * Get the draft Release ID from the GitHub API: `curl -in https://api.github.com/repos/git-lfs/git-lfs/releases`
index 8dd5edd..59555d4 100644 (file)
--- a/Makefile
+++ b/Makefile
-GOC ?= gccgo
-AR ?= ar
+# GIT_LFS_SHA is the '--short'-form SHA1 of the current revision of Git LFS.
+GIT_LFS_SHA ?= $(shell git rev-parse --short HEAD)
+# VERSION is the longer-form describe output of the current revision of Git LFS,
+# used for identifying intermediate releases.
+#
+# If Git LFS is being built for a published release, VERSION and GIT_LFS_SHA
+# should be identical.
+VERSION ?= $(shell git describe HEAD)
 
-SRCDIR := $(dir $(lastword $(MAKEFILE_LIST)))
+# GO is the name of the 'go' binary used to compile Git LFS.
+GO ?= go
 
-LIBDIR := out/github.com/git-lfs/git-lfs
-GOFLAGS := -Iout
+# GO_TEST_EXTRA_ARGS are extra arguments given to invocations of 'go test'.
+#
+# Examples include:
+#
+#      make test GO_TEST_EXTRA_ARGS=-v
+#      make test GO_TEST_EXTRA_ARGS='-run TestMyExample'
+GO_TEST_EXTRA_ARGS =
 
-ifeq ($(MAKEFILE_GEN),)
+# BUILTIN_LD_FLAGS are the internal flags used to pass to the linker. By default
+# the config.GitCommit variable is always set via this variable, and
+# DWARF-stripping is enabled unless DWARF=YesPlease.
+BUILTIN_LD_FLAGS =
+BUILTIN_LD_FLAGS += -X github.com/git-lfs/git-lfs/config.GitCommit=$(GIT_LFS_SHA)
+ifneq ("$(DWARF)","YesPlease")
+BUILTIN_LD_FLAGS += -s
+BUILTIN_LD_FLAGS += -w
+endif
+# EXTRA_LD_FLAGS are given by the caller, and are passed to the Go linker after
+# BUILTIN_LD_FLAGS are processed.
+EXTRA_LD_FLAGS =
+# LD_FLAGS is the union of the above two BUILTIN_LD_FLAGS and EXTRA_LD_FLAGS.
+LD_FLAGS = $(BUILTIN_LD_FLAGS) $(EXTRA_LD_FLAGS)
+
+# BUILTIN_GC_FLAGS are the internal flags used to pass compiler.
+BUILTIN_GC_FLAGS =
+# EXTRA_GC_FLAGS are the caller-provided flags to pass to the compiler.
+EXTRA_GC_FLAGS =
+# GC_FLAGS are the union of the above two BUILTIN_GC_FLAGS and EXTRA_GC_FLAGS.
+GC_FLAGS = $(BUILTIN_GC_FLAGS) $(EXTRA_GC_FLAGS)
+
+# GLIDE is the name of the 'glide' binary used to manage vendored dependencies.
+GLIDE ?= glide
 
-MAKEFILE_GEN := out/Makefile.gen
+# RONN is the name of the 'ronn' program used to generate man pages.
+RONN ?= ronn
+# RONN_EXTRA_ARGS are extra arguments given to the $(RONN) program when invoked.
+RONN_EXTRA_ARGS ?=
 
-all: $(MAKEFILE_GEN)
-       @$(MAKE) -f $(lastword $(MAKEFILE_LIST)) $(MAKEFLAGS) MAKEFILE_GEN=$(MAKEFILE_GEN) $@
+# GREP is the name of the program used for regular expression matching, or
+# 'grep' if unset.
+GREP ?= grep
+# RM is the name of the program used removing files, or 'rm -f' if unset.
+RM ?= rm -f
+# XARGS is the name of the program used to turn stdin into program arguments, or
+# 'xargs' if unset.
+XARGS ?= xargs
 
-$(MAKEFILE_GEN) : out/genmakefile $(SRCDIR)commands/mancontent_gen.go
-       @mkdir -p $(dir $@)
-       $< "$(SRCDIR)" github.com/git-lfs/git-lfs/ > $@
+# GOIMPORTS is the name of the program formatter used before compiling.
+GOIMPORTS ?= goimports
+# GOIMPORTS_EXTRA_OPTS are the default options given to the $(GOIMPORTS)
+# program.
+GOIMPORTS_EXTRA_OPTS ?= -w -l
 
+# SOURCES is a listing of all .go files in this and child directories, excluding
+# that in vendor.
+SOURCES = $(shell find . -type f -name '*.go' | grep -v vendor)
+# PKGS is a listing of packages that are considered to be a part of Git LFS, and
+# are used in package-specific commands, such as the 'make test' targets. For
+# example:
+#
+#      make test                               # run 'go test' in all packages
+#      make PKGS='config git/githistory' test  # run 'go test' in config and
+#                                              # git/githistory
+#
+# By default, it is a listing of all packages in Git LFS. When new packages (or
+# sub-packages) are created, they should be added here.
+ifndef PKGS
+PKGS =
+PKGS += commands
+PKGS += config
+PKGS += errors
+PKGS += filepathfilter
+PKGS += fs
+PKGS += git
+PKGS += git/gitattr
+PKGS += git/githistory
+PKGS += git
+PKGS += lfs
+PKGS += lfsapi
+PKGS += locking
+PKGS += subprocess
+PKGS += tasklog
+PKGS += tools
+PKGS += tools/humanize
+PKGS += tools/kv
+PKGS += tq
+endif
+
+# X is the platform-specific extension for Git LFS binaries. It is automatically
+# set to .exe on Windows, and the empty string on all other platforms. It may be
+# overridden.
+#
+# BUILD_MAIN is the main ".go" file that contains func main() for Git LFS. On
+# macOS and other non-Windows platforms, it is required that a specific
+# entrypoint be given, hence the below conditional. On Windows, it is required
+# that an entrypoint not be given so that goversioninfo can successfully embed
+# the resource.syso file (for more, see below).
+ifeq ($(OS),Windows_NT)
+X ?= .exe
+BUILD_MAIN ?=
 else
+X ?=
+BUILD_MAIN ?= ./git-lfs.go
+endif
+
+# BUILD is a macro used to build a single binary of Git LFS using the above
+# LD_FLAGS and GC_FLAGS.
+#
+# It takes three arguments:
+#
+#      $(1) - a valid GOOS value, or empty-string
+#      $(2) - a valid GOARCH value, or empty-string
+#      $(3) - an optional program extension. If $(3) is given as '-foo', then the
+#             program will be written to bin/git-lfs-foo.
+#
+# It uses BUILD_MAIN as defined above to specify the entrypoint for building Git
+# LFS.
+BUILD = GOOS=$(1) GOARCH=$(2) \
+       $(GO) build \
+       -ldflags="$(LD_FLAGS)" \
+       -gcflags="$(GC_FLAGS)" \
+       -o ./bin/git-lfs$(3) $(BUILD_MAIN)
+
+# BUILD_TARGETS is the set of all platforms and architectures that Git LFS is
+# built for.
+BUILD_TARGETS = bin/git-lfs-darwin-amd64 bin/git-lfs-darwin-386 \
+       bin/git-lfs-linux-amd64 bin/git-lfs-linux-386 \
+       bin/git-lfs-freebsd-amd64 bin/git-lfs-freebsd-386 \
+       bin/git-lfs-windows-amd64.exe bin/git-lfs-windows-386.exe
+
+# Targets 'all' and 'build' build binaries of Git LFS for the above release
+# matrix.
+.PHONY : all build
+all build : $(BUILD_TARGETS)
+
+# The following bin/git-lfs-% targets make a single binary compilation of Git
+# LFS for a specific operating system and architecture pair.
+#
+# They function by translating target names into arguments for the above BUILD
+# builtin, and appending the appropriate suffix to the build target.
+#
+# On Windows, they also depend on the resource.syso target, which installs and
+# embeds the versioninfo into the binary.
+bin/git-lfs-darwin-amd64 : $(SOURCES)
+       $(call BUILD,darwin,amd64,-darwin-amd64)
+bin/git-lfs-darwin-386 : $(SOURCES)
+       $(call BUILD,darwin,386,-darwin-386)
+bin/git-lfs-linux-amd64 : $(SOURCES)
+       $(call BUILD,linux,amd64,-linux-amd64)
+bin/git-lfs-linux-386 : $(SOURCES)
+       $(call BUILD,linux,386,-linux-386)
+bin/git-lfs-freebsd-amd64 : $(SOURCES)
+       $(call BUILD,freebsd,amd64,-freebsd-amd64)
+bin/git-lfs-freebsd-386 : $(SOURCES)
+       $(call BUILD,freebsd,386,-freebsd-386)
+bin/git-lfs-windows-amd64.exe : resource.syso $(SOURCES)
+       $(call BUILD,windows,amd64,-windows-amd64.exe)
+bin/git-lfs-windows-386.exe : resource.syso $(SOURCES)
+       $(call BUILD,windows,386,-windows-386.exe)
+
+# .DEFAULT_GOAL sets the operating system-appropriate Git LFS binary as the
+# default output of 'make'.
+.DEFAULT_GOAL := bin/git-lfs$(X)
+
+# bin/git-lfs targets the default output of Git LFS on non-Windows operating
+# systems, and respects the build knobs as above.
+bin/git-lfs : $(SOURCES) fmt
+       $(call BUILD,$(GOOS),$(GOARCH),)
 
-all : bin/git-lfs
+# bin/git-lfs.exe targets the default output of Git LFS on Windows systems, and
+# respects the build knobs as above.
+bin/git-lfs.exe : $(SOURCES) resource.syso
+       $(call BUILD,$(GOOS),$(GOARCH),.exe)
 
-include $(MAKEFILE_GEN)
+# resource.syso installs the 'goversioninfo' command and uses it in order to
+# generate a binary that has information included necessary to create the
+# Windows installer.
+resource.syso:
+       @$(GO) get github.com/josephspurrier/goversioninfo/cmd/goversioninfo
+       $(GO) generate
 
-$(LIBDIR)/git-lfs.o : $(SRC_main) $(DEPS_main)
-       @mkdir -p $(dir $@)
-       $(GOC) $(GOFLAGS) -c -o $@ $(SRC_main)
+# RELEASE_TARGETS is the set of all release artifacts that we generate over a
+# particular release. They each have a corresponding entry in BUILD_TARGETS as
+# above.
+#
+# Unlike BUILD_TARGETS above, each of the below create a compressed directory
+# containing the matching binary, as well as the contents of RELEASE_INCLUDES
+# below.
+#
+# To build a specific release, execute the following:
+#
+#      make bin/releases/git-lfs-darwin-amd64-$(git describe HEAD).tar.gz
+#
+# To build a specific release with a custom VERSION suffix, run the following:
+#
+#      make VERSION=my-version bin/releases/git-lfs-darwin-amd64-my-version.tar.gz
+RELEASE_TARGETS = bin/releases/git-lfs-darwin-amd64-$(VERSION).tar.gz \
+       bin/releases/git-lfs-darwin-386-$(VERSION).tar.gz \
+       bin/releases/git-lfs-linux-amd64-$(VERSION).tar.gz \
+       bin/releases/git-lfs-linux-386-$(VERSION).tar.gz \
+       bin/releases/git-lfs-freebsd-amd64-$(VERSION).tar.gz \
+       bin/releases/git-lfs-freebsd-386-$(VERSION).tar.gz \
+       bin/releases/git-lfs-windows-amd64-$(VERSION).zip \
+       bin/releases/git-lfs-windows-386-$(VERSION).zip
 
-bin/git-lfs : $(LIBDIR)/git-lfs.o $(DEPS_main)
-       @mkdir -p $(dir $@)
-       $(GOC) $(GOFLAGS) -o $@ $^
+# RELEASE_INCLUDES are the names of additional files that are added to each
+# release artifact.
+RELEASE_INCLUDES = README.md CHANGELOG.md
 
-%.a : %.o
-       $(AR) rc $@ $<
+# release is a phony target that builds all of the release artifacts, and then
+# shows the SHA 256 signature of each.
+#
+# To build all of the release binaries for a given Git LFS release:
+#
+#      make release
+.PHONY : release
+release : $(RELEASE_TARGETS)
+       shasum -a 256 $(RELEASE_TARGETS)
 
+# bin/releases/git-lfs-%-$(VERSION).tar.gz generates a gzip-compressed TAR of
+# the non-Windows release artifacts.
+#
+# It includes all of RELEASE_INCLUDES, as well as script/install.sh.
+bin/releases/git-lfs-%-$(VERSION).tar.gz : \
+$(RELEASE_INCLUDES) bin/git-lfs-% script/install.sh
+       @mkdir -p bin/releases
+       tar -s '!bin/git-lfs-.*!git-lfs!' -s '!script/!!' -czf $@ $^
+
+# bin/releases/git-lfs-%-$(VERSION).zip generates a ZIP compression of all of
+# the Windows release artifacts.
+#
+# It includes all of the RELEASE_INCLUDES, and converts LF-style line endings to
+# CRLF in the non-binary components of the artifact.
+bin/releases/git-lfs-%-$(VERSION).zip : $(RELEASE_INCLUDES) bin/git-lfs-%.exe
+       @mkdir -p bin/releases
+       zip -j -l $@ $^
+
+# TEST_TARGETS is a list of all phony test targets. Each one of them corresponds
+# to a specific kind or subset of tests to run.
+TEST_TARGETS := test-bench test-verbose test-race
+.PHONY : $(TEST_TARGETS) test
+$(TEST_TARGETS) : test
+
+# test-bench runs all Go benchmark tests, and nothing more.
+test-bench : GO_TEST_EXTRA_ARGS=-run=__nothing__ -bench=.
+# test-verbose runs all Go tests in verbose mode.
+test-verbose : GO_TEST_EXTRA_ARGS=-v
+# test-race runs all Go tests in race-detection mode.
+test-race : GO_TEST_EXTRA_ARGS=-race
+
+# test runs the Go tests with GO_TEST_EXTRA_ARGS in all specified packages,
+# given by the PKGS variable.
+#
+# For example, a caller can invoke the race-detection tests in just the config
+# package by running:
+#
+#              make PKGS=config test-race
+#
+# Or in a series of packages, like:
+#
+#              make PKGS="config lfsapi tools/kv" test-race
+#
+# And so on.
+test : fmt
+       $(GO) test $(GO_TEST_EXTRA_ARGS) $(addprefix ./,$(PKGS))
+
+# integration is a shorthand for running 'make' in the 't' directory.
+.PHONY : integration
+integration : bin/git-lfs$(X)
+       make -C t test
+
+# glide.lock is the permanent record of the glide.yaml file, and it is built by
+# running 'glide update'.
+glide.lock : glide.yaml
+       $(GLIDE) update
+
+# vendor updates the glide.lock-file, and installs vendored dependencies into
+# the vendor/ sub-tree, removing sub-packages (listed below) that are unused by
+# Git LFS.
+.PHONY : vendor
+vendor : glide.lock
+       $(GLIDE) install
+       $(RM) -r vendor/github.com/ThomsonReutersEikon/go-ntlm/utils
+       $(RM) -r vendor/github.com/davecgh/go-spew
+       $(RM) -r vendor/github.com/pmezard/go-difflib
+
+# fmt runs goimports over all files in Git LFS (as defined by $(SOURCES) above),
+# and replaces their contents with a formatted one in-place.
+#
+# If $(GOIMPORTS) does not exist, or isn't otherwise executable, this recipe
+# still performs the linting sequence, but gracefully skips over running a
+# non-existent command.
+.PHONY : fmt
+ifeq ($(shell test -x "`which $(GOIMPORTS)`"; echo $$?),0)
+fmt : $(SOURCES) | lint
+       $(GOIMPORTS) $(GOIMPORTS_EXTRA_OPTS) $?;
+else
+fmt : $(SOURCES) | lint
+       @echo "git-lfs: skipping fmt, no goimports found at \`$(GOIMPORTS)\` ..."
 endif
 
-$(SRCDIR)commands/mancontent_gen.go : out/mangen
-       cd $(SRCDIR)commands && $(CURDIR)/out/mangen
+# lint ensures that there are all dependencies outside of the standard library
+# are vendored in via vendor (see: above).
+.PHONY : lint
+lint : $(SOURCES)
+       $(GO) list -f '{{ join .Deps "\n" }}' . \
+       | $(XARGS) $(GO) list -f '{{ if not .Standard }}{{ .ImportPath }}{{ end }}' \
+       | $(GREP) -v "github.com/git-lfs/git-lfs" || exit 0
+
+# MAN_ROFF_TARGETS is a list of all ROFF-style targets in the man pages.
+MAN_ROFF_TARGETS = man/git-lfs-checkout.1 \
+  man/git-lfs-clean.1 \
+  man/git-lfs-clone.1 \
+  man/git-lfs-config.5 \
+  man/git-lfs-env.1 \
+  man/git-lfs-ext.1 \
+  man/git-lfs-fetch.1 \
+  man/git-lfs-filter-process.1 \
+  man/git-lfs-fsck.1 \
+  man/git-lfs-install.1 \
+  man/git-lfs-lock.1 \
+  man/git-lfs-locks.1 \
+  man/git-lfs-logs.1 \
+  man/git-lfs-ls-files.1 \
+  man/git-lfs-migrate.1 \
+  man/git-lfs-pointer.1 \
+  man/git-lfs-post-checkout.1 \
+  man/git-lfs-post-merge.1 \
+  man/git-lfs-pre-push.1 \
+  man/git-lfs-prune.1 \
+  man/git-lfs-pull.1 \
+  man/git-lfs-push.1 \
+  man/git-lfs-smudge.1 \
+  man/git-lfs-status.1 \
+  man/git-lfs-track.1 \
+  man/git-lfs-uninstall.1 \
+  man/git-lfs-unlock.1 \
+  man/git-lfs-untrack.1 \
+  man/git-lfs-update.1 \
+  man/git-lfs.1
+
+# MAN_HTML_TARGETS is a list of all HTML-style targets in the man pages.
+MAN_HTML_TARGETS = man/git-lfs-checkout.1.html \
+  man/git-lfs-clean.1.html \
+  man/git-lfs-clone.1.html \
+  man/git-lfs-config.5.html \
+  man/git-lfs-env.1.html \
+  man/git-lfs-ext.1.html \
+  man/git-lfs-fetch.1.html \
+  man/git-lfs-filter-process.1.html \
+  man/git-lfs-fsck.1.html \
+  man/git-lfs-install.1.html \
+  man/git-lfs-lock.1.html \
+  man/git-lfs-locks.1.html \
+  man/git-lfs-logs.1.html \
+  man/git-lfs-ls-files.1.html \
+  man/git-lfs-migrate.1.html \
+  man/git-lfs-pointer.1.html \
+  man/git-lfs-post-checkout.1.html \
+  man/git-lfs-post-merge.1.html \
+  man/git-lfs-pre-push.1.html \
+  man/git-lfs-prune.1.html \
+  man/git-lfs-pull.1.html \
+  man/git-lfs-push.1.html \
+  man/git-lfs-smudge.1.html \
+  man/git-lfs-status.1.html \
+  man/git-lfs-track.1.html \
+  man/git-lfs-uninstall.1.html \
+  man/git-lfs-unlock.1.html \
+  man/git-lfs-untrack.1.html \
+  man/git-lfs-update.1.html \
+  man/git-lfs.1.html
 
-out/mangen : $(SRCDIR)docs/man/mangen.go
-       @mkdir -p $(dir $@)
-       $(GOC) -o $@ $<
+# man generates all ROFF- and HTML-style manpage targets.
+.PHONY : man
+man : $(MAN_ROFF_TARGETS) $(MAN_HTML_TARGETS)
 
-out/genmakefile : $(SRCDIR)script/genmakefile/genmakefile.go
-       @mkdir -p $(dir $@)
-       $(GOC) -o $@ $<
+# man/% generates ROFF-style man pages from the corresponding .ronn file.
+man/% : docs/man/%.ronn
+       @mkdir -p man
+       $(RONN) $(RONN_EXTRA_ARGS) -r --pipe < $^ > $@
 
-clean :
-       rm -rf out bin
-       rm -f $(SRCDIR)commands/mancontent_gen.go
+# man/%.html generates HTML-style man pages from the corresponding .ronn file.
+man/%.html : docs/man/%.ronn
+       @mkdir -p man
+       $(RONN) $(RONN_EXTRA_ARGS) -5 --pipe < $^ > $@
index 8bc3c65..7810c16 100644 (file)
--- a/README.md
+++ b/README.md
@@ -29,12 +29,15 @@ setup and preferences.
   [PackageCloud](https://packagecloud.io/github/git-lfs/install).
 * **macOS users**. [Homebrew](https://brew.sh) bottles are distributed, and can
   be installed via `brew install git-lfs`.
-* **Windows users**. Chocolatey packages are distributed, and can be installed
-  via `choco install git-lfs`.
+* **Windows users**. Git LFS is included in the distribution of 
+  [Git for Windows](https://gitforwindows.org/). Alternatively, you can 
+  install a recent version of Git LFS from the Chocolatey package manager.
 
 In addition, [binary packages](https://github.com/git-lfs/git-lfs/releases) are
 available for Linux, macOS, Windows, and FreeBSD. This repository can also be
-built-from-source using the latest version of [Go](https://golang.org).
+built from source using the latest version of [Go](https://golang.org), and the
+available instructions in our
+[Wiki](https://github.com/git-lfs/git-lfs/wiki/Installation#source).
 
 ### Usage
 
index dd30a52..a3789d1 100644 (file)
@@ -1,16 +1,28 @@
+image: Visual Studio 2017
+
 skip_branch_with_pr: true
 
 environment:
-  GOPATH: $(HOMEDRIVE)$(HOMEPATH)\go
+  GIT_LFS_NO_TEST_COUNT: 1
+  GIT_LFS_LOCK_ACQUIRE_DISABLED: 1
+  GOPATH: C:\Users\appveyor\go
   MSYSTEM: MINGW64
 
 clone_folder: $(GOPATH)\src\github.com\git-lfs\git-lfs
 
 install:
   - rd C:\Go /s /q
-  - cinst golang --version 1.8.3 -y
+  - rd C:\Perl /s /q
+  - refreshenv
+  - curl -sL -o go1.10.3.windows-amd64.zip https://storage.googleapis.com/golang/go1.10.3.windows-amd64.zip
+  - 7z x go1.10.3.windows-amd64.zip -oC:\ >nul
+  - C:\go\bin\go version
   - cinst InnoSetup -y
+  - cinst strawberryperl -y
+  - refreshenv
+  - cinst make
   - refreshenv
+  - set PATH=%GOPATH%\bin\windows_386;%PATH%
   - ps: |
       echo "Go directories in machine PATH environment:"
       [environment]::GetEnvironmentVariable("PATH","Machine").split(";") | Select-String -Pattern "\\go\\"
@@ -22,9 +34,9 @@ install:
       go version
 
 build_script:
-  - bash --login -c 'GOARCH=386 script/bootstrap'
+  - bash --login -c 'make GOARCH=386 -B'
   - mv bin\git-lfs.exe git-lfs-x86.exe
-  - bash --login -c 'GOARCH=amd64 script/bootstrap'
+  - bash --login -c 'make GOARCH=amd64 -B'
   - mv bin\git-lfs.exe git-lfs-x64.exe
 
 after_build:
index d26b002..122f246 100644 (file)
@@ -3,6 +3,7 @@ package commands
 import (
        "fmt"
        "os"
+       "strings"
 
        "github.com/git-lfs/git-lfs/filepathfilter"
        "github.com/git-lfs/git-lfs/git"
@@ -14,6 +15,15 @@ import (
 
 func checkoutCommand(cmd *cobra.Command, args []string) {
        requireInRepo()
+
+       msg := []string{
+               "WARNING: 'git lfs checkout' is deprecated and will be removed in v3.0.0.",
+
+               "'git checkout' has been updated in upstream Git to have comparable speeds",
+               "to 'git lfs checkout'.",
+       }
+       fmt.Fprintln(os.Stderr, strings.Join(msg, "\n"))
+
        ref, err := git.CurrentRef()
        if err != nil {
                Panic(err, "Could not checkout")
@@ -29,6 +39,7 @@ func checkoutCommand(cmd *cobra.Command, args []string) {
        var pointers []*lfs.WrappedPointer
        logger := tasklog.NewLogger(os.Stdout)
        meter := tq.NewMeter()
+       meter.Direction = tq.Checkout
        meter.Logger = meter.LoggerFromEnv(cfg.Os)
        logger.Enqueue(meter)
        chgitscanner := lfs.NewGitScanner(func(p *lfs.WrappedPointer, err error) {
index 612ce58..0129070 100644 (file)
@@ -111,7 +111,8 @@ func lsFilesCommand(cmd *cobra.Command, args []string) {
 
 // Returns true if a pointer appears to be properly smudge on checkout
 func fileExistsOfSize(p *lfs.WrappedPointer) bool {
-       info, err := os.Stat(p.Name)
+       path := cfg.Filesystem().DecodePathname(p.Name)
+       info, err := os.Stat(path)
        return err == nil && info.Size() == p.Size
 }
 
index 8aef8ab..2f4f476 100644 (file)
@@ -1,15 +1,17 @@
 package commands
 
 import (
+       "bufio"
        "fmt"
+       "io"
        "path/filepath"
        "strings"
 
        "github.com/git-lfs/git-lfs/errors"
        "github.com/git-lfs/git-lfs/git"
        "github.com/git-lfs/git-lfs/git/githistory"
-       "github.com/git-lfs/git-lfs/git/odb"
        "github.com/git-lfs/git-lfs/tasklog"
+       "github.com/git-lfs/gitobj"
        "github.com/spf13/cobra"
 )
 
@@ -21,6 +23,10 @@ var (
        // in the migration.
        migrateExcludeRefs []string
 
+       // migrateYes indicates that an answer of 'yes' should be presumed
+       // whenever 'git lfs migrate' asks for user input.
+       migrateYes bool
+
        // migrateSkipFetch assumes that the client has the latest copy of
        // remote references, and thus should not contact the remote for a set
        // of updated references.
@@ -32,9 +38,28 @@ var (
 
        // migrateVerbose enables verbose logging
        migrateVerbose bool
+
+       // objectMapFile is the path to the map of old sha1 to new sha1
+       // commits
+       objectMapFilePath string
+
+       // migrateNoRewrite is the flag indicating whether or not the
+       // command should rewrite git history
+       migrateNoRewrite bool
+       // migrateCommitMessage is the message to use with the commit generated
+       // by the migrate command
+       migrateCommitMessage string
+
+       // exportRemote is the remote from which to download objects when
+       // performing an export
+       exportRemote string
+
+       // migrateFixup is the flag indicating whether or not to infer the
+       // included and excluded filepath patterns.
+       migrateFixup bool
 )
 
-// migrate takes the given command and arguments, *odb.ObjectDatabase, as well
+// migrate takes the given command and arguments, *gitobj.ObjectDatabase, as well
 // as a BlobRewriteFn to apply, and performs a migration.
 func migrate(args []string, r *githistory.Rewriter, l *tasklog.Logger, opts *githistory.RewriteOptions) {
        requireInRepo()
@@ -52,12 +77,12 @@ func migrate(args []string, r *githistory.Rewriter, l *tasklog.Logger, opts *git
 
 // getObjectDatabase creates a *git.ObjectDatabase from the filesystem pointed
 // at the .git directory of the currently checked-out repository.
-func getObjectDatabase() (*odb.ObjectDatabase, error) {
+func getObjectDatabase() (*gitobj.ObjectDatabase, error) {
        dir, err := git.GitDir()
        if err != nil {
                return nil, errors.Wrap(err, "cannot open root")
        }
-       return odb.FromFilesystem(filepath.Join(dir, "objects"), cfg.TempDir())
+       return gitobj.FromFilesystem(filepath.Join(dir, "objects"), cfg.TempDir())
 }
 
 // rewriteOptions returns *githistory.RewriteOptions able to be passed to a
@@ -83,11 +108,13 @@ func rewriteOptions(args []string, opts *githistory.RewriteOptions, l *tasklog.L
                Include: include,
                Exclude: exclude,
 
-               UpdateRefs: opts.UpdateRefs,
-               Verbose:    opts.Verbose,
+               UpdateRefs:        opts.UpdateRefs,
+               Verbose:           opts.Verbose,
+               ObjectMapFilePath: opts.ObjectMapFilePath,
 
-               BlobFn:         opts.BlobFn,
-               TreeCallbackFn: opts.TreeCallbackFn,
+               BlobFn:            opts.BlobFn,
+               TreePreCallbackFn: opts.TreePreCallbackFn,
+               TreeCallbackFn:    opts.TreeCallbackFn,
        }, nil
 }
 
@@ -152,13 +179,31 @@ func includeExcludeRefs(l *tasklog.Logger, args []string) (include, exclude []st
                include = append(include, migrateIncludeRefs...)
                exclude = append(exclude, migrateExcludeRefs...)
        } else if migrateEverything {
-               localRefs, err := git.LocalRefs()
+               refs, err := git.AllRefsIn("")
                if err != nil {
                        return nil, nil, err
                }
 
-               for _, ref := range localRefs {
-                       include = append(include, ref.Refspec())
+               for _, ref := range refs {
+                       switch ref.Type {
+                       case git.RefTypeLocalBranch, git.RefTypeLocalTag,
+                               git.RefTypeRemoteBranch, git.RefTypeRemoteTag:
+
+                               include = append(include, ref.Refspec())
+                       case git.RefTypeOther:
+                               parts := strings.SplitN(ref.Refspec(), "/", 3)
+                               if len(parts) < 2 {
+                                       continue
+                               }
+
+                               switch parts[1] {
+                               // The following are GitLab-, GitHub-, VSTS-,
+                               // and BitBucket-specific reference naming
+                               // conventions.
+                               case "merge-requests", "pull", "pull-requests":
+                                       include = append(include, ref.Refspec())
+                               }
+                       }
                }
        } else {
                bare, err := git.IsBare()
@@ -265,7 +310,7 @@ func currentRefToMigrate() (*git.Ref, error) {
 
 // getHistoryRewriter returns a history rewriter that includes the filepath
 // filter given by the --include and --exclude arguments.
-func getHistoryRewriter(cmd *cobra.Command, db *odb.ObjectDatabase, l *tasklog.Logger) *githistory.Rewriter {
+func getHistoryRewriter(cmd *cobra.Command, db *gitobj.ObjectDatabase, l *tasklog.Logger) *githistory.Rewriter {
        include, exclude := getIncludeExcludeArgs(cmd)
        filter := buildFilepathFilter(cfg, include, exclude)
 
@@ -273,6 +318,56 @@ func getHistoryRewriter(cmd *cobra.Command, db *odb.ObjectDatabase, l *tasklog.L
                githistory.WithFilter(filter), githistory.WithLogger(l))
 }
 
+func ensureWorkingCopyClean(in io.Reader, out io.Writer) {
+       dirty, err := git.IsWorkingCopyDirty()
+       if err != nil {
+               ExitWithError(errors.Wrap(err,
+                       "fatal: could not determine if working copy is dirty"))
+       }
+
+       if !dirty {
+               return
+       }
+
+       var proceed bool
+       if migrateYes {
+               proceed = true
+       } else {
+               answer := bufio.NewReader(in)
+       L:
+               for {
+                       fmt.Fprintf(out, "migrate: override changes in your working copy? [Y/n] ")
+                       s, err := answer.ReadString('\n')
+                       if err != nil {
+                               if err == io.EOF {
+                                       break L
+                               }
+                               ExitWithError(errors.Wrap(err,
+                                       "fatal: could not read answer"))
+                       }
+
+                       switch strings.TrimSpace(s) {
+                       case "n", "N":
+                               proceed = false
+                               break L
+                       case "y", "Y":
+                               proceed = true
+                               break L
+                       }
+
+                       if !strings.HasSuffix(s, "\n") {
+                               fmt.Fprintf(out, "\n")
+                       }
+               }
+       }
+
+       if proceed {
+               fmt.Fprintf(out, "migrate: changes in your working copy will be overridden ...\n")
+       } else {
+               Exit("migrate: working copy must not be dirty")
+       }
+}
+
 func init() {
        info := NewCommand("info", migrateInfoCommand)
        info.Flags().IntVar(&migrateInfoTopN, "top", 5, "--top=<n>")
@@ -281,6 +376,15 @@ func init() {
 
        importCmd := NewCommand("import", migrateImportCommand)
        importCmd.Flags().BoolVar(&migrateVerbose, "verbose", false, "Verbose logging")
+       importCmd.Flags().StringVar(&objectMapFilePath, "object-map", "", "Object map file")
+       importCmd.Flags().BoolVar(&migrateNoRewrite, "no-rewrite", false, "Add new history without rewriting previous")
+       importCmd.Flags().StringVarP(&migrateCommitMessage, "message", "m", "", "With --no-rewrite, an optional commit message")
+       importCmd.Flags().BoolVar(&migrateFixup, "fixup", false, "Infer filepaths based on .gitattributes")
+
+       exportCmd := NewCommand("export", migrateExportCommand)
+       exportCmd.Flags().BoolVar(&migrateVerbose, "verbose", false, "Verbose logging")
+       exportCmd.Flags().StringVar(&objectMapFilePath, "object-map", "", "Object map file")
+       exportCmd.Flags().StringVar(&exportRemote, "remote", "", "Remote from which to download objects")
 
        RegisterCommand("migrate", nil, func(cmd *cobra.Command) {
                cmd.PersistentFlags().StringVarP(&includeArg, "include", "I", "", "Include a list of paths")
@@ -291,6 +395,8 @@ func init() {
                cmd.PersistentFlags().BoolVar(&migrateEverything, "everything", false, "Migrate all local references")
                cmd.PersistentFlags().BoolVar(&migrateSkipFetch, "skip-fetch", false, "Assume up-to-date remote references.")
 
-               cmd.AddCommand(importCmd, info)
+               cmd.PersistentFlags().BoolVarP(&migrateYes, "yes", "y", false, "Don't prompt for answers.")
+
+               cmd.AddCommand(exportCmd, importCmd, info)
        })
 }
diff --git a/commands/command_migrate_export.go b/commands/command_migrate_export.go
new file mode 100644 (file)
index 0000000..aba64c6
--- /dev/null
@@ -0,0 +1,196 @@
+package commands
+
+import (
+       "fmt"
+       "os"
+       "path/filepath"
+
+       "github.com/git-lfs/git-lfs/errors"
+       "github.com/git-lfs/git-lfs/filepathfilter"
+       "github.com/git-lfs/git-lfs/git"
+       "github.com/git-lfs/git-lfs/git/githistory"
+       "github.com/git-lfs/git-lfs/lfs"
+       "github.com/git-lfs/git-lfs/tasklog"
+       "github.com/git-lfs/git-lfs/tools"
+       "github.com/git-lfs/gitobj"
+       "github.com/spf13/cobra"
+)
+
+func migrateExportCommand(cmd *cobra.Command, args []string) {
+       ensureWorkingCopyClean(os.Stdin, os.Stderr)
+
+       l := tasklog.NewLogger(os.Stderr)
+       defer l.Close()
+
+       db, err := getObjectDatabase()
+       if err != nil {
+               ExitWithError(err)
+       }
+       defer db.Close()
+
+       rewriter := getHistoryRewriter(cmd, db, l)
+
+       filter := rewriter.Filter()
+       if len(filter.Include()) <= 0 {
+               ExitWithError(errors.Errorf("fatal: one or more files must be specified with --include"))
+       }
+
+       tracked := trackedFromExportFilter(filter)
+       gitfilter := lfs.NewGitFilter(cfg)
+
+       opts := &githistory.RewriteOptions{
+               Verbose:           migrateVerbose,
+               ObjectMapFilePath: objectMapFilePath,
+               BlobFn: func(path string, b *gitobj.Blob) (*gitobj.Blob, error) {
+                       if filepath.Base(path) == ".gitattributes" {
+                               return b, nil
+                       }
+
+                       ptr, err := lfs.DecodePointer(b.Contents)
+                       if err != nil {
+                               if errors.IsNotAPointerError(err) {
+                                       return b, nil
+                               }
+                               return nil, err
+                       }
+
+                       downloadPath, err := gitfilter.ObjectPath(ptr.Oid)
+                       if err != nil {
+                               return nil, err
+                       }
+
+                       return gitobj.NewBlobFromFile(downloadPath)
+               },
+
+               TreeCallbackFn: func(path string, t *gitobj.Tree) (*gitobj.Tree, error) {
+                       if path != "/" {
+                               // Ignore non-root trees.
+                               return t, nil
+                       }
+
+                       ours := tracked
+                       theirs, err := trackedFromAttrs(db, t)
+                       if err != nil {
+                               return nil, err
+                       }
+
+                       // Create a blob of the attributes that are optionally
+                       // present in the "t" tree's .gitattributes blob, and
+                       // union in the patterns that we've tracked.
+                       //
+                       // Perform this Union() operation each time we visit a
+                       // root tree such that if the underlying .gitattributes
+                       // is present and has a diff between commits in the
+                       // range of commits to migrate, those changes are
+                       // preserved.
+                       blob, err := trackedToBlob(db, theirs.Clone().Union(ours))
+                       if err != nil {
+                               return nil, err
+                       }
+
+                       // Finally, return a copy of the tree "t" that has the
+                       // new .gitattributes file included/replaced.
+                       return t.Merge(&gitobj.TreeEntry{
+                               Name:     ".gitattributes",
+                               Filemode: 0100644,
+                               Oid:      blob,
+                       }), nil
+               },
+
+               UpdateRefs: true,
+       }
+
+       requireInRepo()
+
+       opts, err = rewriteOptions(args, opts, l)
+       if err != nil {
+               ExitWithError(err)
+       }
+
+       remote := cfg.Remote()
+       if cmd.Flag("remote").Changed {
+               remote = exportRemote
+       }
+       remoteURL := getAPIClient().Endpoints.RemoteEndpoint("download", remote).Url
+       if remoteURL == "" && cmd.Flag("remote").Changed {
+               ExitWithError(errors.Errorf("fatal: invalid remote %s provided", remote))
+       }
+
+       // If we have a valid remote, pre-download all objects using the Transfer Queue
+       if remoteURL != "" {
+               q := newDownloadQueue(getTransferManifestOperationRemote("Download", remote), remote)
+               gs := lfs.NewGitScanner(func(p *lfs.WrappedPointer, err error) {
+                       if err != nil {
+                               return
+                       }
+
+                       if !filter.Allows(p.Name) {
+                               return
+                       }
+
+                       downloadPath, err := gitfilter.ObjectPath(p.Oid)
+                       if err != nil {
+                               return
+                       }
+
+                       if _, err := os.Stat(downloadPath); os.IsNotExist(err) {
+                               q.Add(p.Name, downloadPath, p.Oid, p.Size)
+                       }
+               })
+               gs.ScanRefs(opts.Include, opts.Exclude, nil)
+
+               q.Wait()
+
+               for _, err := range q.Errors() {
+                       if err != nil {
+                               ExitWithError(err)
+                       }
+               }
+       }
+
+       // Perform the rewrite
+       if _, err := rewriter.Rewrite(opts); err != nil {
+               ExitWithError(err)
+       }
+
+       // Only perform `git-checkout(1) -f` if the repository is non-bare.
+       if bare, _ := git.IsBare(); !bare {
+               t := l.Waiter("migrate: checkout")
+               err := git.Checkout("", nil, true)
+               t.Complete()
+
+               if err != nil {
+                       ExitWithError(err)
+               }
+       }
+
+       fetchPruneCfg := lfs.NewFetchPruneConfig(cfg.Git)
+
+       // Set our preservation time-window for objects existing on the remote to
+       // 0. Because the newly rewritten commits have not yet been pushed, some
+       // exported objects can still exist on the remote within the time window
+       // and thus will not be pruned from the cache.
+       fetchPruneCfg.FetchRecentRefsDays = 0
+
+       // Prune our cache
+       prune(fetchPruneCfg, false, false, true)
+}
+
+// trackedFromExportFilter returns an ordered set of strings where each entry
+// is a line we intend to place in the .gitattributes file. It adds/removes the
+// filter/diff/merge=lfs attributes based on patterns included/excluded in the
+// given filter. Since `migrate export` removes files from Git LFS, it will
+// remove attributes for included files, and add attributes for excluded files
+func trackedFromExportFilter(filter *filepathfilter.Filter) *tools.OrderedSet {
+       tracked := tools.NewOrderedSet()
+
+       for _, include := range filter.Include() {
+               tracked.Add(fmt.Sprintf("%s text !filter !merge !diff", escapeAttrPattern(include)))
+       }
+
+       for _, exclude := range filter.Exclude() {
+               tracked.Add(fmt.Sprintf("%s filter=lfs diff=lfs merge=lfs -text", escapeAttrPattern(exclude)))
+       }
+
+       return tracked
+}
index 606ba4c..b979ba7 100644 (file)
@@ -9,17 +9,21 @@ import (
        "path/filepath"
        "strings"
 
+       "github.com/git-lfs/git-lfs/errors"
        "github.com/git-lfs/git-lfs/filepathfilter"
        "github.com/git-lfs/git-lfs/git"
+       "github.com/git-lfs/git-lfs/git/gitattr"
        "github.com/git-lfs/git-lfs/git/githistory"
-       "github.com/git-lfs/git-lfs/git/odb"
        "github.com/git-lfs/git-lfs/lfs"
        "github.com/git-lfs/git-lfs/tasklog"
        "github.com/git-lfs/git-lfs/tools"
+       "github.com/git-lfs/gitobj"
        "github.com/spf13/cobra"
 )
 
 func migrateImportCommand(cmd *cobra.Command, args []string) {
+       ensureWorkingCopyClean(os.Stdin, os.Stderr)
+
        l := tasklog.NewLogger(os.Stderr)
        defer l.Close()
 
@@ -29,19 +33,111 @@ func migrateImportCommand(cmd *cobra.Command, args []string) {
        }
        defer db.Close()
 
+       if migrateNoRewrite {
+               if migrateFixup {
+                       ExitWithError(errors.Errorf("fatal: --no-rewrite and --fixup cannot be combined"))
+               }
+
+               if len(args) == 0 {
+                       ExitWithError(errors.Errorf("fatal: expected one or more files with --no-rewrite"))
+               }
+
+               ref, err := git.CurrentRef()
+               if err != nil {
+                       ExitWithError(errors.Wrap(err, "fatal: unable to find current reference"))
+               }
+
+               sha, _ := hex.DecodeString(ref.Sha)
+               commit, err := db.Commit(sha)
+               if err != nil {
+                       ExitWithError(errors.Wrap(err, "fatal: unable to load commit"))
+               }
+
+               root := commit.TreeID
+
+               filter := git.GetAttributeFilter(cfg.LocalWorkingDir(), cfg.LocalGitDir())
+               if len(filter.Include()) == 0 {
+                       ExitWithError(errors.Errorf("fatal: no Git LFS filters found in .gitattributes"))
+               }
+
+               gf := lfs.NewGitFilter(cfg)
+
+               for _, file := range args {
+                       if !filter.Allows(file) {
+                               ExitWithError(errors.Errorf("fatal: file %s did not match any Git LFS filters in .gitattributes", file))
+                       }
+               }
+
+               for _, file := range args {
+                       root, err = rewriteTree(gf, db, root, file)
+                       if err != nil {
+                               ExitWithError(errors.Wrapf(err, "fatal: could not rewrite %q", file))
+                       }
+               }
+
+               name, email := cfg.CurrentCommitter()
+               author := fmt.Sprintf("%s <%s>", name, email)
+
+               oid, err := db.WriteCommit(&gitobj.Commit{
+                       Author:    author,
+                       Committer: author,
+                       ParentIDs: [][]byte{sha},
+                       Message:   generateMigrateCommitMessage(cmd, strings.Join(args, ",")),
+                       TreeID:    root,
+               })
+
+               if err != nil {
+                       ExitWithError(errors.Wrap(err, "fatal: unable to write commit"))
+               }
+
+               if err := git.UpdateRef(ref, oid, "git lfs migrate import --no-rewrite"); err != nil {
+                       ExitWithError(errors.Wrap(err, "fatal: unable to update ref"))
+               }
+
+               if err := checkoutNonBare(l); err != nil {
+                       ExitWithError(errors.Wrap(err, "fatal: could not checkout"))
+               }
+
+               return
+       }
+
+       if migrateFixup {
+               include, exclude := getIncludeExcludeArgs(cmd)
+               if include != nil || exclude != nil {
+                       ExitWithError(errors.Errorf("fatal: cannot use --fixup with --include, --exclude"))
+               }
+       }
+
        rewriter := getHistoryRewriter(cmd, db, l)
 
        tracked := trackedFromFilter(rewriter.Filter())
        exts := tools.NewOrderedSet()
        gitfilter := lfs.NewGitFilter(cfg)
 
+       var fixups *gitattr.Tree
+
        migrate(args, rewriter, l, &githistory.RewriteOptions{
-               Verbose: migrateVerbose,
-               BlobFn: func(path string, b *odb.Blob) (*odb.Blob, error) {
+               Verbose:           migrateVerbose,
+               ObjectMapFilePath: objectMapFilePath,
+               BlobFn: func(path string, b *gitobj.Blob) (*gitobj.Blob, error) {
                        if filepath.Base(path) == ".gitattributes" {
                                return b, nil
                        }
 
+                       if migrateFixup {
+                               var ok bool
+                               attrs := fixups.Applied(path)
+                               for _, attr := range attrs {
+                                       if attr.K == "filter" {
+                                               ok = attr.V == "lfs"
+                                       }
+                               }
+
+                               if !ok {
+                                       return b, nil
+                               }
+                       }
+
                        var buf bytes.Buffer
 
                        if _, err := clean(gitfilter, &buf, b.Contents, path, b.Size); err != nil {
@@ -52,14 +148,28 @@ func migrateImportCommand(cmd *cobra.Command, args []string) {
                                exts.Add(fmt.Sprintf("*%s filter=lfs diff=lfs merge=lfs -text", ext))
                        }
 
-                       return &odb.Blob{
+                       return &gitobj.Blob{
                                Contents: &buf, Size: int64(buf.Len()),
                        }, nil
                },
 
-               TreeCallbackFn: func(path string, t *odb.Tree) (*odb.Tree, error) {
-                       if path != "/" {
-                               // Ignore non-root trees.
+               TreePreCallbackFn: func(path string, t *gitobj.Tree) error {
+                       if migrateFixup && path == "/" {
+                               var err error
+
+                               fixups, err = gitattr.New(db, t)
+                               if err != nil {
+                                       return err
+                               }
+                               return nil
+                       }
+                       return nil
+               },
+
+               TreeCallbackFn: func(path string, t *gitobj.Tree) (*gitobj.Tree, error) {
+                       if path != "/" || migrateFixup {
+                               // Avoid updating .gitattributes in non-root
+                               // trees, or if --fixup is given.
                                return t, nil
                        }
 
@@ -70,6 +180,18 @@ func migrateImportCommand(cmd *cobra.Command, args []string) {
                                // include set is the wildcard filepath
                                // extensions of files tracked.
                                ours = exts
+
+                               if ours.Cardinality() == 0 {
+                                       // If it is still the case that we have
+                                       // no patterns to track, that means that
+                                       // we are in a tree that does not
+                                       // require .gitattributes changes.
+                                       //
+                                       // We can return early to avoid
+                                       // comparing and saving an identical
+                                       // tree.
+                                       return t, nil
+                               }
                        }
 
                        theirs, err := trackedFromAttrs(db, t)
@@ -93,7 +215,7 @@ func migrateImportCommand(cmd *cobra.Command, args []string) {
 
                        // Finally, return a copy of the tree "t" that has the
                        // new .gitattributes file included/replaced.
-                       return t.Merge(&odb.TreeEntry{
+                       return t.Merge(&gitobj.TreeEntry{
                                Name:     ".gitattributes",
                                Filemode: 0100644,
                                Oid:      blob,
@@ -103,17 +225,33 @@ func migrateImportCommand(cmd *cobra.Command, args []string) {
                UpdateRefs: true,
        })
 
-       // Only perform `git-checkout(1) -f` if the repository is
-       // non-bare.
-       if bare, _ := git.IsBare(); !bare {
-               t := l.Waiter("migrate: checkout")
-               err := git.Checkout("", nil, true)
-               t.Complete()
+       if err := checkoutNonBare(l); err != nil {
+               ExitWithError(errors.Wrap(err, "fatal: could not checkout"))
+       }
+}
 
-               if err != nil {
-                       ExitWithError(err)
-               }
+// generateMigrateCommitMessage generates a commit message used with
+// --no-rewrite, using --message (if given) or generating one if it isn't.
+func generateMigrateCommitMessage(cmd *cobra.Command, patterns string) string {
+       if cmd.Flag("message").Changed {
+               return migrateCommitMessage
        }
+       return fmt.Sprintf("%s: convert to Git LFS", patterns)
+}
+
+// checkoutNonBare forces a checkout of the current reference, so long as the
+// repository is non-bare.
+//
+// It returns nil on success, and a non-nil error on failure.
+func checkoutNonBare(l *tasklog.Logger) error {
+       if bare, _ := git.IsBare(); bare {
+               return nil
+       }
+
+       t := l.Waiter("migrate: checkout")
+       defer t.Complete()
+
+       return git.Checkout("", nil, true)
 }
 
 // trackedFromFilter returns an ordered set of strings where each entry is a
@@ -144,11 +282,11 @@ var (
 //
 // It returns an empty set if no attributes file could be found, or an error if
 // it could not otherwise be opened.
-func trackedFromAttrs(db *odb.ObjectDatabase, t *odb.Tree) (*tools.OrderedSet, error) {
+func trackedFromAttrs(db *gitobj.ObjectDatabase, t *gitobj.Tree) (*tools.OrderedSet, error) {
        var oid []byte
 
        for _, e := range t.Entries {
-               if strings.ToLower(e.Name) == ".gitattributes" && e.Type() == odb.BlobObjectType {
+               if strings.ToLower(e.Name) == ".gitattributes" && e.Type() == gitobj.BlobObjectType {
                        oid = e.Oid
                        break
                }
@@ -189,15 +327,108 @@ func trackedFromAttrs(db *odb.ObjectDatabase, t *odb.Tree) (*tools.OrderedSet, e
 
 // trackedToBlob writes and returns the OID of a .gitattributes blob based on
 // the patterns given in the ordered set of patterns, "patterns".
-func trackedToBlob(db *odb.ObjectDatabase, patterns *tools.OrderedSet) ([]byte, error) {
+func trackedToBlob(db *gitobj.ObjectDatabase, patterns *tools.OrderedSet) ([]byte, error) {
        var attrs bytes.Buffer
 
        for pattern := range patterns.Iter() {
                fmt.Fprintf(&attrs, "%s\n", pattern)
        }
 
-       return db.WriteBlob(&odb.Blob{
+       return db.WriteBlob(&gitobj.Blob{
                Contents: &attrs,
                Size:     int64(attrs.Len()),
        })
 }
+
+// rewriteTree replaces the blob at the provided path within the given tree with
+// a git lfs pointer. It will recursively rewrite any subtrees along the path to the
+// blob.
+func rewriteTree(gf *lfs.GitFilter, db *gitobj.ObjectDatabase, root []byte, path string) ([]byte, error) {
+       tree, err := db.Tree(root)
+       if err != nil {
+               return nil, err
+       }
+
+       splits := strings.SplitN(path, "/", 2)
+
+       switch len(splits) {
+       case 1:
+               // The path points to an entry at the root of this tree, so it must be a blob.
+               // Try to replace this blob with a Git LFS pointer.
+               index := findEntry(tree, splits[0])
+               if index < 0 {
+                       return nil, errors.Errorf("unable to find entry %s in tree", splits[0])
+               }
+
+               blobEntry := tree.Entries[index]
+               blob, err := db.Blob(blobEntry.Oid)
+               if err != nil {
+                       return nil, err
+               }
+
+               var buf bytes.Buffer
+
+               if _, err := clean(gf, &buf, blob.Contents, blobEntry.Name, blob.Size); err != nil {
+                       return nil, err
+               }
+
+               newOid, err := db.WriteBlob(&gitobj.Blob{
+                       Contents: &buf,
+                       Size:     int64(buf.Len()),
+               })
+
+               if err != nil {
+                       return nil, err
+               }
+
+               tree = tree.Merge(&gitobj.TreeEntry{
+                       Name:     splits[0],
+                       Filemode: blobEntry.Filemode,
+                       Oid:      newOid,
+               })
+               return db.WriteTree(tree)
+
+       case 2:
+               // The path points to an entry in a subtree contained at the root of the tree.
+               // Recursively rewrite the subtree.
+               head, tail := splits[0], splits[1]
+
+               index := findEntry(tree, head)
+               if index < 0 {
+                       return nil, errors.Errorf("unable to find entry %s in tree", head)
+               }
+
+               subtreeEntry := tree.Entries[index]
+               if subtreeEntry.Type() != gitobj.TreeObjectType {
+                       return nil, errors.Errorf("migrate: expected %s to be a tree, got %s", head, subtreeEntry.Type())
+               }
+
+               rewrittenSubtree, err := rewriteTree(gf, db, subtreeEntry.Oid, tail)
+               if err != nil {
+                       return nil, err
+               }
+
+               tree = tree.Merge(&gitobj.TreeEntry{
+                       Filemode: subtreeEntry.Filemode,
+                       Name:     subtreeEntry.Name,
+                       Oid:      rewrittenSubtree,
+               })
+
+               return db.WriteTree(tree)
+
+       default:
+               return nil, errors.Errorf("error parsing path %s", path)
+       }
+}
+
+// findEntry searches a tree for the desired entry, and returns the index of that
+// entry within the tree's Entries array
+func findEntry(t *gitobj.Tree, name string) int {
+       for i, entry := range t.Entries {
+               if entry.Name == name {
+                       return i
+               }
+       }
+
+       return -1
+}
index 2c1fa92..ef4956f 100644 (file)
@@ -10,10 +10,10 @@ import (
 
        "github.com/git-lfs/git-lfs/errors"
        "github.com/git-lfs/git-lfs/git/githistory"
-       "github.com/git-lfs/git-lfs/git/odb"
        "github.com/git-lfs/git-lfs/tasklog"
        "github.com/git-lfs/git-lfs/tools"
        "github.com/git-lfs/git-lfs/tools/humanize"
+       "github.com/git-lfs/gitobj"
        "github.com/spf13/cobra"
 )
 
@@ -69,7 +69,7 @@ func migrateInfoCommand(cmd *cobra.Command, args []string) {
        migrateInfoAbove = above
 
        migrate(args, rewriter, l, &githistory.RewriteOptions{
-               BlobFn: func(path string, b *odb.Blob) (*odb.Blob, error) {
+               BlobFn: func(path string, b *gitobj.Blob) (*gitobj.Blob, error) {
                        ext := fmt.Sprintf("*%s", filepath.Ext(path))
 
                        if len(ext) > 1 {
index 6584fd8..48de5b9 100644 (file)
@@ -38,7 +38,7 @@ func pushCommand(cmd *cobra.Command, args []string) {
        requireGitVersion()
 
        // Remote is first arg
-       if err := cfg.SetValidRemote(args[0]); err != nil {
+       if err := cfg.SetValidPushRemote(args[0]); err != nil {
                Exit("Invalid remote name %q: %s", args[0], err)
        }
 
index 010b499..47bec0c 100644 (file)
@@ -6,6 +6,7 @@ import (
        "fmt"
        "io"
        "os"
+       "path/filepath"
        "regexp"
        "strings"
 
@@ -52,19 +53,29 @@ func statusCommand(cmd *cobra.Command, args []string) {
                ExitWithError(err)
        }
 
+       wd, _ := os.Getwd()
+       repo := cfg.LocalWorkingDir()
+
        Print("\nGit LFS objects to be committed:\n")
        for _, entry := range staged {
+               // Find a path from the current working directory to the
+               // absolute path of each side of the entry.
+               src := relativize(wd, filepath.Join(repo, entry.SrcName))
+               dst := relativize(wd, filepath.Join(repo, entry.DstName))
+
                switch entry.Status {
                case lfs.StatusRename, lfs.StatusCopy:
-                       Print("\t%s -> %s (%s)", entry.SrcName, entry.DstName, formatBlobInfo(scanner, entry))
+                       Print("\t%s -> %s (%s)", src, dst, formatBlobInfo(scanner, entry))
                default:
-                       Print("\t%s (%s)", entry.SrcName, formatBlobInfo(scanner, entry))
+                       Print("\t%s (%s)", src, formatBlobInfo(scanner, entry))
                }
        }
 
        Print("\nGit LFS objects not staged for commit:\n")
        for _, entry := range unstaged {
-               Print("\t%s (%s)", entry.SrcName, formatBlobInfo(scanner, entry))
+               src := relativize(wd, filepath.Join(repo, entry.SrcName))
+
+               Print("\t%s (%s)", src, formatBlobInfo(scanner, entry))
        }
 
        Print("")
@@ -134,7 +145,7 @@ func blobInfo(s *lfs.PointerScanner, blobSha, name string) (sha, from string, er
                return s.ContentsSha()[:7], from, nil
        }
 
-       f, err := os.Open(name)
+       f, err := os.Open(filepath.Join(cfg.LocalWorkingDir(), name))
        if err != nil {
                return "", "", err
        }
@@ -311,6 +322,39 @@ func porcelainStatusLine(entry *lfs.DiffIndexEntry) string {
        return fmt.Sprintf("%s  %s", entry.Status, entry.SrcName)
 }
 
+// relativize relatives a path from "from" to "to". For instance, note that, for
+// any paths "from" and "to", that:
+//
+//   to == filepath.Clean(filepath.Join(from, relativize(from, to)))
+func relativize(from, to string) string {
+       if len(from) == 0 {
+               return to
+       }
+
+       flist := strings.Split(filepath.ToSlash(from), "/")
+       tlist := strings.Split(filepath.ToSlash(to), "/")
+
+       var (
+               divergence int
+               min        int
+       )
+
+       if lf, lt := len(flist), len(tlist); lf < lt {
+               min = lf
+       } else {
+               min = lt
+       }
+
+       for ; divergence < min; divergence++ {
+               if flist[divergence] != tlist[divergence] {
+                       break
+               }
+       }
+
+       return strings.Repeat("../", len(flist)-divergence) +
+               strings.Join(tlist[divergence:], "/")
+}
+
 func init() {
        RegisterCommand("status", statusCommand, func(cmd *cobra.Command) {
                cmd.Flags().BoolVarP(&porcelain, "porcelain", "p", false, "Give the output in an easy-to-parse format for scripts.")
index 5ba0692..8d160dc 100644 (file)
@@ -49,6 +49,8 @@ func trackCommand(cmd *cobra.Command, args []string) {
                return
        }
 
+       // Intentionally do _not_ consider global- and system-level
+       // .gitattributes here.
        knownPatterns := git.GetAttributePaths(cfg.LocalWorkingDir(), cfg.LocalGitDir())
        lineEnd := getAttributeLineEnding(knownPatterns)
        if len(lineEnd) == 0 {
@@ -213,7 +215,7 @@ ArgsLoop:
 }
 
 func listPatterns() {
-       knownPatterns := git.GetAttributePaths(cfg.LocalWorkingDir(), cfg.LocalGitDir())
+       knownPatterns := getAllKnownPatterns()
        if len(knownPatterns) < 1 {
                return
        }
@@ -228,6 +230,14 @@ func listPatterns() {
        }
 }
 
+func getAllKnownPatterns() []git.AttributePath {
+       knownPatterns := git.GetAttributePaths(cfg.LocalWorkingDir(), cfg.LocalGitDir())
+       knownPatterns = append(knownPatterns, git.GetRootAttributePaths(cfg.Git)...)
+       knownPatterns = append(knownPatterns, git.GetSystemAttributePaths(cfg.Os)...)
+
+       return knownPatterns
+}
+
 func getAttributeLineEnding(attribs []git.AttributePath) string {
        for _, a := range attribs {
                if a.Source.Path == ".gitattributes" {
index 1992d1d..c08ae16 100644 (file)
@@ -100,7 +100,7 @@ func newUploadContext(dryRun bool) *uploadContext {
                uploadedOids: tools.NewStringSet(),
                gitfilter:    lfs.NewGitFilter(cfg),
                lockVerifier: newLockVerifier(manifest),
-               allowMissing: cfg.Git.Bool("lfs.allowincompletepush", true),
+               allowMissing: cfg.Git.Bool("lfs.allowincompletepush", false),
                missing:      make(map[string]string),
                corrupt:      make(map[string]string),
                otherErrs:    make([]error, 0),
@@ -289,6 +289,11 @@ func (c *uploadContext) ReportErrors() {
                }
 
                if !c.allowMissing {
+                       pushMissingHint := []string{
+                               "hint: Your push was rejected due to missing or corrupt local objects.",
+                               "hint: You can disable this check with: 'git config lfs.allowincompletepush true'",
+                       }
+                       Print(strings.Join(pushMissingHint, "\n"))
                        os.Exit(2)
                }
        }
index 089565b..0f0c5a2 100644 (file)
@@ -232,10 +232,22 @@ func (c *Configuration) SetValidRemote(name string) error {
        return nil
 }
 
+func (c *Configuration) SetValidPushRemote(name string) error {
+       if err := git.ValidateRemote(name); err != nil {
+               return err
+       }
+       c.SetPushRemote(name)
+       return nil
+}
+
 func (c *Configuration) SetRemote(name string) {
        c.currentRemote = &name
 }
 
+func (c *Configuration) SetPushRemote(name string) {
+       c.pushRemote = &name
+}
+
 func (c *Configuration) Remotes() []string {
        c.loadGitConfig()
        return c.remotes
@@ -295,7 +307,8 @@ func (c *Configuration) loadGitDirs() {
        if err != nil {
                errMsg := err.Error()
                tracerx.Printf("Error running 'git rev-parse': %s", errMsg)
-               if !strings.Contains(errMsg, "Not a git repository") {
+               if !strings.Contains(strings.ToLower(errMsg),
+                       "not a git repository") {
                        fmt.Fprintf(os.Stderr, "Error: %s\n", errMsg)
                }
                c.gitDir = &gitdir
@@ -310,8 +323,8 @@ func (c *Configuration) LocalGitStorageDir() string {
        return c.Filesystem().GitStorageDir
 }
 
-func (c *Configuration) LocalReferenceDir() string {
-       return c.Filesystem().ReferenceDir
+func (c *Configuration) LocalReferenceDirs() []string {
+       return c.Filesystem().ReferenceDirs
 }
 
 func (c *Configuration) LFSStorageDir() string {
@@ -345,7 +358,12 @@ func (c *Configuration) Filesystem() *fs.Filesystem {
 
        if c.fs == nil {
                lfsdir, _ := c.Git.Get("lfs.storage")
-               c.fs = fs.New(c.LocalGitDir(), c.LocalWorkingDir(), lfsdir)
+               c.fs = fs.New(
+                       c.Os,
+                       c.LocalGitDir(),
+                       c.LocalWorkingDir(),
+                       lfsdir,
+               )
        }
 
        return c.fs
index f38d468..3554fc6 100644 (file)
@@ -158,6 +158,7 @@ func keyIsUnsafe(key string) bool {
 }
 
 var safeKeys = []string{
+       "lfs.allowincompletepush",
        "lfs.fetchexclude",
        "lfs.fetchinclude",
        "lfs.gitprotocol",
index 4bb1bba..e11dfe7 100644 (file)
@@ -12,7 +12,7 @@ var (
 )
 
 const (
-       Version = "2.4.2"
+       Version = "2.5.0"
 )
 
 func init() {
index ceb0cf3..ecd7ae4 100644 (file)
@@ -1,3 +1,9 @@
+git-lfs (2.5.0) stable; urgency=low
+
+  * New upstream version
+
+ -- Taylor Blau <me@ttaylorr.com>  Thu, 26 Jul 2018 14:29:00 +0000
+
 git-lfs (2.4.2) stable; urgency=low
 
   * New upstream version
index ddae758..0ef00ba 100755 (executable)
@@ -16,7 +16,7 @@ endif
 
 BUILD_DIR := obj-$(DEB_HOST_GNU_TYPE)
 export DH_GOPKG := github.com/git-lfs/git-lfs
-# DH_GOLANG_EXCLUDES typically incorporates vendor exclusions from script/test
+# DH_GOLANG_EXCLUDES typically incorporates vendor exclusions
 export DH_GOLANG_EXCLUDES := test github.com/olekukonko/ts/* github.com/xeipuuv/* github.com/spf13/cobra/* github.com/kr/* github.com/pkg/errors github.com/alexbrainman/sspi/*
 export PATH := $(CURDIR)/$(BUILD_DIR)/bin:$(PATH)
 
@@ -32,6 +32,7 @@ override_dh_clean:
        dh_clean
 
 override_dh_auto_build:
+       cd ${BUILD_DIR}/src/github.com/git-lfs/git-lfs && go generate ./commands
        dh_auto_build
        #dh_golang doesn't do anything here in deb 8, and it's needed in both
        if [ "$(DEB_HOST_GNU_TYPE)" != "$(DEB_BUILD_GNU_TYPE)" ]; then\
@@ -40,7 +41,7 @@ override_dh_auto_build:
        fi
        rm $(BUILD_DIR)/bin/script
        rm $(BUILD_DIR)/bin/man
-       ./script/man
+       make man
 
 override_dh_strip:
        # strip disabled as golang upstream doesn't support it and it makes go
index c7dd82f..adab6a9 100644 (file)
@@ -7,6 +7,8 @@ git-lfs-checkout(1) -- Update working copy with file content if available
 
 ## DESCRIPTION
 
+This command is deprecated, and should be replaced with `git checkout`.
+
 Try to ensure that the working copy contains file content for Git LFS objects
 for the current ref, if the object data is available. Does not download any
 content, see git-lfs-fetch(1) for that. 
index 32b3b28..579742f 100644 (file)
@@ -51,6 +51,11 @@ be scoped inside the configuration for a remote.
   Sets the maximum time, in seconds, for the HTTP client to maintain keepalive
   connections. Default: 30 minutes.
 
+* `lfs.ssh.retries`
+
+  Specifies the number of times Git LFS will attempt to obtain authorization via
+  SSH before aborting. Default: 5.
+
 * `core.askpass`, GIT_ASKPASS
 
   Given as a program and its arguments, this is invoked when authentication is
@@ -156,7 +161,7 @@ be scoped inside the configuration for a remote.
 * `lfs.allowincompletepush`
 
   When pushing, allow objects to be missing from the local cache without halting
-  a Git push. Default: true.
+  a Git push. Default: false.
 
 ### Fetch settings
 
@@ -303,6 +308,14 @@ be scoped inside the configuration for a remote.
   The default is `true`; you can disable this behaviour and have all files
   writeable by setting either variable to 0, 'no' or 'false'.
 
+* `lfs.defaulttokenttl`
+
+  This setting sets a default token TTL when git-lfs-authenticate does not
+  include the TTL in the JSON response but still enforces it.
+
+  Note that this is only necessary for larger repositories hosted on LFS
+  servers that don't include the TTL.
+
 ## LFSCONFIG
 
 The .lfsconfig file in a repository is read and interpreted in the same format
index 7ee3782..9b06b13 100644 (file)
@@ -80,12 +80,78 @@ options and these additional ones:
 * `--verbose`
     Print the commit oid and filename of migrated files to STDOUT.
 
-If `--include` or `--exclude` (`-I`, `-X`, respectively) are given, the
-.gitattributes will be modified to include any new filepath patterns as given by
-those flags.
+* `--object-map=<path>`
+    Write to 'path' a file with the mapping of each rewritten commits. The file
+    format is CSV with this pattern: `OLD-SHA`,`NEW-SHA`
+
+* `--no-rewrite`
+    Migrate large objects to Git LFS in a new commit without rewriting git
+    history. Please note that when this option is used, the `migrate import`
+    command will expect a different argument list, specialized options will
+    become available, and the core `migrate` options will be ignored. See
+    [IMPORT (NO REWRITE)].
+
+* `--fixup`
+    Infer `--include` and `--exclude` filters on a per-commit basis based on the
+    .gitattributes files in a repository. In practice, this option imports any
+    filepaths which should be tracked by Git LFS according to the repository's
+    .gitattributes file(s), but aren't already pointers. This option is
+    incompatible with explicitly given `--include`, `--exclude` filters.
+
+If `--no-rewrite` is not provided and `--include` or `--exclude` (`-I`, `-X`,
+respectively) are given, the .gitattributes will be modified to include any new
+filepath patterns as given by those flags.
+
+If `--no-rewrite` is not provided and neither of those flags are given, the
+gitattributes will be incrementally modified to include new filepath extensions
+as they are rewritten in history.
+
+### IMPORT (NO REWRITE)
+
+The `import` mode has a special sub-mode enabled by the `--no-rewrite` flag.
+This sub-mode will migrate large objects to pointers as in the base `import`
+mode, but will do so in a new commit without rewriting Git history. When using
+this sub-mode, the base `migrate` options, such as `--include-ref`, will be
+ignored, as will those for the base `import` mode. The `migrate` command will
+also take a different argument list. As a result of these changes,
+`--no-rewrite` will only operate on the current branch - any other interested
+branches must have the generated commit merged in.
+
+The `--no-rewrite` sub-mode supports the following options and arguments:
+
+* `-m <message> --message=<message>`
+    Specifies a commit message for the newly created commit.
+
+* [file ...]
+    The list of files to import. These files must be tracked by patterns
+    specified in the gitattributes.
+
+If `--message` is given, the new commit will be created with the provided
+message. If no message is given, a commit message will be generated based on the
+file arguments.
+
+### EXPORT
+
+The 'export' mode migrates Git LFS pointer files present in the Git history out
+of Git LFS, converting them into their corresponding object files. It supports
+all the core 'migrate' options and these additional ones:
 
-If neither of those flags are given, the gitattributes will be incrementally
-modified to include new filepath extensions as they are rewritten in history.
+* `--verbose`
+    Print the commit oid and filename of migrated files to STDOUT.
+
+* `--object-map=<path>`
+    Write to 'path' a file with the mapping of each rewritten commit. The file
+    format is CSV with this pattern: `OLD-SHA`,`NEW-SHA`
+
+* `--remote=<git-remote>`
+    Download LFS objects from the provided 'git-remote' during the export. If
+    not provided, defaults to 'origin'.
+
+The 'export' mode requires at minimum a pattern provided with the `--include`
+argument to specify which files to export. Files matching the `--include`
+patterns will be removed from Git LFS, while files matching the `--exclude`
+patterns will retain their Git LFS status. The export command will modify the
+.gitattributes to set/unset any filepath patterns as given by those flags.
 
 ## INCLUDE AND EXCLUDE
 
@@ -124,8 +190,8 @@ The following configuration:
 
 Would, therefore, include commits: F, E, D, C, B, but exclude commit A.
 
-The presence of flag `--everything` indicates that all local references should be
-migrated.
+The presence of flag `--everything` indicates that all local and remote
+references should be migrated.
 
 ## EXAMPLES
 
@@ -185,6 +251,24 @@ $ git lfs migrate import --everything --include="*.zip"
 
 Note: This will require a force push to any existing Git remotes.
 
+### Migrate without rewriting local history
+
+You can also migrate files without modifying the existing history of your
+repository:
+
+Without a specified commit message:
+
+```
+$ git lfs migrate import --no-rewrite test.zip *.mp3 *.psd
+```
+
+With a specified commit message:
+
+```
+$ git lfs migrate import --no-rewrite -m "Import .zip, .mp3, .psd files" \
+  test.zip *.mpd *.psd
+```
+
 ## SEE ALSO
 
 Part of the git-lfs(1) suite.
index 234880e..41810bc 100644 (file)
@@ -59,6 +59,6 @@ to match paths.
 
 ## SEE ALSO
 
-git-lfs-untrack(1), git-lfs-install(1), gitattributes(5).
+git-lfs-untrack(1), git-lfs-install(1), gitattributes(5), gitignore(5).
 
 Part of the git-lfs(1) suite.
index dc5cc42..1621cfe 100644 (file)
@@ -33,7 +33,7 @@ commands and low level ("plumbing") commands.
     Display the Git LFS environment.
 * git-lfs-checkout(1):
     Populate working copy with real content from Git LFS files.
-* git lfs clone:
+* git-lfs-clone(1):
     Efficiently clone a Git LFS-enabled repository.
 * git-lfs-fetch(1):
     Download Git LFS files from a remote.
@@ -46,15 +46,16 @@ commands and low level ("plumbing") commands.
 * git-lfs-locks(1):
     List currently "locked" files from the Git LFS server.
 * git-lfs-logs(1):
-    Show errors from the git-lfs command.
+    Show errors from the Git LFS command.
 * git-lfs-ls-files(1):
     Show information about Git LFS files in the index and working tree.
 * git-lfs-migrate(1):
-    Migrate history to or from git-lfs
+    Migrate history to or from Git LFS
 * git-lfs-prune(1):
     Delete old Git LFS files from local storage
 * git-lfs-pull(1):
-    Fetch LFS changes from the remote & checkout any required working tree files.
+    Fetch Git LFS changes from the remote & checkout any required working tree
+    files.
 * git-lfs-push(1):
     Push queued large files to the Git LFS endpoint.
 * git-lfs-status(1):
@@ -69,7 +70,7 @@ commands and low level ("plumbing") commands.
     Remove Git LFS paths from Git Attributes.
 * git-lfs-update(1):
     Update Git hooks for the current Git repository.
-* git lfs version:
+* git-lfs-version(1):
     Report the version number.
 
 ### Low level commands (plumbing)
@@ -80,5 +81,32 @@ commands and low level ("plumbing") commands.
     Build and compare pointers.
 * git-lfs-pre-push(1):
     Git pre-push hook implementation.
+* git-lfs-filter-process(1):
+    Git process filter that converts between large files and pointers.
 * git-lfs-smudge(1):
     Git smudge filter that converts pointer in blobs to the actual content.
+
+## EXAMPLES
+
+To get started with Git LFS, the following commands can be used.
+
+ 1. Setup Git LFS on your system. You only have to do this once per
+    repository per machine:
+
+        git lfs install
+
+ 2. Choose the type of files you want to track, for examples all `ISO`
+    images, with git-lfs-track(1):
+
+        git lfs track "*.iso"
+
+ 3. The above stores this information in gitattributes(5) files, so
+    that file need to be added to the repository:
+
+        git add .gitattributes
+
+ 3. Commit, push and work with the files normally:
+
+        git add file.iso
+        git commit -m "Add disk image"
+        git push
index b174f1a..c189ead 100644 (file)
--- a/fs/fs.go
+++ b/fs/fs.go
@@ -1,19 +1,31 @@
 package fs
 
 import (
+       "bufio"
+       "bytes"
        "fmt"
        "io/ioutil"
        "os"
        "path/filepath"
        "regexp"
+       "strconv"
        "strings"
        "sync"
 
        "github.com/git-lfs/git-lfs/tools"
+       "github.com/rubyist/tracerx"
 )
 
 var oidRE = regexp.MustCompile(`\A[[:alnum:]]{64}`)
 
+// Environment is a copy of a subset of the interface
+// github.com/git-lfs/git-lfs/config.Environment.
+//
+// For more information, see config/environment.go.
+type Environment interface {
+       Get(key string) (val string, ok bool)
+}
+
 // Object represents a locally stored LFS object.
 type Object struct {
        Oid  string
@@ -21,9 +33,9 @@ type Object struct {
 }
 
 type Filesystem struct {
-       GitStorageDir string // parent of objects/lfs (may be same as GitDir but may not)
-       LFSStorageDir string // parent of lfs objects and tmp dirs. Default: ".git/lfs"
-       ReferenceDir  string // alternative local media dir (relative to clone reference repo)
+       GitStorageDir string   // parent of objects/lfs (may be same as GitDir but may not)
+       LFSStorageDir string   // parent of lfs objects and tmp dirs. Default: ".git/lfs"
+       ReferenceDirs []string // alternative local media dirs (relative to clone reference repo)
        lfsobjdir     string
        tmpdir        string
        logdir        string
@@ -63,16 +75,56 @@ func (f *Filesystem) ObjectPathname(oid string) string {
        return filepath.Join(f.localObjectDir(oid), oid)
 }
 
+func (f *Filesystem) DecodePathname(path string) string {
+       return string(DecodePathBytes([]byte(path)))
+}
+
+/**
+ * Revert non ascii chracters escaped by git or windows (as octal sequences \000) back to bytes.
+ */
+func DecodePathBytes(path []byte) []byte {
+       var expression = regexp.MustCompile(`\\[0-9]{3}`)
+       var buffer bytes.Buffer
+
+       // strip quotes if any
+       if len(path) > 2 && path[0] == '"' && path[len(path)-1] == '"' {
+               path = path[1 : len(path)-1]
+       }
+
+       base := 0
+       for _, submatches := range expression.FindAllSubmatchIndex(path, -1) {
+               buffer.Write(path[base:submatches[0]])
+
+               match := string(path[submatches[0]+1 : submatches[0]+4])
+
+               k, err := strconv.ParseUint(match, 8, 64)
+               if err != nil {
+                       return path
+               } // abort on error
+
+               buffer.Write([]byte{byte(k)})
+               base = submatches[1]
+       }
+
+       buffer.Write(path[base:len(path)])
+
+       return buffer.Bytes()
+}
+
 func (f *Filesystem) localObjectDir(oid string) string {
        return filepath.Join(f.LFSObjectDir(), oid[0:2], oid[2:4])
 }
 
-func (f *Filesystem) ObjectReferencePath(oid string) string {
-       if len(f.ReferenceDir) == 0 {
-               return f.ReferenceDir
+func (f *Filesystem) ObjectReferencePaths(oid string) []string {
+       if len(f.ReferenceDirs) == 0 {
+               return nil
        }
 
-       return filepath.Join(f.ReferenceDir, oid[0:2], oid[2:4], oid)
+       var paths []string
+       for _, ref := range f.ReferenceDirs {
+               paths = append(paths, filepath.Join(ref, oid[0:2], oid[2:4], oid))
+       }
+       return paths
 }
 
 func (f *Filesystem) LFSObjectDir() string {
@@ -121,12 +173,12 @@ func (f *Filesystem) Cleanup() error {
 // New initializes a new *Filesystem with the given directories. gitdir is the
 // path to the bare repo, workdir is the path to the repository working
 // directory, and lfsdir is the optional path to the `.git/lfs` directory.
-func New(gitdir, workdir, lfsdir string) *Filesystem {
+func New(env Environment, gitdir, workdir, lfsdir string) *Filesystem {
        fs := &Filesystem{
                GitStorageDir: resolveGitStorageDir(gitdir),
        }
 
-       fs.ReferenceDir = resolveReferenceDir(fs.GitStorageDir)
+       fs.ReferenceDirs = resolveReferenceDirs(env, fs.GitStorageDir)
 
        if len(lfsdir) == 0 {
                lfsdir = "lfs"
@@ -141,19 +193,75 @@ func New(gitdir, workdir, lfsdir string) *Filesystem {
        return fs
 }
 
-func resolveReferenceDir(gitStorageDir string) string {
+func resolveReferenceDirs(env Environment, gitStorageDir string) []string {
+       var references []string
+
+       envAlternates, ok := env.Get("GIT_ALTERNATE_OBJECT_DIRECTORIES")
+       if ok {
+               splits := strings.Split(envAlternates, string(os.PathListSeparator))
+               for _, split := range splits {
+                       if dir, ok := existsAlternate(split); ok {
+                               references = append(references, dir)
+                       }
+               }
+       }
+
        cloneReferencePath := filepath.Join(gitStorageDir, "objects", "info", "alternates")
        if tools.FileExists(cloneReferencePath) {
-               buffer, err := ioutil.ReadFile(cloneReferencePath)
-               if err == nil {
-                       path := strings.TrimSpace(string(buffer[:]))
-                       referenceLfsStoragePath := filepath.Join(filepath.Dir(path), "lfs", "objects")
-                       if tools.DirExists(referenceLfsStoragePath) {
-                               return referenceLfsStoragePath
+               f, err := os.Open(cloneReferencePath)
+               if err != nil {
+                       tracerx.Printf("could not open %s: %s",
+                               cloneReferencePath, err)
+                       return nil
+               }
+               defer f.Close()
+
+               scanner := bufio.NewScanner(f)
+               for scanner.Scan() {
+                       text := strings.TrimSpace(scanner.Text())
+                       if len(text) == 0 || strings.HasPrefix(text, "#") {
+                               continue
+                       }
+
+                       if dir, ok := existsAlternate(text); ok {
+                               references = append(references, dir)
                        }
                }
+
+               if err := scanner.Err(); err != nil {
+                       tracerx.Printf("could not scan %s: %s",
+                               cloneReferencePath, err)
+               }
+       }
+       return references
+}
+
+// existsAlternate takes an object directory given in "objs" (read as a single,
+// line from .git/objects/info/alternates). If that is a satisfiable alternates
+// directory (i.e., it exists), the directory is returned along with "true". If
+// not, the empty string and false is returned instead.
+func existsAlternate(objs string) (string, bool) {
+       objs = strings.TrimSpace(objs)
+       if strings.HasPrefix(objs, "\"") {
+               var err error
+
+               unquote := strings.LastIndex(objs, "\"")
+               if unquote == 0 {
+                       return "", false
+               }
+
+               objs, err = strconv.Unquote(objs[:unquote+1])
+               if err != nil {
+                       return "", false
+               }
+       }
+
+       storage := filepath.Join(filepath.Dir(objs), "lfs", "objects")
+
+       if tools.DirExists(storage) {
+               return storage, true
        }
-       return ""
+       return "", false
 }
 
 // From a git dir, get the location that objects are to be stored (we will store lfs alongside)
diff --git a/fs/fs_test.go b/fs/fs_test.go
new file mode 100644 (file)
index 0000000..7d0933e
--- /dev/null
@@ -0,0 +1,26 @@
+package fs
+
+import "testing"
+
+func TestDecodeNone(t *testing.T) {
+       evaluate(t, "A:\\some\\regular\\windows\\path", "A:\\some\\regular\\windows\\path")
+}
+
+func TestDecodeSingle(t *testing.T) {
+       evaluate(t, "A:\\bl\\303\\204\\file.txt", "A:\\blÄ\\file.txt")
+}
+
+func TestDecodeMultiple(t *testing.T) {
+       evaluate(t, "A:\\fo\\130\\file\\303\\261.txt", "A:\\fo\130\\file\303\261.txt")
+}
+
+func evaluate(t *testing.T, input string, expected string) {
+
+       fs := Filesystem{}
+       output := fs.DecodePathname(input)
+
+       if output != expected {
+               t.Errorf("Expecting same path, got: %s, want: %s.", output, expected)
+       }
+
+}
index 067bf42..6a033b5 100644 (file)
@@ -7,6 +7,7 @@ import (
        "path/filepath"
        "strings"
 
+       "github.com/git-lfs/git-lfs/filepathfilter"
        "github.com/git-lfs/git-lfs/tools"
        "github.com/rubyist/tracerx"
 )
@@ -34,6 +35,36 @@ func (s *AttributeSource) String() string {
        return s.Path
 }
 
+// GetRootAttributePaths beahves as GetRootAttributePaths, and loads information
+// only from the global gitattributes file.
+func GetRootAttributePaths(cfg Env) []AttributePath {
+       af, ok := cfg.Get("core.attributesfile")
+       if !ok {
+               return nil
+       }
+
+       // The working directory for the root gitattributes file is blank.
+       return attrPaths(af, "")
+}
+
+// GetSystemAttributePaths behaves as GetAttributePaths, and loads information
+// only from the system gitattributes file, respecting the $PREFIX environment
+// variable.
+func GetSystemAttributePaths(env Env) []AttributePath {
+       prefix, _ := env.Get("PREFIX")
+       if len(prefix) == 0 {
+               prefix = string(filepath.Separator)
+       }
+
+       path := filepath.Join(prefix, "etc", "gitattributes")
+
+       if _, err := os.Stat(path); os.IsNotExist(err) {
+               return nil
+       }
+
+       return attrPaths(path, "")
+}
+
 // GetAttributePaths returns a list of entries in .gitattributes which are
 // configured with the filter=lfs attribute
 // workingDir is the root of the working copy
@@ -42,61 +73,87 @@ func GetAttributePaths(workingDir, gitDir string) []AttributePath {
        paths := make([]AttributePath, 0)
 
        for _, path := range findAttributeFiles(workingDir, gitDir) {
-               attributes, err := os.Open(path)
-               if err != nil {
-                       continue
-               }
+               paths = append(paths, attrPaths(path, workingDir)...)
+       }
+
+       return paths
+}
 
-               relfile, _ := filepath.Rel(workingDir, path)
-               reldir := filepath.Dir(relfile)
-               source := &AttributeSource{Path: relfile}
+func attrPaths(path, workingDir string) []AttributePath {
+       attributes, err := os.Open(path)
+       if err != nil {
+               return nil
+       }
 
-               le := &lineEndingSplitter{}
-               scanner := bufio.NewScanner(attributes)
-               scanner.Split(le.ScanLines)
+       var paths []AttributePath
 
-               for scanner.Scan() {
-                       line := strings.TrimSpace(scanner.Text())
+       relfile, _ := filepath.Rel(workingDir, path)
+       reldir := filepath.Dir(relfile)
+       source := &AttributeSource{Path: relfile}
 
-                       if strings.HasPrefix(line, "#") {
-                               continue
-                       }
+       le := &lineEndingSplitter{}
+       scanner := bufio.NewScanner(attributes)
+       scanner.Split(le.ScanLines)
 
-                       // Check for filter=lfs (signifying that LFS is tracking
-                       // this file) or "lockable", which indicates that the
-                       // file is lockable (and may or may not be tracked by
-                       // Git LFS).
-                       if strings.Contains(line, "filter=lfs") ||
-                               strings.HasSuffix(line, "lockable") {
-
-                               fields := strings.Fields(line)
-                               pattern := fields[0]
-                               if len(reldir) > 0 {
-                                       pattern = filepath.Join(reldir, pattern)
-                               }
-                               // Find lockable flag in any position after pattern to avoid
-                               // edge case of matching "lockable" to a file pattern
-                               lockable := false
-                               for _, f := range fields[1:] {
-                                       if f == LockableAttrib {
-                                               lockable = true
-                                               break
-                                       }
+       for scanner.Scan() {
+               line := strings.TrimSpace(scanner.Text())
+
+               if strings.HasPrefix(line, "#") {
+                       continue
+               }
+
+               // Check for filter=lfs (signifying that LFS is tracking
+               // this file) or "lockable", which indicates that the
+               // file is lockable (and may or may not be tracked by
+               // Git LFS).
+               if strings.Contains(line, "filter=lfs") ||
+                       strings.HasSuffix(line, "lockable") {
+
+                       fields := strings.Fields(line)
+                       pattern := fields[0]
+                       if len(reldir) > 0 {
+                               pattern = filepath.Join(reldir, pattern)
+                       }
+                       // Find lockable flag in any position after pattern to avoid
+                       // edge case of matching "lockable" to a file pattern
+                       lockable := false
+                       for _, f := range fields[1:] {
+                               if f == LockableAttrib {
+                                       lockable = true
+                                       break
                                }
-                               paths = append(paths, AttributePath{
-                                       Path:     pattern,
-                                       Source:   source,
-                                       Lockable: lockable,
-                               })
                        }
+                       paths = append(paths, AttributePath{
+                               Path:     pattern,
+                               Source:   source,
+                               Lockable: lockable,
+                       })
                }
-
-               source.LineEnding = le.LineEnding()
        }
 
+       source.LineEnding = le.LineEnding()
+
        return paths
 }
 
+// GetAttributeFilter returns a list of entries in .gitattributes which are
+// configured with the filter=lfs attribute as a file path filter which
+// file paths can be matched against
+// workingDir is the root of the working copy
+// gitDir is the root of the git repo
+func GetAttributeFilter(workingDir, gitDir string) *filepathfilter.Filter {
+       paths := GetAttributePaths(workingDir, gitDir)
+       patterns := make([]filepathfilter.Pattern, 0, len(paths))
+
+       for _, path := range paths {
+               // Convert all separators to `/` before creating a pattern to
+               // avoid characters being escaped in situations like `subtree\*.md`
+               patterns = append(patterns, filepathfilter.NewPattern(filepath.ToSlash(path.Path)))
+       }
+
+       return filepathfilter.NewFromPatterns(patterns, nil)
+}
+
 // copies bufio.ScanLines(), counting LF vs CRLF in a file
 type lineEndingSplitter struct {
        LFCount   int
index fd54257..7b7970d 100644 (file)
@@ -975,7 +975,13 @@ func Fetch(remotes ...string) error {
                return nil
        }
 
-       _, err := gitNoLFSSimple(append([]string{"fetch"}, remotes...)...)
+       var args []string
+       if len(remotes) > 1 {
+               args = []string{"--multiple", "--"}
+       }
+       args = append(args, remotes...)
+
+       _, err := gitNoLFSSimple(append([]string{"fetch"}, args...)...)
        return err
 }
 
@@ -1186,3 +1192,21 @@ func IsFileModified(filepath string) (bool, error) {
 
        return matched, nil
 }
+
+// IsWorkingCopyDirty returns true if and only if the working copy in which the
+// command was executed is dirty as compared to the index.
+//
+// If the status of the working copy could not be determined, an error will be
+// returned instead.
+func IsWorkingCopyDirty() (bool, error) {
+       bare, err := IsBare()
+       if bare || err != nil {
+               return false, err
+       }
+
+       out, err := gitSimple("status", "--porcelain")
+       if err != nil {
+               return false, err
+       }
+       return len(out) != 0, nil
+}
index 6b0228b..0a94f2b 100644 (file)
@@ -9,7 +9,7 @@ import (
        "time"
 
        . "github.com/git-lfs/git-lfs/git"
-       "github.com/git-lfs/git-lfs/test"
+       test "github.com/git-lfs/git-lfs/t/cmd/util"
        "github.com/stretchr/testify/assert"
 )
 
diff --git a/git/gitattr/attr.go b/git/gitattr/attr.go
new file mode 100644 (file)
index 0000000..2246a39
--- /dev/null
@@ -0,0 +1,129 @@
+package gitattr
+
+import (
+       "bufio"
+       "io"
+       "strconv"
+       "strings"
+
+       "github.com/git-lfs/git-lfs/errors"
+       "github.com/git-lfs/wildmatch"
+)
+
+// Line carries a single line from a repository's .gitattributes file, affecting
+// a single pattern and applying zero or more attributes.
+type Line struct {
+       // Pattern is a wildmatch pattern that, when matched, indicates that all
+       // of the below attributes (Attrs) should be applied to that tree entry.
+       //
+       // Pattern is relative to the tree in which the .gitattributes was read
+       // from. For example, /.gitattributes affects all blobs in the
+       // repository, while /path/to/.gitattributes affects all blobs that are
+       // direct or indirect children of /path/to.
+       Pattern *wildmatch.Wildmatch
+       // Attrs is the list of attributes to be applied when the above pattern
+       // matches a given filename.
+       //
+       // It is populated in-order as it was written in the .gitattributes file
+       // being read, from left to right.
+       Attrs []*Attr
+}
+
+// Attr is a single attribute that may be applied to a file.
+type Attr struct {
+       // K is the name of the attribute. It is commonly, "filter", "diff",
+       // "merge", or "text".
+       //
+       // It will never contain the special "false" shorthand ("-"), or the
+       // unspecify declarative ("!").
+       K string
+       // V is the value held by that attribute. It is commonly "lfs", or
+       // "false", indicating the special value given by a "-"-prefixed name.
+       V string
+       // Unspecified indicates whether or not this attribute was explicitly
+       // unset by prefixing the keyname with "!".
+       Unspecified bool
+}
+
+// ParseLines parses the given io.Reader "r" line-wise as if it were the
+// contents of a .gitattributes file.
+//
+// If an error was encountered, it will be returned and the []*Line should be
+// considered unusable.
+func ParseLines(r io.Reader) ([]*Line, error) {
+       var lines []*Line
+
+       scanner := bufio.NewScanner(r)
+       for scanner.Scan() {
+
+               text := strings.TrimSpace(scanner.Text())
+               if len(text) == 0 {
+                       continue
+               }
+
+               var pattern string
+               var applied string
+
+               switch text[0] {
+               case '#':
+                       continue
+               case '"':
+                       var err error
+                       last := strings.LastIndex(text, "\"")
+                       if last == 0 {
+                               return nil, errors.Errorf("git/gitattr: unbalanced quote: %s", text)
+                       }
+                       pattern, err = strconv.Unquote(text[:last+1])
+                       if err != nil {
+                               return nil, errors.Wrapf(err, "git/gitattr")
+                       }
+                       applied = strings.TrimSpace(text[last+1:])
+               default:
+                       splits := strings.SplitN(text, " ", 2)
+
+                       pattern = splits[0]
+                       if len(splits) == 2 {
+                               applied = splits[1]
+                       }
+               }
+
+               var attrs []*Attr
+
+               for _, s := range strings.Split(applied, " ") {
+                       if s == "" {
+                               continue
+                       }
+
+                       var attr Attr
+
+                       if strings.HasPrefix(s, "-") {
+                               attr.K = strings.TrimPrefix(s, "-")
+                               attr.V = "false"
+                       } else if strings.HasPrefix(s, "!") {
+                               attr.K = strings.TrimPrefix(s, "!")
+                               attr.Unspecified = true
+                       } else {
+                               splits := strings.SplitN(s, "=", 2)
+                               if len(splits) != 2 {
+                                       return nil, errors.Errorf("git/gitattr: malformed attribute: %s", s)
+                               }
+                               attr.K = splits[0]
+                               attr.V = splits[1]
+                       }
+
+                       attrs = append(attrs, &attr)
+               }
+
+               lines = append(lines, &Line{
+                       Pattern: wildmatch.NewWildmatch(pattern,
+                               wildmatch.Basename, wildmatch.SystemCase,
+                       ),
+                       Attrs: attrs,
+               })
+       }
+
+       if err := scanner.Err(); err != nil {
+               return nil, err
+       }
+       return lines, nil
+}
diff --git a/git/gitattr/attr_test.go b/git/gitattr/attr_test.go
new file mode 100644 (file)
index 0000000..7632482
--- /dev/null
@@ -0,0 +1,134 @@
+package gitattr
+
+import (
+       "fmt"
+       "strings"
+       "testing"
+
+       "github.com/stretchr/testify/assert"
+)
+
+func TestParseLines(t *testing.T) {
+       lines, err := ParseLines(strings.NewReader("*.dat filter=lfs"))
+
+       assert.NoError(t, err)
+       assert.Len(t, lines, 1)
+
+       assert.Equal(t, lines[0].Pattern.String(), "*.dat")
+       assert.Equal(t, lines[0].Attrs[0], &Attr{
+               K: "filter", V: "lfs",
+       })
+}
+
+func TestParseLinesManyAttrs(t *testing.T) {
+       lines, err := ParseLines(strings.NewReader(
+               "*.dat filter=lfs diff=lfs merge=lfs -text"))
+
+       assert.NoError(t, err)
+
+       assert.Len(t, lines, 1)
+       assert.Equal(t, lines[0].Pattern.String(), "*.dat")
+
+       assert.Len(t, lines[0].Attrs, 4)
+       assert.Equal(t, lines[0].Attrs[0], &Attr{K: "filter", V: "lfs"})
+       assert.Equal(t, lines[0].Attrs[1], &Attr{K: "diff", V: "lfs"})
+       assert.Equal(t, lines[0].Attrs[2], &Attr{K: "merge", V: "lfs"})
+       assert.Equal(t, lines[0].Attrs[3], &Attr{K: "text", V: "false"})
+}
+
+func TestParseLinesManyLines(t *testing.T) {
+       lines, err := ParseLines(strings.NewReader(strings.Join([]string{
+               "*.dat filter=lfs diff=lfs merge=lfs -text",
+               "*.jpg filter=lfs diff=lfs merge=lfs -text",
+               "# *.pdf filter=lfs diff=lfs merge=lfs -text",
+               "*.png filter=lfs diff=lfs merge=lfs -text"}, "\n")))
+
+       assert.NoError(t, err)
+
+       assert.Len(t, lines, 3)
+       assert.Equal(t, lines[0].Pattern.String(), "*.dat")
+       assert.Equal(t, lines[1].Pattern.String(), "*.jpg")
+       assert.Equal(t, lines[2].Pattern.String(), "*.png")
+
+       assert.Len(t, lines[0].Attrs, 4)
+       assert.Equal(t, lines[0].Attrs[0], &Attr{K: "filter", V: "lfs"})
+       assert.Equal(t, lines[0].Attrs[1], &Attr{K: "diff", V: "lfs"})
+       assert.Equal(t, lines[0].Attrs[2], &Attr{K: "merge", V: "lfs"})
+       assert.Equal(t, lines[0].Attrs[3], &Attr{K: "text", V: "false"})
+
+       assert.Len(t, lines[1].Attrs, 4)
+       assert.Equal(t, lines[1].Attrs[0], &Attr{K: "filter", V: "lfs"})
+       assert.Equal(t, lines[1].Attrs[1], &Attr{K: "diff", V: "lfs"})
+       assert.Equal(t, lines[1].Attrs[2], &Attr{K: "merge", V: "lfs"})
+       assert.Equal(t, lines[1].Attrs[3], &Attr{K: "text", V: "false"})
+
+       assert.Len(t, lines[1].Attrs, 4)
+       assert.Equal(t, lines[1].Attrs[0], &Attr{K: "filter", V: "lfs"})
+       assert.Equal(t, lines[1].Attrs[1], &Attr{K: "diff", V: "lfs"})
+       assert.Equal(t, lines[1].Attrs[2], &Attr{K: "merge", V: "lfs"})
+       assert.Equal(t, lines[1].Attrs[3], &Attr{K: "text", V: "false"})
+}
+
+func TestParseLinesUnset(t *testing.T) {
+       lines, err := ParseLines(strings.NewReader("*.dat -filter"))
+
+       assert.NoError(t, err)
+       assert.Len(t, lines, 1)
+
+       assert.Equal(t, lines[0].Pattern.String(), "*.dat")
+       assert.Equal(t, lines[0].Attrs[0], &Attr{
+               K: "filter", V: "false",
+       })
+}
+
+func TestParseLinesUnspecified(t *testing.T) {
+       lines, err := ParseLines(strings.NewReader("*.dat !filter"))
+
+       assert.NoError(t, err)
+       assert.Len(t, lines, 1)
+
+       assert.Equal(t, lines[0].Pattern.String(), "*.dat")
+       assert.Equal(t, lines[0].Attrs[0], &Attr{
+               K: "filter", Unspecified: true,
+       })
+}
+
+func TestParseLinesQuotedPattern(t *testing.T) {
+       lines, err := ParseLines(strings.NewReader(
+               "\"space *.dat\" filter=lfs"))
+
+       assert.NoError(t, err)
+       assert.Len(t, lines, 1)
+
+       assert.Equal(t, lines[0].Pattern.String(), "space *.dat")
+       assert.Equal(t, lines[0].Attrs[0], &Attr{
+               K: "filter", V: "lfs",
+       })
+}
+
+func TestParseLinesCommented(t *testing.T) {
+       lines, err := ParseLines(strings.NewReader(
+               "# \"space *.dat\" filter=lfs"))
+
+       assert.NoError(t, err)
+       assert.Len(t, lines, 0)
+}
+
+func TestParseLinesUnbalancedQuotes(t *testing.T) {
+       const text = "\"space *.dat filter=lfs"
+       lines, err := ParseLines(strings.NewReader(text))
+
+       assert.Empty(t, lines)
+       assert.EqualError(t, err, fmt.Sprintf(
+               "git/gitattr: unbalanced quote: %s", text))
+}
+
+func TestParseLinesWithNoAttributes(t *testing.T) {
+       lines, err := ParseLines(strings.NewReader("*.dat"))
+
+       assert.Len(t, lines, 1)
+       assert.NoError(t, err)
+
+       assert.Equal(t, lines[0].Pattern.String(), "*.dat")
+       assert.Empty(t, lines[0].Attrs)
+}
diff --git a/git/gitattr/tree.go b/git/gitattr/tree.go
new file mode 100644 (file)
index 0000000..45e7bde
--- /dev/null
@@ -0,0 +1,104 @@
+package gitattr
+
+import (
+       "strings"
+
+       "github.com/git-lfs/gitobj"
+)
+
+// Tree represents the .gitattributes file at one layer of the tree in a Git
+// repository.
+type Tree struct {
+       // Lines are the lines of the .gitattributes at this level of the tree.
+       Lines []*Line
+       // Children are the named child directories in the repository.
+       Children map[string]*Tree
+}
+
+// New constructs a *Tree starting at the given tree "t" and reading objects
+// from the given ObjectDatabase. If a tree was not able to be read, an error
+// will be propagated up accordingly.
+func New(db *gitobj.ObjectDatabase, t *gitobj.Tree) (*Tree, error) {
+       children := make(map[string]*Tree)
+       lines, err := linesInTree(db, t)
+       if err != nil {
+               return nil, err
+       }
+
+       for _, entry := range t.Entries {
+               if entry.Type() != gitobj.TreeObjectType {
+                       continue
+               }
+
+               // For every entry in the current tree, parse its sub-trees to
+               // see if they might contain a .gitattributes.
+               t, err := db.Tree(entry.Oid)
+               if err != nil {
+                       return nil, err
+               }
+
+               at, err := New(db, t)
+               if err != nil {
+                       return nil, err
+               }
+
+               if len(at.Children) > 0 || len(at.Lines) > 0 {
+                       // Only include entries that have either (1) a
+                       // .gitattributes in their tree, or (2) a .gitattributes
+                       // in a sub-tree.
+                       children[entry.Name] = at
+               }
+       }
+
+       return &Tree{
+               Lines:    lines,
+               Children: children,
+       }, nil
+}
+
+// linesInTree parses a given tree's .gitattributes and returns a slice of lines
+// in that .gitattributes, or an error. If no .gitattributes blob was found,
+// return nil.
+func linesInTree(db *gitobj.ObjectDatabase, t *gitobj.Tree) ([]*Line, error) {
+       var at int = -1
+       for i, e := range t.Entries {
+               if e.Name == ".gitattributes" {
+                       at = i
+                       break
+               }
+       }
+
+       if at < 0 {
+               return nil, nil
+       }
+
+       blob, err := db.Blob(t.Entries[at].Oid)
+       if err != nil {
+               return nil, err
+       }
+       defer blob.Close()
+
+       return ParseLines(blob.Contents)
+}
+
+// Applied returns a slice of attributes applied to the given path, relative to
+// the receiving tree. It traverse through sub-trees in a topological ordering,
+// if there are relevant .gitattributes matching that path.
+func (t *Tree) Applied(to string) []*Attr {
+       var attrs []*Attr
+       for _, line := range t.Lines {
+               if line.Pattern.Match(to) {
+                       attrs = append(attrs, line.Attrs...)
+               }
+       }
+
+       splits := strings.SplitN(to, "/", 2)
+       if len(splits) == 2 {
+               car, cdr := splits[0], splits[1]
+               if child, ok := t.Children[car]; ok {
+                       attrs = append(attrs, child.Applied(cdr)...)
+               }
+       }
+
+       return attrs
+}
diff --git a/git/gitattr/tree_test.go b/git/gitattr/tree_test.go
new file mode 100644 (file)
index 0000000..10933fe
--- /dev/null
@@ -0,0 +1,250 @@
+package gitattr
+
+import (
+       "io/ioutil"
+       "os"
+       "testing"
+
+       "github.com/git-lfs/gitobj"
+       "github.com/git-lfs/wildmatch"
+       "github.com/stretchr/testify/assert"
+       "github.com/stretchr/testify/require"
+)
+
+var (
+       dat = wildmatch.NewWildmatch("*.dat",
+               wildmatch.Basename,
+               wildmatch.SystemCase)
+
+       example = &Tree{
+               Lines: []*Line{{
+                       Pattern: dat,
+                       Attrs: []*Attr{
+                               {
+                                       K: "filter", V: "lfs",
+                               },
+                               {
+                                       K: "diff", V: "lfs",
+                               },
+                               {
+                                       K: "merge", V: "lfs",
+                               },
+                               {
+                                       K: "text", V: "false",
+                               },
+                       },
+               }},
+               Children: map[string]*Tree{
+                       "subdir": &Tree{
+                               Lines: []*Line{{
+                                       Pattern: dat,
+                                       Attrs: []*Attr{
+                                               {
+                                                       K: "subdir", V: "yes",
+                                               },
+                                       },
+                               }},
+                       },
+               },
+       }
+)
+
+func TestTreeAppliedInRoot(t *testing.T) {
+       attrs := example.Applied("a.dat")
+
+       assert.Len(t, attrs, 4)
+       assert.Equal(t, attrs[0], &Attr{K: "filter", V: "lfs"})
+       assert.Equal(t, attrs[1], &Attr{K: "diff", V: "lfs"})
+       assert.Equal(t, attrs[2], &Attr{K: "merge", V: "lfs"})
+       assert.Equal(t, attrs[3], &Attr{K: "text", V: "false"})
+}
+
+func TestTreeAppliedInSubtreeRelevant(t *testing.T) {
+       attrs := example.Applied("subdir/a.dat")
+
+       assert.Len(t, attrs, 5)
+       assert.Equal(t, attrs[0], &Attr{K: "filter", V: "lfs"})
+       assert.Equal(t, attrs[1], &Attr{K: "diff", V: "lfs"})
+       assert.Equal(t, attrs[2], &Attr{K: "merge", V: "lfs"})
+       assert.Equal(t, attrs[3], &Attr{K: "text", V: "false"})
+       assert.Equal(t, attrs[4], &Attr{K: "subdir", V: "yes"})
+}
+
+func TestTreeAppliedInSubtreeIrrelevant(t *testing.T) {
+       attrs := example.Applied("subdir/a.txt")
+
+       assert.Empty(t, attrs)
+}
+
+func TestTreeAppliedInIrrelevantSubtree(t *testing.T) {
+       attrs := example.Applied("other/subdir/a.dat")
+
+       assert.Len(t, attrs, 4)
+       assert.Equal(t, attrs[0], &Attr{K: "filter", V: "lfs"})
+       assert.Equal(t, attrs[1], &Attr{K: "diff", V: "lfs"})
+       assert.Equal(t, attrs[2], &Attr{K: "merge", V: "lfs"})
+       assert.Equal(t, attrs[3], &Attr{K: "text", V: "false"})
+}
+
+func TestNewDiscoversSimpleTrees(t *testing.T) {
+       tmp, err := ioutil.TempDir("", "")
+       require.NoError(t, err)
+       defer os.Remove(tmp)
+
+       db, err := gitobj.FromFilesystem(tmp, "")
+       require.NoError(t, err)
+       defer db.Close()
+
+       blob, err := db.WriteBlob(gitobj.NewBlobFromBytes([]byte(`
+               *.dat filter=lfs diff=lfs merge=lfs -text
+       `)))
+       require.NoError(t, err)
+
+       tree, err := New(db, &gitobj.Tree{Entries: []*gitobj.TreeEntry{
+               {
+                       Name:     ".gitattributes",
+                       Oid:      blob,
+                       Filemode: 0100644,
+               },
+       }})
+       require.NoError(t, err)
+
+       attrs := tree.Applied("foo.dat")
+
+       assert.Len(t, attrs, 4)
+       assert.Equal(t, attrs[0], &Attr{K: "filter", V: "lfs"})
+       assert.Equal(t, attrs[1], &Attr{K: "diff", V: "lfs"})
+       assert.Equal(t, attrs[2], &Attr{K: "merge", V: "lfs"})
+       assert.Equal(t, attrs[3], &Attr{K: "text", V: "false"})
+}
+
+func TestNewDiscoversSimpleChildrenTrees(t *testing.T) {
+       tmp, err := ioutil.TempDir("", "")
+       require.NoError(t, err)
+       defer os.Remove(tmp)
+
+       db, err := gitobj.FromFilesystem(tmp, "")
+       require.NoError(t, err)
+       defer db.Close()
+
+       blob, err := db.WriteBlob(gitobj.NewBlobFromBytes([]byte(`
+               *.dat filter=lfs diff=lfs merge=lfs -text
+       `)))
+       require.NoError(t, err)
+
+       child, err := db.WriteTree(&gitobj.Tree{Entries: []*gitobj.TreeEntry{
+               {
+                       Name:     ".gitattributes",
+                       Oid:      blob,
+                       Filemode: 0100644,
+               },
+       }})
+
+       tree, err := New(db, &gitobj.Tree{Entries: []*gitobj.TreeEntry{
+               {
+                       Name:     "child",
+                       Oid:      child,
+                       Filemode: 040000,
+               },
+       }})
+       require.NoError(t, err)
+       assert.Empty(t, tree.Lines)
+       assert.Len(t, tree.Children, 1)
+
+       attrs := tree.Applied("child/foo.dat")
+
+       assert.Len(t, attrs, 4)
+       assert.Equal(t, attrs[0], &Attr{K: "filter", V: "lfs"})
+       assert.Equal(t, attrs[1], &Attr{K: "diff", V: "lfs"})
+       assert.Equal(t, attrs[2], &Attr{K: "merge", V: "lfs"})
+       assert.Equal(t, attrs[3], &Attr{K: "text", V: "false"})
+}
+
+func TestNewDiscoversIndirectChildrenTrees(t *testing.T) {
+       tmp, err := ioutil.TempDir("", "")
+       require.NoError(t, err)
+       defer os.Remove(tmp)
+
+       db, err := gitobj.FromFilesystem(tmp, "")
+       require.NoError(t, err)
+       defer db.Close()
+
+       blob, err := db.WriteBlob(gitobj.NewBlobFromBytes([]byte(`
+               *.dat filter=lfs diff=lfs merge=lfs -text
+       `)))
+       require.NoError(t, err)
+
+       indirect, err := db.WriteTree(&gitobj.Tree{Entries: []*gitobj.TreeEntry{
+               {
+                       Name:     ".gitattributes",
+                       Oid:      blob,
+                       Filemode: 0100644,
+               },
+       }})
+
+       child, err := db.WriteTree(&gitobj.Tree{Entries: []*gitobj.TreeEntry{
+               {
+                       Name:     "indirect",
+                       Oid:      indirect,
+                       Filemode: 040000,
+               },
+       }})
+
+       tree, err := New(db, &gitobj.Tree{Entries: []*gitobj.TreeEntry{
+               {
+                       Name:     "child",
+                       Oid:      child,
+                       Filemode: 040000,
+               },
+       }})
+       require.NoError(t, err)
+       assert.Empty(t, tree.Lines)
+       assert.Len(t, tree.Children, 1)
+
+       attrs := tree.Applied("child/indirect/foo.dat")
+
+       assert.Len(t, attrs, 4)
+       assert.Equal(t, attrs[0], &Attr{K: "filter", V: "lfs"})
+       assert.Equal(t, attrs[1], &Attr{K: "diff", V: "lfs"})
+       assert.Equal(t, attrs[2], &Attr{K: "merge", V: "lfs"})
+       assert.Equal(t, attrs[3], &Attr{K: "text", V: "false"})
+}
+
+func TestNewIgnoresChildrenAppropriately(t *testing.T) {
+       tmp, err := ioutil.TempDir("", "")
+       require.NoError(t, err)
+       defer os.Remove(tmp)
+
+       db, err := gitobj.FromFilesystem(tmp, "")
+       require.NoError(t, err)
+       defer db.Close()
+
+       blob, err := db.WriteBlob(gitobj.NewBlobFromBytes([]byte(`
+               *.dat filter=lfs diff=lfs merge=lfs -text
+       `)))
+       require.NoError(t, err)
+
+       child, err := db.WriteTree(&gitobj.Tree{Entries: []*gitobj.TreeEntry{
+               {
+                       Name:     "README.md",
+                       Oid:      []byte("00000000000000000000"),
+                       Filemode: 0100644,
+               },
+       }})
+
+       tree, err := New(db, &gitobj.Tree{Entries: []*gitobj.TreeEntry{
+               {
+                       Name:     ".gitattributes",
+                       Oid:      blob,
+                       Filemode: 0100644,
+               },
+               {
+                       Name:     "child",
+                       Oid:      child,
+                       Filemode: 040000,
+               },
+       }})
+       require.NoError(t, err)
+
+       assert.NotContains(t, tree.Children, "child")
+}
index 25f8c46..098aeb5 100644 (file)
@@ -11,35 +11,35 @@ import (
        "strings"
        "testing"
 
-       "github.com/git-lfs/git-lfs/git/odb"
+       "github.com/git-lfs/gitobj"
        "github.com/stretchr/testify/assert"
 )
 
-// DatabaseFromFixture returns a *git/odb.ObjectDatabase instance that is safely
+// DatabaseFromFixture returns a *gitobj.ObjectDatabase instance that is safely
 // mutable and created from a template equivelant to the fixture that you
 // provided it.
 //
 // If any error was encountered, it will call t.Fatalf() immediately.
-func DatabaseFromFixture(t *testing.T, name string) *odb.ObjectDatabase {
+func DatabaseFromFixture(t *testing.T, name string) *gitobj.ObjectDatabase {
        path, err := copyToTmp(filepath.Join("fixtures", name))
        if err != nil {
-               t.Fatalf("git/odb: could not copy fixture %s: %v", name, err)
+               t.Fatalf("gitobj: could not copy fixture %s: %v", name, err)
        }
 
-       db, err := odb.FromFilesystem(filepath.Join(path, "objects"), "")
+       db, err := gitobj.FromFilesystem(filepath.Join(path, "objects"), "")
        if err != nil {
-               t.Fatalf("git/odb: could not create object database: %v", err)
+               t.Fatalf("gitobj: could not create object database: %v", err)
        }
        return db
 }
 
 // AssertBlobContents asserts that the blob contents given by loading the path
 // starting from the root tree "tree" has the given "contents".
-func AssertBlobContents(t *testing.T, db *odb.ObjectDatabase, tree, path, contents string) {
+func AssertBlobContents(t *testing.T, db *gitobj.ObjectDatabase, tree, path, contents string) {
        // First, load the root tree.
        root, err := db.Tree(HexDecode(t, tree))
        if err != nil {
-               t.Fatalf("git/odb: cannot load tree: %s: %s", tree, err)
+               t.Fatalf("gitobj: cannot load tree: %s: %s", tree, err)
        }
 
        // Then, iterating through each part of the filepath (i.e., a/b/c.txt ->
@@ -49,7 +49,7 @@ func AssertBlobContents(t *testing.T, db *odb.ObjectDatabase, tree, path, conten
                part := parts[i]
 
                // Load the subtree given by that name.
-               var subtree *odb.Tree
+               var subtree *gitobj.Tree
                for _, entry := range root.Entries {
                        if entry.Name != part {
                                continue
@@ -57,13 +57,13 @@ func AssertBlobContents(t *testing.T, db *odb.ObjectDatabase, tree, path, conten
 
                        subtree, err = db.Tree(entry.Oid)
                        if err != nil {
-                               t.Fatalf("git/odb: cannot load subtree %s: %s", filepath.Join(parts[:i]...), err)
+                               t.Fatalf("gitobj: cannot load subtree %s: %s", filepath.Join(parts[:i]...), err)
                        }
                        break
                }
 
                if subtree == nil {
-                       t.Fatalf("git/odb: subtree %s does not exist", path)
+                       t.Fatalf("gitobj: subtree %s does not exist", path)
                }
 
                // And re-assign it to root, creating a sort of pseudo-recursion.
@@ -73,25 +73,25 @@ func AssertBlobContents(t *testing.T, db *odb.ObjectDatabase, tree, path, conten
        filename := parts[len(parts)-1]
 
        // Find the blob given by the last entry in parts (the filename).
-       var blob *odb.Blob
+       var blob *gitobj.Blob
        for _, entry := range root.Entries {
                if entry.Name == filename {
                        blob, err = db.Blob(entry.Oid)
                        if err != nil {
-                               t.Fatalf("git/odb: cannot load blob %x: %s", entry.Oid, err)
+                               t.Fatalf("gitobj: cannot load blob %x: %s", entry.Oid, err)
                        }
                }
        }
 
        // If we couldn't find the blob, fail immediately.
        if blob == nil {
-               t.Fatalf("git/odb: blob at %s in %s does not exist", path, tree)
+               t.Fatalf("gitobj: blob at %s in %s does not exist", path, tree)
        }
 
        // Perform an assertion on the blob's contents.
        got, err := ioutil.ReadAll(blob.Contents)
        if err != nil {
-               t.Fatalf("git/odb: cannot read contents from blob %s: %s", path, err)
+               t.Fatalf("gitobj: cannot read contents from blob %s: %s", path, err)
        }
 
        assert.Equal(t, contents, string(got))
@@ -99,41 +99,41 @@ func AssertBlobContents(t *testing.T, db *odb.ObjectDatabase, tree, path, conten
 
 // AssertCommitParent asserts that the given commit has a parent equivalent to
 // the one provided.
-func AssertCommitParent(t *testing.T, db *odb.ObjectDatabase, sha, parent string) {
+func AssertCommitParent(t *testing.T, db *gitobj.ObjectDatabase, sha, parent string) {
        commit, err := db.Commit(HexDecode(t, sha))
        if err != nil {
-               t.Fatalf("git/odb: expected to read commit: %s, couldn't: %v", sha, err)
+               t.Fatalf("gitobj: expected to read commit: %s, couldn't: %v", sha, err)
        }
 
        decoded, err := hex.DecodeString(parent)
        if err != nil {
-               t.Fatalf("git/odb: expected to decode parent SHA: %s, couldn't: %v", parent, err)
+               t.Fatalf("gitobj: expected to decode parent SHA: %s, couldn't: %v", parent, err)
        }
 
        assert.Contains(t, commit.ParentIDs, decoded,
-               "git/odb: expected parents of commit: %s to contain: %s", sha, parent)
+               "gitobj: expected parents of commit: %s to contain: %s", sha, parent)
 }
 
 // AssertCommitTree asserts that the given commit has a tree equivelant to the
 // one provided.
-func AssertCommitTree(t *testing.T, db *odb.ObjectDatabase, sha, tree string) {
+func AssertCommitTree(t *testing.T, db *gitobj.ObjectDatabase, sha, tree string) {
        commit, err := db.Commit(HexDecode(t, sha))
        if err != nil {
-               t.Fatalf("git/odb: expected to read commit: %s, couldn't: %v", sha, err)
+               t.Fatalf("gitobj: expected to read commit: %s, couldn't: %v", sha, err)
        }
 
        decoded, err := hex.DecodeString(tree)
        if err != nil {
-               t.Fatalf("git/odb: expected to decode tree SHA: %s, couldn't: %v", tree, err)
+               t.Fatalf("gitobj: expected to decode tree SHA: %s, couldn't: %v", tree, err)
        }
 
-       assert.Equal(t, decoded, commit.TreeID, "git/odb: expected tree ID: %s (got: %x)", tree, commit.TreeID)
+       assert.Equal(t, decoded, commit.TreeID, "gitobj: expected tree ID: %s (got: %x)", tree, commit.TreeID)
 }
 
 // AssertRef asserts that a given refname points at the expected commit.
-func AssertRef(t *testing.T, db *odb.ObjectDatabase, ref string, expected []byte) {
+func AssertRef(t *testing.T, db *gitobj.ObjectDatabase, ref string, expected []byte) {
        root, ok := db.Root()
-       assert.True(t, ok, "git/odb: expected *odb.ObjectDatabase to have Root()")
+       assert.True(t, ok, "gitobj: expected *odb.ObjectDatabase to have Root()")
 
        cmd := exec.Command("git", "rev-parse", ref)
        cmd.Dir = root
@@ -149,7 +149,7 @@ func AssertRef(t *testing.T, db *odb.ObjectDatabase, ref string, expected []byte
 func HexDecode(t *testing.T, sha string) []byte {
        b, err := hex.DecodeString(sha)
        if err != nil {
-               t.Fatalf("git/odb: could not decode string: %q, %v", sha, err)
+               t.Fatalf("gitobj: could not decode string: %q, %v", sha, err)
        }
 
        return b
index 02fee5d..44173ac 100644 (file)
@@ -7,9 +7,9 @@ import (
 
        "github.com/git-lfs/git-lfs/errors"
        "github.com/git-lfs/git-lfs/git"
-       "github.com/git-lfs/git-lfs/git/odb"
        "github.com/git-lfs/git-lfs/tasklog"
        "github.com/git-lfs/git-lfs/tools"
+       "github.com/git-lfs/gitobj"
 )
 
 // refUpdater is a type responsible for moving references from one point in the
@@ -27,7 +27,7 @@ type refUpdater struct {
        // located.
        Root string
 
-       db *odb.ObjectDatabase
+       db *gitobj.ObjectDatabase
 }
 
 // UpdateRefs performs the reference update(s) from existing locations (see:
@@ -57,7 +57,7 @@ func (r *refUpdater) UpdateRefs() error {
 
                if ref.Type == git.RefTypeLocalTag {
                        tag, _ := r.db.Tag(sha1)
-                       if tag != nil && tag.ObjectType == odb.CommitObjectType {
+                       if tag != nil && tag.ObjectType == gitobj.CommitObjectType {
                                // Assume that a non-nil error is an indication
                                // that the tag is bare (without annotation).
 
@@ -66,7 +66,7 @@ func (r *refUpdater) UpdateRefs() error {
                                        continue
                                }
 
-                               newTag, err := r.db.WriteTag(&odb.Tag{
+                               newTag, err := r.db.WriteTag(&gitobj.Tag{
                                        Object:     toObj,
                                        ObjectType: tag.ObjectType,
                                        Name:       tag.Name,
index b83cb2b..3810ec4 100644 (file)
@@ -4,14 +4,15 @@ import (
        "encoding/hex"
        "fmt"
        "io"
+       "os"
        "strings"
        "sync"
 
        "github.com/git-lfs/git-lfs/errors"
        "github.com/git-lfs/git-lfs/filepathfilter"
        "github.com/git-lfs/git-lfs/git"
-       "github.com/git-lfs/git-lfs/git/odb"
        "github.com/git-lfs/git-lfs/tasklog"
+       "github.com/git-lfs/gitobj"
 )
 
 // Rewriter allows rewriting topologically equivalent Git histories
@@ -22,7 +23,7 @@ type Rewriter struct {
        // entries is a mapping of old tree entries to new (rewritten) ones.
        // Since TreeEntry contains a []byte (and is therefore not a key-able
        // type), a unique TreeEntry -> string function is used for map keys.
-       entries map[string]*odb.TreeEntry
+       entries map[string]*gitobj.TreeEntry
        // commits is a mapping of old commit SHAs to new ones, where the ASCII
        // hex encoding of the SHA1 values are used as map keys.
        commits map[string][]byte
@@ -32,7 +33,7 @@ type Rewriter struct {
        filter *filepathfilter.Filter
        // db is the *ObjectDatabase from which blobs, commits, and trees are
        // loaded from.
-       db *odb.ObjectDatabase
+       db *gitobj.ObjectDatabase
        // l is the *tasklog.Logger to which updates are written.
        l *tasklog.Logger
 }
@@ -54,6 +55,10 @@ type RewriteOptions struct {
        // Verbose mode prints migrated objects.
        Verbose bool
 
+       // ObjectMapFilePath is the path to the map of old sha1 to new sha1
+       // commits
+       ObjectMapFilePath string
+
        // BlobFn specifies a function to rewrite blobs.
        //
        // It is called once per unique, unchanged path. That is to say, if
@@ -62,6 +67,10 @@ type RewriteOptions struct {
        // each blob for subsequent revisions, so long as each entry remains
        // unchanged.
        BlobFn BlobRewriteFn
+       // TreePreCallbackFn specifies a function to be called before opening a
+       // tree for rewriting. It will be called on all trees throughout history
+       // in topological ordering through the tree, starting at the root.
+       TreePreCallbackFn TreePreCallbackFn
        // TreeCallbackFn specifies a function to rewrite trees after they have
        // been reassembled by calling the above BlobFn on all existing tree
        // entries.
@@ -77,6 +86,15 @@ func (r *RewriteOptions) blobFn() BlobRewriteFn {
        return r.BlobFn
 }
 
+// treePreFn returns a useable TreePreCallbackFn, either the one that was given
+// in the *RewriteOptions, or a noopTreePreFn.
+func (r *RewriteOptions) treePreFn() TreePreCallbackFn {
+       if r.TreePreCallbackFn == nil {
+               return noopTreePreFn
+       }
+       return r.TreePreCallbackFn
+}
+
 // treeFn returns a useable TreeRewriteFn, either the one that was given in the
 // *RewriteOptions, or a noopTreeFn.
 func (r *RewriteOptions) treeFn() TreeCallbackFn {
@@ -91,7 +109,7 @@ func (r *RewriteOptions) treeFn() TreeCallbackFn {
 // and instead the error will be returned from the Rewrite() function.
 //
 // Invocations of an instance of BlobRewriteFn are not expected to store the
-// returned blobs in the *git/odb.ObjectDatabase.
+// returned blobs in the *git/gitobj.ObjectDatabase.
 //
 // The path argument is given to be an absolute path to the tree entry being
 // rewritten, where the repository root is the root of the path given. For
@@ -100,22 +118,33 @@ func (r *RewriteOptions) treeFn() TreeCallbackFn {
 //
 // As above, the path separators are OS specific, and equivalent to the result
 // of filepath.Join(...) or os.PathSeparator.
-type BlobRewriteFn func(path string, b *odb.Blob) (*odb.Blob, error)
+type BlobRewriteFn func(path string, b *gitobj.Blob) (*gitobj.Blob, error)
+
+// TreePreCallbackFn specifies a function to call upon opening a new tree for
+// rewriting.
+//
+// Unlike its sibling TreeCallbackFn, TreePreCallbackFn may not modify the given
+// tree.
+//
+// TreePreCallbackFn can be nil, and will therefore exhibit behavior equivalent
+// to only calling the BlobFn on existing tree entries.
+//
+// If the TreePreCallbackFn returns an error, it will be returned from the
+// Rewrite() invocation.
+type TreePreCallbackFn func(path string, t *gitobj.Tree) error
 
 // TreeCallbackFn specifies a function to call before writing a re-written tree
 // to the object database. The TreeCallbackFn can return a modified tree to be
 // written to the object database instead of one generated from calling BlobFn
 // on all of the tree entries.
 //
-// Trees returned from a TreeCallbackFn MUST have all objects referenced in the
-// entryset already written to the object database.
 //
 // TreeCallbackFn can be nil, and will therefore exhibit behavior equivalent to
 // only calling the BlobFn on existing tree entries.
 //
 // If the TreeCallbackFn returns an error, it will be returned from the
 // Rewrite() invocation.
-type TreeCallbackFn func(path string, t *odb.Tree) (*odb.Tree, error)
+type TreeCallbackFn func(path string, t *gitobj.Tree) (*gitobj.Tree, error)
 
 type rewriterOption func(*Rewriter)
 
@@ -145,17 +174,20 @@ var (
 
        // noopBlobFn is a no-op implementation of the BlobRewriteFn. It returns
        // the blob that it was given, and returns no error.
-       noopBlobFn = func(path string, b *odb.Blob) (*odb.Blob, error) { return b, nil }
+       noopBlobFn = func(path string, b *gitobj.Blob) (*gitobj.Blob, error) { return b, nil }
+       // noopTreePreFn is a no-op implementation of the TreePreRewriteFn. It
+       // returns the tree that it was given, and returns no error.
+       noopTreePreFn = func(path string, t *gitobj.Tree) error { return nil }
        // noopTreeFn is a no-op implementation of the TreeRewriteFn. It returns
        // the tree that it was given, and returns no error.
-       noopTreeFn = func(path string, t *odb.Tree) (*odb.Tree, error) { return t, nil }
+       noopTreeFn = func(path string, t *gitobj.Tree) (*gitobj.Tree, error) { return t, nil }
 )
 
 // NewRewriter constructs a *Rewriter from the given *ObjectDatabase instance.
-func NewRewriter(db *odb.ObjectDatabase, opts ...rewriterOption) *Rewriter {
+func NewRewriter(db *gitobj.ObjectDatabase, opts ...rewriterOption) *Rewriter {
        rewriter := &Rewriter{
                mu:      new(sync.Mutex),
-               entries: make(map[string]*odb.TreeEntry),
+               entries: make(map[string]*gitobj.TreeEntry),
                commits: make(map[string][]byte),
 
                db: db,
@@ -188,6 +220,15 @@ func (r *Rewriter) Rewrite(opt *RewriteOptions) ([]byte, error) {
                vPerc = perc
        }
 
+       var objectMapFile *os.File
+       if len(opt.ObjectMapFilePath) > 0 {
+               objectMapFile, err = os.OpenFile(opt.ObjectMapFilePath, os.O_RDWR|os.O_CREATE|os.O_EXCL, 0666)
+               if err != nil {
+                       return nil, fmt.Errorf("Could not create object map file: %v", err)
+               }
+               defer objectMapFile.Close()
+       }
+
        // Keep track of the last commit that we rewrote. Callers often want
        // this so that they can perform a git-update-ref(1).
        var tip []byte
@@ -200,7 +241,7 @@ func (r *Rewriter) Rewrite(opt *RewriteOptions) ([]byte, error) {
                }
 
                // Rewrite the tree given at that commit.
-               rewrittenTree, err := r.rewriteTree(oid, original.TreeID, "", opt.blobFn(), opt.treeFn(), vPerc)
+               rewrittenTree, err := r.rewriteTree(oid, original.TreeID, "", opt.blobFn(), opt.treePreFn(), opt.treeFn(), vPerc)
                if err != nil {
                        return nil, err
                }
@@ -233,7 +274,7 @@ func (r *Rewriter) Rewrite(opt *RewriteOptions) ([]byte, error) {
 
                // Construct a new commit using the original header information,
                // but the rewritten set of parents as well as root tree.
-               rewrittenCommit := &odb.Commit{
+               rewrittenCommit := &gitobj.Commit{
                        Author:       original.Author,
                        Committer:    original.Committer,
                        ExtraHeaders: original.ExtraHeaders,
@@ -253,6 +294,11 @@ func (r *Rewriter) Rewrite(opt *RewriteOptions) ([]byte, error) {
                        if err != nil {
                                return nil, err
                        }
+                       if objectMapFile != nil {
+                               if _, err := fmt.Fprintf(objectMapFile, "%x,%x\n", oid, newSha); err != nil {
+                                       return nil, err
+                               }
+                       }
                }
 
                // Cache that commit so that we can reassign children of this
@@ -302,13 +348,20 @@ func (r *Rewriter) Rewrite(opt *RewriteOptions) ([]byte, error) {
 //
 // It returns the new SHA of the rewritten tree, or an error if the tree was
 // unable to be rewritten.
-func (r *Rewriter) rewriteTree(commitOID []byte, treeOID []byte, path string, fn BlobRewriteFn, tfn TreeCallbackFn, perc *tasklog.PercentageTask) ([]byte, error) {
+func (r *Rewriter) rewriteTree(commitOID []byte, treeOID []byte, path string,
+       fn BlobRewriteFn, tpfn TreePreCallbackFn, tfn TreeCallbackFn,
+       perc *tasklog.PercentageTask) ([]byte, error) {
+
        tree, err := r.db.Tree(treeOID)
        if err != nil {
                return nil, err
        }
 
-       entries := make([]*odb.TreeEntry, 0, len(tree.Entries))
+       if err := tpfn("/"+path, tree); err != nil {
+               return nil, err
+       }
+
+       entries := make([]*gitobj.TreeEntry, 0, len(tree.Entries))
        for _, entry := range tree.Entries {
                var fullpath string
                if len(path) > 0 {
@@ -336,10 +389,10 @@ func (r *Rewriter) rewriteTree(commitOID []byte, treeOID []byte, path string, fn
                var oid []byte
 
                switch entry.Type() {
-               case odb.BlobObjectType:
+               case gitobj.BlobObjectType:
                        oid, err = r.rewriteBlob(commitOID, entry.Oid, fullpath, fn, perc)
-               case odb.TreeObjectType:
-                       oid, err = r.rewriteTree(commitOID, entry.Oid, fullpath, fn, tfn, perc)
+               case gitobj.TreeObjectType:
+                       oid, err = r.rewriteTree(commitOID, entry.Oid, fullpath, fn, tpfn, tfn, perc)
                default:
                        oid = entry.Oid
 
@@ -348,14 +401,14 @@ func (r *Rewriter) rewriteTree(commitOID []byte, treeOID []byte, path string, fn
                        return nil, err
                }
 
-               entries = append(entries, r.cacheEntry(entry, &odb.TreeEntry{
+               entries = append(entries, r.cacheEntry(entry, &gitobj.TreeEntry{
                        Filemode: entry.Filemode,
                        Name:     entry.Name,
                        Oid:      oid,
                }))
        }
 
-       rewritten, err := tfn("/"+path, &odb.Tree{Entries: entries})
+       rewritten, err := tfn("/"+path, &gitobj.Tree{Entries: entries})
        if err != nil {
                return nil, err
        }
@@ -366,7 +419,7 @@ func (r *Rewriter) rewriteTree(commitOID []byte, treeOID []byte, path string, fn
        return r.db.WriteTree(rewritten)
 }
 
-func copyEntry(e *odb.TreeEntry) *odb.TreeEntry {
+func copyEntry(e *gitobj.TreeEntry) *gitobj.TreeEntry {
        if e == nil {
                return nil
        }
@@ -374,18 +427,18 @@ func copyEntry(e *odb.TreeEntry) *odb.TreeEntry {
        oid := make([]byte, len(e.Oid))
        copy(oid, e.Oid)
 
-       return &odb.TreeEntry{
+       return &gitobj.TreeEntry{
                Filemode: e.Filemode,
                Name:     e.Name,
                Oid:      oid,
        }
 }
 
-func (r *Rewriter) allows(typ odb.ObjectType, abs string) bool {
+func (r *Rewriter) allows(typ gitobj.ObjectType, abs string) bool {
        switch typ {
-       case odb.BlobObjectType:
+       case gitobj.BlobObjectType:
                return r.Filter().Allows(strings.TrimPrefix(abs, "/"))
-       case odb.CommitObjectType, odb.TreeObjectType:
+       case gitobj.CommitObjectType, gitobj.TreeObjectType:
                return true
        default:
                panic(fmt.Sprintf("git/githistory: unknown entry type: %s", typ))
@@ -527,7 +580,7 @@ func (r *Rewriter) Filter() *filepathfilter.Filter {
 
 // cacheEntry caches then given "from" entry so that it is always rewritten as
 // a *TreeEntry equivalent to "to".
-func (r *Rewriter) cacheEntry(from, to *odb.TreeEntry) *odb.TreeEntry {
+func (r *Rewriter) cacheEntry(from, to *gitobj.TreeEntry) *gitobj.TreeEntry {
        r.mu.Lock()
        defer r.mu.Unlock()
 
@@ -539,7 +592,7 @@ func (r *Rewriter) cacheEntry(from, to *odb.TreeEntry) *odb.TreeEntry {
 // uncacheEntry returns a *TreeEntry that is cached from the given *TreeEntry
 // "from". That is to say, it returns the *TreeEntry that "from" should be
 // rewritten to, or nil if none could be found.
-func (r *Rewriter) uncacheEntry(from *odb.TreeEntry) *odb.TreeEntry {
+func (r *Rewriter) uncacheEntry(from *gitobj.TreeEntry) *gitobj.TreeEntry {
        r.mu.Lock()
        defer r.mu.Unlock()
 
@@ -547,12 +600,12 @@ func (r *Rewriter) uncacheEntry(from *odb.TreeEntry) *odb.TreeEntry {
 }
 
 // entryKey returns a unique key for a given *TreeEntry "e".
-func (r *Rewriter) entryKey(e *odb.TreeEntry) string {
+func (r *Rewriter) entryKey(e *gitobj.TreeEntry) string {
        return fmt.Sprintf("%s:%x", e.Name, e.Oid)
 }
 
 // cacheEntry caches then given "from" commit so that it is always rewritten as
-// a *git/odb.Commit equivalent to "to".
+// a *git/gitobj.Commit equivalent to "to".
 func (r *Rewriter) cacheCommit(from, to []byte) {
        r.mu.Lock()
        defer r.mu.Unlock()
@@ -560,8 +613,8 @@ func (r *Rewriter) cacheCommit(from, to []byte) {
        r.commits[hex.EncodeToString(from)] = to
 }
 
-// uncacheCommit returns a *git/odb.Commit that is cached from the given
-// *git/odb.Commit "from". That is to say, it returns the *git/odb.Commit that
+// uncacheCommit returns a *git/gitobj.Commit that is cached from the given
+// *git/gitobj.Commit "from". That is to say, it returns the *git/gitobj.Commit that
 // "from" should be rewritten to and true, or nil and false if none could be
 // found.
 func (r *Rewriter) uncacheCommit(from []byte) ([]byte, bool) {
index 0d570ba..8c3d893 100644 (file)
@@ -3,7 +3,6 @@ package githistory
 import (
        "bytes"
        "encoding/hex"
-       "fmt"
        "io"
        "io/ioutil"
        "reflect"
@@ -11,8 +10,9 @@ import (
        "strings"
        "testing"
 
+       "github.com/git-lfs/git-lfs/errors"
        "github.com/git-lfs/git-lfs/filepathfilter"
-       "github.com/git-lfs/git-lfs/git/odb"
+       "github.com/git-lfs/gitobj"
        "github.com/stretchr/testify/assert"
 )
 
@@ -21,7 +21,7 @@ func TestRewriterRewritesHistory(t *testing.T) {
        r := NewRewriter(db)
 
        tip, err := r.Rewrite(&RewriteOptions{Include: []string{"refs/heads/master"},
-               BlobFn: func(path string, b *odb.Blob) (*odb.Blob, error) {
+               BlobFn: func(path string, b *gitobj.Blob) (*gitobj.Blob, error) {
                        contents, err := ioutil.ReadAll(b.Contents)
                        if err != nil {
                                return nil, err
@@ -34,7 +34,7 @@ func TestRewriterRewritesHistory(t *testing.T) {
 
                        rewritten := strconv.Itoa(n + 1)
 
-                       return &odb.Blob{
+                       return &gitobj.Blob{
                                Contents: strings.NewReader(rewritten),
                                Size:     int64(len(rewritten)),
                        }, nil
@@ -61,8 +61,8 @@ func TestRewriterRewritesHistory(t *testing.T) {
        //
        //   100644 blob e440e5c842586965a7fb77deda2eca68612b1f53   hello.txt
 
-       AssertCommitParent(t, db, hex.EncodeToString(tip), "911994ab82ce256433c1fa739dbbbc7142156289")
-       AssertCommitTree(t, db, "911994ab82ce256433c1fa739dbbbc7142156289", tree2)
+       AssertCommitParent(t, db, hex.EncodeToString(tip), "4aaa3f49ffeabbb874250fe13ffeb8c683aba650")
+       AssertCommitTree(t, db, "4aaa3f49ffeabbb874250fe13ffeb8c683aba650", tree2)
 
        AssertBlobContents(t, db, tree2, "hello.txt", "3")
 
@@ -71,8 +71,8 @@ func TestRewriterRewritesHistory(t *testing.T) {
        //
        //   100644 blob d8263ee9860594d2806b0dfd1bfd17528b0ba2a4   hello.txt
 
-       AssertCommitParent(t, db, "911994ab82ce256433c1fa739dbbbc7142156289", "38679ebeba3403103196eb6272b326f96c928ace")
-       AssertCommitTree(t, db, "38679ebeba3403103196eb6272b326f96c928ace", tree3)
+       AssertCommitParent(t, db, "4aaa3f49ffeabbb874250fe13ffeb8c683aba650", "24a341e1ff75addc22e336a8d87f82ba56b86fcf")
+       AssertCommitTree(t, db, "24a341e1ff75addc22e336a8d87f82ba56b86fcf", tree3)
 
        AssertBlobContents(t, db, tree3, "hello.txt", "2")
 }
@@ -82,8 +82,8 @@ func TestRewriterRewritesOctopusMerges(t *testing.T) {
        r := NewRewriter(db)
 
        tip, err := r.Rewrite(&RewriteOptions{Include: []string{"refs/heads/master"},
-               BlobFn: func(path string, b *odb.Blob) (*odb.Blob, error) {
-                       return &odb.Blob{
+               BlobFn: func(path string, b *gitobj.Blob) (*gitobj.Blob, error) {
+                       return &gitobj.Blob{
                                Contents: io.MultiReader(b.Contents, strings.NewReader("_new")),
                                Size:     b.Size + int64(len("_new")),
                        }, nil
@@ -112,14 +112,14 @@ func TestRewriterRewritesOctopusMerges(t *testing.T) {
        //   parent 1fe2b9577d5610e8d8fb2c3030534036fb648393
        //   parent ca447959bdcd20253d69b227bcc7c2e1d3126d5c
 
-       AssertCommitParent(t, db, hex.EncodeToString(tip), "89ab88fb7e11a439299aa2aa77a5d98f6629b750")
-       AssertCommitParent(t, db, hex.EncodeToString(tip), "adf1e9085f9dd263c1bec399b995ccfa5d994721")
+       AssertCommitParent(t, db, hex.EncodeToString(tip), "1fe2b9577d5610e8d8fb2c3030534036fb648393")
+       AssertCommitParent(t, db, hex.EncodeToString(tip), "ca447959bdcd20253d69b227bcc7c2e1d3126d5c")
 
        // And each of those parents should contain the root commit as their own
        // parent:
 
-       AssertCommitParent(t, db, "89ab88fb7e11a439299aa2aa77a5d98f6629b750", "52daca68bcf750bb86289fd95f92f5b3bd202328")
-       AssertCommitParent(t, db, "adf1e9085f9dd263c1bec399b995ccfa5d994721", "52daca68bcf750bb86289fd95f92f5b3bd202328")
+       AssertCommitParent(t, db, "1fe2b9577d5610e8d8fb2c3030534036fb648393", "9237567f379b3c83ddf53ad9a2ae3755afb62a09")
+       AssertCommitParent(t, db, "ca447959bdcd20253d69b227bcc7c2e1d3126d5c", "9237567f379b3c83ddf53ad9a2ae3755afb62a09")
 }
 
 func TestRewriterVisitsPackedObjects(t *testing.T) {
@@ -129,7 +129,7 @@ func TestRewriterVisitsPackedObjects(t *testing.T) {
        var contents []byte
 
        _, err := r.Rewrite(&RewriteOptions{Include: []string{"refs/heads/master"},
-               BlobFn: func(path string, b *odb.Blob) (*odb.Blob, error) {
+               BlobFn: func(path string, b *gitobj.Blob) (*gitobj.Blob, error) {
                        var err error
 
                        contents, err = ioutil.ReadAll(b.Contents)
@@ -137,7 +137,7 @@ func TestRewriterVisitsPackedObjects(t *testing.T) {
                                return nil, err
                        }
 
-                       return &odb.Blob{
+                       return &gitobj.Blob{
                                Contents: bytes.NewReader(contents),
                                Size:     int64(len(contents)),
                        }, nil
@@ -155,7 +155,7 @@ func TestRewriterDoesntVisitUnchangedSubtrees(t *testing.T) {
        seen := make(map[string]int)
 
        _, err := r.Rewrite(&RewriteOptions{Include: []string{"refs/heads/master"},
-               BlobFn: func(path string, b *odb.Blob) (*odb.Blob, error) {
+               BlobFn: func(path string, b *gitobj.Blob) (*gitobj.Blob, error) {
                        seen[path] = seen[path] + 1
 
                        return b, nil
@@ -173,12 +173,12 @@ func TestRewriterVisitsUniqueEntriesWithIdenticalContents(t *testing.T) {
        r := NewRewriter(db)
 
        tip, err := r.Rewrite(&RewriteOptions{Include: []string{"refs/heads/master"},
-               BlobFn: func(path string, b *odb.Blob) (*odb.Blob, error) {
+               BlobFn: func(path string, b *gitobj.Blob) (*gitobj.Blob, error) {
                        if path == "b.txt" {
                                return b, nil
                        }
 
-                       return &odb.Blob{
+                       return &gitobj.Blob{
                                Contents: strings.NewReader("changed"),
                                Size:     int64(len("changed")),
                        }, nil
@@ -189,10 +189,6 @@ func TestRewriterVisitsUniqueEntriesWithIdenticalContents(t *testing.T) {
 
        tree := "bbbe0a7676523ae02234bfe874784ca2380c2d4b"
 
-       fmt.Println(hex.EncodeToString(tip))
-       root, _ := db.Root()
-       fmt.Println(root)
-
        AssertCommitTree(t, db, hex.EncodeToString(tip), tree)
 
        // After rewriting, the HEAD state of the repository should contain a
@@ -217,7 +213,7 @@ func TestRewriterIgnoresPathsThatDontMatchFilter(t *testing.T) {
        seen := make(map[string]int)
 
        _, err := r.Rewrite(&RewriteOptions{Include: []string{"refs/heads/master"},
-               BlobFn: func(path string, b *odb.Blob) (*odb.Blob, error) {
+               BlobFn: func(path string, b *gitobj.Blob) (*gitobj.Blob, error) {
                        seen[path] = seen[path] + 1
 
                        return b, nil
@@ -233,20 +229,20 @@ func TestRewriterAllowsAdditionalTreeEntries(t *testing.T) {
        db := DatabaseFromFixture(t, "linear-history.git")
        r := NewRewriter(db)
 
-       extra, err := db.WriteBlob(&odb.Blob{
+       extra, err := db.WriteBlob(&gitobj.Blob{
                Contents: strings.NewReader("extra\n"),
                Size:     int64(len("extra\n")),
        })
        assert.Nil(t, err)
 
        tip, err := r.Rewrite(&RewriteOptions{Include: []string{"refs/heads/master"},
-               BlobFn: func(path string, b *odb.Blob) (*odb.Blob, error) {
+               BlobFn: func(path string, b *gitobj.Blob) (*gitobj.Blob, error) {
                        return b, nil
                },
 
-               TreeCallbackFn: func(path string, tr *odb.Tree) (*odb.Tree, error) {
-                       return &odb.Tree{
-                               Entries: append(tr.Entries, &odb.TreeEntry{
+               TreeCallbackFn: func(path string, tr *gitobj.Tree) (*gitobj.Tree, error) {
+                       return &gitobj.Tree{
+                               Entries: append(tr.Entries, &gitobj.TreeEntry{
                                        Name:     "extra.txt",
                                        Filemode: 0100644,
                                        Oid:      extra,
@@ -278,8 +274,8 @@ func TestRewriterAllowsAdditionalTreeEntries(t *testing.T) {
        //   100644 blob d8263ee9860594d2806b0dfd1bfd17528b0ba2a4    hello.txt
        //   100644 blob 0f2287157f7cb0dd40498c7a92f74b6975fa2d57    extra.txt
 
-       AssertCommitParent(t, db, hex.EncodeToString(tip), "54ca0fdd5ee455d872ce4b4e379abe1c4cdc39b3")
-       AssertCommitTree(t, db, "54ca0fdd5ee455d872ce4b4e379abe1c4cdc39b3", tree2)
+       AssertCommitParent(t, db, hex.EncodeToString(tip), "45af5deb9a25bc4069b15c1f5bdccb0340978707")
+       AssertCommitTree(t, db, "45af5deb9a25bc4069b15c1f5bdccb0340978707", tree2)
 
        AssertBlobContents(t, db, tree2, "hello.txt", "2")
        AssertBlobContents(t, db, tree2, "extra.txt", "extra\n")
@@ -290,13 +286,116 @@ func TestRewriterAllowsAdditionalTreeEntries(t *testing.T) {
        //   100644 blob 56a6051ca2b02b04ef92d5150c9ef600403cb1de    hello.txt
        //   100644 blob 0f2287157f7cb0dd40498c7a92f74b6975fa2d57    extra.txt
 
-       AssertCommitParent(t, db, "54ca0fdd5ee455d872ce4b4e379abe1c4cdc39b3", "4c52196256c611d18ad718b9b68b3d54d0a6686d")
-       AssertCommitTree(t, db, "4c52196256c611d18ad718b9b68b3d54d0a6686d", tree3)
+       AssertCommitParent(t, db, "45af5deb9a25bc4069b15c1f5bdccb0340978707", "99f6bd7cd69b45494afed95b026f3e450de8304f")
+       AssertCommitTree(t, db, "99f6bd7cd69b45494afed95b026f3e450de8304f", tree3)
 
        AssertBlobContents(t, db, tree3, "hello.txt", "1")
        AssertBlobContents(t, db, tree3, "extra.txt", "extra\n")
 }
 
+// CallbackCall is a structure recording information pertinent to when a
+// *githistory.Rewrite called either BlobFn, TreePreCallbackFn, or
+// TreeCallbackFn.
+type CallbackCall struct {
+       Type string
+       Path string
+}
+
+var (
+       // collectCalls is a function that returns a *RewriteOptions that
+       // updates a pointer to a slice of `*CallbackCall`'s with each call that
+       // is received.
+       collectCalls = func(calls *[]*CallbackCall) *RewriteOptions {
+               return &RewriteOptions{Include: []string{"refs/heads/master"},
+                       BlobFn: func(path string, b *gitobj.Blob) (*gitobj.Blob, error) {
+                               *calls = append(*calls, &CallbackCall{
+                                       Type: "blob",
+                                       Path: path,
+                               })
+                               return b, nil
+                       },
+
+                       TreePreCallbackFn: func(path string, t *gitobj.Tree) error {
+                               *calls = append(*calls, &CallbackCall{
+                                       Type: "tree-pre",
+                                       Path: path,
+                               })
+                               return nil
+                       },
+
+                       TreeCallbackFn: func(path string, t *gitobj.Tree) (*gitobj.Tree, error) {
+                               *calls = append(*calls, &CallbackCall{
+                                       Type: "tree-post",
+                                       Path: path,
+                               })
+                               return t, nil
+                       },
+               }
+       }
+)
+
+func TestHistoryRewriterCallbacks(t *testing.T) {
+       var calls []*CallbackCall
+
+       db := DatabaseFromFixture(t, "linear-history.git")
+       r := NewRewriter(db)
+
+       _, err := r.Rewrite(collectCalls(&calls))
+
+       assert.Nil(t, err)
+
+       assert.Len(t, calls, 9)
+       assert.Equal(t, calls[0], &CallbackCall{Type: "tree-pre", Path: "/"})
+       assert.Equal(t, calls[1], &CallbackCall{Type: "blob", Path: "hello.txt"})
+       assert.Equal(t, calls[2], &CallbackCall{Type: "tree-post", Path: "/"})
+       assert.Equal(t, calls[3], &CallbackCall{Type: "tree-pre", Path: "/"})
+       assert.Equal(t, calls[4], &CallbackCall{Type: "blob", Path: "hello.txt"})
+       assert.Equal(t, calls[5], &CallbackCall{Type: "tree-post", Path: "/"})
+       assert.Equal(t, calls[6], &CallbackCall{Type: "tree-pre", Path: "/"})
+       assert.Equal(t, calls[7], &CallbackCall{Type: "blob", Path: "hello.txt"})
+       assert.Equal(t, calls[8], &CallbackCall{Type: "tree-post", Path: "/"})
+}
+
+func TestHistoryRewriterCallbacksSubtrees(t *testing.T) {
+       var calls []*CallbackCall
+
+       db := DatabaseFromFixture(t, "non-repeated-subtrees.git")
+       r := NewRewriter(db)
+
+       _, err := r.Rewrite(collectCalls(&calls))
+
+       assert.Nil(t, err)
+
+       assert.Len(t, calls, 8)
+       assert.Equal(t, calls[0], &CallbackCall{Type: "tree-pre", Path: "/"})
+       assert.Equal(t, calls[1], &CallbackCall{Type: "blob", Path: "a.txt"})
+       assert.Equal(t, calls[2], &CallbackCall{Type: "tree-post", Path: "/"})
+       assert.Equal(t, calls[3], &CallbackCall{Type: "tree-pre", Path: "/"})
+       assert.Equal(t, calls[4], &CallbackCall{Type: "tree-pre", Path: "/subdir"})
+       assert.Equal(t, calls[5], &CallbackCall{Type: "blob", Path: "subdir/b.txt"})
+       assert.Equal(t, calls[6], &CallbackCall{Type: "tree-post", Path: "/subdir"})
+       assert.Equal(t, calls[7], &CallbackCall{Type: "tree-post", Path: "/"})
+}
+
+func TestHistoryRewriterTreePreCallbackPropagatesErrors(t *testing.T) {
+       expected := errors.Errorf("my error")
+
+       db := DatabaseFromFixture(t, "linear-history.git")
+       r := NewRewriter(db)
+
+       _, err := r.Rewrite(&RewriteOptions{Include: []string{"refs/heads/master"},
+               BlobFn: func(path string, b *gitobj.Blob) (*gitobj.Blob, error) {
+                       return b, nil
+               },
+
+               TreePreCallbackFn: func(path string, t *gitobj.Tree) error {
+                       return expected
+               },
+       })
+
+       assert.Equal(t, err, expected)
+}
+
 func TestHistoryRewriterUseOriginalParentsForPartialMigration(t *testing.T) {
        db := DatabaseFromFixture(t, "linear-history-with-tags.git")
        r := NewRewriter(db)
@@ -305,7 +404,7 @@ func TestHistoryRewriterUseOriginalParentsForPartialMigration(t *testing.T) {
                Include: []string{"refs/heads/master"},
                Exclude: []string{"refs/tags/middle"},
 
-               BlobFn: func(path string, b *odb.Blob) (*odb.Blob, error) {
+               BlobFn: func(path string, b *gitobj.Blob) (*gitobj.Blob, error) {
                        return b, nil
                },
        })
@@ -342,10 +441,10 @@ func TestHistoryRewriterUpdatesRefs(t *testing.T) {
 
                UpdateRefs: true,
 
-               BlobFn: func(path string, b *odb.Blob) (*odb.Blob, error) {
+               BlobFn: func(path string, b *gitobj.Blob) (*gitobj.Blob, error) {
                        suffix := strings.NewReader("_suffix")
 
-                       return &odb.Blob{
+                       return &gitobj.Blob{
                                Contents: io.MultiReader(b.Contents, suffix),
                                Size:     b.Size + int64(suffix.Len()),
                        }, nil
@@ -355,8 +454,8 @@ func TestHistoryRewriterUpdatesRefs(t *testing.T) {
        assert.Nil(t, err)
 
        c1 := hex.EncodeToString(tip)
-       c2 := "86f7ba8f02edaca4f980cdd584ea8899e18b840c"
-       c3 := "d73b8c1a294e2371b287d9b75dbed82328ad446e"
+       c2 := "66561fe3ae68651658e18e48053dcfe66a2e9da1"
+       c3 := "8268d8486c48024a871fa42fc487dbeabd6e3d86"
 
        AssertRef(t, db, "refs/heads/master", tip)
 
@@ -374,3 +473,18 @@ func TestHistoryRewriterReturnsFilter(t *testing.T) {
        assert.Equal(t, expected, got,
                "git/githistory: expected Rewriter.Filter() to return same *filepathfilter.Filter instance")
 }
+
+// debug is meant to be called from a defer statement to aide in debugging a
+// test failure among any in this file.
+//
+// Callers are expected to call it immediately after calling the Rewrite()
+// function.
+func debug(t *testing.T, db *gitobj.ObjectDatabase, tip []byte, err error) {
+       root, ok := db.Root()
+
+       t.Log(strings.Repeat("*", 80))
+       t.Logf("* root=%s, ok=%t\n", root, ok)
+       t.Logf("* tip=%x\n", tip)
+       t.Logf("* err=%s\n", err)
+       t.Log(strings.Repeat("*", 80))
+}
index b823f1e..2c77d20 100644 (file)
@@ -1,5 +1,5 @@
-hash: 5d2fbd8be4931b982d29c6ac8df833f139b28ffdb44ca062948a2386e2096a4d
-updated: 2018-05-28T18:35:44.591993-07:00
+hash: a39eef1817877f30955e685f12d3d610f277c5f6abc0756f6bab6944dc27c4dd
+updated: 2018-07-06T12:09:00.254181079-05:00
 imports:
 - name: github.com/alexbrainman/sspi
   version: 4729b3d4d8581b2db83864d1018926e4154f9406
@@ -9,12 +9,16 @@ imports:
   version: 5215b55f46b2b919f50a1df0eaa5886afe4e3b3d
   subpackages:
   - spew
+- name: github.com/git-lfs/gitobj
+  version: 0fcb9c3796fa00bd974c86dc25b1919da1479007
+  subpackages:
+  - pack
 - name: github.com/git-lfs/go-netrc
   version: e0e9ca483a183481412e6f5a700ff20a36177503
   subpackages:
   - netrc
 - name: github.com/git-lfs/wildmatch
-  version: 8a0518641565a619e62a2738c7d4498fc345daf6
+  version: b31c34466d64fcd421b503261f815a303e74296e
 - name: github.com/inconshreveable/mousetrap
   version: 76626ae9c91c4f2a10f34cad8ce83ea42c93bb75
 - name: github.com/kr/pty
index 5e7758d..19f5a61 100644 (file)
@@ -27,8 +27,10 @@ import:
 - package: github.com/pkg/errors
   version: c605e284fe17294bda444b34710735b29d1a9d90
 - package: github.com/git-lfs/wildmatch
-  version: 8a0518641565a619e62a2738c7d4498fc345daf6
+  version: b31c34466d64fcd421b503261f815a303e74296e
 - package: github.com/alexbrainman/sspi
   version: 4729b3d4d8581b2db83864d1018926e4154f9406
   subpackages:
   - ntlm
+- package: github.com/git-lfs/gitobj
+  version: 0fcb9c3796fa00bd974c86dc25b1919da1479007
index 0d1c0d1..b6dc99f 100644 (file)
@@ -16,6 +16,18 @@ import (
 
 func (f *GitFilter) SmudgeToFile(filename string, ptr *Pointer, download bool, manifest *tq.Manifest, cb tools.CopyCallback) error {
        os.MkdirAll(filepath.Dir(filename), 0755)
+
+       if stat, _ := os.Stat(filename); stat != nil && stat.Mode()&0200 == 0 {
+               if err := os.Chmod(filename, stat.Mode()|0200); err != nil {
+                       return errors.Wrap(err,
+                               "Could not restore write permission")
+               }
+
+               // When we're done, return the file back to its normal
+               // permission bits.
+               defer os.Chmod(filename, stat.Mode())
+       }
+
        file, err := os.Create(filename)
        if err != nil {
                return fmt.Errorf("Could not create working directory file: %v", err)
index 15a6d58..3d0763a 100644 (file)
@@ -89,7 +89,20 @@ func (s *GitScanner) ScanLeftToRemote(left string, cb GitScannerFoundPointer) er
        }
        s.mu.Unlock()
 
-       return scanRefsToChan(s, callback, left, "", s.opts(ScanLeftToRemoteMode))
+       return scanLeftRightToChan(s, callback, left, "", s.opts(ScanLeftToRemoteMode))
+}
+
+// ScanRefs through all commits reachable by refs contained in "include" and
+// not reachable by any refs included in "excluded"
+func (s *GitScanner) ScanRefs(include, exclude []string, cb GitScannerFoundPointer) error {
+       callback, err := firstGitScannerCallback(cb, s.FoundPointer)
+       if err != nil {
+               return err
+       }
+
+       opts := s.opts(ScanRefsMode)
+       opts.SkipDeletedBlobs = false
+       return scanRefsToChan(s, callback, include, exclude, opts)
 }
 
 // ScanRefRange scans through all commits from the given left and right refs,
@@ -102,7 +115,7 @@ func (s *GitScanner) ScanRefRange(left, right string, cb GitScannerFoundPointer)
 
        opts := s.opts(ScanRefsMode)
        opts.SkipDeletedBlobs = false
-       return scanRefsToChan(s, callback, left, right, opts)
+       return scanLeftRightToChan(s, callback, left, right, opts)
 }
 
 // ScanRefWithDeleted scans through all objects in the given ref, including
@@ -121,7 +134,7 @@ func (s *GitScanner) ScanRef(ref string, cb GitScannerFoundPointer) error {
 
        opts := s.opts(ScanRefsMode)
        opts.SkipDeletedBlobs = true
-       return scanRefsToChan(s, callback, ref, "", opts)
+       return scanLeftRightToChan(s, callback, ref, "", opts)
 }
 
 // ScanAll scans through all objects in the git repository.
@@ -133,7 +146,7 @@ func (s *GitScanner) ScanAll(cb GitScannerFoundPointer) error {
 
        opts := s.opts(ScanAllMode)
        opts.SkipDeletedBlobs = false
-       return scanRefsToChan(s, callback, "", "", opts)
+       return scanLeftRightToChan(s, callback, "", "", opts)
 }
 
 // ScanTree takes a ref and returns WrappedPointer objects in the tree at that
index e66daee..f4619e0 100644 (file)
@@ -33,15 +33,16 @@ func (s *lockableNameSet) Check(blobSha string) (string, bool) {
 
 func noopFoundLockable(name string) {}
 
-// scanRefsToChan takes a ref and returns a channel of WrappedPointer objects
-// for all Git LFS pointers it finds for that ref.
+// scanRefsToChan scans through all commits reachable by refs contained in
+// "include" and not reachable by any refs included in "excluded" and returns
+// a channel of WrappedPointer objects for all Git LFS pointers it finds.
 // Reports unique oids once only, not multiple times if >1 file uses the same content
-func scanRefsToChan(scanner *GitScanner, pointerCb GitScannerFoundPointer, refLeft, refRight string, opt *ScanRefsOptions) error {
+func scanRefsToChan(scanner *GitScanner, pointerCb GitScannerFoundPointer, include, exclude []string, opt *ScanRefsOptions) error {
        if opt == nil {
                panic("no scan ref options")
        }
 
-       revs, err := revListShas([]string{refLeft, refRight}, nil, opt)
+       revs, err := revListShas(include, exclude, opt)
        if err != nil {
                return err
        }
@@ -91,6 +92,13 @@ func scanRefsToChan(scanner *GitScanner, pointerCb GitScannerFoundPointer, refLe
        return nil
 }
 
+// scanLeftRightToChan takes a ref and returns a channel of WrappedPointer objects
+// for all Git LFS pointers it finds for that ref.
+// Reports unique oids once only, not multiple times if >1 file uses the same content
+func scanLeftRightToChan(scanner *GitScanner, pointerCb GitScannerFoundPointer, refLeft, refRight string, opt *ScanRefsOptions) error {
+       return scanRefsToChan(scanner, pointerCb, []string{refLeft, refRight}, nil, opt)
+}
+
 // revListShas uses git rev-list to return the list of object sha1s
 // for the given ref. If all is true, ref is ignored. It returns a
 // channel from which sha1 strings can be read.
index eae67ca..9b4b43d 100644 (file)
@@ -35,12 +35,14 @@ func Environ(cfg *config.Configuration, manifest *tq.Manifest) []string {
 
        fetchPruneConfig := NewFetchPruneConfig(cfg.Git)
 
+       references := strings.Join(cfg.LocalReferenceDirs(), ", ")
+
        env = append(env,
                fmt.Sprintf("LocalWorkingDir=%s", cfg.LocalWorkingDir()),
                fmt.Sprintf("LocalGitDir=%s", cfg.LocalGitDir()),
                fmt.Sprintf("LocalGitStorageDir=%s", cfg.LocalGitStorageDir()),
                fmt.Sprintf("LocalMediaDir=%s", cfg.LFSObjectDir()),
-               fmt.Sprintf("LocalReferenceDir=%s", cfg.LocalReferenceDir()),
+               fmt.Sprintf("LocalReferenceDirs=%s", references),
                fmt.Sprintf("TempDir=%s", cfg.TempDir()),
                fmt.Sprintf("ConcurrentTransfers=%d", api.ConcurrentTransfers),
                fmt.Sprintf("TusTransfers=%v", cfg.TusTransfersAllowed()),
@@ -98,13 +100,19 @@ func LinkOrCopyFromReference(cfg *config.Configuration, oid string, size int64)
        if cfg.LFSObjectExists(oid, size) {
                return nil
        }
-       altMediafile := cfg.Filesystem().ObjectReferencePath(oid)
+       altMediafiles := cfg.Filesystem().ObjectReferencePaths(oid)
        mediafile, err := cfg.Filesystem().ObjectPath(oid)
        if err != nil {
                return err
        }
-       if altMediafile != "" && tools.FileExistsOfSize(altMediafile, size) {
-               return LinkOrCopy(cfg, altMediafile, mediafile)
+       for _, altMediafile := range altMediafiles {
+               tracerx.Printf("altMediafile: %s", altMediafile)
+               if altMediafile != "" && tools.FileExistsOfSize(altMediafile, size) {
+                       err = LinkOrCopy(cfg, altMediafile, mediafile)
+                       if err == nil {
+                               break
+                       }
+               }
        }
-       return nil
+       return err
 }
index 156a447..e3eb946 100644 (file)
@@ -7,7 +7,7 @@ import (
 
        "github.com/git-lfs/git-lfs/fs"
        "github.com/git-lfs/git-lfs/lfs"
-       "github.com/git-lfs/git-lfs/test"
+       test "github.com/git-lfs/git-lfs/t/cmd/util"
        "github.com/stretchr/testify/assert"
 )
 
index a5cc1eb..e70c95a 100644 (file)
@@ -11,7 +11,7 @@ import (
        "time"
 
        . "github.com/git-lfs/git-lfs/lfs"
-       "github.com/git-lfs/git-lfs/test"
+       test "github.com/git-lfs/git-lfs/t/cmd/util"
        "github.com/stretchr/testify/assert"
 )
 
index 840c4d5..ede1f3b 100644 (file)
@@ -28,16 +28,20 @@ var (
        httpRE    = regexp.MustCompile(`\Ahttps?://`)
 )
 
+var hintFileUrl = strings.TrimSpace(`
+hint: The remote resolves to a file:// URL, which can only work with a
+hint: standalone transfer agent.  See section "Using a Custom Transfer Type
+hint: without the API server" in custom-transfers.md for details.
+`)
+
 func (c *Client) NewRequest(method string, e Endpoint, suffix string, body interface{}) (*http.Request, error) {
-       sshRes, err := c.SSH.Resolve(e, method)
-       if err != nil {
-               tracerx.Printf("ssh: %s failed, error: %s, message: %s",
-                       e.SshUserAndHost, err.Error(), sshRes.Message,
-               )
+       if strings.HasPrefix(e.Url, "file://") {
+               // Initial `\n` to avoid overprinting `Downloading LFS...`.
+               fmt.Fprintf(os.Stderr, "\n%s\n", hintFileUrl)
+       }
 
-               if len(sshRes.Message) > 0 {
-                       return nil, errors.Wrap(err, sshRes.Message)
-               }
+       sshRes, err := c.sshResolveWithRetries(e, method)
+       if err != nil {
                return nil, err
        }
 
@@ -107,6 +111,30 @@ func (c *Client) Close() error {
        return c.httpLogger.Close()
 }
 
+func (c *Client) sshResolveWithRetries(e Endpoint, method string) (*sshAuthResponse, error) {
+       var sshRes sshAuthResponse
+       var err error
+
+       requests := tools.MaxInt(0, c.sshTries) + 1
+       for i := 0; i < requests; i++ {
+               sshRes, err = c.SSH.Resolve(e, method)
+               if err == nil {
+                       return &sshRes, nil
+               }
+
+               tracerx.Printf(
+                       "ssh: %s failed, error: %s, message: %s (try: %d/%d)",
+                       e.SshUserAndHost, err.Error(), sshRes.Message, i,
+                       requests,
+               )
+       }
+
+       if len(sshRes.Message) > 0 {
+               return nil, errors.Wrap(err, sshRes.Message)
+       }
+       return nil, err
+}
+
 func (c *Client) extraHeadersFor(req *http.Request) http.Header {
        extraHeaders := c.extraHeaders(req.URL)
        if len(extraHeaders) == 0 {
index 4c113b4..2cd3aa0 100644 (file)
@@ -78,6 +78,14 @@ type AskPassCredentialHelper struct {
        Program string
 }
 
+type credValueType int
+
+const (
+       credValueTypeUnknown credValueType = iota
+       credValueTypeUsername
+       credValueTypePassword
+)
+
 // Fill implements fill by running the ASKPASS program and returning its output
 // as a password encoded in the Creds type given the key "password".
 //
@@ -86,60 +94,92 @@ type AskPassCredentialHelper struct {
 //
 // If there was an error running the command, it is returned instead of a set of
 // filled credentials.
+//
+// The ASKPASS program is only queried if a credential was not already
+// provided, i.e. through the git URL
 func (a *AskPassCredentialHelper) Fill(what Creds) (Creds, error) {
-       var user bytes.Buffer
-       var pass bytes.Buffer
-       var err bytes.Buffer
-
        u := &url.URL{
                Scheme: what["protocol"],
                Host:   what["host"],
                Path:   what["path"],
        }
 
-       // 'ucmd' will run the GIT_ASKPASS (or core.askpass) command prompting
-       // for a username.
-       ucmd := exec.Command(a.Program, a.args(fmt.Sprintf("Username for %q", u))...)
-       ucmd.Stderr = &err
-       ucmd.Stdout = &user
+       creds := make(Creds)
 
-       tracerx.Printf("creds: filling with GIT_ASKPASS: %s", strings.Join(ucmd.Args, " "))
-       if err := ucmd.Run(); err != nil {
+       username, err := a.getValue(what, credValueTypeUsername, u)
+       if err != nil {
                return nil, err
        }
+       creds["username"] = username
 
-       if err.Len() > 0 {
-               return nil, errors.New(err.String())
-       }
-
-       if username := strings.TrimSpace(user.String()); len(username) > 0 {
+       if len(username) > 0 {
                // If a non-empty username was given, add it to the URL via func
                // 'net/url.User()'.
-               u.User = url.User(username)
+               u.User = url.User(creds["username"])
        }
 
-       // Regardless, create 'pcmd' to run the GIT_ASKPASS (or core.askpass)
-       // command prompting for a password.
-       pcmd := exec.Command(a.Program, a.args(fmt.Sprintf("Password for %q", u))...)
-       pcmd.Stderr = &err
-       pcmd.Stdout = &pass
-
-       tracerx.Printf("creds: filling with GIT_ASKPASS: %s", strings.Join(pcmd.Args, " "))
-       if err := pcmd.Run(); err != nil {
+       password, err := a.getValue(what, credValueTypePassword, u)
+       if err != nil {
                return nil, err
        }
+       creds["password"] = password
 
-       if err.Len() > 0 {
-               return nil, errors.New(err.String())
+       return creds, nil
+}
+
+func (a *AskPassCredentialHelper) getValue(what Creds, valueType credValueType, u *url.URL) (string, error) {
+       var valueString string
+
+       switch valueType {
+       case credValueTypeUsername:
+               valueString = "username"
+       case credValueTypePassword:
+               valueString = "password"
+       default:
+               return "", errors.Errorf("Invalid Credential type queried from AskPass")
        }
 
-       // Finally, now that we have the username and password information,
-       // store it in the creds instance that we will return to the caller.
-       creds := make(Creds)
-       creds["username"] = strings.TrimSpace(user.String())
-       creds["password"] = strings.TrimSpace(pass.String())
+       // Return the existing credential if it was already provided, otherwise
+       // query AskPass for it
+       if given, ok := what[valueString]; ok {
+               return given, nil
+       }
+       return a.getFromProgram(valueType, u)
+}
 
-       return creds, nil
+func (a *AskPassCredentialHelper) getFromProgram(valueType credValueType, u *url.URL) (string, error) {
+       var (
+               value bytes.Buffer
+               err   bytes.Buffer
+
+               valueString string
+       )
+
+       switch valueType {
+       case credValueTypeUsername:
+               valueString = "Username"
+       case credValueTypePassword:
+               valueString = "Password"
+       default:
+               return "", errors.Errorf("Invalid Credential type queried from AskPass")
+       }
+
+       // 'cmd' will run the GIT_ASKPASS (or core.askpass) command prompting
+       // for the desired valueType (`Username` or `Password`)
+       cmd := exec.Command(a.Program, a.args(fmt.Sprintf("%s for %q", valueString, u))...)
+       cmd.Stderr = &err
+       cmd.Stdout = &value
+
+       tracerx.Printf("creds: filling with GIT_ASKPASS: %s", strings.Join(cmd.Args, " "))
+       if err := cmd.Run(); err != nil {
+               return "", err
+       }
+
+       if err.Len() > 0 {
+               return "", errors.New(err.String())
+       }
+
+       return strings.TrimSpace(value.String()), nil
 }
 
 // Approve implements CredentialHelper.Approve, and returns nil. The ASKPASS
index 8e91c11..7ecb159 100644 (file)
@@ -106,3 +106,10 @@ func endpointFromGitUrl(u *url.URL, e *endpointGitFinder) Endpoint {
        u.Scheme = e.gitProtocol
        return Endpoint{Url: u.String()}
 }
+
+func endpointFromLocalPath(path string) Endpoint {
+       if !strings.HasSuffix(path, ".git") {
+               path = fmt.Sprintf("%s/.git", path)
+       }
+       return Endpoint{Url: fmt.Sprintf("file://%s", path)}
+}
index 9c7f878..84c4f2e 100644 (file)
@@ -170,6 +170,9 @@ func (e *endpointGitFinder) NewEndpointFromCloneURL(rawurl string) Endpoint {
 
 func (e *endpointGitFinder) NewEndpoint(rawurl string) Endpoint {
        rawurl = e.ReplaceUrlAlias(rawurl)
+       if strings.HasPrefix(rawurl, "/") {
+               return endpointFromLocalPath(rawurl)
+       }
        u, err := url.Parse(rawurl)
        if err != nil {
                return endpointFromBareSshUrl(rawurl)
index 0af7696..3ff6f09 100644 (file)
@@ -250,6 +250,22 @@ func TestBareGitEndpointAddsLfsSuffix(t *testing.T) {
        assert.Equal(t, "", e.SshPort)
 }
 
+func TestLocalPathEndpointAddsDotGitDir(t *testing.T) {
+       finder := NewEndpointFinder(NewContext(nil, nil, map[string]string{
+               "remote.origin.url": "/local/path",
+       }))
+       e := finder.Endpoint("download", "")
+       assert.Equal(t, "file:///local/path/.git/info/lfs", e.Url)
+}
+
+func TestLocalPathEndpointPreservesDotGit(t *testing.T) {
+       finder := NewEndpointFinder(NewContext(nil, nil, map[string]string{
+               "remote.origin.url": "/local/path.git",
+       }))
+       e := finder.Endpoint("download", "")
+       assert.Equal(t, "file:///local/path.git/info/lfs", e.Url)
+}
+
 func TestAccessConfig(t *testing.T) {
        type accessTest struct {
                Access        string
index db20dab..f512fd1 100644 (file)
@@ -51,6 +51,8 @@ type Client struct {
        gitEnv            config.Environment
        osEnv             config.Environment
        uc                *config.URLConfig
+
+       sshTries int
 }
 
 type Context interface {
@@ -72,7 +74,7 @@ func NewClient(ctx Context) (*Client, error) {
        }
 
        cacheCreds := gitEnv.Bool("lfs.cachecredentials", true)
-       var sshResolver SSHResolver = &sshAuthClient{os: osEnv}
+       var sshResolver SSHResolver = &sshAuthClient{os: osEnv, git: gitEnv}
        if cacheCreds {
                sshResolver = withSSHCache(sshResolver)
        }
@@ -91,9 +93,10 @@ func NewClient(ctx Context) (*Client, error) {
                commandCredHelper: &commandCredentialHelper{
                        SkipPrompt: osEnv.Bool("GIT_TERMINAL_PROMPT", false),
                },
-               gitEnv: gitEnv,
-               osEnv:  osEnv,
-               uc:     config.NewURLConfig(gitEnv),
+               gitEnv:   gitEnv,
+               osEnv:    osEnv,
+               uc:       config.NewURLConfig(gitEnv),
+               sshTries: gitEnv.Int("lfs.ssh.retries", 5),
        }
 
        askpass, ok := osEnv.Get("GIT_ASKPASS")
index d67f2dc..c741077 100644 (file)
@@ -49,13 +49,6 @@ func proxyFromClient(c *Client) func(req *http.Request) (*url.URL, error) {
 }
 
 func getProxyServers(u *url.URL, urlCfg *config.URLConfig, osEnv config.Environment) (httpsProxy string, httpProxy string, noProxy string) {
-       if urlCfg != nil {
-               httpProxy, _ = urlCfg.Get("http", u.String(), "proxy")
-               if strings.HasPrefix(httpProxy, "https://") {
-                       httpsProxy = httpProxy
-               }
-       }
-
        if osEnv == nil {
                return
        }
@@ -76,6 +69,16 @@ func getProxyServers(u *url.URL, urlCfg *config.URLConfig, osEnv config.Environm
                httpProxy, _ = osEnv.Get("http_proxy")
        }
 
+       if urlCfg != nil {
+               gitProxy, ok := urlCfg.Get("http", u.String(), "proxy")
+               if len(gitProxy) > 0 && ok {
+                       if strings.HasPrefix(gitProxy, "https://") {
+                               httpsProxy = gitProxy
+                       }
+                       httpProxy = gitProxy
+               }
+       }
+
        noProxy, _ = osEnv.Get("NO_PROXY")
        if len(noProxy) == 0 {
                noProxy, _ = osEnv.Get("no_proxy")
index f2dac89..c623fcd 100644 (file)
@@ -66,11 +66,13 @@ type sshAuthResponse struct {
 }
 
 func (r *sshAuthResponse) IsExpiredWithin(d time.Duration) (time.Time, bool) {
-       return tools.IsExpiredAtOrIn(r.createdAt, d, r.ExpiresAt, time.Duration(r.ExpiresIn)*time.Second)
+       return tools.IsExpiredAtOrIn(r.createdAt, d, r.ExpiresAt,
+               time.Duration(r.ExpiresIn)*time.Second)
 }
 
 type sshAuthClient struct {
-       os config.Environment
+       os  config.Environment
+       git config.Environment
 }
 
 func (c *sshAuthClient) Resolve(e Endpoint, method string) (sshAuthResponse, error) {
@@ -100,6 +102,13 @@ func (c *sshAuthClient) Resolve(e Endpoint, method string) (sshAuthResponse, err
                res.Message = strings.TrimSpace(errbuf.String())
        } else {
                err = json.Unmarshal(outbuf.Bytes(), &res)
+               if res.ExpiresIn == 0 && res.ExpiresAt.IsZero() {
+                       ttl := c.git.Int("lfs.defaulttokenttl", 0)
+                       if ttl < 0 {
+                               ttl = 0
+                       }
+                       res.ExpiresIn = ttl
+               }
                res.createdAt = now
        }
 
index f0a4330..58a05d1 100644 (file)
@@ -1,5 +1,5 @@
 Name:           git-lfs
-Version:        2.4.2
+Version:        2.5.0
 Release:        1%{?dist}
 Summary:        Git extension for versioning large files
 
@@ -35,12 +35,12 @@ ln -s $(pwd) src/github.com/git-lfs/%{name}
 
 pushd src/github.com/git-lfs/%{name}
   %if %{_arch} == i386
-    GOARCH=386 ./script/bootstrap
+    GOARCH=386 make
   %else
-    GOARCH=amd64 ./script/bootstrap
+    GOARCH=amd64 make
   %endif
 popd
-./script/man
+make man
 
 %install
 [ "$RPM_BUILD_ROOT" != "/" ] && rm -rf $RPM_BUILD_ROOT
@@ -66,12 +66,12 @@ export GIT_LFS_TEST_DIR=$(mktemp -d)
 export SKIPAPITESTCOMPILE=1
 
 pushd src/github.com/git-lfs/%{name}
-  ./script/test
+  make test
   go get github.com/ThomsonReutersEikon/go-ntlm/ntlm
-  ./script/integration
+  make -C t PROVE_EXTRA_ARGS=-j4 test
 popd
 
-rmdir ${GIT_LFS_TEST_DIR}
+rm -rf ${GIT_LFS_TEST_DIR}
 
 %clean
 rm -rf %{buildroot}
index cc3fd62..51dd965 100755 (executable)
@@ -140,14 +140,11 @@ fi
 
 pushd ${CURDIR}/..
   #Yes, compile lfs before compiling lfs...
-  ./script/bootstrap
+  make
   #Use the version output to grab the version number and short sha
   #(that yes, I could have gotten from git myself)
   LFS_VERSION=$(./bin/git-lfs version | sed -r 's|.*/([0-9.]*).*|\1|')
   sed -i 's|\(^Version:\s*\).*|\1'"${LFS_VERSION}"'|' ${CURDIR}/SPECS/git-lfs.spec
-  #LFS_SHA=$(git rev-parse --short HEAD)
-  #sed -i 's|\(^commit=*\).*|\1'"${LFS_SHA}"'|' ./script/run
-  #Not needed thanks to #549
 popd
 
 #Prep the SOURCES dir for git-lfs
diff --git a/script/bootstrap b/script/bootstrap
deleted file mode 100755 (executable)
index e57a1b8..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-#!/usr/bin/env bash
-set -e
-
-if uname -s | grep -q "_NT-"; then
-  # Tell Cygwin / MSYS to really create symbolic links.
-  export CYGWIN="$CYGWIN winsymlinks:nativestrict"
-  export MSYS="$MSYS winsymlinks:nativestrict"
-fi
-
-if [ -z "$GOPATH" ]; then
-  export GOPATH="$(pwd)"
-  mkdir -p src/github.com/git-lfs
-  [ -h src/github.com/git-lfs/git-lfs ] ||
-    ln -s "$GOPATH" src/github.com/git-lfs/git-lfs
-fi
-
-if uname -s | grep -q "_NT-"; then
-  echo "Installing goversioninfo to embed resources into Windows executables..."
-  go get github.com/josephspurrier/goversioninfo/cmd/goversioninfo
-  export PATH=$PATH:$GOPATH/bin/windows_386
-  echo "Creating the resource.syso version information file..."
-  go generate
-fi
-
-script/fmt
-rm -rf bin/*
-GO15VENDOREXPERIMENT=1 go run script/*.go -cmd build "$@"
diff --git a/script/build.go b/script/build.go
deleted file mode 100644 (file)
index 4553a2c..0000000
+++ /dev/null
@@ -1,337 +0,0 @@
-package main
-
-import (
-       "crypto/sha256"
-       "encoding/hex"
-       "encoding/json"
-       "flag"
-       "fmt"
-       "io"
-       "io/ioutil"
-       "log"
-       "os"
-       "os/exec"
-       "path/filepath"
-       "runtime"
-       "strings"
-
-       "github.com/git-lfs/git-lfs/config"
-)
-
-var (
-       BuildOS      = flag.String("os", "", "OS to target: darwin,freebsd,linux,windows")
-       BuildArch    = flag.String("arch", "", "Arch to target: 386,amd64")
-       BuildAll     = flag.Bool("all", false, "Builds all architectures")
-       BuildDwarf   = flag.Bool("dwarf", false, "Includes DWARF tables in build artifacts")
-       BuildLdFlags = flag.String("ldflags", "", "-ldflags to pass to the compiler")
-       BuildGcFlags = flag.String("gcflags", "", "-gcflags to pass to the compiler")
-       ShowHelp     = flag.Bool("help", false, "Shows help")
-       matrixKeys   = map[string]string{
-               "darwin":  "Mac",
-               "freebsd": "FreeBSD",
-               "linux":   "Linux",
-               "windows": "Windows",
-               "amd64":   "AMD64",
-       }
-       LdFlags []string
-)
-
-func mainBuild() {
-       if *ShowHelp {
-               fmt.Println("usage: script/bootstrap [-os] [-arch] [-all]")
-               flag.PrintDefaults()
-               return
-       }
-
-       fmt.Printf("Using %s\n", runtime.Version())
-
-       genOut, err := exec.Command("go", "generate", "./commands").CombinedOutput()
-       if err != nil {
-               fmt.Fprintf(os.Stderr, "go generate failed:\n%v", string(genOut))
-               os.Exit(1)
-       }
-       cmd, _ := exec.Command("git", "rev-parse", "--short", "HEAD").Output()
-
-       if len(cmd) > 0 {
-               LdFlags = append(LdFlags, "-X", strings.TrimSpace(
-                       "github.com/git-lfs/git-lfs/config.GitCommit="+string(cmd),
-               ))
-       }
-       if !*BuildDwarf {
-               LdFlags = append(LdFlags, "-s", "-w")
-       }
-
-       buildMatrix := make(map[string]Release)
-       errored := false
-
-       var platforms, arches []string
-       if len(*BuildOS) > 0 {
-               platforms = strings.Split(*BuildOS, ",")
-       }
-       if len(*BuildArch) > 0 {
-               arches = strings.Split(*BuildArch, ",")
-       }
-       if *BuildAll {
-               platforms = []string{"linux", "darwin", "freebsd", "windows"}
-               arches = []string{"amd64", "386"}
-       }
-
-       if len(platforms) < 1 || len(arches) < 1 {
-               if err := build("", "", buildMatrix); err != nil {
-                       log.Fatalln(err)
-               }
-               return // skip build matrix stuff
-       }
-
-       for _, buildos := range platforms {
-               for _, buildarch := range arches {
-                       err := build(strings.TrimSpace(buildos), strings.TrimSpace(buildarch), buildMatrix)
-                       if err != nil {
-                               errored = true
-                       }
-               }
-       }
-
-       if errored {
-               os.Exit(1)
-       }
-
-       by, err := json.Marshal(buildMatrix)
-       if err != nil {
-               log.Fatalln("Error encoding build matrix to json:", err)
-       }
-
-       file, err := os.Create("bin/releases/build_matrix.json")
-       if err != nil {
-               log.Fatalln("Error creating build_matrix.json:", err)
-       }
-
-       written, err := file.Write(by)
-       file.Close()
-
-       if err != nil {
-               log.Fatalln("Error writing build_matrix.json", err)
-       }
-
-       if jsonSize := len(by); written != jsonSize {
-               log.Fatalf("Expected to write %d bytes, actually wrote %d.\n", jsonSize, written)
-       }
-}
-
-func build(buildos, buildarch string, buildMatrix map[string]Release) error {
-       addenv := len(buildos) > 0 && len(buildarch) > 0
-       name := "git-lfs-" + config.Version
-       dir := "bin"
-
-       if addenv {
-               fmt.Printf("Building for %s/%s\n", buildos, buildarch)
-               dir = filepath.Join(dir, "releases", buildos+"-"+buildarch, name)
-       }
-
-       if err := buildCommand(dir, buildos, buildarch); err != nil {
-               return err
-       }
-
-       if addenv {
-               err := os.MkdirAll(dir, 0755)
-               if err != nil {
-                       log.Println("Error setting up installer:\n", err.Error())
-                       return err
-               }
-
-               err = setupInstaller(buildos, buildarch, dir, buildMatrix)
-               if err != nil {
-                       log.Println("Error setting up installer:\n", err.Error())
-                       return err
-               }
-       }
-
-       return nil
-}
-
-func buildCommand(dir, buildos, buildarch string) error {
-       addenv := len(buildos) > 0 && len(buildarch) > 0
-
-       bin := filepath.Join(dir, "git-lfs")
-
-       cmdOS := runtime.GOOS
-       if len(buildos) > 0 {
-               cmdOS = buildos
-       }
-       if cmdOS == "windows" {
-               bin = bin + ".exe"
-       }
-
-       args := make([]string, 1, 6)
-       args[0] = "build"
-       if len(*BuildLdFlags) > 0 {
-               args = append(args, "-ldflags", *BuildLdFlags)
-       } else if len(LdFlags) > 0 {
-               args = append(args, "-ldflags", strings.Join(LdFlags, " "))
-       }
-
-       if len(*BuildGcFlags) > 0 {
-               args = append(args, "-gcflags", *BuildGcFlags)
-       }
-
-       args = append(args, "-o", bin, ".")
-
-       cmd := exec.Command("go", args...)
-       if addenv {
-               cmd.Env = buildGoEnv(buildos, buildarch)
-       }
-
-       output, err := cmd.CombinedOutput()
-       if len(output) > 0 {
-               fmt.Println(string(output))
-       }
-       return err
-}
-
-func buildGoEnv(buildos, buildarch string) []string {
-       env := make([]string, 6, 9)
-       env[0] = "GOOS=" + buildos
-       env[1] = "GOARCH=" + buildarch
-       env[2] = "GOPATH=" + os.Getenv("GOPATH")
-       env[3] = "GOROOT=" + os.Getenv("GOROOT")
-       env[4] = "PATH=" + os.Getenv("PATH")
-       env[5] = "GO15VENDOREXPERIMENT=" + os.Getenv("GO15VENDOREXPERIMENT")
-       for _, key := range []string{"TMP", "TEMP", "TEMPDIR"} {
-               v := os.Getenv(key)
-               if len(v) == 0 {
-                       continue
-               }
-               env = append(env, key+"="+v)
-       }
-       return env
-}
-
-func setupInstaller(buildos, buildarch, dir string, buildMatrix map[string]Release) error {
-       textfiles := []string{
-               "README.md", "CHANGELOG.md",
-       }
-
-       if buildos == "windows" {
-               return winInstaller(textfiles, buildos, buildarch, dir, buildMatrix)
-       } else {
-               return unixInstaller(textfiles, buildos, buildarch, dir, buildMatrix)
-       }
-}
-
-func unixInstaller(textfiles []string, buildos, buildarch, dir string, buildMatrix map[string]Release) error {
-       for _, filename := range textfiles {
-               cmd := exec.Command("cp", filename, filepath.Join(dir, filename))
-               if err := logAndRun(cmd); err != nil {
-                       return err
-               }
-       }
-
-       fullInstallPath := filepath.Join(dir, "install.sh")
-       cmd := exec.Command("cp", "script/install.sh.example", fullInstallPath)
-       if err := logAndRun(cmd); err != nil {
-               return err
-       }
-
-       if err := os.Chmod(fullInstallPath, 0755); err != nil {
-               return err
-       }
-
-       name := zipName(buildos, buildarch) + ".tar.gz"
-       cmd = exec.Command("tar", "czf", "../"+name, filepath.Base(dir))
-       cmd.Dir = filepath.Dir(dir)
-       if err := logAndRun(cmd); err != nil {
-               return nil
-       }
-
-       addToMatrix(buildMatrix, buildos, buildarch, name)
-       return nil
-}
-
-func winInstaller(textfiles []string, buildos, buildarch, dir string, buildMatrix map[string]Release) error {
-       for _, filename := range textfiles {
-               by, err := ioutil.ReadFile(filename)
-               if err != nil {
-                       return err
-               }
-
-               winEndings := strings.Replace(string(by), "\n", "\r\n", -1)
-               err = ioutil.WriteFile(filepath.Join(dir, filename), []byte(winEndings), 0644)
-               if err != nil {
-                       return err
-               }
-       }
-
-       installerPath := filepath.Dir(filepath.Dir(dir))
-       name := zipName(buildos, buildarch) + ".zip"
-       full := filepath.Join(installerPath, name)
-       matches, err := filepath.Glob(dir + "/*")
-       if err != nil {
-               return err
-       }
-
-       args := make([]string, len(matches)+2)
-       args[0] = "-j" // junk the zip paths
-       args[1] = full
-       copy(args[2:], matches)
-
-       cmd := exec.Command("zip", args...)
-       if err := logAndRun(cmd); err != nil {
-               return err
-       }
-
-       addToMatrix(buildMatrix, buildos, buildarch, name)
-       return nil
-}
-
-func addToMatrix(buildMatrix map[string]Release, buildos, buildarch, name string) {
-       buildMatrix[fmt.Sprintf("%s-%s", buildos, buildarch)] = Release{
-               Label:    releaseLabel(buildos, buildarch),
-               Filename: name,
-               SHA256:   hashRelease(name),
-       }
-}
-
-func hashRelease(name string) string {
-       full := filepath.Join("bin/releases", name)
-       file, err := os.Open(full)
-       if err != nil {
-               fmt.Printf("unable to open release %q: %+v\n", full, err)
-               os.Exit(1)
-       }
-
-       defer file.Close()
-
-       h := sha256.New()
-       if _, err = io.Copy(h, file); err != nil {
-               fmt.Printf("error reading release %q: %+v\n", full, err)
-               os.Exit(1)
-       }
-
-       return hex.EncodeToString(h.Sum(nil))
-}
-
-func logAndRun(cmd *exec.Cmd) error {
-       fmt.Printf(" - %s\n", strings.Join(cmd.Args, " "))
-       if len(cmd.Dir) > 0 {
-               fmt.Printf("   - in %s\n", cmd.Dir)
-       }
-
-       output, err := cmd.CombinedOutput()
-       fmt.Println(string(output))
-       return err
-}
-
-func zipName(os, arch string) string {
-       return fmt.Sprintf("git-lfs-%s-%s-%s", os, arch, config.Version)
-}
-
-func releaseLabel(buildos, buildarch string) string {
-       return fmt.Sprintf("%s %s", key(buildos), key(buildarch))
-}
-
-func key(k string) string {
-       if s, ok := matrixKeys[k]; ok {
-               return s
-       }
-       return k
-}
index 1c0b3c8..5c230cd 100755 (executable)
@@ -1,8 +1,31 @@
 #!/usr/bin/env bash
 set -e
-script/test
+
+GOIMPORTS="goimports"
+if [ "appveyor" = "$USERNAME" ]; then
+  GOIMPORTS="C:\\Users\\appveyor\\go\\bin\\goimports"
+fi
+
+GOCACHE=off make GOIMPORTS="$GOIMPORTS" && make GOIMPORTS="$GOIMPORTS" test
 
 # re-run test to ensure GIT_TRACE output doesn't leak into the git package
-GIT_TRACE=1 script/test git
+GIT_TRACE=1 GOCACHE=off make GOIMPORTS="$GOIMPORTS" PKGS=git test
+
+pushd t >/dev/null
+  UNAME=$(uname -s)
+  X=""
+  if [[ $UNAME == MINGW* || $UNAME == MSYS* || $UNAME == CYGWIN* ]]; then
+    X=".exe"
+  fi
+
+  PROVE="prove"
+  PROVE_EXTRA_ARGS="-j9"
+  if [ "appveyor" = "$USERNAME" ]; then
+    export PATH="/c/Strawberry/perl/bin:.:$PATH"
+    PROVE="prove.bat"
+    PROVE_EXTRA_ARGS="$PROVE_EXTRA_ARGS --exec bash"
+  fi
 
-VERBOSE_LOGS=1 script/integration
+  VERBOSE_LOGS=1 make X="$X" clean
+  VERBOSE_LOGS=1 make X="$X" PROVE="$PROVE" PROVE_EXTRA_ARGS="$PROVE_EXTRA_ARGS"
+popd >/dev/null
diff --git a/script/fmt b/script/fmt
deleted file mode 100755 (executable)
index dc2d39a..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-#!/usr/bin/env bash
-
-formatter=gofmt
-hash goimports 2>/dev/null && {
-  formatter=goimports
-}
-
-# don't run gofmt in these directories
-ignored=(/bin/ /docs/ /log/ /man/ /tmp/ /vendor/ /rpm/ /docker/ /debian/ /src/)
-for i in */ ; do
-  if [[ ! ${ignored[*]} =~ "/$i" ]]; then
-    $formatter -w -l "$@" "${i%?}"
-  fi
-done
-
-msg=`script/lint`
-if [ $? -ne 0 ];
-then
-  echo "$msg"
-  exit 1
-fi
diff --git a/script/genmakefile/genmakefile.go b/script/genmakefile/genmakefile.go
deleted file mode 100644 (file)
index 516eadc..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-package main
-
-import (
-       "fmt"
-       "go/build"
-       "os"
-       "strings"
-)
-
-var packages map[string]string = make(map[string]string)
-
-func generate_target(srcdir string, pkgdir string, prefix string, ctx build.Context) string {
-       pkg, _ := ctx.ImportDir(srcdir+pkgdir, 0)
-       name := pkg.Name
-       var deps []string
-       for _, imp := range pkg.Imports {
-               if strings.HasPrefix(imp, prefix) {
-                       imp = strings.TrimPrefix(imp, prefix)
-                       if packages[imp] == "" {
-                               packages[imp] = generate_target(srcdir, imp, prefix, ctx)
-                       }
-                       deps = append(deps, "$(LIBS_"+packages[imp]+")")
-               }
-       }
-       if pkgdir != "" {
-               fmt.Printf("SRCDIR_%s := $(SRCDIR)%s/\n", name, pkgdir)
-       } else {
-               fmt.Printf("SRCDIR_%s := $(SRCDIR)\n", name)
-       }
-       fmt.Printf("SRC_%s := $(addprefix $(SRCDIR_%s), %s)\n", name, name, strings.Join(pkg.GoFiles, " "))
-       fmt.Printf("DEPS_%s := %s\n", name, strings.Join(deps, " "))
-       if pkgdir != "" {
-               fmt.Printf("OBJ_%s := $(LIBDIR)/%s.o\n", name, pkgdir)
-               fmt.Printf("LIB_%s := $(LIBDIR)/%s.a\n", name, pkgdir)
-               fmt.Printf("LIBS_%s := $(LIB_%s) $(DEPS_%s)\n", name, name, name)
-               fmt.Printf("$(OBJ_%s) : $(SRC_%s) $(DEPS_%s)\n", name, name, name)
-               fmt.Printf("\t@mkdir -p $(dir $@)\n")
-               fmt.Printf("\t$(GOC) $(GOFLAGS) -c -o $@ $(SRC_%s)\n", name)
-       }
-       return name
-}
-
-func main() {
-       srcdir := os.Args[1]
-       prefix := os.Args[2]
-       ctx := build.Default
-       ctx.CgoEnabled = false
-       generate_target(srcdir, "", prefix, ctx)
-}
similarity index 100%
rename from script/install.sh.example
rename to script/install.sh
diff --git a/script/integration b/script/integration
deleted file mode 100755 (executable)
index ab92785..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-#!/usr/bin/env bash
-
-. "test/testenv.sh"
-set -e
-
-SHUTDOWN_LFS=no
-SHOW_LOGS=yes
-
-atexit() {
-  res=${1:-$?}
-  SHUTDOWN_LFS=yes
-  if [ "$res" = "0" ]; then
-    SHOW_LOGS=no
-  fi
-
-  if [ "$SHOW_LOGS" = "yes" ] && [ "$VERBOSE_LOGS" = "1" ]; then
-    if [ -s "$REMOTEDIR/gitserver.log" ]; then
-      echo ""
-      echo "gitserver.log:"
-      cat "$REMOTEDIR/gitserver.log"
-    fi
-
-    echo ""
-    echo "env:"
-    env
-  fi
-
-  shutdown
-  exit $res
-}
-
-trap "atexit" EXIT
-
-if [ -s "$LFS_URL_FILE" ]; then
-  SHOW_LOGS=no
-  echo "$LFS_URL_FILE still exists!"
-  echo "Confirm other tests are done, and run:"
-  echo "  $ curl $(cat "$LFS_URL_FILE")/shutdown"
-  exit 1
-fi
-
-setup
-
-GO15VENDOREXPERIMENT=1 GIT_LFS_TEST_MAXPROCS=$GIT_LFS_TEST_MAXPROCS GIT_LFS_TEST_DIR="$GIT_LFS_TEST_DIR" SHUTDOWN_LFS="no" go run script/*.go -cmd integration "$@"
diff --git a/script/integration.go b/script/integration.go
deleted file mode 100644 (file)
index e67b30a..0000000
+++ /dev/null
@@ -1,209 +0,0 @@
-package main
-
-import (
-       "bytes"
-       "errors"
-       "fmt"
-       "os"
-       "os/exec"
-       "path/filepath"
-       "regexp"
-       "runtime"
-       "strconv"
-       "strings"
-       "sync"
-       "time"
-)
-
-var (
-       bashPath    string
-       debugging   = false
-       erroring    = false
-       maxprocs    = 4
-       testPattern = regexp.MustCompile(`test[/\\]test-([a-z\-]+)\.sh$`)
-)
-
-func mainIntegration() {
-       if len(os.Getenv("DEBUG")) > 0 {
-               debugging = true
-       }
-
-       setBash()
-
-       if max, _ := strconv.Atoi(os.Getenv("GIT_LFS_TEST_MAXPROCS")); max > 0 {
-               maxprocs = max
-       }
-
-       fmt.Println("Running this maxprocs", maxprocs)
-
-       files := testFiles()
-
-       if len(files) == 0 {
-               fmt.Println("no tests to run")
-               os.Exit(1)
-       }
-
-       var wg sync.WaitGroup
-       tests := make(chan string, len(files))
-       output := make(chan string, len(files))
-
-       for _, file := range files {
-               tests <- file
-       }
-       close(tests)
-
-       outputDone := make(chan bool)
-       go func() {
-               for out := range output {
-                       fmt.Println(out)
-               }
-               outputDone <- true
-       }()
-
-       for i := 0; i < maxprocs; i++ {
-               wg.Add(1)
-               go worker(tests, output, &wg)
-       }
-
-       wg.Wait()
-       close(output)
-       <-outputDone
-
-       if erroring {
-               os.Exit(1)
-       }
-}
-
-func runTest(output chan string, testname string) {
-       buf := &bytes.Buffer{}
-       cmd := exec.Command(bashPath, testname)
-       cmd.Stdout = buf
-       cmd.Stderr = buf
-
-       err := cmd.Start()
-       if err != nil {
-               sendTestOutput(output, testname, buf, err)
-               return
-       }
-
-       done := make(chan error)
-       go func() {
-               if err := cmd.Wait(); err != nil {
-                       done <- err
-               }
-               close(done)
-       }()
-
-       select {
-       case err = <-done:
-               sendTestOutput(output, testname, buf, err)
-               return
-       case <-time.After(3 * time.Minute):
-               sendTestOutput(output, testname, buf, errors.New("Timed out"))
-               cmd.Process.Kill()
-               return
-       }
-}
-
-func sendTestOutput(output chan string, testname string, buf *bytes.Buffer, err error) {
-       cli := strings.TrimSpace(buf.String())
-       if len(cli) == 0 {
-               cli = fmt.Sprintf("<no output for %s>", testname)
-       }
-
-       if err == nil {
-               output <- cli
-       } else {
-               basetestname := filepath.Base(testname)
-               if debugging {
-                       fmt.Printf("Error on %s: %s\n", basetestname, err)
-               }
-               erroring = true
-               output <- fmt.Sprintf("error: %s => %s\n%s", basetestname, err, cli)
-       }
-}
-
-func worker(tests <-chan string, output chan string, wg *sync.WaitGroup) {
-       defer wg.Done()
-       for {
-               select {
-               case testname, ok := <-tests:
-                       if !ok {
-                               return
-                       }
-                       runTest(output, testname)
-               }
-       }
-}
-
-func testFiles() []string {
-       if len(os.Args) < 4 {
-               return allTestFiles()
-       }
-
-       fileMap := make(map[string]bool)
-       for _, file := range allTestFiles() {
-               fileMap[file] = true
-       }
-
-       files := make([]string, 0, len(os.Args)-3)
-       for _, arg := range os.Args {
-               fullname := "test/test-" + arg + ".sh"
-               if fileMap[fullname] {
-                       files = append(files, fullname)
-               }
-       }
-
-       return files
-}
-
-func allTestFiles() []string {
-       files := make([]string, 0, 100)
-       filepath.Walk("test", func(path string, info os.FileInfo, err error) error {
-               if debugging {
-                       fmt.Println("FOUND:", path)
-               }
-               if err != nil || info.IsDir() || !testPattern.MatchString(path) {
-                       return nil
-               }
-
-               if debugging {
-                       fmt.Println("MATCHING:", path)
-               }
-               files = append(files, path)
-               return nil
-       })
-       return files
-}
-
-func setBash() {
-       findcmd := "which"
-       if runtime.GOOS == "windows" {
-               // Can't use paths returned from which even if it's on PATH in Windows
-               // Because our Go binary is a separate Windows app & not MinGW, it
-               // can't understand paths like '/usr/bin/bash', needs Windows version
-               findcmd = "where"
-       }
-
-       out, err := exec.Command(findcmd, "bash").Output()
-       if err != nil {
-               fmt.Println("Unable to find bash:", err)
-               os.Exit(1)
-       }
-       if len(out) == 0 {
-               fmt.Printf("No output from '%s bash'\n", findcmd)
-               os.Exit(1)
-       }
-
-       bashPath = strings.TrimSpace(strings.Split(string(out), "\n")[0])
-       if debugging {
-               fmt.Println("Using", bashPath)
-       }
-
-       // Test
-       _, err = exec.Command(bashPath, "--version").CombinedOutput()
-       if err != nil {
-               fmt.Println("Error calling bash:", err)
-               os.Exit(1)
-       }
-}
diff --git a/script/lint b/script/lint
deleted file mode 100755 (executable)
index cb1ff5e..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-#!/usr/bin/env bash
-
-deps=$(GO15VENDOREXPERIMENT=1 go list -f '{{join .Deps "\n"}}' . | xargs go list -f '{{if not .Standard}}{{.ImportPath}}{{end}}' | grep -v "github.com/git-lfs/git-lfs")
-
-# exit 0 means non-vendored deps were found
-if [ $? -eq 0 ];
-then
-  echo "Non vendored dependencies found:"
-  for d in $deps; do echo "\t$d"; done
-  echo
-  echo "These dependencies should be tracked in 'glide.yaml'."
-  echo "Consider running "glide update" or "glide get" to vendor a new dependency."
-  exit 1
-else
-  echo "Looks good!"
-fi
diff --git a/script/man b/script/man
deleted file mode 100755 (executable)
index 2632ded..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-#!/usr/bin/env bash
-ronn=`which ronn`
-
-if [ -x "$ronn" ]; then
-  mkdir -p man
-  rm -rf man/*.ronn
-  rm -rf man/*.txt
-  cp docs/man/*.ronn man
-  cp docs/man/*.txt man
-  $ronn man/*.ronn
-  rm -rf man/*.ronn
-  rm -rf man/*.txt
-else
-  echo "Install the 'ronn' ruby gem to build the man pages."
-fi
index 0efa6d2..f6991b5 100755 (executable)
@@ -1,3 +1,3 @@
 #!/usr/bin/env bash
-script/fmt
+make fmt
 GO15VENDOREXPERIMENT=1 go run script/*.go -cmd release "$@"
index 8cc2a9c..85f2be2 100644 (file)
@@ -25,7 +25,7 @@ func mainRelease() {
        file, err := os.Open("bin/releases/build_matrix.json")
        if err != nil {
                log.Println("Error opening build_matrix.json:", err)
-               log.Fatalln("Ensure `script/bootstrap -all` has completed successfully")
+               log.Fatalln("Ensure `make release` has completed successfully")
        }
 
        defer file.Close()
diff --git a/script/run b/script/run
deleted file mode 100755 (executable)
index a19f646..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-#!/usr/bin/env bash
-script/fmt
-commit=`git rev-parse --short HEAD`
-GO15VENDOREXPERIMENT=1 go run -ldflags="-X github.com/git-lfs/git-lfs/config.GitCommit=$commit" ./git-lfs.go "$@"
index 7c2ad85..8dd02de 100644 (file)
@@ -16,12 +16,8 @@ var SubCommand = flag.String("cmd", "", "Command: build or release")
 func main() {
        flag.Parse()
        switch *SubCommand {
-       case "build":
-               mainBuild()
        case "release":
                mainRelease()
-       case "integration":
-               mainIntegration()
        default:
                log.Fatalln("Unknown command:", *SubCommand)
        }
diff --git a/script/test b/script/test
deleted file mode 100755 (executable)
index b8fb7fc..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-#!/usr/bin/env bash
-#
-# Usage: script/test          # run all non-vendored tests
-#        script/test <subpkg> # run just a package's tests
-
-PACKAGES="$@"
-if [ $# -eq 0 ]; then
-  # The following vendor test-exclusion grep-s typically need to match the same
-  # set in debian/rules variable DH_GOLANG_EXCLUDES, so update those when adding
-  # here.
-  PACKAGES="$(go list ./... \
-                | grep -v "github.com/kr/pty" \
-                | grep -v "github.com/kr/text" \
-                | grep -v "github.com/olekukonko/ts" \
-                | grep -v "github.com/pkg/errors" \
-                | grep -v "github.com/stretchr/testify" \
-                | grep -v "github.com/xeipuuv/gojsonreference" \
-                | grep -v "github.com/xeipuuv/gojsonschema" \
-                | grep -v "github.com/alexbrainman/sspi" \
-  )"
-else
-  PACKAGES="$(echo "$PACKAGES" \
-                | sed -e 's/ / .\//g' \
-                | sed -e 's/^\([^\.]\)/.\/\1/g')"
-fi
-
-script/fmt
-
-GO15VENDOREXPERIMENT=1 go test $PACKAGES
-GO15VENDOREXPERIMENT=1 go tool vet $(
-  echo "$PACKAGES" \
-    | grep -v vendor \
-    | grep -v git-source \
-    | sed -e 's/github\.com\/git-lfs\/git-lfs//g' \
-    | sed -e 's/^\///g' \
-    | xargs \
-)
diff --git a/script/update-version b/script/update-version
deleted file mode 100755 (executable)
index 1742ff8..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-#!/usr/bin/env bash
-
-VERSION_STRING=$1
-VERSION_ARRAY=( ${VERSION_STRING//./ } )
-VERSION_MAJOR=${VERSION_ARRAY[0]}
-VERSION_MINOR=${VERSION_ARRAY[1]}
-VERSION_PATCH=${VERSION_ARRAY[2]:-0}
-VERSION_BUILD=${VERSION_ARRAY[3]:-0}
-
-# Update the version number git-lfs is reporting.
-sed -i "s,\(Version = \"\).*\(\"\),\1$VERSION_STRING\2," config/version.go
-
-# Update the version number in the RPM package.
-sed -i "s,\(Version:[[:space:]]*\).*,\1$VERSION_STRING," rpm/SPECS/git-lfs.spec
-
-# Update the version numbers in the Windows installer.
-sed -i "s,\(\"Major\": \).*\,,\1$VERSION_MAJOR\,," versioninfo.json
-sed -i "s,\(\"Minor\": \).*\,,\1$VERSION_MINOR\,," versioninfo.json
-sed -i "s,\(\"Patch\": \).*\,,\1$VERSION_PATCH\,," versioninfo.json
-sed -i "s,\(\"Build\": \).*,\1$VERSION_BUILD," versioninfo.json
-sed -i "s,\(\"ProductVersion\": \"\).*\(\"\),\1$VERSION_STRING\2," versioninfo.json
diff --git a/script/vendor b/script/vendor
deleted file mode 100755 (executable)
index 8e13269..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-#!/usr/bin/env bash
-glide update -s -u
-glide install -s -u
-
-rm -rf vendor/github.com/ThomsonReutersEikon/go-ntlm/utils
-rm -rf vendor/github.com/davecgh/go-spew
-rm -rf vendor/github.com/pmezard/go-difflib
diff --git a/t/Makefile b/t/Makefile
new file mode 100644 (file)
index 0000000..846063d
--- /dev/null
@@ -0,0 +1,40 @@
+RM ?= rm -f
+PROVE ?= prove
+PROVE_EXTRA_ARGS =
+DEFAULT_TEST_TARGET ?= test
+
+GO ?= go
+X =
+
+TEST_CMDS =
+
+TEST_CMDS += ../bin/git-credential-lfsnoop$X
+TEST_CMDS += ../bin/git-credential-lfstest$X
+TEST_CMDS += ../bin/lfs-askpass$X
+TEST_CMDS += ../bin/lfs-ssh-echo$X
+TEST_CMDS += ../bin/lfs-ssh-proxy-test$X
+TEST_CMDS += ../bin/lfstest-count-tests$X
+TEST_CMDS += ../bin/lfstest-customadapter$X
+TEST_CMDS += ../bin/lfstest-gitserver$X
+TEST_CMDS += ../bin/lfstest-standalonecustomadapter$X
+TEST_CMDS += ../bin/lfstest-testutils$X
+
+all : $(DEFAULT_TEST_TARGET)
+
+test : $(TEST_CMDS)
+       $(RM) -r remote test_count{,.lock}
+       @GIT_LFS_NO_TEST_COUNT= bash -c '. ./testenv.sh && setup'
+       $(PROVE) $(PROVE_EXTRA_ARGS) ./t-*.sh
+       @GIT_LFS_NO_TEST_COUNT= bash -c '. ./testenv.sh && shutdown'
+
+./t-%.sh : $(TEST_CMDS)
+       $(RM) -r remote test_count{,.lock}
+       $(PROVE) -v $(PROVE_EXTRA_ARGS) $@
+
+.PHONY : clean
+clean :
+       $(RM) -r remote
+       $(RM) $(TEST_CMDS)
+
+../bin/%$X : cmd/%.go
+       go build -o $@ $^
diff --git a/t/README.md b/t/README.md
new file mode 100644 (file)
index 0000000..a433f98
--- /dev/null
@@ -0,0 +1,117 @@
+# `t`
+
+This directory contains one of the two types of tests that the Git LFS project
+uses to protect against regression. The first, scattered in `*_test.go` files
+throughout the repository are _unit tests_, and written in Go, designed to
+uncover failures at the unit level.
+
+The second kind--and the one contained in this directory--are _integration
+tests_, which are designed to exercise Git LFS in an end-to-end fashion,
+running the `git`, and `git-lfs` binaries, along with a mock Git server.
+
+You can run all tests in this directory with any of the following:
+
+```ShellSession
+$ make
+$ make test
+$ make PROVE_EXTRA_ARGS=-j9 test
+```
+
+Or run a single test (for example, `t-checkout.sh`) by any of the following:
+
+```ShellSession
+$ make ./t-checkout.sh
+$ make PROVE_EXTRA_ARGS=-v ./t-checkout.sh
+$ ./t-checkout.sh
+```
+
+Alternatively, one can run a selection of tests (via explicitly listing them or
+making use of the built-in shell globbing) by any of the following:
+
+```ShellSession
+$ make ./t-*.sh
+$ make PROVE_EXTRA_ARGS=-j9 ./t-*.sh
+$ ./t-*.sh
+```
+
+## Test File(s)
+
+There are a few important kinds of files to know about in the `t` directory:
+
+- `cmd/`: contains the source code of binaries that are useful during test
+  time, like the mocked Git server, or the test counting binary. For more about
+  the contents of this directory, see [test lifecycle](#test-lifecycle) below.
+
+  The file `t/cmd/testutils.go` is automatically linked and included during the
+  build process of each file in `cmd`.
+
+- `fixtures/`: contains shell scripts that load fixture repositories useful for
+  testing against.
+
+- `t-*.sh`: file(s) containing zero or more tests, typically related to
+  a similar topic (c.f,. `t/t-push.sh`, `t/t-pull.sh`, etc.)
+
+- `testenv.sh`: loads environment variables useful during tests. This file is
+  sourced by `testlib.sh`.
+
+- `testhelpers.sh`: loads shell functions useful during tests, like
+  `setup_remote_repo`, and `clone_repo`.
+
+- `testlib.sh`: loads the `begin_test`, `end_test`, and similar functions
+  useful for instantiating a particular test.
+
+## Test Lifecycle
+
+When a test is run, the following occurs, in order:
+
+1. Missing test binaries are compiled into the `bin` directory in the
+   repository root. Note: this does _not_ include the `git-lfs` binary, which
+   is re-compiled via `script/boostrap`.
+
+2. An integration server is started by either (1) the `Makefile` or (2) the
+   `cmd/lfstest-count-test.go` program, which keeps track of the number of
+   running tests and starts an integration server any time the number of active
+   tests goes from `0` to `1`, and stops the server when it goes from `n` to
+   `0`.
+
+3. After sourcing `t/testlib.sh` (& loading `t/testenv.sh`), each test is run
+   in sequence per file. (In other words, multiple test files can be run in
+   parallel, but the tests in a single file are run in sequence.)
+
+4. An individual test will finish, and (if running under `prove`) another will
+   be started in its place. Once all tests are done, `t/test_count` will go to
+   `0`, and the test server will be torn down.
+
+## Test Environment
+
+There are a few environment variables that you can set to change the test suite
+behavior:
+
+* `GIT_LFS_TEST_DIR=path` - This sets the directory that is used as the current
+working directory of the tests. By default, this will be in your temp dir. It's
+recommended that this is set to a directory outside of any Git repository.
+
+* `KEEPTRASH=1` - This will leave the local repository data in a `tmp` directory
+and the remote repository data in `test/remote`.
+
+Also ensure that your `noproxy` environment variable contains `127.0.0.1` host,
+to allow git commands to reach the local Git server `lfstest-gitserver`.
+
+## Writing new tests
+
+A new test file should be named `t/t-*.sh`, where `*` is the topic of Git LFS
+being tested. It should look as follows:
+
+```bash
+#!/usr/bin/env bash
+
+. "$(dirname "$0")/testlib.sh"
+
+begin_test "my test"
+(
+  set -e
+
+  # ...
+)
+end_test
+```
similarity index 100%
rename from test/cmd/lfs-askpass.go
rename to t/cmd/lfs-askpass.go
diff --git a/t/cmd/lfstest-count-tests.go b/t/cmd/lfstest-count-tests.go
new file mode 100644 (file)
index 0000000..75874ba
--- /dev/null
@@ -0,0 +1,296 @@
+package main
+
+import (
+       "context"
+       "fmt"
+       "io"
+       "io/ioutil"
+       "net/http"
+       "os"
+       "os/exec"
+       "path/filepath"
+       "runtime"
+       "strconv"
+       "strings"
+       "time"
+)
+
+var (
+       // countFile is the path to a file (relative to the $LFSTEST_DIR) who's
+       // contents is the number of actively-running integration tests.
+       countFile = "test_count"
+       // lockFile is the path to a file (relative to the $LFSTEST_DIR) who's
+       // presence indicates that another invocation of the lfstest-count-tests
+       // program is modifying the test_count.
+       lockFile = "test_count.lock"
+
+       // lockAcquireTimeout is the maximum amount of time that we will wait
+       // for lockFile to become available (and thus the amount of time that we
+       // will wait in order to acquire the lock).
+       lockAcquireTimeout = 5 * time.Second
+
+       // errCouldNotAcquire indicates that the program could not acquire the
+       // lock needed to modify the test_count. It is a fatal error.
+       errCouldNotAcquire = fmt.Errorf("could not acquire lock, dying")
+       // errNegativeCount indicates that the count in test_count was negative,
+       // which is unexpected and makes this script behave in an undefined
+       // fashion
+       errNegativeCount = fmt.Errorf("unexpected negative count")
+)
+
+// countFn is a type signature that all functions who wish to modify the
+// test_count must inhabit.
+//
+// The first and only formal parameter is the current number of running tests
+// found in test_count after acquiring the lock.
+//
+// The returned tuple indicates (1) the new number that should be written to
+// test_count, and (2) if there was an error in computing that value. If err is
+// non-nil, the program will exit and test_count will not be updated.
+type countFn func(int) (int, error)
+
+func main() {
+       if len(os.Args) > 2 {
+               fmt.Fprintf(os.Stderr,
+                       "usage: %s [increment|decrement]\n", os.Args[0])
+               os.Exit(1)
+       }
+
+       ctx, cancel := context.WithTimeout(
+               context.Background(), lockAcquireTimeout)
+       defer cancel()
+
+       if err := acquire(ctx); err != nil {
+               fatal(err)
+       }
+       defer release()
+
+       if len(os.Args) == 1 {
+               // Calling with no arguments indicates that we simply want to
+               // read the contents of test_count.
+               callWithCount(func(n int) (int, error) {
+                       fmt.Fprintf(os.Stdout, "%d\n", n)
+                       return n, nil
+               })
+               return
+       }
+
+       var err error
+
+       switch strings.ToLower(os.Args[1]) {
+       case "increment":
+               err = callWithCount(func(n int) (int, error) {
+                       if n > 0 {
+                               // If n>1, it is therefore true that a
+                               // lfstest-gitserver invocation is already
+                               // running.
+                               //
+                               // Hence, let's do nothing here other than
+                               // increase the count.
+                               return n + 1, nil
+                       }
+
+                       // The lfstest-gitserver invocation (see: below) does
+                       // not itself create a gitserver.log in the appropriate
+                       // directory. Thus, let's create it ourselves instead.
+                       log, err := os.Create(fmt.Sprintf(
+                               "%s/gitserver.log", os.Getenv("LFSTEST_DIR")))
+                       if err != nil {
+                               return n, err
+                       }
+
+                       // The executable name depends on the X environment
+                       // variable, which is set in script/cibuild.
+                       var cmd *exec.Cmd
+                       if runtime.GOOS == "windows" {
+                               cmd = exec.Command("lfstest-gitserver.exe")
+                       } else {
+                               cmd = exec.Command("lfstest-gitserver")
+                       }
+
+                       // The following are ported from the old
+                       // test/testhelpers.sh, and comprise the requisite
+                       // environment variables needed to run
+                       // lfstest-gitserver.
+                       cmd.Env = append(os.Environ(),
+                               fmt.Sprintf("LFSTEST_URL=%s", os.Getenv("LFSTEST_URL")),
+                               fmt.Sprintf("LFSTEST_SSL_URL=%s", os.Getenv("LFSTEST_SSL_URL")),
+                               fmt.Sprintf("LFSTEST_CLIENT_CERT_URL=%s", os.Getenv("LFSTEST_CLIENT_CERT_URL")),
+                               fmt.Sprintf("LFSTEST_DIR=%s", os.Getenv("LFSTEST_DIR")),
+                               fmt.Sprintf("LFSTEST_CERT=%s", os.Getenv("LFSTEST_CERT")),
+                               fmt.Sprintf("LFSTEST_CLIENT_CERT=%s", os.Getenv("LFSTEST_CLIENT_CERT")),
+                               fmt.Sprintf("LFSTEST_CLIENT_KEY=%s", os.Getenv("LFSTEST_CLIENT_KEY")),
+                       )
+                       cmd.Stdout = log
+
+                       // Start performs a fork/execve, hence we can abandon
+                       // this process once it has started.
+                       if err := cmd.Start(); err != nil {
+                               return n, err
+                       }
+                       return 1, nil
+               })
+       case "decrement":
+               err = callWithCount(func(n int) (int, error) {
+                       if n > 1 {
+                               // If there is at least two tests running, we
+                               // need not shutdown a lfstest-gitserver
+                               // instance.
+                               return n - 1, nil
+                       }
+
+                       // Otherwise, we need to POST to /shutdown, which will
+                       // cause the lfstest-gitserver to abort itself.
+                       url, err := ioutil.ReadFile(os.Getenv("LFS_URL_FILE"))
+                       if err == nil {
+                               _, err = http.Post(string(url)+"/shutdown",
+                                       "application/text",
+                                       strings.NewReader(time.Now().String()))
+                       }
+
+                       return 0, nil
+               })
+       }
+
+       if err != nil {
+               fatal(err)
+       }
+}
+
+var (
+       // acquireTick is the constant time that one tick (i.e., one attempt at
+       // acquiring the lock) should last.
+       acquireTick = 10 * time.Millisecond
+)
+
+// acquire acquires the lock file necessary to perform updates to test_count,
+// and returns an error if that lock cannot be acquired.
+func acquire(ctx context.Context) error {
+       if disabled() {
+               return nil
+       }
+
+       path, err := path(lockFile)
+       if err != nil {
+               return err
+       }
+
+       tick := time.NewTicker(acquireTick)
+       defer tick.Stop()
+
+       for {
+               select {
+               case <-tick.C:
+                       // Try every tick of the above ticker before giving up
+                       // and trying again.
+                       _, err := os.OpenFile(path, os.O_CREATE|os.O_EXCL, 0666)
+                       if err == nil || !os.IsExist(err) {
+                               return err
+                       }
+               case <-ctx.Done():
+                       // If the context.Context above has reached its
+                       // deadline, we must give up.
+                       return errCouldNotAcquire
+               }
+       }
+}
+
+// release releases the lock file so that another process can take over, or
+// returns an error.
+func release() error {
+       if disabled() {
+               return nil
+       }
+
+       path, err := path(lockFile)
+       if err != nil {
+               return err
+       }
+       return os.Remove(path)
+}
+
+// callWithCount calls the given countFn with the current count in test_count,
+// and updates it with what the function returns.
+//
+// If the function produced an error, that will be returned instead.
+func callWithCount(fn countFn) error {
+       path, err := path(countFile)
+       if err != nil {
+               return err
+       }
+
+       f, err := os.OpenFile(path, os.O_CREATE|os.O_RDWR, 0666)
+       if err != nil {
+               return err
+       }
+
+       contents, err := ioutil.ReadAll(f)
+       if err != nil {
+               return err
+       }
+
+       var n int = 0
+       if len(contents) != 0 {
+               n, err = strconv.Atoi(string(contents))
+               if err != nil {
+                       return err
+               }
+
+               if n < 0 {
+                       return errNegativeCount
+               }
+       }
+
+       after, err := fn(n)
+       if err != nil {
+               return err
+       }
+
+       // We want to write over the contents in the file, so "truncate" the
+       // file to a length of 0, and then seek to the beginning of the file to
+       // update the write head.
+       if err := f.Truncate(0); err != nil {
+               return err
+       }
+       if _, err := f.Seek(0, io.SeekStart); err != nil {
+               return err
+       }
+
+       if _, err := fmt.Fprintf(f, "%d", after); err != nil {
+               return err
+       }
+       return nil
+}
+
+// path returns an absolute path corresponding to any given path relative to the
+// 't' directory of the current checkout of Git LFS.
+func path(s string) (string, error) {
+       p := filepath.Join(filepath.Dir(os.Getenv("LFSTEST_DIR")), s)
+       if err := os.MkdirAll(filepath.Dir(p), 0666); err != nil {
+               return "", err
+       }
+       return p, nil
+}
+
+// disabled returns true if and only if the lock acquisition phase is disabled.
+func disabled() bool {
+       s := os.Getenv("GIT_LFS_LOCK_ACQUIRE_DISABLED")
+       b, err := strconv.ParseBool(s)
+       if err != nil {
+               return false
+       }
+       return b
+}
+
+// fatal reports the given error (if non-nil), and then dies. If the error was
+// nil, nothing happens.
+func fatal(err error) {
+       if err == nil {
+               return
+       }
+       if err := release(); err != nil {
+               fmt.Fprintf(os.Stderr, "fatal: while dying, got: %s\n", err)
+       }
+       fmt.Fprintf(os.Stderr, "fatal: %s\n", err)
+       os.Exit(1)
+}
similarity index 99%
rename from test/cmd/lfstest-gitserver.go
rename to t/cmd/lfstest-gitserver.go
index 9773299..7af7f16 100644 (file)
@@ -101,6 +101,9 @@ func main() {
        mux.HandleFunc("/storage/", storageHandler)
        mux.HandleFunc("/verify", verifyHandler)
        mux.HandleFunc("/redirect307/", redirect307Handler)
+       mux.HandleFunc("/status", func(w http.ResponseWriter, r *http.Request) {
+               fmt.Fprintf(w, "%s\n", time.Now().String())
+       })
        mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
                id, ok := reqId(w)
                if !ok {
similarity index 88%
rename from test/cmd/lfstest-testutils.go
rename to t/cmd/lfstest-testutils.go
index beb5c92..370aa50 100644 (file)
@@ -9,7 +9,7 @@ import (
        "os"
        "path/filepath"
 
-       "github.com/git-lfs/git-lfs/test"
+       . "github.com/git-lfs/git-lfs/t/cmd/util"
 )
 
 type TestUtilRepoCallback struct{}
@@ -23,7 +23,7 @@ func (*TestUtilRepoCallback) Errorf(format string, args ...interface{}) {
 }
 
 func main() {
-       commandMap := map[string]func(*test.Repo){
+       commandMap := map[string]func(*Repo){
                "addcommits": AddCommits,
        }
        if len(os.Args) < 2 {
@@ -51,18 +51,18 @@ func main() {
                os.Exit(2)
        }
 
-       repo := test.WrapRepo(&TestUtilRepoCallback{}, wd)
+       repo := WrapRepo(&TestUtilRepoCallback{}, wd)
        f(repo)
 }
 
-func AddCommits(repo *test.Repo) {
-       // Read stdin as JSON []*test.CommitInput
+func AddCommits(repo *Repo) {
+       // Read stdin as JSON []*CommitInput
        in, err := ioutil.ReadAll(os.Stdin)
        if err != nil {
                fmt.Fprintf(os.Stderr, "addcommits: Unable to read input data: %v\n", err)
                os.Exit(3)
        }
-       inputs := make([]*test.CommitInput, 0)
+       inputs := make([]*CommitInput, 0)
        err = json.Unmarshal(in, &inputs)
        if err != nil {
                fmt.Fprintf(os.Stderr, "addcommits: Unable to unmarshal JSON: %v\n%v\n", string(in), err)
similarity index 99%
rename from test/testutils.go
rename to t/cmd/util/testutils.go
index c01446d..454af13 100644 (file)
@@ -1,4 +1,4 @@
-package test
+package util
 
 // Utility functions for more complex go tests
 // Need to be in a separate test package so they can be imported anywhere
similarity index 50%
rename from test/test-migrate-fixtures.sh
rename to t/fixtures/migrate.sh
index 6d3408f..bdcd5dc 100755 (executable)
@@ -44,6 +44,130 @@ setup_local_branch_with_gitattrs() {
   git commit -m "add .gitattributes"
 }
 
+# setup_local_branch_with_nested_gitattrs creates a repository as follows:
+#
+#   A---B
+#        \
+#         refs/heads/master
+#
+# - Commit 'A' has 120, in a.txt, and a corresponding entry in .gitattributes. There is also
+#   140 in a.md, with no corresponding entry in .gitattributes.
+#   It also has 140 in subtree/a.md, and a corresponding entry in subtree/.gitattributes
+setup_local_branch_with_nested_gitattrs() {
+  set -e
+
+  reponame="nested-attrs"
+
+  remove_and_create_local_repo "$reponame"
+
+  mkdir b
+
+  base64 < /dev/urandom | head -c 120 > a.txt
+  base64 < /dev/urandom | head -c 140 > a.md
+  base64 < /dev/urandom | head -c 140 > b/a.md
+
+  git add a.txt a.md b/a.md
+  git commit -m "initial commit"
+
+  git lfs track "*.txt"
+
+  git add .gitattributes
+  git commit -m "add .gitattributes"
+
+  cd b
+
+  git lfs track "*.md"
+
+  cd ..
+
+  git add b/.gitattributes
+  git commit -m "add nested .gitattributes"
+}
+
+# setup_single_local_branch_tracked creates a repository as follows:
+#
+#   A---B
+#        \
+#         refs/heads/master
+#
+# - Commit 'A' has 120, in a.txt and 140 in a.md, with both files tracked as
+#   pointers in Git LFS
+setup_single_local_branch_tracked() {
+  set -e
+
+  reponame="migrate-single-remote-branch-with-attrs"
+
+  remove_and_create_local_repo "$reponame"
+
+  git lfs track "*.txt" "*.md"
+
+  git add .gitattributes
+  git commit -m "initial commit"
+
+  base64 < /dev/urandom | head -c 120 > a.txt
+  base64 < /dev/urandom | head -c 140 > a.md
+
+  git add a.txt a.md
+  git commit -m "add a.{txt,md}"
+}
+
+# setup_single_local_branch_complex_tracked creates a repository as follows:
+#
+#   A
+#    \
+#     refs/heads/master
+#
+# - Commit 'A' has 1 byte of text in a.txt and dir/b.txt. According to the
+#   .gitattributes files, a.txt should be tracked using Git LFS, but b.txt should
+#   not be.
+setup_single_local_branch_complex_tracked() {
+  set -e
+
+  reponame="migrate-single-local-branch-complex-tracked"
+
+  remove_and_create_local_repo "$reponame"
+
+  mkdir -p dir
+  echo "*.txt filter=lfs diff=lfs merge=lfs -text" > .gitattributes
+  echo "*.txt !filter !diff !merge" > dir/.gitattributes
+
+  printf "a" > a.txt
+  printf "b" > dir/b.txt
+
+  git lfs uninstall
+
+  git add .gitattributes dir/.gitattributes a.txt dir/b.txt
+  git commit -m "initial commit"
+
+  git lfs install
+}
+
+# setup_single_local_branch_tracked_corrupt creates a repository as follows:
+#
+#   A
+#    \
+#     refs/heads/master
+#
+# - Commit 'A' has 120 bytes of random data in a.txt, and tracks *.txt under Git
+#   LFS, but a.txt is not stored as an LFS object.
+setup_single_local_branch_tracked_corrupt() {
+  set -e
+
+  reponame="migrate-single-locla-branch-with-attrs-corrupt"
+
+  remove_and_create_local_repo "$reponame"
+
+  git lfs track "*.txt"
+  git lfs uninstall
+
+  base64 < /dev/urandom | head -c 120 > a.txt
+
+  git add .gitattributes a.txt
+  git commit -m "initial commit"
+
+  git lfs install
+}
+
 # setup_multiple_local_branches creates a repository as follows:
 #
 #     B
@@ -54,7 +178,7 @@ setup_local_branch_with_gitattrs() {
 #
 # - Commit 'A' has 120, 140 bytes of data in a.txt, and a.md, respectively.
 #
-# - Commit 'B' has 30 bytes of data in a.txt, and includes commit 'A' as a
+# - Commit 'B' has 30 bytes of data in a.md, and includes commit 'A' as a
 #   parent.
 setup_multiple_local_branches() {
   set -e
@@ -79,6 +203,74 @@ setup_multiple_local_branches() {
   git checkout master
 }
 
+# setup_multiple_local_branches_with_gitattrs creates a repository in the same way
+# as setup_multiple_local_branches, but also adds relevant lfs filters to the
+# .gitattributes file in the master branch
+setup_multiple_local_branches_with_gitattrs() {
+  set -e
+
+  setup_multiple_local_branches
+
+  git lfs track *.txt
+  git lfs track *.md
+
+  git add .gitattributes
+  git commit -m "add .gitattributes"
+}
+
+# setup_multiple_local_branches_non_standard creates a repository as follows:
+#
+#      refs/pull/1/head
+#     /
+#     |
+#     B
+#    / \
+#   A   refs/heads/my-feature
+#   |\
+#   | refs/heads/master
+#    \
+#     refs/pull/1/base
+#
+# With the same contents in 'A' and 'B' as setup_multiple_local_branches.
+setup_multiple_local_branches_non_standard() {
+  set -e
+
+  setup_multiple_local_branches
+
+  git update-ref refs/pull/1/head "$(git rev-parse my-feature)"
+  git update-ref refs/pull/1/base "$(git rev-parse master)"
+}
+
+# setup_multiple_local_branches_tracked creates a repo with exactly the same
+# structure as in setup_multiple_local_branches, but with all files tracked by
+# Git LFS
+setup_multiple_local_branches_tracked() {
+  set -e
+
+  reponame="migrate-info-multiple-local-branches"
+
+  remove_and_create_local_repo "$reponame"
+
+  git lfs track "*.txt" "*.md"
+  git add .gitattributes
+  git commit -m "initial commit"
+
+  base64 < /dev/urandom | head -c 120 > a.txt
+  base64 < /dev/urandom | head -c 140 > a.md
+
+  git add a.txt a.md
+  git commit -m "add a.{txt,md}"
+
+  git checkout -b my-feature
+
+  base64 < /dev/urandom | head -c 30 > a.md
+
+  git add a.md
+  git commit -m "add an additional 30 bytes to a.md"
+
+  git checkout master
+}
+
 # setup_local_branch_with_space creates a repository as follows:
 #
 #   A
@@ -134,6 +326,46 @@ setup_single_remote_branch() {
   git commit -m "add an additional 30, 50 bytes to a.{txt,md}"
 }
 
+setup_single_remote_branch_with_gitattrs() {
+  set -e
+
+  setup_single_remote_branch
+
+  git lfs track *.txt
+  git lfs track *.md
+
+  git add .gitattributes
+  git commit -m "add .gitattributes"
+}
+
+# Creates a repo identical to setup_single_remote_branch, except with *.md and
+# *.txt files tracked by Git LFS
+setup_single_remote_branch_tracked() {
+  set -e
+
+  reponame="migrate-info-single-remote-branch"
+
+  remove_and_create_remote_repo "$reponame"
+
+  git lfs track "*.md" "*.txt"
+  git add .gitattributes
+  git commit -m "initial commit"
+
+  base64 < /dev/urandom | head -c 120 > a.txt
+  base64 < /dev/urandom | head -c 140 > a.md
+
+  git add a.txt a.md
+  git commit -m "add a.{txt,md}"
+
+  git push origin master
+
+  base64 < /dev/urandom | head -c 30 > a.txt
+  base64 < /dev/urandom | head -c 50 > a.md
+
+  git add a.md a.txt
+  git commit -m "add an additional 30, 50 bytes to a.{txt,md}"
+}
+
 # setup_multiple_remote_branches creates a repository as follows:
 #
 #         C
@@ -180,6 +412,41 @@ setup_multiple_remote_branches() {
   git checkout master
 }
 
+# Creates a repo identical to that in setup_multiple_remote_branches(), but
+# with all files tracked by Git LFS
+setup_multiple_remote_branches_gitattrs() {
+  set -e
+
+  reponame="migrate-info-exclude-remote-refs-given-branch"
+
+  remove_and_create_remote_repo "$reponame"
+
+  git lfs track "*.txt" "*.md"
+  git add .gitattributes
+  git commit -m "initial commit"
+
+  base64 < /dev/urandom | head -c 10 > a.txt
+  base64 < /dev/urandom | head -c 11 > a.md
+  git add a.txt a.md
+  git commit -m "add 10, 11 bytes, a.{txt,md}"
+
+  git push origin master
+
+  base64 < /dev/urandom | head -c 20 > a.txt
+  base64 < /dev/urandom | head -c 21 > a.md
+  git add a.txt a.md
+  git commit -m "add 20, 21 bytes, a.{txt,md}"
+
+  git checkout -b my-feature
+
+  base64 < /dev/urandom | head -c 30 > a.txt
+  base64 < /dev/urandom | head -c 31 > a.md
+  git add a.txt a.md
+  git commit -m "add 30, 31 bytes, a.{txt,md}"
+
+  git checkout master
+}
+
 # setup_single_local_branch_with_tags creates a repository as follows:
 #
 #   A---B
@@ -241,6 +508,31 @@ setup_single_local_branch_with_annotated_tags() {
   git tag "v1.0.0" -m "v1.0.0"
 }
 
+setup_multiple_remotes() {
+  set -e
+
+  reponame="migrate-multiple-remotes"
+  remove_and_create_remote_repo "$reponame"
+
+  forkname="$(git remote -v \
+    | head -n1 \
+    | cut -d ' ' -f 1 \
+    | sed -e 's/^.*\///g')-fork"
+  ( setup_remote_repo "$forkname" )
+
+  git remote add fork "$GITSERVER/$forkname"
+
+  base64 < /dev/urandom | head -c 16 > a.txt
+  git add a.txt
+  git commit -m "initial commit"
+  git push origin master
+
+  base64 < /dev/urandom | head -c 16 > a.txt
+  git add a.txt
+  git commit -m "another commit"
+  git push fork master
+}
+
 # setup_single_local_branch_deep_trees creates a repository as follows:
 #
 #   A
@@ -284,6 +576,28 @@ setup_local_branch_with_symlink() {
   git commit -m "add symlink"
 }
 
+# setup_local_branch_with_dirty_copy creates a repository as follows:
+#
+#   A
+#    \
+#     refs/heads/master
+#
+# - Commit 'A' has the contents "a.txt in a.txt, and marks a.txt as unclean
+#   in the working copy.
+setup_local_branch_with_dirty_copy() {
+  set -e
+
+  reponame="migrate-single-local-branch-with-dirty-copy"
+  remove_and_create_local_repo "$reponame"
+
+  printf "a.txt" > a.txt
+
+  git add a.txt
+  git commit -m "initial commit"
+
+  printf "2" >> a.txt
+}
+
 # make_bare converts the existing full checkout of a repository into a bare one,
 # and then `cd`'s into it.
 make_bare() {
@@ -318,4 +632,6 @@ remove_and_create_remote_repo() {
 
   setup_remote_repo "$reponame"
   clone_repo "$reponame" "$reponame"
+
+  rm clone.log
 }
diff --git a/t/git-lfs-test-server-api/.gitignore b/t/git-lfs-test-server-api/.gitignore
new file mode 100644 (file)
index 0000000..ad2a747
--- /dev/null
@@ -0,0 +1 @@
+git-lfs-test-server-api*
similarity index 94%
rename from test/git-lfs-test-server-api/main.go
rename to t/git-lfs-test-server-api/main.go
index 295536f..3635df7 100644 (file)
@@ -13,8 +13,8 @@ import (
        "github.com/git-lfs/git-lfs/errors"
        "github.com/git-lfs/git-lfs/fs"
        "github.com/git-lfs/git-lfs/lfsapi"
+       t "github.com/git-lfs/git-lfs/t/cmd/util"
        "github.com/git-lfs/git-lfs/tasklog"
-       "github.com/git-lfs/git-lfs/test"
        "github.com/git-lfs/git-lfs/tq"
        "github.com/spf13/cobra"
 )
@@ -64,7 +64,7 @@ func testServerApi(cmd *cobra.Command, args []string) {
        // Use test repo for this to simplify the process of making sure data matches oid
        // We're not performing a real test at this point (although an upload fail will break it)
        var callback testDataCallback
-       repo := test.NewRepo(&callback)
+       repo := t.NewRepo(&callback)
 
        // Force loading of config before we alter it
        repo.GitEnv().All()
@@ -137,7 +137,7 @@ func (*testDataCallback) Errorf(format string, args ...interface{}) {
        fmt.Printf(format, args...)
 }
 
-func buildManifest(r *test.Repo) (*tq.Manifest, error) {
+func buildManifest(r *t.Repo) (*tq.Manifest, error) {
        // Configure the endpoint manually
        finder := lfsapi.NewEndpointFinder(r)
 
@@ -173,7 +173,7 @@ func (c *constantEndpoint) Endpoint(operation, remote string) lfsapi.Endpoint {
 
 func (c *constantEndpoint) RemoteEndpoint(operation, remote string) lfsapi.Endpoint { return c.e }
 
-func buildTestData(repo *test.Repo, manifest *tq.Manifest) (oidsExist, oidsMissing []TestObject, err error) {
+func buildTestData(repo *t.Repo, manifest *tq.Manifest) (oidsExist, oidsMissing []TestObject, err error) {
        const oidCount = 50
        oidsExist = make([]TestObject, 0, oidCount)
        oidsMissing = make([]TestObject, 0, oidCount)
@@ -183,14 +183,14 @@ func buildTestData(repo *test.Repo, manifest *tq.Manifest) (oidsExist, oidsMissi
        meter := tq.NewMeter()
        meter.Logger = meter.LoggerFromEnv(repo.OSEnv())
        logger.Enqueue(meter)
-       commit := test.CommitInput{CommitterName: "A N Other", CommitterEmail: "noone@somewhere.com"}
+       commit := t.CommitInput{CommitterName: "A N Other", CommitterEmail: "noone@somewhere.com"}
        for i := 0; i < oidCount; i++ {
                filename := fmt.Sprintf("file%d.dat", i)
                sz := int64(rand.Intn(200)) + 50
-               commit.Files = append(commit.Files, &test.FileInput{Filename: filename, Size: sz})
+               commit.Files = append(commit.Files, &t.FileInput{Filename: filename, Size: sz})
                meter.Add(sz)
        }
-       outputs := repo.AddCommits([]*test.CommitInput{&commit})
+       outputs := repo.AddCommits([]*t.CommitInput{&commit})
 
        // now upload
        uploadQueue := tq.NewTransferQueue(tq.Upload, manifest, "origin", tq.WithProgress(meter))
similarity index 78%
rename from test/test-askpass.sh
rename to t/t-askpass.sh
index 29d3d52..ef5f6c6 100755 (executable)
@@ -1,6 +1,6 @@
 #!/usr/bin/env bash
 
-. "test/testlib.sh"
+. "$(dirname "$0")/testlib.sh"
 
 begin_test "askpass: push with GIT_ASKPASS"
 (
@@ -102,3 +102,33 @@ begin_test "askpass: push with SSH_ASKPASS"
   grep "master -> master" push.log
 )
 end_test
+
+begin_test "askpass: defaults to provided credentials"
+(
+  set -e
+
+  reponame="askpass-provided-creds"
+  setup_remote_repo "$reponame"
+  clone_repo "$reponame" "$reponame"
+
+  git lfs track "*.dat"
+  echo "hello" > a.dat
+
+  git add .gitattributes a.dat
+  git commit -m "initial commit"
+
+  # $password is defined from test/cmd/lfstest-gitserver.go (see: skipIfBadAuth)
+  export LFS_ASKPASS_USERNAME="fakeuser"
+  export LFS_ASKPASS_PASSWORD="fakepass"
+  git config --local "credential.helper" ""
+
+  url=$(git config --get remote.origin.url)
+  newurl=${url/http:\/\//http:\/\/user\:pass@}
+  git remote set-url origin "$newurl"
+
+  GIT_ASKPASS="lfs-askpass" GIT_TRACE=1 GIT_CURL_VERBOSE=1 git push origin master 2>&1 | tee push.log
+
+  [ ! $(grep "filling with GIT_ASKPASS" push.log) ]
+  grep "master -> master" push.log
+)
+end_test
similarity index 98%
rename from test/test-batch-error-handling.sh
rename to t/t-batch-error-handling.sh
index cb087e1..b1192ac 100755 (executable)
@@ -2,7 +2,7 @@
 # This is a sample Git LFS test.  See test/README.md and testhelpers.sh for
 # more documentation.
 
-. "test/testlib.sh"
+. "$(dirname "$0")/testlib.sh"
 
 begin_test "batch error handling"
 (
similarity index 98%
rename from test/test-batch-retries.sh
rename to t/t-batch-retries.sh
index 13735dc..f10b590 100755 (executable)
@@ -1,6 +1,6 @@
 #!/usr/bin/env bash
 
-. "test/testlib.sh"
+. "$(dirname "$0")/testlib.sh"
 
 begin_test "batch storage upload causes retries"
 (
similarity index 99%
rename from test/test-batch-transfer.sh
rename to t/t-batch-transfer.sh
index 1c7b779..2a5ba7b 100755 (executable)
@@ -2,7 +2,7 @@
 # This is a sample Git LFS test.  See test/README.md and testhelpers.sh for
 # more documentation.
 
-. "test/testlib.sh"
+. "$(dirname "$0")/testlib.sh"
 
 begin_test "batch transfer"
 (
similarity index 95%
rename from test/test-batch-unknown-oids.sh
rename to t/t-batch-unknown-oids.sh
index b96721b..a2eb5c8 100755 (executable)
@@ -1,6 +1,6 @@
 #!/usr/bin/env bash
 
-. "test/testlib.sh"
+. "$(dirname "$0")/testlib.sh"
 
 begin_test "transfer queue rejects unknown OIDs"
 (
similarity index 85%
rename from test/test-checkout.sh
rename to t/t-checkout.sh
index ef0ee6a..9271f3f 100755 (executable)
@@ -1,6 +1,6 @@
 #!/usr/bin/env bash
 
-. "test/testlib.sh"
+. "$(dirname "$0")/testlib.sh"
 
 begin_test "checkout"
 (
@@ -41,12 +41,13 @@ begin_test "checkout"
   rm -rf file1.dat file2.dat file3.dat folder1/nested.dat folder2/nested.dat
 
   echo "checkout should replace all"
-  git lfs checkout
+  git lfs checkout 2>&1 | tee checkout.log
   [ "$contents" = "$(cat file1.dat)" ]
   [ "$contents" = "$(cat file2.dat)" ]
   [ "$contents" = "$(cat file3.dat)" ]
   [ "$contents" = "$(cat folder1/nested.dat)" ]
   [ "$contents" = "$(cat folder2/nested.dat)" ]
+  grep "Checking out LFS objects: 100% (5/5), 95 B" checkout.log
 
   # Remove the working directory
   rm -rf file1.dat file2.dat file3.dat folder1/nested.dat folder2/nested.dat
@@ -73,7 +74,7 @@ begin_test "checkout"
   [ ! -f ../folder2/nested.dat ]
   # test '.' in current dir
   rm nested.dat
-  git lfs checkout .
+  git lfs checkout . 2>&1 | tee checkout.log
   [ "$contents" = "$(cat nested.dat)" ]
   popd
 
@@ -155,3 +156,29 @@ begin_test "checkout: outside git repository"
   grep "Not in a git repository" checkout.log
 )
 end_test
+
+begin_test "checkout: write-only file"
+(
+  set -e
+
+  reponame="checkout-locked"
+  filename="a.txt"
+
+  setup_remote_repo_with_file "$reponame" "$filename"
+
+  pushd "$TRASHDIR" > /dev/null
+    GIT_LFS_SKIP_SMUDGE=1 clone_repo "$reponame" "${reponame}_checkout"
+
+    chmod -w "$filename"
+
+    refute_file_writeable "$filename"
+    assert_pointer "refs/heads/master" "$filename" "$(calc_oid "$filename\n")" 6
+
+    git lfs fetch
+    git lfs checkout "$filename"
+
+    refute_file_writeable "$filename"
+    [ "$filename" = "$(cat "$filename")" ]
+  popd > /dev/null
+)
+end_test
similarity index 98%
rename from test/test-chunked-transfer-encoding.sh
rename to t/t-chunked-transfer-encoding.sh
index a545ca3..8ddc50e 100755 (executable)
@@ -2,7 +2,7 @@
 # This is a sample Git LFS test.  See test/README.md and testhelpers.sh for
 # more documentation.
 
-. "test/testlib.sh"
+. "$(dirname "$0")/testlib.sh"
 
 begin_test "chunked transfer encoding"
 (
similarity index 99%
rename from test/test-clean.sh
rename to t/t-clean.sh
index 3b21c07..806778e 100755 (executable)
@@ -1,6 +1,6 @@
 #!/usr/bin/env bash
 
-. "test/testlib.sh"
+. "$(dirname "$0")/testlib.sh"
 
 clean_setup () {
   mkdir "$1"
similarity index 93%
rename from test/test-clone-deprecated.sh
rename to t/t-clone-deprecated.sh
index 7686093..f75c257 100755 (executable)
@@ -1,6 +1,6 @@
 #!/usr/bin/env bash
 
-. "test/testlib.sh"
+. "$(dirname "$0")/testlib.sh"
 
 ensure_git_version_isnt $VERSION_LOWER "2.15.0"
 
similarity index 99%
rename from test/test-clone.sh
rename to t/t-clone.sh
index ec51cf3..7fcb718 100755 (executable)
@@ -1,6 +1,6 @@
 #!/usr/bin/env bash
 
-. "test/testlib.sh"
+. "$(dirname "$0")/testlib.sh"
 
 ensure_git_version_isnt $VERSION_LOWER "2.2.0"
 
similarity index 97%
rename from test/test-commit-delete-push.sh
rename to t/t-commit-delete-push.sh
index aac5c49..057f607 100755 (executable)
@@ -1,6 +1,6 @@
 #!/usr/bin/env bash
 
-. "test/testlib.sh"
+. "$(dirname "$0")/testlib.sh"
 
 begin_test "commit, delete, then push"
 (
similarity index 99%
rename from test/test-config.sh
rename to t/t-config.sh
index 7127a81..b9c4356 100755 (executable)
@@ -1,6 +1,6 @@
 #!/usr/bin/env bash
 
-. "test/testlib.sh"
+. "$(dirname "$0")/testlib.sh"
 
 begin_test "default config"
 (
similarity index 97%
rename from test/test-credentials-no-prompt.sh
rename to t/t-credentials-no-prompt.sh
index a9fd287..31e6f9e 100755 (executable)
@@ -1,6 +1,6 @@
 #!/usr/bin/env bash
 
-. "test/testlib.sh"
+. "$(dirname "$0")/testlib.sh"
 
 # these tests rely on GIT_TERMINAL_PROMPT to test properly
 ensure_git_version_isnt $VERSION_LOWER "2.3.0"
similarity index 98%
rename from test/test-credentials.sh
rename to t/t-credentials.sh
index 845d484..29e30fb 100755 (executable)
@@ -1,6 +1,6 @@
 #!/usr/bin/env bash
 
-. "test/testlib.sh"
+. "$(dirname "$0")/testlib.sh"
 
 ensure_git_version_isnt $VERSION_LOWER "2.3.0"
 
@@ -77,6 +77,7 @@ begin_test "credentials with url-specific useHttpPath, with bad path password"
 
   clone_repo "$reponame" with-url-specific-path
   git config credential.$GITSERVER.useHttpPath false
+  git config lfs.locksverify false
   git checkout -b without-path
 
   git lfs track "*.dat" 2>&1 | tee track.log
@@ -164,7 +165,7 @@ begin_test "credentials with useHttpPath, with correct password"
   credcalls="$(grep "creds: git credential" push.log)"
   [ "0" -eq "$(echo "$credcalls" | grep '", "")' | wc -l)" ]
   expected="$(echo "$credcalls" | wc -l)"
-  [ "$expected" -eq "$(printf "$credcalls" | grep "test-credentials" | wc -l)" ]
+  [ "$expected" -eq "$(printf "$credcalls" | grep "t-credentials" | wc -l)" ]
 )
 end_test
 
similarity index 99%
rename from test/test-custom-transfers.sh
rename to t/t-custom-transfers.sh
index b8898bf..8130ef6 100755 (executable)
@@ -1,6 +1,6 @@
 #!/usr/bin/env bash
 
-. "test/testlib.sh"
+. "$(dirname "$0")/testlib.sh"
 
 begin_test "custom-transfer-wrong-path"
 (
@@ -102,7 +102,6 @@ begin_test "custom-transfer-upload-download"
 
   grep "xfer: started custom adapter process" fetchcustom.log
   grep "xfer\[lfstest-customadapter\]:" fetchcustom.log
-  grep "Downloading LFS objects: 100% (12/12)" fetchcustom.log
 
   grep "Terminating test custom adapter gracefully" fetchcustom.log
 
similarity index 97%
rename from test/test-duplicate-oids.sh
rename to t/t-duplicate-oids.sh
index 9b9c6fb..9508e8a 100755 (executable)
@@ -1,6 +1,6 @@
 #!/usr/bin/env bash
 
-. "test/testlib.sh"
+. "$(dirname "$0")/testlib.sh"
 
 begin_test "multiple revs with same OID get pushed once"
 (
similarity index 94%
rename from test/test-env.sh
rename to t/t-env.sh
index 2a3047e..5145a3f 100755 (executable)
@@ -1,6 +1,6 @@
 #!/usr/bin/env bash
 
-. "test/testlib.sh"
+. "$(dirname "$0")/testlib.sh"
 
 envInitConfig='git config filter.lfs.process = "git-lfs filter-process"
 git config filter.lfs.smudge = "git-lfs smudge -- %f"
@@ -29,7 +29,7 @@ LocalWorkingDir=%s
 LocalGitDir=%s
 LocalGitStorageDir=%s
 LocalMediaDir=%s
-LocalReferenceDir=
+LocalReferenceDirs=
 TempDir=%s
 ConcurrentTransfers=3
 TusTransfers=false
@@ -81,7 +81,7 @@ LocalWorkingDir=%s
 LocalGitDir=%s
 LocalGitStorageDir=%s
 LocalMediaDir=%s
-LocalReferenceDir=
+LocalReferenceDirs=
 TempDir=%s
 ConcurrentTransfers=3
 TusTransfers=false
@@ -140,7 +140,7 @@ LocalWorkingDir=%s
 LocalGitDir=%s
 LocalGitStorageDir=%s
 LocalMediaDir=%s
-LocalReferenceDir=
+LocalReferenceDirs=
 TempDir=%s
 ConcurrentTransfers=3
 TusTransfers=false
@@ -197,7 +197,7 @@ LocalWorkingDir=%s
 LocalGitDir=%s
 LocalGitStorageDir=%s
 LocalMediaDir=%s
-LocalReferenceDir=
+LocalReferenceDirs=
 TempDir=%s
 ConcurrentTransfers=3
 TusTransfers=false
@@ -256,7 +256,7 @@ LocalWorkingDir=%s
 LocalGitDir=%s
 LocalGitStorageDir=%s
 LocalMediaDir=%s
-LocalReferenceDir=
+LocalReferenceDirs=
 TempDir=%s
 ConcurrentTransfers=3
 TusTransfers=false
@@ -316,7 +316,7 @@ LocalWorkingDir=%s
 LocalGitDir=%s
 LocalGitStorageDir=%s
 LocalMediaDir=%s
-LocalReferenceDir=
+LocalReferenceDirs=
 TempDir=%s
 ConcurrentTransfers=3
 TusTransfers=false
@@ -377,7 +377,7 @@ LocalWorkingDir=%s
 LocalGitDir=%s
 LocalGitStorageDir=%s
 LocalMediaDir=%s
-LocalReferenceDir=
+LocalReferenceDirs=
 TempDir=%s
 ConcurrentTransfers=5
 TusTransfers=false
@@ -445,7 +445,7 @@ LocalWorkingDir=%s
 LocalGitDir=%s
 LocalGitStorageDir=%s
 LocalMediaDir=%s
-LocalReferenceDir=
+LocalReferenceDirs=
 TempDir=%s
 ConcurrentTransfers=3
 TusTransfers=false
@@ -500,7 +500,7 @@ LocalWorkingDir=%s
 LocalGitDir=%s
 LocalGitStorageDir=%s
 LocalMediaDir=%s
-LocalReferenceDir=
+LocalReferenceDirs=
 TempDir=%s
 ConcurrentTransfers=3
 TusTransfers=false
@@ -542,14 +542,19 @@ UploadTransfers=basic
   contains_same_elements "$expected" "$actual4"
 
   envVars="$(GIT_DIR=$gitDir GIT_WORK_TREE=a/b env | grep "^GIT" | sort)"
+
+  # `a/b` is an invalid relative path from where we are now and results in an
+  # error, so resulting output will have many fields blank or invalid
+  mediaDir5=$(native_path "lfs/objects")
+  tempDir5=$(native_path "lfs/tmp")
   expected5=$(printf '%s
 %s
 
-LocalWorkingDir=%s
-LocalGitDir=%s
-LocalGitStorageDir=%s
+LocalWorkingDir=
+LocalGitDir=
+LocalGitStorageDir=
 LocalMediaDir=%s
-LocalReferenceDir=
+LocalReferenceDirs=
 TempDir=%s
 ConcurrentTransfers=3
 TusTransfers=false
@@ -562,13 +567,16 @@ FetchRecentRefsIncludeRemotes=true
 PruneOffsetDays=3
 PruneVerifyRemoteAlways=false
 PruneRemoteName=origin
-LfsStorageDir=%s
+LfsStorageDir=lfs
 AccessDownload=none
 AccessUpload=none
 DownloadTransfers=basic
 UploadTransfers=basic
 %s
-' "$(git lfs version)" "$(git version)" "$localwd" "$localgit" "$localgitstore" "$localmedia" "$tempdir" "$lfsstorage" "$envVars")
+git config filter.lfs.process = ""
+git config filter.lfs.smudge = ""
+git config filter.lfs.clean = ""
+' "$(git lfs version)" "$(git version)" "$mediaDir5" "$tempDir5" "$envVars")
   actual5=$(GIT_DIR=$gitDir GIT_WORK_TREE=a/b git lfs env \
             | grep -v "^GIT_EXEC_PATH=")
   contains_same_elements "$expected5" "$actual5"
@@ -582,7 +590,7 @@ LocalWorkingDir=%s
 LocalGitDir=%s
 LocalGitStorageDir=%s
 LocalMediaDir=%s
-LocalReferenceDir=
+LocalReferenceDirs=
 TempDir=%s
 ConcurrentTransfers=3
 TusTransfers=false
@@ -615,7 +623,7 @@ LocalWorkingDir=%s
 LocalGitDir=%s
 LocalGitStorageDir=%s
 LocalMediaDir=%s
-LocalReferenceDir=
+LocalReferenceDirs=
 TempDir=%s
 ConcurrentTransfers=3
 TusTransfers=false
@@ -660,7 +668,7 @@ LocalWorkingDir=
 LocalGitDir=%s
 LocalGitStorageDir=%s
 LocalMediaDir=%s
-LocalReferenceDir=
+LocalReferenceDirs=
 TempDir=%s
 ConcurrentTransfers=3
 TusTransfers=false
@@ -739,7 +747,7 @@ LocalWorkingDir=%s
 LocalGitDir=%s
 LocalGitStorageDir=%s
 LocalMediaDir=%s
-LocalReferenceDir=
+LocalReferenceDirs=
 TempDir=%s
 ConcurrentTransfers=3
 TusTransfers=false
@@ -772,12 +780,12 @@ LocalWorkingDir=%s
 LocalGitDir=%s
 LocalGitStorageDir=%s
 LocalMediaDir=%s
-LocalReferenceDir=
+LocalReferenceDirs=
 TempDir=%s
 ConcurrentTransfers=3
 TusTransfers=false
 BasicTransfersOnly=false
-SkipDownloadErrors=true
+SkipDownloadErrors=false
 FetchRecentAlways=false
 FetchRecentRefsDays=7
 FetchRecentCommitsDays=0
@@ -797,8 +805,37 @@ UploadTransfers=basic
   contains_same_elements "$expecteddisabled" "$actual"
 
   # now enable via env var
+  envVarsEnabled=$(printf "%s" "$(GIT_LFS_SKIP_DOWNLOAD_ERRORS=1 env | grep "^GIT")")
+  expectedenabled2=$(printf '%s
+%s
+
+LocalWorkingDir=%s
+LocalGitDir=%s
+LocalGitStorageDir=%s
+LocalMediaDir=%s
+LocalReferenceDirs=
+TempDir=%s
+ConcurrentTransfers=3
+TusTransfers=false
+BasicTransfersOnly=false
+SkipDownloadErrors=true
+FetchRecentAlways=false
+FetchRecentRefsDays=7
+FetchRecentCommitsDays=0
+FetchRecentRefsIncludeRemotes=true
+PruneOffsetDays=3
+PruneVerifyRemoteAlways=false
+PruneRemoteName=origin
+LfsStorageDir=%s
+AccessDownload=none
+AccessUpload=none
+DownloadTransfers=basic
+UploadTransfers=basic
+%s
+%s
+' "$(git lfs version)" "$(git version)" "$localwd" "$localgit" "$localgitstore" "$localmedia" "$tempdir" "$lfsstorage" "$envVarsEnabled" "$envInitConfig")
   actual=$(GIT_LFS_SKIP_DOWNLOAD_ERRORS=1 git lfs env | grep -v "^GIT_EXEC_PATH=")
-  contains_same_elements "$expectedenabled" "$actual"
+  contains_same_elements "$expectedenabled2" "$actual"
 
 
 
@@ -838,7 +875,7 @@ LocalWorkingDir=%s
 LocalGitDir=%s
 LocalGitStorageDir=%s
 LocalMediaDir=%s
-LocalReferenceDir=
+LocalReferenceDirs=
 TempDir=%s
 ConcurrentTransfers=3
 TusTransfers=true
similarity index 97%
rename from test/test-expired.sh
rename to t/t-expired.sh
index 5639442..2e2647c 100755 (executable)
@@ -1,6 +1,6 @@
 #!/usr/bin/env bash
 
-. "test/testlib.sh"
+. "$(dirname "$0")/testlib.sh"
 
 declare -a expiration_types=("absolute" "relative" "both")
 
similarity index 97%
rename from test/test-ext.sh
rename to t/t-ext.sh
index 9cae8d8..4fb3e8b 100755 (executable)
@@ -1,6 +1,6 @@
 #!/usr/bin/env bash
 
-. "test/testlib.sh"
+. "$(dirname "$0")/testlib.sh"
 
 begin_test "ext"
 (
similarity index 98%
rename from test/test-extra-header.sh
rename to t/t-extra-header.sh
index b3a5f91..995d22b 100755 (executable)
@@ -1,6 +1,6 @@
 #!/usr/bin/env bash
 
-. "test/testlib.sh"
+. "$(dirname "$0")/testlib.sh"
 
 begin_test "http.<url>.extraHeader"
 (
similarity index 98%
rename from test/test-fetch-include.sh
rename to t/t-fetch-include.sh
index a5f183a..85fbe9c 100755 (executable)
@@ -1,6 +1,6 @@
 #!/usr/bin/env bash
 
-. "test/testlib.sh"
+. "$(dirname "$0")/testlib.sh"
 
 reponame="$(basename "$0" ".sh")"
 contents="big file"
similarity index 98%
rename from test/test-fetch-paths.sh
rename to t/t-fetch-paths.sh
index a4f63dc..6d4a1f7 100755 (executable)
@@ -1,6 +1,6 @@
 #!/usr/bin/env bash
 
-. "test/testlib.sh"
+. "$(dirname "$0")/testlib.sh"
 
 reponame="$(basename "$0" ".sh")"
 contents="a"
similarity index 99%
rename from test/test-fetch-recent.sh
rename to t/t-fetch-recent.sh
index 5ade93c..391a643 100755 (executable)
@@ -1,6 +1,6 @@
 #!/usr/bin/env bash
 
-. "test/testlib.sh"
+. "$(dirname "$0")/testlib.sh"
 
 reponame="fetch-recent"
 
similarity index 98%
rename from test/test-fetch-refspec.sh
rename to t/t-fetch-refspec.sh
index 38529a1..3e94f02 100755 (executable)
@@ -1,6 +1,6 @@
 #!/usr/bin/env bash
 
-. "test/testlib.sh"
+. "$(dirname "$0")/testlib.sh"
 
 begin_test "fetch with good ref"
 (
similarity index 99%
rename from test/test-fetch.sh
rename to t/t-fetch.sh
index bc3410b..6940317 100755 (executable)
@@ -1,6 +1,6 @@
 #!/usr/bin/env bash
 
-. "test/testlib.sh"
+. "$(dirname "$0")/testlib.sh"
 
 contents="a"
 contents_oid=$(calc_oid "$contents")
@@ -526,14 +526,14 @@ begin_test "fetch raw remote url"
   git init
   git lfs install --local --skip-smudge
 
-  git remote add origin $GITSERVER/test-fetch
+  git remote add origin "$GITSERVER/$reponame"
   git pull origin master
 
   # LFS object not downloaded, pointer in working directory
   refute_local_object "$contents_oid"
   grep "$content_oid" a.dat
 
-  git lfs fetch "$GITSERVER/test-fetch"
+  git lfs fetch "$GITSERVER/$reponame"
 
   # LFS object downloaded, pointer still in working directory
   assert_local_object "$contents_oid" 1
similarity index 96%
rename from test/test-filter-branch.sh
rename to t/t-filter-branch.sh
index 6377812..9a31248 100755 (executable)
@@ -1,6 +1,6 @@
 #!/usr/bin/env bash
 
-. "test/testlib.sh"
+. "$(dirname "$0")/testlib.sh"
 
 begin_test "filter-branch (git-lfs/git-lfs#1773)"
 (
similarity index 98%
rename from test/test-filter-process.sh
rename to t/t-filter-process.sh
index 32b8386..21ef709 100755 (executable)
@@ -1,6 +1,6 @@
 #!/usr/bin/env bash
 
-. "test/testlib.sh"
+. "$(dirname "$0")/testlib.sh"
 
 # HACK(taylor): git uses ".g<hash>" in the version name to signal that it is
 # from the "next" branch, which is the only (current) version of Git that has
similarity index 98%
rename from test/test-fsck.sh
rename to t/t-fsck.sh
index 6d6ccfa..170492e 100755 (executable)
@@ -1,6 +1,6 @@
 #!/usr/bin/env bash
 
-. "test/testlib.sh"
+. "$(dirname "$0")/testlib.sh"
 
 begin_test "fsck default"
 (
similarity index 99%
rename from test/test-happy-path.sh
rename to t/t-happy-path.sh
index d3aea38..38c5781 100755 (executable)
@@ -2,7 +2,7 @@
 # This is a sample Git LFS test.  See test/README.md and testhelpers.sh for
 # more documentation.
 
-. "test/testlib.sh"
+. "$(dirname "$0")/testlib.sh"
 
 begin_test "happy path"
 (
similarity index 95%
rename from test/test-install-custom-hooks-path-unsupported.sh
rename to t/t-install-custom-hooks-path-unsupported.sh
index e5c624e..7cf9f2f 100755 (executable)
@@ -1,6 +1,6 @@
 #!/usr/bin/env bash
 
-. "test/testlib.sh"
+. "$(dirname "$0")/testlib.sh"
 
 # These tests rely on behavior found in Git versions less than 2.9.0 to perform
 # themselves, specifically:
similarity index 96%
rename from test/test-install-custom-hooks-path.sh
rename to t/t-install-custom-hooks-path.sh
index 26b9d16..4a403ca 100755 (executable)
@@ -1,6 +1,6 @@
 #!/usr/bin/env bash
 
-. "test/testlib.sh"
+. "$(dirname "$0")/testlib.sh"
 
 # These tests rely on behavior found in 2.9.0 to perform themselves,
 # specifically:
similarity index 99%
rename from test/test-install.sh
rename to t/t-install.sh
index abc8f64..05753b3 100755 (executable)
@@ -1,6 +1,6 @@
 #!/usr/bin/env bash
 
-. "test/testlib.sh"
+. "$(dirname "$0")/testlib.sh"
 
 begin_test "install again"
 (
similarity index 99%
rename from test/test-lock.sh
rename to t/t-lock.sh
index bd82b4f..9d3b8f8 100755 (executable)
@@ -1,6 +1,6 @@
 #!/usr/bin/env bash
 
-. "test/testlib.sh"
+. "$(dirname "$0")/testlib.sh"
 
 begin_test "lock with good ref"
 (
similarity index 99%
rename from test/test-locks.sh
rename to t/t-locks.sh
index e167750..d822ff0 100755 (executable)
@@ -1,6 +1,6 @@
 #!/usr/bin/env bash
 
-. "test/testlib.sh"
+. "$(dirname "$0")/testlib.sh"
 
 begin_test "list a single lock with bad ref"
 (
similarity index 92%
rename from test/test-logs.sh
rename to t/t-logs.sh
index a4176da..8ebb194 100755 (executable)
@@ -1,6 +1,6 @@
 #!/usr/bin/env bash
 
-. "test/testlib.sh"
+. "$(dirname "$0")/testlib.sh"
 
 begin_test "logs"
 (
similarity index 90%
rename from test/test-ls-files.sh
rename to t/t-ls-files.sh
index 5ceee0d..947bbd3 100755 (executable)
@@ -1,6 +1,6 @@
 #!/usr/bin/env bash
 
-. "test/testlib.sh"
+. "$(dirname "$0")/testlib.sh"
 
 begin_test "ls-files"
 (
@@ -329,3 +329,36 @@ begin_test "ls-files: invalid --all ordering"
   grep "Could not scan for Git LFS tree" ls-files.out
 )
 end_test
+
+begin_test "ls-files: list/stat files with escaped runes in path before commit"
+(
+  set -e
+
+  reponame=runes-in-path
+  content="zero"
+  checksum="d3eb539a55"
+  pathWithGermanRunes="german/äöü"
+  fileWithGermanRunes="schüüch.bin"
+
+  mkdir $reponame
+  git init "$reponame"
+  cd $reponame
+  git lfs track "**/*"
+
+  echo "$content" > regular
+  echo "$content" > "$fileWithGermanRunes"
+
+  mkdir -p "$pathWithGermanRunes"
+  echo "$content" > "$pathWithGermanRunes/regular"
+  echo "$content" > "$pathWithGermanRunes/$fileWithGermanRunes"
+
+  git add *
+
+  # check short form
+  [ 4 -eq "$(git lfs ls-files | grep -c '*')" ]
+
+  # also check long format
+  [ 4 -eq "$(git lfs ls-files -l | grep -c '*')" ]
+
+)
+end_test
similarity index 98%
rename from test/test-malformed-pointers.sh
rename to t/t-malformed-pointers.sh
index e2f7b26..a384e3b 100755 (executable)
@@ -1,6 +1,6 @@
 #!/usr/bin/env bash
 
-. "test/testlib.sh"
+. "$(dirname "$0")/testlib.sh"
 
 begin_test "malformed pointers"
 (
similarity index 96%
rename from test/test-mergetool.sh
rename to t/t-mergetool.sh
index baac2e8..3fd7765 100755 (executable)
@@ -1,6 +1,6 @@
 #!/usr/bin/env bash
 
-. "test/testlib.sh"
+. "$(dirname "$0")/testlib.sh"
 
 begin_test "mergetool works with large files"
 (
diff --git a/t/t-migrate-export.sh b/t/t-migrate-export.sh
new file mode 100755 (executable)
index 0000000..fc114d3
--- /dev/null
@@ -0,0 +1,444 @@
+#!/usr/bin/env bash
+
+. "$(dirname "$0")/fixtures/migrate.sh"
+. "$(dirname "$0")/testlib.sh"
+
+begin_test "migrate export (default branch)"
+(
+  set -e
+
+  setup_multiple_local_branches_tracked
+
+  # Add b.md, a pointer existing only on master
+  base64 < /dev/urandom | head -c 160 > b.md
+  git add b.md
+  git commit -m "add b.md"
+
+  md_oid="$(calc_oid "$(cat a.md)")"
+  txt_oid="$(calc_oid "$(cat a.txt)")"
+  b_md_oid="$(calc_oid "$(cat b.md)")"
+
+  git checkout my-feature
+  md_feature_oid="$(calc_oid "$(cat a.md)")"
+  git checkout master
+
+  assert_pointer "refs/heads/master" "a.md" "$md_oid" "140"
+  assert_pointer "refs/heads/master" "a.txt" "$txt_oid" "120"
+  assert_pointer "refs/heads/master" "b.md" "$b_md_oid" "160"
+  assert_pointer "refs/heads/my-feature" "a.md" "$md_feature_oid" "30"
+
+  git lfs migrate export --include="*.md, *.txt"
+
+  refute_pointer "refs/heads/master" "a.md"
+  refute_pointer "refs/heads/master" "a.txt"
+  refute_pointer "refs/heads/master" "b.md"
+  assert_pointer "refs/heads/my-feature" "a.md" "$md_feature_oid" "30"
+
+  # b.md should be pruned as no pointer exists to reference it
+  refute_local_object "$b_md_oid" "160"
+
+  # Other objects should not be pruned as they're still referenced in `feature`
+  # by pointers
+  assert_local_object "$md_oid" "140"
+  assert_local_object "$txt_oid" "120"
+  assert_local_object "$md_feature_oid" "30"
+
+  master="$(git rev-parse refs/heads/master)"
+  feature="$(git rev-parse refs/heads/my-feature)"
+
+  master_attrs="$(git cat-file -p "$master:.gitattributes")"
+  feature_attrs="$(git cat-file -p "$feature:.gitattributes")"
+
+  echo "$master_attrs" | grep -q "*.md text !filter !merge !diff"
+  echo "$master_attrs" | grep -q "*.txt text !filter !merge !diff"
+
+  [ ! $(echo "$feature_attrs" | grep -q "*.md text !filter !merge !diff") ]
+  [ ! $(echo "$feature_attrs" | grep -q "*.txt text !filter !merge !diff") ]
+)
+end_test
+
+begin_test "migrate export (with remote)"
+(
+  set -e
+
+  setup_single_remote_branch_tracked
+
+  git push origin master
+
+  md_oid="$(calc_oid "$(cat a.md)")"
+  txt_oid="$(calc_oid "$(cat a.txt)")"
+
+  assert_pointer "refs/heads/master" "a.md" "$md_oid" "50"
+  assert_pointer "refs/heads/master" "a.txt" "$txt_oid" "30"
+
+  assert_pointer "refs/remotes/origin/master" "a.md" "$md_oid" "50"
+  assert_pointer "refs/remotes/origin/master" "a.txt" "$txt_oid" "30"
+
+  # Flush the cache to ensure all objects have to be downloaded
+  rm -rf .git/lfs/objects
+
+  git lfs migrate export --everything --include="*.md, *.txt"
+
+  refute_pointer "refs/heads/master" "a.md"
+  refute_pointer "refs/heads/master" "a.txt"
+
+  # All pointers have been exported, so all objects should be pruned
+  refute_local_object "$md_oid" "50"
+  refute_local_object "$txt_oid" "30"
+
+  master="$(git rev-parse refs/heads/master)"
+  master_attrs="$(git cat-file -p "$master:.gitattributes")"
+
+  echo "$master_attrs" | grep -q "*.md text !filter !merge !diff"
+  echo "$master_attrs" | grep -q "*.txt text !filter !merge !diff"
+)
+end_test
+
+begin_test "migrate export (include/exclude args)"
+(
+  set -e
+
+  setup_single_local_branch_tracked
+
+  md_oid="$(calc_oid "$(cat a.md)")"
+  txt_oid="$(calc_oid "$(cat a.txt)")"
+
+  assert_pointer "refs/heads/master" "a.txt" "$txt_oid" "120"
+  assert_pointer "refs/heads/master" "a.md" "$md_oid" "140"
+
+  git lfs migrate export --include="*" --exclude="a.md"
+
+  refute_pointer "refs/heads/master" "a.txt"
+  assert_pointer "refs/heads/master" "a.md" "$md_oid" "140"
+
+  refute_local_object "$txt_oid" "120"
+  assert_local_object "$md_oid" "140"
+
+  master="$(git rev-parse refs/heads/master)"
+
+  master_attrs="$(git cat-file -p "$master:.gitattributes")"
+
+  echo "$master_attrs" | grep -q "* text !filter !merge !diff"
+  echo "$master_attrs" | grep -q "a.md filter=lfs diff=lfs merge=lfs"
+)
+end_test
+
+begin_test "migrate export (bare repository)"
+(
+  set -e
+
+  setup_single_remote_branch_tracked
+  git push origin master
+
+  md_oid="$(calc_oid "$(cat a.md)")"
+  txt_oid="$(calc_oid "$(cat a.txt)")"
+
+  make_bare
+
+  assert_pointer "refs/heads/master" "a.txt" "$txt_oid" "30"
+  assert_pointer "refs/heads/master" "a.md" "$md_oid" "50"
+
+  git lfs migrate export --everything --include="*"
+
+  refute_pointer "refs/heads/master" "a.md"
+  refute_pointer "refs/heads/master" "a.txt"
+
+  # All pointers have been exported, so all objects should be pruned
+  refute_local_object "$md_oid" "50"
+  refute_local_object "$txt_oid" "30"
+)
+end_test
+
+begin_test "migrate export (given branch)"
+(
+  set -e
+
+  setup_multiple_local_branches_tracked
+
+  md_oid="$(calc_oid "$(cat a.md)")"
+  txt_oid="$(calc_oid "$(cat a.txt)")"
+
+  git checkout my-feature
+  md_feature_oid="$(calc_oid "$(cat a.md)")"
+  git checkout master
+
+  assert_pointer "refs/heads/my-feature" "a.md" "$md_feature_oid" "30"
+  assert_pointer "refs/heads/my-feature" "a.txt" "$txt_oid" "120"
+  assert_pointer "refs/heads/master" "a.md" "$md_oid" "140"
+  assert_pointer "refs/heads/master" "a.txt" "$txt_oid" "120"
+
+  git lfs migrate export --include="*.md,*.txt" my-feature
+
+  refute_pointer "refs/heads/my-feature" "a.md"
+  refute_pointer "refs/heads/my-feature" "a.txt"
+  refute_pointer "refs/heads/master" "a.md"
+  refute_pointer "refs/heads/master" "a.txt"
+
+  # No pointers left, so all objects should be pruned
+  refute_local_object "$md_feature_oid" "30"
+  refute_local_object "$txt_oid" "120"
+  refute_local_object "$md_oid" "140"
+
+  master="$(git rev-parse refs/heads/master)"
+  feature="$(git rev-parse refs/heads/my-feature)"
+
+  master_attrs="$(git cat-file -p "$master:.gitattributes")"
+  feature_attrs="$(git cat-file -p "$feature:.gitattributes")"
+
+  echo "$master_attrs" | grep -q "*.md text !filter !merge !diff"
+  echo "$master_attrs" | grep -q "*.txt text !filter !merge !diff"
+  echo "$feature_attrs" | grep -q "*.md text !filter !merge !diff"
+  echo "$feature_attrs" | grep -q "*.txt text !filter !merge !diff"
+)
+end_test
+
+begin_test "migrate export (no filter)"
+(
+  set -e
+
+  setup_multiple_local_branches_tracked
+
+  git lfs migrate export --yes 2>&1 | tee migrate.log
+  if [ ${PIPESTATUS[0]} -eq 0 ]; then
+    echo >&2 "fatal: expected git lfs migrate export to fail, didn't"
+    exit 1
+  fi
+
+  grep "fatal: one or more files must be specified with --include" migrate.log
+)
+end_test
+
+begin_test "migrate export (exclude remote refs)"
+(
+  set -e
+
+  setup_single_remote_branch_tracked
+
+  md_oid="$(calc_oid "$(cat a.md)")"
+  txt_oid="$(calc_oid "$(cat a.txt)")"
+
+  git checkout refs/remotes/origin/master
+  md_remote_oid="$(calc_oid "$(cat a.md)")"
+  txt_remote_oid="$(calc_oid "$(cat a.txt)")"
+  git checkout master
+
+  assert_pointer "refs/heads/master" "a.md" "$md_oid" "50"
+  assert_pointer "refs/heads/master" "a.txt" "$txt_oid" "30"
+
+  assert_pointer "refs/remotes/origin/master" "a.md" "$md_remote_oid" "140"
+  assert_pointer "refs/remotes/origin/master" "a.txt" "$txt_remote_oid" "120"
+
+  git lfs migrate export --include="*.md,*.txt"
+
+  refute_pointer "refs/heads/master" "a.md"
+  refute_pointer "refs/heads/master" "a.txt"
+
+  refute_local_object "$md_oid" "50"
+  refute_local_object "$txt_oid" "30"
+
+  assert_pointer "refs/remotes/origin/master" "a.md" "$md_remote_oid" "140"
+  assert_pointer "refs/remotes/origin/master" "a.txt" "$txt_remote_oid" "120"
+
+  # Since these two objects exist on the remote, they should be removed with
+  # our prune operation
+  refute_local_object "$md_remote_oid" "140"
+  refute_local_object "$txt_remote_oid" "120"
+
+  master="$(git rev-parse refs/heads/master)"
+  remote="$(git rev-parse refs/remotes/origin/master)"
+
+  master_attrs="$(git cat-file -p "$master:.gitattributes")"
+  remote_attrs="$(git cat-file -p "$remote:.gitattributes")"
+
+  echo "$master_attrs" | grep -q "*.md text !filter !merge !diff"
+  echo "$master_attrs" | grep -q "*.txt text !filter !merge !diff"
+
+  [ ! $(echo "$remote_attrs" | grep -q "*.md text !filter !merge !diff") ]
+  [ ! $(echo "$remote_attrs" | grep -q "*.txt text !filter !merge !diff") ]
+)
+end_test
+
+begin_test "migrate export (--skip-fetch)"
+(
+  set -e
+
+  setup_single_remote_branch_tracked
+
+  md_master_oid="$(calc_oid "$(cat a.md)")"
+  txt_master_oid="$(calc_oid "$(cat a.txt)")"
+
+  git checkout refs/remotes/origin/master
+  md_remote_oid="$(calc_oid "$(cat a.md)")"
+  txt_remote_oid="$(calc_oid "$(cat a.txt)")"
+  git checkout master
+
+  git tag pseudo-remote "$(git rev-parse refs/remotes/origin/master)"
+  # Remove the refs/remotes/origin/master ref, and instruct 'git lfs migrate' to
+  # not fetch it.
+  git update-ref -d refs/remotes/origin/master
+
+  assert_pointer "refs/heads/master" "a.md" "$md_master_oid" "50"
+  assert_pointer "pseudo-remote" "a.md" "$md_remote_oid" "140"
+  assert_pointer "refs/heads/master" "a.txt" "$txt_master_oid" "30"
+  assert_pointer "pseudo-remote" "a.txt" "$txt_remote_oid" "120"
+
+  git lfs migrate export --skip-fetch --include="*.md,*.txt"
+
+  refute_pointer "refs/heads/master" "a.md"
+  refute_pointer "pseudo-remote" "a.md"
+  refute_pointer "refs/heads/master" "a.txt"
+  refute_pointer "pseudo-remote" "a.txt"
+
+  refute_local_object "$md_master_oid" "50"
+  refute_local_object "$md_remote_oid" "140"
+  refute_local_object "$txt_master_oid" "30"
+  refute_local_object "$txt_remote_oid" "120"
+
+  master="$(git rev-parse refs/heads/master)"
+  remote="$(git rev-parse pseudo-remote)"
+
+  master_attrs="$(git cat-file -p "$master:.gitattributes")"
+  remote_attrs="$(git cat-file -p "$remote:.gitattributes")"
+
+  echo "$master_attrs" | grep -q "*.md text !filter !merge !diff"
+  echo "$master_attrs" | grep -q "*.txt text !filter !merge !diff"
+  echo "$remote_attrs" | grep -q "*.md text !filter !merge !diff"
+  echo "$remote_attrs" | grep -q "*.txt text !filter !merge !diff"
+)
+end_test
+
+begin_test "migrate export (include/exclude ref)"
+(
+  set -e
+
+  setup_multiple_remote_branches_gitattrs
+
+  md_master_oid="$(calc_oid "$(cat a.md)")"
+  txt_master_oid="$(calc_oid "$(cat a.txt)")"
+
+  git checkout refs/remotes/origin/master
+  md_remote_oid="$(calc_oid "$(cat a.md)")"
+  txt_remote_oid="$(calc_oid "$(cat a.txt)")"
+
+  git checkout my-feature
+  md_feature_oid="$(calc_oid "$(cat a.md)")"
+  txt_feature_oid="$(calc_oid "$(cat a.txt)")"
+
+  git checkout master
+
+  git lfs migrate export \
+    --include="*.txt" \
+    --include-ref=refs/heads/my-feature \
+    --exclude-ref=refs/heads/master
+
+  assert_pointer "refs/heads/master" "a.md" "$md_master_oid" "21"
+  assert_pointer "refs/heads/master" "a.txt" "$txt_master_oid" "20"
+
+  assert_pointer "refs/remotes/origin/master" "a.md" "$md_remote_oid" "11"
+  assert_pointer "refs/remotes/origin/master" "a.txt" "$txt_remote_oid" "10"
+
+  assert_pointer "refs/heads/my-feature" "a.md" "$md_feature_oid" "31"
+  refute_pointer "refs/heads/my-feature" "a.txt"
+
+  # Master objects should not be pruned as they exist in unpushed commits
+  assert_local_object "$md_master_oid" "21"
+  assert_local_object "$txt_master_oid" "20"
+
+  # Remote master objects should be pruned as they exist in the remote
+  refute_local_object "$md_remote_oid" "11"
+  refute_local_object "$txt_remote_oid" "10"
+
+  # txt_feature_oid should be pruned as it's no longer a pointer, but
+  # md_feature_oid should remain as it's still a pointer in unpushed commits
+  assert_local_object "$md_feature_oid" "31"
+  refute_local_object "$txt_feature_oid" "30"
+
+  master="$(git rev-parse refs/heads/master)"
+  feature="$(git rev-parse refs/heads/my-feature)"
+  remote="$(git rev-parse refs/remotes/origin/master)"
+
+  master_attrs="$(git cat-file -p "$master:.gitattributes")"
+  remote_attrs="$(git cat-file -p "$remote:.gitattributes")"
+  feature_attrs="$(git cat-file -p "$feature:.gitattributes")"
+
+  [ ! $(echo "$master_attrs" | grep -q "*.txt text !filter !merge !diff") ]
+  [ ! $(echo "$remote_attrs" | grep -q "*.txt text !filter !merge !diff") ]
+  echo "$feature_attrs" | grep -q "*.txt text !filter !merge !diff"
+)
+end_test
+
+begin_test "migrate export (--object-map)"
+(
+  set -e
+
+  setup_multiple_local_branches_tracked
+
+  output_dir=$(mktemp -d)
+
+  git log --all --pretty='format:%H' > "${output_dir}/old_sha.txt"
+  git lfs migrate export --everything --include="*" --object-map "${output_dir}/object-map.txt"
+  git log --all --pretty='format:%H' > "${output_dir}/new_sha.txt"
+  paste -d',' "${output_dir}/old_sha.txt" "${output_dir}/new_sha.txt" > "${output_dir}/expected-map.txt"
+
+  diff -u <(sort "${output_dir}/expected-map.txt") <(sort "${output_dir}/object-map.txt")
+)
+end_test
+
+begin_test "migrate export (--verbose)"
+(
+  set -e
+
+  setup_multiple_local_branches_tracked
+
+  git lfs migrate export --everything --include="*" --verbose 2>&1 | grep -q "migrate: commit "
+)
+end_test
+
+begin_test "migrate export (--remote)"
+(
+  set -e
+
+  setup_single_remote_branch_tracked
+
+  git push origin master
+
+  md_oid="$(calc_oid "$(cat a.md)")"
+  txt_oid="$(calc_oid "$(cat a.txt)")"
+
+  assert_pointer "refs/heads/master" "a.md" "$md_oid" "50"
+  assert_pointer "refs/heads/master" "a.txt" "$txt_oid" "30"
+
+  # Flush the cache to ensure all objects have to be downloaded
+  rm -rf .git/lfs/objects
+
+  # Setup a new remote and invalidate the default
+  remote_url="$(git config --get remote.origin.url)"
+  git remote add zeta "$remote_url"
+  git remote set-url origin ""
+
+  git lfs migrate export --everything --remote="zeta" --include="*.md, *.txt"
+
+  refute_pointer "refs/heads/master" "a.md"
+  refute_pointer "refs/heads/master" "a.txt"
+
+  refute_local_object "$md_oid" "50"
+  refute_local_object "$txt_oid" "30"
+)
+end_test
+
+begin_test "migrate export (invalid --remote)"
+(
+  set -e
+
+  setup_single_remote_branch_tracked
+
+  git lfs migrate export --include="*" --remote="zz" --yes 2>&1 \
+    | tee migrate.log
+  if [ ${PIPESTATUS[0]} -eq 0 ]; then
+    echo >&2 "fatal: expected git lfs migrate export to fail, didn't"
+    exit 1
+  fi
+
+  grep "fatal: invalid remote zz provided" migrate.log
+)
+end_test
diff --git a/t/t-migrate-fixup.sh b/t/t-migrate-fixup.sh
new file mode 100755 (executable)
index 0000000..17f5039
--- /dev/null
@@ -0,0 +1,102 @@
+#!/usr/bin/env bash
+
+. "$(dirname "$0")/fixtures/migrate.sh"
+. "$(dirname "$0")/testlib.sh"
+
+begin_test "migrate import (--fixup)"
+(
+  set -e
+
+  setup_single_local_branch_tracked_corrupt
+
+  txt_oid="$(calc_oid "$(git cat-file -p :a.txt)")"
+
+  git lfs migrate import --everything --fixup --yes
+
+  assert_pointer "refs/heads/master" "a.txt" "$txt_oid" "120"
+  assert_local_object "$txt_oid" "120"
+
+  master="$(git rev-parse refs/heads/master)"
+  master_attrs="$(git cat-file -p "$master:.gitattributes")"
+  echo "$master_attrs" | grep -q "*.txt filter=lfs diff=lfs merge=lfs"
+)
+end_test
+
+begin_test "migrate import (--fixup, complex nested)"
+(
+  set -e
+
+  setup_single_local_branch_complex_tracked
+
+  a_oid="$(calc_oid "$(git cat-file -p :a.txt)")"
+  b_oid="$(calc_oid "$(git cat-file -p :dir/b.txt)")"
+
+  git lfs migrate import --everything --fixup --yes
+
+  assert_pointer "refs/heads/master" "a.txt" "$a_oid" "1"
+  refute_pointer "refs/heads/master" "b.txt"
+
+  assert_local_object "$a_oid" "1"
+  refute_local_object "$b_oid" "1"
+
+  master="$(git rev-parse refs/heads/master)"
+  master_attrs="$(git cat-file -p "$master:.gitattributes")"
+  master_dir_attrs="$(git cat-file -p "$master:dir/.gitattributes")"
+  echo "$master_attrs" | grep -q "*.txt filter=lfs diff=lfs merge=lfs"
+  echo "$master_dir_attrs" | grep -q "*.txt !filter !diff !merge"
+)
+end_test
+
+begin_test "migrate import (--fixup, --include)"
+(
+  set -e
+
+  setup_single_local_branch_tracked_corrupt
+
+  git lfs migrate import --everything --fixup --yes --include="*.txt" 2>&1 \
+    | tee migrate.log
+
+  if [ "${PIPESTATUS[0]}" -eq 0 ]; then
+    echo >&2 "fatal: expected 'git lfs migrate ...' to fail, didn't ..."
+    exit 1
+  fi
+
+  grep -q "fatal: cannot use --fixup with --include, --exclude" migrate.log
+)
+end_test
+
+begin_test "migrate import (--fixup, --exclude)"
+(
+  set -e
+
+  setup_single_local_branch_tracked_corrupt
+
+  git lfs migrate import --everything --fixup --yes --exclude="*.txt" 2>&1 \
+    | tee migrate.log
+
+  if [ "${PIPESTATUS[0]}" -eq 0 ]; then
+    echo >&2 "fatal: expected 'git lfs migrate ...' to fail, didn't ..."
+    exit 1
+  fi
+
+  grep -q "fatal: cannot use --fixup with --include, --exclude" migrate.log
+)
+end_test
+
+begin_test "migrate import (--fixup, --no-rewrite)"
+(
+  set -e
+
+  setup_single_local_branch_tracked_corrupt
+
+  git lfs migrate import --everything --fixup --yes --no-rewrite 2>&1 \
+    | tee migrate.log
+
+  if [ "${PIPESTATUS[0]}" -eq 0 ]; then
+    echo >&2 "fatal: expected 'git lfs migrate ...' to fail, didn't ..."
+    exit 1
+  fi
+
+  grep -q "fatal: --no-rewrite and --fixup cannot be combined" migrate.log
+)
+end_test
diff --git a/t/t-migrate-import-no-rewrite.sh b/t/t-migrate-import-no-rewrite.sh
new file mode 100755 (executable)
index 0000000..d59883c
--- /dev/null
@@ -0,0 +1,224 @@
+#!/usr/bin/env bash
+
+. "$(dirname "$0")/fixtures/migrate.sh"
+. "$(dirname "$0")/testlib.sh"
+
+begin_test "migrate import --no-rewrite (default branch)"
+(
+  set -e
+
+  setup_local_branch_with_gitattrs
+
+  txt_oid="$(calc_oid "$(git cat-file -p :a.txt)")"
+  prev_commit_oid="$(git rev-parse HEAD)"
+
+  git lfs migrate import --no-rewrite --yes *.txt
+
+  # Ensure our desired files were imported into git-lfs
+  assert_pointer "refs/heads/master" "a.txt" "$txt_oid" "120"
+  assert_local_object "$txt_oid" "120"
+
+  # Ensure the git history remained the same
+  new_commit_oid="$(git rev-parse HEAD~1)"
+  if [ "$prev_commit_oid" != "$new_commit_oid" ]; then
+    exit 1
+  fi
+
+  # Ensure a new commit was made
+  new_head_oid="$(git rev-parse HEAD)"
+  if [ "$prev_commit_oid" == "$new_oid" ]; then
+    exit 1
+  fi
+
+  # Ensure a new commit message was generated based on the list of imported files
+  commit_msg="$(git log -1 --pretty=format:%s)"
+  echo "$commit_msg" | grep -q "a.txt: convert to Git LFS"
+)
+end_test
+
+begin_test "migrate import --no-rewrite (bare repository)"
+(
+  set -e
+
+  setup_single_remote_branch_with_gitattrs
+
+  prev_commit_oid="$(git rev-parse HEAD)"
+  txt_oid="$(calc_oid "$(git cat-file -p :a.txt)")"
+  md_oid="$(calc_oid "$(git cat-file -p :a.md)")"
+
+  git lfs migrate import --no-rewrite --yes a.txt a.md
+
+  # Ensure our desired files were imported
+  assert_pointer "refs/heads/master" "a.txt" "$txt_oid" "30"
+  assert_pointer "refs/heads/master" "a.md" "$md_oid" "50"
+
+  # Ensure the git history remained the same
+  new_commit_oid="$(git rev-parse HEAD~1)"
+  if [ "$prev_commit_oid" != "$new_commit_oid" ]; then
+    exit 1
+  fi
+
+  # Ensure a new commit was made
+  new_head_oid="$(git rev-parse HEAD)"
+  if [ "$prev_commit_oid" == "$new_oid" ]; then
+    exit 1
+  fi
+)
+end_test
+
+begin_test "migrate import --no-rewrite (multiple branches)"
+(
+  set -e
+
+  setup_multiple_local_branches_with_gitattrs
+
+  prev_commit_oid="$(git rev-parse HEAD)"
+
+  md_oid="$(calc_oid "$(git cat-file -p :a.md)")"
+  txt_oid="$(calc_oid "$(git cat-file -p :a.txt)")"
+  md_feature_oid="$(calc_oid "$(git cat-file -p my-feature:a.md)")"
+
+  git lfs migrate import --no-rewrite --yes *.txt *.md
+
+  # Ensure our desired files were imported
+  assert_pointer "refs/heads/master" "a.md" "$md_oid" "140"
+  assert_pointer "refs/heads/master" "a.txt" "$txt_oid" "120"
+
+  assert_local_object "$md_oid" "140"
+  assert_local_object "$txt_oid" "120"
+
+  # Ensure our other branch was unmodified
+  refute_local_object "$md_feature_oid" "30"
+
+  # Ensure the git history remained the same
+  new_commit_oid="$(git rev-parse HEAD~1)"
+  if [ "$prev_commit_oid" != "$new_commit_oid" ]; then
+    exit 1
+  fi
+
+  # Ensure a new commit was made
+  new_head_oid="$(git rev-parse HEAD)"
+  if [ "$prev_commit_oid" == "$new_oid" ]; then
+    exit 1
+  fi
+)
+end_test
+
+begin_test "migrate import --no-rewrite (no .gitattributes)"
+(
+  set -e
+
+  setup_multiple_local_branches
+
+  # Ensure command fails if no .gitattributes files are present
+  git lfs migrate import --no-rewrite --yes *.txt *.md 2>&1 | tee migrate.log
+  if [ ${PIPESTATUS[0]} -eq 0 ]; then
+    echo >&2 "fatal: expected git lfs migrate import --no-rewrite to fail, didn't"
+    exit 1
+  fi
+
+  grep "no Git LFS filters found in .gitattributes" migrate.log
+)
+end_test
+
+begin_test "migrate import --no-rewrite (nested .gitattributes)"
+(
+  set -e
+
+  setup_local_branch_with_nested_gitattrs
+
+  # Ensure a .md filter does not exist in the top-level .gitattributes
+  master_attrs="$(git cat-file -p "$master:.gitattributes")"
+  [ !"$(echo "$master_attrs" | grep -q ".md")" ]
+
+  # Ensure a .md filter exists in the nested .gitattributes
+  nested_attrs="$(git cat-file -p "$master:b/.gitattributes")"
+  echo "$nested_attrs" | grep -q "*.md filter=lfs diff=lfs merge=lfs"
+
+  md_oid="$(calc_oid "$(git cat-file -p :a.md)")"
+  nested_md_oid="$(calc_oid "$(git cat-file -p :b/a.md)")"
+  txt_oid="$(calc_oid "$(git cat-file -p :a.txt)")"
+
+  git lfs migrate import --no-rewrite --yes a.txt b/a.md
+
+  # Ensure a.txt and subtree/a.md were imported, even though *.md only exists in the
+  # nested subtree/.gitattributes file
+  assert_pointer "refs/heads/master" "b/a.md" "$nested_md_oid" "140"
+  assert_pointer "refs/heads/master" "a.txt" "$txt_oid" "120"
+
+  assert_local_object "$nested_md_oid" 140
+  assert_local_object "$txt_oid" 120
+  refute_local_object "$md_oid" 140
+
+  # Failure should occur when trying to import a.md as no entry exists in
+  # top-level .gitattributes file
+  git lfs migrate import --no-rewrite --yes a.md 2>&1 | tee migrate.log
+  if [ ${PIPESTATUS[0]} -eq 0 ]; then
+    echo >&2 "fatal: expected git lfs migrate import --no-rewrite to fail, didn't"
+    exit 1
+  fi
+
+  grep "a.md did not match any Git LFS filters in .gitattributes" migrate.log
+)
+end_test
+
+begin_test "migrate import --no-rewrite (with commit message)"
+(
+  set -e
+
+  setup_local_branch_with_gitattrs
+
+  prev_commit_oid="$(git rev-parse HEAD)"
+  expected_commit_msg="run git-lfs migrate import --no-rewrite"
+
+  git lfs migrate import --message "$expected_commit_msg" --no-rewrite --yes *.txt
+
+  # Ensure the git history remained the same
+  new_commit_oid="$(git rev-parse HEAD~1)"
+  if [ "$prev_commit_oid" != "$new_commit_oid" ]; then
+    exit 1
+  fi
+
+  # Ensure a new commit was made
+  new_head_oid="$(git rev-parse HEAD)"
+  if [ "$prev_commit_oid" == "$new_oid" ]; then
+    exit 1
+  fi
+
+  # Ensure the provided commit message was used
+  commit_msg="$(git log -1 --pretty=format:%s)"
+  if [ "$commit_msg" != "$expected_commit_msg" ]; then
+    exit 1
+  fi
+)
+end_test
+
+begin_test "migrate import --no-rewrite (with empty commit message)"
+(
+  set -e
+
+  setup_local_branch_with_gitattrs
+
+  prev_commit_oid="$(git rev-parse HEAD)"
+
+  git lfs migrate import -m "" --no-rewrite --yes *.txt
+
+  # Ensure the git history remained the same
+  new_commit_oid="$(git rev-parse HEAD~1)"
+  if [ "$prev_commit_oid" != "$new_commit_oid" ]; then
+    exit 1
+  fi
+
+  # Ensure a new commit was made
+  new_head_oid="$(git rev-parse HEAD)"
+  if [ "$prev_commit_oid" == "$new_oid" ]; then
+    exit 1
+  fi
+
+  # Ensure the provided commit message was used
+  commit_msg="$(git log -1 --pretty=format:%s)"
+  if [ "$commit_msg" != "" ]; then
+    exit 1
+  fi
+)
+end_test
similarity index 85%
rename from test/test-migrate-import.sh
rename to t/t-migrate-import.sh
index 6adcb09..6e79f3c 100755 (executable)
@@ -1,7 +1,7 @@
 #!/usr/bin/env bash
 
-. "test/test-migrate-fixtures.sh"
-. "test/testlib.sh"
+. "$(dirname "$0")/fixtures/migrate.sh"
+. "$(dirname "$0")/testlib.sh"
 
 begin_test "migrate import (default branch)"
 (
@@ -417,7 +417,7 @@ begin_test "migrate import (existing .gitattributes)"
 
   txt_master_oid="$(calc_oid "$(git cat-file -p "$master:a.txt")")"
 
-  git lfs migrate import --include-ref=refs/heads/master --include="*.txt"
+  git lfs migrate import --yes --include-ref=refs/heads/master --include="*.txt"
 
   assert_local_object "$txt_master_oid" "120"
 
@@ -617,6 +617,23 @@ begin_test "migrate import (handle copies of files)"
 )
 end_test
 
+begin_test "migrate import (--object-map)"
+(
+  set -e
+
+  setup_multiple_local_branches
+
+  output_dir=$(mktemp -d)
+
+  git log --all --pretty='format:%H' > "${output_dir}/old_sha.txt"
+  git lfs migrate import --everything --object-map "${output_dir}/object-map.txt"
+  git log --all --pretty='format:%H' > "${output_dir}/new_sha.txt"
+  paste -d',' "${output_dir}/old_sha.txt" "${output_dir}/new_sha.txt" > "${output_dir}/expected-map.txt"
+
+  diff -u <(sort "${output_dir}/expected-map.txt") <(sort "${output_dir}/object-map.txt")
+)
+end_test
+
 begin_test "migrate import (--include with space)"
 (
   set -e
@@ -656,3 +673,119 @@ begin_test "migrate import (handle symbolic link)"
   refute_local_object "$link_oid" "5"
 )
 end_test
+
+begin_test "migrate import (commit --allow-empty)"
+(
+  set -e
+
+  reponame="migrate---allow-empty"
+  git init "$reponame"
+  cd "$reponame"
+
+  git commit --allow-empty -m "initial commit"
+
+  original_head="$(git rev-parse HEAD)"
+  git lfs migrate import --everything
+  migrated_head="$(git rev-parse HEAD)"
+
+  assert_ref_unmoved "HEAD" "$original_head" "$migrated_head"
+)
+end_test
+
+begin_test "migrate import (multiple remotes)"
+(
+  set -e
+
+  setup_multiple_remotes
+
+  original_master="$(git rev-parse master)"
+
+  git lfs migrate import
+
+  migrated_master="$(git rev-parse master)"
+
+  assert_ref_unmoved "master" "$original_master" "$migrated_master"
+)
+end_test
+
+begin_test "migrate import (dirty copy, negative answer)"
+(
+  set -e
+
+  setup_local_branch_with_dirty_copy
+
+  original_master="$(git rev-parse master)"
+
+  echo "n" | git lfs migrate import --everything 2>&1 | tee migrate.log
+  grep "migrate: working copy must not be dirty" migrate.log
+
+  migrated_master="$(git rev-parse master)"
+
+  assert_ref_unmoved "master" "$original_master" "$migrated_master"
+)
+end_test
+
+begin_test "migrate import (dirty copy, unknown then negative answer)"
+(
+  set -e
+
+  setup_local_branch_with_dirty_copy
+
+  original_master="$(git rev-parse master)"
+
+  echo "x\nn" | git lfs migrate import --everything 2>&1 | tee migrate.log
+
+  cat migrate.log
+
+  [ "2" -eq "$(grep -o "override changes in your working copy" migrate.log \
+    | wc -l | awk '{ print $1 }')" ]
+  grep "migrate: working copy must not be dirty" migrate.log
+
+  migrated_master="$(git rev-parse master)"
+
+  assert_ref_unmoved "master" "$original_master" "$migrated_master"
+)
+end_test
+
+begin_test "migrate import (dirty copy, positive answer)"
+(
+  set -e
+
+  setup_local_branch_with_dirty_copy
+
+  oid="$(calc_oid "$(git cat-file -p :a.txt)")"
+
+  echo "y" | git lfs migrate import --everything 2>&1 | tee migrate.log
+  grep "migrate: changes in your working copy will be overridden ..." \
+    migrate.log
+
+  assert_pointer "refs/heads/master" "a.txt" "$oid" "5"
+  assert_local_object "$oid" "5"
+)
+end_test
+
+begin_test "migrate import (non-standard refs)"
+(
+  set -e
+
+  setup_multiple_local_branches_non_standard
+
+  md_oid="$(calc_oid "$(git cat-file -p :a.md)")"
+  txt_oid="$(calc_oid "$(git cat-file -p :a.txt)")"
+  md_feature_oid="$(calc_oid "$(git cat-file -p my-feature:a.md)")"
+
+  git lfs migrate import --everything
+
+  assert_pointer "refs/heads/master" "a.md" "$md_oid" "140"
+  assert_pointer "refs/heads/master" "a.txt" "$txt_oid" "120"
+  assert_pointer "refs/pull/1/base" "a.md" "$md_oid" "140"
+  assert_pointer "refs/pull/1/base" "a.txt" "$txt_oid" "120"
+
+  assert_pointer "refs/heads/my-feature" "a.txt" "$txt_oid" "120"
+  assert_pointer "refs/pull/1/head" "a.txt" "$txt_oid" "120"
+
+  assert_local_object "$md_oid" "140"
+  assert_local_object "$txt_oid" "120"
+  assert_local_object "$md_feature_oid" "30"
+)
+end_test
similarity index 99%
rename from test/test-migrate-info.sh
rename to t/t-migrate-info.sh
index 62a8de0..a463089 100755 (executable)
@@ -1,7 +1,7 @@
 #!/usr/bin/env bash
 
-. "test/test-migrate-fixtures.sh"
-. "test/testlib.sh"
+. "$(dirname "$0")/fixtures/migrate.sh"
+. "$(dirname "$0")/testlib.sh"
 
 begin_test "migrate info (default branch)"
 (
similarity index 94%
rename from test/test-object-authenticated.sh
rename to t/t-object-authenticated.sh
index 4f16247..228550c 100755 (executable)
@@ -1,6 +1,6 @@
 #!/usr/bin/env bash
 
-. "test/testlib.sh"
+. "$(dirname "$0")/testlib.sh"
 
 # these tests rely on GIT_TERMINAL_PROMPT to test properly
 ensure_git_version_isnt $VERSION_LOWER "2.3.0"
similarity index 98%
rename from test/test-pointer.sh
rename to t/t-pointer.sh
index 8f93da1..dc49366 100755 (executable)
@@ -1,6 +1,6 @@
 #!/usr/bin/env bash
 
-. "test/testlib.sh"
+. "$(dirname "$0")/testlib.sh"
 
 
 begin_test "pointer --file --stdin"
@@ -110,6 +110,7 @@ begin_test "pointer --stdin without stdin"
 
   [ "1" = "$status" ]
 )
+end_test
 
 begin_test "pointer --stdin with bad pointer"
 (
@@ -126,6 +127,7 @@ Pointer file error: invalid header"
 
   [ "1" = "$status" ]
 )
+end_test
 
 begin_test "pointer --file --pointer mismatch"
 (
@@ -239,7 +241,7 @@ begin_test "pointer invalid --pointer"
 
   expected="Pointer from some-pointer
 
-Pointer file error: invalid header
+Pointer file error: invalid header"
 
   diff -u <(printf "$expected") <(printf "$output")
 
similarity index 99%
rename from test/test-post-checkout.sh
rename to t/t-post-checkout.sh
index 9ef0b89..0808c69 100755 (executable)
@@ -1,6 +1,6 @@
 #!/usr/bin/env bash
 
-. "test/testlib.sh"
+. "$(dirname "$0")/testlib.sh"
 
 begin_test "post-checkout"
 (
similarity index 98%
rename from test/test-post-commit.sh
rename to t/t-post-commit.sh
index ba489e1..3751d71 100755 (executable)
@@ -1,6 +1,6 @@
 #!/usr/bin/env bash
 
-. "test/testlib.sh"
+. "$(dirname "$0")/testlib.sh"
 
 begin_test "post-commit"
 (
similarity index 98%
rename from test/test-post-merge.sh
rename to t/t-post-merge.sh
index 8592da5..2bf3752 100755 (executable)
@@ -1,6 +1,6 @@
 #!/usr/bin/env bash
 
-. "test/testlib.sh"
+. "$(dirname "$0")/testlib.sh"
 
 begin_test "post-merge"
 (
similarity index 99%
rename from test/test-pre-push.sh
rename to t/t-pre-push.sh
index 8772439..f2dae3e 100755 (executable)
@@ -1,6 +1,6 @@
 #!/usr/bin/env bash
 
-. "test/testlib.sh"
+. "$(dirname "$0")/testlib.sh"
 
 begin_test "pre-push with good ref"
 (
@@ -320,7 +320,7 @@ begin_test "pre-push with missing pointer which is on server"
 )
 end_test
 
-begin_test "pre-push with missing and present pointers"
+begin_test "pre-push with missing and present pointers (lfs.allowincompletepush true)"
 (
   set -e
 
@@ -352,6 +352,8 @@ begin_test "pre-push with missing and present pointers"
   missing_oid_path=".git/lfs/objects/$missing_oid_part_1/$missing_oid_part_2/$missing_oid"
   rm "$missing_oid_path"
 
+  git config lfs.allowincompletepush true
+
   echo "refs/heads/master master refs/heads/master 0000000000000000000000000000000000000000" |
     git lfs pre-push origin "$GITSERVER/$reponame" 2>&1 |
     tee push.log
@@ -369,7 +371,7 @@ begin_test "pre-push with missing and present pointers"
 )
 end_test
 
-begin_test "pre-push allowincompletepush=f reject missing pointers"
+begin_test "pre-push reject missing pointers (lfs.allowincompletepush default)"
 (
   set -e
 
@@ -401,8 +403,6 @@ begin_test "pre-push allowincompletepush=f reject missing pointers"
   missing_oid_path=".git/lfs/objects/$missing_oid_part_1/$missing_oid_part_2/$missing_oid"
   rm "$missing_oid_path"
 
-  git config "lfs.allowincompletepush" "false"
-
   echo "refs/heads/master master refs/heads/master 0000000000000000000000000000000000000000" |
     git lfs pre-push origin "$GITSERVER/$reponame" 2>&1 |
     tee push.log
similarity index 94%
rename from test/test-progress-meter.sh
rename to t/t-progress-meter.sh
index 5c86f11..1f7b9e8 100755 (executable)
@@ -1,6 +1,6 @@
 #!/usr/bin/env bash
 
-. "test/testlib.sh"
+. "$(dirname "$0")/testlib.sh"
 
 begin_test "progress meter displays positive progress"
 (
similarity index 97%
rename from test/test-progress.sh
rename to t/t-progress.sh
index 38a077f..b8303fe 100755 (executable)
@@ -1,6 +1,6 @@
 #!/usr/bin/env bash
 
-. "test/testlib.sh"
+. "$(dirname "$0")/testlib.sh"
 
 reponame="$(basename "$0" ".sh")"
 
similarity index 99%
rename from test/test-prune-worktree.sh
rename to t/t-prune-worktree.sh
index 582cc82..e443b06 100755 (executable)
@@ -1,6 +1,6 @@
 #!/usr/bin/env bash
 
-. "test/testlib.sh"
+. "$(dirname "$0")/testlib.sh"
 
 ensure_git_version_isnt $VERSION_LOWER "2.5.0"
 
similarity index 99%
rename from test/test-prune.sh
rename to t/t-prune.sh
index abe6fea..df37cd8 100755 (executable)
@@ -1,6 +1,6 @@
 #!/usr/bin/env bash
 
-. "test/testlib.sh"
+. "$(dirname "$0")/testlib.sh"
 
 begin_test "prune unreferenced and old"
 (
similarity index 97%
rename from test/test-pull.sh
rename to t/t-pull.sh
index ca10758..b46eaa3 100755 (executable)
@@ -1,6 +1,6 @@
 #!/usr/bin/env bash
 
-. "test/testlib.sh"
+. "$(dirname "$0")/testlib.sh"
 
 begin_test "pull"
 (
@@ -149,7 +149,7 @@ begin_test "pull without clean filter"
 (
   set -e
 
-  GIT_LFS_SKIP_SMUDGE=1 git clone $GITSERVER/test-pull no-clean
+  GIT_LFS_SKIP_SMUDGE=1 git clone $GITSERVER/t-pull no-clean
   cd no-clean
   git lfs uninstall
   git config --list > config.txt
@@ -198,7 +198,7 @@ begin_test "pull with raw remote url"
   git init
   git lfs install --local --skip-smudge
 
-  git remote add origin $GITSERVER/test-pull
+  git remote add origin $GITSERVER/t-pull
   git pull origin master
 
   contents="a"
@@ -208,7 +208,7 @@ begin_test "pull with raw remote url"
   refute_local_object "$contents_oid"
   grep "$contents_oid" a.dat
 
-  git lfs pull "$GITSERVER/test-pull"
+  git lfs pull "$GITSERVER/t-pull"
   echo "pulled!"
 
   # LFS object downloaded and in working directory
similarity index 95%
rename from test/test-push-bad-dns.sh
rename to t/t-push-bad-dns.sh
index ca0e401..99f8b9d 100755 (executable)
@@ -1,6 +1,6 @@
 #!/usr/bin/env bash
 
-. "test/testlib.sh"
+. "$(dirname "$0")/testlib.sh"
 
 ensure_git_version_isnt $VERSION_LOWER "2.3.0"
 
diff --git a/t/t-push-failures-local.sh b/t/t-push-failures-local.sh
new file mode 100755 (executable)
index 0000000..ef2d755
--- /dev/null
@@ -0,0 +1,198 @@
+#!/usr/bin/env bash
+
+. "$(dirname "$0")/testlib.sh"
+
+begin_test "push with missing objects (lfs.allowincompletepush true)"
+(
+  set -e
+
+  reponame="push-with-missing-objects"
+  setup_remote_repo "$reponame"
+  clone_repo "$reponame" "$reponame"
+
+  git lfs track "*.dat"
+  git add .gitattributes
+  git commit -m "initial commit"
+
+  present="present"
+  present_oid="$(calc_oid "$present")"
+  printf "$present" > present.dat
+
+  missing="missing"
+  missing_oid="$(calc_oid "$missing")"
+  printf "$missing" > missing.dat
+
+  git add missing.dat present.dat
+  git commit -m "add objects"
+
+  git rm missing.dat
+  git commit -m "remove missing"
+
+  # :fire: the "missing" object
+  missing_oid_part_1="$(echo "$missing_oid" | cut -b 1-2)"
+  missing_oid_part_2="$(echo "$missing_oid" | cut -b 3-4)"
+  missing_oid_path=".git/lfs/objects/$missing_oid_part_1/$missing_oid_part_2/$missing_oid"
+  rm "$missing_oid_path"
+
+  git config lfs.allowincompletepush true
+
+  git push origin master 2>&1 | tee push.log
+  if [ "0" -ne "${PIPESTATUS[0]}" ]; then
+    echo >&2 "fatal: expected \`git push origin master\` to succeed ..."
+    exit 1
+  fi
+
+  grep "LFS upload missing objects" push.log
+  grep "  (missing) missing.dat ($missing_oid)" push.log
+
+  assert_server_object "$reponame" "$present_oid"
+  refute_server_object "$reponame" "$missing_oid"
+)
+end_test
+
+begin_test "push reject missing objects (lfs.allowincompletepush false)"
+(
+  set -e
+
+  reponame="push-reject-missing-objects"
+  setup_remote_repo "$reponame"
+  clone_repo "$reponame" "$reponame"
+
+  git lfs track "*.dat"
+  git add .gitattributes
+  git commit -m "initial commit"
+
+  present="present"
+  present_oid="$(calc_oid "$present")"
+  printf "$present" > present.dat
+
+  missing="missing"
+  missing_oid="$(calc_oid "$missing")"
+  printf "$missing" > missing.dat
+
+  git add missing.dat present.dat
+  git commit -m "add objects"
+
+  git rm missing.dat
+  git commit -m "remove missing"
+
+  # :fire: the "missing" object
+  missing_oid_part_1="$(echo "$missing_oid" | cut -b 1-2)"
+  missing_oid_part_2="$(echo "$missing_oid" | cut -b 3-4)"
+  missing_oid_path=".git/lfs/objects/$missing_oid_part_1/$missing_oid_part_2/$missing_oid"
+  rm "$missing_oid_path"
+
+  git config lfs.allowincompletepush false
+
+  git push origin master 2>&1 | tee push.log
+  if [ "1" -ne "${PIPESTATUS[0]}" ]; then
+    echo >&2 "fatal: expected \`git push origin master\` to succeed ..."
+    exit 1
+  fi
+
+  grep "no such file or directory" push.log || # unix
+    grep "cannot find the file" push.log       # windows
+  grep "failed to push some refs" push.log
+
+  refute_server_object "$reponame" "$present_oid"
+  refute_server_object "$reponame" "$missing_oid"
+)
+end_test
+
+begin_test "push reject missing objects (lfs.allowincompletepush default)"
+(
+  set -e
+
+  reponame="push-missing-objects"
+  setup_remote_repo "$reponame"
+  clone_repo "$reponame" "$reponame"
+
+  git lfs track "*.dat"
+  git add .gitattributes
+  git commit -m "initial commit"
+
+  missing="missing"
+  missing_oid="$(calc_oid "$missing")"
+  missing_len="$(printf "$missing" | wc -c | awk '{ print $1 }')"
+  printf "$missing" > missing.dat
+  git add missing.dat
+  git commit -m "add missing.dat"
+
+  present="present"
+  present_oid="$(calc_oid "$present")"
+  present_len="$(printf "$present" | wc -c | awk '{ print $1 }')"
+  printf "$present" > present.dat
+  git add present.dat
+  git commit -m "add present.dat"
+
+  assert_local_object "$missing_oid" "$missing_len"
+  assert_local_object "$present_oid" "$present_len"
+
+  delete_local_object "$missing_oid"
+
+  refute_local_object "$missing_oid"
+  assert_local_object "$present_oid" "$present_len"
+
+  git push origin master 2>&1 | tee push.log
+
+  if [ "0" -eq "${PIPESTATUS[0]}" ]; then
+    echo >&2 "fatal: expected 'git push origin master' to exit with non-zero code"
+    exit 1
+  fi
+
+  grep "LFS upload failed:" push.log
+  grep "  (missing) missing.dat ($missing_oid)" push.log
+
+  refute_server_object "$reponame" "$missing_oid"
+  assert_server_object "$reponame" "$present_oid"
+)
+end_test
+
+begin_test "push reject corrupt objects (lfs.allowincompletepush default)"
+(
+  set -e
+
+  reponame="push-corrupt-objects"
+  setup_remote_repo "$reponame"
+  clone_repo "$reponame" "$reponame"
+
+  git lfs track "*.dat"
+  git add .gitattributes
+  git commit -m "initial commit"
+
+  corrupt="corrupt"
+  corrupt_oid="$(calc_oid "$corrupt")"
+  corrupt_len="$(printf "$corrupt" | wc -c | awk '{ print $1 }')"
+  printf "$corrupt" > corrupt.dat
+  git add corrupt.dat
+  git commit -m "add corrupt.dat"
+
+  present="present"
+  present_oid="$(calc_oid "$present")"
+  present_len="$(printf "$present" | wc -c | awk '{ print $1 }')"
+  printf "$present" > present.dat
+  git add present.dat
+  git commit -m "add present.dat"
+
+  assert_local_object "$corrupt_oid" "$corrupt_len"
+  assert_local_object "$present_oid" "$present_len"
+
+  corrupt_local_object "$corrupt_oid"
+
+  refute_local_object "$corrupt_oid" "$corrupt_len"
+  assert_local_object "$present_oid" "$present_len"
+
+  git push origin master 2>&1 | tee push.log
+
+  if [ "0" -eq "${PIPESTATUS[0]}" ]; then
+    echo >&2 "fatal: expected 'git push origin master' to exit with non-zero code"
+    exit 1
+  fi
+
+  grep "LFS upload failed:" push.log
+  grep "  (corrupt) corrupt.dat ($corrupt_oid)" push.log
+
+  refute_server_object "$reponame" "$corrupt_oid"
+  assert_server_object "$reponame" "$present_oid"
+)
+end_test
similarity index 98%
rename from test/test-push-failures.sh
rename to t/t-push-failures-remote.sh
index 30b2050..b5b6c8a 100755 (executable)
@@ -1,6 +1,6 @@
 #!/usr/bin/env bash
 
-. "test/testlib.sh"
+. "$(dirname "$0")/testlib.sh"
 
 # push_fail_test preforms a test expecting a `git lfs push` to fail given the
 # contents of a particular file contained within that push. The Git server used
similarity index 93%
rename from test/test-push-file-with-branch-name.sh
rename to t/t-push-file-with-branch-name.sh
index 0655d05..7ba4f42 100755 (executable)
@@ -1,6 +1,6 @@
 #!/usr/bin/env bash
 
-. "test/testlib.sh"
+. "$(dirname "$0")/testlib.sh"
 
 begin_test "push a file with the same name as a branch"
 (
similarity index 85%
rename from test/test-push.sh
rename to t/t-push.sh
index be22229..48ee3ee 100755 (executable)
@@ -1,11 +1,12 @@
 #!/usr/bin/env bash
 
-. "test/testlib.sh"
+. "$(dirname "$0")/testlib.sh"
 
-begin_test "push with good ref"
-(
-  set -e
-  reponame="push-master-branch-required"
+# sets up the repos for the first few push tests. The passed argument is the
+# name of the repo to setup. The resuling repo will have a local file tracked
+# with LFS and committed, but not yet pushed to the remote
+push_repo_setup() {
+  reponame="$1"
   setup_remote_repo "$reponame"
   clone_repo "$reponame" "$reponame"
 
@@ -14,6 +15,12 @@ begin_test "push with good ref"
   echo "push a" > a.dat
   git add .gitattributes a.dat
   git commit -m "add a.dat"
+}
+
+begin_test "push with good ref"
+(
+  set -e
+  push_repo_setup "push-master-branch-required"
 
   git lfs push origin master
 )
@@ -22,15 +29,8 @@ end_test
 begin_test "push with tracked ref"
 (
   set -e
-  reponame="push-tracked-branch-required"
-  setup_remote_repo "$reponame"
-  clone_repo "$reponame" "$reponame"
 
-  git config "lfs.$(repo_endpoint "$GITSERVER" "$reponame").locksverify" false
-  git lfs track "*.dat"
-  echo "push a" > a.dat
-  git add .gitattributes a.dat
-  git commit -m "add a.dat"
+  push_repo_setup "push-tracked-branch-required"
 
   git config push.default upstream
   git config branch.master.merge refs/heads/tracked
@@ -41,15 +41,7 @@ end_test
 begin_test "push with bad ref"
 (
   set -e
-  reponame="push-other-branch-required"
-  setup_remote_repo "$reponame"
-  clone_repo "$reponame" "$reponame"
-
-  git config "lfs.$(repo_endpoint "$GITSERVER" "$reponame").locksverify" false
-  git lfs track "*.dat"
-  echo "push a" > a.dat
-  git add .gitattributes a.dat
-  git commit -m "add a.dat"
+  push_repo_setup "push-other-branch-required"
 
   git lfs push origin master 2>&1 | tee push.log
   if [ "0" -eq "${PIPESTATUS[0]}" ]; then
@@ -61,6 +53,19 @@ begin_test "push with bad ref"
 )
 end_test
 
+begin_test "push with given remote, configured pushRemote"
+(
+  set -e
+  push_repo_setup "push-given-and-config"
+
+  git remote add bad-remote "invalid-url"
+
+  git config branch.master.pushRemote bad-remote
+
+  git lfs push --all origin
+)
+end_test
+
 begin_test "push"
 (
   set -e
@@ -661,98 +666,4 @@ begin_test "push with deprecated _links"
 
   assert_server_object "$reponame" "$contents_oid"
 )
-
-begin_test "push with missing objects (lfs.allowincompletepush=t)"
-(
-  set -e
-
-  reponame="push-with-missing-objects"
-  setup_remote_repo "$reponame"
-  clone_repo "$reponame" "$reponame"
-
-  git lfs track "*.dat"
-  git add .gitattributes
-  git commit -m "initial commit"
-
-  present="present"
-  present_oid="$(calc_oid "$present")"
-  printf "$present" > present.dat
-
-  missing="missing"
-  missing_oid="$(calc_oid "$missing")"
-  printf "$missing" > missing.dat
-
-  git add missing.dat present.dat
-  git commit -m "add objects"
-
-  git rm missing.dat
-  git commit -m "remove missing"
-
-  # :fire: the "missing" object
-  missing_oid_part_1="$(echo "$missing_oid" | cut -b 1-2)"
-  missing_oid_part_2="$(echo "$missing_oid" | cut -b 3-4)"
-  missing_oid_path=".git/lfs/objects/$missing_oid_part_1/$missing_oid_part_2/$missing_oid"
-  rm "$missing_oid_path"
-
-  git push origin master 2>&1 | tee push.log
-  if [ "0" -ne "${PIPESTATUS[0]}" ]; then
-    echo >&2 "fatal: expected \`git push origin master\` to succeed ..."
-    exit 1
-  fi
-
-  grep "LFS upload missing objects" push.log
-  grep "  (missing) missing.dat ($missing_oid)" push.log
-
-  assert_server_object "$reponame" "$present_oid"
-  refute_server_object "$reponame" "$missing_oid"
-)
-end_test
-
-begin_test "push reject missing objects (lfs.allowincompletepush=f)"
-(
-  set -e
-
-  reponame="push-reject-missing-objects"
-  setup_remote_repo "$reponame"
-  clone_repo "$reponame" "$reponame"
-
-  git lfs track "*.dat"
-  git add .gitattributes
-  git commit -m "initial commit"
-
-  present="present"
-  present_oid="$(calc_oid "$present")"
-  printf "$present" > present.dat
-
-  missing="missing"
-  missing_oid="$(calc_oid "$missing")"
-  printf "$missing" > missing.dat
-
-  git add missing.dat present.dat
-  git commit -m "add objects"
-
-  git rm missing.dat
-  git commit -m "remove missing"
-
-  # :fire: the "missing" object
-  missing_oid_part_1="$(echo "$missing_oid" | cut -b 1-2)"
-  missing_oid_part_2="$(echo "$missing_oid" | cut -b 3-4)"
-  missing_oid_path=".git/lfs/objects/$missing_oid_part_1/$missing_oid_part_2/$missing_oid"
-  rm "$missing_oid_path"
-
-  git config "lfs.allowincompletepush" "false"
-
-  git push origin master 2>&1 | tee push.log
-  if [ "1" -ne "${PIPESTATUS[0]}" ]; then
-    echo >&2 "fatal: expected \`git push origin master\` to succeed ..."
-    exit 1
-  fi
-
-  grep "no such file or directory" push.log || # unix
-    grep "cannot find the file" push.log       # windows
-  grep "failed to push some refs" push.log
-
-  refute_server_object "$reponame" "$present_oid"
-  refute_server_object "$reponame" "$missing_oid"
-)
 end_test
similarity index 98%
rename from test/test-reference-clone.sh
rename to t/t-reference-clone.sh
index 80f4127..039ce45 100755 (executable)
@@ -1,6 +1,6 @@
 #!/usr/bin/env bash
 
-. "test/testlib.sh"
+. "$(dirname "$0")/testlib.sh"
 
 assert_same_inode() {
   local repo1=$1
similarity index 98%
rename from test/test-resume-http-range.sh
rename to t/t-resume-http-range.sh
index 011a302..4751fec 100755 (executable)
@@ -1,6 +1,6 @@
 #!/usr/bin/env bash
 
-. "test/testlib.sh"
+. "$(dirname "$0")/testlib.sh"
 
 begin_test "resume-http-range"
 (
similarity index 98%
rename from test/test-resume-tus.sh
rename to t/t-resume-tus.sh
index 02a986b..3bc5b44 100755 (executable)
@@ -1,6 +1,6 @@
 #!/usr/bin/env bash
 
-. "test/testlib.sh"
+. "$(dirname "$0")/testlib.sh"
 
 begin_test "tus-upload-uninterrupted"
 (
similarity index 99%
rename from test/test-smudge.sh
rename to t/t-smudge.sh
index ea4a5e8..5eb01c4 100755 (executable)
@@ -1,6 +1,6 @@
 #!/usr/bin/env bash
 
-. "test/testlib.sh"
+. "$(dirname "$0")/testlib.sh"
 
 begin_test "smudge"
 (
similarity index 95%
rename from test/test-ssh.sh
rename to t/t-ssh.sh
index 7394d80..6d65543 100755 (executable)
@@ -1,6 +1,6 @@
 #!/usr/bin/env bash
 
-. "test/testlib.sh"
+. "$(dirname "$0")/testlib.sh"
 
 begin_test "ssh with proxy command in lfs.url"
 (
similarity index 94%
rename from test/test-status.sh
rename to t/t-status.sh
index cfe437e..ea83e45 100755 (executable)
@@ -1,6 +1,6 @@
 #!/usr/bin/env bash
 
-. "test/testlib.sh"
+. "$(dirname "$0")/testlib.sh"
 
 begin_test "status"
 (
@@ -119,6 +119,34 @@ begin_test "status --json"
 )
 end_test
 
+begin_test "status in a sub-directory"
+(
+  set -e
+
+  reponame="status-sub-directory"
+  git init "$reponame"
+  cd "$reponame"
+
+  git lfs track "*.dat"
+  printf "asdf" > file.dat
+  mkdir -p dir
+  git add .gitattributes file.dat
+  git commit -m "initial commit"
+
+  printf "ASDF" > file.dat
+
+  expected="On branch master
+
+Git LFS objects to be committed:
+
+
+Git LFS objects not staged for commit:
+
+       ../file.dat (LFS: f0e4c2f -> File: 99b3bcf)"
+
+       [ "$expected" = "$(cd dir && git lfs status)" ]
+)
+end_test
 
 begin_test "status: outside git repository"
 (
similarity index 98%
rename from test/test-submodule-lfsconfig.sh
rename to t/t-submodule-lfsconfig.sh
index cfe1ade..cc15bfe 100755 (executable)
@@ -1,6 +1,6 @@
 #!/usr/bin/env bash
 
-. "test/testlib.sh"
+. "$(dirname "$0")/testlib.sh"
 lfsname="submodule-config-test-lfs"
 reponame="submodule-config-test-repo"
 submodname="submodule-config-test-submodule"
similarity index 98%
rename from test/test-submodule.sh
rename to t/t-submodule.sh
index 828ad1f..c2f71ee 100755 (executable)
@@ -1,6 +1,6 @@
 #!/usr/bin/env bash
 
-. "test/testlib.sh"
+. "$(dirname "$0")/testlib.sh"
 reponame="submodule-test-repo"
 submodname="submodule-test-submodule"
 
similarity index 95%
rename from test/test-track-attrs.sh
rename to t/t-track-attrs.sh
index 31735c5..ad9d40f 100755 (executable)
@@ -1,6 +1,6 @@
 #!/usr/bin/env bash
 
-. "test/testlib.sh"
+. "$(dirname "$0")/testlib.sh"
 
 ensure_git_version_isnt $VERSION_LOWER "2.1.0"
 
old mode 100644 (file)
new mode 100755 (executable)
similarity index 98%
rename from test/test-track-wildcards.sh
rename to t/t-track-wildcards.sh
index fcdce3b..8a6ee70
@@ -1,6 +1,6 @@
 #!/usr/bin/env bash
 
-. "test/testlib.sh"
+. "$(dirname "$0")/testlib.sh"
 
 begin_test "track files using wildcard pattern with leading slash"
 (
similarity index 93%
rename from test/test-track.sh
rename to t/t-track.sh
index 02ff7ce..021ad49 100755 (executable)
@@ -1,6 +1,6 @@
 #!/usr/bin/env bash
 
-. "test/testlib.sh"
+. "$(dirname "$0")/testlib.sh"
 
 begin_test "track"
 (
@@ -558,3 +558,40 @@ begin_test "track (with current-directory prefix)"
   grep -e "^a.dat" .gitattributes
 )
 end_test
+
+begin_test "track (global gitattributes)"
+(
+  set -e
+
+  reponame="track-global-gitattributes"
+  git init "$reponame"
+  cd "$reponame"
+
+  global="$(cd .. && pwd)/gitattributes-global"
+
+  echo "*.dat filter=lfs diff=lfs merge=lfs -text" > "$global"
+  git config --local core.attributesfile "$global"
+
+  git lfs track 2>&1 | tee track.log
+  grep "*.dat" track.log
+)
+end_test
+
+begin_test "track (system gitattributes)"
+(
+  set -e
+
+  reponame="track-system-gitattributes"
+  git init "$reponame"
+  cd "$reponame"
+
+  pushd "$TRASHDIR" > /dev/null
+    mkdir -p "prefix/${reponame}/etc"
+    cd "prefix/${reponame}/etc"
+    echo "*.dat filter=lfs diff=lfs merge=lfs -text" > gitattributes
+  popd > /dev/null
+
+  PREFIX="${TRASHDIR}/prefix/${reponame}" git lfs track 2>&1 | tee track.log
+  grep "*.dat" track.log
+)
+end_test
similarity index 99%
rename from test/test-uninstall.sh
rename to t/t-uninstall.sh
index 82b0734..4dad640 100755 (executable)
@@ -1,6 +1,6 @@
 #!/usr/bin/env bash
 
-. "test/testlib.sh"
+. "$(dirname "$0")/testlib.sh"
 
 begin_test "uninstall outside repository"
 (
similarity index 99%
rename from test/test-unlock.sh
rename to t/t-unlock.sh
index 75195cb..c5d65ea 100755 (executable)
@@ -1,6 +1,6 @@
 #!/usr/bin/env bash
 
-. "test/testlib.sh"
+. "$(dirname "$0")/testlib.sh"
 
 begin_test "unlocking a lock by path with good ref"
 (
similarity index 98%
rename from test/test-untrack.sh
rename to t/t-untrack.sh
index 2e5005e..60b285f 100755 (executable)
@@ -1,6 +1,6 @@
 #!/usr/bin/env bash
 
-. "test/testlib.sh"
+. "$(dirname "$0")/testlib.sh"
 
 begin_test "untrack"
 (
similarity index 94%
rename from test/test-unusual-filenames.sh
rename to t/t-unusual-filenames.sh
index 2f356f5..a3ef40e 100755 (executable)
@@ -1,6 +1,6 @@
 #!/usr/bin/env bash
 
-. "test/testlib.sh"
+. "$(dirname "$0")/testlib.sh"
 
 reponame="$(basename "$0" ".sh")"
 
similarity index 99%
rename from test/test-update.sh
rename to t/t-update.sh
index 8bde210..9af4195 100755 (executable)
@@ -1,6 +1,6 @@
 #!/usr/bin/env bash
 
-. "test/testlib.sh"
+. "$(dirname "$0")/testlib.sh"
 
 begin_test "update"
 (
similarity index 98%
rename from test/test-verify.sh
rename to t/t-verify.sh
index d161381..399868c 100755 (executable)
@@ -1,6 +1,6 @@
 #!/usr/bin/env bash
 
-. "test/testlib.sh"
+. "$(dirname "$0")/testlib.sh"
 
 begin_test "verify with retries"
 (
similarity index 93%
rename from test/test-version.sh
rename to t/t-version.sh
index 31dfdb7..a0218ba 100755 (executable)
@@ -1,6 +1,6 @@
 #!/usr/bin/env bash
 
-. "test/testlib.sh"
+. "$(dirname "$0")/testlib.sh"
 
 begin_test "git lfs --version is a synonym of git lfs version"
 (
similarity index 94%
rename from test/test-worktree.sh
rename to t/t-worktree.sh
index d49f99a..9f2bc87 100755 (executable)
@@ -1,6 +1,6 @@
 #!/usr/bin/env bash
 
-. "test/testlib.sh"
+. "$(dirname "$0")/testlib.sh"
 
 ensure_git_version_isnt $VERSION_LOWER "2.5.0"
 envInitConfig='git config filter.lfs.process = "git-lfs filter-process"
@@ -25,7 +25,7 @@ LocalWorkingDir=$(native_path_escaped "$TRASHDIR/$reponame")
 LocalGitDir=$(native_path_escaped "$TRASHDIR/$reponame/.git")
 LocalGitStorageDir=$(native_path_escaped "$TRASHDIR/$reponame/.git")
 LocalMediaDir=$(native_path_escaped "$TRASHDIR/$reponame/.git/lfs/objects")
-LocalReferenceDir=
+LocalReferenceDirs=
 TempDir=$(native_path_escaped "$TRASHDIR/$reponame/.git/lfs/tmp")
 ConcurrentTransfers=3
 TusTransfers=false
@@ -61,8 +61,8 @@ LocalWorkingDir=$(native_path_escaped "$TRASHDIR/$worktreename")
 LocalGitDir=$(native_path_escaped "$TRASHDIR/$reponame/.git/worktrees/$worktreename")
 LocalGitStorageDir=$(native_path_escaped "$TRASHDIR/$reponame/.git")
 LocalMediaDir=$(native_path_escaped "$TRASHDIR/$reponame/.git/lfs/objects")
-LocalReferenceDir=
-TempDir=$(native_path_escaped "$TRASHDIR/$reponame/.git/worktrees/$worktreename/lfs/tmp")
+LocalReferenceDirs=
+TempDir=$(native_path_escaped "$TRASHDIR/$reponame/.git/lfs/tmp")
 ConcurrentTransfers=3
 TusTransfers=false
 BasicTransfersOnly=false
similarity index 97%
rename from test/test-zero-len-file.sh
rename to t/t-zero-len-file.sh
index ff536e7..6141f32 100755 (executable)
@@ -1,6 +1,6 @@
 #!/usr/bin/env bash
 
-. "test/testlib.sh"
+. "$(dirname "$0")/testlib.sh"
 
 reponame="$(basename "$0" ".sh")"
 
diff --git a/t/test-alternates.sh b/t/test-alternates.sh
new file mode 100755 (executable)
index 0000000..d60a84e
--- /dev/null
@@ -0,0 +1,143 @@
+#!/usr/bin/env bash
+
+. "test/testlib.sh"
+
+begin_test "alternates (single)"
+(
+  set -e
+
+  reponame="alternates-single-alternate"
+  setup_remote_repo_with_file "$reponame" "a.txt"
+
+  pushd "$TRASHDIR" > /dev/null
+    clone_repo "$reponame" "${reponame}_alternate"
+  popd > /dev/null
+
+  rm -rf .git/lfs/objects
+
+  alternate="$TRASHDIR/${reponame}_alternate/.git/objects"
+  echo "$alternate" > .git/objects/info/alternates
+
+  GIT_TRACE=1 git lfs fetch origin master 2>&1 | tee fetch.log
+  [ "0" -eq "$(grep -c "sending batch of size 1" fetch.log)" ]
+)
+end_test
+
+begin_test "alternates (multiple)"
+(
+  set -e
+
+  reponame="alternates-multiple-alternates"
+  setup_remote_repo_with_file "$reponame" "a.txt"
+
+  pushd "$TRASHDIR" > /dev/null
+    clone_repo "$reponame" "${reponame}_alternate_stale"
+    rm -rf .git/lfs/objects
+  popd > /dev/null
+  pushd "$TRASHDIR" > /dev/null
+    clone_repo "$reponame" "${reponame}_alternate"
+  popd > /dev/null
+
+  rm -rf .git/lfs/objects
+
+  alternate_stale="$TRASHDIR/${reponame}_alternate_stale/.git/objects"
+  alternate="$TRASHDIR/${reponame}_alternate/.git/objects"
+  echo "$alternate" > .git/objects/info/alternates
+  echo "$alternate_stale" >> .git/objects/info/alternates
+
+  GIT_TRACE=1 git lfs fetch origin master 2>&1 | tee fetch.log
+  [ "0" -eq "$(grep -c "sending batch of size 1" fetch.log)" ]
+)
+end_test
+
+begin_test "alternates (commented)"
+(
+  set -e
+
+  reponame="alternates-commented-alternate"
+  setup_remote_repo_with_file "$reponame" "a.txt"
+
+  pushd "$TRASHDIR" > /dev/null
+    clone_repo "$reponame" "${reponame}_alternate"
+  popd > /dev/null
+
+  rm -rf .git/lfs/objects
+
+  alternate="$TRASHDIR/${reponame}_alternate/.git/objects"
+  echo "# $alternate" > .git/objects/info/alternates
+
+  GIT_TRACE=1 git lfs fetch origin master 2>&1 | tee fetch.log
+  [ "1" -eq "$(grep -c "sending batch of size 1" fetch.log)" ]
+)
+end_test
+
+begin_test "alternates (quoted)"
+(
+  set -e
+
+  reponame="alternates-quoted-alternate"
+  setup_remote_repo_with_file "$reponame" "a.txt"
+
+  pushd "$TRASHDIR" > /dev/null
+    clone_repo "$reponame" "${reponame}_alternate"
+  popd > /dev/null
+
+  rm -rf .git/lfs/objects
+
+  alternate="$TRASHDIR/${reponame}_alternate/.git/objects"
+  echo "\"$alternate\"" > .git/objects/info/alternates
+
+  GIT_TRACE=1 git lfs fetch origin master 2>&1 | tee fetch.log
+  [ "0" -eq "$(grep -c "sending batch of size 1" fetch.log)" ]
+)
+end_test
+
+begin_test "alternates (OS environment, single)"
+(
+  set -e
+
+  reponame="alternates-environment-single-alternate"
+  setup_remote_repo_with_file "$reponame" "a.txt"
+
+  pushd "$TRASHDIR" > /dev/null
+    clone_repo "$reponame" "${reponame}_alternate"
+  popd > /dev/null
+
+  rm -rf .git/lfs/objects
+
+  alternate="$TRASHDIR/${reponame}_alternate/.git/objects"
+
+  GIT_ALTERNATE_OBJECT_DIRECTORIES="$alternate" \
+  GIT_TRACE=1 \
+    git lfs fetch origin master 2>&1 | tee fetch.log
+  [ "0" -eq "$(grep -c "sending batch of size 1" fetch.log)" ]
+)
+end_test
+
+begin_test "alternates (OS environment, multiple)"
+(
+  set -e
+
+  reponame="alternates-environment-multiple-alternates"
+  setup_remote_repo_with_file "$reponame" "a.txt"
+
+  pushd "$TRASHDIR" > /dev/null
+    clone_repo "$reponame" "${reponame}_alternate_stale"
+    rm -rf .git/lfs/objects
+  popd > /dev/null
+  pushd "$TRASHDIR" > /dev/null
+    clone_repo "$reponame" "${reponame}_alternate"
+  popd > /dev/null
+
+  rm -rf .git/lfs/objects
+
+  alternate_stale="$TRASHDIR/${reponame}_alternate_stale/.git/objects"
+  alternate="$TRASHDIR/${reponame}_alternate/.git/objects"
+  sep="$(native_path_list_separator)"
+
+  GIT_ALTERNATE_OBJECT_DIRECTORIES="$alternate_stale$sep$alternate" \
+  GIT_TRACE=1 \
+    git lfs fetch origin master 2>&1 | tee fetch.log
+  [ "0" -eq "$(grep -c "sending batch of size 1" fetch.log)" ]
+)
+end_test
similarity index 92%
rename from test/testenv.sh
rename to t/testenv.sh
index 97f5304..34ab648 100644 (file)
@@ -1,5 +1,5 @@
 #!/usr/bin/env bash
-# Including in script/integration and every test/test-*.sh file.
+# Including in script/integration and every t/t-*.sh file.
 
 set -e
 
@@ -53,7 +53,7 @@ resolve_symlink() {
 
 # The root directory for the git-lfs repository by default.
 if [ -z "$ROOTDIR" ]; then
-  ROOTDIR=$(cd $(dirname "$0")/.. && pwd -P)
+  ROOTDIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd -P)"
 fi
 
 # Where Git LFS outputs the compiled binaries
@@ -78,7 +78,7 @@ TRASHDIR="$TMPDIR/$(basename "$0")-$$"
 
 # The directory that the test Git server works from.  This cleared at the
 # beginning of every test run.
-REMOTEDIR="$ROOTDIR/test/remote"
+REMOTEDIR="$ROOTDIR/t/remote"
 
 # The directory that stores credentials. Credentials are stored in files with
 # the username:password with filenames identifying the host (port numbers are
@@ -93,19 +93,19 @@ REMOTEDIR="$ROOTDIR/test/remote"
 CREDSDIR="$REMOTEDIR/creds"
 
 # This is the prefix for Git config files.  See the "Test Suite" section in
-# test/README.md
+# t/README.md
 LFS_CONFIG="$REMOTEDIR/config"
 
 # This file contains the URL of the test Git server. See the "Test Suite"
-# section in test/README.md
+# section in t/README.md
 LFS_URL_FILE="$REMOTEDIR/url"
 
 # This file contains the SSL URL of the test Git server. See the "Test Suite"
-# section in test/README.md
+# section in t/README.md
 LFS_SSL_URL_FILE="$REMOTEDIR/sslurl"
 
 # This file contains the client cert SSL URL of the test Git server. See the "Test Suite"
-# section in test/README.md
+# section in t/README.md
 LFS_CLIENT_CERT_URL_FILE="$REMOTEDIR/clientcerturl"
 
 # This file contains the self-signed SSL cert of the TLS endpoint of the test Git server.
@@ -137,4 +137,5 @@ if [ $IS_WINDOWS -eq 1 ]; then
   # prevent Windows OpenSSH from opening GUI prompts
   SSH_ASKPASS=""
 fi
-. "test/testhelpers.sh"
+
+. "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/testhelpers.sh"
similarity index 83%
rename from test/testhelpers.sh
rename to t/testhelpers.sh
index 4018093..3e86322 100644 (file)
@@ -24,6 +24,31 @@ assert_pointer() {
   fi
 }
 
+# refute_pointer confirms that the file in the repository for $path in the
+# given $ref is _not_ a pointer.
+#
+#   $ refute_pointer "master" "path/to/file"
+refute_pointer() {
+  local ref="$1"
+  local path="$2"
+
+  gitblob=$(git ls-tree -lrz "$ref" |
+    while read -r -d $'\0' x; do
+      echo $x
+    done |
+    grep "$path" | cut -f 3 -d " ")
+
+  file=$(git cat-file -p $gitblob)
+  version="version https://git-lfs.github.com/spec/v[0-9]"
+  oid="oid sha256:[0-9a-f]\{64\}"
+  size="size [0-9]*"
+  regex="$version.*$oid.*$size"
+
+  if echo $file | grep -q "$regex"; then
+    exit 1
+  fi
+}
+
 # assert_local_object confirms that an object file is stored for the given oid &
 # has the correct size
 # $ assert_local_object "some-oid" size
@@ -288,9 +313,9 @@ wait_for_file() {
 
 # setup_remote_repo initializes a bare Git repository that is accessible through
 # the test Git server. The `pwd` is set to the repository's directory, in case
-# further commands need to be run. This server is running for every test in a
-# script/integration run, so every test file should setup its own remote
-# repository to avoid conflicts.
+# further commands need to be run. This server is running for every test in an
+# integration run, so every test file should setup its own remote repository to
+# avoid conflicts.
 #
 #   $ setup_remote_repo "some-name"
 #
@@ -465,33 +490,25 @@ repo_endpoint() {
 setup() {
   cd "$ROOTDIR"
 
-  rm -rf "$REMOTEDIR"
-  mkdir "$REMOTEDIR"
-
-  if [ -z "$SKIPCOMPILE" ] && [ -z "$LFS_BIN" ]; then
-    echo "compile git-lfs for $0"
-    script/bootstrap || {
-      return $?
-    }
+  if [ ! -d "$REMOTEDIR" ]; then
+    mkdir "$REMOTEDIR"
   fi
 
-  echo "Git LFS: ${LFS_BIN:-$(which git-lfs)}"
-  git lfs version
-  git version
-
-  if [ -z "$SKIPCOMPILE" ]; then
-    [ $IS_WINDOWS -eq 1 ] && EXT=".exe"
-    for go in test/cmd/*.go; do
-      GO15VENDOREXPERIMENT=1 go build -o "$BINPATH/$(basename $go .go)$EXT" "$go"
-    done
-    if [ -z "$SKIPAPITESTCOMPILE" ]; then
-      # Ensure API test util is built during tests to ensure it stays in sync
-      GO15VENDOREXPERIMENT=1 go build -o "$BINPATH/git-lfs-test-server-api$EXT" "test/git-lfs-test-server-api/main.go" "test/git-lfs-test-server-api/testdownload.go" "test/git-lfs-test-server-api/testupload.go"
-    fi
+  echo "Git LFS: ${LFS_BIN:-$(which git-lfs)}"
+  git lfs version | sed -e 's/^/# /g'
+  git version | sed -e 's/^/# /g'
+
+  if [ -z "$GIT_LFS_NO_TEST_COUNT" ]; then
+    LFSTEST_URL="$LFS_URL_FILE" \
+    LFSTEST_SSL_URL="$LFS_SSL_URL_FILE" \
+    LFSTEST_CLIENT_CERT_URL="$LFS_CLIENT_CERT_URL_FILE" \
+    LFSTEST_DIR="$REMOTEDIR" \
+    LFSTEST_CERT="$LFS_CERT_FILE" \
+    LFSTEST_CLIENT_CERT="$LFS_CLIENT_CERT_FILE" \
+    LFSTEST_CLIENT_KEY="$LFS_CLIENT_KEY_FILE" \
+      lfstest-count-tests increment
   fi
 
-  LFSTEST_URL="$LFS_URL_FILE" LFSTEST_SSL_URL="$LFS_SSL_URL_FILE" LFSTEST_CLIENT_CERT_URL="$LFS_CLIENT_CERT_URL_FILE" LFSTEST_DIR="$REMOTEDIR" LFSTEST_CERT="$LFS_CERT_FILE" LFSTEST_CLIENT_CERT="$LFS_CLIENT_CERT_FILE" LFSTEST_CLIENT_KEY="$LFS_CLIENT_KEY_FILE" lfstest-gitserver > "$REMOTEDIR/gitserver.log" 2>&1 &
-
   wait_for_file "$LFS_URL_FILE"
   wait_for_file "$LFS_SSL_URL_FILE"
   wait_for_file "$LFS_CLIENT_CERT_URL_FILE"
@@ -503,64 +520,56 @@ setup() {
 
   # Set up the initial git config and osx keychain if applicable
   HOME="$TESTHOME"
-  mkdir "$HOME"
-  git lfs install --skip-repo
-  git config --global credential.usehttppath true
-  git config --global credential.helper lfstest
-  git config --global user.name "Git LFS Tests"
-  git config --global user.email "git-lfs@example.com"
-  git config --global http.sslcainfo "$LFS_CERT_FILE"
-  git config --global http.$LFS_CLIENT_CERT_URL/.sslKey "$LFS_CLIENT_KEY_FILE"
-  git config --global http.$LFS_CLIENT_CERT_URL/.sslCert "$LFS_CLIENT_CERT_FILE"
-  git config --global http.$LFS_CLIENT_CERT_URL/.sslVerify "false"
-
-  ( grep "git-lfs clean" "$REMOTEDIR/home/.gitconfig" > /dev/null && grep "git-lfs filter-process" "$REMOTEDIR/home/.gitconfig" > /dev/null ) || {
-    echo "global git config should be set in $REMOTEDIR/home"
-    ls -al "$REMOTEDIR/home"
-    exit 1
-  }
+  if [ ! -d "$HOME" ]; then
+    mkdir "$HOME"
+  fi
+
+  if [ ! -f $HOME/.gitconfig ]; then
+    git lfs install --skip-repo
+    git config --global credential.usehttppath true
+    git config --global credential.helper lfstest
+    git config --global user.name "Git LFS Tests"
+    git config --global user.email "git-lfs@example.com"
+    git config --global http.sslcainfo "$LFS_CERT_FILE"
+    git config --global http.$LFS_CLIENT_CERT_URL/.sslKey "$LFS_CLIENT_KEY_FILE"
+    git config --global http.$LFS_CLIENT_CERT_URL/.sslCert "$LFS_CLIENT_CERT_FILE"
+    git config --global http.$LFS_CLIENT_CERT_URL/.sslVerify "false"
+  fi | sed -e 's/^/# /g'
 
   # setup the git credential password storage
   mkdir -p "$CREDSDIR"
   printf "user:pass" > "$CREDSDIR/127.0.0.1"
 
-  echo
-  echo "HOME: $HOME"
-  echo "TMP: $TMPDIR"
-  echo "CREDS: $CREDSDIR"
-  echo "lfstest-gitserver:"
-  echo "  LFSTEST_URL=$LFS_URL_FILE"
-  echo "  LFSTEST_SSL_URL=$LFS_SSL_URL_FILE"
-  echo "  LFSTEST_CLIENT_CERT_URL=$LFS_CLIENT_CERT_URL_FILE ($LFS_CLIENT_CERT_URL)"
-  echo "  LFSTEST_CERT=$LFS_CERT_FILE"
-  echo "  LFSTEST_CLIENT_CERT=$LFS_CLIENT_CERT_FILE"
-  echo "  LFSTEST_CLIENT_KEY=$LFS_CLIENT_KEY_FILE"
-  echo "  LFSTEST_DIR=$REMOTEDIR"
-  echo "GIT:"
-  git config --global --get-regexp "lfs|credential|user"
-
-  echo
+  echo "#"
+  echo "# HOME: $HOME"
+  echo "# TMP: $TMPDIR"
+  echo "# CREDS: $CREDSDIR"
+  echo "# lfstest-gitserver:"
+  echo "#   LFSTEST_URL=$LFS_URL_FILE"
+  echo "#   LFSTEST_SSL_URL=$LFS_SSL_URL_FILE"
+  echo "#   LFSTEST_CLIENT_CERT_URL=$LFS_CLIENT_CERT_URL_FILE ($LFS_CLIENT_CERT_URL)"
+  echo "#   LFSTEST_CERT=$LFS_CERT_FILE"
+  echo "#   LFSTEST_CLIENT_CERT=$LFS_CLIENT_CERT_FILE"
+  echo "#   LFSTEST_CLIENT_KEY=$LFS_CLIENT_KEY_FILE"
+  echo "#   LFSTEST_DIR=$REMOTEDIR"
 }
 
 # shutdown cleans the $TRASHDIR and shuts the test Git server down.
 shutdown() {
-  # every test/test-*.sh file should cleanup its trashdir
+  # every t/t-*.sh file should cleanup its trashdir
   [ -z "$KEEPTRASH" ] && rm -rf "$TRASHDIR"
 
-  if [ "$SHUTDOWN_LFS" != "no" ]; then
-    # only cleanup test/remote after script/integration done OR a single
-    # test/test-*.sh file is run manually.
-    if [ -s "$LFS_URL_FILE" ]; then
-      curl -s "$(cat "$LFS_URL_FILE")/shutdown"
-    fi
+  if [ -z "$GIT_LFS_NO_TEST_COUNT" ]; then
+    LFSTEST_DIR="$REMOTEDIR" \
+    LFS_URL_FILE="$LFS_URL_FILE" \
+      lfstest-count-tests decrement
+  fi
+}
 
-    [ -z "$KEEPTRASH" ] && rm -rf "$REMOTEDIR"
+tap_show_plan() {
+  local tests="$1"
 
-    # delete entire lfs test root if we created it (double check pattern)
-    if [ -z "$KEEPTRASH" ] && [ "$RM_GIT_LFS_TEST_DIR" = "yes" ] && [[ $GIT_LFS_TEST_DIR == *"$TEMPDIR_PREFIX"* ]]; then
-      rm -rf "$GIT_LFS_TEST_DIR"
-    fi
-fi
+  printf "1..%i\n" "$tests"
 }
 
 ensure_git_version_isnt() {
@@ -705,6 +714,16 @@ native_path_escaped() {
   escape_path "$unescaped"
 }
 
+# native_path_list_separator prints the operating system-specific path list
+# separator.
+native_path_list_separator() {
+  if [ "$IS_WINDOWS" -eq 1 ]; then
+    printf ";";
+  else
+    printf ":";
+  fi
+}
+
 cat_end() {
   if [ $IS_WINDOWS -eq 1 ]; then
     printf '^M$'
@@ -716,15 +735,7 @@ cat_end() {
 # Compare 2 lists which are newline-delimited in a string, ignoring ordering and blank lines
 contains_same_elements() {
   # Remove blank lines then sort
-  printf '%s' "$1" | grep -v '^$' | sort > a.txt
-  printf '%s' "$2" | grep -v '^$' | sort > b.txt
-
-  set +e
-  diff -u a.txt b.txt 1>&2
-  res=$?
-  set -e
-  rm a.txt b.txt
-  exit $res
+  diff -u <(printf '%s' "$1" | grep -v '^$' | sort) <(printf '%s' "$2" | grep -v '^$' | sort)
 }
 
 is_stdin_attached() {
similarity index 79%
rename from test/testlib.sh
rename to t/testlib.sh
index ea42fdf..c0391b0 100644 (file)
@@ -22,7 +22,7 @@
 
 fullfile="$(pwd)/$0"
 
-. "test/testenv.sh"
+. "$(dirname "$0")/testenv.sh"
 set -e
 
 # keep track of num tests and failures
@@ -31,6 +31,7 @@ failures=0
 
 # this runs at process exit
 atexit () {
+  tap_show_plan "$tests"
   shutdown
 
   if [ $failures -gt 0 ]; then
@@ -41,21 +42,12 @@ atexit () {
 }
 
 # create the trash dir
-trap "atexit" EXIT
+trap "atexit" SIGKILL SIGINT SIGTERM EXIT
 
 SHUTDOWN_LFS=yes
 GITSERVER=undefined
 
-# if the file exists, assume another process started it, and will clean it up
-# when it's done
-if [ -s $LFS_URL_FILE ]; then
-  SHUTDOWN_LFS=no
-else
-  setup || {
-    failures=$(( failures + 1 ))
-    exit $?
-  }
-fi
+setup
 
 GITSERVER=$(cat "$LFS_URL_FILE")
 SSLGITSERVER=$(cat "$LFS_SSL_URL_FILE")
@@ -109,19 +101,19 @@ end_test () {
     exec 5>&-
 
     if [ "$test_status" -eq 0 ]; then
-        printf "test: %-60s OK\n" "$test_description ..."
+        printf "ok %d - %-60s\n" "$tests" "$test_description ..."
     else
         failures=$(( failures + 1 ))
-        printf "test: %-60s FAILED\n" "$test_description ..."
+        printf "not ok %d - %-60s\n" "$tests" "$test_description ..."
         (
-            echo "-- stdout --"
-            sed 's/^/    /' <"$TRASHDIR/out"
-            echo "-- stderr --"
+            echo "-- stdout --"
+            sed 's/^/    /' <"$TRASHDIR/out"
+            echo "-- stderr --"
             grep -v -e '^\+ end_test' -e '^+ set +x' <"$TRASHDIR/err" |
-                sed 's/^/    /'
+                sed 's/^/    /'
             if [ $IS_WINDOWS -eq 0 ]; then
-                echo "-- git trace --"
-                sed 's/^/   /' <"$TRASHDIR/trace"
+                echo "-- git trace --"
+                sed 's/^/   /' <"$TRASHDIR/trace"
             fi
         ) 1>&2
         echo
diff --git a/test/README.md b/test/README.md
deleted file mode 100644 (file)
index b289421..0000000
+++ /dev/null
@@ -1,137 +0,0 @@
-# Git LFS Tests
-
-Git LFS uses two form of tests: unit tests for the internals written in Go, and
-integration tests that run `git` and `git-lfs` in a real shell environment.
-You can run them separately:
-
-```
-$ script/test        # Tests the Go packages.
-$ script/integration # Tests the commands in shell scripts.
-```
-
-CI servers should always run both:
-
-```
-$ script/cibuild
-```
-
-## Internal Package Tests
-
-The internal tests use Go's builtin [testing][t] package.
-
-You can run individual tests by passing arguments to `script/test`:
-
-```
-# test a specific Go package
-$ script/test lfs
-
-# pass other `go test` arguments
-$ script/test lfs -run TestSuccessStatus -v
-github.com/rubyist/tracerx
-github.com/git-lfs/git-lfs/git
-github.com/technoweenie/assert
-=== RUN TestSuccessStatus
---- PASS: TestSuccessStatus (0.00 seconds)
-PASS
-ok     _/Users/rick/git-lfs/git-lfs/lfs        0.011s
-```
-
-[t]: http://golang.org/pkg/testing/
-
-## Integration Tests
-
-Git LFS integration tests are shell scripts that test the `git-lfs` command from
-the shell.  Each test file can be run individually, or in parallel through
-`script/integration`. Some tests will change the `pwd`, so it's important that
-they run in separate OS processes.
-
-```
-$ test/test-happy-path.sh
-compile git-lfs for test/test-happy-path.sh
-LFSTEST_URL=/Users/rick/git-lfs/git-lfs/test/remote/url LFSTEST_DIR=/Users/rick/git-lfs/git-lfs/test/remote lfstest-gitserver
-test: happy path ...                                               OK
-```
-
-1. The integration tests should not rely on global system or git config.
-2. The tests should be cross platform (Linux, Mac, Windows).
-3. Tests should bootstrap an isolated, clean environment.  See the Test Suite
-section.
-4. Successful test runs should have minimal output.
-5. Failing test runs should dump enough information to diagnose the bug.  This
-includes stdout, stderr, any log files, and even the OS environment.
-
-There are a few environment variables that you can set to change the test suite
-behavior:
-
-* `GIT_LFS_TEST_DIR=path` - This sets the directory that is used as the current
-working directory of the tests. By default, this will be in your temp dir. It's
-recommended that this is set to a directory outside of any Git repository.
-* `GIT_LFS_TEST_MAXPROCS=N` - This tells `script/integration` how many tests to
-run in parallel.  Default: 4.
-* `KEEPTRASH=1` - This will leave the local repository data in a `tmp` directory
-and the remote repository data in `test/remote`.
-* `SKIPCOMPILE=1` - This skips the Git LFS compilation step.  Speeds up the
-tests when you're running the same test script multiple times without changing
-any Go code.
-
-Also ensure that your `noproxy` environment variable contains `127.0.0.1` host,
-to allow git commands to reach the local Git server `lfstest-gitserver`.
-
-### Test Suite
-
-The `testenv.sh` script includes some global variables used in tests.  This
-should be automatically included in every `test/test-*.sh` script and
-`script/integration`.
-
-`testhelpers.sh` defines some shell functions.  Most are only used in the test
-scripts themselves.  `script/integration` uses the `setup()` and `shutdown()`
-functions.
-
-`testlib.sh` is a [fork of a lightweight shell testing lib][testlib] that is
-used internally at GitHub.  Only the `test/test-*.sh` scripts should include
-this.
-
-Tests live in this `./test` directory, and must have a unique name like:
-`test-{name}.sh`. All tests should start with a basic template.  See
-`test/test-happy-path.sh` for an example.
-
-```
-#!/usr/bin/env bash
-
-. "test/testlib.sh"
-
-begin_test "template"
-(
-  set -e
-
-  echo "your tests go here"
-)
-end_test
-```
-
-The `set -e` command will bail on the test at the first command that returns a
-non zero exit status. Use simple shell commands like `grep` as assertions.
-
-The test suite has standard `setup` and `shutdown` functions that should be
-run only once, before/after running the tests.  The `setup` and `shutdown`
-functions are run by `script/integration` and also by individual test scripts
-when they are executed directly. Setup does the following:
-
-* Resets temporary test directories.
-* Compiles git-lfs with the latest code changes.
-* Compiles Go files in `test/cmd` to `bin`, and adds them the PATH.
-* Spins up a test Git and Git LFS server so the entire push/pull flow can be
-exercised.
-* Sets up a git credential helper that always returns a set username and
-password.
-
-The test Git server writes a `test/remote/url` file when it's complete.  This
-file is how individual test scripts detect if `script/integration` is being
-run.  You can fake this by manually spinning up the Git server using the
-`lfstest-gitserver` line that is output after Git LFS is compiled.
-
-By default, temporary directories in `tmp` and the `test/remote` directory are
-cleared after test runs. Send the "KEEPTRASH" if you want to keep these files
-around for debugging failed tests.
-
-[testlib]: https://gist3.github.com/rtomayko/3877539
diff --git a/test/git-lfs-test-server-api/.gitignore b/test/git-lfs-test-server-api/.gitignore
deleted file mode 100644 (file)
index 6b3d752..0000000
+++ /dev/null
@@ -1 +0,0 @@
-git-lfs-test-server-api*
\ No newline at end of file
diff --git a/test/test-push-missing.sh b/test/test-push-missing.sh
deleted file mode 100755 (executable)
index f5752df..0000000
+++ /dev/null
@@ -1,66 +0,0 @@
-#!/usr/bin/env bash
-
-. "test/testlib.sh"
-
-begin_test "push missing objects"
-(
-  set -e
-
-  reponame="push-missing-objects"
-  setup_remote_repo "$reponame"
-  clone_repo "$reponame" "$reponame"
-
-  git lfs track "*.dat"
-  git add .gitattributes
-  git commit -m "initial commit"
-
-  missing="missing"
-  missing_oid="$(calc_oid "$missing")"
-  missing_len="$(printf "$missing" | wc -c | awk '{ print $1 }')"
-  printf "$missing" > missing.dat
-  git add missing.dat
-  git commit -m "add missing.dat"
-
-  corrupt="corrupt"
-  corrupt_oid="$(calc_oid "$corrupt")"
-  corrupt_len="$(printf "$corrupt" | wc -c | awk '{ print $1 }')"
-  printf "$corrupt" > corrupt.dat
-  git add corrupt.dat
-  git commit -m "add corrupt.dat"
-
-  present="present"
-  present_oid="$(calc_oid "$present")"
-  present_len="$(printf "$present" | wc -c | awk '{ print $1 }')"
-  printf "$present" > present.dat
-  git add present.dat
-  git commit -m "add present.dat"
-
-  assert_local_object "$missing_oid" "$missing_len"
-  assert_local_object "$corrupt_oid" "$corrupt_len"
-  assert_local_object "$present_oid" "$present_len"
-
-  delete_local_object "$missing_oid"
-  corrupt_local_object "$corrupt_oid"
-
-  refute_local_object "$missing_oid"
-  refute_local_object "$corrupt_oid" "$corrupt_len"
-  assert_local_object "$present_oid" "$present_len"
-
-  git config lfs.allowincompletepush false
-
-  git push origin master 2>&1 | tee push.log
-
-  if [ "0" -eq "${PIPESTATUS[0]}" ]; then
-    echo >&2 "fatal: expected 'git push origin master' to exit with non-zero code"
-    exit 1
-  fi
-
-  grep "LFS upload failed:" push.log
-  grep "  (missing) missing.dat ($missing_oid)" push.log
-  grep "  (corrupt) corrupt.dat ($corrupt_oid)" push.log
-
-  refute_server_object "$reponame" "$missing_oid"
-  refute_server_object "$reponame" "$corrupt_oid"
-  assert_server_object "$reponame" "$present_oid"
-)
-end_test
index 00ced92..8e7a3d3 100644 (file)
@@ -3,6 +3,7 @@ package tq
 import (
        "io"
        "io/ioutil"
+       "net/http"
        "os"
        "path/filepath"
        "strconv"
@@ -14,7 +15,8 @@ import (
 )
 
 const (
-       BasicAdapterName = "basic"
+       BasicAdapterName   = "basic"
+       defaultContentType = "application/octet-stream"
 )
 
 // Adapter for basic uploads (non resumable)
@@ -56,10 +58,6 @@ func (a *basicUploadAdapter) DoTransfer(ctx interface{}, t *Transfer, cb Progres
                return err
        }
 
-       if len(req.Header.Get("Content-Type")) == 0 {
-               req.Header.Set("Content-Type", "application/octet-stream")
-       }
-
        if req.Header.Get("Transfer-Encoding") == "chunked" {
                req.TransferEncoding = []string{"chunked"}
        } else {
@@ -74,6 +72,10 @@ func (a *basicUploadAdapter) DoTransfer(ctx interface{}, t *Transfer, cb Progres
        }
        defer f.Close()
 
+       if err := setContentTypeFor(req, f); err != nil {
+               return err
+       }
+
        // Ensure progress callbacks made while uploading
        // Wrap callback to give name context
        ccb := func(totalSize int64, readSoFar int64, readSinceLast int) error {
@@ -171,3 +173,27 @@ func configureBasicUploadAdapter(m *Manifest) {
                return nil
        })
 }
+
+func setContentTypeFor(req *http.Request, r io.ReadSeeker) error {
+       if len(req.Header.Get("Content-Type")) != 0 {
+               return nil
+       }
+
+       buffer := make([]byte, 512)
+       n, err := r.Read(buffer)
+       if err != nil && err != io.EOF {
+               return errors.Wrap(err, "content type detect")
+       }
+
+       contentType := http.DetectContentType(buffer[:n])
+       if _, err := r.Seek(0, 0); err != nil {
+               return errors.Wrap(err, "content type rewind")
+       }
+
+       if contentType == "" {
+               contentType = defaultContentType
+       }
+
+       req.Header.Set("Content-Type", contentType)
+       return nil
+}
index a42a2cb..36a6ae2 100644 (file)
@@ -5,7 +5,6 @@ import (
        "math"
        "os"
        "path/filepath"
-       "strings"
        "sync"
        "sync/atomic"
        "time"
@@ -231,12 +230,10 @@ func (m *Meter) skipUpdate() bool {
 
 func (m *Meter) str() string {
        // (Uploading|Downloading) LFS objects: 100% (10/10) 100 MiB | 10 MiB/s
-
-       direction := strings.Title(m.Direction.String()) + "ing"
        percentage := 100 * float64(m.finishedFiles) / float64(m.estimatedFiles)
 
        return fmt.Sprintf("%s LFS objects: %3.f%% (%d/%d), %s | %s",
-               direction,
+               m.Direction.Verb(),
                percentage,
                m.finishedFiles, m.estimatedFiles,
                humanize.FormatBytes(clamp(m.currentBytes)),
index b6a31ec..60484e7 100644 (file)
@@ -16,10 +16,27 @@ type Direction int
 const (
        Upload   = Direction(iota)
        Download = Direction(iota)
+       Checkout = Direction(iota)
 )
 
+// Verb returns a string containing the verb form of the receiving action.
+func (d Direction) Verb() string {
+       switch d {
+       case Checkout:
+               return "Checking out"
+       case Download:
+               return "Downloading"
+       case Upload:
+               return "Uploading"
+       default:
+               return "<unknown>"
+       }
+}
+
 func (d Direction) String() string {
        switch d {
+       case Checkout:
+               return "checkout"
        case Download:
                return "download"
        case Upload:
diff --git a/vendor/github.com/git-lfs/gitobj/LICENSE.md b/vendor/github.com/git-lfs/gitobj/LICENSE.md
new file mode 100644 (file)
index 0000000..81f9b05
--- /dev/null
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2017- GitHub, Inc. and Git LFS contributors
+
+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.
diff --git a/vendor/github.com/git-lfs/gitobj/README.md b/vendor/github.com/git-lfs/gitobj/README.md
new file mode 100644 (file)
index 0000000..ae57ad8
--- /dev/null
@@ -0,0 +1,9 @@
+# gitobj
+
+Package `gitobj` reads and writes loose and packed Git objects.
+
+For more: godoc.org/github.com/git-lfs/gitobj.
+
+## License
+
+MIT.
similarity index 69%
rename from git/odb/blob.go
rename to vendor/github.com/git-lfs/gitobj/blob.go
index 7f9d66a..d783843 100644 (file)
@@ -1,8 +1,10 @@
-package odb
+package gitobj
 
 import (
        "bytes"
+       "fmt"
        "io"
+       "os"
 )
 
 // Blob represents a Git object of type "blob".
@@ -27,6 +29,43 @@ func NewBlobFromBytes(contents []byte) *Blob {
        }
 }
 
+// NewBlobFromFile returns a new *Blob that contains the contents of the file
+// at location "path" on disk. NewBlobFromFile does not read the file ahead of
+// time, and instead defers this task until encoding the blob to the object
+// database.
+//
+// If the file cannot be opened or stat(1)-ed, an error will be returned.
+//
+// When the blob receives a function call Close(), the file will also be closed,
+// and any error encountered in doing so will be returned from Close().
+func NewBlobFromFile(path string) (*Blob, error) {
+       f, err := os.Open(path)
+       if err != nil {
+               return nil, fmt.Errorf("gitobj: could not open: %s: %s", path,
+                       err)
+       }
+
+       stat, err := f.Stat()
+       if err != nil {
+               return nil, fmt.Errorf("gitobj: could not stat %s: %s", path,
+                       err)
+       }
+
+       return &Blob{
+               Contents: f,
+               Size:     stat.Size(),
+
+               closeFn: func() error {
+                       if err := f.Close(); err != nil {
+                               return fmt.Errorf(
+                                       "gitobj: could not close %s: %s",
+                                       path, err)
+                       }
+                       return nil
+               },
+       }, nil
+}
+
 // Type implements Object.ObjectType by returning the correct object type for
 // Blobs, BlobObjectType.
 func (b *Blob) Type() ObjectType { return BlobObjectType }
similarity index 99%
rename from git/odb/blob_test.go
rename to vendor/github.com/git-lfs/gitobj/blob_test.go
index 3b7225a..0ab4538 100644 (file)
@@ -1,4 +1,4 @@
-package odb
+package gitobj
 
 import (
        "bytes"
similarity index 95%
rename from git/odb/commit.go
rename to vendor/github.com/git-lfs/gitobj/commit.go
index bd96aa0..8a21631 100644 (file)
@@ -1,4 +1,4 @@
-package odb
+package gitobj
 
 import (
        "bufio"
@@ -185,7 +185,11 @@ func (c *Commit) Encode(to io.Writer) (n int, err error) {
                n = n + n3
        }
 
-       n4, err := fmt.Fprintf(to, "\n%s", c.Message)
+       // c.Message is built from messageParts in the Decode() function.
+       //
+       // Since each entry in messageParts _does not_ contain its trailing LF,
+       // append an empty string to capture the final newline.
+       n4, err := fmt.Fprintf(to, "\n%s\n", c.Message)
        if err != nil {
                return n, err
        }
similarity index 99%
rename from git/odb/commit_test.go
rename to vendor/github.com/git-lfs/gitobj/commit_test.go
index 913fc81..e35457c 100644 (file)
@@ -1,4 +1,4 @@
-package odb
+package gitobj
 
 import (
        "bytes"
similarity index 80%
rename from git/odb/errors.go
rename to vendor/github.com/git-lfs/gitobj/errors.go
index ed11908..5556095 100644 (file)
@@ -1,4 +1,4 @@
-package odb
+package gitobj
 
 import "fmt"
 
@@ -14,5 +14,5 @@ type UnexpectedObjectType struct {
 
 // Error implements the error.Error() function.
 func (e *UnexpectedObjectType) Error() string {
-       return fmt.Sprintf("git/odb: unexpected object type, got: %q, wanted: %q", e.Got, e.Wanted)
+       return fmt.Sprintf("gitobj: unexpected object type, got: %q, wanted: %q", e.Got, e.Wanted)
 }
similarity index 64%
rename from git/odb/errors_test.go
rename to vendor/github.com/git-lfs/gitobj/errors_test.go
index 1f82bce..628a0d6 100644 (file)
@@ -1,4 +1,4 @@
-package odb
+package gitobj
 
 import (
        "testing"
@@ -11,5 +11,5 @@ func TestUnexpectedObjectTypeErrFormatting(t *testing.T) {
                Got: TreeObjectType, Wanted: BlobObjectType,
        }
 
-       assert.Equal(t, "git/odb: unexpected object type, got: \"tree\", wanted: \"blob\"", err.Error())
+       assert.Equal(t, "gitobj: unexpected object type, got: \"tree\", wanted: \"blob\"", err.Error())
 }
similarity index 95%
rename from git/odb/file_storer.go
rename to vendor/github.com/git-lfs/gitobj/file_storer.go
index 0033d1c..1dbb04e 100644 (file)
@@ -1,13 +1,12 @@
-package odb
+package gitobj
 
 import (
        "encoding/hex"
+       "fmt"
        "io"
        "io/ioutil"
        "os"
        "path/filepath"
-
-       "github.com/git-lfs/git-lfs/errors"
 )
 
 // fileStorer implements the storer interface by writing to the .git/objects
@@ -53,7 +52,7 @@ func (fs *fileStorer) Store(sha []byte, r io.Reader) (n int64, err error) {
                // collision).
                _, err = io.Copy(ioutil.Discard, r)
                if err != nil {
-                       return 0, errors.Wrap(err, "discard pre-existing object data")
+                       return 0, fmt.Errorf("discard pre-existing object data: %s", err)
                }
 
                return 0, nil
diff --git a/vendor/github.com/git-lfs/gitobj/glide.lock b/vendor/github.com/git-lfs/gitobj/glide.lock
new file mode 100644 (file)
index 0000000..fb91358
--- /dev/null
@@ -0,0 +1,17 @@
+hash: 7ac25f90bf24ea1f92a5b1153932af0d26e35dc6ea4ecb50fc48c4138429d6a0
+updated: 2018-07-05T11:01:37.530865814-05:00
+imports: []
+testImports:
+- name: github.com/davecgh/go-spew
+  version: 5215b55f46b2b919f50a1df0eaa5886afe4e3b3d
+  subpackages:
+  - spew
+- name: github.com/pmezard/go-difflib
+  version: d8ed2627bdf02c080bf22230dbb337003b7aba2d
+  subpackages:
+  - difflib
+- name: github.com/stretchr/testify
+  version: 6cb3b85ef5a0efef77caef88363ec4d4b5c0976d
+  subpackages:
+  - assert
+  - require
diff --git a/vendor/github.com/git-lfs/gitobj/glide.yaml b/vendor/github.com/git-lfs/gitobj/glide.yaml
new file mode 100644 (file)
index 0000000..486d6d2
--- /dev/null
@@ -0,0 +1,8 @@
+package: github.com/git-lfs/go-gitobj
+import: []
+testImport:
+- package: github.com/stretchr/testify
+  version: 6cb3b85ef5a0efef77caef88363ec4d4b5c0976d
+  subpackages:
+  - assert
+  - require
similarity index 99%
rename from git/odb/memory_storer.go
rename to vendor/github.com/git-lfs/gitobj/memory_storer.go
index b246535..65857be 100644 (file)
@@ -1,4 +1,4 @@
-package odb
+package gitobj
 
 import (
        "bytes"
similarity index 98%
rename from git/odb/object.go
rename to vendor/github.com/git-lfs/gitobj/object.go
index b6c2c84..00b79da 100644 (file)
@@ -1,4 +1,4 @@
-package odb
+package gitobj
 
 import "io"
 
similarity index 96%
rename from git/odb/object_db.go
rename to vendor/github.com/git-lfs/gitobj/object_db.go
index 80e5dca..78a736d 100644 (file)
@@ -1,4 +1,4 @@
-package odb
+package gitobj
 
 import (
        "bytes"
@@ -9,8 +9,7 @@ import (
        "strings"
        "sync/atomic"
 
-       "github.com/git-lfs/git-lfs/errors"
-       "github.com/git-lfs/git-lfs/git/odb/pack"
+       "github.com/git-lfs/gitobj/pack"
 )
 
 // ObjectDatabase enables the reading and writing of objects against a storage
@@ -58,7 +57,7 @@ func FromFilesystem(root, tmp string) (*ObjectDatabase, error) {
 // If Close() has already been called, this function will return an error.
 func (o *ObjectDatabase) Close() error {
        if !atomic.CompareAndSwapUint32(&o.closed, 0, 1) {
-               return errors.New("git/odb: *ObjectDatabase already closed")
+               return fmt.Errorf("gitobj: *ObjectDatabase already closed")
        }
 
        if err := o.packs.Close(); err != nil {
@@ -246,7 +245,7 @@ func (o *ObjectDatabase) open(sha []byte) (*ObjectReader, error) {
                // load its contents from the *git.ObjectScanner by leveraging
                // `git-cat-file --batch`.
                if atomic.LoadUint32(&o.closed) == 1 {
-                       return nil, errors.New("git/odb: cannot use closed *pack.Set")
+                       return nil, fmt.Errorf("gitobj: cannot use closed *pack.Set")
                }
 
                packed, err := o.packs.Object(sha)
@@ -280,7 +279,7 @@ func (o *ObjectDatabase) open(sha []byte) (*ObjectReader, error) {
 // the `io.Closer` interface), but skips this if the "into" Object is of type
 // BlobObjectType. Blob's don't exhaust the buffer completely (they instead
 // maintain a handle on the blob's contents via an io.LimitedReader) and
-// therefore cannot be closed until signaled explicitly by git/odb.Blob.Close().
+// therefore cannot be closed until signaled explicitly by gitobj.Blob.Close().
 func (o *ObjectDatabase) decode(sha []byte, into Object) error {
        r, err := o.open(sha)
        if err != nil {
similarity index 96%
rename from git/odb/object_db_test.go
rename to vendor/github.com/git-lfs/gitobj/object_db_test.go
index 46069a6..e2ce95b 100644 (file)
@@ -1,4 +1,4 @@
-package odb
+package gitobj
 
 import (
        "bytes"
@@ -159,7 +159,7 @@ func TestWriteCommit(t *testing.T) {
                Message:   "initial commit",
        })
 
-       expected := "77a746376fdb591a44a4848b5ba308b2d3e2a90c"
+       expected := "fee8a35c2890cd6e0e28d24cc457fcecbd460962"
 
        assert.Nil(t, err)
        assert.Equal(t, expected, hex.EncodeToString(sha))
@@ -226,7 +226,7 @@ func TestReadingAMissingObjectAfterClose(t *testing.T) {
        }
 
        blob, err := db.Blob(sha)
-       assert.EqualError(t, err, "git/odb: cannot use closed *pack.Set")
+       assert.EqualError(t, err, "gitobj: cannot use closed *pack.Set")
        assert.Nil(t, blob)
 }
 
@@ -235,7 +235,7 @@ func TestClosingAnObjectDatabaseMoreThanOnce(t *testing.T) {
        assert.Nil(t, err)
 
        assert.Nil(t, db.Close())
-       assert.EqualError(t, db.Close(), "git/odb: *ObjectDatabase already closed")
+       assert.EqualError(t, db.Close(), "gitobj: *ObjectDatabase already closed")
 }
 
 func TestObjectDatabaseRootWithRoot(t *testing.T) {
similarity index 97%
rename from git/odb/object_reader.go
rename to vendor/github.com/git-lfs/gitobj/object_reader.go
index 5e5b582..ba00d8c 100644 (file)
@@ -1,14 +1,13 @@
-package odb
+package gitobj
 
 import (
        "bufio"
        "compress/zlib"
+       "fmt"
        "io"
        "io/ioutil"
        "strconv"
        "strings"
-
-       "github.com/pkg/errors"
 )
 
 // ObjectReader provides an io.Reader implementation that can read Git object
@@ -106,8 +105,8 @@ func (r *ObjectReader) Header() (typ ObjectType, size int64, err error) {
                return UnknownObjectType, 0, err
        }
        if len(typs) == 0 {
-               return UnknownObjectType, 0, errors.Errorf(
-                       "git/odb: object type must not be empty",
+               return UnknownObjectType, 0, fmt.Errorf(
+                       "gitobj: object type must not be empty",
                )
        }
        typs = strings.TrimSuffix(typs, " ")
similarity index 98%
rename from git/odb/object_type.go
rename to vendor/github.com/git-lfs/gitobj/object_type.go
index eb25621..bcaff3c 100644 (file)
@@ -1,4 +1,4 @@
-package odb
+package gitobj
 
 import "strings"
 
similarity index 96%
rename from git/odb/object_writer.go
rename to vendor/github.com/git-lfs/gitobj/object_writer.go
index b248c88..8507439 100644 (file)
@@ -1,4 +1,4 @@
-package odb
+package gitobj
 
 import (
        "compress/zlib"
@@ -85,7 +85,7 @@ func NewObjectWriteCloser(w io.WriteCloser) *ObjectWriter {
 // WriteHeader MUST be called only once, or a panic() will occur.
 func (w *ObjectWriter) WriteHeader(typ ObjectType, len int64) (n int, err error) {
        if !atomic.CompareAndSwapUint32(&w.wroteHeader, 0, 1) {
-               panic("git/odb: cannot write headers more than once")
+               panic("gitobj: cannot write headers more than once")
        }
        return fmt.Fprintf(w, "%s %d\x00", typ, len)
 }
@@ -98,7 +98,7 @@ func (w *ObjectWriter) WriteHeader(typ ObjectType, len int64) (n int, err error)
 // occur.
 func (w *ObjectWriter) Write(p []byte) (n int, err error) {
        if atomic.LoadUint32(&w.wroteHeader) != 1 {
-               panic("git/odb: cannot write data without header")
+               panic("gitobj: cannot write data without header")
        }
        return w.w.Write(p)
 }
similarity index 93%
rename from git/odb/object_writer_test.go
rename to vendor/github.com/git-lfs/gitobj/object_writer_test.go
index b493781..38beb23 100644 (file)
@@ -1,4 +1,4 @@
-package odb
+package gitobj
 
 import (
        "bytes"
@@ -61,7 +61,7 @@ func TestObjectWriterPanicsOnWritesWithoutHeader(t *testing.T) {
                err := recover()
 
                assert.NotNil(t, err)
-               assert.Equal(t, "git/odb: cannot write data without header", err)
+               assert.Equal(t, "gitobj: cannot write data without header", err)
        }()
 
        w := NewObjectWriter(new(bytes.Buffer))
@@ -73,7 +73,7 @@ func TestObjectWriterPanicsOnMultipleHeaderWrites(t *testing.T) {
                err := recover()
 
                assert.NotNil(t, err)
-               assert.Equal(t, "git/odb: cannot write headers more than once", err)
+               assert.Equal(t, "gitobj: cannot write headers more than once", err)
        }()
 
        w := NewObjectWriter(new(bytes.Buffer))
similarity index 98%
rename from git/odb/pack/bounds.go
rename to vendor/github.com/git-lfs/gitobj/pack/bounds.go
index 0cd5ccd..48b29f3 100644 (file)
@@ -9,7 +9,7 @@ import "fmt"
 // inclusive or exclusive. *bounds makes no assumptions on the inclusivity of
 // those values.
 //
-// See: *git/odb/pack.Index for more.
+// See: *gitobj/pack.Index for more.
 type bounds struct {
        // left is the left or lower bound of the bounds.
        left int64
similarity index 94%
rename from git/odb/pack/chain_delta.go
rename to vendor/github.com/git-lfs/gitobj/pack/chain_delta.go
index daf240d..38a0e97 100644 (file)
@@ -1,8 +1,6 @@
 package pack
 
-import (
-       "github.com/git-lfs/git-lfs/errors"
-)
+import "fmt"
 
 // ChainDelta represents a "delta" component of a delta-base chain.
 type ChainDelta struct {
@@ -49,7 +47,7 @@ func patch(base, delta []byte) ([]byte, error) {
                //
                // If this does not match with the srcSize, return an error
                // early so as to avoid a possible bounds error below.
-               return nil, errors.New("git/odb/pack: invalid delta data")
+               return nil, fmt.Errorf("gitobj/pack: invalid delta data")
        }
 
        // The remainder of the delta header contains the destination size, and
@@ -136,8 +134,8 @@ func patch(base, delta []byte) ([]byte, error) {
                        // instruction.
                        //
                        // Return immediately.
-                       return nil, errors.New(
-                               "git/odb/pack: invalid delta data")
+                       return nil, fmt.Errorf(
+                               "gitobj/pack: invalid delta data")
                }
        }
 
@@ -147,7 +145,7 @@ func patch(base, delta []byte) ([]byte, error) {
                // an invalid set of patch instructions.
                //
                // Return immediately.
-               return nil, errors.New("git/odb/pack: invalid delta data")
+               return nil, fmt.Errorf("gitobj/pack: invalid delta data")
        }
        return dest, nil
 }
@@ -161,7 +159,7 @@ func patchDeltaHeader(delta []byte, pos int) (size int64, end int) {
 
        for shift == 0 || c&0x80 != 0 {
                if len(delta) <= pos {
-                       panic("git/odb/pack: invalid delta header")
+                       panic("gitobj/pack: invalid delta header")
                }
 
                c = int64(delta[pos])
similarity index 94%
rename from git/odb/pack/chain_delta_test.go
rename to vendor/github.com/git-lfs/gitobj/pack/chain_delta_test.go
index 553d1f3..275684a 100644 (file)
@@ -87,7 +87,7 @@ func TestChainDeltaWithInvalidDeltaInstruction(t *testing.T) {
        }
 
        data, err := c.Unpack()
-       assert.EqualError(t, err, "git/odb/pack: invalid delta data")
+       assert.EqualError(t, err, "gitobj/pack: invalid delta data")
        assert.Nil(t, data)
 }
 
@@ -107,6 +107,6 @@ func TestChainDeltaWithExtraInstructions(t *testing.T) {
        }
 
        data, err := c.Unpack()
-       assert.EqualError(t, err, "git/odb/pack: invalid delta data")
+       assert.EqualError(t, err, "gitobj/pack: invalid delta data")
        assert.Nil(t, data)
 }
similarity index 83%
rename from git/odb/pack/errors.go
rename to vendor/github.com/git-lfs/gitobj/pack/errors.go
index f85be31..6009c26 100644 (file)
@@ -11,5 +11,5 @@ type UnsupportedVersionErr struct {
 
 // Error implements 'error.Error()'.
 func (u *UnsupportedVersionErr) Error() string {
-       return fmt.Sprintf("git/odb/pack: unsupported version: %d", u.Got)
+       return fmt.Sprintf("gitobj/pack: unsupported version: %d", u.Got)
 }
similarity index 73%
rename from git/odb/pack/errors_test.go
rename to vendor/github.com/git-lfs/gitobj/pack/errors_test.go
index 1e6b253..5181faf 100644 (file)
@@ -9,5 +9,5 @@ import (
 func TestUnsupportedVersionErr(t *testing.T) {
        u := &UnsupportedVersionErr{Got: 3}
 
-       assert.Error(t, u, "git/odb/pack: unsupported version: 3")
+       assert.Error(t, u, "gitobj/pack: unsupported version: 3")
 }
similarity index 97%
rename from git/odb/pack/index.go
rename to vendor/github.com/git-lfs/gitobj/pack/index.go
index f2bf3b9..143d6ef 100644 (file)
@@ -2,9 +2,8 @@ package pack
 
 import (
        "bytes"
+       "fmt"
        "io"
-
-       "github.com/git-lfs/git-lfs/errors"
 )
 
 // Index stores information about the location of objects in a corresponding
@@ -43,7 +42,7 @@ func (i *Index) Close() error {
 var (
        // errNotFound is an error returned by Index.Entry() (see: below) when
        // an object cannot be found in the index.
-       errNotFound = errors.New("git/odb/pack: object not found in index")
+       errNotFound = fmt.Errorf("gitobj/pack: object not found in index")
 )
 
 // IsNotFound returns whether a given error represents a missing object in the
similarity index 97%
rename from git/odb/pack/index_decode.go
rename to vendor/github.com/git-lfs/gitobj/pack/index_decode.go
index 5130c77..a2cf54c 100644 (file)
@@ -3,9 +3,8 @@ package pack
 import (
        "bytes"
        "encoding/binary"
+       "fmt"
        "io"
-
-       "github.com/git-lfs/git-lfs/errors"
 )
 
 const (
@@ -57,7 +56,7 @@ const (
 var (
        // ErrShortFanout is an error representing situations where the entire
        // fanout table could not be read, and is thus too short.
-       ErrShortFanout = errors.New("git/odb/pack: too short fanout table")
+       ErrShortFanout = fmt.Errorf("gitobj/pack: too short fanout table")
 
        // indexHeader is the first four "magic" bytes of index files version 2
        // or newer.
@@ -109,7 +108,6 @@ func decodeIndexHeader(r io.ReaderAt) (IndexVersion, error) {
                case 2:
                        return new(V2), nil
                }
-
                return nil, &UnsupportedVersionErr{uint32(version)}
        }
        return new(V1), nil
@@ -9,13 +9,6 @@ import (
        "github.com/stretchr/testify/assert"
 )
 
-func TestDecodeIndexV1InvalidFanout(t *testing.T) {
-       idx, err := DecodeIndex(bytes.NewReader(make([]byte, indexFanoutWidth-1)))
-
-       assert.Equal(t, ErrShortFanout, err)
-       assert.Nil(t, idx)
-}
-
 func TestDecodeIndexV2(t *testing.T) {
        buf := make([]byte, 0, indexV2Width+indexFanoutWidth)
        buf = append(buf, 0xff, 0x74, 0x4f, 0x63)
@@ -42,8 +35,8 @@ func TestDecodeIndexV2InvalidFanout(t *testing.T) {
 
        idx, err := DecodeIndex(bytes.NewReader(buf))
 
-       assert.Nil(t, idx)
        assert.Equal(t, ErrShortFanout, err)
+       assert.Nil(t, idx)
 }
 
 func TestDecodeIndexV1(t *testing.T) {
@@ -53,6 +46,13 @@ func TestDecodeIndexV1(t *testing.T) {
        assert.EqualValues(t, 0, idx.Count())
 }
 
+func TestDecodeIndexV1InvalidFanout(t *testing.T) {
+       idx, err := DecodeIndex(bytes.NewReader(make([]byte, indexFanoutWidth-1)))
+
+       assert.Equal(t, ErrShortFanout, err)
+       assert.Nil(t, idx)
+}
+
 func TestDecodeIndexUnsupportedVersion(t *testing.T) {
        buf := make([]byte, 0, 4+4)
        buf = append(buf, 0xff, 0x74, 0x4f, 0x63)
@@ -60,7 +60,7 @@ func TestDecodeIndexUnsupportedVersion(t *testing.T) {
 
        idx, err := DecodeIndex(bytes.NewReader(buf))
 
-       assert.EqualError(t, err, "git/odb/pack: unsupported version: 3")
+       assert.EqualError(t, err, "gitobj/pack: unsupported version: 3")
        assert.Nil(t, idx)
 }
 
similarity index 97%
rename from git/odb/pack/index_test.go
rename to vendor/github.com/git-lfs/gitobj/pack/index_test.go
index 8af1e46..d56fab4 100644 (file)
@@ -3,10 +3,9 @@ package pack
 import (
        "bytes"
        "encoding/binary"
+       "fmt"
        "testing"
 
-       "github.com/git-lfs/git-lfs/errors"
-
        "github.com/stretchr/testify/assert"
 )
 
@@ -81,7 +80,7 @@ func TestIndexIsNotFound(t *testing.T) {
 }
 
 func TestIndexIsNotFoundForOtherErrors(t *testing.T) {
-       assert.False(t, IsNotFound(errors.New("git/odb/pack: misc")),
+       assert.False(t, IsNotFound(fmt.Errorf("gitobj/pack: misc")),
                "expected 'err' not to satisfy 'IsNotFound()'")
 }
 
similarity index 84%
rename from git/odb/pack/index_version.go
rename to vendor/github.com/git-lfs/gitobj/pack/index_version.go
index 6ffc1fe..47e911a 100644 (file)
@@ -1,7 +1,5 @@
 package pack
 
-// IndexVersion is a constant type that represents the version of encoding used
-// by a particular index version.
 type IndexVersion interface {
        // Name returns the name of the object located at the given offset "at",
        // in the Index file "idx".
similarity index 90%
rename from git/odb/pack/io_test.go
rename to vendor/github.com/git-lfs/gitobj/pack/io_test.go
index 53f5a47..f429a87 100644 (file)
@@ -2,10 +2,9 @@ package pack
 
 import (
        "bytes"
+       "fmt"
        "testing"
 
-       "github.com/git-lfs/git-lfs/errors"
-
        "github.com/stretchr/testify/assert"
 )
 
@@ -32,7 +31,7 @@ func TestOffsetReaderAtReadsAtOffset(t *testing.T) {
 }
 
 func TestOffsetReaderPropogatesErrors(t *testing.T) {
-       expected := errors.New("git/odb/pack: testing")
+       expected := fmt.Errorf("gitobj/pack: testing")
        bo := &OffsetReaderAt{
                r: &ErrReaderAt{Err: expected},
                o: 1,
similarity index 88%
rename from git/odb/pack/object_test.go
rename to vendor/github.com/git-lfs/gitobj/pack/object_test.go
index 8adbb4c..7ba2d09 100644 (file)
@@ -1,10 +1,9 @@
 package pack
 
 import (
+       "fmt"
        "testing"
 
-       "github.com/git-lfs/git-lfs/errors"
-
        "github.com/stretchr/testify/assert"
 )
 
@@ -32,7 +31,7 @@ func TestObjectUnpackUnpacksData(t *testing.T) {
 }
 
 func TestObjectUnpackPropogatesErrors(t *testing.T) {
-       expected := errors.New("git/odb/pack: testing")
+       expected := fmt.Errorf("gitobj/pack: testing")
 
        o := &Object{
                data: &ChainSimple{
similarity index 97%
rename from git/odb/pack/packfile.go
rename to vendor/github.com/git-lfs/gitobj/pack/packfile.go
index 5520b4d..eb0cdbc 100644 (file)
@@ -2,10 +2,9 @@ package pack
 
 import (
        "compress/zlib"
+       "fmt"
        "io"
        "io/ioutil"
-
-       "github.com/git-lfs/git-lfs/errors"
 )
 
 // Packfile encapsulates the behavior of accessing an unpacked representation of
@@ -57,8 +56,7 @@ func (p *Packfile) Object(name []byte) (*Object, error) {
                if !IsNotFound(err) {
                        // If the error was not an errNotFound, re-wrap it with
                        // additional context.
-                       err = errors.Wrap(err,
-                               "git/odb/pack: could not load index")
+                       err = fmt.Errorf("gitobj/pack: could not load index: %s", err)
                }
                return nil, err
        }
@@ -225,8 +223,8 @@ func (p *Packfile) findBase(typ PackedObjectType, offset, objOffset int64) (Chai
        default:
                // If we did not receive an OBJ_OFS_DELTA, or OBJ_REF_DELTA, the
                // type given is not a delta-fied type. Return an error.
-               return nil, baseOffset, errors.Errorf(
-                       "git/odb/pack: type %s is not deltafied", typ)
+               return nil, baseOffset, fmt.Errorf(
+                       "gitobj/pack: type %s is not deltafied", typ)
        }
 
        // Once we have determined the base offset of the object's chain base,
similarity index 94%
rename from git/odb/pack/packfile_decode.go
rename to vendor/github.com/git-lfs/gitobj/pack/packfile_decode.go
index 21b3021..ef7bf47 100644 (file)
@@ -13,7 +13,7 @@ var (
 
        // errBadPackHeader is a sentinel error value returned when the given
        // pack header does not match the expected one.
-       errBadPackHeader = errors.New("git/odb/pack: bad pack header")
+       errBadPackHeader = errors.New("gitobj/pack: bad pack header")
 )
 
 // DecodePackfile opens the packfile given by the io.ReaderAt "r" for reading.
similarity index 97%
rename from git/odb/pack/packfile_test.go
rename to vendor/github.com/git-lfs/gitobj/pack/packfile_test.go
index f7d5aae..d64bc23 100644 (file)
@@ -4,13 +4,12 @@ import (
        "bytes"
        "encoding/binary"
        "encoding/hex"
+       "fmt"
        "sort"
        "strings"
        "sync/atomic"
        "testing"
 
-       "github.com/git-lfs/git-lfs/errors"
-
        "github.com/stretchr/testify/assert"
 )
 
@@ -184,7 +183,7 @@ func TestPackfileClosesReadClosers(t *testing.T) {
 }
 
 func TestPackfileClosePropogatesCloseErrors(t *testing.T) {
-       e := errors.New("git/odb/pack: testing")
+       e := fmt.Errorf("gitobj/pack: testing")
        p := &Packfile{
                r: &ReaderAtCloser{E: e},
        }
@@ -269,7 +268,7 @@ func IndexWith(offsets map[string]uint32) *Index {
 func DecodeHex(t *testing.T, str string) []byte {
        b, err := hex.DecodeString(str)
        if err != nil {
-               t.Fatalf("git/odb/pack: unexpected hex.DecodeString error: %s", err)
+               t.Fatalf("gitobj/pack: unexpected hex.DecodeString error: %s", err)
        }
 
        return b
similarity index 85%
rename from git/odb/pack/type.go
rename to vendor/github.com/git-lfs/gitobj/pack/type.go
index 94423dc..4da73cd 100644 (file)
@@ -29,7 +29,7 @@ const (
 )
 
 // String implements fmt.Stringer and returns an encoding of the type valid for
-// use in the loose object format protocol (see: package 'git/odb' for more).
+// use in the loose object format protocol (see: package 'gitobj' for more).
 //
 // If the receiving instance is not defined, String() will panic().
 func (t PackedObjectType) String() string {
@@ -50,9 +50,9 @@ func (t PackedObjectType) String() string {
                return "obj_ref_delta"
        }
 
-       panic(fmt.Sprintf("git/odb/pack: unknown object type: %d", t))
+       panic(fmt.Sprintf("gitobj/pack: unknown object type: %d", t))
 }
 
 var (
-       errUnrecognizedObjectType = errors.New("git/odb/pack: unrecognized object type")
+       errUnrecognizedObjectType = errors.New("gitobj/pack: unrecognized object type")
 )
similarity index 91%
rename from git/odb/pack/type_test.go
rename to vendor/github.com/git-lfs/gitobj/pack/type_test.go
index 6fe74ca..8f2ef3f 100644 (file)
@@ -20,7 +20,7 @@ func (c *PackedObjectStringTestCase) Assert(t *testing.T) {
                        err := recover()
 
                        if err == nil {
-                               t.Fatalf("git/odb/pack: expected panic()")
+                               t.Fatalf("gitobj/pack: expected panic()")
                        }
 
                        assert.Equal(t, c.Expected, fmt.Sprintf("%s", err))
@@ -45,7 +45,7 @@ func TestPackedObjectTypeString(t *testing.T) {
                        Expected: "obj_ref_delta"},
 
                "unknown type": {T: PackedObjectType(5), Panic: true,
-                       Expected: "git/odb/pack: unknown object type: 5"},
+                       Expected: "gitobj/pack: unknown object type: 5"},
        } {
                t.Run(desc, c.Assert)
        }
similarity index 97%
rename from git/odb/storer.go
rename to vendor/github.com/git-lfs/gitobj/storer.go
index b129274..1cc1249 100644 (file)
@@ -1,4 +1,4 @@
-package odb
+package gitobj
 
 import "io"
 
similarity index 90%
rename from git/odb/tag.go
rename to vendor/github.com/git-lfs/gitobj/tag.go
index a2f7405..65f17fb 100644 (file)
@@ -1,4 +1,4 @@
-package odb
+package gitobj
 
 import (
        "bufio"
@@ -7,8 +7,6 @@ import (
        "fmt"
        "io"
        "strings"
-
-       "github.com/git-lfs/git-lfs/errors"
 )
 
 type Tag struct {
@@ -45,14 +43,14 @@ func (t *Tag) Decode(r io.Reader, size int64) (int, error) {
 
                        parts := strings.SplitN(scanner.Text(), " ", 2)
                        if len(parts) < 2 {
-                               return 0, errors.Errorf("git/odb: invalid tag header: %s", scanner.Text())
+                               return 0, fmt.Errorf("gitobj: invalid tag header: %s", scanner.Text())
                        }
 
                        switch parts[0] {
                        case "object":
                                sha, err := hex.DecodeString(parts[1])
                                if err != nil {
-                                       return 0, errors.Wrap(err, "git/odb: unable to decode SHA-1")
+                                       return 0, fmt.Errorf("gitobj: unable to decode SHA-1: %s", err)
                                }
 
                                t.Object = sha
@@ -63,7 +61,7 @@ func (t *Tag) Decode(r io.Reader, size int64) (int, error) {
                        case "tagger":
                                t.Tagger = parts[1]
                        default:
-                               return 0, errors.Errorf("git/odb: unknown tag header: %s", parts[0])
+                               return 0, fmt.Errorf("gitobj: unknown tag header: %s", parts[0])
                        }
                }
        }
similarity index 99%
rename from git/odb/tag_test.go
rename to vendor/github.com/git-lfs/gitobj/tag_test.go
index 786a04b..c171825 100644 (file)
@@ -1,4 +1,4 @@
-package odb
+package gitobj
 
 import (
        "bytes"
similarity index 98%
rename from git/odb/tree.go
rename to vendor/github.com/git-lfs/gitobj/tree.go
index 457fbed..6ebcf12 100644 (file)
@@ -1,4 +1,4 @@
-package odb
+package gitobj
 
 import (
        "bufio"
@@ -220,7 +220,7 @@ func (e *TreeEntry) Type() ObjectType {
                        // Safeguard that catch here, or otherwise panic.
                        return CommitObjectType
                } else {
-                       panic(fmt.Sprintf("git/odb: unknown object type: %o",
+                       panic(fmt.Sprintf("gitobj: unknown object type: %o",
                                e.Filemode))
                }
        }
@@ -231,7 +231,7 @@ func (e *TreeEntry) Type() ObjectType {
 // write trees in a correct, readable format to the Git object database.
 //
 // The format is as follows: entries are sorted lexicographically in byte-order,
-// with subtrees (entries of Type() == git/odb.TreeObjectType) being sorted as
+// with subtrees (entries of Type() == gitobj.TreeObjectType) being sorted as
 // if their `Name` fields ended in a "/".
 //
 // See: https://github.com/git/git/blob/v2.13.0/fsck.c#L492-L525 for more
similarity index 98%
rename from git/odb/tree_test.go
rename to vendor/github.com/git-lfs/gitobj/tree_test.go
index 0d7b87b..9625902 100644 (file)
@@ -1,4 +1,4 @@
-package odb
+package gitobj
 
 import (
        "bufio"
@@ -173,7 +173,7 @@ func (c *TreeEntryTypeTestCase) Assert(t *testing.T) {
        got := e.Type()
 
        assert.Equal(t, c.Expected, got,
-               "git/odb: expected type: %s, got: %s", c.Expected, got)
+               "gitobj: expected type: %s, got: %s", c.Expected, got)
 }
 
 func TestTreeEntryTypeResolution(t *testing.T) {
@@ -192,9 +192,9 @@ func TestTreeEntryTypeResolutionUnknown(t *testing.T) {
 
        defer func() {
                if err := recover(); err == nil {
-                       t.Fatal("git/odb: expected panic(), got none")
+                       t.Fatal("gitobj: expected panic(), got none")
                } else {
-                       assert.Equal(t, "git/odb: unknown object type: -1", err)
+                       assert.Equal(t, "gitobj: unknown object type: -1", err)
                }
        }()
 
diff --git a/vendor/github.com/git-lfs/gitobj/vendor/github.com/davecgh/go-spew/.gitignore b/vendor/github.com/git-lfs/gitobj/vendor/github.com/davecgh/go-spew/.gitignore
new file mode 100644 (file)
index 0000000..0026861
--- /dev/null
@@ -0,0 +1,22 @@
+# Compiled Object files, Static and Dynamic libs (Shared Objects)
+*.o
+*.a
+*.so
+
+# Folders
+_obj
+_test
+
+# Architecture specific extensions/prefixes
+*.[568vq]
+[568vq].out
+
+*.cgo1.go
+*.cgo2.c
+_cgo_defun.c
+_cgo_gotypes.go
+_cgo_export.*
+
+_testmain.go
+
+*.exe
diff --git a/vendor/github.com/git-lfs/gitobj/vendor/github.com/davecgh/go-spew/.travis.yml b/vendor/github.com/git-lfs/gitobj/vendor/github.com/davecgh/go-spew/.travis.yml
new file mode 100644 (file)
index 0000000..10f469a
--- /dev/null
@@ -0,0 +1,11 @@
+language: go
+go: 1.2
+install:
+    - go get -v code.google.com/p/go.tools/cmd/cover
+script:
+    - go test -v -tags=disableunsafe ./spew
+    - go test -v -tags=testcgo ./spew -covermode=count -coverprofile=profile.cov
+after_success:
+    - go get -v github.com/mattn/goveralls
+    - export PATH=$PATH:$HOME/gopath/bin
+    - goveralls -coverprofile=profile.cov -service=travis-ci
diff --git a/vendor/github.com/git-lfs/gitobj/vendor/github.com/davecgh/go-spew/LICENSE b/vendor/github.com/git-lfs/gitobj/vendor/github.com/davecgh/go-spew/LICENSE
new file mode 100644 (file)
index 0000000..2a7cfd2
--- /dev/null
@@ -0,0 +1,13 @@
+Copyright (c) 2012-2013 Dave Collins <dave@davec.name>
+
+Permission to use, copy, modify, and distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
diff --git a/vendor/github.com/git-lfs/gitobj/vendor/github.com/davecgh/go-spew/README.md b/vendor/github.com/git-lfs/gitobj/vendor/github.com/davecgh/go-spew/README.md
new file mode 100644 (file)
index 0000000..777a8e1
--- /dev/null
@@ -0,0 +1,194 @@
+go-spew
+=======
+
+[![Build Status](https://travis-ci.org/davecgh/go-spew.png?branch=master)]
+(https://travis-ci.org/davecgh/go-spew) [![Coverage Status]
+(https://coveralls.io/repos/davecgh/go-spew/badge.png?branch=master)]
+(https://coveralls.io/r/davecgh/go-spew?branch=master)
+
+Go-spew implements a deep pretty printer for Go data structures to aid in
+debugging.  A comprehensive suite of tests with 100% test coverage is provided
+to ensure proper functionality.  See `test_coverage.txt` for the gocov coverage
+report.  Go-spew is licensed under the liberal ISC license, so it may be used in
+open source or commercial projects.
+
+If you're interested in reading about how this package came to life and some
+of the challenges involved in providing a deep pretty printer, there is a blog
+post about it
+[here](https://blog.cyphertite.com/go-spew-a-journey-into-dumping-go-data-structures/).
+
+## Documentation
+
+[![GoDoc](https://godoc.org/github.com/davecgh/go-spew/spew?status.png)]
+(http://godoc.org/github.com/davecgh/go-spew/spew)
+
+Full `go doc` style documentation for the project can be viewed online without
+installing this package by using the excellent GoDoc site here:
+http://godoc.org/github.com/davecgh/go-spew/spew
+
+You can also view the documentation locally once the package is installed with
+the `godoc` tool by running `godoc -http=":6060"` and pointing your browser to
+http://localhost:6060/pkg/github.com/davecgh/go-spew/spew
+
+## Installation
+
+```bash
+$ go get -u github.com/davecgh/go-spew/spew
+```
+
+## Quick Start
+
+Add this import line to the file you're working in:
+
+```Go
+import "github.com/davecgh/go-spew/spew"
+```
+
+To dump a variable with full newlines, indentation, type, and pointer
+information use Dump, Fdump, or Sdump:
+
+```Go
+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): 
+
+```Go
+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)
+```
+
+## Debugging a Web Application Example
+
+Here is an example of how you can use `spew.Sdump()` to help debug a web application. Please be sure to wrap your output using the `html.EscapeString()` function for safety reasons. You should also only use this debugging technique in a development environment, never in production.
+
+```Go
+package main
+
+import (
+    "fmt"
+    "html"
+    "net/http"
+
+    "github.com/davecgh/go-spew/spew"
+)
+
+func handler(w http.ResponseWriter, r *http.Request) {
+    w.Header().Set("Content-Type", "text/html")
+    fmt.Fprintf(w, "Hi there, %s!", r.URL.Path[1:])
+    fmt.Fprintf(w, "<!--\n" + html.EscapeString(spew.Sdump(w)) + "\n-->")
+}
+
+func main() {
+    http.HandleFunc("/", handler)
+    http.ListenAndServe(":8080", nil)
+}
+```
+
+## Sample Dump Output
+
+```
+(main.Foo) {
+ unexportedField: (*main.Bar)(0xf84002e210)({
+  flag: (main.Flag) flagTwo,
+  data: (uintptr) <nil>
+ }),
+ ExportedField: (map[interface {}]interface {}) {
+  (string) "one": (bool) true
+ }
+}
+([]uint8) {
+ 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|
+}
+```
+
+## 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>}
+```
+
+## 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.
+
+```
+* 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.  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 "disableunsafe" build tag specified.
+       Pointer method invocation is enabled by default.
+
+* 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
+       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.
+
+```
+
+## Unsafe Package Dependency
+
+This package relies on the unsafe package to perform some of the more advanced
+features, however it also supports a "limited" mode which allows it to work in
+environments where the unsafe package is not available.  By default, it will
+operate in this mode on Google App Engine.  The "disableunsafe" build tag may
+also be specified to force the package to build without using the unsafe
+package.
+
+## License
+
+Go-spew is licensed under the liberal ISC License.
diff --git a/vendor/github.com/git-lfs/gitobj/vendor/github.com/davecgh/go-spew/cov_report.sh b/vendor/github.com/git-lfs/gitobj/vendor/github.com/davecgh/go-spew/cov_report.sh
new file mode 100644 (file)
index 0000000..9579497
--- /dev/null
@@ -0,0 +1,22 @@
+#!/bin/sh
+
+# This script uses gocov to generate a test coverage report.
+# The gocov tool my be obtained with the following command:
+#   go get github.com/axw/gocov/gocov
+#
+# It will be installed to $GOPATH/bin, so ensure that location is in your $PATH.
+
+# Check for gocov.
+if ! type gocov >/dev/null 2>&1; then
+       echo >&2 "This script requires the gocov tool."
+       echo >&2 "You may obtain it with the following command:"
+       echo >&2 "go get github.com/axw/gocov/gocov"
+       exit 1
+fi
+
+# Only run the cgo tests if gcc is installed.
+if type gcc >/dev/null 2>&1; then
+       (cd spew && gocov test -tags testcgo | gocov report)
+else
+       (cd spew && gocov test | gocov report)
+fi
diff --git a/vendor/github.com/git-lfs/gitobj/vendor/github.com/davecgh/go-spew/spew/bypass.go b/vendor/github.com/git-lfs/gitobj/vendor/github.com/davecgh/go-spew/spew/bypass.go
new file mode 100644 (file)
index 0000000..565bf58
--- /dev/null
@@ -0,0 +1,151 @@
+// Copyright (c) 2015 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 and "-tags disableunsafe"
+// is not added to the go build command line.
+// +build !appengine,!disableunsafe
+
+package spew
+
+import (
+       "reflect"
+       "unsafe"
+)
+
+const (
+       // UnsafeDisabled is a build-time constant which specifies whether or
+       // not access to the unsafe package is available.
+       UnsafeDisabled = false
+
+       // ptrSize is the size of a pointer on the current arch.
+       ptrSize = unsafe.Sizeof((*byte)(nil))
+)
+
+var (
+       // offsetPtr, offsetScalar, and offsetFlag are the offsets for the
+       // internal reflect.Value fields.  These values are valid before golang
+       // commit ecccf07e7f9d which changed the format.  The are also valid
+       // after commit 82f48826c6c7 which changed the format again to mirror
+       // the original format.  Code in the init function updates these offsets
+       // as necessary.
+       offsetPtr    = uintptr(ptrSize)
+       offsetScalar = uintptr(0)
+       offsetFlag   = uintptr(ptrSize * 2)
+
+       // flagKindWidth and flagKindShift indicate various bits that the
+       // reflect package uses internally to track kind information.
+       //
+       // flagRO indicates whether or not the value field of a reflect.Value is
+       // read-only.
+       //
+       // flagIndir indicates whether the value field of a reflect.Value is
+       // the actual data or a pointer to the data.
+       //
+       // These values are valid before golang commit 90a7c3c86944 which
+       // changed their positions.  Code in the init function updates these
+       // flags as necessary.
+       flagKindWidth = uintptr(5)
+       flagKindShift = uintptr(flagKindWidth - 1)
+       flagRO        = uintptr(1 << 0)
+       flagIndir     = uintptr(1 << 1)
+)
+
+func init() {
+       // Older versions of reflect.Value stored small integers directly in the
+       // ptr field (which is named val in the older versions).  Versions
+       // between commits ecccf07e7f9d and 82f48826c6c7 added a new field named
+       // scalar for this purpose which unfortunately came before the flag
+       // field, so the offset of the flag field is different for those
+       // versions.
+       //
+       // This code constructs a new reflect.Value from a known small integer
+       // and checks if the size of the reflect.Value struct indicates it has
+       // the scalar field. When it does, the offsets are updated accordingly.
+       vv := reflect.ValueOf(0xf00)
+       if unsafe.Sizeof(vv) == (ptrSize * 4) {
+               offsetScalar = ptrSize * 2
+               offsetFlag = ptrSize * 3
+       }
+
+       // Commit 90a7c3c86944 changed the flag positions such that the low
+       // order bits are the kind.  This code extracts the kind from the flags
+       // field and ensures it's the correct type.  When it's not, the flag
+       // order has been changed to the newer format, so the flags are updated
+       // accordingly.
+       upf := unsafe.Pointer(uintptr(unsafe.Pointer(&vv)) + offsetFlag)
+       upfv := *(*uintptr)(upf)
+       flagKindMask := uintptr((1<<flagKindWidth - 1) << flagKindShift)
+       if (upfv&flagKindMask)>>flagKindShift != uintptr(reflect.Int) {
+               flagKindShift = 0
+               flagRO = 1 << 5
+               flagIndir = 1 << 6
+
+               // Commit adf9b30e5594 modified the flags to separate the
+               // flagRO flag into two bits which specifies whether or not the
+               // field is embedded.  This causes flagIndir to move over a bit
+               // and means that flagRO is the combination of either of the
+               // original flagRO bit and the new bit.
+               //
+               // This code detects the change by extracting what used to be
+               // the indirect bit to ensure it's set.  When it's not, the flag
+               // order has been changed to the newer format, so the flags are
+               // updated accordingly.
+               if upfv&flagIndir == 0 {
+                       flagRO = 3 << 5
+                       flagIndir = 1 << 7
+               }
+       }
+}
+
+// unsafeReflectValue converts the passed reflect.Value into a one that bypasses
+// the typical safety restrictions preventing access to unaddressable and
+// unexported data.  It works by digging the raw pointer to the underlying
+// value out of the protected value and generating a new unprotected (unsafe)
+// reflect.Value to it.
+//
+// This allows us to check for implementations of the Stringer and error
+// interfaces to be used for pretty printing ordinarily unaddressable and
+// inaccessible values such as unexported struct fields.
+func unsafeReflectValue(v reflect.Value) (rv reflect.Value) {
+       indirects := 1
+       vt := v.Type()
+       upv := unsafe.Pointer(uintptr(unsafe.Pointer(&v)) + offsetPtr)
+       rvf := *(*uintptr)(unsafe.Pointer(uintptr(unsafe.Pointer(&v)) + offsetFlag))
+       if rvf&flagIndir != 0 {
+               vt = reflect.PtrTo(v.Type())
+               indirects++
+       } else if offsetScalar != 0 {
+               // The value is in the scalar field when it's not one of the
+               // reference types.
+               switch vt.Kind() {
+               case reflect.Uintptr:
+               case reflect.Chan:
+               case reflect.Func:
+               case reflect.Map:
+               case reflect.Ptr:
+               case reflect.UnsafePointer:
+               default:
+                       upv = unsafe.Pointer(uintptr(unsafe.Pointer(&v)) +
+                               offsetScalar)
+               }
+       }
+
+       pv := reflect.NewAt(vt, upv)
+       rv = pv
+       for i := 0; i < indirects; i++ {
+               rv = rv.Elem()
+       }
+       return rv
+}
diff --git a/vendor/github.com/git-lfs/gitobj/vendor/github.com/davecgh/go-spew/spew/bypasssafe.go b/vendor/github.com/git-lfs/gitobj/vendor/github.com/davecgh/go-spew/spew/bypasssafe.go
new file mode 100644 (file)
index 0000000..457e412
--- /dev/null
@@ -0,0 +1,37 @@
+// Copyright (c) 2015 Dave Collins <dave@davec.name>
+//
+// Permission to use, copy, modify, and distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+// NOTE: Due to the following build constraints, this file will only be compiled
+// when either the code is running on Google App Engine or "-tags disableunsafe"
+// is added to the go build command line.
+// +build appengine disableunsafe
+
+package spew
+
+import "reflect"
+
+const (
+       // UnsafeDisabled is a build-time constant which specifies whether or
+       // not access to the unsafe package is available.
+       UnsafeDisabled = true
+)
+
+// unsafeReflectValue typically converts the passed reflect.Value into a one
+// that bypasses the typical safety restrictions preventing access to
+// unaddressable and unexported data.  However, doing this relies on access to
+// the unsafe package.  This is a stub version which simply returns the passed
+// reflect.Value when the unsafe package is not available.
+func unsafeReflectValue(v reflect.Value) reflect.Value {
+       return v
+}
diff --git a/vendor/github.com/git-lfs/gitobj/vendor/github.com/davecgh/go-spew/spew/common.go b/vendor/github.com/git-lfs/gitobj/vendor/github.com/davecgh/go-spew/spew/common.go
new file mode 100644 (file)
index 0000000..14f02dc
--- /dev/null
@@ -0,0 +1,341 @@
+/*
+ * Copyright (c) 2013 Dave Collins <dave@davec.name>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+package spew
+
+import (
+       "bytes"
+       "fmt"
+       "io"
+       "reflect"
+       "sort"
+       "strconv"
+)
+
+// Some constants in the form of bytes to avoid string overhead.  This mirrors
+// the technique used in the fmt package.
+var (
+       panicBytes            = []byte("(PANIC=")
+       plusBytes             = []byte("+")
+       iBytes                = []byte("i")
+       trueBytes             = []byte("true")
+       falseBytes            = []byte("false")
+       interfaceBytes        = []byte("(interface {})")
+       commaNewlineBytes     = []byte(",\n")
+       newlineBytes          = []byte("\n")
+       openBraceBytes        = []byte("{")
+       openBraceNewlineBytes = []byte("{\n")
+       closeBraceBytes       = []byte("}")
+       asteriskBytes         = []byte("*")
+       colonBytes            = []byte(":")
+       colonSpaceBytes       = []byte(": ")
+       openParenBytes        = []byte("(")
+       closeParenBytes       = []byte(")")
+       spaceBytes            = []byte(" ")
+       pointerChainBytes     = []byte("->")
+       nilAngleBytes         = []byte("<nil>")
+       maxNewlineBytes       = []byte("<max depth reached>\n")
+       maxShortBytes         = []byte("<max>")
+       circularBytes         = []byte("<already shown>")
+       circularShortBytes    = []byte("<shown>")
+       invalidAngleBytes     = []byte("<invalid>")
+       openBracketBytes      = []byte("[")
+       closeBracketBytes     = []byte("]")
+       percentBytes          = []byte("%")
+       precisionBytes        = []byte(".")
+       openAngleBytes        = []byte("<")
+       closeAngleBytes       = []byte(">")
+       openMapBytes          = []byte("map[")
+       closeMapBytes         = []byte("]")
+       lenEqualsBytes        = []byte("len=")
+       capEqualsBytes        = []byte("cap=")
+)
+
+// hexDigits is used to map a decimal value to a hex digit.
+var hexDigits = "0123456789abcdef"
+
+// catchPanic handles any panics that might occur during the handleMethods
+// calls.
+func catchPanic(w io.Writer, v reflect.Value) {
+       if err := recover(); err != nil {
+               w.Write(panicBytes)
+               fmt.Fprintf(w, "%v", err)
+               w.Write(closeParenBytes)
+       }
+}
+
+// handleMethods attempts to call the Error and String methods on the underlying
+// type the passed reflect.Value represents and outputes the result to Writer w.
+//
+// It handles panics in any called methods by catching and displaying the error
+// as the formatted value.
+func handleMethods(cs *ConfigState, w io.Writer, v reflect.Value) (handled bool) {
+       // We need an interface to check if the type implements the error or
+       // Stringer interface.  However, the reflect package won't give us an
+       // interface on certain things like unexported struct fields in order
+       // to enforce visibility rules.  We use unsafe, when it's available,
+       // to bypass these restrictions since this package does not mutate the
+       // values.
+       if !v.CanInterface() {
+               if UnsafeDisabled {
+                       return false
+               }
+
+               v = unsafeReflectValue(v)
+       }
+
+       // Choose whether or not to do error and Stringer interface lookups against
+       // the base type or a pointer to the base type depending on settings.
+       // Technically calling one of these methods with a pointer receiver can
+       // mutate the value, however, types which choose to satisify an error or
+       // Stringer interface with a pointer receiver should not be mutating their
+       // state inside these interface methods.
+       if !cs.DisablePointerMethods && !UnsafeDisabled && !v.CanAddr() {
+               v = unsafeReflectValue(v)
+       }
+       if v.CanAddr() {
+               v = v.Addr()
+       }
+
+       // Is it an error or Stringer?
+       switch iface := v.Interface().(type) {
+       case error:
+               defer catchPanic(w, v)
+               if cs.ContinueOnMethod {
+                       w.Write(openParenBytes)
+                       w.Write([]byte(iface.Error()))
+                       w.Write(closeParenBytes)
+                       w.Write(spaceBytes)
+                       return false
+               }
+
+               w.Write([]byte(iface.Error()))
+               return true
+
+       case fmt.Stringer:
+               defer catchPanic(w, v)
+               if cs.ContinueOnMethod {
+                       w.Write(openParenBytes)
+                       w.Write([]byte(iface.String()))
+                       w.Write(closeParenBytes)
+                       w.Write(spaceBytes)
+                       return false
+               }
+               w.Write([]byte(iface.String()))
+               return true
+       }
+       return false
+}
+
+// printBool outputs a boolean value as true or false to Writer w.
+func printBool(w io.Writer, val bool) {
+       if val {
+               w.Write(trueBytes)
+       } else {
+               w.Write(falseBytes)
+       }
+}
+
+// printInt outputs a signed integer value to Writer w.
+func printInt(w io.Writer, val int64, base int) {
+       w.Write([]byte(strconv.FormatInt(val, base)))
+}
+
+// printUint outputs an unsigned integer value to Writer w.
+func printUint(w io.Writer, val uint64, base int) {
+       w.Write([]byte(strconv.FormatUint(val, base)))
+}
+
+// printFloat outputs a floating point value using the specified precision,
+// which is expected to be 32 or 64bit, to Writer w.
+func printFloat(w io.Writer, val float64, precision int) {
+       w.Write([]byte(strconv.FormatFloat(val, 'g', -1, precision)))
+}
+
+// printComplex outputs a complex value using the specified float precision
+// for the real and imaginary parts to Writer w.
+func printComplex(w io.Writer, c complex128, floatPrecision int) {
+       r := real(c)
+       w.Write(openParenBytes)
+       w.Write([]byte(strconv.FormatFloat(r, 'g', -1, floatPrecision)))
+       i := imag(c)
+       if i >= 0 {
+               w.Write(plusBytes)
+       }
+       w.Write([]byte(strconv.FormatFloat(i, 'g', -1, floatPrecision)))
+       w.Write(iBytes)
+       w.Write(closeParenBytes)
+}
+
+// printHexPtr outputs a uintptr formatted as hexidecimal with a leading '0x'
+// prefix to Writer w.
+func printHexPtr(w io.Writer, p uintptr) {
+       // Null pointer.
+       num := uint64(p)
+       if num == 0 {
+               w.Write(nilAngleBytes)
+               return
+       }
+
+       // Max uint64 is 16 bytes in hex + 2 bytes for '0x' prefix
+       buf := make([]byte, 18)
+
+       // It's simpler to construct the hex string right to left.
+       base := uint64(16)
+       i := len(buf) - 1
+       for num >= base {
+               buf[i] = hexDigits[num%base]
+               num /= base
+               i--
+       }
+       buf[i] = hexDigits[num]
+
+       // Add '0x' prefix.
+       i--
+       buf[i] = 'x'
+       i--
+       buf[i] = '0'
+
+       // Strip unused leading bytes.
+       buf = buf[i:]
+       w.Write(buf)
+}
+
+// valuesSorter implements sort.Interface to allow a slice of reflect.Value
+// elements to be sorted.
+type valuesSorter struct {
+       values  []reflect.Value
+       strings []string // either nil or same len and values
+       cs      *ConfigState
+}
+
+// newValuesSorter initializes a valuesSorter instance, which holds a set of
+// surrogate keys on which the data should be sorted.  It uses flags in
+// ConfigState to decide if and how to populate those surrogate keys.
+func newValuesSorter(values []reflect.Value, cs *ConfigState) sort.Interface {
+       vs := &valuesSorter{values: values, cs: cs}
+       if canSortSimply(vs.values[0].Kind()) {
+               return vs
+       }
+       if !cs.DisableMethods {
+               vs.strings = make([]string, len(values))
+               for i := range vs.values {
+                       b := bytes.Buffer{}
+                       if !handleMethods(cs, &b, vs.values[i]) {
+                               vs.strings = nil
+                               break
+                       }
+                       vs.strings[i] = b.String()
+               }
+       }
+       if vs.strings == nil && cs.SpewKeys {
+               vs.strings = make([]string, len(values))
+               for i := range vs.values {
+                       vs.strings[i] = Sprintf("%#v", vs.values[i].Interface())
+               }
+       }
+       return vs
+}
+
+// canSortSimply tests whether a reflect.Kind is a primitive that can be sorted
+// directly, or whether it should be considered for sorting by surrogate keys
+// (if the ConfigState allows it).
+func canSortSimply(kind reflect.Kind) bool {
+       // This switch parallels valueSortLess, except for the default case.
+       switch kind {
+       case reflect.Bool:
+               return true
+       case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int:
+               return true
+       case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint:
+               return true
+       case reflect.Float32, reflect.Float64:
+               return true
+       case reflect.String:
+               return true
+       case reflect.Uintptr:
+               return true
+       case reflect.Array:
+               return true
+       }
+       return false
+}
+
+// Len returns the number of values in the slice.  It is part of the
+// sort.Interface implementation.
+func (s *valuesSorter) Len() int {
+       return len(s.values)
+}
+
+// Swap swaps the values at the passed indices.  It is part of the
+// sort.Interface implementation.
+func (s *valuesSorter) Swap(i, j int) {
+       s.values[i], s.values[j] = s.values[j], s.values[i]
+       if s.strings != nil {
+               s.strings[i], s.strings[j] = s.strings[j], s.strings[i]
+       }
+}
+
+// valueSortLess returns whether the first value should sort before the second
+// value.  It is used by valueSorter.Less as part of the sort.Interface
+// implementation.
+func valueSortLess(a, b reflect.Value) bool {
+       switch a.Kind() {
+       case reflect.Bool:
+               return !a.Bool() && b.Bool()
+       case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int:
+               return a.Int() < b.Int()
+       case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint:
+               return a.Uint() < b.Uint()
+       case reflect.Float32, reflect.Float64:
+               return a.Float() < b.Float()
+       case reflect.String:
+               return a.String() < b.String()
+       case reflect.Uintptr:
+               return a.Uint() < b.Uint()
+       case reflect.Array:
+               // Compare the contents of both arrays.
+               l := a.Len()
+               for i := 0; i < l; i++ {
+                       av := a.Index(i)
+                       bv := b.Index(i)
+                       if av.Interface() == bv.Interface() {
+                               continue
+                       }
+                       return valueSortLess(av, bv)
+               }
+       }
+       return a.String() < b.String()
+}
+
+// Less returns whether the value at index i should sort before the
+// value at index j.  It is part of the sort.Interface implementation.
+func (s *valuesSorter) Less(i, j int) bool {
+       if s.strings == nil {
+               return valueSortLess(s.values[i], s.values[j])
+       }
+       return s.strings[i] < s.strings[j]
+}
+
+// sortValues is a sort function that handles both native types and any type that
+// can be converted to error or Stringer.  Other inputs are sorted according to
+// their Value.String() value to ensure display stability.
+func sortValues(values []reflect.Value, cs *ConfigState) {
+       if len(values) == 0 {
+               return
+       }
+       sort.Sort(newValuesSorter(values, cs))
+}
diff --git a/vendor/github.com/git-lfs/gitobj/vendor/github.com/davecgh/go-spew/spew/common_test.go b/vendor/github.com/git-lfs/gitobj/vendor/github.com/davecgh/go-spew/spew/common_test.go
new file mode 100644 (file)
index 0000000..39b7525
--- /dev/null
@@ -0,0 +1,298 @@
+/*
+ * Copyright (c) 2013 Dave Collins <dave@davec.name>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+package spew_test
+
+import (
+       "fmt"
+       "reflect"
+       "testing"
+
+       "github.com/davecgh/go-spew/spew"
+)
+
+// custom type to test Stinger interface on non-pointer receiver.
+type stringer string
+
+// String implements the Stringer interface for testing invocation of custom
+// stringers on types with non-pointer receivers.
+func (s stringer) String() string {
+       return "stringer " + string(s)
+}
+
+// custom type to test Stinger interface on pointer receiver.
+type pstringer string
+
+// String implements the Stringer interface for testing invocation of custom
+// stringers on types with only pointer receivers.
+func (s *pstringer) String() string {
+       return "stringer " + string(*s)
+}
+
+// xref1 and xref2 are cross referencing structs for testing circular reference
+// detection.
+type xref1 struct {
+       ps2 *xref2
+}
+type xref2 struct {
+       ps1 *xref1
+}
+
+// indirCir1, indirCir2, and indirCir3 are used to generate an indirect circular
+// reference for testing detection.
+type indirCir1 struct {
+       ps2 *indirCir2
+}
+type indirCir2 struct {
+       ps3 *indirCir3
+}
+type indirCir3 struct {
+       ps1 *indirCir1
+}
+
+// embed is used to test embedded structures.
+type embed struct {
+       a string
+}
+
+// embedwrap is used to test embedded structures.
+type embedwrap struct {
+       *embed
+       e *embed
+}
+
+// panicer is used to intentionally cause a panic for testing spew properly
+// handles them
+type panicer int
+
+func (p panicer) String() string {
+       panic("test panic")
+}
+
+// customError is used to test custom error interface invocation.
+type customError int
+
+func (e customError) Error() string {
+       return fmt.Sprintf("error: %d", int(e))
+}
+
+// stringizeWants converts a slice of wanted test output into a format suitable
+// for a test error message.
+func stringizeWants(wants []string) string {
+       s := ""
+       for i, want := range wants {
+               if i > 0 {
+                       s += fmt.Sprintf("want%d: %s", i+1, want)
+               } else {
+                       s += "want: " + want
+               }
+       }
+       return s
+}
+
+// testFailed returns whether or not a test failed by checking if the result
+// of the test is in the slice of wanted strings.
+func testFailed(result string, wants []string) bool {
+       for _, want := range wants {
+               if result == want {
+                       return false
+               }
+       }
+       return true
+}
+
+type sortableStruct struct {
+       x int
+}
+
+func (ss sortableStruct) String() string {
+       return fmt.Sprintf("ss.%d", ss.x)
+}
+
+type unsortableStruct struct {
+       x int
+}
+
+type sortTestCase struct {
+       input    []reflect.Value
+       expected []reflect.Value
+}
+
+func helpTestSortValues(tests []sortTestCase, cs *spew.ConfigState, t *testing.T) {
+       getInterfaces := func(values []reflect.Value) []interface{} {
+               interfaces := []interface{}{}
+               for _, v := range values {
+                       interfaces = append(interfaces, v.Interface())
+               }
+               return interfaces
+       }
+
+       for _, test := range tests {
+               spew.SortValues(test.input, cs)
+               // reflect.DeepEqual cannot really make sense of reflect.Value,
+               // probably because of all the pointer tricks. For instance,
+               // v(2.0) != v(2.0) on a 32-bits system. Turn them into interface{}
+               // instead.
+               input := getInterfaces(test.input)
+               expected := getInterfaces(test.expected)
+               if !reflect.DeepEqual(input, expected) {
+                       t.Errorf("Sort mismatch:\n %v != %v", input, expected)
+               }
+       }
+}
+
+// TestSortValues ensures the sort functionality for relect.Value based sorting
+// works as intended.
+func TestSortValues(t *testing.T) {
+       v := reflect.ValueOf
+
+       a := v("a")
+       b := v("b")
+       c := v("c")
+       embedA := v(embed{"a"})
+       embedB := v(embed{"b"})
+       embedC := v(embed{"c"})
+       tests := []sortTestCase{
+               // No values.
+               {
+                       []reflect.Value{},
+                       []reflect.Value{},
+               },
+               // Bools.
+               {
+                       []reflect.Value{v(false), v(true), v(false)},
+                       []reflect.Value{v(false), v(false), v(true)},
+               },
+               // Ints.
+               {
+                       []reflect.Value{v(2), v(1), v(3)},
+                       []reflect.Value{v(1), v(2), v(3)},
+               },
+               // Uints.
+               {
+                       []reflect.Value{v(uint8(2)), v(uint8(1)), v(uint8(3))},
+                       []reflect.Value{v(uint8(1)), v(uint8(2)), v(uint8(3))},
+               },
+               // Floats.
+               {
+                       []reflect.Value{v(2.0), v(1.0), v(3.0)},
+                       []reflect.Value{v(1.0), v(2.0), v(3.0)},
+               },
+               // Strings.
+               {
+                       []reflect.Value{b, a, c},
+                       []reflect.Value{a, b, c},
+               },
+               // Array
+               {
+                       []reflect.Value{v([3]int{3, 2, 1}), v([3]int{1, 3, 2}), v([3]int{1, 2, 3})},
+                       []reflect.Value{v([3]int{1, 2, 3}), v([3]int{1, 3, 2}), v([3]int{3, 2, 1})},
+               },
+               // Uintptrs.
+               {
+                       []reflect.Value{v(uintptr(2)), v(uintptr(1)), v(uintptr(3))},
+                       []reflect.Value{v(uintptr(1)), v(uintptr(2)), v(uintptr(3))},
+               },
+               // SortableStructs.
+               {
+                       // Note: not sorted - DisableMethods is set.
+                       []reflect.Value{v(sortableStruct{2}), v(sortableStruct{1}), v(sortableStruct{3})},
+                       []reflect.Value{v(sortableStruct{2}), v(sortableStruct{1}), v(sortableStruct{3})},
+               },
+               // UnsortableStructs.
+               {
+                       // Note: not sorted - SpewKeys is false.
+                       []reflect.Value{v(unsortableStruct{2}), v(unsortableStruct{1}), v(unsortableStruct{3})},
+                       []reflect.Value{v(unsortableStruct{2}), v(unsortableStruct{1}), v(unsortableStruct{3})},
+               },
+               // Invalid.
+               {
+                       []reflect.Value{embedB, embedA, embedC},
+                       []reflect.Value{embedB, embedA, embedC},
+               },
+       }
+       cs := spew.ConfigState{DisableMethods: true, SpewKeys: false}
+       helpTestSortValues(tests, &cs, t)
+}
+
+// TestSortValuesWithMethods ensures the sort functionality for relect.Value
+// based sorting works as intended when using string methods.
+func TestSortValuesWithMethods(t *testing.T) {
+       v := reflect.ValueOf
+
+       a := v("a")
+       b := v("b")
+       c := v("c")
+       tests := []sortTestCase{
+               // Ints.
+               {
+                       []reflect.Value{v(2), v(1), v(3)},
+                       []reflect.Value{v(1), v(2), v(3)},
+               },
+               // Strings.
+               {
+                       []reflect.Value{b, a, c},
+                       []reflect.Value{a, b, c},
+               },
+               // SortableStructs.
+               {
+                       []reflect.Value{v(sortableStruct{2}), v(sortableStruct{1}), v(sortableStruct{3})},
+                       []reflect.Value{v(sortableStruct{1}), v(sortableStruct{2}), v(sortableStruct{3})},
+               },
+               // UnsortableStructs.
+               {
+                       // Note: not sorted - SpewKeys is false.
+                       []reflect.Value{v(unsortableStruct{2}), v(unsortableStruct{1}), v(unsortableStruct{3})},
+                       []reflect.Value{v(unsortableStruct{2}), v(unsortableStruct{1}), v(unsortableStruct{3})},
+               },
+       }
+       cs := spew.ConfigState{DisableMethods: false, SpewKeys: false}
+       helpTestSortValues(tests, &cs, t)
+}
+
+// TestSortValuesWithSpew ensures the sort functionality for relect.Value
+// based sorting works as intended when using spew to stringify keys.
+func TestSortValuesWithSpew(t *testing.T) {
+       v := reflect.ValueOf
+
+       a := v("a")
+       b := v("b")
+       c := v("c")
+       tests := []sortTestCase{
+               // Ints.
+               {
+                       []reflect.Value{v(2), v(1), v(3)},
+                       []reflect.Value{v(1), v(2), v(3)},
+               },
+               // Strings.
+               {
+                       []reflect.Value{b, a, c},
+                       []reflect.Value{a, b, c},
+               },
+               // SortableStructs.
+               {
+                       []reflect.Value{v(sortableStruct{2}), v(sortableStruct{1}), v(sortableStruct{3})},
+                       []reflect.Value{v(sortableStruct{1}), v(sortableStruct{2}), v(sortableStruct{3})},
+               },
+               // UnsortableStructs.
+               {
+                       []reflect.Value{v(unsortableStruct{2}), v(unsortableStruct{1}), v(unsortableStruct{3})},
+                       []reflect.Value{v(unsortableStruct{1}), v(unsortableStruct{2}), v(unsortableStruct{3})},
+               },
+       }
+       cs := spew.ConfigState{DisableMethods: true, SpewKeys: true}
+       helpTestSortValues(tests, &cs, t)
+}
diff --git a/vendor/github.com/git-lfs/gitobj/vendor/github.com/davecgh/go-spew/spew/config.go b/vendor/github.com/git-lfs/gitobj/vendor/github.com/davecgh/go-spew/spew/config.go
new file mode 100644 (file)
index 0000000..ee1ab07
--- /dev/null
@@ -0,0 +1,297 @@
+/*
+ * Copyright (c) 2013 Dave Collins <dave@davec.name>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+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 "disableunsafe" build tag specified.
+       DisablePointerMethods 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: " "}
+}
diff --git a/vendor/github.com/git-lfs/gitobj/vendor/github.com/davecgh/go-spew/spew/doc.go b/vendor/github.com/git-lfs/gitobj/vendor/github.com/davecgh/go-spew/spew/doc.go
new file mode 100644 (file)
index 0000000..5be0c40
--- /dev/null
@@ -0,0 +1,202 @@
+/*
+ * Copyright (c) 2013 Dave Collins <dave@davec.name>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+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.
+
+       * 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
diff --git a/vendor/github.com/git-lfs/gitobj/vendor/github.com/davecgh/go-spew/spew/dump.go b/vendor/github.com/git-lfs/gitobj/vendor/github.com/davecgh/go-spew/spew/dump.go
new file mode 100644 (file)
index 0000000..a0ff95e
--- /dev/null
@@ -0,0 +1,509 @@
+/*
+ * Copyright (c) 2013 Dave Collins <dave@davec.name>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+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 len(pointerChain) > 0 {
+               d.w.Write(openParenBytes)
+               for i, addr := range pointerChain {
+                       if i > 0 {
+                               d.w.Write(pointerChainBytes)
+                       }
+                       printHexPtr(d.w, addr)
+               }
+               d.w.Write(closeParenBytes)
+       }
+
+       // Display dereferenced value.
+       d.w.Write(openParenBytes)
+       switch {
+       case nilFound == true:
+               d.w.Write(nilAngleBytes)
+
+       case cycleFound == true:
+               d.w.Write(circularBytes)
+
+       default:
+               d.ignoreNextType = true
+               d.dump(ve)
+       }
+       d.w.Write(closeParenBytes)
+}
+
+// dumpSlice handles formatting of arrays and slices.  Byte (uint8 under
+// reflection) arrays and slices are dumped in hexdump -C fashion.
+func (d *dumpState) dumpSlice(v reflect.Value) {
+       // Determine whether this type should be hex dumped or not.  Also,
+       // for types which should be hexdumped, try to use the underlying data
+       // first, then fall back to trying to convert them to a uint8 slice.
+       var buf []uint8
+       doConvert := false
+       doHexDump := false
+       numEntries := v.Len()
+       if numEntries > 0 {
+               vt := v.Index(0).Type()
+               vts := vt.String()
+               switch {
+               // C types that need to be converted.
+               case cCharRE.MatchString(vts):
+                       fallthrough
+               case cUnsignedCharRE.MatchString(vts):
+                       fallthrough
+               case cUint8tCharRE.MatchString(vts):
+                       doConvert = true
+
+               // Try to use existing uint8 slices and fall back to converting
+               // and copying if that fails.
+               case vt.Kind() == reflect.Uint8:
+                       // We need an addressable interface to convert the type
+                       // to a byte slice.  However, the reflect package won't
+                       // give us an interface on certain things like
+                       // unexported struct fields in order to enforce
+                       // visibility rules.  We use unsafe, when available, to
+                       // bypass these restrictions since this package does not
+                       // mutate the values.
+                       vs := v
+                       if !vs.CanInterface() || !vs.CanAddr() {
+                               vs = unsafeReflectValue(vs)
+                       }
+                       if !UnsafeDisabled {
+                               vs = vs.Slice(0, numEntries)
+
+                               // Use the existing uint8 slice if it can be
+                               // type asserted.
+                               iface := vs.Interface()
+                               if slice, ok := iface.([]uint8); ok {
+                                       buf = slice
+                                       doHexDump = true
+                                       break
+                               }
+                       }
+
+                       // The underlying data needs to be converted if it can't
+                       // be type asserted to a uint8 slice.
+                       doConvert = true
+               }
+
+               // Copy and convert the underlying type if needed.
+               if doConvert && vt.ConvertibleTo(uint8Type) {
+                       // Convert and copy each element into a uint8 byte
+                       // slice.
+                       buf = make([]uint8, numEntries)
+                       for i := 0; i < numEntries; i++ {
+                               vv := v.Index(i)
+                               buf[i] = uint8(vv.Convert(uint8Type).Uint())
+                       }
+                       doHexDump = true
+               }
+       }
+
+       // Hexdump the entire slice as needed.
+       if doHexDump {
+               indent := strings.Repeat(d.cs.Indent, d.depth)
+               str := indent + hex.Dump(buf)
+               str = strings.Replace(str, "\n", "\n"+indent, -1)
+               str = strings.TrimRight(str, d.cs.Indent)
+               d.w.Write([]byte(str))
+               return
+       }
+
+       // Recursively call dump for each item.
+       for i := 0; i < numEntries; i++ {
+               d.dump(d.unpackValue(v.Index(i)))
+               if i < (numEntries - 1) {
+                       d.w.Write(commaNewlineBytes)
+               } else {
+                       d.w.Write(newlineBytes)
+               }
+       }
+}
+
+// dump is the main workhorse for dumping a value.  It uses the passed reflect
+// value to figure out what kind of object we are dealing with and formats it
+// appropriately.  It is a recursive function, however circular data structures
+// are detected and handled properly.
+func (d *dumpState) dump(v reflect.Value) {
+       // Handle invalid reflect values immediately.
+       kind := v.Kind()
+       if kind == reflect.Invalid {
+               d.w.Write(invalidAngleBytes)
+               return
+       }
+
+       // Handle pointers specially.
+       if kind == reflect.Ptr {
+               d.indent()
+               d.dumpPtr(v)
+               return
+       }
+
+       // Print type information unless already handled elsewhere.
+       if !d.ignoreNextType {
+               d.indent()
+               d.w.Write(openParenBytes)
+               d.w.Write([]byte(v.Type().String()))
+               d.w.Write(closeParenBytes)
+               d.w.Write(spaceBytes)
+       }
+       d.ignoreNextType = false
+
+       // Display length and capacity if the built-in len and cap functions
+       // work with the value's kind and the len/cap itself is non-zero.
+       valueLen, valueCap := 0, 0
+       switch v.Kind() {
+       case reflect.Array, reflect.Slice, reflect.Chan:
+               valueLen, valueCap = v.Len(), v.Cap()
+       case reflect.Map, reflect.String:
+               valueLen = v.Len()
+       }
+       if valueLen != 0 || valueCap != 0 {
+               d.w.Write(openParenBytes)
+               if valueLen != 0 {
+                       d.w.Write(lenEqualsBytes)
+                       printInt(d.w, int64(valueLen), 10)
+               }
+               if 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...)
+}
diff --git a/vendor/github.com/git-lfs/gitobj/vendor/github.com/davecgh/go-spew/spew/dump_test.go b/vendor/github.com/git-lfs/gitobj/vendor/github.com/davecgh/go-spew/spew/dump_test.go
new file mode 100644 (file)
index 0000000..2b32040
--- /dev/null
@@ -0,0 +1,1042 @@
+/*
+ * Copyright (c) 2013 Dave Collins <dave@davec.name>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+Test Summary:
+NOTE: For each test, a nil pointer, a single pointer and double pointer to the
+base test element are also tested to ensure proper indirection across all types.
+
+- Max int8, int16, int32, int64, int
+- Max uint8, uint16, uint32, uint64, uint
+- Boolean true and false
+- Standard complex64 and complex128
+- Array containing standard ints
+- Array containing type with custom formatter on pointer receiver only
+- Array containing interfaces
+- Array containing bytes
+- Slice containing standard float32 values
+- Slice containing type with custom formatter on pointer receiver only
+- Slice containing interfaces
+- Slice containing bytes
+- Nil slice
+- Standard string
+- Nil interface
+- Sub-interface
+- Map with string keys and int vals
+- Map with custom formatter type on pointer receiver only keys and vals
+- Map with interface keys and values
+- Map with nil interface value
+- Struct with primitives
+- Struct that contains another struct
+- Struct that contains custom type with Stringer pointer interface via both
+  exported and unexported fields
+- Struct that contains embedded struct and field to same struct
+- Uintptr to 0 (null pointer)
+- Uintptr address of real variable
+- Unsafe.Pointer to 0 (null pointer)
+- Unsafe.Pointer to address of real variable
+- Nil channel
+- Standard int channel
+- Function with no params and no returns
+- Function with param and no returns
+- Function with multiple params and multiple returns
+- Struct that is circular through self referencing
+- Structs that are circular through cross referencing
+- Structs that are indirectly circular
+- Type that panics in its Stringer interface
+*/
+
+package spew_test
+
+import (
+       "bytes"
+       "fmt"
+       "testing"
+       "unsafe"
+
+       "github.com/davecgh/go-spew/spew"
+)
+
+// dumpTest is used to describe a test to be perfomed against the Dump method.
+type dumpTest struct {
+       in    interface{}
+       wants []string
+}
+
+// dumpTests houses all of the tests to be performed against the Dump method.
+var dumpTests = make([]dumpTest, 0)
+
+// addDumpTest is a helper method to append the passed input and desired result
+// to dumpTests
+func addDumpTest(in interface{}, wants ...string) {
+       test := dumpTest{in, wants}
+       dumpTests = append(dumpTests, test)
+}
+
+func addIntDumpTests() {
+       // Max int8.
+       v := int8(127)
+       nv := (*int8)(nil)
+       pv := &v
+       vAddr := fmt.Sprintf("%p", pv)
+       pvAddr := fmt.Sprintf("%p", &pv)
+       vt := "int8"
+       vs := "127"
+       addDumpTest(v, "("+vt+") "+vs+"\n")
+       addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n")
+       addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n")
+       addDumpTest(nv, "(*"+vt+")(<nil>)\n")
+
+       // Max int16.
+       v2 := int16(32767)
+       nv2 := (*int16)(nil)
+       pv2 := &v2
+       v2Addr := fmt.Sprintf("%p", pv2)
+       pv2Addr := fmt.Sprintf("%p", &pv2)
+       v2t := "int16"
+       v2s := "32767"
+       addDumpTest(v2, "("+v2t+") "+v2s+"\n")
+       addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s+")\n")
+       addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n")
+       addDumpTest(nv2, "(*"+v2t+")(<nil>)\n")
+
+       // Max int32.
+       v3 := int32(2147483647)
+       nv3 := (*int32)(nil)
+       pv3 := &v3
+       v3Addr := fmt.Sprintf("%p", pv3)
+       pv3Addr := fmt.Sprintf("%p", &pv3)
+       v3t := "int32"
+       v3s := "2147483647"
+       addDumpTest(v3, "("+v3t+") "+v3s+"\n")
+       addDumpTest(pv3, "(*"+v3t+")("+v3Addr+")("+v3s+")\n")
+       addDumpTest(&pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")("+v3s+")\n")
+       addDumpTest(nv3, "(*"+v3t+")(<nil>)\n")
+
+       // Max int64.
+       v4 := int64(9223372036854775807)
+       nv4 := (*int64)(nil)
+       pv4 := &v4
+       v4Addr := fmt.Sprintf("%p", pv4)
+       pv4Addr := fmt.Sprintf("%p", &pv4)
+       v4t := "int64"
+       v4s := "9223372036854775807"
+       addDumpTest(v4, "("+v4t+") "+v4s+"\n")
+       addDumpTest(pv4, "(*"+v4t+")("+v4Addr+")("+v4s+")\n")
+       addDumpTest(&pv4, "(**"+v4t+")("+pv4Addr+"->"+v4Addr+")("+v4s+")\n")
+       addDumpTest(nv4, "(*"+v4t+")(<nil>)\n")
+
+       // Max int.
+       v5 := int(2147483647)
+       nv5 := (*int)(nil)
+       pv5 := &v5
+       v5Addr := fmt.Sprintf("%p", pv5)
+       pv5Addr := fmt.Sprintf("%p", &pv5)
+       v5t := "int"
+       v5s := "2147483647"
+       addDumpTest(v5, "("+v5t+") "+v5s+"\n")
+       addDumpTest(pv5, "(*"+v5t+")("+v5Addr+")("+v5s+")\n")
+       addDumpTest(&pv5, "(**"+v5t+")("+pv5Addr+"->"+v5Addr+")("+v5s+")\n")
+       addDumpTest(nv5, "(*"+v5t+")(<nil>)\n")
+}
+
+func addUintDumpTests() {
+       // Max uint8.
+       v := uint8(255)
+       nv := (*uint8)(nil)
+       pv := &v
+       vAddr := fmt.Sprintf("%p", pv)
+       pvAddr := fmt.Sprintf("%p", &pv)
+       vt := "uint8"
+       vs := "255"
+       addDumpTest(v, "("+vt+") "+vs+"\n")
+       addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n")
+       addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n")
+       addDumpTest(nv, "(*"+vt+")(<nil>)\n")
+
+       // Max uint16.
+       v2 := uint16(65535)
+       nv2 := (*uint16)(nil)
+       pv2 := &v2
+       v2Addr := fmt.Sprintf("%p", pv2)
+       pv2Addr := fmt.Sprintf("%p", &pv2)
+       v2t := "uint16"
+       v2s := "65535"
+       addDumpTest(v2, "("+v2t+") "+v2s+"\n")
+       addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s+")\n")
+       addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n")
+       addDumpTest(nv2, "(*"+v2t+")(<nil>)\n")
+
+       // Max uint32.
+       v3 := uint32(4294967295)
+       nv3 := (*uint32)(nil)
+       pv3 := &v3
+       v3Addr := fmt.Sprintf("%p", pv3)
+       pv3Addr := fmt.Sprintf("%p", &pv3)
+       v3t := "uint32"
+       v3s := "4294967295"
+       addDumpTest(v3, "("+v3t+") "+v3s+"\n")
+       addDumpTest(pv3, "(*"+v3t+")("+v3Addr+")("+v3s+")\n")
+       addDumpTest(&pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")("+v3s+")\n")
+       addDumpTest(nv3, "(*"+v3t+")(<nil>)\n")
+
+       // Max uint64.
+       v4 := uint64(18446744073709551615)
+       nv4 := (*uint64)(nil)
+       pv4 := &v4
+       v4Addr := fmt.Sprintf("%p", pv4)
+       pv4Addr := fmt.Sprintf("%p", &pv4)
+       v4t := "uint64"
+       v4s := "18446744073709551615"
+       addDumpTest(v4, "("+v4t+") "+v4s+"\n")
+       addDumpTest(pv4, "(*"+v4t+")("+v4Addr+")("+v4s+")\n")
+       addDumpTest(&pv4, "(**"+v4t+")("+pv4Addr+"->"+v4Addr+")("+v4s+")\n")
+       addDumpTest(nv4, "(*"+v4t+")(<nil>)\n")
+
+       // Max uint.
+       v5 := uint(4294967295)
+       nv5 := (*uint)(nil)
+       pv5 := &v5
+       v5Addr := fmt.Sprintf("%p", pv5)
+       pv5Addr := fmt.Sprintf("%p", &pv5)
+       v5t := "uint"
+       v5s := "4294967295"
+       addDumpTest(v5, "("+v5t+") "+v5s+"\n")
+       addDumpTest(pv5, "(*"+v5t+")("+v5Addr+")("+v5s+")\n")
+       addDumpTest(&pv5, "(**"+v5t+")("+pv5Addr+"->"+v5Addr+")("+v5s+")\n")
+       addDumpTest(nv5, "(*"+v5t+")(<nil>)\n")
+}
+
+func addBoolDumpTests() {
+       // Boolean true.
+       v := bool(true)
+       nv := (*bool)(nil)
+       pv := &v
+       vAddr := fmt.Sprintf("%p", pv)
+       pvAddr := fmt.Sprintf("%p", &pv)
+       vt := "bool"
+       vs := "true"
+       addDumpTest(v, "("+vt+") "+vs+"\n")
+       addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n")
+       addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n")
+       addDumpTest(nv, "(*"+vt+")(<nil>)\n")
+
+       // Boolean false.
+       v2 := bool(false)
+       pv2 := &v2
+       v2Addr := fmt.Sprintf("%p", pv2)
+       pv2Addr := fmt.Sprintf("%p", &pv2)
+       v2t := "bool"
+       v2s := "false"
+       addDumpTest(v2, "("+v2t+") "+v2s+"\n")
+       addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s+")\n")
+       addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n")
+}
+
+func addFloatDumpTests() {
+       // Standard float32.
+       v := float32(3.1415)
+       nv := (*float32)(nil)
+       pv := &v
+       vAddr := fmt.Sprintf("%p", pv)
+       pvAddr := fmt.Sprintf("%p", &pv)
+       vt := "float32"
+       vs := "3.1415"
+       addDumpTest(v, "("+vt+") "+vs+"\n")
+       addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n")
+       addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n")
+       addDumpTest(nv, "(*"+vt+")(<nil>)\n")
+
+       // Standard float64.
+       v2 := float64(3.1415926)
+       nv2 := (*float64)(nil)
+       pv2 := &v2
+       v2Addr := fmt.Sprintf("%p", pv2)
+       pv2Addr := fmt.Sprintf("%p", &pv2)
+       v2t := "float64"
+       v2s := "3.1415926"
+       addDumpTest(v2, "("+v2t+") "+v2s+"\n")
+       addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s+")\n")
+       addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n")
+       addDumpTest(nv2, "(*"+v2t+")(<nil>)\n")
+}
+
+func addComplexDumpTests() {
+       // Standard complex64.
+       v := complex(float32(6), -2)
+       nv := (*complex64)(nil)
+       pv := &v
+       vAddr := fmt.Sprintf("%p", pv)
+       pvAddr := fmt.Sprintf("%p", &pv)
+       vt := "complex64"
+       vs := "(6-2i)"
+       addDumpTest(v, "("+vt+") "+vs+"\n")
+       addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n")
+       addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n")
+       addDumpTest(nv, "(*"+vt+")(<nil>)\n")
+
+       // Standard complex128.
+       v2 := complex(float64(-6), 2)
+       nv2 := (*complex128)(nil)
+       pv2 := &v2
+       v2Addr := fmt.Sprintf("%p", pv2)
+       pv2Addr := fmt.Sprintf("%p", &pv2)
+       v2t := "complex128"
+       v2s := "(-6+2i)"
+       addDumpTest(v2, "("+v2t+") "+v2s+"\n")
+       addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s+")\n")
+       addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n")
+       addDumpTest(nv2, "(*"+v2t+")(<nil>)\n")
+}
+
+func addArrayDumpTests() {
+       // Array containing standard ints.
+       v := [3]int{1, 2, 3}
+       vLen := fmt.Sprintf("%d", len(v))
+       vCap := fmt.Sprintf("%d", cap(v))
+       nv := (*[3]int)(nil)
+       pv := &v
+       vAddr := fmt.Sprintf("%p", pv)
+       pvAddr := fmt.Sprintf("%p", &pv)
+       vt := "int"
+       vs := "(len=" + vLen + " cap=" + vCap + ") {\n (" + vt + ") 1,\n (" +
+               vt + ") 2,\n (" + vt + ") 3\n}"
+       addDumpTest(v, "([3]"+vt+") "+vs+"\n")
+       addDumpTest(pv, "(*[3]"+vt+")("+vAddr+")("+vs+")\n")
+       addDumpTest(&pv, "(**[3]"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n")
+       addDumpTest(nv, "(*[3]"+vt+")(<nil>)\n")
+
+       // Array containing type with custom formatter on pointer receiver only.
+       v2i0 := pstringer("1")
+       v2i1 := pstringer("2")
+       v2i2 := pstringer("3")
+       v2 := [3]pstringer{v2i0, v2i1, v2i2}
+       v2i0Len := fmt.Sprintf("%d", len(v2i0))
+       v2i1Len := fmt.Sprintf("%d", len(v2i1))
+       v2i2Len := fmt.Sprintf("%d", len(v2i2))
+       v2Len := fmt.Sprintf("%d", len(v2))
+       v2Cap := fmt.Sprintf("%d", cap(v2))
+       nv2 := (*[3]pstringer)(nil)
+       pv2 := &v2
+       v2Addr := fmt.Sprintf("%p", pv2)
+       pv2Addr := fmt.Sprintf("%p", &pv2)
+       v2t := "spew_test.pstringer"
+       v2sp := "(len=" + v2Len + " cap=" + v2Cap + ") {\n (" + v2t +
+               ") (len=" + v2i0Len + ") stringer 1,\n (" + v2t +
+               ") (len=" + v2i1Len + ") stringer 2,\n (" + v2t +
+               ") (len=" + v2i2Len + ") " + "stringer 3\n}"
+       v2s := v2sp
+       if spew.UnsafeDisabled {
+               v2s = "(len=" + v2Len + " cap=" + v2Cap + ") {\n (" + v2t +
+                       ") (len=" + v2i0Len + ") \"1\",\n (" + v2t + ") (len=" +
+                       v2i1Len + ") \"2\",\n (" + v2t + ") (len=" + v2i2Len +
+                       ") " + "\"3\"\n}"
+       }
+       addDumpTest(v2, "([3]"+v2t+") "+v2s+"\n")
+       addDumpTest(pv2, "(*[3]"+v2t+")("+v2Addr+")("+v2sp+")\n")
+       addDumpTest(&pv2, "(**[3]"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2sp+")\n")
+       addDumpTest(nv2, "(*[3]"+v2t+")(<nil>)\n")
+
+       // Array containing interfaces.
+       v3i0 := "one"
+       v3 := [3]interface{}{v3i0, int(2), uint(3)}
+       v3i0Len := fmt.Sprintf("%d", len(v3i0))
+       v3Len := fmt.Sprintf("%d", len(v3))
+       v3Cap := fmt.Sprintf("%d", cap(v3))
+       nv3 := (*[3]interface{})(nil)
+       pv3 := &v3
+       v3Addr := fmt.Sprintf("%p", pv3)
+       pv3Addr := fmt.Sprintf("%p", &pv3)
+       v3t := "[3]interface {}"
+       v3t2 := "string"
+       v3t3 := "int"
+       v3t4 := "uint"
+       v3s := "(len=" + v3Len + " cap=" + v3Cap + ") {\n (" + v3t2 + ") " +
+               "(len=" + v3i0Len + ") \"one\",\n (" + v3t3 + ") 2,\n (" +
+               v3t4 + ") 3\n}"
+       addDumpTest(v3, "("+v3t+") "+v3s+"\n")
+       addDumpTest(pv3, "(*"+v3t+")("+v3Addr+")("+v3s+")\n")
+       addDumpTest(&pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")("+v3s+")\n")
+       addDumpTest(nv3, "(*"+v3t+")(<nil>)\n")
+
+       // Array containing bytes.
+       v4 := [34]byte{
+               0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
+               0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20,
+               0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
+               0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30,
+               0x31, 0x32,
+       }
+       v4Len := fmt.Sprintf("%d", len(v4))
+       v4Cap := fmt.Sprintf("%d", cap(v4))
+       nv4 := (*[34]byte)(nil)
+       pv4 := &v4
+       v4Addr := fmt.Sprintf("%p", pv4)
+       pv4Addr := fmt.Sprintf("%p", &pv4)
+       v4t := "[34]uint8"
+       v4s := "(len=" + v4Len + " cap=" + v4Cap + ") " +
+               "{\n 00000000  11 12 13 14 15 16 17 18  19 1a 1b 1c 1d 1e 1f 20" +
+               "  |............... |\n" +
+               " 00000010  21 22 23 24 25 26 27 28  29 2a 2b 2c 2d 2e 2f 30" +
+               "  |!\"#$%&'()*+,-./0|\n" +
+               " 00000020  31 32                                           " +
+               "  |12|\n}"
+       addDumpTest(v4, "("+v4t+") "+v4s+"\n")
+       addDumpTest(pv4, "(*"+v4t+")("+v4Addr+")("+v4s+")\n")
+       addDumpTest(&pv4, "(**"+v4t+")("+pv4Addr+"->"+v4Addr+")("+v4s+")\n")
+       addDumpTest(nv4, "(*"+v4t+")(<nil>)\n")
+}
+
+func addSliceDumpTests() {
+       // Slice containing standard float32 values.
+       v := []float32{3.14, 6.28, 12.56}
+       vLen := fmt.Sprintf("%d", len(v))
+       vCap := fmt.Sprintf("%d", cap(v))
+       nv := (*[]float32)(nil)
+       pv := &v
+       vAddr := fmt.Sprintf("%p", pv)
+       pvAddr := fmt.Sprintf("%p", &pv)
+       vt := "float32"
+       vs := "(len=" + vLen + " cap=" + vCap + ") {\n (" + vt + ") 3.14,\n (" +
+               vt + ") 6.28,\n (" + vt + ") 12.56\n}"
+       addDumpTest(v, "([]"+vt+") "+vs+"\n")
+       addDumpTest(pv, "(*[]"+vt+")("+vAddr+")("+vs+")\n")
+       addDumpTest(&pv, "(**[]"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n")
+       addDumpTest(nv, "(*[]"+vt+")(<nil>)\n")
+
+       // Slice containing type with custom formatter on pointer receiver only.
+       v2i0 := pstringer("1")
+       v2i1 := pstringer("2")
+       v2i2 := pstringer("3")
+       v2 := []pstringer{v2i0, v2i1, v2i2}
+       v2i0Len := fmt.Sprintf("%d", len(v2i0))
+       v2i1Len := fmt.Sprintf("%d", len(v2i1))
+       v2i2Len := fmt.Sprintf("%d", len(v2i2))
+       v2Len := fmt.Sprintf("%d", len(v2))
+       v2Cap := fmt.Sprintf("%d", cap(v2))
+       nv2 := (*[]pstringer)(nil)
+       pv2 := &v2
+       v2Addr := fmt.Sprintf("%p", pv2)
+       pv2Addr := fmt.Sprintf("%p", &pv2)
+       v2t := "spew_test.pstringer"
+       v2s := "(len=" + v2Len + " cap=" + v2Cap + ") {\n (" + v2t + ") (len=" +
+               v2i0Len + ") stringer 1,\n (" + v2t + ") (len=" + v2i1Len +
+               ") stringer 2,\n (" + v2t + ") (len=" + v2i2Len + ") " +
+               "stringer 3\n}"
+       addDumpTest(v2, "([]"+v2t+") "+v2s+"\n")
+       addDumpTest(pv2, "(*[]"+v2t+")("+v2Addr+")("+v2s+")\n")
+       addDumpTest(&pv2, "(**[]"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n")
+       addDumpTest(nv2, "(*[]"+v2t+")(<nil>)\n")
+
+       // Slice containing interfaces.
+       v3i0 := "one"
+       v3 := []interface{}{v3i0, int(2), uint(3), nil}
+       v3i0Len := fmt.Sprintf("%d", len(v3i0))
+       v3Len := fmt.Sprintf("%d", len(v3))
+       v3Cap := fmt.Sprintf("%d", cap(v3))
+       nv3 := (*[]interface{})(nil)
+       pv3 := &v3
+       v3Addr := fmt.Sprintf("%p", pv3)
+       pv3Addr := fmt.Sprintf("%p", &pv3)
+       v3t := "[]interface {}"
+       v3t2 := "string"
+       v3t3 := "int"
+       v3t4 := "uint"
+       v3t5 := "interface {}"
+       v3s := "(len=" + v3Len + " cap=" + v3Cap + ") {\n (" + v3t2 + ") " +
+               "(len=" + v3i0Len + ") \"one\",\n (" + v3t3 + ") 2,\n (" +
+               v3t4 + ") 3,\n (" + v3t5 + ") <nil>\n}"
+       addDumpTest(v3, "("+v3t+") "+v3s+"\n")
+       addDumpTest(pv3, "(*"+v3t+")("+v3Addr+")("+v3s+")\n")
+       addDumpTest(&pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")("+v3s+")\n")
+       addDumpTest(nv3, "(*"+v3t+")(<nil>)\n")
+
+       // Slice containing bytes.
+       v4 := []byte{
+               0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
+               0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20,
+               0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
+               0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30,
+               0x31, 0x32,
+       }
+       v4Len := fmt.Sprintf("%d", len(v4))
+       v4Cap := fmt.Sprintf("%d", cap(v4))
+       nv4 := (*[]byte)(nil)
+       pv4 := &v4
+       v4Addr := fmt.Sprintf("%p", pv4)
+       pv4Addr := fmt.Sprintf("%p", &pv4)
+       v4t := "[]uint8"
+       v4s := "(len=" + v4Len + " cap=" + v4Cap + ") " +
+               "{\n 00000000  11 12 13 14 15 16 17 18  19 1a 1b 1c 1d 1e 1f 20" +
+               "  |............... |\n" +
+               " 00000010  21 22 23 24 25 26 27 28  29 2a 2b 2c 2d 2e 2f 30" +
+               "  |!\"#$%&'()*+,-./0|\n" +
+               " 00000020  31 32                                           " +
+               "  |12|\n}"
+       addDumpTest(v4, "("+v4t+") "+v4s+"\n")
+       addDumpTest(pv4, "(*"+v4t+")("+v4Addr+")("+v4s+")\n")
+       addDumpTest(&pv4, "(**"+v4t+")("+pv4Addr+"->"+v4Addr+")("+v4s+")\n")
+       addDumpTest(nv4, "(*"+v4t+")(<nil>)\n")
+
+       // Nil slice.
+       v5 := []int(nil)
+       nv5 := (*[]int)(nil)
+       pv5 := &v5
+       v5Addr := fmt.Sprintf("%p", pv5)
+       pv5Addr := fmt.Sprintf("%p", &pv5)
+       v5t := "[]int"
+       v5s := "<nil>"
+       addDumpTest(v5, "("+v5t+") "+v5s+"\n")
+       addDumpTest(pv5, "(*"+v5t+")("+v5Addr+")("+v5s+")\n")
+       addDumpTest(&pv5, "(**"+v5t+")("+pv5Addr+"->"+v5Addr+")("+v5s+")\n")
+       addDumpTest(nv5, "(*"+v5t+")(<nil>)\n")
+}
+
+func addStringDumpTests() {
+       // Standard string.
+       v := "test"
+       vLen := fmt.Sprintf("%d", len(v))
+       nv := (*string)(nil)
+       pv := &v
+       vAddr := fmt.Sprintf("%p", pv)
+       pvAddr := fmt.Sprintf("%p", &pv)
+       vt := "string"
+       vs := "(len=" + vLen + ") \"test\""
+       addDumpTest(v, "("+vt+") "+vs+"\n")
+       addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n")
+       addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n")
+       addDumpTest(nv, "(*"+vt+")(<nil>)\n")
+}
+
+func addInterfaceDumpTests() {
+       // Nil interface.
+       var v interface{}
+       nv := (*interface{})(nil)
+       pv := &v
+       vAddr := fmt.Sprintf("%p", pv)
+       pvAddr := fmt.Sprintf("%p", &pv)
+       vt := "interface {}"
+       vs := "<nil>"
+       addDumpTest(v, "("+vt+") "+vs+"\n")
+       addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n")
+       addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n")
+       addDumpTest(nv, "(*"+vt+")(<nil>)\n")
+
+       // Sub-interface.
+       v2 := interface{}(uint16(65535))
+       pv2 := &v2
+       v2Addr := fmt.Sprintf("%p", pv2)
+       pv2Addr := fmt.Sprintf("%p", &pv2)
+       v2t := "uint16"
+       v2s := "65535"
+       addDumpTest(v2, "("+v2t+") "+v2s+"\n")
+       addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s+")\n")
+       addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n")
+}
+
+func addMapDumpTests() {
+       // Map with string keys and int vals.
+       k := "one"
+       kk := "two"
+       m := map[string]int{k: 1, kk: 2}
+       klen := fmt.Sprintf("%d", len(k)) // not kLen to shut golint up
+       kkLen := fmt.Sprintf("%d", len(kk))
+       mLen := fmt.Sprintf("%d", len(m))
+       nilMap := map[string]int(nil)
+       nm := (*map[string]int)(nil)
+       pm := &m
+       mAddr := fmt.Sprintf("%p", pm)
+       pmAddr := fmt.Sprintf("%p", &pm)
+       mt := "map[string]int"
+       mt1 := "string"
+       mt2 := "int"
+       ms := "(len=" + mLen + ") {\n (" + mt1 + ") (len=" + klen + ") " +
+               "\"one\": (" + mt2 + ") 1,\n (" + mt1 + ") (len=" + kkLen +
+               ") \"two\": (" + mt2 + ") 2\n}"
+       ms2 := "(len=" + mLen + ") {\n (" + mt1 + ") (len=" + kkLen + ") " +
+               "\"two\": (" + mt2 + ") 2,\n (" + mt1 + ") (len=" + klen +
+               ") \"one\": (" + mt2 + ") 1\n}"
+       addDumpTest(m, "("+mt+") "+ms+"\n", "("+mt+") "+ms2+"\n")
+       addDumpTest(pm, "(*"+mt+")("+mAddr+")("+ms+")\n",
+               "(*"+mt+")("+mAddr+")("+ms2+")\n")
+       addDumpTest(&pm, "(**"+mt+")("+pmAddr+"->"+mAddr+")("+ms+")\n",
+               "(**"+mt+")("+pmAddr+"->"+mAddr+")("+ms2+")\n")
+       addDumpTest(nm, "(*"+mt+")(<nil>)\n")
+       addDumpTest(nilMap, "("+mt+") <nil>\n")
+
+       // Map with custom formatter type on pointer receiver only keys and vals.
+       k2 := pstringer("one")
+       v2 := pstringer("1")
+       m2 := map[pstringer]pstringer{k2: v2}
+       k2Len := fmt.Sprintf("%d", len(k2))
+       v2Len := fmt.Sprintf("%d", len(v2))
+       m2Len := fmt.Sprintf("%d", len(m2))
+       nilMap2 := map[pstringer]pstringer(nil)
+       nm2 := (*map[pstringer]pstringer)(nil)
+       pm2 := &m2
+       m2Addr := fmt.Sprintf("%p", pm2)
+       pm2Addr := fmt.Sprintf("%p", &pm2)
+       m2t := "map[spew_test.pstringer]spew_test.pstringer"
+       m2t1 := "spew_test.pstringer"
+       m2t2 := "spew_test.pstringer"
+       m2s := "(len=" + m2Len + ") {\n (" + m2t1 + ") (len=" + k2Len + ") " +
+               "stringer one: (" + m2t2 + ") (len=" + v2Len + ") stringer 1\n}"
+       if spew.UnsafeDisabled {
+               m2s = "(len=" + m2Len + ") {\n (" + m2t1 + ") (len=" + k2Len +
+                       ") " + "\"one\": (" + m2t2 + ") (len=" + v2Len +
+                       ") \"1\"\n}"
+       }
+       addDumpTest(m2, "("+m2t+") "+m2s+"\n")
+       addDumpTest(pm2, "(*"+m2t+")("+m2Addr+")("+m2s+")\n")
+       addDumpTest(&pm2, "(**"+m2t+")("+pm2Addr+"->"+m2Addr+")("+m2s+")\n")
+       addDumpTest(nm2, "(*"+m2t+")(<nil>)\n")
+       addDumpTest(nilMap2, "("+m2t+") <nil>\n")
+
+       // Map with interface keys and values.
+       k3 := "one"
+       k3Len := fmt.Sprintf("%d", len(k3))
+       m3 := map[interface{}]interface{}{k3: 1}
+       m3Len := fmt.Sprintf("%d", len(m3))
+       nilMap3 := map[interface{}]interface{}(nil)
+       nm3 := (*map[interface{}]interface{})(nil)
+       pm3 := &m3
+       m3Addr := fmt.Sprintf("%p", pm3)
+       pm3Addr := fmt.Sprintf("%p", &pm3)
+       m3t := "map[interface {}]interface {}"
+       m3t1 := "string"
+       m3t2 := "int"
+       m3s := "(len=" + m3Len + ") {\n (" + m3t1 + ") (len=" + k3Len + ") " +
+               "\"one\": (" + m3t2 + ") 1\n}"
+       addDumpTest(m3, "("+m3t+") "+m3s+"\n")
+       addDumpTest(pm3, "(*"+m3t+")("+m3Addr+")("+m3s+")\n")
+       addDumpTest(&pm3, "(**"+m3t+")("+pm3Addr+"->"+m3Addr+")("+m3s+")\n")
+       addDumpTest(nm3, "(*"+m3t+")(<nil>)\n")
+       addDumpTest(nilMap3, "("+m3t+") <nil>\n")
+
+       // Map with nil interface value.
+       k4 := "nil"
+       k4Len := fmt.Sprintf("%d", len(k4))
+       m4 := map[string]interface{}{k4: nil}
+       m4Len := fmt.Sprintf("%d", len(m4))
+       nilMap4 := map[string]interface{}(nil)
+       nm4 := (*map[string]interface{})(nil)
+       pm4 := &m4
+       m4Addr := fmt.Sprintf("%p", pm4)
+       pm4Addr := fmt.Sprintf("%p", &pm4)
+       m4t := "map[string]interface {}"
+       m4t1 := "string"
+       m4t2 := "interface {}"
+       m4s := "(len=" + m4Len + ") {\n (" + m4t1 + ") (len=" + k4Len + ")" +
+               " \"nil\": (" + m4t2 + ") <nil>\n}"
+       addDumpTest(m4, "("+m4t+") "+m4s+"\n")
+       addDumpTest(pm4, "(*"+m4t+")("+m4Addr+")("+m4s+")\n")
+       addDumpTest(&pm4, "(**"+m4t+")("+pm4Addr+"->"+m4Addr+")("+m4s+")\n")
+       addDumpTest(nm4, "(*"+m4t+")(<nil>)\n")
+       addDumpTest(nilMap4, "("+m4t+") <nil>\n")
+}
+
+func addStructDumpTests() {
+       // Struct with primitives.
+       type s1 struct {
+               a int8
+               b uint8
+       }
+       v := s1{127, 255}
+       nv := (*s1)(nil)
+       pv := &v
+       vAddr := fmt.Sprintf("%p", pv)
+       pvAddr := fmt.Sprintf("%p", &pv)
+       vt := "spew_test.s1"
+       vt2 := "int8"
+       vt3 := "uint8"
+       vs := "{\n a: (" + vt2 + ") 127,\n b: (" + vt3 + ") 255\n}"
+       addDumpTest(v, "("+vt+") "+vs+"\n")
+       addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n")
+       addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n")
+       addDumpTest(nv, "(*"+vt+")(<nil>)\n")
+
+       // Struct that contains another struct.
+       type s2 struct {
+               s1 s1
+               b  bool
+       }
+       v2 := s2{s1{127, 255}, true}
+       nv2 := (*s2)(nil)
+       pv2 := &v2
+       v2Addr := fmt.Sprintf("%p", pv2)
+       pv2Addr := fmt.Sprintf("%p", &pv2)
+       v2t := "spew_test.s2"
+       v2t2 := "spew_test.s1"
+       v2t3 := "int8"
+       v2t4 := "uint8"
+       v2t5 := "bool"
+       v2s := "{\n s1: (" + v2t2 + ") {\n  a: (" + v2t3 + ") 127,\n  b: (" +
+               v2t4 + ") 255\n },\n b: (" + v2t5 + ") true\n}"
+       addDumpTest(v2, "("+v2t+") "+v2s+"\n")
+       addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s+")\n")
+       addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n")
+       addDumpTest(nv2, "(*"+v2t+")(<nil>)\n")
+
+       // Struct that contains custom type with Stringer pointer interface via both
+       // exported and unexported fields.
+       type s3 struct {
+               s pstringer
+               S pstringer
+       }
+       v3 := s3{"test", "test2"}
+       nv3 := (*s3)(nil)
+       pv3 := &v3
+       v3Addr := fmt.Sprintf("%p", pv3)
+       pv3Addr := fmt.Sprintf("%p", &pv3)
+       v3t := "spew_test.s3"
+       v3t2 := "spew_test.pstringer"
+       v3s := "{\n s: (" + v3t2 + ") (len=4) stringer test,\n S: (" + v3t2 +
+               ") (len=5) stringer test2\n}"
+       v3sp := v3s
+       if spew.UnsafeDisabled {
+               v3s = "{\n s: (" + v3t2 + ") (len=4) \"test\",\n S: (" +
+                       v3t2 + ") (len=5) \"test2\"\n}"
+               v3sp = "{\n s: (" + v3t2 + ") (len=4) \"test\",\n S: (" +
+                       v3t2 + ") (len=5) stringer test2\n}"
+       }
+       addDumpTest(v3, "("+v3t+") "+v3s+"\n")
+       addDumpTest(pv3, "(*"+v3t+")("+v3Addr+")("+v3sp+")\n")
+       addDumpTest(&pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")("+v3sp+")\n")
+       addDumpTest(nv3, "(*"+v3t+")(<nil>)\n")
+
+       // Struct that contains embedded struct and field to same struct.
+       e := embed{"embedstr"}
+       eLen := fmt.Sprintf("%d", len("embedstr"))
+       v4 := embedwrap{embed: &e, e: &e}
+       nv4 := (*embedwrap)(nil)
+       pv4 := &v4
+       eAddr := fmt.Sprintf("%p", &e)
+       v4Addr := fmt.Sprintf("%p", pv4)
+       pv4Addr := fmt.Sprintf("%p", &pv4)
+       v4t := "spew_test.embedwrap"
+       v4t2 := "spew_test.embed"
+       v4t3 := "string"
+       v4s := "{\n embed: (*" + v4t2 + ")(" + eAddr + ")({\n  a: (" + v4t3 +
+               ") (len=" + eLen + ") \"embedstr\"\n }),\n e: (*" + v4t2 +
+               ")(" + eAddr + ")({\n  a: (" + v4t3 + ") (len=" + eLen + ")" +
+               " \"embedstr\"\n })\n}"
+       addDumpTest(v4, "("+v4t+") "+v4s+"\n")
+       addDumpTest(pv4, "(*"+v4t+")("+v4Addr+")("+v4s+")\n")
+       addDumpTest(&pv4, "(**"+v4t+")("+pv4Addr+"->"+v4Addr+")("+v4s+")\n")
+       addDumpTest(nv4, "(*"+v4t+")(<nil>)\n")
+}
+
+func addUintptrDumpTests() {
+       // Null pointer.
+       v := uintptr(0)
+       pv := &v
+       vAddr := fmt.Sprintf("%p", pv)
+       pvAddr := fmt.Sprintf("%p", &pv)
+       vt := "uintptr"
+       vs := "<nil>"
+       addDumpTest(v, "("+vt+") "+vs+"\n")
+       addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n")
+       addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n")
+
+       // Address of real variable.
+       i := 1
+       v2 := uintptr(unsafe.Pointer(&i))
+       nv2 := (*uintptr)(nil)
+       pv2 := &v2
+       v2Addr := fmt.Sprintf("%p", pv2)
+       pv2Addr := fmt.Sprintf("%p", &pv2)
+       v2t := "uintptr"
+       v2s := fmt.Sprintf("%p", &i)
+       addDumpTest(v2, "("+v2t+") "+v2s+"\n")
+       addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s+")\n")
+       addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n")
+       addDumpTest(nv2, "(*"+v2t+")(<nil>)\n")
+}
+
+func addUnsafePointerDumpTests() {
+       // Null pointer.
+       v := unsafe.Pointer(uintptr(0))
+       nv := (*unsafe.Pointer)(nil)
+       pv := &v
+       vAddr := fmt.Sprintf("%p", pv)
+       pvAddr := fmt.Sprintf("%p", &pv)
+       vt := "unsafe.Pointer"
+       vs := "<nil>"
+       addDumpTest(v, "("+vt+") "+vs+"\n")
+       addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n")
+       addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n")
+       addDumpTest(nv, "(*"+vt+")(<nil>)\n")
+
+       // Address of real variable.
+       i := 1
+       v2 := unsafe.Pointer(&i)
+       pv2 := &v2
+       v2Addr := fmt.Sprintf("%p", pv2)
+       pv2Addr := fmt.Sprintf("%p", &pv2)
+       v2t := "unsafe.Pointer"
+       v2s := fmt.Sprintf("%p", &i)
+       addDumpTest(v2, "("+v2t+") "+v2s+"\n")
+       addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s+")\n")
+       addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n")
+       addDumpTest(nv, "(*"+vt+")(<nil>)\n")
+}
+
+func addChanDumpTests() {
+       // Nil channel.
+       var v chan int
+       pv := &v
+       nv := (*chan int)(nil)
+       vAddr := fmt.Sprintf("%p", pv)
+       pvAddr := fmt.Sprintf("%p", &pv)
+       vt := "chan int"
+       vs := "<nil>"
+       addDumpTest(v, "("+vt+") "+vs+"\n")
+       addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n")
+       addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n")
+       addDumpTest(nv, "(*"+vt+")(<nil>)\n")
+
+       // Real channel.
+       v2 := make(chan int)
+       pv2 := &v2
+       v2Addr := fmt.Sprintf("%p", pv2)
+       pv2Addr := fmt.Sprintf("%p", &pv2)
+       v2t := "chan int"
+       v2s := fmt.Sprintf("%p", v2)
+       addDumpTest(v2, "("+v2t+") "+v2s+"\n")
+       addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s+")\n")
+       addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n")
+}
+
+func addFuncDumpTests() {
+       // Function with no params and no returns.
+       v := addIntDumpTests
+       nv := (*func())(nil)
+       pv := &v
+       vAddr := fmt.Sprintf("%p", pv)
+       pvAddr := fmt.Sprintf("%p", &pv)
+       vt := "func()"
+       vs := fmt.Sprintf("%p", v)
+       addDumpTest(v, "("+vt+") "+vs+"\n")
+       addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n")
+       addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n")
+       addDumpTest(nv, "(*"+vt+")(<nil>)\n")
+
+       // Function with param and no returns.
+       v2 := TestDump
+       nv2 := (*func(*testing.T))(nil)
+       pv2 := &v2
+       v2Addr := fmt.Sprintf("%p", pv2)
+       pv2Addr := fmt.Sprintf("%p", &pv2)
+       v2t := "func(*testing.T)"
+       v2s := fmt.Sprintf("%p", v2)
+       addDumpTest(v2, "("+v2t+") "+v2s+"\n")
+       addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s+")\n")
+       addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n")
+       addDumpTest(nv2, "(*"+v2t+")(<nil>)\n")
+
+       // Function with multiple params and multiple returns.
+       var v3 = func(i int, s string) (b bool, err error) {
+               return true, nil
+       }
+       nv3 := (*func(int, string) (bool, error))(nil)
+       pv3 := &v3
+       v3Addr := fmt.Sprintf("%p", pv3)
+       pv3Addr := fmt.Sprintf("%p", &pv3)
+       v3t := "func(int, string) (bool, error)"
+       v3s := fmt.Sprintf("%p", v3)
+       addDumpTest(v3, "("+v3t+") "+v3s+"\n")
+       addDumpTest(pv3, "(*"+v3t+")("+v3Addr+")("+v3s+")\n")
+       addDumpTest(&pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")("+v3s+")\n")
+       addDumpTest(nv3, "(*"+v3t+")(<nil>)\n")
+}
+
+func addCircularDumpTests() {
+       // Struct that is circular through self referencing.
+       type circular struct {
+               c *circular
+       }
+       v := circular{nil}
+       v.c = &v
+       pv := &v
+       vAddr := fmt.Sprintf("%p", pv)
+       pvAddr := fmt.Sprintf("%p", &pv)
+       vt := "spew_test.circular"
+       vs := "{\n c: (*" + vt + ")(" + vAddr + ")({\n  c: (*" + vt + ")(" +
+               vAddr + ")(<already shown>)\n })\n}"
+       vs2 := "{\n c: (*" + vt + ")(" + vAddr + ")(<already shown>)\n}"
+       addDumpTest(v, "("+vt+") "+vs+"\n")
+       addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs2+")\n")
+       addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs2+")\n")
+
+       // Structs that are circular through cross referencing.
+       v2 := xref1{nil}
+       ts2 := xref2{&v2}
+       v2.ps2 = &ts2
+       pv2 := &v2
+       ts2Addr := fmt.Sprintf("%p", &ts2)
+       v2Addr := fmt.Sprintf("%p", pv2)
+       pv2Addr := fmt.Sprintf("%p", &pv2)
+       v2t := "spew_test.xref1"
+       v2t2 := "spew_test.xref2"
+       v2s := "{\n ps2: (*" + v2t2 + ")(" + ts2Addr + ")({\n  ps1: (*" + v2t +
+               ")(" + v2Addr + ")({\n   ps2: (*" + v2t2 + ")(" + ts2Addr +
+               ")(<already shown>)\n  })\n })\n}"
+       v2s2 := "{\n ps2: (*" + v2t2 + ")(" + ts2Addr + ")({\n  ps1: (*" + v2t +
+               ")(" + v2Addr + ")(<already shown>)\n })\n}"
+       addDumpTest(v2, "("+v2t+") "+v2s+"\n")
+       addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s2+")\n")
+       addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s2+")\n")
+
+       // Structs that are indirectly circular.
+       v3 := indirCir1{nil}
+       tic2 := indirCir2{nil}
+       tic3 := indirCir3{&v3}
+       tic2.ps3 = &tic3
+       v3.ps2 = &tic2
+       pv3 := &v3
+       tic2Addr := fmt.Sprintf("%p", &tic2)
+       tic3Addr := fmt.Sprintf("%p", &tic3)
+       v3Addr := fmt.Sprintf("%p", pv3)
+       pv3Addr := fmt.Sprintf("%p", &pv3)
+       v3t := "spew_test.indirCir1"
+       v3t2 := "spew_test.indirCir2"
+       v3t3 := "spew_test.indirCir3"
+       v3s := "{\n ps2: (*" + v3t2 + ")(" + tic2Addr + ")({\n  ps3: (*" + v3t3 +
+               ")(" + tic3Addr + ")({\n   ps1: (*" + v3t + ")(" + v3Addr +
+               ")({\n    ps2: (*" + v3t2 + ")(" + tic2Addr +
+               ")(<already shown>)\n   })\n  })\n })\n}"
+       v3s2 := "{\n ps2: (*" + v3t2 + ")(" + tic2Addr + ")({\n  ps3: (*" + v3t3 +
+               ")(" + tic3Addr + ")({\n   ps1: (*" + v3t + ")(" + v3Addr +
+               ")(<already shown>)\n  })\n })\n}"
+       addDumpTest(v3, "("+v3t+") "+v3s+"\n")
+       addDumpTest(pv3, "(*"+v3t+")("+v3Addr+")("+v3s2+")\n")
+       addDumpTest(&pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")("+v3s2+")\n")
+}
+
+func addPanicDumpTests() {
+       // Type that panics in its Stringer interface.
+       v := panicer(127)
+       nv := (*panicer)(nil)
+       pv := &v
+       vAddr := fmt.Sprintf("%p", pv)
+       pvAddr := fmt.Sprintf("%p", &pv)
+       vt := "spew_test.panicer"
+       vs := "(PANIC=test panic)127"
+       addDumpTest(v, "("+vt+") "+vs+"\n")
+       addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n")
+       addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n")
+       addDumpTest(nv, "(*"+vt+")(<nil>)\n")
+}
+
+func addErrorDumpTests() {
+       // Type that has a custom Error interface.
+       v := customError(127)
+       nv := (*customError)(nil)
+       pv := &v
+       vAddr := fmt.Sprintf("%p", pv)
+       pvAddr := fmt.Sprintf("%p", &pv)
+       vt := "spew_test.customError"
+       vs := "error: 127"
+       addDumpTest(v, "("+vt+") "+vs+"\n")
+       addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n")
+       addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n")
+       addDumpTest(nv, "(*"+vt+")(<nil>)\n")
+}
+
+// TestDump executes all of the tests described by dumpTests.
+func TestDump(t *testing.T) {
+       // Setup tests.
+       addIntDumpTests()
+       addUintDumpTests()
+       addBoolDumpTests()
+       addFloatDumpTests()
+       addComplexDumpTests()
+       addArrayDumpTests()
+       addSliceDumpTests()
+       addStringDumpTests()
+       addInterfaceDumpTests()
+       addMapDumpTests()
+       addStructDumpTests()
+       addUintptrDumpTests()
+       addUnsafePointerDumpTests()
+       addChanDumpTests()
+       addFuncDumpTests()
+       addCircularDumpTests()
+       addPanicDumpTests()
+       addErrorDumpTests()
+       addCgoDumpTests()
+
+       t.Logf("Running %d tests", len(dumpTests))
+       for i, test := range dumpTests {
+               buf := new(bytes.Buffer)
+               spew.Fdump(buf, test.in)
+               s := buf.String()
+               if testFailed(s, test.wants) {
+                       t.Errorf("Dump #%d\n got: %s %s", i, s, stringizeWants(test.wants))
+                       continue
+               }
+       }
+}
+
+func TestDumpSortedKeys(t *testing.T) {
+       cfg := spew.ConfigState{SortKeys: true}
+       s := cfg.Sdump(map[int]string{1: "1", 3: "3", 2: "2"})
+       expected := "(map[int]string) (len=3) {\n(int) 1: (string) (len=1) " +
+               "\"1\",\n(int) 2: (string) (len=1) \"2\",\n(int) 3: (string) " +
+               "(len=1) \"3\"\n" +
+               "}\n"
+       if s != expected {
+               t.Errorf("Sorted keys mismatch:\n  %v %v", s, expected)
+       }
+
+       s = cfg.Sdump(map[stringer]int{"1": 1, "3": 3, "2": 2})
+       expected = "(map[spew_test.stringer]int) (len=3) {\n" +
+               "(spew_test.stringer) (len=1) stringer 1: (int) 1,\n" +
+               "(spew_test.stringer) (len=1) stringer 2: (int) 2,\n" +
+               "(spew_test.stringer) (len=1) stringer 3: (int) 3\n" +
+               "}\n"
+       if s != expected {
+               t.Errorf("Sorted keys mismatch:\n  %v %v", s, expected)
+       }
+
+       s = cfg.Sdump(map[pstringer]int{pstringer("1"): 1, pstringer("3"): 3, pstringer("2"): 2})
+       expected = "(map[spew_test.pstringer]int) (len=3) {\n" +
+               "(spew_test.pstringer) (len=1) stringer 1: (int) 1,\n" +
+               "(spew_test.pstringer) (len=1) stringer 2: (int) 2,\n" +
+               "(spew_test.pstringer) (len=1) stringer 3: (int) 3\n" +
+               "}\n"
+       if spew.UnsafeDisabled {
+               expected = "(map[spew_test.pstringer]int) (len=3) {\n" +
+                       "(spew_test.pstringer) (len=1) \"1\": (int) 1,\n" +
+                       "(spew_test.pstringer) (len=1) \"2\": (int) 2,\n" +
+                       "(spew_test.pstringer) (len=1) \"3\": (int) 3\n" +
+                       "}\n"
+       }
+       if s != expected {
+               t.Errorf("Sorted keys mismatch:\n  %v %v", s, expected)
+       }
+
+       s = cfg.Sdump(map[customError]int{customError(1): 1, customError(3): 3, customError(2): 2})
+       expected = "(map[spew_test.customError]int) (len=3) {\n" +
+               "(spew_test.customError) error: 1: (int) 1,\n" +
+               "(spew_test.customError) error: 2: (int) 2,\n" +
+               "(spew_test.customError) error: 3: (int) 3\n" +
+               "}\n"
+       if s != expected {
+               t.Errorf("Sorted keys mismatch:\n  %v %v", s, expected)
+       }
+
+}
diff --git a/vendor/github.com/git-lfs/gitobj/vendor/github.com/davecgh/go-spew/spew/dumpcgo_test.go b/vendor/github.com/git-lfs/gitobj/vendor/github.com/davecgh/go-spew/spew/dumpcgo_test.go
new file mode 100644 (file)
index 0000000..18a3835
--- /dev/null
@@ -0,0 +1,98 @@
+// Copyright (c) 2013 Dave Collins <dave@davec.name>
+//
+// Permission to use, copy, modify, and distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+// NOTE: Due to the following build constraints, this file will only be compiled
+// when both cgo is supported and "-tags testcgo" is added to the go test
+// command line.  This means the cgo tests are only added (and hence run) when
+// specifially requested.  This configuration is used because spew itself
+// does not require cgo to run even though it does handle certain cgo types
+// specially.  Rather than forcing all clients to require cgo and an external
+// C compiler just to run the tests, this scheme makes them optional.
+// +build cgo,testcgo
+
+package spew_test
+
+import (
+       "fmt"
+
+       "github.com/davecgh/go-spew/spew/testdata"
+)
+
+func addCgoDumpTests() {
+       // C char pointer.
+       v := testdata.GetCgoCharPointer()
+       nv := testdata.GetCgoNullCharPointer()
+       pv := &v
+       vcAddr := fmt.Sprintf("%p", v)
+       vAddr := fmt.Sprintf("%p", pv)
+       pvAddr := fmt.Sprintf("%p", &pv)
+       vt := "*testdata._Ctype_char"
+       vs := "116"
+       addDumpTest(v, "("+vt+")("+vcAddr+")("+vs+")\n")
+       addDumpTest(pv, "(*"+vt+")("+vAddr+"->"+vcAddr+")("+vs+")\n")
+       addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+"->"+vcAddr+")("+vs+")\n")
+       addDumpTest(nv, "("+vt+")(<nil>)\n")
+
+       // C char array.
+       v2, v2l, v2c := testdata.GetCgoCharArray()
+       v2Len := fmt.Sprintf("%d", v2l)
+       v2Cap := fmt.Sprintf("%d", v2c)
+       v2t := "[6]testdata._Ctype_char"
+       v2s := "(len=" + v2Len + " cap=" + v2Cap + ") " +
+               "{\n 00000000  74 65 73 74 32 00                               " +
+               "  |test2.|\n}"
+       addDumpTest(v2, "("+v2t+") "+v2s+"\n")
+
+       // C unsigned char array.
+       v3, v3l, v3c := testdata.GetCgoUnsignedCharArray()
+       v3Len := fmt.Sprintf("%d", v3l)
+       v3Cap := fmt.Sprintf("%d", v3c)
+       v3t := "[6]testdata._Ctype_unsignedchar"
+       v3s := "(len=" + v3Len + " cap=" + v3Cap + ") " +
+               "{\n 00000000  74 65 73 74 33 00                               " +
+               "  |test3.|\n}"
+       addDumpTest(v3, "("+v3t+") "+v3s+"\n")
+
+       // C signed char array.
+       v4, v4l, v4c := testdata.GetCgoSignedCharArray()
+       v4Len := fmt.Sprintf("%d", v4l)
+       v4Cap := fmt.Sprintf("%d", v4c)
+       v4t := "[6]testdata._Ctype_schar"
+       v4t2 := "testdata._Ctype_schar"
+       v4s := "(len=" + v4Len + " cap=" + v4Cap + ") " +
+               "{\n (" + v4t2 + ") 116,\n (" + v4t2 + ") 101,\n (" + v4t2 +
+               ") 115,\n (" + v4t2 + ") 116,\n (" + v4t2 + ") 52,\n (" + v4t2 +
+               ") 0\n}"
+       addDumpTest(v4, "("+v4t+") "+v4s+"\n")
+
+       // C uint8_t array.
+       v5, v5l, v5c := testdata.GetCgoUint8tArray()
+       v5Len := fmt.Sprintf("%d", v5l)
+       v5Cap := fmt.Sprintf("%d", v5c)
+       v5t := "[6]testdata._Ctype_uint8_t"
+       v5s := "(len=" + v5Len + " cap=" + v5Cap + ") " +
+               "{\n 00000000  74 65 73 74 35 00                               " +
+               "  |test5.|\n}"
+       addDumpTest(v5, "("+v5t+") "+v5s+"\n")
+
+       // C typedefed unsigned char array.
+       v6, v6l, v6c := testdata.GetCgoTypdefedUnsignedCharArray()
+       v6Len := fmt.Sprintf("%d", v6l)
+       v6Cap := fmt.Sprintf("%d", v6c)
+       v6t := "[6]testdata._Ctype_custom_uchar_t"
+       v6s := "(len=" + v6Len + " cap=" + v6Cap + ") " +
+               "{\n 00000000  74 65 73 74 36 00                               " +
+               "  |test6.|\n}"
+       addDumpTest(v6, "("+v6t+") "+v6s+"\n")
+}
diff --git a/vendor/github.com/git-lfs/gitobj/vendor/github.com/davecgh/go-spew/spew/dumpnocgo_test.go b/vendor/github.com/git-lfs/gitobj/vendor/github.com/davecgh/go-spew/spew/dumpnocgo_test.go
new file mode 100644 (file)
index 0000000..52a0971
--- /dev/null
@@ -0,0 +1,26 @@
+// Copyright (c) 2013 Dave Collins <dave@davec.name>
+//
+// Permission to use, copy, modify, and distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+// NOTE: Due to the following build constraints, this file will only be compiled
+// when either cgo is not supported or "-tags testcgo" is not added to the go
+// test command line.  This file intentionally does not setup any cgo tests in
+// this scenario.
+// +build !cgo !testcgo
+
+package spew_test
+
+func addCgoDumpTests() {
+       // Don't add any tests for cgo since this file is only compiled when
+       // there should not be any cgo tests.
+}
diff --git a/vendor/github.com/git-lfs/gitobj/vendor/github.com/davecgh/go-spew/spew/example_test.go b/vendor/github.com/git-lfs/gitobj/vendor/github.com/davecgh/go-spew/spew/example_test.go
new file mode 100644 (file)
index 0000000..de6c4e3
--- /dev/null
@@ -0,0 +1,226 @@
+/*
+ * Copyright (c) 2013 Dave Collins <dave@davec.name>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+package spew_test
+
+import (
+       "fmt"
+
+       "github.com/davecgh/go-spew/spew"
+)
+
+type Flag int
+
+const (
+       flagOne Flag = iota
+       flagTwo
+)
+
+var flagStrings = map[Flag]string{
+       flagOne: "flagOne",
+       flagTwo: "flagTwo",
+}
+
+func (f Flag) String() string {
+       if s, ok := flagStrings[f]; ok {
+               return s
+       }
+       return fmt.Sprintf("Unknown flag (%d)", int(f))
+}
+
+type Bar struct {
+       data uintptr
+}
+
+type Foo struct {
+       unexportedField Bar
+       ExportedField   map[interface{}]interface{}
+}
+
+// This example demonstrates how to use Dump to dump variables to stdout.
+func ExampleDump() {
+       // The following package level declarations are assumed for this example:
+       /*
+               type Flag int
+
+               const (
+                       flagOne Flag = iota
+                       flagTwo
+               )
+
+               var flagStrings = map[Flag]string{
+                       flagOne: "flagOne",
+                       flagTwo: "flagTwo",
+               }
+
+               func (f Flag) String() string {
+                       if s, ok := flagStrings[f]; ok {
+                               return s
+                       }
+                       return fmt.Sprintf("Unknown flag (%d)", int(f))
+               }
+
+               type Bar struct {
+                       data uintptr
+               }
+
+               type Foo struct {
+                       unexportedField Bar
+                       ExportedField   map[interface{}]interface{}
+               }
+       */
+
+       // Setup some sample data structures for the example.
+       bar := Bar{uintptr(0)}
+       s1 := Foo{bar, map[interface{}]interface{}{"one": true}}
+       f := Flag(5)
+       b := []byte{
+               0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
+               0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20,
+               0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
+               0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30,
+               0x31, 0x32,
+       }
+
+       // Dump!
+       spew.Dump(s1, f, b)
+
+       // Output:
+       // (spew_test.Foo) {
+       //  unexportedField: (spew_test.Bar) {
+       //   data: (uintptr) <nil>
+       //  },
+       //  ExportedField: (map[interface {}]interface {}) (len=1) {
+       //   (string) (len=3) "one": (bool) true
+       //  }
+       // }
+       // (spew_test.Flag) Unknown flag (5)
+       // ([]uint8) (len=34 cap=34) {
+       //  00000000  11 12 13 14 15 16 17 18  19 1a 1b 1c 1d 1e 1f 20  |............... |
+       //  00000010  21 22 23 24 25 26 27 28  29 2a 2b 2c 2d 2e 2f 30  |!"#$%&'()*+,-./0|
+       //  00000020  31 32                                             |12|
+       // }
+       //
+}
+
+// This example demonstrates how to use Printf to display a variable with a
+// format string and inline formatting.
+func ExamplePrintf() {
+       // Create a double pointer to a uint 8.
+       ui8 := uint8(5)
+       pui8 := &ui8
+       ppui8 := &pui8
+
+       // Create a circular data type.
+       type circular struct {
+               ui8 uint8
+               c   *circular
+       }
+       c := circular{ui8: 1}
+       c.c = &c
+
+       // Print!
+       spew.Printf("ppui8: %v\n", ppui8)
+       spew.Printf("circular: %v\n", c)
+
+       // Output:
+       // ppui8: <**>5
+       // circular: {1 <*>{1 <*><shown>}}
+}
+
+// This example demonstrates how to use a ConfigState.
+func ExampleConfigState() {
+       // Modify the indent level of the ConfigState only.  The global
+       // configuration is not modified.
+       scs := spew.ConfigState{Indent: "\t"}
+
+       // Output using the ConfigState instance.
+       v := map[string]int{"one": 1}
+       scs.Printf("v: %v\n", v)
+       scs.Dump(v)
+
+       // Output:
+       // v: map[one:1]
+       // (map[string]int) (len=1) {
+       //      (string) (len=3) "one": (int) 1
+       // }
+}
+
+// This example demonstrates how to use ConfigState.Dump to dump variables to
+// stdout
+func ExampleConfigState_Dump() {
+       // See the top-level Dump example for details on the types used in this
+       // example.
+
+       // Create two ConfigState instances with different indentation.
+       scs := spew.ConfigState{Indent: "\t"}
+       scs2 := spew.ConfigState{Indent: " "}
+
+       // Setup some sample data structures for the example.
+       bar := Bar{uintptr(0)}
+       s1 := Foo{bar, map[interface{}]interface{}{"one": true}}
+
+       // Dump using the ConfigState instances.
+       scs.Dump(s1)
+       scs2.Dump(s1)
+
+       // Output:
+       // (spew_test.Foo) {
+       //      unexportedField: (spew_test.Bar) {
+       //              data: (uintptr) <nil>
+       //      },
+       //      ExportedField: (map[interface {}]interface {}) (len=1) {
+       //              (string) (len=3) "one": (bool) true
+       //      }
+       // }
+       // (spew_test.Foo) {
+       //  unexportedField: (spew_test.Bar) {
+       //   data: (uintptr) <nil>
+       //  },
+       //  ExportedField: (map[interface {}]interface {}) (len=1) {
+       //   (string) (len=3) "one": (bool) true
+       //  }
+       // }
+       //
+}
+
+// This example demonstrates how to use ConfigState.Printf to display a variable
+// with a format string and inline formatting.
+func ExampleConfigState_Printf() {
+       // See the top-level Dump example for details on the types used in this
+       // example.
+
+       // Create two ConfigState instances and modify the method handling of the
+       // first ConfigState only.
+       scs := spew.NewDefaultConfig()
+       scs2 := spew.NewDefaultConfig()
+       scs.DisableMethods = true
+
+       // Alternatively
+       // scs := spew.ConfigState{Indent: " ", DisableMethods: true}
+       // scs2 := spew.ConfigState{Indent: " "}
+
+       // This is of type Flag which implements a Stringer and has raw value 1.
+       f := flagTwo
+
+       // Dump using the ConfigState instances.
+       scs.Printf("f: %v\n", f)
+       scs2.Printf("f: %v\n", f)
+
+       // Output:
+       // f: 1
+       // f: flagTwo
+}
diff --git a/vendor/github.com/git-lfs/gitobj/vendor/github.com/davecgh/go-spew/spew/format.go b/vendor/github.com/git-lfs/gitobj/vendor/github.com/davecgh/go-spew/spew/format.go
new file mode 100644 (file)
index 0000000..ecf3b80
--- /dev/null
@@ -0,0 +1,419 @@
+/*
+ * Copyright (c) 2013 Dave Collins <dave@davec.name>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+package spew
+
+import (
+       "bytes"
+       "fmt"
+       "reflect"
+       "strconv"
+       "strings"
+)
+
+// supportedFlags is a list of all the character flags supported by fmt package.
+const supportedFlags = "0-+# "
+
+// formatState implements the fmt.Formatter interface and contains information
+// about the state of a formatting operation.  The NewFormatter function can
+// be used to get a new Formatter which can be used directly as arguments
+// in standard fmt package printing calls.
+type formatState struct {
+       value          interface{}
+       fs             fmt.State
+       depth          int
+       pointers       map[uintptr]int
+       ignoreNextType bool
+       cs             *ConfigState
+}
+
+// buildDefaultFormat recreates the original format string without precision
+// and width information to pass in to fmt.Sprintf in the case of an
+// unrecognized type.  Unless new types are added to the language, this
+// function won't ever be called.
+func (f *formatState) buildDefaultFormat() (format string) {
+       buf := bytes.NewBuffer(percentBytes)
+
+       for _, flag := range supportedFlags {
+               if f.fs.Flag(int(flag)) {
+                       buf.WriteRune(flag)
+               }
+       }
+
+       buf.WriteRune('v')
+
+       format = buf.String()
+       return format
+}
+
+// constructOrigFormat recreates the original format string including precision
+// and width information to pass along to the standard fmt package.  This allows
+// automatic deferral of all format strings this package doesn't support.
+func (f *formatState) constructOrigFormat(verb rune) (format string) {
+       buf := bytes.NewBuffer(percentBytes)
+
+       for _, flag := range supportedFlags {
+               if f.fs.Flag(int(flag)) {
+                       buf.WriteRune(flag)
+               }
+       }
+
+       if width, ok := f.fs.Width(); ok {
+               buf.WriteString(strconv.Itoa(width))
+       }
+
+       if precision, ok := f.fs.Precision(); ok {
+               buf.Write(precisionBytes)
+               buf.WriteString(strconv.Itoa(precision))
+       }
+
+       buf.WriteRune(verb)
+
+       format = buf.String()
+       return format
+}
+
+// unpackValue returns values inside of non-nil interfaces when possible and
+// ensures that types for values which have been unpacked from an interface
+// are displayed when the show types flag is also set.
+// This is useful for data types like structs, arrays, slices, and maps which
+// can contain varying types packed inside an interface.
+func (f *formatState) unpackValue(v reflect.Value) reflect.Value {
+       if v.Kind() == reflect.Interface {
+               f.ignoreNextType = false
+               if !v.IsNil() {
+                       v = v.Elem()
+               }
+       }
+       return v
+}
+
+// formatPtr handles formatting of pointers by indirecting them as necessary.
+func (f *formatState) formatPtr(v reflect.Value) {
+       // Display nil if top level pointer is nil.
+       showTypes := f.fs.Flag('#')
+       if v.IsNil() && (!showTypes || f.ignoreNextType) {
+               f.fs.Write(nilAngleBytes)
+               return
+       }
+
+       // Remove pointers at or below the current depth from map used to detect
+       // circular refs.
+       for k, depth := range f.pointers {
+               if depth >= f.depth {
+                       delete(f.pointers, k)
+               }
+       }
+
+       // Keep list of all dereferenced pointers to possibly show later.
+       pointerChain := make([]uintptr, 0)
+
+       // Figure out how many levels of indirection there are by derferencing
+       // pointers and unpacking interfaces down the chain while detecting circular
+       // references.
+       nilFound := false
+       cycleFound := false
+       indirects := 0
+       ve := v
+       for ve.Kind() == reflect.Ptr {
+               if ve.IsNil() {
+                       nilFound = true
+                       break
+               }
+               indirects++
+               addr := ve.Pointer()
+               pointerChain = append(pointerChain, addr)
+               if pd, ok := f.pointers[addr]; ok && pd < f.depth {
+                       cycleFound = true
+                       indirects--
+                       break
+               }
+               f.pointers[addr] = f.depth
+
+               ve = ve.Elem()
+               if ve.Kind() == reflect.Interface {
+                       if ve.IsNil() {
+                               nilFound = true
+                               break
+                       }
+                       ve = ve.Elem()
+               }
+       }
+
+       // Display type or indirection level depending on flags.
+       if showTypes && !f.ignoreNextType {
+               f.fs.Write(openParenBytes)
+               f.fs.Write(bytes.Repeat(asteriskBytes, indirects))
+               f.fs.Write([]byte(ve.Type().String()))
+               f.fs.Write(closeParenBytes)
+       } else {
+               if nilFound || cycleFound {
+                       indirects += strings.Count(ve.Type().String(), "*")
+               }
+               f.fs.Write(openAngleBytes)
+               f.fs.Write([]byte(strings.Repeat("*", indirects)))
+               f.fs.Write(closeAngleBytes)
+       }
+
+       // Display pointer information depending on flags.
+       if f.fs.Flag('+') && (len(pointerChain) > 0) {
+               f.fs.Write(openParenBytes)
+               for i, addr := range pointerChain {
+                       if i > 0 {
+                               f.fs.Write(pointerChainBytes)
+                       }
+                       printHexPtr(f.fs, addr)
+               }
+               f.fs.Write(closeParenBytes)
+       }
+
+       // Display dereferenced value.
+       switch {
+       case nilFound == true:
+               f.fs.Write(nilAngleBytes)
+
+       case cycleFound == true:
+               f.fs.Write(circularShortBytes)
+
+       default:
+               f.ignoreNextType = true
+               f.format(ve)
+       }
+}
+
+// format is the main workhorse for providing the Formatter interface.  It
+// uses the passed reflect value to figure out what kind of object we are
+// dealing with and formats it appropriately.  It is a recursive function,
+// however circular data structures are detected and handled properly.
+func (f *formatState) format(v reflect.Value) {
+       // Handle invalid reflect values immediately.
+       kind := v.Kind()
+       if kind == reflect.Invalid {
+               f.fs.Write(invalidAngleBytes)
+               return
+       }
+
+       // Handle pointers specially.
+       if kind == reflect.Ptr {
+               f.formatPtr(v)
+               return
+       }
+
+       // Print type information unless already handled elsewhere.
+       if !f.ignoreNextType && f.fs.Flag('#') {
+               f.fs.Write(openParenBytes)
+               f.fs.Write([]byte(v.Type().String()))
+               f.fs.Write(closeParenBytes)
+       }
+       f.ignoreNextType = false
+
+       // Call Stringer/error interfaces if they exist and the handle methods
+       // flag is enabled.
+       if !f.cs.DisableMethods {
+               if (kind != reflect.Invalid) && (kind != reflect.Interface) {
+                       if handled := handleMethods(f.cs, f.fs, v); handled {
+                               return
+                       }
+               }
+       }
+
+       switch kind {
+       case reflect.Invalid:
+               // Do nothing.  We should never get here since invalid has already
+               // been handled above.
+
+       case reflect.Bool:
+               printBool(f.fs, v.Bool())
+
+       case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int:
+               printInt(f.fs, v.Int(), 10)
+
+       case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint:
+               printUint(f.fs, v.Uint(), 10)
+
+       case reflect.Float32:
+               printFloat(f.fs, v.Float(), 32)
+
+       case reflect.Float64:
+               printFloat(f.fs, v.Float(), 64)
+
+       case reflect.Complex64:
+               printComplex(f.fs, v.Complex(), 32)
+
+       case reflect.Complex128:
+               printComplex(f.fs, v.Complex(), 64)
+
+       case reflect.Slice:
+               if v.IsNil() {
+                       f.fs.Write(nilAngleBytes)
+                       break
+               }
+               fallthrough
+
+       case reflect.Array:
+               f.fs.Write(openBracketBytes)
+               f.depth++
+               if (f.cs.MaxDepth != 0) && (f.depth > f.cs.MaxDepth) {
+                       f.fs.Write(maxShortBytes)
+               } else {
+                       numEntries := v.Len()
+                       for i := 0; i < numEntries; i++ {
+                               if i > 0 {
+                                       f.fs.Write(spaceBytes)
+                               }
+                               f.ignoreNextType = true
+                               f.format(f.unpackValue(v.Index(i)))
+                       }
+               }
+               f.depth--
+               f.fs.Write(closeBracketBytes)
+
+       case reflect.String:
+               f.fs.Write([]byte(v.String()))
+
+       case reflect.Interface:
+               // The only time we should get here is for nil interfaces due to
+               // unpackValue calls.
+               if v.IsNil() {
+                       f.fs.Write(nilAngleBytes)
+               }
+
+       case reflect.Ptr:
+               // Do nothing.  We should never get here since pointers have already
+               // been handled above.
+
+       case reflect.Map:
+               // nil maps should be indicated as different than empty maps
+               if v.IsNil() {
+                       f.fs.Write(nilAngleBytes)
+                       break
+               }
+
+               f.fs.Write(openMapBytes)
+               f.depth++
+               if (f.cs.MaxDepth != 0) && (f.depth > f.cs.MaxDepth) {
+                       f.fs.Write(maxShortBytes)
+               } else {
+                       keys := v.MapKeys()
+                       if f.cs.SortKeys {
+                               sortValues(keys, f.cs)
+                       }
+                       for i, key := range keys {
+                               if i > 0 {
+                                       f.fs.Write(spaceBytes)
+                               }
+                               f.ignoreNextType = true
+                               f.format(f.unpackValue(key))
+                               f.fs.Write(colonBytes)
+                               f.ignoreNextType = true
+                               f.format(f.unpackValue(v.MapIndex(key)))
+                       }
+               }
+               f.depth--
+               f.fs.Write(closeMapBytes)
+
+       case reflect.Struct:
+               numFields := v.NumField()
+               f.fs.Write(openBraceBytes)
+               f.depth++
+               if (f.cs.MaxDepth != 0) && (f.depth > f.cs.MaxDepth) {
+                       f.fs.Write(maxShortBytes)
+               } else {
+                       vt := v.Type()
+                       for i := 0; i < numFields; i++ {
+                               if i > 0 {
+                                       f.fs.Write(spaceBytes)
+                               }
+                               vtf := vt.Field(i)
+                               if f.fs.Flag('+') || f.fs.Flag('#') {
+                                       f.fs.Write([]byte(vtf.Name))
+                                       f.fs.Write(colonBytes)
+                               }
+                               f.format(f.unpackValue(v.Field(i)))
+                       }
+               }
+               f.depth--
+               f.fs.Write(closeBraceBytes)
+
+       case reflect.Uintptr:
+               printHexPtr(f.fs, uintptr(v.Uint()))
+
+       case reflect.UnsafePointer, reflect.Chan, reflect.Func:
+               printHexPtr(f.fs, v.Pointer())
+
+       // There were not any other types at the time this code was written, but
+       // fall back to letting the default fmt package handle it if any get added.
+       default:
+               format := f.buildDefaultFormat()
+               if v.CanInterface() {
+                       fmt.Fprintf(f.fs, format, v.Interface())
+               } else {
+                       fmt.Fprintf(f.fs, format, v.String())
+               }
+       }
+}
+
+// Format satisfies the fmt.Formatter interface. See NewFormatter for usage
+// details.
+func (f *formatState) Format(fs fmt.State, verb rune) {
+       f.fs = fs
+
+       // Use standard formatting for verbs that are not v.
+       if verb != 'v' {
+               format := f.constructOrigFormat(verb)
+               fmt.Fprintf(fs, format, f.value)
+               return
+       }
+
+       if f.value == nil {
+               if fs.Flag('#') {
+                       fs.Write(interfaceBytes)
+               }
+               fs.Write(nilAngleBytes)
+               return
+       }
+
+       f.format(reflect.ValueOf(f.value))
+}
+
+// newFormatter is a helper function to consolidate the logic from the various
+// public methods which take varying config states.
+func newFormatter(cs *ConfigState, v interface{}) fmt.Formatter {
+       fs := &formatState{value: v, cs: cs}
+       fs.pointers = make(map[uintptr]int)
+       return fs
+}
+
+/*
+NewFormatter returns a custom formatter that satisfies the fmt.Formatter
+interface.  As a result, it integrates cleanly with standard fmt package
+printing functions.  The formatter is useful for inline printing of smaller data
+types similar to the standard %v format specifier.
+
+The custom formatter only responds to the %v (most compact), %+v (adds pointer
+addresses), %#v (adds types), or %#+v (adds types and pointer addresses) verb
+combinations.  Any other verbs such as %x and %q will be sent to the the
+standard fmt package for formatting.  In addition, the custom formatter ignores
+the width and precision arguments (however they will still work on the format
+specifiers not handled by the custom formatter).
+
+Typically this function shouldn't be called directly.  It is much easier to make
+use of the custom formatter by calling one of the convenience functions such as
+Printf, Println, or Fprintf.
+*/
+func NewFormatter(v interface{}) fmt.Formatter {
+       return newFormatter(&Config, v)
+}
diff --git a/vendor/github.com/git-lfs/gitobj/vendor/github.com/davecgh/go-spew/spew/format_test.go b/vendor/github.com/git-lfs/gitobj/vendor/github.com/davecgh/go-spew/spew/format_test.go
new file mode 100644 (file)
index 0000000..b664b3f
--- /dev/null
@@ -0,0 +1,1558 @@
+/*
+ * Copyright (c) 2013 Dave Collins <dave@davec.name>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+Test Summary:
+NOTE: For each test, a nil pointer, a single pointer and double pointer to the
+base test element are also tested to ensure proper indirection across all types.
+
+- Max int8, int16, int32, int64, int
+- Max uint8, uint16, uint32, uint64, uint
+- Boolean true and false
+- Standard complex64 and complex128
+- Array containing standard ints
+- Array containing type with custom formatter on pointer receiver only
+- Array containing interfaces
+- Slice containing standard float32 values
+- Slice containing type with custom formatter on pointer receiver only
+- Slice containing interfaces
+- Nil slice
+- Standard string
+- Nil interface
+- Sub-interface
+- Map with string keys and int vals
+- Map with custom formatter type on pointer receiver only keys and vals
+- Map with interface keys and values
+- Map with nil interface value
+- Struct with primitives
+- Struct that contains another struct
+- Struct that contains custom type with Stringer pointer interface via both
+  exported and unexported fields
+- Struct that contains embedded struct and field to same struct
+- Uintptr to 0 (null pointer)
+- Uintptr address of real variable
+- Unsafe.Pointer to 0 (null pointer)
+- Unsafe.Pointer to address of real variable
+- Nil channel
+- Standard int channel
+- Function with no params and no returns
+- Function with param and no returns
+- Function with multiple params and multiple returns
+- Struct that is circular through self referencing
+- Structs that are circular through cross referencing
+- Structs that are indirectly circular
+- Type that panics in its Stringer interface
+- Type that has a custom Error interface
+- %x passthrough with uint
+- %#x passthrough with uint
+- %f passthrough with precision
+- %f passthrough with width and precision
+- %d passthrough with width
+- %q passthrough with string
+*/
+
+package spew_test
+
+import (
+       "bytes"
+       "fmt"
+       "testing"
+       "unsafe"
+
+       "github.com/davecgh/go-spew/spew"
+)
+
+// formatterTest is used to describe a test to be perfomed against NewFormatter.
+type formatterTest struct {
+       format string
+       in     interface{}
+       wants  []string
+}
+
+// formatterTests houses all of the tests to be performed against NewFormatter.
+var formatterTests = make([]formatterTest, 0)
+
+// addFormatterTest is a helper method to append the passed input and desired
+// result to formatterTests.
+func addFormatterTest(format string, in interface{}, wants ...string) {
+       test := formatterTest{format, in, wants}
+       formatterTests = append(formatterTests, test)
+}
+
+func addIntFormatterTests() {
+       // Max int8.
+       v := int8(127)
+       nv := (*int8)(nil)
+       pv := &v
+       vAddr := fmt.Sprintf("%p", pv)
+       pvAddr := fmt.Sprintf("%p", &pv)
+       vt := "int8"
+       vs := "127"
+       addFormatterTest("%v", v, vs)
+       addFormatterTest("%v", pv, "<*>"+vs)
+       addFormatterTest("%v", &pv, "<**>"+vs)
+       addFormatterTest("%v", nv, "<nil>")
+       addFormatterTest("%+v", v, vs)
+       addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs)
+       addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs)
+       addFormatterTest("%+v", nv, "<nil>")
+       addFormatterTest("%#v", v, "("+vt+")"+vs)
+       addFormatterTest("%#v", pv, "(*"+vt+")"+vs)
+       addFormatterTest("%#v", &pv, "(**"+vt+")"+vs)
+       addFormatterTest("%#v", nv, "(*"+vt+")"+"<nil>")
+       addFormatterTest("%#+v", v, "("+vt+")"+vs)
+       addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs)
+       addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs)
+       addFormatterTest("%#+v", nv, "(*"+vt+")"+"<nil>")
+
+       // Max int16.
+       v2 := int16(32767)
+       nv2 := (*int16)(nil)
+       pv2 := &v2
+       v2Addr := fmt.Sprintf("%p", pv2)
+       pv2Addr := fmt.Sprintf("%p", &pv2)
+       v2t := "int16"
+       v2s := "32767"
+       addFormatterTest("%v", v2, v2s)
+       addFormatterTest("%v", pv2, "<*>"+v2s)
+       addFormatterTest("%v", &pv2, "<**>"+v2s)
+       addFormatterTest("%v", nv2, "<nil>")
+       addFormatterTest("%+v", v2, v2s)
+       addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s)
+       addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s)
+       addFormatterTest("%+v", nv2, "<nil>")
+       addFormatterTest("%#v", v2, "("+v2t+")"+v2s)
+       addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s)
+       addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s)
+       addFormatterTest("%#v", nv2, "(*"+v2t+")"+"<nil>")
+       addFormatterTest("%#+v", v2, "("+v2t+")"+v2s)
+       addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s)
+       addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s)
+       addFormatterTest("%#+v", nv2, "(*"+v2t+")"+"<nil>")
+
+       // Max int32.
+       v3 := int32(2147483647)
+       nv3 := (*int32)(nil)
+       pv3 := &v3
+       v3Addr := fmt.Sprintf("%p", pv3)
+       pv3Addr := fmt.Sprintf("%p", &pv3)
+       v3t := "int32"
+       v3s := "2147483647"
+       addFormatterTest("%v", v3, v3s)
+       addFormatterTest("%v", pv3, "<*>"+v3s)
+       addFormatterTest("%v", &pv3, "<**>"+v3s)
+       addFormatterTest("%v", nv3, "<nil>")
+       addFormatterTest("%+v", v3, v3s)
+       addFormatterTest("%+v", pv3, "<*>("+v3Addr+")"+v3s)
+       addFormatterTest("%+v", &pv3, "<**>("+pv3Addr+"->"+v3Addr+")"+v3s)
+       addFormatterTest("%+v", nv3, "<nil>")
+       addFormatterTest("%#v", v3, "("+v3t+")"+v3s)
+       addFormatterTest("%#v", pv3, "(*"+v3t+")"+v3s)
+       addFormatterTest("%#v", &pv3, "(**"+v3t+")"+v3s)
+       addFormatterTest("%#v", nv3, "(*"+v3t+")"+"<nil>")
+       addFormatterTest("%#+v", v3, "("+v3t+")"+v3s)
+       addFormatterTest("%#+v", pv3, "(*"+v3t+")("+v3Addr+")"+v3s)
+       addFormatterTest("%#+v", &pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")"+v3s)
+       addFormatterTest("%#v", nv3, "(*"+v3t+")"+"<nil>")
+
+       // Max int64.
+       v4 := int64(9223372036854775807)
+       nv4 := (*int64)(nil)
+       pv4 := &v4
+       v4Addr := fmt.Sprintf("%p", pv4)
+       pv4Addr := fmt.Sprintf("%p", &pv4)
+       v4t := "int64"
+       v4s := "9223372036854775807"
+       addFormatterTest("%v", v4, v4s)
+       addFormatterTest("%v", pv4, "<*>"+v4s)
+       addFormatterTest("%v", &pv4, "<**>"+v4s)
+       addFormatterTest("%v", nv4, "<nil>")
+       addFormatterTest("%+v", v4, v4s)
+       addFormatterTest("%+v", pv4, "<*>("+v4Addr+")"+v4s)
+       addFormatterTest("%+v", &pv4, "<**>("+pv4Addr+"->"+v4Addr+")"+v4s)
+       addFormatterTest("%+v", nv4, "<nil>")
+       addFormatterTest("%#v", v4, "("+v4t+")"+v4s)
+       addFormatterTest("%#v", pv4, "(*"+v4t+")"+v4s)
+       addFormatterTest("%#v", &pv4, "(**"+v4t+")"+v4s)
+       addFormatterTest("%#v", nv4, "(*"+v4t+")"+"<nil>")
+       addFormatterTest("%#+v", v4, "("+v4t+")"+v4s)
+       addFormatterTest("%#+v", pv4, "(*"+v4t+")("+v4Addr+")"+v4s)
+       addFormatterTest("%#+v", &pv4, "(**"+v4t+")("+pv4Addr+"->"+v4Addr+")"+v4s)
+       addFormatterTest("%#+v", nv4, "(*"+v4t+")"+"<nil>")
+
+       // Max int.
+       v5 := int(2147483647)
+       nv5 := (*int)(nil)
+       pv5 := &v5
+       v5Addr := fmt.Sprintf("%p", pv5)
+       pv5Addr := fmt.Sprintf("%p", &pv5)
+       v5t := "int"
+       v5s := "2147483647"
+       addFormatterTest("%v", v5, v5s)
+       addFormatterTest("%v", pv5, "<*>"+v5s)
+       addFormatterTest("%v", &pv5, "<**>"+v5s)
+       addFormatterTest("%v", nv5, "<nil>")
+       addFormatterTest("%+v", v5, v5s)
+       addFormatterTest("%+v", pv5, "<*>("+v5Addr+")"+v5s)
+       addFormatterTest("%+v", &pv5, "<**>("+pv5Addr+"->"+v5Addr+")"+v5s)
+       addFormatterTest("%+v", nv5, "<nil>")
+       addFormatterTest("%#v", v5, "("+v5t+")"+v5s)
+       addFormatterTest("%#v", pv5, "(*"+v5t+")"+v5s)
+       addFormatterTest("%#v", &pv5, "(**"+v5t+")"+v5s)
+       addFormatterTest("%#v", nv5, "(*"+v5t+")"+"<nil>")
+       addFormatterTest("%#+v", v5, "("+v5t+")"+v5s)
+       addFormatterTest("%#+v", pv5, "(*"+v5t+")("+v5Addr+")"+v5s)
+       addFormatterTest("%#+v", &pv5, "(**"+v5t+")("+pv5Addr+"->"+v5Addr+")"+v5s)
+       addFormatterTest("%#+v", nv5, "(*"+v5t+")"+"<nil>")
+}
+
+func addUintFormatterTests() {
+       // Max uint8.
+       v := uint8(255)
+       nv := (*uint8)(nil)
+       pv := &v
+       vAddr := fmt.Sprintf("%p", pv)
+       pvAddr := fmt.Sprintf("%p", &pv)
+       vt := "uint8"
+       vs := "255"
+       addFormatterTest("%v", v, vs)
+       addFormatterTest("%v", pv, "<*>"+vs)
+       addFormatterTest("%v", &pv, "<**>"+vs)
+       addFormatterTest("%v", nv, "<nil>")
+       addFormatterTest("%+v", v, vs)
+       addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs)
+       addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs)
+       addFormatterTest("%+v", nv, "<nil>")
+       addFormatterTest("%#v", v, "("+vt+")"+vs)
+       addFormatterTest("%#v", pv, "(*"+vt+")"+vs)
+       addFormatterTest("%#v", &pv, "(**"+vt+")"+vs)
+       addFormatterTest("%#v", nv, "(*"+vt+")"+"<nil>")
+       addFormatterTest("%#+v", v, "("+vt+")"+vs)
+       addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs)
+       addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs)
+       addFormatterTest("%#+v", nv, "(*"+vt+")"+"<nil>")
+
+       // Max uint16.
+       v2 := uint16(65535)
+       nv2 := (*uint16)(nil)
+       pv2 := &v2
+       v2Addr := fmt.Sprintf("%p", pv2)
+       pv2Addr := fmt.Sprintf("%p", &pv2)
+       v2t := "uint16"
+       v2s := "65535"
+       addFormatterTest("%v", v2, v2s)
+       addFormatterTest("%v", pv2, "<*>"+v2s)
+       addFormatterTest("%v", &pv2, "<**>"+v2s)
+       addFormatterTest("%v", nv2, "<nil>")
+       addFormatterTest("%+v", v2, v2s)
+       addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s)
+       addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s)
+       addFormatterTest("%+v", nv2, "<nil>")
+       addFormatterTest("%#v", v2, "("+v2t+")"+v2s)
+       addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s)
+       addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s)
+       addFormatterTest("%#v", nv2, "(*"+v2t+")"+"<nil>")
+       addFormatterTest("%#+v", v2, "("+v2t+")"+v2s)
+       addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s)
+       addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s)
+       addFormatterTest("%#+v", nv2, "(*"+v2t+")"+"<nil>")
+
+       // Max uint32.
+       v3 := uint32(4294967295)
+       nv3 := (*uint32)(nil)
+       pv3 := &v3
+       v3Addr := fmt.Sprintf("%p", pv3)
+       pv3Addr := fmt.Sprintf("%p", &pv3)
+       v3t := "uint32"
+       v3s := "4294967295"
+       addFormatterTest("%v", v3, v3s)
+       addFormatterTest("%v", pv3, "<*>"+v3s)
+       addFormatterTest("%v", &pv3, "<**>"+v3s)
+       addFormatterTest("%v", nv3, "<nil>")
+       addFormatterTest("%+v", v3, v3s)
+       addFormatterTest("%+v", pv3, "<*>("+v3Addr+")"+v3s)
+       addFormatterTest("%+v", &pv3, "<**>("+pv3Addr+"->"+v3Addr+")"+v3s)
+       addFormatterTest("%+v", nv3, "<nil>")
+       addFormatterTest("%#v", v3, "("+v3t+")"+v3s)
+       addFormatterTest("%#v", pv3, "(*"+v3t+")"+v3s)
+       addFormatterTest("%#v", &pv3, "(**"+v3t+")"+v3s)
+       addFormatterTest("%#v", nv3, "(*"+v3t+")"+"<nil>")
+       addFormatterTest("%#+v", v3, "("+v3t+")"+v3s)
+       addFormatterTest("%#+v", pv3, "(*"+v3t+")("+v3Addr+")"+v3s)
+       addFormatterTest("%#+v", &pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")"+v3s)
+       addFormatterTest("%#v", nv3, "(*"+v3t+")"+"<nil>")
+
+       // Max uint64.
+       v4 := uint64(18446744073709551615)
+       nv4 := (*uint64)(nil)
+       pv4 := &v4
+       v4Addr := fmt.Sprintf("%p", pv4)
+       pv4Addr := fmt.Sprintf("%p", &pv4)
+       v4t := "uint64"
+       v4s := "18446744073709551615"
+       addFormatterTest("%v", v4, v4s)
+       addFormatterTest("%v", pv4, "<*>"+v4s)
+       addFormatterTest("%v", &pv4, "<**>"+v4s)
+       addFormatterTest("%v", nv4, "<nil>")
+       addFormatterTest("%+v", v4, v4s)
+       addFormatterTest("%+v", pv4, "<*>("+v4Addr+")"+v4s)
+       addFormatterTest("%+v", &pv4, "<**>("+pv4Addr+"->"+v4Addr+")"+v4s)
+       addFormatterTest("%+v", nv4, "<nil>")
+       addFormatterTest("%#v", v4, "("+v4t+")"+v4s)
+       addFormatterTest("%#v", pv4, "(*"+v4t+")"+v4s)
+       addFormatterTest("%#v", &pv4, "(**"+v4t+")"+v4s)
+       addFormatterTest("%#v", nv4, "(*"+v4t+")"+"<nil>")
+       addFormatterTest("%#+v", v4, "("+v4t+")"+v4s)
+       addFormatterTest("%#+v", pv4, "(*"+v4t+")("+v4Addr+")"+v4s)
+       addFormatterTest("%#+v", &pv4, "(**"+v4t+")("+pv4Addr+"->"+v4Addr+")"+v4s)
+       addFormatterTest("%#+v", nv4, "(*"+v4t+")"+"<nil>")
+
+       // Max uint.
+       v5 := uint(4294967295)
+       nv5 := (*uint)(nil)
+       pv5 := &v5
+       v5Addr := fmt.Sprintf("%p", pv5)
+       pv5Addr := fmt.Sprintf("%p", &pv5)
+       v5t := "uint"
+       v5s := "4294967295"
+       addFormatterTest("%v", v5, v5s)
+       addFormatterTest("%v", pv5, "<*>"+v5s)
+       addFormatterTest("%v", &pv5, "<**>"+v5s)
+       addFormatterTest("%v", nv5, "<nil>")
+       addFormatterTest("%+v", v5, v5s)
+       addFormatterTest("%+v", pv5, "<*>("+v5Addr+")"+v5s)
+       addFormatterTest("%+v", &pv5, "<**>("+pv5Addr+"->"+v5Addr+")"+v5s)
+       addFormatterTest("%+v", nv5, "<nil>")
+       addFormatterTest("%#v", v5, "("+v5t+")"+v5s)
+       addFormatterTest("%#v", pv5, "(*"+v5t+")"+v5s)
+       addFormatterTest("%#v", &pv5, "(**"+v5t+")"+v5s)
+       addFormatterTest("%#v", nv5, "(*"+v5t+")"+"<nil>")
+       addFormatterTest("%#+v", v5, "("+v5t+")"+v5s)
+       addFormatterTest("%#+v", pv5, "(*"+v5t+")("+v5Addr+")"+v5s)
+       addFormatterTest("%#+v", &pv5, "(**"+v5t+")("+pv5Addr+"->"+v5Addr+")"+v5s)
+       addFormatterTest("%#v", nv5, "(*"+v5t+")"+"<nil>")
+}
+
+func addBoolFormatterTests() {
+       // Boolean true.
+       v := bool(true)
+       nv := (*bool)(nil)
+       pv := &v
+       vAddr := fmt.Sprintf("%p", pv)
+       pvAddr := fmt.Sprintf("%p", &pv)
+       vt := "bool"
+       vs := "true"
+       addFormatterTest("%v", v, vs)
+       addFormatterTest("%v", pv, "<*>"+vs)
+       addFormatterTest("%v", &pv, "<**>"+vs)
+       addFormatterTest("%v", nv, "<nil>")
+       addFormatterTest("%+v", v, vs)
+       addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs)
+       addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs)
+       addFormatterTest("%+v", nv, "<nil>")
+       addFormatterTest("%#v", v, "("+vt+")"+vs)
+       addFormatterTest("%#v", pv, "(*"+vt+")"+vs)
+       addFormatterTest("%#v", &pv, "(**"+vt+")"+vs)
+       addFormatterTest("%#v", nv, "(*"+vt+")"+"<nil>")
+       addFormatterTest("%#+v", v, "("+vt+")"+vs)
+       addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs)
+       addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs)
+       addFormatterTest("%#+v", nv, "(*"+vt+")"+"<nil>")
+
+       // Boolean false.
+       v2 := bool(false)
+       pv2 := &v2
+       v2Addr := fmt.Sprintf("%p", pv2)
+       pv2Addr := fmt.Sprintf("%p", &pv2)
+       v2t := "bool"
+       v2s := "false"
+       addFormatterTest("%v", v2, v2s)
+       addFormatterTest("%v", pv2, "<*>"+v2s)
+       addFormatterTest("%v", &pv2, "<**>"+v2s)
+       addFormatterTest("%+v", v2, v2s)
+       addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s)
+       addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s)
+       addFormatterTest("%#v", v2, "("+v2t+")"+v2s)
+       addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s)
+       addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s)
+       addFormatterTest("%#+v", v2, "("+v2t+")"+v2s)
+       addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s)
+       addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s)
+}
+
+func addFloatFormatterTests() {
+       // Standard float32.
+       v := float32(3.1415)
+       nv := (*float32)(nil)
+       pv := &v
+       vAddr := fmt.Sprintf("%p", pv)
+       pvAddr := fmt.Sprintf("%p", &pv)
+       vt := "float32"
+       vs := "3.1415"
+       addFormatterTest("%v", v, vs)
+       addFormatterTest("%v", pv, "<*>"+vs)
+       addFormatterTest("%v", &pv, "<**>"+vs)
+       addFormatterTest("%v", nv, "<nil>")
+       addFormatterTest("%+v", v, vs)
+       addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs)
+       addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs)
+       addFormatterTest("%+v", nv, "<nil>")
+       addFormatterTest("%#v", v, "("+vt+")"+vs)
+       addFormatterTest("%#v", pv, "(*"+vt+")"+vs)
+       addFormatterTest("%#v", &pv, "(**"+vt+")"+vs)
+       addFormatterTest("%#v", nv, "(*"+vt+")"+"<nil>")
+       addFormatterTest("%#+v", v, "("+vt+")"+vs)
+       addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs)
+       addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs)
+       addFormatterTest("%#+v", nv, "(*"+vt+")"+"<nil>")
+
+       // Standard float64.
+       v2 := float64(3.1415926)
+       nv2 := (*float64)(nil)
+       pv2 := &v2
+       v2Addr := fmt.Sprintf("%p", pv2)
+       pv2Addr := fmt.Sprintf("%p", &pv2)
+       v2t := "float64"
+       v2s := "3.1415926"
+       addFormatterTest("%v", v2, v2s)
+       addFormatterTest("%v", pv2, "<*>"+v2s)
+       addFormatterTest("%v", &pv2, "<**>"+v2s)
+       addFormatterTest("%+v", nv2, "<nil>")
+       addFormatterTest("%+v", v2, v2s)
+       addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s)
+       addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s)
+       addFormatterTest("%+v", nv2, "<nil>")
+       addFormatterTest("%#v", v2, "("+v2t+")"+v2s)
+       addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s)
+       addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s)
+       addFormatterTest("%#v", nv2, "(*"+v2t+")"+"<nil>")
+       addFormatterTest("%#+v", v2, "("+v2t+")"+v2s)
+       addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s)
+       addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s)
+       addFormatterTest("%#+v", nv2, "(*"+v2t+")"+"<nil>")
+}
+
+func addComplexFormatterTests() {
+       // Standard complex64.
+       v := complex(float32(6), -2)
+       nv := (*complex64)(nil)
+       pv := &v
+       vAddr := fmt.Sprintf("%p", pv)
+       pvAddr := fmt.Sprintf("%p", &pv)
+       vt := "complex64"
+       vs := "(6-2i)"
+       addFormatterTest("%v", v, vs)
+       addFormatterTest("%v", pv, "<*>"+vs)
+       addFormatterTest("%v", &pv, "<**>"+vs)
+       addFormatterTest("%+v", nv, "<nil>")
+       addFormatterTest("%+v", v, vs)
+       addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs)
+       addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs)
+       addFormatterTest("%+v", nv, "<nil>")
+       addFormatterTest("%#v", v, "("+vt+")"+vs)
+       addFormatterTest("%#v", pv, "(*"+vt+")"+vs)
+       addFormatterTest("%#v", &pv, "(**"+vt+")"+vs)
+       addFormatterTest("%#v", nv, "(*"+vt+")"+"<nil>")
+       addFormatterTest("%#+v", v, "("+vt+")"+vs)
+       addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs)
+       addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs)
+       addFormatterTest("%#+v", nv, "(*"+vt+")"+"<nil>")
+
+       // Standard complex128.
+       v2 := complex(float64(-6), 2)
+       nv2 := (*complex128)(nil)
+       pv2 := &v2
+       v2Addr := fmt.Sprintf("%p", pv2)
+       pv2Addr := fmt.Sprintf("%p", &pv2)
+       v2t := "complex128"
+       v2s := "(-6+2i)"
+       addFormatterTest("%v", v2, v2s)
+       addFormatterTest("%v", pv2, "<*>"+v2s)
+       addFormatterTest("%v", &pv2, "<**>"+v2s)
+       addFormatterTest("%+v", nv2, "<nil>")
+       addFormatterTest("%+v", v2, v2s)
+       addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s)
+       addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s)
+       addFormatterTest("%+v", nv2, "<nil>")
+       addFormatterTest("%#v", v2, "("+v2t+")"+v2s)
+       addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s)
+       addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s)
+       addFormatterTest("%#v", nv2, "(*"+v2t+")"+"<nil>")
+       addFormatterTest("%#+v", v2, "("+v2t+")"+v2s)
+       addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s)
+       addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s)
+       addFormatterTest("%#+v", nv2, "(*"+v2t+")"+"<nil>")
+}
+
+func addArrayFormatterTests() {
+       // Array containing standard ints.
+       v := [3]int{1, 2, 3}
+       nv := (*[3]int)(nil)
+       pv := &v
+       vAddr := fmt.Sprintf("%p", pv)
+       pvAddr := fmt.Sprintf("%p", &pv)
+       vt := "[3]int"
+       vs := "[1 2 3]"
+       addFormatterTest("%v", v, vs)
+       addFormatterTest("%v", pv, "<*>"+vs)
+       addFormatterTest("%v", &pv, "<**>"+vs)
+       addFormatterTest("%+v", nv, "<nil>")
+       addFormatterTest("%+v", v, vs)
+       addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs)
+       addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs)
+       addFormatterTest("%+v", nv, "<nil>")
+       addFormatterTest("%#v", v, "("+vt+")"+vs)
+       addFormatterTest("%#v", pv, "(*"+vt+")"+vs)
+       addFormatterTest("%#v", &pv, "(**"+vt+")"+vs)
+       addFormatterTest("%#v", nv, "(*"+vt+")"+"<nil>")
+       addFormatterTest("%#+v", v, "("+vt+")"+vs)
+       addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs)
+       addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs)
+       addFormatterTest("%#+v", nv, "(*"+vt+")"+"<nil>")
+
+       // Array containing type with custom formatter on pointer receiver only.
+       v2 := [3]pstringer{"1", "2", "3"}
+       nv2 := (*[3]pstringer)(nil)
+       pv2 := &v2
+       v2Addr := fmt.Sprintf("%p", pv2)
+       pv2Addr := fmt.Sprintf("%p", &pv2)
+       v2t := "[3]spew_test.pstringer"
+       v2sp := "[stringer 1 stringer 2 stringer 3]"
+       v2s := v2sp
+       if spew.UnsafeDisabled {
+               v2s = "[1 2 3]"
+       }
+       addFormatterTest("%v", v2, v2s)
+       addFormatterTest("%v", pv2, "<*>"+v2sp)
+       addFormatterTest("%v", &pv2, "<**>"+v2sp)
+       addFormatterTest("%+v", nv2, "<nil>")
+       addFormatterTest("%+v", v2, v2s)
+       addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2sp)
+       addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2sp)
+       addFormatterTest("%+v", nv2, "<nil>")
+       addFormatterTest("%#v", v2, "("+v2t+")"+v2s)
+       addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2sp)
+       addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2sp)
+       addFormatterTest("%#v", nv2, "(*"+v2t+")"+"<nil>")
+       addFormatterTest("%#+v", v2, "("+v2t+")"+v2s)
+       addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2sp)
+       addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2sp)
+       addFormatterTest("%#+v", nv2, "(*"+v2t+")"+"<nil>")
+
+       // Array containing interfaces.
+       v3 := [3]interface{}{"one", int(2), uint(3)}
+       nv3 := (*[3]interface{})(nil)
+       pv3 := &v3
+       v3Addr := fmt.Sprintf("%p", pv3)
+       pv3Addr := fmt.Sprintf("%p", &pv3)
+       v3t := "[3]interface {}"
+       v3t2 := "string"
+       v3t3 := "int"
+       v3t4 := "uint"
+       v3s := "[one 2 3]"
+       v3s2 := "[(" + v3t2 + ")one (" + v3t3 + ")2 (" + v3t4 + ")3]"
+       addFormatterTest("%v", v3, v3s)
+       addFormatterTest("%v", pv3, "<*>"+v3s)
+       addFormatterTest("%v", &pv3, "<**>"+v3s)
+       addFormatterTest("%+v", nv3, "<nil>")
+       addFormatterTest("%+v", v3, v3s)
+       addFormatterTest("%+v", pv3, "<*>("+v3Addr+")"+v3s)
+       addFormatterTest("%+v", &pv3, "<**>("+pv3Addr+"->"+v3Addr+")"+v3s)
+       addFormatterTest("%+v", nv3, "<nil>")
+       addFormatterTest("%#v", v3, "("+v3t+")"+v3s2)
+       addFormatterTest("%#v", pv3, "(*"+v3t+")"+v3s2)
+       addFormatterTest("%#v", &pv3, "(**"+v3t+")"+v3s2)
+       addFormatterTest("%#v", nv3, "(*"+v3t+")"+"<nil>")
+       addFormatterTest("%#+v", v3, "("+v3t+")"+v3s2)
+       addFormatterTest("%#+v", pv3, "(*"+v3t+")("+v3Addr+")"+v3s2)
+       addFormatterTest("%#+v", &pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")"+v3s2)
+       addFormatterTest("%#+v", nv3, "(*"+v3t+")"+"<nil>")
+}
+
+func addSliceFormatterTests() {
+       // Slice containing standard float32 values.
+       v := []float32{3.14, 6.28, 12.56}
+       nv := (*[]float32)(nil)
+       pv := &v
+       vAddr := fmt.Sprintf("%p", pv)
+       pvAddr := fmt.Sprintf("%p", &pv)
+       vt := "[]float32"
+       vs := "[3.14 6.28 12.56]"
+       addFormatterTest("%v", v, vs)
+       addFormatterTest("%v", pv, "<*>"+vs)
+       addFormatterTest("%v", &pv, "<**>"+vs)
+       addFormatterTest("%+v", nv, "<nil>")
+       addFormatterTest("%+v", v, vs)
+       addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs)
+       addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs)
+       addFormatterTest("%+v", nv, "<nil>")
+       addFormatterTest("%#v", v, "("+vt+")"+vs)
+       addFormatterTest("%#v", pv, "(*"+vt+")"+vs)
+       addFormatterTest("%#v", &pv, "(**"+vt+")"+vs)
+       addFormatterTest("%#v", nv, "(*"+vt+")"+"<nil>")
+       addFormatterTest("%#+v", v, "("+vt+")"+vs)
+       addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs)
+       addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs)
+       addFormatterTest("%#+v", nv, "(*"+vt+")"+"<nil>")
+
+       // Slice containing type with custom formatter on pointer receiver only.
+       v2 := []pstringer{"1", "2", "3"}
+       nv2 := (*[]pstringer)(nil)
+       pv2 := &v2
+       v2Addr := fmt.Sprintf("%p", pv2)
+       pv2Addr := fmt.Sprintf("%p", &pv2)
+       v2t := "[]spew_test.pstringer"
+       v2s := "[stringer 1 stringer 2 stringer 3]"
+       addFormatterTest("%v", v2, v2s)
+       addFormatterTest("%v", pv2, "<*>"+v2s)
+       addFormatterTest("%v", &pv2, "<**>"+v2s)
+       addFormatterTest("%+v", nv2, "<nil>")
+       addFormatterTest("%+v", v2, v2s)
+       addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s)
+       addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s)
+       addFormatterTest("%+v", nv2, "<nil>")
+       addFormatterTest("%#v", v2, "("+v2t+")"+v2s)
+       addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s)
+       addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s)
+       addFormatterTest("%#v", nv2, "(*"+v2t+")"+"<nil>")
+       addFormatterTest("%#+v", v2, "("+v2t+")"+v2s)
+       addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s)
+       addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s)
+       addFormatterTest("%#+v", nv2, "(*"+v2t+")"+"<nil>")
+
+       // Slice containing interfaces.
+       v3 := []interface{}{"one", int(2), uint(3), nil}
+       nv3 := (*[]interface{})(nil)
+       pv3 := &v3
+       v3Addr := fmt.Sprintf("%p", pv3)
+       pv3Addr := fmt.Sprintf("%p", &pv3)
+       v3t := "[]interface {}"
+       v3t2 := "string"
+       v3t3 := "int"
+       v3t4 := "uint"
+       v3t5 := "interface {}"
+       v3s := "[one 2 3 <nil>]"
+       v3s2 := "[(" + v3t2 + ")one (" + v3t3 + ")2 (" + v3t4 + ")3 (" + v3t5 +
+               ")<nil>]"
+       addFormatterTest("%v", v3, v3s)
+       addFormatterTest("%v", pv3, "<*>"+v3s)
+       addFormatterTest("%v", &pv3, "<**>"+v3s)
+       addFormatterTest("%+v", nv3, "<nil>")
+       addFormatterTest("%+v", v3, v3s)
+       addFormatterTest("%+v", pv3, "<*>("+v3Addr+")"+v3s)
+       addFormatterTest("%+v", &pv3, "<**>("+pv3Addr+"->"+v3Addr+")"+v3s)
+       addFormatterTest("%+v", nv3, "<nil>")
+       addFormatterTest("%#v", v3, "("+v3t+")"+v3s2)
+       addFormatterTest("%#v", pv3, "(*"+v3t+")"+v3s2)
+       addFormatterTest("%#v", &pv3, "(**"+v3t+")"+v3s2)
+       addFormatterTest("%#v", nv3, "(*"+v3t+")"+"<nil>")
+       addFormatterTest("%#+v", v3, "("+v3t+")"+v3s2)
+       addFormatterTest("%#+v", pv3, "(*"+v3t+")("+v3Addr+")"+v3s2)
+       addFormatterTest("%#+v", &pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")"+v3s2)
+       addFormatterTest("%#+v", nv3, "(*"+v3t+")"+"<nil>")
+
+       // Nil slice.
+       var v4 []int
+       nv4 := (*[]int)(nil)
+       pv4 := &v4
+       v4Addr := fmt.Sprintf("%p", pv4)
+       pv4Addr := fmt.Sprintf("%p", &pv4)
+       v4t := "[]int"
+       v4s := "<nil>"
+       addFormatterTest("%v", v4, v4s)
+       addFormatterTest("%v", pv4, "<*>"+v4s)
+       addFormatterTest("%v", &pv4, "<**>"+v4s)
+       addFormatterTest("%+v", nv4, "<nil>")
+       addFormatterTest("%+v", v4, v4s)
+       addFormatterTest("%+v", pv4, "<*>("+v4Addr+")"+v4s)
+       addFormatterTest("%+v", &pv4, "<**>("+pv4Addr+"->"+v4Addr+")"+v4s)
+       addFormatterTest("%+v", nv4, "<nil>")
+       addFormatterTest("%#v", v4, "("+v4t+")"+v4s)
+       addFormatterTest("%#v", pv4, "(*"+v4t+")"+v4s)
+       addFormatterTest("%#v", &pv4, "(**"+v4t+")"+v4s)
+       addFormatterTest("%#v", nv4, "(*"+v4t+")"+"<nil>")
+       addFormatterTest("%#+v", v4, "("+v4t+")"+v4s)
+       addFormatterTest("%#+v", pv4, "(*"+v4t+")("+v4Addr+")"+v4s)
+       addFormatterTest("%#+v", &pv4, "(**"+v4t+")("+pv4Addr+"->"+v4Addr+")"+v4s)
+       addFormatterTest("%#+v", nv4, "(*"+v4t+")"+"<nil>")
+}
+
+func addStringFormatterTests() {
+       // Standard string.
+       v := "test"
+       nv := (*string)(nil)
+       pv := &v
+       vAddr := fmt.Sprintf("%p", pv)
+       pvAddr := fmt.Sprintf("%p", &pv)
+       vt := "string"
+       vs := "test"
+       addFormatterTest("%v", v, vs)
+       addFormatterTest("%v", pv, "<*>"+vs)
+       addFormatterTest("%v", &pv, "<**>"+vs)
+       addFormatterTest("%+v", nv, "<nil>")
+       addFormatterTest("%+v", v, vs)
+       addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs)
+       addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs)
+       addFormatterTest("%+v", nv, "<nil>")
+       addFormatterTest("%#v", v, "("+vt+")"+vs)
+       addFormatterTest("%#v", pv, "(*"+vt+")"+vs)
+       addFormatterTest("%#v", &pv, "(**"+vt+")"+vs)
+       addFormatterTest("%#v", nv, "(*"+vt+")"+"<nil>")
+       addFormatterTest("%#+v", v, "("+vt+")"+vs)
+       addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs)
+       addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs)
+       addFormatterTest("%#+v", nv, "(*"+vt+")"+"<nil>")
+}
+
+func addInterfaceFormatterTests() {
+       // Nil interface.
+       var v interface{}
+       nv := (*interface{})(nil)
+       pv := &v
+       vAddr := fmt.Sprintf("%p", pv)
+       pvAddr := fmt.Sprintf("%p", &pv)
+       vt := "interface {}"
+       vs := "<nil>"
+       addFormatterTest("%v", v, vs)
+       addFormatterTest("%v", pv, "<*>"+vs)
+       addFormatterTest("%v", &pv, "<**>"+vs)
+       addFormatterTest("%+v", nv, "<nil>")
+       addFormatterTest("%+v", v, vs)
+       addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs)
+       addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs)
+       addFormatterTest("%+v", nv, "<nil>")
+       addFormatterTest("%#v", v, "("+vt+")"+vs)
+       addFormatterTest("%#v", pv, "(*"+vt+")"+vs)
+       addFormatterTest("%#v", &pv, "(**"+vt+")"+vs)
+       addFormatterTest("%#v", nv, "(*"+vt+")"+"<nil>")
+       addFormatterTest("%#+v", v, "("+vt+")"+vs)
+       addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs)
+       addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs)
+       addFormatterTest("%#+v", nv, "(*"+vt+")"+"<nil>")
+
+       // Sub-interface.
+       v2 := interface{}(uint16(65535))
+       pv2 := &v2
+       v2Addr := fmt.Sprintf("%p", pv2)
+       pv2Addr := fmt.Sprintf("%p", &pv2)
+       v2t := "uint16"
+       v2s := "65535"
+       addFormatterTest("%v", v2, v2s)
+       addFormatterTest("%v", pv2, "<*>"+v2s)
+       addFormatterTest("%v", &pv2, "<**>"+v2s)
+       addFormatterTest("%+v", v2, v2s)
+       addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s)
+       addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s)
+       addFormatterTest("%#v", v2, "("+v2t+")"+v2s)
+       addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s)
+       addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s)
+       addFormatterTest("%#+v", v2, "("+v2t+")"+v2s)
+       addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s)
+       addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s)
+}
+
+func addMapFormatterTests() {
+       // Map with string keys and int vals.
+       v := map[string]int{"one": 1, "two": 2}
+       nilMap := map[string]int(nil)
+       nv := (*map[string]int)(nil)
+       pv := &v
+       vAddr := fmt.Sprintf("%p", pv)
+       pvAddr := fmt.Sprintf("%p", &pv)
+       vt := "map[string]int"
+       vs := "map[one:1 two:2]"
+       vs2 := "map[two:2 one:1]"
+       addFormatterTest("%v", v, vs, vs2)
+       addFormatterTest("%v", pv, "<*>"+vs, "<*>"+vs2)
+       addFormatterTest("%v", &pv, "<**>"+vs, "<**>"+vs2)
+       addFormatterTest("%+v", nilMap, "<nil>")
+       addFormatterTest("%+v", nv, "<nil>")
+       addFormatterTest("%+v", v, vs, vs2)
+       addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs, "<*>("+vAddr+")"+vs2)
+       addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs,
+               "<**>("+pvAddr+"->"+vAddr+")"+vs2)
+       addFormatterTest("%+v", nilMap, "<nil>")
+       addFormatterTest("%+v", nv, "<nil>")
+       addFormatterTest("%#v", v, "("+vt+")"+vs, "("+vt+")"+vs2)
+       addFormatterTest("%#v", pv, "(*"+vt+")"+vs, "(*"+vt+")"+vs2)
+       addFormatterTest("%#v", &pv, "(**"+vt+")"+vs, "(**"+vt+")"+vs2)
+       addFormatterTest("%#v", nilMap, "("+vt+")"+"<nil>")
+       addFormatterTest("%#v", nv, "(*"+vt+")"+"<nil>")
+       addFormatterTest("%#+v", v, "("+vt+")"+vs, "("+vt+")"+vs2)
+       addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs,
+               "(*"+vt+")("+vAddr+")"+vs2)
+       addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs,
+               "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs2)
+       addFormatterTest("%#+v", nilMap, "("+vt+")"+"<nil>")
+       addFormatterTest("%#+v", nv, "(*"+vt+")"+"<nil>")
+
+       // Map with custom formatter type on pointer receiver only keys and vals.
+       v2 := map[pstringer]pstringer{"one": "1"}
+       nv2 := (*map[pstringer]pstringer)(nil)
+       pv2 := &v2
+       v2Addr := fmt.Sprintf("%p", pv2)
+       pv2Addr := fmt.Sprintf("%p", &pv2)
+       v2t := "map[spew_test.pstringer]spew_test.pstringer"
+       v2s := "map[stringer one:stringer 1]"
+       if spew.UnsafeDisabled {
+               v2s = "map[one:1]"
+       }
+       addFormatterTest("%v", v2, v2s)
+       addFormatterTest("%v", pv2, "<*>"+v2s)
+       addFormatterTest("%v", &pv2, "<**>"+v2s)
+       addFormatterTest("%+v", nv2, "<nil>")
+       addFormatterTest("%+v", v2, v2s)
+       addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s)
+       addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s)
+       addFormatterTest("%+v", nv2, "<nil>")
+       addFormatterTest("%#v", v2, "("+v2t+")"+v2s)
+       addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s)
+       addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s)
+       addFormatterTest("%#v", nv2, "(*"+v2t+")"+"<nil>")
+       addFormatterTest("%#+v", v2, "("+v2t+")"+v2s)
+       addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s)
+       addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s)
+       addFormatterTest("%#+v", nv2, "(*"+v2t+")"+"<nil>")
+
+       // Map with interface keys and values.
+       v3 := map[interface{}]interface{}{"one": 1}
+       nv3 := (*map[interface{}]interface{})(nil)
+       pv3 := &v3
+       v3Addr := fmt.Sprintf("%p", pv3)
+       pv3Addr := fmt.Sprintf("%p", &pv3)
+       v3t := "map[interface {}]interface {}"
+       v3t1 := "string"
+       v3t2 := "int"
+       v3s := "map[one:1]"
+       v3s2 := "map[(" + v3t1 + ")one:(" + v3t2 + ")1]"
+       addFormatterTest("%v", v3, v3s)
+       addFormatterTest("%v", pv3, "<*>"+v3s)
+       addFormatterTest("%v", &pv3, "<**>"+v3s)
+       addFormatterTest("%+v", nv3, "<nil>")
+       addFormatterTest("%+v", v3, v3s)
+       addFormatterTest("%+v", pv3, "<*>("+v3Addr+")"+v3s)
+       addFormatterTest("%+v", &pv3, "<**>("+pv3Addr+"->"+v3Addr+")"+v3s)
+       addFormatterTest("%+v", nv3, "<nil>")
+       addFormatterTest("%#v", v3, "("+v3t+")"+v3s2)
+       addFormatterTest("%#v", pv3, "(*"+v3t+")"+v3s2)
+       addFormatterTest("%#v", &pv3, "(**"+v3t+")"+v3s2)
+       addFormatterTest("%#v", nv3, "(*"+v3t+")"+"<nil>")
+       addFormatterTest("%#+v", v3, "("+v3t+")"+v3s2)
+       addFormatterTest("%#+v", pv3, "(*"+v3t+")("+v3Addr+")"+v3s2)
+       addFormatterTest("%#+v", &pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")"+v3s2)
+       addFormatterTest("%#+v", nv3, "(*"+v3t+")"+"<nil>")
+
+       // Map with nil interface value
+       v4 := map[string]interface{}{"nil": nil}
+       nv4 := (*map[string]interface{})(nil)
+       pv4 := &v4
+       v4Addr := fmt.Sprintf("%p", pv4)
+       pv4Addr := fmt.Sprintf("%p", &pv4)
+       v4t := "map[string]interface {}"
+       v4t1 := "interface {}"
+       v4s := "map[nil:<nil>]"
+       v4s2 := "map[nil:(" + v4t1 + ")<nil>]"
+       addFormatterTest("%v", v4, v4s)
+       addFormatterTest("%v", pv4, "<*>"+v4s)
+       addFormatterTest("%v", &pv4, "<**>"+v4s)
+       addFormatterTest("%+v", nv4, "<nil>")
+       addFormatterTest("%+v", v4, v4s)
+       addFormatterTest("%+v", pv4, "<*>("+v4Addr+")"+v4s)
+       addFormatterTest("%+v", &pv4, "<**>("+pv4Addr+"->"+v4Addr+")"+v4s)
+       addFormatterTest("%+v", nv4, "<nil>")
+       addFormatterTest("%#v", v4, "("+v4t+")"+v4s2)
+       addFormatterTest("%#v", pv4, "(*"+v4t+")"+v4s2)
+       addFormatterTest("%#v", &pv4, "(**"+v4t+")"+v4s2)
+       addFormatterTest("%#v", nv4, "(*"+v4t+")"+"<nil>")
+       addFormatterTest("%#+v", v4, "("+v4t+")"+v4s2)
+       addFormatterTest("%#+v", pv4, "(*"+v4t+")("+v4Addr+")"+v4s2)
+       addFormatterTest("%#+v", &pv4, "(**"+v4t+")("+pv4Addr+"->"+v4Addr+")"+v4s2)
+       addFormatterTest("%#+v", nv4, "(*"+v4t+")"+"<nil>")
+}
+
+func addStructFormatterTests() {
+       // Struct with primitives.
+       type s1 struct {
+               a int8
+               b uint8
+       }
+       v := s1{127, 255}
+       nv := (*s1)(nil)
+       pv := &v
+       vAddr := fmt.Sprintf("%p", pv)
+       pvAddr := fmt.Sprintf("%p", &pv)
+       vt := "spew_test.s1"
+       vt2 := "int8"
+       vt3 := "uint8"
+       vs := "{127 255}"
+       vs2 := "{a:127 b:255}"
+       vs3 := "{a:(" + vt2 + ")127 b:(" + vt3 + ")255}"
+       addFormatterTest("%v", v, vs)
+       addFormatterTest("%v", pv, "<*>"+vs)
+       addFormatterTest("%v", &pv, "<**>"+vs)
+       addFormatterTest("%+v", nv, "<nil>")
+       addFormatterTest("%+v", v, vs2)
+       addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs2)
+       addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs2)
+       addFormatterTest("%+v", nv, "<nil>")
+       addFormatterTest("%#v", v, "("+vt+")"+vs3)
+       addFormatterTest("%#v", pv, "(*"+vt+")"+vs3)
+       addFormatterTest("%#v", &pv, "(**"+vt+")"+vs3)
+       addFormatterTest("%#v", nv, "(*"+vt+")"+"<nil>")
+       addFormatterTest("%#+v", v, "("+vt+")"+vs3)
+       addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs3)
+       addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs3)
+       addFormatterTest("%#+v", nv, "(*"+vt+")"+"<nil>")
+
+       // Struct that contains another struct.
+       type s2 struct {
+               s1 s1
+               b  bool
+       }
+       v2 := s2{s1{127, 255}, true}
+       nv2 := (*s2)(nil)
+       pv2 := &v2
+       v2Addr := fmt.Sprintf("%p", pv2)
+       pv2Addr := fmt.Sprintf("%p", &pv2)
+       v2t := "spew_test.s2"
+       v2t2 := "spew_test.s1"
+       v2t3 := "int8"
+       v2t4 := "uint8"
+       v2t5 := "bool"
+       v2s := "{{127 255} true}"
+       v2s2 := "{s1:{a:127 b:255} b:true}"
+       v2s3 := "{s1:(" + v2t2 + "){a:(" + v2t3 + ")127 b:(" + v2t4 + ")255} b:(" +
+               v2t5 + ")true}"
+       addFormatterTest("%v", v2, v2s)
+       addFormatterTest("%v", pv2, "<*>"+v2s)
+       addFormatterTest("%v", &pv2, "<**>"+v2s)
+       addFormatterTest("%+v", nv2, "<nil>")
+       addFormatterTest("%+v", v2, v2s2)
+       addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s2)
+       addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s2)
+       addFormatterTest("%+v", nv2, "<nil>")
+       addFormatterTest("%#v", v2, "("+v2t+")"+v2s3)
+       addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s3)
+       addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s3)
+       addFormatterTest("%#v", nv2, "(*"+v2t+")"+"<nil>")
+       addFormatterTest("%#+v", v2, "("+v2t+")"+v2s3)
+       addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s3)
+       addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s3)
+       addFormatterTest("%#+v", nv2, "(*"+v2t+")"+"<nil>")
+
+       // Struct that contains custom type with Stringer pointer interface via both
+       // exported and unexported fields.
+       type s3 struct {
+               s pstringer
+               S pstringer
+       }
+       v3 := s3{"test", "test2"}
+       nv3 := (*s3)(nil)
+       pv3 := &v3
+       v3Addr := fmt.Sprintf("%p", pv3)
+       pv3Addr := fmt.Sprintf("%p", &pv3)
+       v3t := "spew_test.s3"
+       v3t2 := "spew_test.pstringer"
+       v3s := "{stringer test stringer test2}"
+       v3sp := v3s
+       v3s2 := "{s:stringer test S:stringer test2}"
+       v3s2p := v3s2
+       v3s3 := "{s:(" + v3t2 + ")stringer test S:(" + v3t2 + ")stringer test2}"
+       v3s3p := v3s3
+       if spew.UnsafeDisabled {
+               v3s = "{test test2}"
+               v3sp = "{test stringer test2}"
+               v3s2 = "{s:test S:test2}"
+               v3s2p = "{s:test S:stringer test2}"
+               v3s3 = "{s:(" + v3t2 + ")test S:(" + v3t2 + ")test2}"
+               v3s3p = "{s:(" + v3t2 + ")test S:(" + v3t2 + ")stringer test2}"
+       }
+       addFormatterTest("%v", v3, v3s)
+       addFormatterTest("%v", pv3, "<*>"+v3sp)
+       addFormatterTest("%v", &pv3, "<**>"+v3sp)
+       addFormatterTest("%+v", nv3, "<nil>")
+       addFormatterTest("%+v", v3, v3s2)
+       addFormatterTest("%+v", pv3, "<*>("+v3Addr+")"+v3s2p)
+       addFormatterTest("%+v", &pv3, "<**>("+pv3Addr+"->"+v3Addr+")"+v3s2p)
+       addFormatterTest("%+v", nv3, "<nil>")
+       addFormatterTest("%#v", v3, "("+v3t+")"+v3s3)
+       addFormatterTest("%#v", pv3, "(*"+v3t+")"+v3s3p)
+       addFormatterTest("%#v", &pv3, "(**"+v3t+")"+v3s3p)
+       addFormatterTest("%#v", nv3, "(*"+v3t+")"+"<nil>")
+       addFormatterTest("%#+v", v3, "("+v3t+")"+v3s3)
+       addFormatterTest("%#+v", pv3, "(*"+v3t+")("+v3Addr+")"+v3s3p)
+       addFormatterTest("%#+v", &pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")"+v3s3p)
+       addFormatterTest("%#+v", nv3, "(*"+v3t+")"+"<nil>")
+
+       // Struct that contains embedded struct and field to same struct.
+       e := embed{"embedstr"}
+       v4 := embedwrap{embed: &e, e: &e}
+       nv4 := (*embedwrap)(nil)
+       pv4 := &v4
+       eAddr := fmt.Sprintf("%p", &e)
+       v4Addr := fmt.Sprintf("%p", pv4)
+       pv4Addr := fmt.Sprintf("%p", &pv4)
+       v4t := "spew_test.embedwrap"
+       v4t2 := "spew_test.embed"
+       v4t3 := "string"
+       v4s := "{<*>{embedstr} <*>{embedstr}}"
+       v4s2 := "{embed:<*>(" + eAddr + "){a:embedstr} e:<*>(" + eAddr +
+               "){a:embedstr}}"
+       v4s3 := "{embed:(*" + v4t2 + "){a:(" + v4t3 + ")embedstr} e:(*" + v4t2 +
+               "){a:(" + v4t3 + ")embedstr}}"
+       v4s4 := "{embed:(*" + v4t2 + ")(" + eAddr + "){a:(" + v4t3 +
+               ")embedstr} e:(*" + v4t2 + ")(" + eAddr + "){a:(" + v4t3 + ")embedstr}}"
+       addFormatterTest("%v", v4, v4s)
+       addFormatterTest("%v", pv4, "<*>"+v4s)
+       addFormatterTest("%v", &pv4, "<**>"+v4s)
+       addFormatterTest("%+v", nv4, "<nil>")
+       addFormatterTest("%+v", v4, v4s2)
+       addFormatterTest("%+v", pv4, "<*>("+v4Addr+")"+v4s2)
+       addFormatterTest("%+v", &pv4, "<**>("+pv4Addr+"->"+v4Addr+")"+v4s2)
+       addFormatterTest("%+v", nv4, "<nil>")
+       addFormatterTest("%#v", v4, "("+v4t+")"+v4s3)
+       addFormatterTest("%#v", pv4, "(*"+v4t+")"+v4s3)
+       addFormatterTest("%#v", &pv4, "(**"+v4t+")"+v4s3)
+       addFormatterTest("%#v", nv4, "(*"+v4t+")"+"<nil>")
+       addFormatterTest("%#+v", v4, "("+v4t+")"+v4s4)
+       addFormatterTest("%#+v", pv4, "(*"+v4t+")("+v4Addr+")"+v4s4)
+       addFormatterTest("%#+v", &pv4, "(**"+v4t+")("+pv4Addr+"->"+v4Addr+")"+v4s4)
+       addFormatterTest("%#+v", nv4, "(*"+v4t+")"+"<nil>")
+}
+
+func addUintptrFormatterTests() {
+       // Null pointer.
+       v := uintptr(0)
+       nv := (*uintptr)(nil)
+       pv := &v
+       vAddr := fmt.Sprintf("%p", pv)
+       pvAddr := fmt.Sprintf("%p", &pv)
+       vt := "uintptr"
+       vs := "<nil>"
+       addFormatterTest("%v", v, vs)
+       addFormatterTest("%v", pv, "<*>"+vs)
+       addFormatterTest("%v", &pv, "<**>"+vs)
+       addFormatterTest("%+v", nv, "<nil>")
+       addFormatterTest("%+v", v, vs)
+       addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs)
+       addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs)
+       addFormatterTest("%+v", nv, "<nil>")
+       addFormatterTest("%#v", v, "("+vt+")"+vs)
+       addFormatterTest("%#v", pv, "(*"+vt+")"+vs)
+       addFormatterTest("%#v", &pv, "(**"+vt+")"+vs)
+       addFormatterTest("%#v", nv, "(*"+vt+")"+"<nil>")
+       addFormatterTest("%#+v", v, "("+vt+")"+vs)
+       addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs)
+       addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs)
+       addFormatterTest("%#+v", nv, "(*"+vt+")"+"<nil>")
+
+       // Address of real variable.
+       i := 1
+       v2 := uintptr(unsafe.Pointer(&i))
+       pv2 := &v2
+       v2Addr := fmt.Sprintf("%p", pv2)
+       pv2Addr := fmt.Sprintf("%p", &pv2)
+       v2t := "uintptr"
+       v2s := fmt.Sprintf("%p", &i)
+       addFormatterTest("%v", v2, v2s)
+       addFormatterTest("%v", pv2, "<*>"+v2s)
+       addFormatterTest("%v", &pv2, "<**>"+v2s)
+       addFormatterTest("%+v", v2, v2s)
+       addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s)
+       addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s)
+       addFormatterTest("%#v", v2, "("+v2t+")"+v2s)
+       addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s)
+       addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s)
+       addFormatterTest("%#+v", v2, "("+v2t+")"+v2s)
+       addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s)
+       addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s)
+}
+
+func addUnsafePointerFormatterTests() {
+       // Null pointer.
+       v := unsafe.Pointer(uintptr(0))
+       nv := (*unsafe.Pointer)(nil)
+       pv := &v
+       vAddr := fmt.Sprintf("%p", pv)
+       pvAddr := fmt.Sprintf("%p", &pv)
+       vt := "unsafe.Pointer"
+       vs := "<nil>"
+       addFormatterTest("%v", v, vs)
+       addFormatterTest("%v", pv, "<*>"+vs)
+       addFormatterTest("%v", &pv, "<**>"+vs)
+       addFormatterTest("%+v", nv, "<nil>")
+       addFormatterTest("%+v", v, vs)
+       addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs)
+       addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs)
+       addFormatterTest("%+v", nv, "<nil>")
+       addFormatterTest("%#v", v, "("+vt+")"+vs)
+       addFormatterTest("%#v", pv, "(*"+vt+")"+vs)
+       addFormatterTest("%#v", &pv, "(**"+vt+")"+vs)
+       addFormatterTest("%#v", nv, "(*"+vt+")"+"<nil>")
+       addFormatterTest("%#+v", v, "("+vt+")"+vs)
+       addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs)
+       addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs)
+       addFormatterTest("%#+v", nv, "(*"+vt+")"+"<nil>")
+
+       // Address of real variable.
+       i := 1
+       v2 := unsafe.Pointer(&i)
+       pv2 := &v2
+       v2Addr := fmt.Sprintf("%p", pv2)
+       pv2Addr := fmt.Sprintf("%p", &pv2)
+       v2t := "unsafe.Pointer"
+       v2s := fmt.Sprintf("%p", &i)
+       addFormatterTest("%v", v2, v2s)
+       addFormatterTest("%v", pv2, "<*>"+v2s)
+       addFormatterTest("%v", &pv2, "<**>"+v2s)
+       addFormatterTest("%+v", v2, v2s)
+       addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s)
+       addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s)
+       addFormatterTest("%#v", v2, "("+v2t+")"+v2s)
+       addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s)
+       addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s)
+       addFormatterTest("%#+v", v2, "("+v2t+")"+v2s)
+       addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s)
+       addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s)
+}
+
+func addChanFormatterTests() {
+       // Nil channel.
+       var v chan int
+       pv := &v
+       nv := (*chan int)(nil)
+       vAddr := fmt.Sprintf("%p", pv)
+       pvAddr := fmt.Sprintf("%p", &pv)
+       vt := "chan int"
+       vs := "<nil>"
+       addFormatterTest("%v", v, vs)
+       addFormatterTest("%v", pv, "<*>"+vs)
+       addFormatterTest("%v", &pv, "<**>"+vs)
+       addFormatterTest("%+v", nv, "<nil>")
+       addFormatterTest("%+v", v, vs)
+       addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs)
+       addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs)
+       addFormatterTest("%+v", nv, "<nil>")
+       addFormatterTest("%#v", v, "("+vt+")"+vs)
+       addFormatterTest("%#v", pv, "(*"+vt+")"+vs)
+       addFormatterTest("%#v", &pv, "(**"+vt+")"+vs)
+       addFormatterTest("%#v", nv, "(*"+vt+")"+"<nil>")
+       addFormatterTest("%#+v", v, "("+vt+")"+vs)
+       addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs)
+       addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs)
+       addFormatterTest("%#+v", nv, "(*"+vt+")"+"<nil>")
+
+       // Real channel.
+       v2 := make(chan int)
+       pv2 := &v2
+       v2Addr := fmt.Sprintf("%p", pv2)
+       pv2Addr := fmt.Sprintf("%p", &pv2)
+       v2t := "chan int"
+       v2s := fmt.Sprintf("%p", v2)
+       addFormatterTest("%v", v2, v2s)
+       addFormatterTest("%v", pv2, "<*>"+v2s)
+       addFormatterTest("%v", &pv2, "<**>"+v2s)
+       addFormatterTest("%+v", v2, v2s)
+       addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s)
+       addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s)
+       addFormatterTest("%#v", v2, "("+v2t+")"+v2s)
+       addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s)
+       addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s)
+       addFormatterTest("%#+v", v2, "("+v2t+")"+v2s)
+       addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s)
+       addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s)
+}
+
+func addFuncFormatterTests() {
+       // Function with no params and no returns.
+       v := addIntFormatterTests
+       nv := (*func())(nil)
+       pv := &v
+       vAddr := fmt.Sprintf("%p", pv)
+       pvAddr := fmt.Sprintf("%p", &pv)
+       vt := "func()"
+       vs := fmt.Sprintf("%p", v)
+       addFormatterTest("%v", v, vs)
+       addFormatterTest("%v", pv, "<*>"+vs)
+       addFormatterTest("%v", &pv, "<**>"+vs)
+       addFormatterTest("%+v", nv, "<nil>")
+       addFormatterTest("%+v", v, vs)
+       addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs)
+       addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs)
+       addFormatterTest("%+v", nv, "<nil>")
+       addFormatterTest("%#v", v, "("+vt+")"+vs)
+       addFormatterTest("%#v", pv, "(*"+vt+")"+vs)
+       addFormatterTest("%#v", &pv, "(**"+vt+")"+vs)
+       addFormatterTest("%#v", nv, "(*"+vt+")"+"<nil>")
+       addFormatterTest("%#+v", v, "("+vt+")"+vs)
+       addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs)
+       addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs)
+       addFormatterTest("%#+v", nv, "(*"+vt+")"+"<nil>")
+
+       // Function with param and no returns.
+       v2 := TestFormatter
+       nv2 := (*func(*testing.T))(nil)
+       pv2 := &v2
+       v2Addr := fmt.Sprintf("%p", pv2)
+       pv2Addr := fmt.Sprintf("%p", &pv2)
+       v2t := "func(*testing.T)"
+       v2s := fmt.Sprintf("%p", v2)
+       addFormatterTest("%v", v2, v2s)
+       addFormatterTest("%v", pv2, "<*>"+v2s)
+       addFormatterTest("%v", &pv2, "<**>"+v2s)
+       addFormatterTest("%+v", nv2, "<nil>")
+       addFormatterTest("%+v", v2, v2s)
+       addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s)
+       addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s)
+       addFormatterTest("%+v", nv2, "<nil>")
+       addFormatterTest("%#v", v2, "("+v2t+")"+v2s)
+       addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s)
+       addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s)
+       addFormatterTest("%#v", nv2, "(*"+v2t+")"+"<nil>")
+       addFormatterTest("%#+v", v2, "("+v2t+")"+v2s)
+       addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s)
+       addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s)
+       addFormatterTest("%#+v", nv2, "(*"+v2t+")"+"<nil>")
+
+       // Function with multiple params and multiple returns.
+       var v3 = func(i int, s string) (b bool, err error) {
+               return true, nil
+       }
+       nv3 := (*func(int, string) (bool, error))(nil)
+       pv3 := &v3
+       v3Addr := fmt.Sprintf("%p", pv3)
+       pv3Addr := fmt.Sprintf("%p", &pv3)
+       v3t := "func(int, string) (bool, error)"
+       v3s := fmt.Sprintf("%p", v3)
+       addFormatterTest("%v", v3, v3s)
+       addFormatterTest("%v", pv3, "<*>"+v3s)
+       addFormatterTest("%v", &pv3, "<**>"+v3s)
+       addFormatterTest("%+v", nv3, "<nil>")
+       addFormatterTest("%+v", v3, v3s)
+       addFormatterTest("%+v", pv3, "<*>("+v3Addr+")"+v3s)
+       addFormatterTest("%+v", &pv3, "<**>("+pv3Addr+"->"+v3Addr+")"+v3s)
+       addFormatterTest("%+v", nv3, "<nil>")
+       addFormatterTest("%#v", v3, "("+v3t+")"+v3s)
+       addFormatterTest("%#v", pv3, "(*"+v3t+")"+v3s)
+       addFormatterTest("%#v", &pv3, "(**"+v3t+")"+v3s)
+       addFormatterTest("%#v", nv3, "(*"+v3t+")"+"<nil>")
+       addFormatterTest("%#+v", v3, "("+v3t+")"+v3s)
+       addFormatterTest("%#+v", pv3, "(*"+v3t+")("+v3Addr+")"+v3s)
+       addFormatterTest("%#+v", &pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")"+v3s)
+       addFormatterTest("%#+v", nv3, "(*"+v3t+")"+"<nil>")
+}
+
+func addCircularFormatterTests() {
+       // Struct that is circular through self referencing.
+       type circular struct {
+               c *circular
+       }
+       v := circular{nil}
+       v.c = &v
+       pv := &v
+       vAddr := fmt.Sprintf("%p", pv)
+       pvAddr := fmt.Sprintf("%p", &pv)
+       vt := "spew_test.circular"
+       vs := "{<*>{<*><shown>}}"
+       vs2 := "{<*><shown>}"
+       vs3 := "{c:<*>(" + vAddr + "){c:<*>(" + vAddr + ")<shown>}}"
+       vs4 := "{c:<*>(" + vAddr + ")<shown>}"
+       vs5 := "{c:(*" + vt + "){c:(*" + vt + ")<shown>}}"
+       vs6 := "{c:(*" + vt + ")<shown>}"
+       vs7 := "{c:(*" + vt + ")(" + vAddr + "){c:(*" + vt + ")(" + vAddr +
+               ")<shown>}}"
+       vs8 := "{c:(*" + vt + ")(" + vAddr + ")<shown>}"
+       addFormatterTest("%v", v, vs)
+       addFormatterTest("%v", pv, "<*>"+vs2)
+       addFormatterTest("%v", &pv, "<**>"+vs2)
+       addFormatterTest("%+v", v, vs3)
+       addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs4)
+       addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs4)
+       addFormatterTest("%#v", v, "("+vt+")"+vs5)
+       addFormatterTest("%#v", pv, "(*"+vt+")"+vs6)
+       addFormatterTest("%#v", &pv, "(**"+vt+")"+vs6)
+       addFormatterTest("%#+v", v, "("+vt+")"+vs7)
+       addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs8)
+       addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs8)
+
+       // Structs that are circular through cross referencing.
+       v2 := xref1{nil}
+       ts2 := xref2{&v2}
+       v2.ps2 = &ts2
+       pv2 := &v2
+       ts2Addr := fmt.Sprintf("%p", &ts2)
+       v2Addr := fmt.Sprintf("%p", pv2)
+       pv2Addr := fmt.Sprintf("%p", &pv2)
+       v2t := "spew_test.xref1"
+       v2t2 := "spew_test.xref2"
+       v2s := "{<*>{<*>{<*><shown>}}}"
+       v2s2 := "{<*>{<*><shown>}}"
+       v2s3 := "{ps2:<*>(" + ts2Addr + "){ps1:<*>(" + v2Addr + "){ps2:<*>(" +
+               ts2Addr + ")<shown>}}}"
+       v2s4 := "{ps2:<*>(" + ts2Addr + "){ps1:<*>(" + v2Addr + ")<shown>}}"
+       v2s5 := "{ps2:(*" + v2t2 + "){ps1:(*" + v2t + "){ps2:(*" + v2t2 +
+               ")<shown>}}}"
+       v2s6 := "{ps2:(*" + v2t2 + "){ps1:(*" + v2t + ")<shown>}}"
+       v2s7 := "{ps2:(*" + v2t2 + ")(" + ts2Addr + "){ps1:(*" + v2t +
+               ")(" + v2Addr + "){ps2:(*" + v2t2 + ")(" + ts2Addr +
+               ")<shown>}}}"
+       v2s8 := "{ps2:(*" + v2t2 + ")(" + ts2Addr + "){ps1:(*" + v2t +
+               ")(" + v2Addr + ")<shown>}}"
+       addFormatterTest("%v", v2, v2s)
+       addFormatterTest("%v", pv2, "<*>"+v2s2)
+       addFormatterTest("%v", &pv2, "<**>"+v2s2)
+       addFormatterTest("%+v", v2, v2s3)
+       addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s4)
+       addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s4)
+       addFormatterTest("%#v", v2, "("+v2t+")"+v2s5)
+       addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s6)
+       addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s6)
+       addFormatterTest("%#+v", v2, "("+v2t+")"+v2s7)
+       addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s8)
+       addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s8)
+
+       // Structs that are indirectly circular.
+       v3 := indirCir1{nil}
+       tic2 := indirCir2{nil}
+       tic3 := indirCir3{&v3}
+       tic2.ps3 = &tic3
+       v3.ps2 = &tic2
+       pv3 := &v3
+       tic2Addr := fmt.Sprintf("%p", &tic2)
+       tic3Addr := fmt.Sprintf("%p", &tic3)
+       v3Addr := fmt.Sprintf("%p", pv3)
+       pv3Addr := fmt.Sprintf("%p", &pv3)
+       v3t := "spew_test.indirCir1"
+       v3t2 := "spew_test.indirCir2"
+       v3t3 := "spew_test.indirCir3"
+       v3s := "{<*>{<*>{<*>{<*><shown>}}}}"
+       v3s2 := "{<*>{<*>{<*><shown>}}}"
+       v3s3 := "{ps2:<*>(" + tic2Addr + "){ps3:<*>(" + tic3Addr + "){ps1:<*>(" +
+               v3Addr + "){ps2:<*>(" + tic2Addr + ")<shown>}}}}"
+       v3s4 := "{ps2:<*>(" + tic2Addr + "){ps3:<*>(" + tic3Addr + "){ps1:<*>(" +
+               v3Addr + ")<shown>}}}"
+       v3s5 := "{ps2:(*" + v3t2 + "){ps3:(*" + v3t3 + "){ps1:(*" + v3t +
+               "){ps2:(*" + v3t2 + ")<shown>}}}}"
+       v3s6 := "{ps2:(*" + v3t2 + "){ps3:(*" + v3t3 + "){ps1:(*" + v3t +
+               ")<shown>}}}"
+       v3s7 := "{ps2:(*" + v3t2 + ")(" + tic2Addr + "){ps3:(*" + v3t3 + ")(" +
+               tic3Addr + "){ps1:(*" + v3t + ")(" + v3Addr + "){ps2:(*" + v3t2 +
+               ")(" + tic2Addr + ")<shown>}}}}"
+       v3s8 := "{ps2:(*" + v3t2 + ")(" + tic2Addr + "){ps3:(*" + v3t3 + ")(" +
+               tic3Addr + "){ps1:(*" + v3t + ")(" + v3Addr + ")<shown>}}}"
+       addFormatterTest("%v", v3, v3s)
+       addFormatterTest("%v", pv3, "<*>"+v3s2)
+       addFormatterTest("%v", &pv3, "<**>"+v3s2)
+       addFormatterTest("%+v", v3, v3s3)
+       addFormatterTest("%+v", pv3, "<*>("+v3Addr+")"+v3s4)
+       addFormatterTest("%+v", &pv3, "<**>("+pv3Addr+"->"+v3Addr+")"+v3s4)
+       addFormatterTest("%#v", v3, "("+v3t+")"+v3s5)
+       addFormatterTest("%#v", pv3, "(*"+v3t+")"+v3s6)
+       addFormatterTest("%#v", &pv3, "(**"+v3t+")"+v3s6)
+       addFormatterTest("%#+v", v3, "("+v3t+")"+v3s7)
+       addFormatterTest("%#+v", pv3, "(*"+v3t+")("+v3Addr+")"+v3s8)
+       addFormatterTest("%#+v", &pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")"+v3s8)
+}
+
+func addPanicFormatterTests() {
+       // Type that panics in its Stringer interface.
+       v := panicer(127)
+       nv := (*panicer)(nil)
+       pv := &v
+       vAddr := fmt.Sprintf("%p", pv)
+       pvAddr := fmt.Sprintf("%p", &pv)
+       vt := "spew_test.panicer"
+       vs := "(PANIC=test panic)127"
+       addFormatterTest("%v", v, vs)
+       addFormatterTest("%v", pv, "<*>"+vs)
+       addFormatterTest("%v", &pv, "<**>"+vs)
+       addFormatterTest("%v", nv, "<nil>")
+       addFormatterTest("%+v", v, vs)
+       addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs)
+       addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs)
+       addFormatterTest("%+v", nv, "<nil>")
+       addFormatterTest("%#v", v, "("+vt+")"+vs)
+       addFormatterTest("%#v", pv, "(*"+vt+")"+vs)
+       addFormatterTest("%#v", &pv, "(**"+vt+")"+vs)
+       addFormatterTest("%#v", nv, "(*"+vt+")"+"<nil>")
+       addFormatterTest("%#+v", v, "("+vt+")"+vs)
+       addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs)
+       addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs)
+       addFormatterTest("%#+v", nv, "(*"+vt+")"+"<nil>")
+}
+
+func addErrorFormatterTests() {
+       // Type that has a custom Error interface.
+       v := customError(127)
+       nv := (*customError)(nil)
+       pv := &v
+       vAddr := fmt.Sprintf("%p", pv)
+       pvAddr := fmt.Sprintf("%p", &pv)
+       vt := "spew_test.customError"
+       vs := "error: 127"
+       addFormatterTest("%v", v, vs)
+       addFormatterTest("%v", pv, "<*>"+vs)
+       addFormatterTest("%v", &pv, "<**>"+vs)
+       addFormatterTest("%v", nv, "<nil>")
+       addFormatterTest("%+v", v, vs)
+       addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs)
+       addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs)
+       addFormatterTest("%+v", nv, "<nil>")
+       addFormatterTest("%#v", v, "("+vt+")"+vs)
+       addFormatterTest("%#v", pv, "(*"+vt+")"+vs)
+       addFormatterTest("%#v", &pv, "(**"+vt+")"+vs)
+       addFormatterTest("%#v", nv, "(*"+vt+")"+"<nil>")
+       addFormatterTest("%#+v", v, "("+vt+")"+vs)
+       addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs)
+       addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs)
+       addFormatterTest("%#+v", nv, "(*"+vt+")"+"<nil>")
+}
+
+func addPassthroughFormatterTests() {
+       // %x passthrough with uint.
+       v := uint(4294967295)
+       pv := &v
+       vAddr := fmt.Sprintf("%x", pv)
+       pvAddr := fmt.Sprintf("%x", &pv)
+       vs := "ffffffff"
+       addFormatterTest("%x", v, vs)
+       addFormatterTest("%x", pv, vAddr)
+       addFormatterTest("%x", &pv, pvAddr)
+
+       // %#x passthrough with uint.
+       v2 := int(2147483647)
+       pv2 := &v2
+       v2Addr := fmt.Sprintf("%#x", pv2)
+       pv2Addr := fmt.Sprintf("%#x", &pv2)
+       v2s := "0x7fffffff"
+       addFormatterTest("%#x", v2, v2s)
+       addFormatterTest("%#x", pv2, v2Addr)
+       addFormatterTest("%#x", &pv2, pv2Addr)
+
+       // %f passthrough with precision.
+       addFormatterTest("%.2f", 3.1415, "3.14")
+       addFormatterTest("%.3f", 3.1415, "3.142")
+       addFormatterTest("%.4f", 3.1415, "3.1415")
+
+       // %f passthrough with width and precision.
+       addFormatterTest("%5.2f", 3.1415, " 3.14")
+       addFormatterTest("%6.3f", 3.1415, " 3.142")
+       addFormatterTest("%7.4f", 3.1415, " 3.1415")
+
+       // %d passthrough with width.
+       addFormatterTest("%3d", 127, "127")
+       addFormatterTest("%4d", 127, " 127")
+       addFormatterTest("%5d", 127, "  127")
+
+       // %q passthrough with string.
+       addFormatterTest("%q", "test", "\"test\"")
+}
+
+// TestFormatter executes all of the tests described by formatterTests.
+func TestFormatter(t *testing.T) {
+       // Setup tests.
+       addIntFormatterTests()
+       addUintFormatterTests()
+       addBoolFormatterTests()
+       addFloatFormatterTests()
+       addComplexFormatterTests()
+       addArrayFormatterTests()
+       addSliceFormatterTests()
+       addStringFormatterTests()
+       addInterfaceFormatterTests()
+       addMapFormatterTests()
+       addStructFormatterTests()
+       addUintptrFormatterTests()
+       addUnsafePointerFormatterTests()
+       addChanFormatterTests()
+       addFuncFormatterTests()
+       addCircularFormatterTests()
+       addPanicFormatterTests()
+       addErrorFormatterTests()
+       addPassthroughFormatterTests()
+
+       t.Logf("Running %d tests", len(formatterTests))
+       for i, test := range formatterTests {
+               buf := new(bytes.Buffer)
+               spew.Fprintf(buf, test.format, test.in)
+               s := buf.String()
+               if testFailed(s, test.wants) {
+                       t.Errorf("Formatter #%d format: %s got: %s %s", i, test.format, s,
+                               stringizeWants(test.wants))
+                       continue
+               }
+       }
+}
+
+type testStruct struct {
+       x int
+}
+
+func (ts testStruct) String() string {
+       return fmt.Sprintf("ts.%d", ts.x)
+}
+
+type testStructP struct {
+       x int
+}
+
+func (ts *testStructP) String() string {
+       return fmt.Sprintf("ts.%d", ts.x)
+}
+
+func TestPrintSortedKeys(t *testing.T) {
+       cfg := spew.ConfigState{SortKeys: true}
+       s := cfg.Sprint(map[int]string{1: "1", 3: "3", 2: "2"})
+       expected := "map[1:1 2:2 3:3]"
+       if s != expected {
+               t.Errorf("Sorted keys mismatch 1:\n  %v %v", s, expected)
+       }
+
+       s = cfg.Sprint(map[stringer]int{"1": 1, "3": 3, "2": 2})
+       expected = "map[stringer 1:1 stringer 2:2 stringer 3:3]"
+       if s != expected {
+               t.Errorf("Sorted keys mismatch 2:\n  %v %v", s, expected)
+       }
+
+       s = cfg.Sprint(map[pstringer]int{pstringer("1"): 1, pstringer("3"): 3, pstringer("2"): 2})
+       expected = "map[stringer 1:1 stringer 2:2 stringer 3:3]"
+       if spew.UnsafeDisabled {
+               expected = "map[1:1 2:2 3:3]"
+       }
+       if s != expected {
+               t.Errorf("Sorted keys mismatch 3:\n  %v %v", s, expected)
+       }
+
+       s = cfg.Sprint(map[testStruct]int{testStruct{1}: 1, testStruct{3}: 3, testStruct{2}: 2})
+       expected = "map[ts.1:1 ts.2:2 ts.3:3]"
+       if s != expected {
+               t.Errorf("Sorted keys mismatch 4:\n  %v %v", s, expected)
+       }
+
+       if !spew.UnsafeDisabled {
+               s = cfg.Sprint(map[testStructP]int{testStructP{1}: 1, testStructP{3}: 3, testStructP{2}: 2})
+               expected = "map[ts.1:1 ts.2:2 ts.3:3]"
+               if s != expected {
+                       t.Errorf("Sorted keys mismatch 5:\n  %v %v", s, expected)
+               }
+       }
+
+       s = cfg.Sprint(map[customError]int{customError(1): 1, customError(3): 3, customError(2): 2})
+       expected = "map[error: 1:1 error: 2:2 error: 3:3]"
+       if s != expected {
+               t.Errorf("Sorted keys mismatch 6:\n  %v %v", s, expected)
+       }
+}
diff --git a/vendor/github.com/git-lfs/gitobj/vendor/github.com/davecgh/go-spew/spew/internal_test.go b/vendor/github.com/git-lfs/gitobj/vendor/github.com/davecgh/go-spew/spew/internal_test.go
new file mode 100644 (file)
index 0000000..1069ee2
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2013 Dave Collins <dave@davec.name>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+This test file is part of the spew package rather than than the spew_test
+package because it needs access to internals to properly test certain cases
+which are not possible via the public interface since they should never happen.
+*/
+
+package spew
+
+import (
+       "bytes"
+       "reflect"
+       "testing"
+)
+
+// dummyFmtState implements a fake fmt.State to use for testing invalid
+// reflect.Value handling.  This is necessary because the fmt package catches
+// invalid values before invoking the formatter on them.
+type dummyFmtState struct {
+       bytes.Buffer
+}
+
+func (dfs *dummyFmtState) Flag(f int) bool {
+       if f == int('+') {
+               return true
+       }
+       return false
+}
+
+func (dfs *dummyFmtState) Precision() (int, bool) {
+       return 0, false
+}
+
+func (dfs *dummyFmtState) Width() (int, bool) {
+       return 0, false
+}
+
+// TestInvalidReflectValue ensures the dump and formatter code handles an
+// invalid reflect value properly.  This needs access to internal state since it
+// should never happen in real code and therefore can't be tested via the public
+// API.
+func TestInvalidReflectValue(t *testing.T) {
+       i := 1
+
+       // Dump invalid reflect value.
+       v := new(reflect.Value)
+       buf := new(bytes.Buffer)
+       d := dumpState{w: buf, cs: &Config}
+       d.dump(*v)
+       s := buf.String()
+       want := "<invalid>"
+       if s != want {
+               t.Errorf("InvalidReflectValue #%d\n got: %s want: %s", i, s, want)
+       }
+       i++
+
+       // Formatter invalid reflect value.
+       buf2 := new(dummyFmtState)
+       f := formatState{value: *v, cs: &Config, fs: buf2}
+       f.format(*v)
+       s = buf2.String()
+       want = "<invalid>"
+       if s != want {
+               t.Errorf("InvalidReflectValue #%d got: %s want: %s", i, s, want)
+       }
+}
+
+// SortValues makes the internal sortValues function available to the test
+// package.
+func SortValues(values []reflect.Value, cs *ConfigState) {
+       sortValues(values, cs)
+}
diff --git a/vendor/github.com/git-lfs/gitobj/vendor/github.com/davecgh/go-spew/spew/internalunsafe_test.go b/vendor/github.com/git-lfs/gitobj/vendor/github.com/davecgh/go-spew/spew/internalunsafe_test.go
new file mode 100644 (file)
index 0000000..83e070e
--- /dev/null
@@ -0,0 +1,101 @@
+// Copyright (c) 2013-2015 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 and "-tags disableunsafe"
+// is not added to the go build command line.
+// +build !appengine,!disableunsafe
+
+/*
+This test file is part of the spew package rather than than the spew_test
+package because it needs access to internals to properly test certain cases
+which are not possible via the public interface since they should never happen.
+*/
+
+package spew
+
+import (
+       "bytes"
+       "reflect"
+       "testing"
+       "unsafe"
+)
+
+// changeKind uses unsafe to intentionally change the kind of a reflect.Value to
+// the maximum kind value which does not exist.  This is needed to test the
+// fallback code which punts to the standard fmt library for new types that
+// might get added to the language.
+func changeKind(v *reflect.Value, readOnly bool) {
+       rvf := (*uintptr)(unsafe.Pointer(uintptr(unsafe.Pointer(v)) + offsetFlag))
+       *rvf = *rvf | ((1<<flagKindWidth - 1) << flagKindShift)
+       if readOnly {
+               *rvf |= flagRO
+       } else {
+               *rvf &= ^uintptr(flagRO)
+       }
+}
+
+// TestAddedReflectValue tests functionaly of the dump and formatter code which
+// falls back to the standard fmt library for new types that might get added to
+// the language.
+func TestAddedReflectValue(t *testing.T) {
+       i := 1
+
+       // Dump using a reflect.Value that is exported.
+       v := reflect.ValueOf(int8(5))
+       changeKind(&v, false)
+       buf := new(bytes.Buffer)
+       d := dumpState{w: buf, cs: &Config}
+       d.dump(v)
+       s := buf.String()
+       want := "(int8) 5"
+       if s != want {
+               t.Errorf("TestAddedReflectValue #%d\n got: %s want: %s", i, s, want)
+       }
+       i++
+
+       // Dump using a reflect.Value that is not exported.
+       changeKind(&v, true)
+       buf.Reset()
+       d.dump(v)
+       s = buf.String()
+       want = "(int8) <int8 Value>"
+       if s != want {
+               t.Errorf("TestAddedReflectValue #%d\n got: %s want: %s", i, s, want)
+       }
+       i++
+
+       // Formatter using a reflect.Value that is exported.
+       changeKind(&v, false)
+       buf2 := new(dummyFmtState)
+       f := formatState{value: v, cs: &Config, fs: buf2}
+       f.format(v)
+       s = buf2.String()
+       want = "5"
+       if s != want {
+               t.Errorf("TestAddedReflectValue #%d got: %s want: %s", i, s, want)
+       }
+       i++
+
+       // Formatter using a reflect.Value that is not exported.
+       changeKind(&v, true)
+       buf2.Reset()
+       f = formatState{value: v, cs: &Config, fs: buf2}
+       f.format(v)
+       s = buf2.String()
+       want = "<int8 Value>"
+       if s != want {
+               t.Errorf("TestAddedReflectValue #%d got: %s want: %s", i, s, want)
+       }
+}
diff --git a/vendor/github.com/git-lfs/gitobj/vendor/github.com/davecgh/go-spew/spew/spew.go b/vendor/github.com/git-lfs/gitobj/vendor/github.com/davecgh/go-spew/spew/spew.go
new file mode 100644 (file)
index 0000000..d8233f5
--- /dev/null
@@ -0,0 +1,148 @@
+/*
+ * Copyright (c) 2013 Dave Collins <dave@davec.name>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+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
+}
diff --git a/vendor/github.com/git-lfs/gitobj/vendor/github.com/davecgh/go-spew/spew/spew_test.go b/vendor/github.com/git-lfs/gitobj/vendor/github.com/davecgh/go-spew/spew/spew_test.go
new file mode 100644 (file)
index 0000000..dbbc085
--- /dev/null
@@ -0,0 +1,309 @@
+/*
+ * Copyright (c) 2013 Dave Collins <dave@davec.name>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+package spew_test
+
+import (
+       "bytes"
+       "fmt"
+       "io/ioutil"
+       "os"
+       "testing"
+
+       "github.com/davecgh/go-spew/spew"
+)
+
+// spewFunc is used to identify which public function of the spew package or
+// ConfigState a test applies to.
+type spewFunc int
+
+const (
+       fCSFdump spewFunc = iota
+       fCSFprint
+       fCSFprintf
+       fCSFprintln
+       fCSPrint
+       fCSPrintln
+       fCSSdump
+       fCSSprint
+       fCSSprintf
+       fCSSprintln
+       fCSErrorf
+       fCSNewFormatter
+       fErrorf
+       fFprint
+       fFprintln
+       fPrint
+       fPrintln
+       fSdump
+       fSprint
+       fSprintf
+       fSprintln
+)
+
+// Map of spewFunc values to names for pretty printing.
+var spewFuncStrings = map[spewFunc]string{
+       fCSFdump:        "ConfigState.Fdump",
+       fCSFprint:       "ConfigState.Fprint",
+       fCSFprintf:      "ConfigState.Fprintf",
+       fCSFprintln:     "ConfigState.Fprintln",
+       fCSSdump:        "ConfigState.Sdump",
+       fCSPrint:        "ConfigState.Print",
+       fCSPrintln:      "ConfigState.Println",
+       fCSSprint:       "ConfigState.Sprint",
+       fCSSprintf:      "ConfigState.Sprintf",
+       fCSSprintln:     "ConfigState.Sprintln",
+       fCSErrorf:       "ConfigState.Errorf",
+       fCSNewFormatter: "ConfigState.NewFormatter",
+       fErrorf:         "spew.Errorf",
+       fFprint:         "spew.Fprint",
+       fFprintln:       "spew.Fprintln",
+       fPrint:          "spew.Print",
+       fPrintln:        "spew.Println",
+       fSdump:          "spew.Sdump",
+       fSprint:         "spew.Sprint",
+       fSprintf:        "spew.Sprintf",
+       fSprintln:       "spew.Sprintln",
+}
+
+func (f spewFunc) String() string {
+       if s, ok := spewFuncStrings[f]; ok {
+               return s
+       }
+       return fmt.Sprintf("Unknown spewFunc (%d)", int(f))
+}
+
+// spewTest is used to describe a test to be performed against the public
+// functions of the spew package or ConfigState.
+type spewTest struct {
+       cs     *spew.ConfigState
+       f      spewFunc
+       format string
+       in     interface{}
+       want   string
+}
+
+// spewTests houses the tests to be performed against the public functions of
+// the spew package and ConfigState.
+//
+// These tests are only intended to ensure the public functions are exercised
+// and are intentionally not exhaustive of types.  The exhaustive type
+// tests are handled in the dump and format tests.
+var spewTests []spewTest
+
+// redirStdout is a helper function to return the standard output from f as a
+// byte slice.
+func redirStdout(f func()) ([]byte, error) {
+       tempFile, err := ioutil.TempFile("", "ss-test")
+       if err != nil {
+               return nil, err
+       }
+       fileName := tempFile.Name()
+       defer os.Remove(fileName) // Ignore error
+
+       origStdout := os.Stdout
+       os.Stdout = tempFile
+       f()
+       os.Stdout = origStdout
+       tempFile.Close()
+
+       return ioutil.ReadFile(fileName)
+}
+
+func initSpewTests() {
+       // Config states with various settings.
+       scsDefault := spew.NewDefaultConfig()
+       scsNoMethods := &spew.ConfigState{Indent: " ", DisableMethods: true}
+       scsNoPmethods := &spew.ConfigState{Indent: " ", DisablePointerMethods: true}
+       scsMaxDepth := &spew.ConfigState{Indent: " ", MaxDepth: 1}
+       scsContinue := &spew.ConfigState{Indent: " ", ContinueOnMethod: true}
+
+       // Variables for tests on types which implement Stringer interface with and
+       // without a pointer receiver.
+       ts := stringer("test")
+       tps := pstringer("test")
+
+       // depthTester is used to test max depth handling for structs, array, slices
+       // and maps.
+       type depthTester struct {
+               ic    indirCir1
+               arr   [1]string
+               slice []string
+               m     map[string]int
+       }
+       dt := depthTester{indirCir1{nil}, [1]string{"arr"}, []string{"slice"},
+               map[string]int{"one": 1}}
+
+       // Variable for tests on types which implement error interface.
+       te := customError(10)
+
+       spewTests = []spewTest{
+               {scsDefault, fCSFdump, "", int8(127), "(int8) 127\n"},
+               {scsDefault, fCSFprint, "", int16(32767), "32767"},
+               {scsDefault, fCSFprintf, "%v", int32(2147483647), "2147483647"},
+               {scsDefault, fCSFprintln, "", int(2147483647), "2147483647\n"},
+               {scsDefault, fCSPrint, "", int64(9223372036854775807), "9223372036854775807"},
+               {scsDefault, fCSPrintln, "", uint8(255), "255\n"},
+               {scsDefault, fCSSdump, "", uint8(64), "(uint8) 64\n"},
+               {scsDefault, fCSSprint, "", complex(1, 2), "(1+2i)"},
+               {scsDefault, fCSSprintf, "%v", complex(float32(3), 4), "(3+4i)"},
+               {scsDefault, fCSSprintln, "", complex(float64(5), 6), "(5+6i)\n"},
+               {scsDefault, fCSErrorf, "%#v", uint16(65535), "(uint16)65535"},
+               {scsDefault, fCSNewFormatter, "%v", uint32(4294967295), "4294967295"},
+               {scsDefault, fErrorf, "%v", uint64(18446744073709551615), "18446744073709551615"},
+               {scsDefault, fFprint, "", float32(3.14), "3.14"},
+               {scsDefault, fFprintln, "", float64(6.28), "6.28\n"},
+               {scsDefault, fPrint, "", true, "true"},
+               {scsDefault, fPrintln, "", false, "false\n"},
+               {scsDefault, fSdump, "", complex(-10, -20), "(complex128) (-10-20i)\n"},
+               {scsDefault, fSprint, "", complex(-1, -2), "(-1-2i)"},
+               {scsDefault, fSprintf, "%v", complex(float32(-3), -4), "(-3-4i)"},
+               {scsDefault, fSprintln, "", complex(float64(-5), -6), "(-5-6i)\n"},
+               {scsNoMethods, fCSFprint, "", ts, "test"},
+               {scsNoMethods, fCSFprint, "", &ts, "<*>test"},
+               {scsNoMethods, fCSFprint, "", tps, "test"},
+               {scsNoMethods, fCSFprint, "", &tps, "<*>test"},
+               {scsNoPmethods, fCSFprint, "", ts, "stringer test"},
+               {scsNoPmethods, fCSFprint, "", &ts, "<*>stringer test"},
+               {scsNoPmethods, fCSFprint, "", tps, "test"},
+               {scsNoPmethods, fCSFprint, "", &tps, "<*>stringer test"},
+               {scsMaxDepth, fCSFprint, "", dt, "{{<max>} [<max>] [<max>] map[<max>]}"},
+               {scsMaxDepth, fCSFdump, "", dt, "(spew_test.depthTester) {\n" +
+                       " ic: (spew_test.indirCir1) {\n  <max depth reached>\n },\n" +
+                       " arr: ([1]string) (len=1 cap=1) {\n  <max depth reached>\n },\n" +
+                       " slice: ([]string) (len=1 cap=1) {\n  <max depth reached>\n },\n" +
+                       " m: (map[string]int) (len=1) {\n  <max depth reached>\n }\n}\n"},
+               {scsContinue, fCSFprint, "", ts, "(stringer test) test"},
+               {scsContinue, fCSFdump, "", ts, "(spew_test.stringer) " +
+                       "(len=4) (stringer test) \"test\"\n"},
+               {scsContinue, fCSFprint, "", te, "(error: 10) 10"},
+               {scsContinue, fCSFdump, "", te, "(spew_test.customError) " +
+                       "(error: 10) 10\n"},
+       }
+}
+
+// TestSpew executes all of the tests described by spewTests.
+func TestSpew(t *testing.T) {
+       initSpewTests()
+
+       t.Logf("Running %d tests", len(spewTests))
+       for i, test := range spewTests {
+               buf := new(bytes.Buffer)
+               switch test.f {
+               case fCSFdump:
+                       test.cs.Fdump(buf, test.in)
+
+               case fCSFprint:
+                       test.cs.Fprint(buf, test.in)
+
+               case fCSFprintf:
+                       test.cs.Fprintf(buf, test.format, test.in)
+
+               case fCSFprintln:
+                       test.cs.Fprintln(buf, test.in)
+
+               case fCSPrint:
+                       b, err := redirStdout(func() { test.cs.Print(test.in) })
+                       if err != nil {
+                               t.Errorf("%v #%d %v", test.f, i, err)
+                               continue
+                       }
+                       buf.Write(b)
+
+               case fCSPrintln:
+                       b, err := redirStdout(func() { test.cs.Println(test.in) })
+                       if err != nil {
+                               t.Errorf("%v #%d %v", test.f, i, err)
+                               continue
+                       }
+                       buf.Write(b)
+
+               case fCSSdump:
+                       str := test.cs.Sdump(test.in)
+                       buf.WriteString(str)
+
+               case fCSSprint:
+                       str := test.cs.Sprint(test.in)
+                       buf.WriteString(str)
+
+               case fCSSprintf:
+                       str := test.cs.Sprintf(test.format, test.in)
+                       buf.WriteString(str)
+
+               case fCSSprintln:
+                       str := test.cs.Sprintln(test.in)
+                       buf.WriteString(str)
+
+               case fCSErrorf:
+                       err := test.cs.Errorf(test.format, test.in)
+                       buf.WriteString(err.Error())
+
+               case fCSNewFormatter:
+                       fmt.Fprintf(buf, test.format, test.cs.NewFormatter(test.in))
+
+               case fErrorf:
+                       err := spew.Errorf(test.format, test.in)
+                       buf.WriteString(err.Error())
+
+               case fFprint:
+                       spew.Fprint(buf, test.in)
+
+               case fFprintln:
+                       spew.Fprintln(buf, test.in)
+
+               case fPrint:
+                       b, err := redirStdout(func() { spew.Print(test.in) })
+                       if err != nil {
+                               t.Errorf("%v #%d %v", test.f, i, err)
+                               continue
+                       }
+                       buf.Write(b)
+
+               case fPrintln:
+                       b, err := redirStdout(func() { spew.Println(test.in) })
+                       if err != nil {
+                               t.Errorf("%v #%d %v", test.f, i, err)
+                               continue
+                       }
+                       buf.Write(b)
+
+               case fSdump:
+                       str := spew.Sdump(test.in)
+                       buf.WriteString(str)
+
+               case fSprint:
+                       str := spew.Sprint(test.in)
+                       buf.WriteString(str)
+
+               case fSprintf:
+                       str := spew.Sprintf(test.format, test.in)
+                       buf.WriteString(str)
+
+               case fSprintln:
+                       str := spew.Sprintln(test.in)
+                       buf.WriteString(str)
+
+               default:
+                       t.Errorf("%v #%d unrecognized function", test.f, i)
+                       continue
+               }
+               s := buf.String()
+               if test.want != s {
+                       t.Errorf("ConfigState #%d\n got: %s want: %s", i, s, test.want)
+                       continue
+               }
+       }
+}
diff --git a/vendor/github.com/git-lfs/gitobj/vendor/github.com/davecgh/go-spew/spew/testdata/dumpcgo.go b/vendor/github.com/git-lfs/gitobj/vendor/github.com/davecgh/go-spew/spew/testdata/dumpcgo.go
new file mode 100644 (file)
index 0000000..5c87dd4
--- /dev/null
@@ -0,0 +1,82 @@
+// Copyright (c) 2013 Dave Collins <dave@davec.name>
+//
+// Permission to use, copy, modify, and distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+// NOTE: Due to the following build constraints, this file will only be compiled
+// when both cgo is supported and "-tags testcgo" is added to the go test
+// command line.  This code should really only be in the dumpcgo_test.go file,
+// but unfortunately Go will not allow cgo in test files, so this is a
+// workaround to allow cgo types to be tested.  This configuration is used
+// because spew itself does not require cgo to run even though it does handle
+// certain cgo types specially.  Rather than forcing all clients to require cgo
+// and an external C compiler just to run the tests, this scheme makes them
+// optional.
+// +build cgo,testcgo
+
+package testdata
+
+/*
+#include <stdint.h>
+typedef unsigned char custom_uchar_t;
+
+char            *ncp = 0;
+char            *cp = "test";
+char             ca[6] = {'t', 'e', 's', 't', '2', '\0'};
+unsigned char    uca[6] = {'t', 'e', 's', 't', '3', '\0'};
+signed char      sca[6] = {'t', 'e', 's', 't', '4', '\0'};
+uint8_t          ui8ta[6] = {'t', 'e', 's', 't', '5', '\0'};
+custom_uchar_t   tuca[6] = {'t', 'e', 's', 't', '6', '\0'};
+*/
+import "C"
+
+// GetCgoNullCharPointer returns a null char pointer via cgo.  This is only
+// used for tests.
+func GetCgoNullCharPointer() interface{} {
+       return C.ncp
+}
+
+// GetCgoCharPointer returns a char pointer via cgo.  This is only used for
+// tests.
+func GetCgoCharPointer() interface{} {
+       return C.cp
+}
+
+// GetCgoCharArray returns a char array via cgo and the array's len and cap.
+// This is only used for tests.
+func GetCgoCharArray() (interface{}, int, int) {
+       return C.ca, len(C.ca), cap(C.ca)
+}
+
+// GetCgoUnsignedCharArray returns an unsigned char array via cgo and the
+// array's len and cap.  This is only used for tests.
+func GetCgoUnsignedCharArray() (interface{}, int, int) {
+       return C.uca, len(C.uca), cap(C.uca)
+}
+
+// GetCgoSignedCharArray returns a signed char array via cgo and the array's len
+// and cap.  This is only used for tests.
+func GetCgoSignedCharArray() (interface{}, int, int) {
+       return C.sca, len(C.sca), cap(C.sca)
+}
+
+// GetCgoUint8tArray returns a uint8_t array via cgo and the array's len and
+// cap.  This is only used for tests.
+func GetCgoUint8tArray() (interface{}, int, int) {
+       return C.ui8ta, len(C.ui8ta), cap(C.ui8ta)
+}
+
+// GetCgoTypdefedUnsignedCharArray returns a typedefed unsigned char array via
+// cgo and the array's len and cap.  This is only used for tests.
+func GetCgoTypdefedUnsignedCharArray() (interface{}, int, int) {
+       return C.tuca, len(C.tuca), cap(C.tuca)
+}
diff --git a/vendor/github.com/git-lfs/gitobj/vendor/github.com/davecgh/go-spew/test_coverage.txt b/vendor/github.com/git-lfs/gitobj/vendor/github.com/davecgh/go-spew/test_coverage.txt
new file mode 100644 (file)
index 0000000..2cd087a
--- /dev/null
@@ -0,0 +1,61 @@
+
+github.com/davecgh/go-spew/spew/dump.go                 dumpState.dump                  100.00% (88/88)
+github.com/davecgh/go-spew/spew/format.go       formatState.format              100.00% (82/82)
+github.com/davecgh/go-spew/spew/format.go       formatState.formatPtr           100.00% (52/52)
+github.com/davecgh/go-spew/spew/dump.go                 dumpState.dumpPtr               100.00% (44/44)
+github.com/davecgh/go-spew/spew/dump.go                 dumpState.dumpSlice             100.00% (39/39)
+github.com/davecgh/go-spew/spew/common.go       handleMethods                   100.00% (30/30)
+github.com/davecgh/go-spew/spew/common.go       printHexPtr                     100.00% (18/18)
+github.com/davecgh/go-spew/spew/common.go       unsafeReflectValue              100.00% (13/13)
+github.com/davecgh/go-spew/spew/format.go       formatState.constructOrigFormat 100.00% (12/12)
+github.com/davecgh/go-spew/spew/dump.go                 fdump                           100.00% (11/11)
+github.com/davecgh/go-spew/spew/format.go       formatState.Format              100.00% (11/11)
+github.com/davecgh/go-spew/spew/common.go       init                            100.00% (10/10)
+github.com/davecgh/go-spew/spew/common.go       printComplex                    100.00% (9/9)
+github.com/davecgh/go-spew/spew/common.go       valuesSorter.Less               100.00% (8/8)
+github.com/davecgh/go-spew/spew/format.go       formatState.buildDefaultFormat  100.00% (7/7)
+github.com/davecgh/go-spew/spew/format.go       formatState.unpackValue         100.00% (5/5)
+github.com/davecgh/go-spew/spew/dump.go                 dumpState.indent                100.00% (4/4)
+github.com/davecgh/go-spew/spew/common.go       catchPanic                      100.00% (4/4)
+github.com/davecgh/go-spew/spew/config.go       ConfigState.convertArgs         100.00% (4/4)
+github.com/davecgh/go-spew/spew/spew.go                 convertArgs                     100.00% (4/4)
+github.com/davecgh/go-spew/spew/format.go       newFormatter                    100.00% (3/3)
+github.com/davecgh/go-spew/spew/dump.go                 Sdump                           100.00% (3/3)
+github.com/davecgh/go-spew/spew/common.go       printBool                       100.00% (3/3)
+github.com/davecgh/go-spew/spew/common.go       sortValues                      100.00% (3/3)
+github.com/davecgh/go-spew/spew/config.go       ConfigState.Sdump               100.00% (3/3)
+github.com/davecgh/go-spew/spew/dump.go                 dumpState.unpackValue           100.00% (3/3)
+github.com/davecgh/go-spew/spew/spew.go                 Printf                          100.00% (1/1)
+github.com/davecgh/go-spew/spew/spew.go                 Println                         100.00% (1/1)
+github.com/davecgh/go-spew/spew/spew.go                 Sprint                          100.00% (1/1)
+github.com/davecgh/go-spew/spew/spew.go                 Sprintf                         100.00% (1/1)
+github.com/davecgh/go-spew/spew/spew.go                 Sprintln                        100.00% (1/1)
+github.com/davecgh/go-spew/spew/common.go       printFloat                      100.00% (1/1)
+github.com/davecgh/go-spew/spew/config.go       NewDefaultConfig                100.00% (1/1)
+github.com/davecgh/go-spew/spew/common.go       printInt                        100.00% (1/1)
+github.com/davecgh/go-spew/spew/common.go       printUint                       100.00% (1/1)
+github.com/davecgh/go-spew/spew/common.go       valuesSorter.Len                100.00% (1/1)
+github.com/davecgh/go-spew/spew/common.go       valuesSorter.Swap               100.00% (1/1)
+github.com/davecgh/go-spew/spew/config.go       ConfigState.Errorf              100.00% (1/1)
+github.com/davecgh/go-spew/spew/config.go       ConfigState.Fprint              100.00% (1/1)
+github.com/davecgh/go-spew/spew/config.go       ConfigState.Fprintf             100.00% (1/1)
+github.com/davecgh/go-spew/spew/config.go       ConfigState.Fprintln            100.00% (1/1)
+github.com/davecgh/go-spew/spew/config.go       ConfigState.Print               100.00% (1/1)
+github.com/davecgh/go-spew/spew/config.go       ConfigState.Printf              100.00% (1/1)
+github.com/davecgh/go-spew/spew/config.go       ConfigState.Println             100.00% (1/1)
+github.com/davecgh/go-spew/spew/config.go       ConfigState.Sprint              100.00% (1/1)
+github.com/davecgh/go-spew/spew/config.go       ConfigState.Sprintf             100.00% (1/1)
+github.com/davecgh/go-spew/spew/config.go       ConfigState.Sprintln            100.00% (1/1)
+github.com/davecgh/go-spew/spew/config.go       ConfigState.NewFormatter        100.00% (1/1)
+github.com/davecgh/go-spew/spew/config.go       ConfigState.Fdump               100.00% (1/1)
+github.com/davecgh/go-spew/spew/config.go       ConfigState.Dump                100.00% (1/1)
+github.com/davecgh/go-spew/spew/dump.go                 Fdump                           100.00% (1/1)
+github.com/davecgh/go-spew/spew/dump.go                 Dump                            100.00% (1/1)
+github.com/davecgh/go-spew/spew/spew.go                 Fprintln                        100.00% (1/1)
+github.com/davecgh/go-spew/spew/format.go       NewFormatter                    100.00% (1/1)
+github.com/davecgh/go-spew/spew/spew.go                 Errorf                          100.00% (1/1)
+github.com/davecgh/go-spew/spew/spew.go                 Fprint                          100.00% (1/1)
+github.com/davecgh/go-spew/spew/spew.go                 Fprintf                         100.00% (1/1)
+github.com/davecgh/go-spew/spew/spew.go                 Print                           100.00% (1/1)
+github.com/davecgh/go-spew/spew                         ------------------------------- 100.00% (505/505)
+
diff --git a/vendor/github.com/git-lfs/gitobj/vendor/github.com/pmezard/go-difflib/.travis.yml b/vendor/github.com/git-lfs/gitobj/vendor/github.com/pmezard/go-difflib/.travis.yml
new file mode 100644 (file)
index 0000000..90c9c6f
--- /dev/null
@@ -0,0 +1,5 @@
+language: go
+go:
+  - 1.5
+  - tip
+
diff --git a/vendor/github.com/git-lfs/gitobj/vendor/github.com/pmezard/go-difflib/LICENSE b/vendor/github.com/git-lfs/gitobj/vendor/github.com/pmezard/go-difflib/LICENSE
new file mode 100644 (file)
index 0000000..c67dad6
--- /dev/null
@@ -0,0 +1,27 @@
+Copyright (c) 2013, Patrick Mezard
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+    Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+    Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+    The names of its contributors may not be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/vendor/github.com/git-lfs/gitobj/vendor/github.com/pmezard/go-difflib/README.md b/vendor/github.com/git-lfs/gitobj/vendor/github.com/pmezard/go-difflib/README.md
new file mode 100644 (file)
index 0000000..e87f307
--- /dev/null
@@ -0,0 +1,50 @@
+go-difflib
+==========
+
+[![Build Status](https://travis-ci.org/pmezard/go-difflib.png?branch=master)](https://travis-ci.org/pmezard/go-difflib)
+[![GoDoc](https://godoc.org/github.com/pmezard/go-difflib/difflib?status.svg)](https://godoc.org/github.com/pmezard/go-difflib/difflib)
+
+Go-difflib is a partial port of python 3 difflib package. Its main goal
+was to make unified and context diff available in pure Go, mostly for
+testing purposes.
+
+The following class and functions (and related tests) have be ported:
+
+* `SequenceMatcher`
+* `unified_diff()`
+* `context_diff()`
+
+## Installation
+
+```bash
+$ go get github.com/pmezard/go-difflib/difflib
+```
+
+### Quick Start
+
+Diffs are configured with Unified (or ContextDiff) structures, and can
+be output to an io.Writer or returned as a string.
+
+```Go
+diff := UnifiedDiff{
+    A:        difflib.SplitLines("foo\nbar\n"),
+    B:        difflib.SplitLines("foo\nbaz\n"),
+    FromFile: "Original",
+    ToFile:   "Current",
+    Context:  3,
+}
+text, _ := GetUnifiedDiffString(diff)
+fmt.Printf(text)
+```
+
+would output:
+
+```
+--- Original
++++ Current
+@@ -1,3 +1,3 @@
+ foo
+-bar
++baz
+```
+
diff --git a/vendor/github.com/git-lfs/gitobj/vendor/github.com/pmezard/go-difflib/difflib/difflib.go b/vendor/github.com/git-lfs/gitobj/vendor/github.com/pmezard/go-difflib/difflib/difflib.go
new file mode 100644 (file)
index 0000000..64cc40f
--- /dev/null
@@ -0,0 +1,758 @@
+// Package difflib is a partial port of Python difflib module.
+//
+// It provides tools to compare sequences of strings and generate textual diffs.
+//
+// The following class and functions have been ported:
+//
+// - SequenceMatcher
+//
+// - unified_diff
+//
+// - context_diff
+//
+// Getting unified diffs was the main goal of the port. Keep in mind this code
+// is mostly suitable to output text differences in a human friendly way, there
+// are no guarantees generated diffs are consumable by patch(1).
+package difflib
+
+import (
+       "bufio"
+       "bytes"
+       "fmt"
+       "io"
+       "strings"
+)
+
+func min(a, b int) int {
+       if a < b {
+               return a
+       }
+       return b
+}
+
+func max(a, b int) int {
+       if a > b {
+               return a
+       }
+       return b
+}
+
+func calculateRatio(matches, length int) float64 {
+       if length > 0 {
+               return 2.0 * float64(matches) / float64(length)
+       }
+       return 1.0
+}
+
+type Match struct {
+       A    int
+       B    int
+       Size int
+}
+
+type OpCode struct {
+       Tag byte
+       I1  int
+       I2  int
+       J1  int
+       J2  int
+}
+
+// SequenceMatcher compares sequence of strings. The basic
+// algorithm predates, and is a little fancier than, an algorithm
+// published in the late 1980's by Ratcliff and Obershelp under the
+// hyperbolic name "gestalt pattern matching".  The basic idea is to find
+// the longest contiguous matching subsequence that contains no "junk"
+// elements (R-O doesn't address junk).  The same idea is then applied
+// recursively to the pieces of the sequences to the left and to the right
+// of the matching subsequence.  This does not yield minimal edit
+// sequences, but does tend to yield matches that "look right" to people.
+//
+// SequenceMatcher tries to compute a "human-friendly diff" between two
+// sequences.  Unlike e.g. UNIX(tm) diff, the fundamental notion is the
+// longest *contiguous* & junk-free matching subsequence.  That's what
+// catches peoples' eyes.  The Windows(tm) windiff has another interesting
+// notion, pairing up elements that appear uniquely in each sequence.
+// That, and the method here, appear to yield more intuitive difference
+// reports than does diff.  This method appears to be the least vulnerable
+// to synching up on blocks of "junk lines", though (like blank lines in
+// ordinary text files, or maybe "<P>" lines in HTML files).  That may be
+// because this is the only method of the 3 that has a *concept* of
+// "junk" <wink>.
+//
+// Timing:  Basic R-O is cubic time worst case and quadratic time expected
+// case.  SequenceMatcher is quadratic time for the worst case and has
+// expected-case behavior dependent in a complicated way on how many
+// elements the sequences have in common; best case time is linear.
+type SequenceMatcher struct {
+       a              []string
+       b              []string
+       b2j            map[string][]int
+       IsJunk         func(string) bool
+       autoJunk       bool
+       bJunk          map[string]struct{}
+       matchingBlocks []Match
+       fullBCount     map[string]int
+       bPopular       map[string]struct{}
+       opCodes        []OpCode
+}
+
+func NewMatcher(a, b []string) *SequenceMatcher {
+       m := SequenceMatcher{autoJunk: true}
+       m.SetSeqs(a, b)
+       return &m
+}
+
+func NewMatcherWithJunk(a, b []string, autoJunk bool,
+       isJunk func(string) bool) *SequenceMatcher {
+
+       m := SequenceMatcher{IsJunk: isJunk, autoJunk: autoJunk}
+       m.SetSeqs(a, b)
+       return &m
+}
+
+// Set two sequences to be compared.
+func (m *SequenceMatcher) SetSeqs(a, b []string) {
+       m.SetSeq1(a)
+       m.SetSeq2(b)
+}
+
+// Set the first sequence to be compared. The second sequence to be compared is
+// not changed.
+//
+// SequenceMatcher computes and caches detailed information about the second
+// sequence, so if you want to compare one sequence S against many sequences,
+// use .SetSeq2(s) once and call .SetSeq1(x) repeatedly for each of the other
+// sequences.
+//
+// See also SetSeqs() and SetSeq2().
+func (m *SequenceMatcher) SetSeq1(a []string) {
+       if &a == &m.a {
+               return
+       }
+       m.a = a
+       m.matchingBlocks = nil
+       m.opCodes = nil
+}
+
+// Set the second sequence to be compared. The first sequence to be compared is
+// not changed.
+func (m *SequenceMatcher) SetSeq2(b []string) {
+       if &b == &m.b {
+               return
+       }
+       m.b = b
+       m.matchingBlocks = nil
+       m.opCodes = nil
+       m.fullBCount = nil
+       m.chainB()
+}
+
+func (m *SequenceMatcher) chainB() {
+       // Populate line -> index mapping
+       b2j := map[string][]int{}
+       for i, s := range m.b {
+               indices := b2j[s]
+               indices = append(indices, i)
+               b2j[s] = indices
+       }
+
+       // Purge junk elements
+       m.bJunk = map[string]struct{}{}
+       if m.IsJunk != nil {
+               junk := m.bJunk
+               for s, _ := range b2j {
+                       if m.IsJunk(s) {
+                               junk[s] = struct{}{}
+                       }
+               }
+               for s, _ := range junk {
+                       delete(b2j, s)
+               }
+       }
+
+       // Purge remaining popular elements
+       popular := map[string]struct{}{}
+       n := len(m.b)
+       if m.autoJunk && n >= 200 {
+               ntest := n/100 + 1
+               for s, indices := range b2j {
+                       if len(indices) > ntest {
+                               popular[s] = struct{}{}
+                       }
+               }
+               for s, _ := range popular {
+                       delete(b2j, s)
+               }
+       }
+       m.bPopular = popular
+       m.b2j = b2j
+}
+
+func (m *SequenceMatcher) isBJunk(s string) bool {
+       _, ok := m.bJunk[s]
+       return ok
+}
+
+// Find longest matching block in a[alo:ahi] and b[blo:bhi].
+//
+// If IsJunk is not defined:
+//
+// Return (i,j,k) such that a[i:i+k] is equal to b[j:j+k], where
+//     alo <= i <= i+k <= ahi
+//     blo <= j <= j+k <= bhi
+// and for all (i',j',k') meeting those conditions,
+//     k >= k'
+//     i <= i'
+//     and if i == i', j <= j'
+//
+// In other words, of all maximal matching blocks, return one that
+// starts earliest in a, and of all those maximal matching blocks that
+// start earliest in a, return the one that starts earliest in b.
+//
+// If IsJunk is defined, first the longest matching block is
+// determined as above, but with the additional restriction that no
+// junk element appears in the block.  Then that block is extended as
+// far as possible by matching (only) junk elements on both sides.  So
+// the resulting block never matches on junk except as identical junk
+// happens to be adjacent to an "interesting" match.
+//
+// If no blocks match, return (alo, blo, 0).
+func (m *SequenceMatcher) findLongestMatch(alo, ahi, blo, bhi int) Match {
+       // CAUTION:  stripping common prefix or suffix would be incorrect.
+       // E.g.,
+       //    ab
+       //    acab
+       // Longest matching block is "ab", but if common prefix is
+       // stripped, it's "a" (tied with "b").  UNIX(tm) diff does so
+       // strip, so ends up claiming that ab is changed to acab by
+       // inserting "ca" in the middle.  That's minimal but unintuitive:
+       // "it's obvious" that someone inserted "ac" at the front.
+       // Windiff ends up at the same place as diff, but by pairing up
+       // the unique 'b's and then matching the first two 'a's.
+       besti, bestj, bestsize := alo, blo, 0
+
+       // find longest junk-free match
+       // during an iteration of the loop, j2len[j] = length of longest
+       // junk-free match ending with a[i-1] and b[j]
+       j2len := map[int]int{}
+       for i := alo; i != ahi; i++ {
+               // look at all instances of a[i] in b; note that because
+               // b2j has no junk keys, the loop is skipped if a[i] is junk
+               newj2len := map[int]int{}
+               for _, j := range m.b2j[m.a[i]] {
+                       // a[i] matches b[j]
+                       if j < blo {
+                               continue
+                       }
+                       if j >= bhi {
+                               break
+                       }
+                       k := j2len[j-1] + 1
+                       newj2len[j] = k
+                       if k > bestsize {
+                               besti, bestj, bestsize = i-k+1, j-k+1, k
+                       }
+               }
+               j2len = newj2len
+       }
+
+       // Extend the best by non-junk elements on each end.  In particular,
+       // "popular" non-junk elements aren't in b2j, which greatly speeds
+       // the inner loop above, but also means "the best" match so far
+       // doesn't contain any junk *or* popular non-junk elements.
+       for besti > alo && bestj > blo && !m.isBJunk(m.b[bestj-1]) &&
+               m.a[besti-1] == m.b[bestj-1] {
+               besti, bestj, bestsize = besti-1, bestj-1, bestsize+1
+       }
+       for besti+bestsize < ahi && bestj+bestsize < bhi &&
+               !m.isBJunk(m.b[bestj+bestsize]) &&
+               m.a[besti+bestsize] == m.b[bestj+bestsize] {
+               bestsize += 1
+       }
+
+       // Now that we have a wholly interesting match (albeit possibly
+       // empty!), we may as well suck up the matching junk on each
+       // side of it too.  Can't think of a good reason not to, and it
+       // saves post-processing the (possibly considerable) expense of
+       // figuring out what to do with it.  In the case of an empty
+       // interesting match, this is clearly the right thing to do,
+       // because no other kind of match is possible in the regions.
+       for besti > alo && bestj > blo && m.isBJunk(m.b[bestj-1]) &&
+               m.a[besti-1] == m.b[bestj-1] {
+               besti, bestj, bestsize = besti-1, bestj-1, bestsize+1
+       }
+       for besti+bestsize < ahi && bestj+bestsize < bhi &&
+               m.isBJunk(m.b[bestj+bestsize]) &&
+               m.a[besti+bestsize] == m.b[bestj+bestsize] {
+               bestsize += 1
+       }
+
+       return Match{A: besti, B: bestj, Size: bestsize}
+}
+
+// Return list of triples describing matching subsequences.
+//
+// Each triple is of the form (i, j, n), and means that
+// a[i:i+n] == b[j:j+n].  The triples are monotonically increasing in
+// i and in j. It's also guaranteed that if (i, j, n) and (i', j', n') are
+// adjacent triples in the list, and the second is not the last triple in the
+// list, then i+n != i' or j+n != j'. IOW, adjacent triples never describe
+// adjacent equal blocks.
+//
+// The last triple is a dummy, (len(a), len(b), 0), and is the only
+// triple with n==0.
+func (m *SequenceMatcher) GetMatchingBlocks() []Match {
+       if m.matchingBlocks != nil {
+               return m.matchingBlocks
+       }
+
+       var matchBlocks func(alo, ahi, blo, bhi int, matched []Match) []Match
+       matchBlocks = func(alo, ahi, blo, bhi int, matched []Match) []Match {
+               match := m.findLongestMatch(alo, ahi, blo, bhi)
+               i, j, k := match.A, match.B, match.Size
+               if match.Size > 0 {
+                       if alo < i && blo < j {
+                               matched = matchBlocks(alo, i, blo, j, matched)
+                       }
+                       matched = append(matched, match)
+                       if i+k < ahi && j+k < bhi {
+                               matched = matchBlocks(i+k, ahi, j+k, bhi, matched)
+                       }
+               }
+               return matched
+       }
+       matched := matchBlocks(0, len(m.a), 0, len(m.b), nil)
+
+       // It's possible that we have adjacent equal blocks in the
+       // matching_blocks list now.
+       nonAdjacent := []Match{}
+       i1, j1, k1 := 0, 0, 0
+       for _, b := range matched {
+               // Is this block adjacent to i1, j1, k1?
+               i2, j2, k2 := b.A, b.B, b.Size
+               if i1+k1 == i2 && j1+k1 == j2 {
+                       // Yes, so collapse them -- this just increases the length of
+                       // the first block by the length of the second, and the first
+                       // block so lengthened remains the block to compare against.
+                       k1 += k2
+               } else {
+                       // Not adjacent.  Remember the first block (k1==0 means it's
+                       // the dummy we started with), and make the second block the
+                       // new block to compare against.
+                       if k1 > 0 {
+                               nonAdjacent = append(nonAdjacent, Match{i1, j1, k1})
+                       }
+                       i1, j1, k1 = i2, j2, k2
+               }
+       }
+       if k1 > 0 {
+               nonAdjacent = append(nonAdjacent, Match{i1, j1, k1})
+       }
+
+       nonAdjacent = append(nonAdjacent, Match{len(m.a), len(m.b), 0})
+       m.matchingBlocks = nonAdjacent
+       return m.matchingBlocks
+}
+
+// Return list of 5-tuples describing how to turn a into b.
+//
+// Each tuple is of the form (tag, i1, i2, j1, j2).  The first tuple
+// has i1 == j1 == 0, and remaining tuples have i1 == the i2 from the
+// tuple preceding it, and likewise for j1 == the previous j2.
+//
+// The tags are characters, with these meanings:
+//
+// 'r' (replace):  a[i1:i2] should be replaced by b[j1:j2]
+//
+// 'd' (delete):   a[i1:i2] should be deleted, j1==j2 in this case.
+//
+// 'i' (insert):   b[j1:j2] should be inserted at a[i1:i1], i1==i2 in this case.
+//
+// 'e' (equal):    a[i1:i2] == b[j1:j2]
+func (m *SequenceMatcher) GetOpCodes() []OpCode {
+       if m.opCodes != nil {
+               return m.opCodes
+       }
+       i, j := 0, 0
+       matching := m.GetMatchingBlocks()
+       opCodes := make([]OpCode, 0, len(matching))
+       for _, m := range matching {
+               //  invariant:  we've pumped out correct diffs to change
+               //  a[:i] into b[:j], and the next matching block is
+               //  a[ai:ai+size] == b[bj:bj+size]. So we need to pump
+               //  out a diff to change a[i:ai] into b[j:bj], pump out
+               //  the matching block, and move (i,j) beyond the match
+               ai, bj, size := m.A, m.B, m.Size
+               tag := byte(0)
+               if i < ai && j < bj {
+                       tag = 'r'
+               } else if i < ai {
+                       tag = 'd'
+               } else if j < bj {
+                       tag = 'i'
+               }
+               if tag > 0 {
+                       opCodes = append(opCodes, OpCode{tag, i, ai, j, bj})
+               }
+               i, j = ai+size, bj+size
+               // the list of matching blocks is terminated by a
+               // sentinel with size 0
+               if size > 0 {
+                       opCodes = append(opCodes, OpCode{'e', ai, i, bj, j})
+               }
+       }
+       m.opCodes = opCodes
+       return m.opCodes
+}
+
+// Isolate change clusters by eliminating ranges with no changes.
+//
+// Return a generator of groups with up to n lines of context.
+// Each group is in the same format as returned by GetOpCodes().
+func (m *SequenceMatcher) GetGroupedOpCodes(n int) [][]OpCode {
+       if n < 0 {
+               n = 3
+       }
+       codes := m.GetOpCodes()
+       if len(codes) == 0 {
+               codes = []OpCode{OpCode{'e', 0, 1, 0, 1}}
+       }
+       // Fixup leading and trailing groups if they show no changes.
+       if codes[0].Tag == 'e' {
+               c := codes[0]
+               i1, i2, j1, j2 := c.I1, c.I2, c.J1, c.J2
+               codes[0] = OpCode{c.Tag, max(i1, i2-n), i2, max(j1, j2-n), j2}
+       }
+       if codes[len(codes)-1].Tag == 'e' {
+               c := codes[len(codes)-1]
+               i1, i2, j1, j2 := c.I1, c.I2, c.J1, c.J2
+               codes[len(codes)-1] = OpCode{c.Tag, i1, min(i2, i1+n), j1, min(j2, j1+n)}
+       }
+       nn := n + n
+       groups := [][]OpCode{}
+       group := []OpCode{}
+       for _, c := range codes {
+               i1, i2, j1, j2 := c.I1, c.I2, c.J1, c.J2
+               // End the current group and start a new one whenever
+               // there is a large range with no changes.
+               if c.Tag == 'e' && i2-i1 > nn {
+                       group = append(group, OpCode{c.Tag, i1, min(i2, i1+n),
+                               j1, min(j2, j1+n)})
+                       groups = append(groups, group)
+                       group = []OpCode{}
+                       i1, j1 = max(i1, i2-n), max(j1, j2-n)
+               }
+               group = append(group, OpCode{c.Tag, i1, i2, j1, j2})
+       }
+       if len(group) > 0 && !(len(group) == 1 && group[0].Tag == 'e') {
+               groups = append(groups, group)
+       }
+       return groups
+}
+
+// Return a measure of the sequences' similarity (float in [0,1]).
+//
+// Where T is the total number of elements in both sequences, and
+// M is the number of matches, this is 2.0*M / T.
+// Note that this is 1 if the sequences are identical, and 0 if
+// they have nothing in common.
+//
+// .Ratio() is expensive to compute if you haven't already computed
+// .GetMatchingBlocks() or .GetOpCodes(), in which case you may
+// want to try .QuickRatio() or .RealQuickRation() first to get an
+// upper bound.
+func (m *SequenceMatcher) Ratio() float64 {
+       matches := 0
+       for _, m := range m.GetMatchingBlocks() {
+               matches += m.Size
+       }
+       return calculateRatio(matches, len(m.a)+len(m.b))
+}
+
+// Return an upper bound on ratio() relatively quickly.
+//
+// This isn't defined beyond that it is an upper bound on .Ratio(), and
+// is faster to compute.
+func (m *SequenceMatcher) QuickRatio() float64 {
+       // viewing a and b as multisets, set matches to the cardinality
+       // of their intersection; this counts the number of matches
+       // without regard to order, so is clearly an upper bound
+       if m.fullBCount == nil {
+               m.fullBCount = map[string]int{}
+               for _, s := range m.b {
+                       m.fullBCount[s] = m.fullBCount[s] + 1
+               }
+       }
+
+       // avail[x] is the number of times x appears in 'b' less the
+       // number of times we've seen it in 'a' so far ... kinda
+       avail := map[string]int{}
+       matches := 0
+       for _, s := range m.a {
+               n, ok := avail[s]
+               if !ok {
+                       n = m.fullBCount[s]
+               }
+               avail[s] = n - 1
+               if n > 0 {
+                       matches += 1
+               }
+       }
+       return calculateRatio(matches, len(m.a)+len(m.b))
+}
+
+// Return an upper bound on ratio() very quickly.
+//
+// This isn't defined beyond that it is an upper bound on .Ratio(), and
+// is faster to compute than either .Ratio() or .QuickRatio().
+func (m *SequenceMatcher) RealQuickRatio() float64 {
+       la, lb := len(m.a), len(m.b)
+       return calculateRatio(min(la, lb), la+lb)
+}
+
+// Convert range to the "ed" format
+func formatRangeUnified(start, stop int) string {
+       // Per the diff spec at http://www.unix.org/single_unix_specification/
+       beginning := start + 1 // lines start numbering with one
+       length := stop - start
+       if length == 1 {
+               return fmt.Sprintf("%d", beginning)
+       }
+       if length == 0 {
+               beginning -= 1 // empty ranges begin at line just before the range
+       }
+       return fmt.Sprintf("%d,%d", beginning, length)
+}
+
+// Unified diff parameters
+type UnifiedDiff struct {
+       A        []string // First sequence lines
+       FromFile string   // First file name
+       FromDate string   // First file time
+       B        []string // Second sequence lines
+       ToFile   string   // Second file name
+       ToDate   string   // Second file time
+       Eol      string   // Headers end of line, defaults to LF
+       Context  int      // Number of context lines
+}
+
+// Compare two sequences of lines; generate the delta as a unified diff.
+//
+// Unified diffs are a compact way of showing line changes and a few
+// lines of context.  The number of context lines is set by 'n' which
+// defaults to three.
+//
+// By default, the diff control lines (those with ---, +++, or @@) are
+// created with a trailing newline.  This is helpful so that inputs
+// created from file.readlines() result in diffs that are suitable for
+// file.writelines() since both the inputs and outputs have trailing
+// newlines.
+//
+// For inputs that do not have trailing newlines, set the lineterm
+// argument to "" so that the output will be uniformly newline free.
+//
+// The unidiff format normally has a header for filenames and modification
+// times.  Any or all of these may be specified using strings for
+// 'fromfile', 'tofile', 'fromfiledate', and 'tofiledate'.
+// The modification times are normally expressed in the ISO 8601 format.
+func WriteUnifiedDiff(writer io.Writer, diff UnifiedDiff) error {
+       buf := bufio.NewWriter(writer)
+       defer buf.Flush()
+       w := func(format string, args ...interface{}) error {
+               _, err := buf.WriteString(fmt.Sprintf(format, args...))
+               return err
+       }
+
+       if len(diff.Eol) == 0 {
+               diff.Eol = "\n"
+       }
+
+       started := false
+       m := NewMatcher(diff.A, diff.B)
+       for _, g := range m.GetGroupedOpCodes(diff.Context) {
+               if !started {
+                       started = true
+                       fromDate := ""
+                       if len(diff.FromDate) > 0 {
+                               fromDate = "\t" + diff.FromDate
+                       }
+                       toDate := ""
+                       if len(diff.ToDate) > 0 {
+                               toDate = "\t" + diff.ToDate
+                       }
+                       err := w("--- %s%s%s", diff.FromFile, fromDate, diff.Eol)
+                       if err != nil {
+                               return err
+                       }
+                       err = w("+++ %s%s%s", diff.ToFile, toDate, diff.Eol)
+                       if err != nil {
+                               return err
+                       }
+               }
+               first, last := g[0], g[len(g)-1]
+               range1 := formatRangeUnified(first.I1, last.I2)
+               range2 := formatRangeUnified(first.J1, last.J2)
+               if err := w("@@ -%s +%s @@%s", range1, range2, diff.Eol); err != nil {
+                       return err
+               }
+               for _, c := range g {
+                       i1, i2, j1, j2 := c.I1, c.I2, c.J1, c.J2
+                       if c.Tag == 'e' {
+                               for _, line := range diff.A[i1:i2] {
+                                       if err := w(" " + line); err != nil {
+                                               return err
+                                       }
+                               }
+                               continue
+                       }
+                       if c.Tag == 'r' || c.Tag == 'd' {
+                               for _, line := range diff.A[i1:i2] {
+                                       if err := w("-" + line); err != nil {
+                                               return err
+                                       }
+                               }
+                       }
+                       if c.Tag == 'r' || c.Tag == 'i' {
+                               for _, line := range diff.B[j1:j2] {
+                                       if err := w("+" + line); err != nil {
+                                               return err
+                                       }
+                               }
+                       }
+               }
+       }
+       return nil
+}
+
+// Like WriteUnifiedDiff but returns the diff a string.
+func GetUnifiedDiffString(diff UnifiedDiff) (string, error) {
+       w := &bytes.Buffer{}
+       err := WriteUnifiedDiff(w, diff)
+       return string(w.Bytes()), err
+}
+
+// Convert range to the "ed" format.
+func formatRangeContext(start, stop int) string {
+       // Per the diff spec at http://www.unix.org/single_unix_specification/
+       beginning := start + 1 // lines start numbering with one
+       length := stop - start
+       if length == 0 {
+               beginning -= 1 // empty ranges begin at line just before the range
+       }
+       if length <= 1 {
+               return fmt.Sprintf("%d", beginning)
+       }
+       return fmt.Sprintf("%d,%d", beginning, beginning+length-1)
+}
+
+type ContextDiff UnifiedDiff
+
+// Compare two sequences of lines; generate the delta as a context diff.
+//
+// Context diffs are a compact way of showing line changes and a few
+// lines of context. The number of context lines is set by diff.Context
+// which defaults to three.
+//
+// By default, the diff control lines (those with *** or ---) are
+// created with a trailing newline.
+//
+// For inputs that do not have trailing newlines, set the diff.Eol
+// argument to "" so that the output will be uniformly newline free.
+//
+// The context diff format normally has a header for filenames and
+// modification times.  Any or all of these may be specified using
+// strings for diff.FromFile, diff.ToFile, diff.FromDate, diff.ToDate.
+// The modification times are normally expressed in the ISO 8601 format.
+// If not specified, the strings default to blanks.
+func WriteContextDiff(writer io.Writer, diff ContextDiff) error {
+       buf := bufio.NewWriter(writer)
+       defer buf.Flush()
+       var diffErr error
+       w := func(format string, args ...interface{}) {
+               _, err := buf.WriteString(fmt.Sprintf(format, args...))
+               if diffErr == nil && err != nil {
+                       diffErr = err
+               }
+       }
+
+       if len(diff.Eol) == 0 {
+               diff.Eol = "\n"
+       }
+
+       prefix := map[byte]string{
+               'i': "+ ",
+               'd': "- ",
+               'r': "! ",
+               'e': "  ",
+       }
+
+       started := false
+       m := NewMatcher(diff.A, diff.B)
+       for _, g := range m.GetGroupedOpCodes(diff.Context) {
+               if !started {
+                       started = true
+                       fromDate := ""
+                       if len(diff.FromDate) > 0 {
+                               fromDate = "\t" + diff.FromDate
+                       }
+                       toDate := ""
+                       if len(diff.ToDate) > 0 {
+                               toDate = "\t" + diff.ToDate
+                       }
+                       w("*** %s%s%s", diff.FromFile, fromDate, diff.Eol)
+                       w("--- %s%s%s", diff.ToFile, toDate, diff.Eol)
+               }
+
+               first, last := g[0], g[len(g)-1]
+               w("***************" + diff.Eol)
+
+               range1 := formatRangeContext(first.I1, last.I2)
+               w("*** %s ****%s", range1, diff.Eol)
+               for _, c := range g {
+                       if c.Tag == 'r' || c.Tag == 'd' {
+                               for _, cc := range g {
+                                       if cc.Tag == 'i' {
+                                               continue
+                                       }
+                                       for _, line := range diff.A[cc.I1:cc.I2] {
+                                               w(prefix[cc.Tag] + line)
+                                       }
+                               }
+                               break
+                       }
+               }
+
+               range2 := formatRangeContext(first.J1, last.J2)
+               w("--- %s ----%s", range2, diff.Eol)
+               for _, c := range g {
+                       if c.Tag == 'r' || c.Tag == 'i' {
+                               for _, cc := range g {
+                                       if cc.Tag == 'd' {
+                                               continue
+                                       }
+                                       for _, line := range diff.B[cc.J1:cc.J2] {
+                                               w(prefix[cc.Tag] + line)
+                                       }
+                               }
+                               break
+                       }
+               }
+       }
+       return diffErr
+}
+
+// Like WriteContextDiff but returns the diff a string.
+func GetContextDiffString(diff ContextDiff) (string, error) {
+       w := &bytes.Buffer{}
+       err := WriteContextDiff(w, diff)
+       return string(w.Bytes()), err
+}
+
+// Split a string on "\n" while preserving them. The output can be used
+// as input for UnifiedDiff and ContextDiff structures.
+func SplitLines(s string) []string {
+       lines := strings.SplitAfter(s, "\n")
+       lines[len(lines)-1] += "\n"
+       return lines
+}
diff --git a/vendor/github.com/git-lfs/gitobj/vendor/github.com/pmezard/go-difflib/difflib/difflib_test.go b/vendor/github.com/git-lfs/gitobj/vendor/github.com/pmezard/go-difflib/difflib/difflib_test.go
new file mode 100644 (file)
index 0000000..94670be
--- /dev/null
@@ -0,0 +1,352 @@
+package difflib
+
+import (
+       "bytes"
+       "fmt"
+       "math"
+       "reflect"
+       "strings"
+       "testing"
+)
+
+func assertAlmostEqual(t *testing.T, a, b float64, places int) {
+       if math.Abs(a-b) > math.Pow10(-places) {
+               t.Errorf("%.7f != %.7f", a, b)
+       }
+}
+
+func assertEqual(t *testing.T, a, b interface{}) {
+       if !reflect.DeepEqual(a, b) {
+               t.Errorf("%v != %v", a, b)
+       }
+}
+
+func splitChars(s string) []string {
+       chars := make([]string, 0, len(s))
+       // Assume ASCII inputs
+       for i := 0; i != len(s); i++ {
+               chars = append(chars, string(s[i]))
+       }
+       return chars
+}
+
+func TestSequenceMatcherRatio(t *testing.T) {
+       s := NewMatcher(splitChars("abcd"), splitChars("bcde"))
+       assertEqual(t, s.Ratio(), 0.75)
+       assertEqual(t, s.QuickRatio(), 0.75)
+       assertEqual(t, s.RealQuickRatio(), 1.0)
+}
+
+func TestGetOptCodes(t *testing.T) {
+       a := "qabxcd"
+       b := "abycdf"
+       s := NewMatcher(splitChars(a), splitChars(b))
+       w := &bytes.Buffer{}
+       for _, op := range s.GetOpCodes() {
+               fmt.Fprintf(w, "%s a[%d:%d], (%s) b[%d:%d] (%s)\n", string(op.Tag),
+                       op.I1, op.I2, a[op.I1:op.I2], op.J1, op.J2, b[op.J1:op.J2])
+       }
+       result := string(w.Bytes())
+       expected := `d a[0:1], (q) b[0:0] ()
+e a[1:3], (ab) b[0:2] (ab)
+r a[3:4], (x) b[2:3] (y)
+e a[4:6], (cd) b[3:5] (cd)
+i a[6:6], () b[5:6] (f)
+`
+       if expected != result {
+               t.Errorf("unexpected op codes: \n%s", result)
+       }
+}
+
+func TestGroupedOpCodes(t *testing.T) {
+       a := []string{}
+       for i := 0; i != 39; i++ {
+               a = append(a, fmt.Sprintf("%02d", i))
+       }
+       b := []string{}
+       b = append(b, a[:8]...)
+       b = append(b, " i")
+       b = append(b, a[8:19]...)
+       b = append(b, " x")
+       b = append(b, a[20:22]...)
+       b = append(b, a[27:34]...)
+       b = append(b, " y")
+       b = append(b, a[35:]...)
+       s := NewMatcher(a, b)
+       w := &bytes.Buffer{}
+       for _, g := range s.GetGroupedOpCodes(-1) {
+               fmt.Fprintf(w, "group\n")
+               for _, op := range g {
+                       fmt.Fprintf(w, "  %s, %d, %d, %d, %d\n", string(op.Tag),
+                               op.I1, op.I2, op.J1, op.J2)
+               }
+       }
+       result := string(w.Bytes())
+       expected := `group
+  e, 5, 8, 5, 8
+  i, 8, 8, 8, 9
+  e, 8, 11, 9, 12
+group
+  e, 16, 19, 17, 20
+  r, 19, 20, 20, 21
+  e, 20, 22, 21, 23
+  d, 22, 27, 23, 23
+  e, 27, 30, 23, 26
+group
+  e, 31, 34, 27, 30
+  r, 34, 35, 30, 31
+  e, 35, 38, 31, 34
+`
+       if expected != result {
+               t.Errorf("unexpected op codes: \n%s", result)
+       }
+}
+
+func ExampleGetUnifiedDiffString() {
+       a := `one
+two
+three
+four`
+       b := `zero
+one
+three
+four`
+       diff := UnifiedDiff{
+               A:        SplitLines(a),
+               B:        SplitLines(b),
+               FromFile: "Original",
+               FromDate: "2005-01-26 23:30:50",
+               ToFile:   "Current",
+               ToDate:   "2010-04-02 10:20:52",
+               Context:  3,
+       }
+       result, _ := GetUnifiedDiffString(diff)
+       fmt.Printf(strings.Replace(result, "\t", " ", -1))
+       // Output:
+       // --- Original 2005-01-26 23:30:50
+       // +++ Current 2010-04-02 10:20:52
+       // @@ -1,4 +1,4 @@
+       // +zero
+       //  one
+       // -two
+       //  three
+       //  four
+}
+
+func ExampleGetContextDiffString() {
+       a := `one
+two
+three
+four`
+       b := `zero
+one
+tree
+four`
+       diff := ContextDiff{
+               A:        SplitLines(a),
+               B:        SplitLines(b),
+               FromFile: "Original",
+               ToFile:   "Current",
+               Context:  3,
+               Eol:      "\n",
+       }
+       result, _ := GetContextDiffString(diff)
+       fmt.Printf(strings.Replace(result, "\t", " ", -1))
+       // Output:
+       // *** Original
+       // --- Current
+       // ***************
+       // *** 1,4 ****
+       //   one
+       // ! two
+       // ! three
+       //   four
+       // --- 1,4 ----
+       // + zero
+       //   one
+       // ! tree
+       //   four
+}
+
+func rep(s string, count int) string {
+       return strings.Repeat(s, count)
+}
+
+func TestWithAsciiOneInsert(t *testing.T) {
+       sm := NewMatcher(splitChars(rep("b", 100)),
+               splitChars("a"+rep("b", 100)))
+       assertAlmostEqual(t, sm.Ratio(), 0.995, 3)
+       assertEqual(t, sm.GetOpCodes(),
+               []OpCode{{'i', 0, 0, 0, 1}, {'e', 0, 100, 1, 101}})
+       assertEqual(t, len(sm.bPopular), 0)
+
+       sm = NewMatcher(splitChars(rep("b", 100)),
+               splitChars(rep("b", 50)+"a"+rep("b", 50)))
+       assertAlmostEqual(t, sm.Ratio(), 0.995, 3)
+       assertEqual(t, sm.GetOpCodes(),
+               []OpCode{{'e', 0, 50, 0, 50}, {'i', 50, 50, 50, 51}, {'e', 50, 100, 51, 101}})
+       assertEqual(t, len(sm.bPopular), 0)
+}
+
+func TestWithAsciiOnDelete(t *testing.T) {
+       sm := NewMatcher(splitChars(rep("a", 40)+"c"+rep("b", 40)),
+               splitChars(rep("a", 40)+rep("b", 40)))
+       assertAlmostEqual(t, sm.Ratio(), 0.994, 3)
+       assertEqual(t, sm.GetOpCodes(),
+               []OpCode{{'e', 0, 40, 0, 40}, {'d', 40, 41, 40, 40}, {'e', 41, 81, 40, 80}})
+}
+
+func TestWithAsciiBJunk(t *testing.T) {
+       isJunk := func(s string) bool {
+               return s == " "
+       }
+       sm := NewMatcherWithJunk(splitChars(rep("a", 40)+rep("b", 40)),
+               splitChars(rep("a", 44)+rep("b", 40)), true, isJunk)
+       assertEqual(t, sm.bJunk, map[string]struct{}{})
+
+       sm = NewMatcherWithJunk(splitChars(rep("a", 40)+rep("b", 40)),
+               splitChars(rep("a", 44)+rep("b", 40)+rep(" ", 20)), false, isJunk)
+       assertEqual(t, sm.bJunk, map[string]struct{}{" ": struct{}{}})
+
+       isJunk = func(s string) bool {
+               return s == " " || s == "b"
+       }
+       sm = NewMatcherWithJunk(splitChars(rep("a", 40)+rep("b", 40)),
+               splitChars(rep("a", 44)+rep("b", 40)+rep(" ", 20)), false, isJunk)
+       assertEqual(t, sm.bJunk, map[string]struct{}{" ": struct{}{}, "b": struct{}{}})
+}
+
+func TestSFBugsRatioForNullSeqn(t *testing.T) {
+       sm := NewMatcher(nil, nil)
+       assertEqual(t, sm.Ratio(), 1.0)
+       assertEqual(t, sm.QuickRatio(), 1.0)
+       assertEqual(t, sm.RealQuickRatio(), 1.0)
+}
+
+func TestSFBugsComparingEmptyLists(t *testing.T) {
+       groups := NewMatcher(nil, nil).GetGroupedOpCodes(-1)
+       assertEqual(t, len(groups), 0)
+       diff := UnifiedDiff{
+               FromFile: "Original",
+               ToFile:   "Current",
+               Context:  3,
+       }
+       result, err := GetUnifiedDiffString(diff)
+       assertEqual(t, err, nil)
+       assertEqual(t, result, "")
+}
+
+func TestOutputFormatRangeFormatUnified(t *testing.T) {
+       // Per the diff spec at http://www.unix.org/single_unix_specification/
+       //
+       // Each <range> field shall be of the form:
+       //   %1d", <beginning line number>  if the range contains exactly one line,
+       // and:
+       //  "%1d,%1d", <beginning line number>, <number of lines> otherwise.
+       // If a range is empty, its beginning line number shall be the number of
+       // the line just before the range, or 0 if the empty range starts the file.
+       fm := formatRangeUnified
+       assertEqual(t, fm(3, 3), "3,0")
+       assertEqual(t, fm(3, 4), "4")
+       assertEqual(t, fm(3, 5), "4,2")
+       assertEqual(t, fm(3, 6), "4,3")
+       assertEqual(t, fm(0, 0), "0,0")
+}
+
+func TestOutputFormatRangeFormatContext(t *testing.T) {
+       // Per the diff spec at http://www.unix.org/single_unix_specification/
+       //
+       // The range of lines in file1 shall be written in the following format
+       // if the range contains two or more lines:
+       //     "*** %d,%d ****\n", <beginning line number>, <ending line number>
+       // and the following format otherwise:
+       //     "*** %d ****\n", <ending line number>
+       // The ending line number of an empty range shall be the number of the preceding line,
+       // or 0 if the range is at the start of the file.
+       //
+       // Next, the range of lines in file2 shall be written in the following format
+       // if the range contains two or more lines:
+       //     "--- %d,%d ----\n", <beginning line number>, <ending line number>
+       // and the following format otherwise:
+       //     "--- %d ----\n", <ending line number>
+       fm := formatRangeContext
+       assertEqual(t, fm(3, 3), "3")
+       assertEqual(t, fm(3, 4), "4")
+       assertEqual(t, fm(3, 5), "4,5")
+       assertEqual(t, fm(3, 6), "4,6")
+       assertEqual(t, fm(0, 0), "0")
+}
+
+func TestOutputFormatTabDelimiter(t *testing.T) {
+       diff := UnifiedDiff{
+               A:        splitChars("one"),
+               B:        splitChars("two"),
+               FromFile: "Original",
+               FromDate: "2005-01-26 23:30:50",
+               ToFile:   "Current",
+               ToDate:   "2010-04-12 10:20:52",
+               Eol:      "\n",
+       }
+       ud, err := GetUnifiedDiffString(diff)
+       assertEqual(t, err, nil)
+       assertEqual(t, SplitLines(ud)[:2], []string{
+               "--- Original\t2005-01-26 23:30:50\n",
+               "+++ Current\t2010-04-12 10:20:52\n",
+       })
+       cd, err := GetContextDiffString(ContextDiff(diff))
+       assertEqual(t, err, nil)
+       assertEqual(t, SplitLines(cd)[:2], []string{
+               "*** Original\t2005-01-26 23:30:50\n",
+               "--- Current\t2010-04-12 10:20:52\n",
+       })
+}
+
+func TestOutputFormatNoTrailingTabOnEmptyFiledate(t *testing.T) {
+       diff := UnifiedDiff{
+               A:        splitChars("one"),
+               B:        splitChars("two"),
+               FromFile: "Original",
+               ToFile:   "Current",
+               Eol:      "\n",
+       }
+       ud, err := GetUnifiedDiffString(diff)
+       assertEqual(t, err, nil)
+       assertEqual(t, SplitLines(ud)[:2], []string{"--- Original\n", "+++ Current\n"})
+
+       cd, err := GetContextDiffString(ContextDiff(diff))
+       assertEqual(t, err, nil)
+       assertEqual(t, SplitLines(cd)[:2], []string{"*** Original\n", "--- Current\n"})
+}
+
+func TestSplitLines(t *testing.T) {
+       allTests := []struct {
+               input string
+               want  []string
+       }{
+               {"foo", []string{"foo\n"}},
+               {"foo\nbar", []string{"foo\n", "bar\n"}},
+               {"foo\nbar\n", []string{"foo\n", "bar\n", "\n"}},
+       }
+       for _, test := range allTests {
+               assertEqual(t, SplitLines(test.input), test.want)
+       }
+}
+
+func benchmarkSplitLines(b *testing.B, count int) {
+       str := strings.Repeat("foo\n", count)
+
+       b.ResetTimer()
+
+       n := 0
+       for i := 0; i < b.N; i++ {
+               n += len(SplitLines(str))
+       }
+}
+
+func BenchmarkSplitLines100(b *testing.B) {
+       benchmarkSplitLines(b, 100)
+}
+
+func BenchmarkSplitLines10000(b *testing.B) {
+       benchmarkSplitLines(b, 10000)
+}
diff --git a/vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/.gitignore b/vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/.gitignore
new file mode 100644 (file)
index 0000000..5aacdb7
--- /dev/null
@@ -0,0 +1,24 @@
+# Compiled Object files, Static and Dynamic libs (Shared Objects)
+*.o
+*.a
+*.so
+
+# Folders
+_obj
+_test
+
+# Architecture specific extensions/prefixes
+*.[568vq]
+[568vq].out
+
+*.cgo1.go
+*.cgo2.c
+_cgo_defun.c
+_cgo_gotypes.go
+_cgo_export.*
+
+_testmain.go
+
+*.exe
+
+.DS_Store
diff --git a/vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/.travis.yml b/vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/.travis.yml
new file mode 100644 (file)
index 0000000..455923e
--- /dev/null
@@ -0,0 +1,15 @@
+language: go
+
+sudo: false
+
+go:
+  - 1.1
+  - 1.2
+  - 1.3
+  - 1.4
+  - 1.5
+  - 1.6
+  - tip
+
+script:
+  - go test -v ./...
diff --git a/vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/Godeps/Godeps.json b/vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/Godeps/Godeps.json
new file mode 100644 (file)
index 0000000..5069ce0
--- /dev/null
@@ -0,0 +1,21 @@
+{
+       "ImportPath": "github.com/stretchr/testify",
+       "GoVersion": "go1.5",
+       "Packages": [
+               "./..."
+       ],
+       "Deps": [
+               {
+                       "ImportPath": "github.com/davecgh/go-spew/spew",
+                       "Rev": "5215b55f46b2b919f50a1df0eaa5886afe4e3b3d"
+               },
+               {
+                       "ImportPath": "github.com/pmezard/go-difflib/difflib",
+                       "Rev": "d8ed2627bdf02c080bf22230dbb337003b7aba2d"
+               },
+               {
+                       "ImportPath": "github.com/stretchr/objx",
+                       "Rev": "cbeaeb16a013161a98496fad62933b1d21786672"
+               }
+       ]
+}
diff --git a/vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/Godeps/Readme b/vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/Godeps/Readme
new file mode 100644 (file)
index 0000000..4cdaa53
--- /dev/null
@@ -0,0 +1,5 @@
+This directory tree is generated automatically by godep.
+
+Please do not edit.
+
+See https://github.com/tools/godep for more information.
diff --git a/vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/LICENCE.txt b/vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/LICENCE.txt
new file mode 100644 (file)
index 0000000..473b670
--- /dev/null
@@ -0,0 +1,22 @@
+Copyright (c) 2012 - 2013 Mat Ryer and Tyler Bunnell
+
+Please consider promoting this project if you find it useful.
+
+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.
diff --git a/vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/LICENSE b/vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/LICENSE
new file mode 100644 (file)
index 0000000..473b670
--- /dev/null
@@ -0,0 +1,22 @@
+Copyright (c) 2012 - 2013 Mat Ryer and Tyler Bunnell
+
+Please consider promoting this project if you find it useful.
+
+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.
diff --git a/vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/README.md b/vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/README.md
new file mode 100644 (file)
index 0000000..aaf2aa0
--- /dev/null
@@ -0,0 +1,332 @@
+Testify - Thou Shalt Write Tests
+================================
+
+[![Build Status](https://travis-ci.org/stretchr/testify.svg)](https://travis-ci.org/stretchr/testify)
+
+Go code (golang) set of packages that provide many tools for testifying that your code will behave as you intend.
+
+Features include:
+
+  * [Easy assertions](#assert-package)
+  * [Mocking](#mock-package)
+  * [HTTP response trapping](#http-package)
+  * [Testing suite interfaces and functions](#suite-package)
+
+Get started:
+
+  * Install testify with [one line of code](#installation), or [update it with another](#staying-up-to-date)
+  * For an introduction to writing test code in Go, see http://golang.org/doc/code.html#Testing
+  * Check out the API Documentation http://godoc.org/github.com/stretchr/testify
+  * To make your testing life easier, check out our other project, [gorc](http://github.com/stretchr/gorc)
+  * A little about [Test-Driven Development (TDD)](http://en.wikipedia.org/wiki/Test-driven_development)
+
+
+
+[`assert`](http://godoc.org/github.com/stretchr/testify/assert "API documentation") package
+-------------------------------------------------------------------------------------------
+
+The `assert` package provides some helpful methods that allow you to write better test code in Go.
+
+  * Prints friendly, easy to read failure descriptions
+  * Allows for very readable code
+  * Optionally annotate each assertion with a message
+
+See it in action:
+
+```go
+package yours
+
+import (
+  "testing"
+  "github.com/stretchr/testify/assert"
+)
+
+func TestSomething(t *testing.T) {
+
+  // assert equality
+  assert.Equal(t, 123, 123, "they should be equal")
+
+  // assert inequality
+  assert.NotEqual(t, 123, 456, "they should not be equal")
+
+  // assert for nil (good for errors)
+  assert.Nil(t, object)
+
+  // assert for not nil (good when you expect something)
+  if assert.NotNil(t, object) {
+
+    // now we know that object isn't nil, we are safe to make
+    // further assertions without causing any errors
+    assert.Equal(t, "Something", object.Value)
+
+  }
+
+}
+```
+
+  * Every assert func takes the `testing.T` object as the first argument.  This is how it writes the errors out through the normal `go test` capabilities.
+  * Every assert func returns a bool indicating whether the assertion was successful or not, this is useful for if you want to go on making further assertions under certain conditions.
+
+if you assert many times, use the below:
+
+```go
+package yours
+
+import (
+  "testing"
+  "github.com/stretchr/testify/assert"
+)
+
+func TestSomething(t *testing.T) {
+  assert := assert.New(t)
+
+  // assert equality
+  assert.Equal(123, 123, "they should be equal")
+
+  // assert inequality
+  assert.NotEqual(123, 456, "they should not be equal")
+
+  // assert for nil (good for errors)
+  assert.Nil(object)
+
+  // assert for not nil (good when you expect something)
+  if assert.NotNil(object) {
+
+    // now we know that object isn't nil, we are safe to make
+    // further assertions without causing any errors
+    assert.Equal("Something", object.Value)
+  }
+}
+```
+
+[`require`](http://godoc.org/github.com/stretchr/testify/require "API documentation") package
+---------------------------------------------------------------------------------------------
+
+The `require` package provides same global functions as the `assert` package, but instead of returning a boolean result they terminate current test.
+
+See [t.FailNow](http://golang.org/pkg/testing/#T.FailNow) for details.
+
+
+[`http`](http://godoc.org/github.com/stretchr/testify/http "API documentation") package
+---------------------------------------------------------------------------------------
+
+The `http` package contains test objects useful for testing code that relies on the `net/http` package.  Check out the [(deprecated) API documentation for the `http` package](http://godoc.org/github.com/stretchr/testify/http).
+
+We recommend you use [httptest](http://golang.org/pkg/net/http/httptest) instead.
+
+[`mock`](http://godoc.org/github.com/stretchr/testify/mock "API documentation") package
+----------------------------------------------------------------------------------------
+
+The `mock` package provides a mechanism for easily writing mock objects that can be used in place of real objects when writing test code.
+
+An example test function that tests a piece of code that relies on an external object `testObj`, can setup expectations (testify) and assert that they indeed happened:
+
+```go
+package yours
+
+import (
+  "testing"
+  "github.com/stretchr/testify/mock"
+)
+
+/*
+  Test objects
+*/
+
+// MyMockedObject is a mocked object that implements an interface
+// that describes an object that the code I am testing relies on.
+type MyMockedObject struct{
+  mock.Mock
+}
+
+// DoSomething is a method on MyMockedObject that implements some interface
+// and just records the activity, and returns what the Mock object tells it to.
+//
+// In the real object, this method would do something useful, but since this
+// is a mocked object - we're just going to stub it out.
+//
+// NOTE: This method is not being tested here, code that uses this object is.
+func (m *MyMockedObject) DoSomething(number int) (bool, error) {
+
+  args := m.Called(number)
+  return args.Bool(0), args.Error(1)
+
+}
+
+/*
+  Actual test functions
+*/
+
+// TestSomething is an example of how to use our test object to
+// make assertions about some target code we are testing.
+func TestSomething(t *testing.T) {
+
+  // create an instance of our test object
+  testObj := new(MyMockedObject)
+
+  // setup expectations
+  testObj.On("DoSomething", 123).Return(true, nil)
+
+  // call the code we are testing
+  targetFuncThatDoesSomethingWithObj(testObj)
+
+  // assert that the expectations were met
+  testObj.AssertExpectations(t)
+
+}
+```
+
+For more information on how to write mock code, check out the [API documentation for the `mock` package](http://godoc.org/github.com/stretchr/testify/mock).
+
+You can use the [mockery tool](http://github.com/vektra/mockery) to autogenerate the mock code against an interface as well, making using mocks much quicker.
+
+[`suite`](http://godoc.org/github.com/stretchr/testify/suite "API documentation") package
+-----------------------------------------------------------------------------------------
+
+The `suite` package provides functionality that you might be used to from more common object oriented languages.  With it, you can build a testing suite as a struct, build setup/teardown methods and testing methods on your struct, and run them with 'go test' as per normal.
+
+An example suite is shown below:
+
+```go
+// Basic imports
+import (
+    "testing"
+    "github.com/stretchr/testify/assert"
+    "github.com/stretchr/testify/suite"
+)
+
+// Define the suite, and absorb the built-in basic suite
+// functionality from testify - including a T() method which
+// returns the current testing context
+type ExampleTestSuite struct {
+    suite.Suite
+    VariableThatShouldStartAtFive int
+}
+
+// Make sure that VariableThatShouldStartAtFive is set to five
+// before each test
+func (suite *ExampleTestSuite) SetupTest() {
+    suite.VariableThatShouldStartAtFive = 5
+}
+
+// All methods that begin with "Test" are run as tests within a
+// suite.
+func (suite *ExampleTestSuite) TestExample() {
+    assert.Equal(suite.T(), 5, suite.VariableThatShouldStartAtFive)
+}
+
+// In order for 'go test' to run this suite, we need to create
+// a normal test function and pass our suite to suite.Run
+func TestExampleTestSuite(t *testing.T) {
+    suite.Run(t, new(ExampleTestSuite))
+}
+```
+
+For a more complete example, using all of the functionality provided by the suite package, look at our [example testing suite](https://github.com/stretchr/testify/blob/master/suite/suite_test.go)
+
+For more information on writing suites, check out the [API documentation for the `suite` package](http://godoc.org/github.com/stretchr/testify/suite).
+
+`Suite` object has assertion methods:
+
+```go
+// Basic imports
+import (
+    "testing"
+    "github.com/stretchr/testify/suite"
+)
+
+// Define the suite, and absorb the built-in basic suite
+// functionality from testify - including assertion methods.
+type ExampleTestSuite struct {
+    suite.Suite
+    VariableThatShouldStartAtFive int
+}
+
+// Make sure that VariableThatShouldStartAtFive is set to five
+// before each test
+func (suite *ExampleTestSuite) SetupTest() {
+    suite.VariableThatShouldStartAtFive = 5
+}
+
+// All methods that begin with "Test" are run as tests within a
+// suite.
+func (suite *ExampleTestSuite) TestExample() {
+    suite.Equal(suite.VariableThatShouldStartAtFive, 5)
+}
+
+// In order for 'go test' to run this suite, we need to create
+// a normal test function and pass our suite to suite.Run
+func TestExampleTestSuite(t *testing.T) {
+    suite.Run(t, new(ExampleTestSuite))
+}
+```
+
+------
+
+Installation
+============
+
+To install Testify, use `go get`:
+
+    * Latest version: go get github.com/stretchr/testify
+    * Specific version: go get gopkg.in/stretchr/testify.v1
+
+This will then make the following packages available to you:
+
+    github.com/stretchr/testify/assert
+    github.com/stretchr/testify/mock
+    github.com/stretchr/testify/http
+
+Import the `testify/assert` package into your code using this template:
+
+```go
+package yours
+
+import (
+  "testing"
+  "github.com/stretchr/testify/assert"
+)
+
+func TestSomething(t *testing.T) {
+
+  assert.True(t, true, "True is true!")
+
+}
+```
+
+------
+
+Staying up to date
+==================
+
+To update Testify to the latest version, use `go get -u github.com/stretchr/testify`.
+
+------
+
+Version History
+===============
+
+   * 1.0 - New package versioning strategy adopted.
+
+------
+
+Contributing
+============
+
+Please feel free to submit issues, fork the repository and send pull requests!
+
+When submitting an issue, we ask that you please include a complete test function that demonstrates the issue.  Extra credit for those using Testify to write the test code that demonstrates it.
+
+------
+
+Licence
+=======
+Copyright (c) 2012 - 2013 Mat Ryer and Tyler Bunnell
+
+Please consider promoting this project if you find it useful.
+
+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.
diff --git a/vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/_codegen/main.go b/vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/_codegen/main.go
new file mode 100644 (file)
index 0000000..328009f
--- /dev/null
@@ -0,0 +1,287 @@
+// This program reads all assertion functions from the assert package and
+// automatically generates the corersponding requires and forwarded assertions
+
+package main
+
+import (
+       "bytes"
+       "flag"
+       "fmt"
+       "go/ast"
+       "go/build"
+       "go/doc"
+       "go/importer"
+       "go/parser"
+       "go/token"
+       "go/types"
+       "io"
+       "io/ioutil"
+       "log"
+       "os"
+       "path"
+       "strings"
+       "text/template"
+
+       "github.com/ernesto-jimenez/gogen/imports"
+)
+
+var (
+       pkg       = flag.String("assert-path", "github.com/stretchr/testify/assert", "Path to the assert package")
+       outputPkg = flag.String("output-package", "", "package for the resulting code")
+       tmplFile  = flag.String("template", "", "What file to load the function template from")
+       out       = flag.String("out", "", "What file to write the source code to")
+)
+
+func main() {
+       flag.Parse()
+
+       scope, docs, err := parsePackageSource(*pkg)
+       if err != nil {
+               log.Fatal(err)
+       }
+
+       importer, funcs, err := analyzeCode(scope, docs)
+       if err != nil {
+               log.Fatal(err)
+       }
+
+       if err := generateCode(importer, funcs); err != nil {
+               log.Fatal(err)
+       }
+}
+
+func generateCode(importer imports.Importer, funcs []testFunc) error {
+       buff := bytes.NewBuffer(nil)
+
+       tmplHead, tmplFunc, err := parseTemplates()
+       if err != nil {
+               return err
+       }
+
+       // Generate header
+       if err := tmplHead.Execute(buff, struct {
+               Name    string
+               Imports map[string]string
+       }{
+               *outputPkg,
+               importer.Imports(),
+       }); err != nil {
+               return err
+       }
+
+       // Generate funcs
+       for _, fn := range funcs {
+               buff.Write([]byte("\n\n"))
+               if err := tmplFunc.Execute(buff, &fn); err != nil {
+                       return err
+               }
+       }
+
+       // Write file
+       output, err := outputFile()
+       if err != nil {
+               return err
+       }
+       defer output.Close()
+       _, err = io.Copy(output, buff)
+       return err
+}
+
+func parseTemplates() (*template.Template, *template.Template, error) {
+       tmplHead, err := template.New("header").Parse(headerTemplate)
+       if err != nil {
+               return nil, nil, err
+       }
+       if *tmplFile != "" {
+               f, err := ioutil.ReadFile(*tmplFile)
+               if err != nil {
+                       return nil, nil, err
+               }
+               funcTemplate = string(f)
+       }
+       tmpl, err := template.New("function").Parse(funcTemplate)
+       if err != nil {
+               return nil, nil, err
+       }
+       return tmplHead, tmpl, nil
+}
+
+func outputFile() (*os.File, error) {
+       filename := *out
+       if filename == "-" || (filename == "" && *tmplFile == "") {
+               return os.Stdout, nil
+       }
+       if filename == "" {
+               filename = strings.TrimSuffix(strings.TrimSuffix(*tmplFile, ".tmpl"), ".go") + ".go"
+       }
+       return os.Create(filename)
+}
+
+// analyzeCode takes the types scope and the docs and returns the import
+// information and information about all the assertion functions.
+func analyzeCode(scope *types.Scope, docs *doc.Package) (imports.Importer, []testFunc, error) {
+       testingT := scope.Lookup("TestingT").Type().Underlying().(*types.Interface)
+
+       importer := imports.New(*outputPkg)
+       var funcs []testFunc
+       // Go through all the top level functions
+       for _, fdocs := range docs.Funcs {
+               // Find the function
+               obj := scope.Lookup(fdocs.Name)
+
+               fn, ok := obj.(*types.Func)
+               if !ok {
+                       continue
+               }
+               // Check function signatuer has at least two arguments
+               sig := fn.Type().(*types.Signature)
+               if sig.Params().Len() < 2 {
+                       continue
+               }
+               // Check first argument is of type testingT
+               first, ok := sig.Params().At(0).Type().(*types.Named)
+               if !ok {
+                       continue
+               }
+               firstType, ok := first.Underlying().(*types.Interface)
+               if !ok {
+                       continue
+               }
+               if !types.Implements(firstType, testingT) {
+                       continue
+               }
+
+               funcs = append(funcs, testFunc{*outputPkg, fdocs, fn})
+               importer.AddImportsFrom(sig.Params())
+       }
+       return importer, funcs, nil
+}
+
+// parsePackageSource returns the types scope and the package documentation from the pa
+func parsePackageSource(pkg string) (*types.Scope, *doc.Package, error) {
+       pd, err := build.Import(pkg, ".", 0)
+       if err != nil {
+               return nil, nil, err
+       }
+
+       fset := token.NewFileSet()
+       files := make(map[string]*ast.File)
+       fileList := make([]*ast.File, len(pd.GoFiles))
+       for i, fname := range pd.GoFiles {
+               src, err := ioutil.ReadFile(path.Join(pd.SrcRoot, pd.ImportPath, fname))
+               if err != nil {
+                       return nil, nil, err
+               }
+               f, err := parser.ParseFile(fset, fname, src, parser.ParseComments|parser.AllErrors)
+               if err != nil {
+                       return nil, nil, err
+               }
+               files[fname] = f
+               fileList[i] = f
+       }
+
+       cfg := types.Config{
+               Importer: importer.Default(),
+       }
+       info := types.Info{
+               Defs: make(map[*ast.Ident]types.Object),
+       }
+       tp, err := cfg.Check(pkg, fset, fileList, &info)
+       if err != nil {
+               return nil, nil, err
+       }
+
+       scope := tp.Scope()
+
+       ap, _ := ast.NewPackage(fset, files, nil, nil)
+       docs := doc.New(ap, pkg, 0)
+
+       return scope, docs, nil
+}
+
+type testFunc struct {
+       CurrentPkg string
+       DocInfo    *doc.Func
+       TypeInfo   *types.Func
+}
+
+func (f *testFunc) Qualifier(p *types.Package) string {
+       if p == nil || p.Name() == f.CurrentPkg {
+               return ""
+       }
+       return p.Name()
+}
+
+func (f *testFunc) Params() string {
+       sig := f.TypeInfo.Type().(*types.Signature)
+       params := sig.Params()
+       p := ""
+       comma := ""
+       to := params.Len()
+       var i int
+
+       if sig.Variadic() {
+               to--
+       }
+       for i = 1; i < to; i++ {
+               param := params.At(i)
+               p += fmt.Sprintf("%s%s %s", comma, param.Name(), types.TypeString(param.Type(), f.Qualifier))
+               comma = ", "
+       }
+       if sig.Variadic() {
+               param := params.At(params.Len() - 1)
+               p += fmt.Sprintf("%s%s ...%s", comma, param.Name(), types.TypeString(param.Type().(*types.Slice).Elem(), f.Qualifier))
+       }
+       return p
+}
+
+func (f *testFunc) ForwardedParams() string {
+       sig := f.TypeInfo.Type().(*types.Signature)
+       params := sig.Params()
+       p := ""
+       comma := ""
+       to := params.Len()
+       var i int
+
+       if sig.Variadic() {
+               to--
+       }
+       for i = 1; i < to; i++ {
+               param := params.At(i)
+               p += fmt.Sprintf("%s%s", comma, param.Name())
+               comma = ", "
+       }
+       if sig.Variadic() {
+               param := params.At(params.Len() - 1)
+               p += fmt.Sprintf("%s%s...", comma, param.Name())
+       }
+       return p
+}
+
+func (f *testFunc) Comment() string {
+       return "// " + strings.Replace(strings.TrimSpace(f.DocInfo.Doc), "\n", "\n// ", -1)
+}
+
+func (f *testFunc) CommentWithoutT(receiver string) string {
+       search := fmt.Sprintf("assert.%s(t, ", f.DocInfo.Name)
+       replace := fmt.Sprintf("%s.%s(", receiver, f.DocInfo.Name)
+       return strings.Replace(f.Comment(), search, replace, -1)
+}
+
+var headerTemplate = `/*
+* CODE GENERATED AUTOMATICALLY WITH github.com/stretchr/testify/_codegen
+* THIS FILE MUST NOT BE EDITED BY HAND
+*/
+
+package {{.Name}}
+
+import (
+{{range $path, $name := .Imports}}
+       {{$name}} "{{$path}}"{{end}}
+)
+`
+
+var funcTemplate = `{{.Comment}}
+func (fwd *AssertionsForwarder) {{.DocInfo.Name}}({{.Params}}) bool {
+       return assert.{{.DocInfo.Name}}({{.ForwardedParams}})
+}`
diff --git a/vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/assert/assertion_forward.go b/vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/assert/assertion_forward.go
new file mode 100644 (file)
index 0000000..e6a7960
--- /dev/null
@@ -0,0 +1,387 @@
+/*
+* CODE GENERATED AUTOMATICALLY WITH github.com/stretchr/testify/_codegen
+* THIS FILE MUST NOT BE EDITED BY HAND
+*/
+
+package assert
+
+import (
+
+       http "net/http"
+       url "net/url"
+       time "time"
+)
+
+
+// Condition uses a Comparison to assert a complex condition.
+func (a *Assertions) Condition(comp Comparison, msgAndArgs ...interface{}) bool {
+       return Condition(a.t, comp, msgAndArgs...)
+}
+
+
+// Contains asserts that the specified string, list(array, slice...) or map contains the
+// specified substring or element.
+// 
+//    a.Contains("Hello World", "World", "But 'Hello World' does contain 'World'")
+//    a.Contains(["Hello", "World"], "World", "But ["Hello", "World"] does contain 'World'")
+//    a.Contains({"Hello": "World"}, "Hello", "But {'Hello': 'World'} does contain 'Hello'")
+// 
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) Contains(s interface{}, contains interface{}, msgAndArgs ...interface{}) bool {
+       return Contains(a.t, s, contains, msgAndArgs...)
+}
+
+
+// Empty asserts that the specified object is empty.  I.e. nil, "", false, 0 or either
+// a slice or a channel with len == 0.
+// 
+//  a.Empty(obj)
+// 
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) Empty(object interface{}, msgAndArgs ...interface{}) bool {
+       return Empty(a.t, object, msgAndArgs...)
+}
+
+
+// Equal asserts that two objects are equal.
+// 
+//    a.Equal(123, 123, "123 and 123 should be equal")
+// 
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) Equal(expected interface{}, actual interface{}, msgAndArgs ...interface{}) bool {
+       return Equal(a.t, expected, actual, msgAndArgs...)
+}
+
+
+// EqualError asserts that a function returned an error (i.e. not `nil`)
+// and that it is equal to the provided error.
+// 
+//   actualObj, err := SomeFunction()
+//   if assert.Error(t, err, "An error was expected") {
+//        assert.Equal(t, err, expectedError)
+//   }
+// 
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) EqualError(theError error, errString string, msgAndArgs ...interface{}) bool {
+       return EqualError(a.t, theError, errString, msgAndArgs...)
+}
+
+
+// EqualValues asserts that two objects are equal or convertable to the same types
+// and equal.
+// 
+//    a.EqualValues(uint32(123), int32(123), "123 and 123 should be equal")
+// 
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) EqualValues(expected interface{}, actual interface{}, msgAndArgs ...interface{}) bool {
+       return EqualValues(a.t, expected, actual, msgAndArgs...)
+}
+
+
+// Error asserts that a function returned an error (i.e. not `nil`).
+// 
+//   actualObj, err := SomeFunction()
+//   if a.Error(err, "An error was expected") {
+//        assert.Equal(t, err, expectedError)
+//   }
+// 
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) Error(err error, msgAndArgs ...interface{}) bool {
+       return Error(a.t, err, msgAndArgs...)
+}
+
+
+// Exactly asserts that two objects are equal is value and type.
+// 
+//    a.Exactly(int32(123), int64(123), "123 and 123 should NOT be equal")
+// 
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) Exactly(expected interface{}, actual interface{}, msgAndArgs ...interface{}) bool {
+       return Exactly(a.t, expected, actual, msgAndArgs...)
+}
+
+
+// Fail reports a failure through
+func (a *Assertions) Fail(failureMessage string, msgAndArgs ...interface{}) bool {
+       return Fail(a.t, failureMessage, msgAndArgs...)
+}
+
+
+// FailNow fails test
+func (a *Assertions) FailNow(failureMessage string, msgAndArgs ...interface{}) bool {
+       return FailNow(a.t, failureMessage, msgAndArgs...)
+}
+
+
+// False asserts that the specified value is false.
+// 
+//    a.False(myBool, "myBool should be false")
+// 
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) False(value bool, msgAndArgs ...interface{}) bool {
+       return False(a.t, value, msgAndArgs...)
+}
+
+
+// HTTPBodyContains asserts that a specified handler returns a
+// body that contains a string.
+// 
+//  a.HTTPBodyContains(myHandler, "www.google.com", nil, "I'm Feeling Lucky")
+// 
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) HTTPBodyContains(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}) bool {
+       return HTTPBodyContains(a.t, handler, method, url, values, str)
+}
+
+
+// HTTPBodyNotContains asserts that a specified handler returns a
+// body that does not contain a string.
+// 
+//  a.HTTPBodyNotContains(myHandler, "www.google.com", nil, "I'm Feeling Lucky")
+// 
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) HTTPBodyNotContains(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}) bool {
+       return HTTPBodyNotContains(a.t, handler, method, url, values, str)
+}
+
+
+// HTTPError asserts that a specified handler returns an error status code.
+// 
+//  a.HTTPError(myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}}
+// 
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) HTTPError(handler http.HandlerFunc, method string, url string, values url.Values) bool {
+       return HTTPError(a.t, handler, method, url, values)
+}
+
+
+// HTTPRedirect asserts that a specified handler returns a redirect status code.
+// 
+//  a.HTTPRedirect(myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}}
+// 
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) HTTPRedirect(handler http.HandlerFunc, method string, url string, values url.Values) bool {
+       return HTTPRedirect(a.t, handler, method, url, values)
+}
+
+
+// HTTPSuccess asserts that a specified handler returns a success status code.
+// 
+//  a.HTTPSuccess(myHandler, "POST", "http://www.google.com", nil)
+// 
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) HTTPSuccess(handler http.HandlerFunc, method string, url string, values url.Values) bool {
+       return HTTPSuccess(a.t, handler, method, url, values)
+}
+
+
+// Implements asserts that an object is implemented by the specified interface.
+// 
+//    a.Implements((*MyInterface)(nil), new(MyObject), "MyObject")
+func (a *Assertions) Implements(interfaceObject interface{}, object interface{}, msgAndArgs ...interface{}) bool {
+       return Implements(a.t, interfaceObject, object, msgAndArgs...)
+}
+
+
+// InDelta asserts that the two numerals are within delta of each other.
+// 
+//      a.InDelta(math.Pi, (22 / 7.0), 0.01)
+// 
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) InDelta(expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) bool {
+       return InDelta(a.t, expected, actual, delta, msgAndArgs...)
+}
+
+
+// InDeltaSlice is the same as InDelta, except it compares two slices.
+func (a *Assertions) InDeltaSlice(expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) bool {
+       return InDeltaSlice(a.t, expected, actual, delta, msgAndArgs...)
+}
+
+
+// InEpsilon asserts that expected and actual have a relative error less than epsilon
+// 
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) InEpsilon(expected interface{}, actual interface{}, epsilon float64, msgAndArgs ...interface{}) bool {
+       return InEpsilon(a.t, expected, actual, epsilon, msgAndArgs...)
+}
+
+
+// InEpsilonSlice is the same as InEpsilon, except it compares two slices.
+func (a *Assertions) InEpsilonSlice(expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) bool {
+       return InEpsilonSlice(a.t, expected, actual, delta, msgAndArgs...)
+}
+
+
+// IsType asserts that the specified objects are of the same type.
+func (a *Assertions) IsType(expectedType interface{}, object interface{}, msgAndArgs ...interface{}) bool {
+       return IsType(a.t, expectedType, object, msgAndArgs...)
+}
+
+
+// JSONEq asserts that two JSON strings are equivalent.
+// 
+//  a.JSONEq(`{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`)
+// 
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) JSONEq(expected string, actual string, msgAndArgs ...interface{}) bool {
+       return JSONEq(a.t, expected, actual, msgAndArgs...)
+}
+
+
+// Len asserts that the specified object has specific length.
+// Len also fails if the object has a type that len() not accept.
+// 
+//    a.Len(mySlice, 3, "The size of slice is not 3")
+// 
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) Len(object interface{}, length int, msgAndArgs ...interface{}) bool {
+       return Len(a.t, object, length, msgAndArgs...)
+}
+
+
+// Nil asserts that the specified object is nil.
+// 
+//    a.Nil(err, "err should be nothing")
+// 
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) Nil(object interface{}, msgAndArgs ...interface{}) bool {
+       return Nil(a.t, object, msgAndArgs...)
+}
+
+
+// NoError asserts that a function returned no error (i.e. `nil`).
+// 
+//   actualObj, err := SomeFunction()
+//   if a.NoError(err) {
+//        assert.Equal(t, actualObj, expectedObj)
+//   }
+// 
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) NoError(err error, msgAndArgs ...interface{}) bool {
+       return NoError(a.t, err, msgAndArgs...)
+}
+
+
+// NotContains asserts that the specified string, list(array, slice...) or map does NOT contain the
+// specified substring or element.
+// 
+//    a.NotContains("Hello World", "Earth", "But 'Hello World' does NOT contain 'Earth'")
+//    a.NotContains(["Hello", "World"], "Earth", "But ['Hello', 'World'] does NOT contain 'Earth'")
+//    a.NotContains({"Hello": "World"}, "Earth", "But {'Hello': 'World'} does NOT contain 'Earth'")
+// 
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) NotContains(s interface{}, contains interface{}, msgAndArgs ...interface{}) bool {
+       return NotContains(a.t, s, contains, msgAndArgs...)
+}
+
+
+// NotEmpty asserts that the specified object is NOT empty.  I.e. not nil, "", false, 0 or either
+// a slice or a channel with len == 0.
+// 
+//  if a.NotEmpty(obj) {
+//    assert.Equal(t, "two", obj[1])
+//  }
+// 
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) NotEmpty(object interface{}, msgAndArgs ...interface{}) bool {
+       return NotEmpty(a.t, object, msgAndArgs...)
+}
+
+
+// NotEqual asserts that the specified values are NOT equal.
+// 
+//    a.NotEqual(obj1, obj2, "two objects shouldn't be equal")
+// 
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) NotEqual(expected interface{}, actual interface{}, msgAndArgs ...interface{}) bool {
+       return NotEqual(a.t, expected, actual, msgAndArgs...)
+}
+
+
+// NotNil asserts that the specified object is not nil.
+// 
+//    a.NotNil(err, "err should be something")
+// 
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) NotNil(object interface{}, msgAndArgs ...interface{}) bool {
+       return NotNil(a.t, object, msgAndArgs...)
+}
+
+
+// NotPanics asserts that the code inside the specified PanicTestFunc does NOT panic.
+// 
+//   a.NotPanics(func(){
+//     RemainCalm()
+//   }, "Calling RemainCalm() should NOT panic")
+// 
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) NotPanics(f PanicTestFunc, msgAndArgs ...interface{}) bool {
+       return NotPanics(a.t, f, msgAndArgs...)
+}
+
+
+// NotRegexp asserts that a specified regexp does not match a string.
+// 
+//  a.NotRegexp(regexp.MustCompile("starts"), "it's starting")
+//  a.NotRegexp("^start", "it's not starting")
+// 
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) NotRegexp(rx interface{}, str interface{}, msgAndArgs ...interface{}) bool {
+       return NotRegexp(a.t, rx, str, msgAndArgs...)
+}
+
+
+// NotZero asserts that i is not the zero value for its type and returns the truth.
+func (a *Assertions) NotZero(i interface{}, msgAndArgs ...interface{}) bool {
+       return NotZero(a.t, i, msgAndArgs...)
+}
+
+
+// Panics asserts that the code inside the specified PanicTestFunc panics.
+// 
+//   a.Panics(func(){
+//     GoCrazy()
+//   }, "Calling GoCrazy() should panic")
+// 
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) Panics(f PanicTestFunc, msgAndArgs ...interface{}) bool {
+       return Panics(a.t, f, msgAndArgs...)
+}
+
+
+// Regexp asserts that a specified regexp matches a string.
+// 
+//  a.Regexp(regexp.MustCompile("start"), "it's starting")
+//  a.Regexp("start...$", "it's not starting")
+// 
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) Regexp(rx interface{}, str interface{}, msgAndArgs ...interface{}) bool {
+       return Regexp(a.t, rx, str, msgAndArgs...)
+}
+
+
+// True asserts that the specified value is true.
+// 
+//    a.True(myBool, "myBool should be true")
+// 
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) True(value bool, msgAndArgs ...interface{}) bool {
+       return True(a.t, value, msgAndArgs...)
+}
+
+
+// WithinDuration asserts that the two times are within duration delta of each other.
+// 
+//   a.WithinDuration(time.Now(), time.Now(), 10*time.Second, "The difference should not be more than 10s")
+// 
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) WithinDuration(expected time.Time, actual time.Time, delta time.Duration, msgAndArgs ...interface{}) bool {
+       return WithinDuration(a.t, expected, actual, delta, msgAndArgs...)
+}
+
+
+// Zero asserts that i is the zero value for its type and returns the truth.
+func (a *Assertions) Zero(i interface{}, msgAndArgs ...interface{}) bool {
+       return Zero(a.t, i, msgAndArgs...)
+}
diff --git a/vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/assert/assertion_forward.go.tmpl b/vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/assert/assertion_forward.go.tmpl
new file mode 100644 (file)
index 0000000..99f9acf
--- /dev/null
@@ -0,0 +1,4 @@
+{{.CommentWithoutT "a"}}
+func (a *Assertions) {{.DocInfo.Name}}({{.Params}}) bool {
+       return {{.DocInfo.Name}}(a.t, {{.ForwardedParams}})
+}
diff --git a/vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/assert/assertions.go b/vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/assert/assertions.go
new file mode 100644 (file)
index 0000000..d7c16c5
--- /dev/null
@@ -0,0 +1,1004 @@
+package assert
+
+import (
+       "bufio"
+       "bytes"
+       "encoding/json"
+       "fmt"
+       "math"
+       "reflect"
+       "regexp"
+       "runtime"
+       "strings"
+       "time"
+       "unicode"
+       "unicode/utf8"
+
+       "github.com/davecgh/go-spew/spew"
+       "github.com/pmezard/go-difflib/difflib"
+)
+
+// TestingT is an interface wrapper around *testing.T
+type TestingT interface {
+       Errorf(format string, args ...interface{})
+}
+
+// Comparison a custom function that returns true on success and false on failure
+type Comparison func() (success bool)
+
+/*
+       Helper functions
+*/
+
+// ObjectsAreEqual determines if two objects are considered equal.
+//
+// This function does no assertion of any kind.
+func ObjectsAreEqual(expected, actual interface{}) bool {
+
+       if expected == nil || actual == nil {
+               return expected == actual
+       }
+
+       return reflect.DeepEqual(expected, actual)
+
+}
+
+// ObjectsAreEqualValues gets whether two objects are equal, or if their
+// values are equal.
+func ObjectsAreEqualValues(expected, actual interface{}) bool {
+       if ObjectsAreEqual(expected, actual) {
+               return true
+       }
+
+       actualType := reflect.TypeOf(actual)
+       if actualType == nil {
+               return false
+       }
+       expectedValue := reflect.ValueOf(expected)
+       if expectedValue.IsValid() && expectedValue.Type().ConvertibleTo(actualType) {
+               // Attempt comparison after type conversion
+               return reflect.DeepEqual(expectedValue.Convert(actualType).Interface(), actual)
+       }
+
+       return false
+}
+
+/* CallerInfo is necessary because the assert functions use the testing object
+internally, causing it to print the file:line of the assert method, rather than where
+the problem actually occured in calling code.*/
+
+// CallerInfo returns an array of strings containing the file and line number
+// of each stack frame leading from the current test to the assert call that
+// failed.
+func CallerInfo() []string {
+
+       pc := uintptr(0)
+       file := ""
+       line := 0
+       ok := false
+       name := ""
+
+       callers := []string{}
+       for i := 0; ; i++ {
+               pc, file, line, ok = runtime.Caller(i)
+               if !ok {
+                       return nil
+               }
+
+               // This is a huge edge case, but it will panic if this is the case, see #180
+               if file == "<autogenerated>" {
+                       break
+               }
+
+               parts := strings.Split(file, "/")
+               dir := parts[len(parts)-2]
+               file = parts[len(parts)-1]
+               if (dir != "assert" && dir != "mock" && dir != "require") || file == "mock_test.go" {
+                       callers = append(callers, fmt.Sprintf("%s:%d", file, line))
+               }
+
+               f := runtime.FuncForPC(pc)
+               if f == nil {
+                       break
+               }
+               name = f.Name()
+               // Drop the package
+               segments := strings.Split(name, ".")
+               name = segments[len(segments)-1]
+               if isTest(name, "Test") ||
+                       isTest(name, "Benchmark") ||
+                       isTest(name, "Example") {
+                       break
+               }
+       }
+
+       return callers
+}
+
+// Stolen from the `go test` tool.
+// isTest tells whether name looks like a test (or benchmark, according to prefix).
+// It is a Test (say) if there is a character after Test that is not a lower-case letter.
+// We don't want TesticularCancer.
+func isTest(name, prefix string) bool {
+       if !strings.HasPrefix(name, prefix) {
+               return false
+       }
+       if len(name) == len(prefix) { // "Test" is ok
+               return true
+       }
+       rune, _ := utf8.DecodeRuneInString(name[len(prefix):])
+       return !unicode.IsLower(rune)
+}
+
+// getWhitespaceString returns a string that is long enough to overwrite the default
+// output from the go testing framework.
+func getWhitespaceString() string {
+
+       _, file, line, ok := runtime.Caller(1)
+       if !ok {
+               return ""
+       }
+       parts := strings.Split(file, "/")
+       file = parts[len(parts)-1]
+
+       return strings.Repeat(" ", len(fmt.Sprintf("%s:%d:      ", file, line)))
+
+}
+
+func messageFromMsgAndArgs(msgAndArgs ...interface{}) string {
+       if len(msgAndArgs) == 0 || msgAndArgs == nil {
+               return ""
+       }
+       if len(msgAndArgs) == 1 {
+               return msgAndArgs[0].(string)
+       }
+       if len(msgAndArgs) > 1 {
+               return fmt.Sprintf(msgAndArgs[0].(string), msgAndArgs[1:]...)
+       }
+       return ""
+}
+
+// Indents all lines of the message by appending a number of tabs to each line, in an output format compatible with Go's
+// test printing (see inner comment for specifics)
+func indentMessageLines(message string, tabs int) string {
+       outBuf := new(bytes.Buffer)
+
+       for i, scanner := 0, bufio.NewScanner(strings.NewReader(message)); scanner.Scan(); i++ {
+               if i != 0 {
+                       outBuf.WriteRune('\n')
+               }
+               for ii := 0; ii < tabs; ii++ {
+                       outBuf.WriteRune('\t')
+                       // Bizarrely, all lines except the first need one fewer tabs prepended, so deliberately advance the counter
+                       // by 1 prematurely.
+                       if ii == 0 && i > 0 {
+                               ii++
+                       }
+               }
+               outBuf.WriteString(scanner.Text())
+       }
+
+       return outBuf.String()
+}
+
+type failNower interface {
+       FailNow()
+}
+
+// FailNow fails test
+func FailNow(t TestingT, failureMessage string, msgAndArgs ...interface{}) bool {
+       Fail(t, failureMessage, msgAndArgs...)
+
+       // We cannot extend TestingT with FailNow() and
+       // maintain backwards compatibility, so we fallback
+       // to panicking when FailNow is not available in
+       // TestingT.
+       // See issue #263
+
+       if t, ok := t.(failNower); ok {
+               t.FailNow()
+       } else {
+               panic("test failed and t is missing `FailNow()`")
+       }
+       return false
+}
+
+// Fail reports a failure through
+func Fail(t TestingT, failureMessage string, msgAndArgs ...interface{}) bool {
+
+       message := messageFromMsgAndArgs(msgAndArgs...)
+
+       errorTrace := strings.Join(CallerInfo(), "\n\r\t\t\t")
+       if len(message) > 0 {
+               t.Errorf("\r%s\r\tError Trace:\t%s\n"+
+                       "\r\tError:%s\n"+
+                       "\r\tMessages:\t%s\n\r",
+                       getWhitespaceString(),
+                       errorTrace,
+                       indentMessageLines(failureMessage, 2),
+                       message)
+       } else {
+               t.Errorf("\r%s\r\tError Trace:\t%s\n"+
+                       "\r\tError:%s\n\r",
+                       getWhitespaceString(),
+                       errorTrace,
+                       indentMessageLines(failureMessage, 2))
+       }
+
+       return false
+}
+
+// Implements asserts that an object is implemented by the specified interface.
+//
+//    assert.Implements(t, (*MyInterface)(nil), new(MyObject), "MyObject")
+func Implements(t TestingT, interfaceObject interface{}, object interface{}, msgAndArgs ...interface{}) bool {
+
+       interfaceType := reflect.TypeOf(interfaceObject).Elem()
+
+       if !reflect.TypeOf(object).Implements(interfaceType) {
+               return Fail(t, fmt.Sprintf("%T must implement %v", object, interfaceType), msgAndArgs...)
+       }
+
+       return true
+
+}
+
+// IsType asserts that the specified objects are of the same type.
+func IsType(t TestingT, expectedType interface{}, object interface{}, msgAndArgs ...interface{}) bool {
+
+       if !ObjectsAreEqual(reflect.TypeOf(object), reflect.TypeOf(expectedType)) {
+               return Fail(t, fmt.Sprintf("Object expected to be of type %v, but was %v", reflect.TypeOf(expectedType), reflect.TypeOf(object)), msgAndArgs...)
+       }
+
+       return true
+}
+
+// Equal asserts that two objects are equal.
+//
+//    assert.Equal(t, 123, 123, "123 and 123 should be equal")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func Equal(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool {
+
+       if !ObjectsAreEqual(expected, actual) {
+               diff := diff(expected, actual)
+               return Fail(t, fmt.Sprintf("Not equal: %#v (expected)\n"+
+                       "        != %#v (actual)%s", expected, actual, diff), msgAndArgs...)
+       }
+
+       return true
+
+}
+
+// EqualValues asserts that two objects are equal or convertable to the same types
+// and equal.
+//
+//    assert.EqualValues(t, uint32(123), int32(123), "123 and 123 should be equal")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func EqualValues(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool {
+
+       if !ObjectsAreEqualValues(expected, actual) {
+               return Fail(t, fmt.Sprintf("Not equal: %#v (expected)\n"+
+                       "        != %#v (actual)", expected, actual), msgAndArgs...)
+       }
+
+       return true
+
+}
+
+// Exactly asserts that two objects are equal is value and type.
+//
+//    assert.Exactly(t, int32(123), int64(123), "123 and 123 should NOT be equal")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func Exactly(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool {
+
+       aType := reflect.TypeOf(expected)
+       bType := reflect.TypeOf(actual)
+
+       if aType != bType {
+               return Fail(t, fmt.Sprintf("Types expected to match exactly\n\r\t%v != %v", aType, bType), msgAndArgs...)
+       }
+
+       return Equal(t, expected, actual, msgAndArgs...)
+
+}
+
+// NotNil asserts that the specified object is not nil.
+//
+//    assert.NotNil(t, err, "err should be something")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func NotNil(t TestingT, object interface{}, msgAndArgs ...interface{}) bool {
+       if !isNil(object) {
+               return true
+       }
+       return Fail(t, "Expected value not to be nil.", msgAndArgs...)
+}
+
+// isNil checks if a specified object is nil or not, without Failing.
+func isNil(object interface{}) bool {
+       if object == nil {
+               return true
+       }
+
+       value := reflect.ValueOf(object)
+       kind := value.Kind()
+       if kind >= reflect.Chan && kind <= reflect.Slice && value.IsNil() {
+               return true
+       }
+
+       return false
+}
+
+// Nil asserts that the specified object is nil.
+//
+//    assert.Nil(t, err, "err should be nothing")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func Nil(t TestingT, object interface{}, msgAndArgs ...interface{}) bool {
+       if isNil(object) {
+               return true
+       }
+       return Fail(t, fmt.Sprintf("Expected nil, but got: %#v", object), msgAndArgs...)
+}
+
+var numericZeros = []interface{}{
+       int(0),
+       int8(0),
+       int16(0),
+       int32(0),
+       int64(0),
+       uint(0),
+       uint8(0),
+       uint16(0),
+       uint32(0),
+       uint64(0),
+       float32(0),
+       float64(0),
+}
+
+// isEmpty gets whether the specified object is considered empty or not.
+func isEmpty(object interface{}) bool {
+
+       if object == nil {
+               return true
+       } else if object == "" {
+               return true
+       } else if object == false {
+               return true
+       }
+
+       for _, v := range numericZeros {
+               if object == v {
+                       return true
+               }
+       }
+
+       objValue := reflect.ValueOf(object)
+
+       switch objValue.Kind() {
+       case reflect.Map:
+               fallthrough
+       case reflect.Slice, reflect.Chan:
+               {
+                       return (objValue.Len() == 0)
+               }
+       case reflect.Struct:
+               switch object.(type) {
+               case time.Time:
+                       return object.(time.Time).IsZero()
+               }
+       case reflect.Ptr:
+               {
+                       if objValue.IsNil() {
+                               return true
+                       }
+                       switch object.(type) {
+                       case *time.Time:
+                               return object.(*time.Time).IsZero()
+                       default:
+                               return false
+                       }
+               }
+       }
+       return false
+}
+
+// Empty asserts that the specified object is empty.  I.e. nil, "", false, 0 or either
+// a slice or a channel with len == 0.
+//
+//  assert.Empty(t, obj)
+//
+// Returns whether the assertion was successful (true) or not (false).
+func Empty(t TestingT, object interface{}, msgAndArgs ...interface{}) bool {
+
+       pass := isEmpty(object)
+       if !pass {
+               Fail(t, fmt.Sprintf("Should be empty, but was %v", object), msgAndArgs...)
+       }
+
+       return pass
+
+}
+
+// NotEmpty asserts that the specified object is NOT empty.  I.e. not nil, "", false, 0 or either
+// a slice or a channel with len == 0.
+//
+//  if assert.NotEmpty(t, obj) {
+//    assert.Equal(t, "two", obj[1])
+//  }
+//
+// Returns whether the assertion was successful (true) or not (false).
+func NotEmpty(t TestingT, object interface{}, msgAndArgs ...interface{}) bool {
+
+       pass := !isEmpty(object)
+       if !pass {
+               Fail(t, fmt.Sprintf("Should NOT be empty, but was %v", object), msgAndArgs...)
+       }
+
+       return pass
+
+}
+
+// getLen try to get length of object.
+// return (false, 0) if impossible.
+func getLen(x interface{}) (ok bool, length int) {
+       v := reflect.ValueOf(x)
+       defer func() {
+               if e := recover(); e != nil {
+                       ok = false
+               }
+       }()
+       return true, v.Len()
+}
+
+// Len asserts that the specified object has specific length.
+// Len also fails if the object has a type that len() not accept.
+//
+//    assert.Len(t, mySlice, 3, "The size of slice is not 3")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func Len(t TestingT, object interface{}, length int, msgAndArgs ...interface{}) bool {
+       ok, l := getLen(object)
+       if !ok {
+               return Fail(t, fmt.Sprintf("\"%s\" could not be applied builtin len()", object), msgAndArgs...)
+       }
+
+       if l != length {
+               return Fail(t, fmt.Sprintf("\"%s\" should have %d item(s), but has %d", object, length, l), msgAndArgs...)
+       }
+       return true
+}
+
+// True asserts that the specified value is true.
+//
+//    assert.True(t, myBool, "myBool should be true")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func True(t TestingT, value bool, msgAndArgs ...interface{}) bool {
+
+       if value != true {
+               return Fail(t, "Should be true", msgAndArgs...)
+       }
+
+       return true
+
+}
+
+// False asserts that the specified value is false.
+//
+//    assert.False(t, myBool, "myBool should be false")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func False(t TestingT, value bool, msgAndArgs ...interface{}) bool {
+
+       if value != false {
+               return Fail(t, "Should be false", msgAndArgs...)
+       }
+
+       return true
+
+}
+
+// NotEqual asserts that the specified values are NOT equal.
+//
+//    assert.NotEqual(t, obj1, obj2, "two objects shouldn't be equal")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func NotEqual(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool {
+
+       if ObjectsAreEqual(expected, actual) {
+               return Fail(t, fmt.Sprintf("Should not be: %#v\n", actual), msgAndArgs...)
+       }
+
+       return true
+
+}
+
+// containsElement try loop over the list check if the list includes the element.
+// return (false, false) if impossible.
+// return (true, false) if element was not found.
+// return (true, true) if element was found.
+func includeElement(list interface{}, element interface{}) (ok, found bool) {
+
+       listValue := reflect.ValueOf(list)
+       elementValue := reflect.ValueOf(element)
+       defer func() {
+               if e := recover(); e != nil {
+                       ok = false
+                       found = false
+               }
+       }()
+
+       if reflect.TypeOf(list).Kind() == reflect.String {
+               return true, strings.Contains(listValue.String(), elementValue.String())
+       }
+
+       if reflect.TypeOf(list).Kind() == reflect.Map {
+               mapKeys := listValue.MapKeys()
+               for i := 0; i < len(mapKeys); i++ {
+                       if ObjectsAreEqual(mapKeys[i].Interface(), element) {
+                               return true, true
+                       }
+               }
+               return true, false
+       }
+
+       for i := 0; i < listValue.Len(); i++ {
+               if ObjectsAreEqual(listValue.Index(i).Interface(), element) {
+                       return true, true
+               }
+       }
+       return true, false
+
+}
+
+// Contains asserts that the specified string, list(array, slice...) or map contains the
+// specified substring or element.
+//
+//    assert.Contains(t, "Hello World", "World", "But 'Hello World' does contain 'World'")
+//    assert.Contains(t, ["Hello", "World"], "World", "But ["Hello", "World"] does contain 'World'")
+//    assert.Contains(t, {"Hello": "World"}, "Hello", "But {'Hello': 'World'} does contain 'Hello'")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func Contains(t TestingT, s, contains interface{}, msgAndArgs ...interface{}) bool {
+
+       ok, found := includeElement(s, contains)
+       if !ok {
+               return Fail(t, fmt.Sprintf("\"%s\" could not be applied builtin len()", s), msgAndArgs...)
+       }
+       if !found {
+               return Fail(t, fmt.Sprintf("\"%s\" does not contain \"%s\"", s, contains), msgAndArgs...)
+       }
+
+       return true
+
+}
+
+// NotContains asserts that the specified string, list(array, slice...) or map does NOT contain the
+// specified substring or element.
+//
+//    assert.NotContains(t, "Hello World", "Earth", "But 'Hello World' does NOT contain 'Earth'")
+//    assert.NotContains(t, ["Hello", "World"], "Earth", "But ['Hello', 'World'] does NOT contain 'Earth'")
+//    assert.NotContains(t, {"Hello": "World"}, "Earth", "But {'Hello': 'World'} does NOT contain 'Earth'")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func NotContains(t TestingT, s, contains interface{}, msgAndArgs ...interface{}) bool {
+
+       ok, found := includeElement(s, contains)
+       if !ok {
+               return Fail(t, fmt.Sprintf("\"%s\" could not be applied builtin len()", s), msgAndArgs...)
+       }
+       if found {
+               return Fail(t, fmt.Sprintf("\"%s\" should not contain \"%s\"", s, contains), msgAndArgs...)
+       }
+
+       return true
+
+}
+
+// Condition uses a Comparison to assert a complex condition.
+func Condition(t TestingT, comp Comparison, msgAndArgs ...interface{}) bool {
+       result := comp()
+       if !result {
+               Fail(t, "Condition failed!", msgAndArgs...)
+       }
+       return result
+}
+
+// PanicTestFunc defines a func that should be passed to the assert.Panics and assert.NotPanics
+// methods, and represents a simple func that takes no arguments, and returns nothing.
+type PanicTestFunc func()
+
+// didPanic returns true if the function passed to it panics. Otherwise, it returns false.
+func didPanic(f PanicTestFunc) (bool, interface{}) {
+
+       didPanic := false
+       var message interface{}
+       func() {
+
+               defer func() {
+                       if message = recover(); message != nil {
+                               didPanic = true
+                       }
+               }()
+
+               // call the target function
+               f()
+
+       }()
+
+       return didPanic, message
+
+}
+
+// Panics asserts that the code inside the specified PanicTestFunc panics.
+//
+//   assert.Panics(t, func(){
+//     GoCrazy()
+//   }, "Calling GoCrazy() should panic")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func Panics(t TestingT, f PanicTestFunc, msgAndArgs ...interface{}) bool {
+
+       if funcDidPanic, panicValue := didPanic(f); !funcDidPanic {
+               return Fail(t, fmt.Sprintf("func %#v should panic\n\r\tPanic value:\t%v", f, panicValue), msgAndArgs...)
+       }
+
+       return true
+}
+
+// NotPanics asserts that the code inside the specified PanicTestFunc does NOT panic.
+//
+//   assert.NotPanics(t, func(){
+//     RemainCalm()
+//   }, "Calling RemainCalm() should NOT panic")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func NotPanics(t TestingT, f PanicTestFunc, msgAndArgs ...interface{}) bool {
+
+       if funcDidPanic, panicValue := didPanic(f); funcDidPanic {
+               return Fail(t, fmt.Sprintf("func %#v should not panic\n\r\tPanic value:\t%v", f, panicValue), msgAndArgs...)
+       }
+
+       return true
+}
+
+// WithinDuration asserts that the two times are within duration delta of each other.
+//
+//   assert.WithinDuration(t, time.Now(), time.Now(), 10*time.Second, "The difference should not be more than 10s")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func WithinDuration(t TestingT, expected, actual time.Time, delta time.Duration, msgAndArgs ...interface{}) bool {
+
+       dt := expected.Sub(actual)
+       if dt < -delta || dt > delta {
+               return Fail(t, fmt.Sprintf("Max difference between %v and %v allowed is %v, but difference was %v", expected, actual, delta, dt), msgAndArgs...)
+       }
+
+       return true
+}
+
+func toFloat(x interface{}) (float64, bool) {
+       var xf float64
+       xok := true
+
+       switch xn := x.(type) {
+       case uint8:
+               xf = float64(xn)
+       case uint16:
+               xf = float64(xn)
+       case uint32:
+               xf = float64(xn)
+       case uint64:
+               xf = float64(xn)
+       case int:
+               xf = float64(xn)
+       case int8:
+               xf = float64(xn)
+       case int16:
+               xf = float64(xn)
+       case int32:
+               xf = float64(xn)
+       case int64:
+               xf = float64(xn)
+       case float32:
+               xf = float64(xn)
+       case float64:
+               xf = float64(xn)
+       default:
+               xok = false
+       }
+
+       return xf, xok
+}
+
+// InDelta asserts that the two numerals are within delta of each other.
+//
+//      assert.InDelta(t, math.Pi, (22 / 7.0), 0.01)
+//
+// Returns whether the assertion was successful (true) or not (false).
+func InDelta(t TestingT, expected, actual interface{}, delta float64, msgAndArgs ...interface{}) bool {
+
+       af, aok := toFloat(expected)
+       bf, bok := toFloat(actual)
+
+       if !aok || !bok {
+               return Fail(t, fmt.Sprintf("Parameters must be numerical"), msgAndArgs...)
+       }
+
+       if math.IsNaN(af) {
+               return Fail(t, fmt.Sprintf("Actual must not be NaN"), msgAndArgs...)
+       }
+
+       if math.IsNaN(bf) {
+               return Fail(t, fmt.Sprintf("Expected %v with delta %v, but was NaN", expected, delta), msgAndArgs...)
+       }
+
+       dt := af - bf
+       if dt < -delta || dt > delta {
+               return Fail(t, fmt.Sprintf("Max difference between %v and %v allowed is %v, but difference was %v", expected, actual, delta, dt), msgAndArgs...)
+       }
+
+       return true
+}
+
+// InDeltaSlice is the same as InDelta, except it compares two slices.
+func InDeltaSlice(t TestingT, expected, actual interface{}, delta float64, msgAndArgs ...interface{}) bool {
+       if expected == nil || actual == nil ||
+               reflect.TypeOf(actual).Kind() != reflect.Slice ||
+               reflect.TypeOf(expected).Kind() != reflect.Slice {
+               return Fail(t, fmt.Sprintf("Parameters must be slice"), msgAndArgs...)
+       }
+
+       actualSlice := reflect.ValueOf(actual)
+       expectedSlice := reflect.ValueOf(expected)
+
+       for i := 0; i < actualSlice.Len(); i++ {
+               result := InDelta(t, actualSlice.Index(i).Interface(), expectedSlice.Index(i).Interface(), delta)
+               if !result {
+                       return result
+               }
+       }
+
+       return true
+}
+
+func calcRelativeError(expected, actual interface{}) (float64, error) {
+       af, aok := toFloat(expected)
+       if !aok {
+               return 0, fmt.Errorf("expected value %q cannot be converted to float", expected)
+       }
+       if af == 0 {
+               return 0, fmt.Errorf("expected value must have a value other than zero to calculate the relative error")
+       }
+       bf, bok := toFloat(actual)
+       if !bok {
+               return 0, fmt.Errorf("expected value %q cannot be converted to float", actual)
+       }
+
+       return math.Abs(af-bf) / math.Abs(af), nil
+}
+
+// InEpsilon asserts that expected and actual have a relative error less than epsilon
+//
+// Returns whether the assertion was successful (true) or not (false).
+func InEpsilon(t TestingT, expected, actual interface{}, epsilon float64, msgAndArgs ...interface{}) bool {
+       actualEpsilon, err := calcRelativeError(expected, actual)
+       if err != nil {
+               return Fail(t, err.Error(), msgAndArgs...)
+       }
+       if actualEpsilon > epsilon {
+               return Fail(t, fmt.Sprintf("Relative error is too high: %#v (expected)\n"+
+                       "        < %#v (actual)", actualEpsilon, epsilon), msgAndArgs...)
+       }
+
+       return true
+}
+
+// InEpsilonSlice is the same as InEpsilon, except it compares each value from two slices.
+func InEpsilonSlice(t TestingT, expected, actual interface{}, epsilon float64, msgAndArgs ...interface{}) bool {
+       if expected == nil || actual == nil ||
+               reflect.TypeOf(actual).Kind() != reflect.Slice ||
+               reflect.TypeOf(expected).Kind() != reflect.Slice {
+               return Fail(t, fmt.Sprintf("Parameters must be slice"), msgAndArgs...)
+       }
+
+       actualSlice := reflect.ValueOf(actual)
+       expectedSlice := reflect.ValueOf(expected)
+
+       for i := 0; i < actualSlice.Len(); i++ {
+               result := InEpsilon(t, actualSlice.Index(i).Interface(), expectedSlice.Index(i).Interface(), epsilon)
+               if !result {
+                       return result
+               }
+       }
+
+       return true
+}
+
+/*
+       Errors
+*/
+
+// NoError asserts that a function returned no error (i.e. `nil`).
+//
+//   actualObj, err := SomeFunction()
+//   if assert.NoError(t, err) {
+//        assert.Equal(t, actualObj, expectedObj)
+//   }
+//
+// Returns whether the assertion was successful (true) or not (false).
+func NoError(t TestingT, err error, msgAndArgs ...interface{}) bool {
+       if isNil(err) {
+               return true
+       }
+
+       return Fail(t, fmt.Sprintf("Received unexpected error %q", err), msgAndArgs...)
+}
+
+// Error asserts that a function returned an error (i.e. not `nil`).
+//
+//   actualObj, err := SomeFunction()
+//   if assert.Error(t, err, "An error was expected") {
+//        assert.Equal(t, err, expectedError)
+//   }
+//
+// Returns whether the assertion was successful (true) or not (false).
+func Error(t TestingT, err error, msgAndArgs ...interface{}) bool {
+
+       message := messageFromMsgAndArgs(msgAndArgs...)
+       return NotNil(t, err, "An error is expected but got nil. %s", message)
+
+}
+
+// EqualError asserts that a function returned an error (i.e. not `nil`)
+// and that it is equal to the provided error.
+//
+//   actualObj, err := SomeFunction()
+//   if assert.Error(t, err, "An error was expected") {
+//        assert.Equal(t, err, expectedError)
+//   }
+//
+// Returns whether the assertion was successful (true) or not (false).
+func EqualError(t TestingT, theError error, errString string, msgAndArgs ...interface{}) bool {
+
+       message := messageFromMsgAndArgs(msgAndArgs...)
+       if !NotNil(t, theError, "An error is expected but got nil. %s", message) {
+               return false
+       }
+       s := "An error with value \"%s\" is expected but got \"%s\". %s"
+       return Equal(t, errString, theError.Error(),
+               s, errString, theError.Error(), message)
+}
+
+// matchRegexp return true if a specified regexp matches a string.
+func matchRegexp(rx interface{}, str interface{}) bool {
+
+       var r *regexp.Regexp
+       if rr, ok := rx.(*regexp.Regexp); ok {
+               r = rr
+       } else {
+               r = regexp.MustCompile(fmt.Sprint(rx))
+       }
+
+       return (r.FindStringIndex(fmt.Sprint(str)) != nil)
+
+}
+
+// Regexp asserts that a specified regexp matches a string.
+//
+//  assert.Regexp(t, regexp.MustCompile("start"), "it's starting")
+//  assert.Regexp(t, "start...$", "it's not starting")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func Regexp(t TestingT, rx interface{}, str interface{}, msgAndArgs ...interface{}) bool {
+
+       match := matchRegexp(rx, str)
+
+       if !match {
+               Fail(t, fmt.Sprintf("Expect \"%v\" to match \"%v\"", str, rx), msgAndArgs...)
+       }
+
+       return match
+}
+
+// NotRegexp asserts that a specified regexp does not match a string.
+//
+//  assert.NotRegexp(t, regexp.MustCompile("starts"), "it's starting")
+//  assert.NotRegexp(t, "^start", "it's not starting")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func NotRegexp(t TestingT, rx interface{}, str interface{}, msgAndArgs ...interface{}) bool {
+       match := matchRegexp(rx, str)
+
+       if match {
+               Fail(t, fmt.Sprintf("Expect \"%v\" to NOT match \"%v\"", str, rx), msgAndArgs...)
+       }
+
+       return !match
+
+}
+
+// Zero asserts that i is the zero value for its type and returns the truth.
+func Zero(t TestingT, i interface{}, msgAndArgs ...interface{}) bool {
+       if i != nil && !reflect.DeepEqual(i, reflect.Zero(reflect.TypeOf(i)).Interface()) {
+               return Fail(t, fmt.Sprintf("Should be zero, but was %v", i), msgAndArgs...)
+       }
+       return true
+}
+
+// NotZero asserts that i is not the zero value for its type and returns the truth.
+func NotZero(t TestingT, i interface{}, msgAndArgs ...interface{}) bool {
+       if i == nil || reflect.DeepEqual(i, reflect.Zero(reflect.TypeOf(i)).Interface()) {
+               return Fail(t, fmt.Sprintf("Should not be zero, but was %v", i), msgAndArgs...)
+       }
+       return true
+}
+
+// JSONEq asserts that two JSON strings are equivalent.
+//
+//  assert.JSONEq(t, `{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`)
+//
+// Returns whether the assertion was successful (true) or not (false).
+func JSONEq(t TestingT, expected string, actual string, msgAndArgs ...interface{}) bool {
+       var expectedJSONAsInterface, actualJSONAsInterface interface{}
+
+       if err := json.Unmarshal([]byte(expected), &expectedJSONAsInterface); err != nil {
+               return Fail(t, fmt.Sprintf("Expected value ('%s') is not valid json.\nJSON parsing error: '%s'", expected, err.Error()), msgAndArgs...)
+       }
+
+       if err := json.Unmarshal([]byte(actual), &actualJSONAsInterface); err != nil {
+               return Fail(t, fmt.Sprintf("Input ('%s') needs to be valid json.\nJSON parsing error: '%s'", actual, err.Error()), msgAndArgs...)
+       }
+
+       return Equal(t, expectedJSONAsInterface, actualJSONAsInterface, msgAndArgs...)
+}
+
+func typeAndKind(v interface{}) (reflect.Type, reflect.Kind) {
+       t := reflect.TypeOf(v)
+       k := t.Kind()
+
+       if k == reflect.Ptr {
+               t = t.Elem()
+               k = t.Kind()
+       }
+       return t, k
+}
+
+// diff returns a diff of both values as long as both are of the same type and
+// are a struct, map, slice or array. Otherwise it returns an empty string.
+func diff(expected interface{}, actual interface{}) string {
+       if expected == nil || actual == nil {
+               return ""
+       }
+
+       et, ek := typeAndKind(expected)
+       at, _ := typeAndKind(actual)
+
+       if et != at {
+               return ""
+       }
+
+       if ek != reflect.Struct && ek != reflect.Map && ek != reflect.Slice && ek != reflect.Array {
+               return ""
+       }
+
+       spew.Config.SortKeys = true
+       e := spew.Sdump(expected)
+       a := spew.Sdump(actual)
+
+       diff, _ := difflib.GetUnifiedDiffString(difflib.UnifiedDiff{
+               A:        difflib.SplitLines(e),
+               B:        difflib.SplitLines(a),
+               FromFile: "Expected",
+               FromDate: "",
+               ToFile:   "Actual",
+               ToDate:   "",
+               Context:  1,
+       })
+
+       return "\n\nDiff:\n" + diff
+}
diff --git a/vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/assert/assertions_test.go b/vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/assert/assertions_test.go
new file mode 100644 (file)
index 0000000..15a04b8
--- /dev/null
@@ -0,0 +1,1122 @@
+package assert
+
+import (
+       "errors"
+       "io"
+       "math"
+       "os"
+       "reflect"
+       "regexp"
+       "testing"
+       "time"
+)
+
+var (
+       i     interface{}
+       zeros = []interface{}{
+               false,
+               byte(0),
+               complex64(0),
+               complex128(0),
+               float32(0),
+               float64(0),
+               int(0),
+               int8(0),
+               int16(0),
+               int32(0),
+               int64(0),
+               rune(0),
+               uint(0),
+               uint8(0),
+               uint16(0),
+               uint32(0),
+               uint64(0),
+               uintptr(0),
+               "",
+               [0]interface{}{},
+               []interface{}(nil),
+               struct{ x int }{},
+               (*interface{})(nil),
+               (func())(nil),
+               nil,
+               interface{}(nil),
+               map[interface{}]interface{}(nil),
+               (chan interface{})(nil),
+               (<-chan interface{})(nil),
+               (chan<- interface{})(nil),
+       }
+       nonZeros = []interface{}{
+               true,
+               byte(1),
+               complex64(1),
+               complex128(1),
+               float32(1),
+               float64(1),
+               int(1),
+               int8(1),
+               int16(1),
+               int32(1),
+               int64(1),
+               rune(1),
+               uint(1),
+               uint8(1),
+               uint16(1),
+               uint32(1),
+               uint64(1),
+               uintptr(1),
+               "s",
+               [1]interface{}{1},
+               []interface{}{},
+               struct{ x int }{1},
+               (*interface{})(&i),
+               (func())(func() {}),
+               interface{}(1),
+               map[interface{}]interface{}{},
+               (chan interface{})(make(chan interface{})),
+               (<-chan interface{})(make(chan interface{})),
+               (chan<- interface{})(make(chan interface{})),
+       }
+)
+
+// AssertionTesterInterface defines an interface to be used for testing assertion methods
+type AssertionTesterInterface interface {
+       TestMethod()
+}
+
+// AssertionTesterConformingObject is an object that conforms to the AssertionTesterInterface interface
+type AssertionTesterConformingObject struct {
+}
+
+func (a *AssertionTesterConformingObject) TestMethod() {
+}
+
+// AssertionTesterNonConformingObject is an object that does not conform to the AssertionTesterInterface interface
+type AssertionTesterNonConformingObject struct {
+}
+
+func TestObjectsAreEqual(t *testing.T) {
+
+       if !ObjectsAreEqual("Hello World", "Hello World") {
+               t.Error("objectsAreEqual should return true")
+       }
+       if !ObjectsAreEqual(123, 123) {
+               t.Error("objectsAreEqual should return true")
+       }
+       if !ObjectsAreEqual(123.5, 123.5) {
+               t.Error("objectsAreEqual should return true")
+       }
+       if !ObjectsAreEqual([]byte("Hello World"), []byte("Hello World")) {
+               t.Error("objectsAreEqual should return true")
+       }
+       if !ObjectsAreEqual(nil, nil) {
+               t.Error("objectsAreEqual should return true")
+       }
+       if ObjectsAreEqual(map[int]int{5: 10}, map[int]int{10: 20}) {
+               t.Error("objectsAreEqual should return false")
+       }
+       if ObjectsAreEqual('x', "x") {
+               t.Error("objectsAreEqual should return false")
+       }
+       if ObjectsAreEqual("x", 'x') {
+               t.Error("objectsAreEqual should return false")
+       }
+       if ObjectsAreEqual(0, 0.1) {
+               t.Error("objectsAreEqual should return false")
+       }
+       if ObjectsAreEqual(0.1, 0) {
+               t.Error("objectsAreEqual should return false")
+       }
+       if ObjectsAreEqual(uint32(10), int32(10)) {
+               t.Error("objectsAreEqual should return false")
+       }
+       if !ObjectsAreEqualValues(uint32(10), int32(10)) {
+               t.Error("ObjectsAreEqualValues should return true")
+       }
+       if ObjectsAreEqualValues(0, nil) {
+               t.Fail()
+       }
+       if ObjectsAreEqualValues(nil, 0) {
+               t.Fail()
+       }
+
+}
+
+func TestImplements(t *testing.T) {
+
+       mockT := new(testing.T)
+
+       if !Implements(mockT, (*AssertionTesterInterface)(nil), new(AssertionTesterConformingObject)) {
+               t.Error("Implements method should return true: AssertionTesterConformingObject implements AssertionTesterInterface")
+       }
+       if Implements(mockT, (*AssertionTesterInterface)(nil), new(AssertionTesterNonConformingObject)) {
+               t.Error("Implements method should return false: AssertionTesterNonConformingObject does not implements AssertionTesterInterface")
+       }
+
+}
+
+func TestIsType(t *testing.T) {
+
+       mockT := new(testing.T)
+
+       if !IsType(mockT, new(AssertionTesterConformingObject), new(AssertionTesterConformingObject)) {
+               t.Error("IsType should return true: AssertionTesterConformingObject is the same type as AssertionTesterConformingObject")
+       }
+       if IsType(mockT, new(AssertionTesterConformingObject), new(AssertionTesterNonConformingObject)) {
+               t.Error("IsType should return false: AssertionTesterConformingObject is not the same type as AssertionTesterNonConformingObject")
+       }
+
+}
+
+func TestEqual(t *testing.T) {
+
+       mockT := new(testing.T)
+
+       if !Equal(mockT, "Hello World", "Hello World") {
+               t.Error("Equal should return true")
+       }
+       if !Equal(mockT, 123, 123) {
+               t.Error("Equal should return true")
+       }
+       if !Equal(mockT, 123.5, 123.5) {
+               t.Error("Equal should return true")
+       }
+       if !Equal(mockT, []byte("Hello World"), []byte("Hello World")) {
+               t.Error("Equal should return true")
+       }
+       if !Equal(mockT, nil, nil) {
+               t.Error("Equal should return true")
+       }
+       if !Equal(mockT, int32(123), int32(123)) {
+               t.Error("Equal should return true")
+       }
+       if !Equal(mockT, uint64(123), uint64(123)) {
+               t.Error("Equal should return true")
+       }
+
+}
+
+func TestNotNil(t *testing.T) {
+
+       mockT := new(testing.T)
+
+       if !NotNil(mockT, new(AssertionTesterConformingObject)) {
+               t.Error("NotNil should return true: object is not nil")
+       }
+       if NotNil(mockT, nil) {
+               t.Error("NotNil should return false: object is nil")
+       }
+       if NotNil(mockT, (*struct{})(nil)) {
+               t.Error("NotNil should return false: object is (*struct{})(nil)")
+       }
+
+}
+
+func TestNil(t *testing.T) {
+
+       mockT := new(testing.T)
+
+       if !Nil(mockT, nil) {
+               t.Error("Nil should return true: object is nil")
+       }
+       if !Nil(mockT, (*struct{})(nil)) {
+               t.Error("Nil should return true: object is (*struct{})(nil)")
+       }
+       if Nil(mockT, new(AssertionTesterConformingObject)) {
+               t.Error("Nil should return false: object is not nil")
+       }
+
+}
+
+func TestTrue(t *testing.T) {
+
+       mockT := new(testing.T)
+
+       if !True(mockT, true) {
+               t.Error("True should return true")
+       }
+       if True(mockT, false) {
+               t.Error("True should return false")
+       }
+
+}
+
+func TestFalse(t *testing.T) {
+
+       mockT := new(testing.T)
+
+       if !False(mockT, false) {
+               t.Error("False should return true")
+       }
+       if False(mockT, true) {
+               t.Error("False should return false")
+       }
+
+}
+
+func TestExactly(t *testing.T) {
+
+       mockT := new(testing.T)
+
+       a := float32(1)
+       b := float64(1)
+       c := float32(1)
+       d := float32(2)
+
+       if Exactly(mockT, a, b) {
+               t.Error("Exactly should return false")
+       }
+       if Exactly(mockT, a, d) {
+               t.Error("Exactly should return false")
+       }
+       if !Exactly(mockT, a, c) {
+               t.Error("Exactly should return true")
+       }
+
+       if Exactly(mockT, nil, a) {
+               t.Error("Exactly should return false")
+       }
+       if Exactly(mockT, a, nil) {
+               t.Error("Exactly should return false")
+       }
+
+}
+
+func TestNotEqual(t *testing.T) {
+
+       mockT := new(testing.T)
+
+       if !NotEqual(mockT, "Hello World", "Hello World!") {
+               t.Error("NotEqual should return true")
+       }
+       if !NotEqual(mockT, 123, 1234) {
+               t.Error("NotEqual should return true")
+       }
+       if !NotEqual(mockT, 123.5, 123.55) {
+               t.Error("NotEqual should return true")
+       }
+       if !NotEqual(mockT, []byte("Hello World"), []byte("Hello World!")) {
+               t.Error("NotEqual should return true")
+       }
+       if !NotEqual(mockT, nil, new(AssertionTesterConformingObject)) {
+               t.Error("NotEqual should return true")
+       }
+       funcA := func() int { return 23 }
+       funcB := func() int { return 42 }
+       if !NotEqual(mockT, funcA, funcB) {
+               t.Error("NotEqual should return true")
+       }
+
+       if NotEqual(mockT, "Hello World", "Hello World") {
+               t.Error("NotEqual should return false")
+       }
+       if NotEqual(mockT, 123, 123) {
+               t.Error("NotEqual should return false")
+       }
+       if NotEqual(mockT, 123.5, 123.5) {
+               t.Error("NotEqual should return false")
+       }
+       if NotEqual(mockT, []byte("Hello World"), []byte("Hello World")) {
+               t.Error("NotEqual should return false")
+       }
+       if NotEqual(mockT, new(AssertionTesterConformingObject), new(AssertionTesterConformingObject)) {
+               t.Error("NotEqual should return false")
+       }
+}
+
+type A struct {
+       Name, Value string
+}
+
+func TestContains(t *testing.T) {
+
+       mockT := new(testing.T)
+       list := []string{"Foo", "Bar"}
+       complexList := []*A{
+               {"b", "c"},
+               {"d", "e"},
+               {"g", "h"},
+               {"j", "k"},
+       }
+       simpleMap := map[interface{}]interface{}{"Foo": "Bar"}
+
+       if !Contains(mockT, "Hello World", "Hello") {
+               t.Error("Contains should return true: \"Hello World\" contains \"Hello\"")
+       }
+       if Contains(mockT, "Hello World", "Salut") {
+               t.Error("Contains should return false: \"Hello World\" does not contain \"Salut\"")
+       }
+
+       if !Contains(mockT, list, "Bar") {
+               t.Error("Contains should return true: \"[\"Foo\", \"Bar\"]\" contains \"Bar\"")
+       }
+       if Contains(mockT, list, "Salut") {
+               t.Error("Contains should return false: \"[\"Foo\", \"Bar\"]\" does not contain \"Salut\"")
+       }
+       if !Contains(mockT, complexList, &A{"g", "h"}) {
+               t.Error("Contains should return true: complexList contains {\"g\", \"h\"}")
+       }
+       if Contains(mockT, complexList, &A{"g", "e"}) {
+               t.Error("Contains should return false: complexList contains {\"g\", \"e\"}")
+       }
+       if Contains(mockT, complexList, &A{"g", "e"}) {
+               t.Error("Contains should return false: complexList contains {\"g\", \"e\"}")
+       }
+       if !Contains(mockT, simpleMap, "Foo") {
+               t.Error("Contains should return true: \"{\"Foo\": \"Bar\"}\" contains \"Foo\"")
+       }
+       if Contains(mockT, simpleMap, "Bar") {
+               t.Error("Contains should return false: \"{\"Foo\": \"Bar\"}\" does not contains \"Bar\"")
+       }
+}
+
+func TestNotContains(t *testing.T) {
+
+       mockT := new(testing.T)
+       list := []string{"Foo", "Bar"}
+       simpleMap := map[interface{}]interface{}{"Foo": "Bar"}
+
+       if !NotContains(mockT, "Hello World", "Hello!") {
+               t.Error("NotContains should return true: \"Hello World\" does not contain \"Hello!\"")
+       }
+       if NotContains(mockT, "Hello World", "Hello") {
+               t.Error("NotContains should return false: \"Hello World\" contains \"Hello\"")
+       }
+
+       if !NotContains(mockT, list, "Foo!") {
+               t.Error("NotContains should return true: \"[\"Foo\", \"Bar\"]\" does not contain \"Foo!\"")
+       }
+       if NotContains(mockT, list, "Foo") {
+               t.Error("NotContains should return false: \"[\"Foo\", \"Bar\"]\" contains \"Foo\"")
+       }
+       if NotContains(mockT, simpleMap, "Foo") {
+               t.Error("Contains should return true: \"{\"Foo\": \"Bar\"}\" contains \"Foo\"")
+       }
+       if !NotContains(mockT, simpleMap, "Bar") {
+               t.Error("Contains should return false: \"{\"Foo\": \"Bar\"}\" does not contains \"Bar\"")
+       }
+}
+
+func Test_includeElement(t *testing.T) {
+
+       list1 := []string{"Foo", "Bar"}
+       list2 := []int{1, 2}
+       simpleMap := map[interface{}]interface{}{"Foo": "Bar"}
+
+       ok, found := includeElement("Hello World", "World")
+       True(t, ok)
+       True(t, found)
+
+       ok, found = includeElement(list1, "Foo")
+       True(t, ok)
+       True(t, found)
+
+       ok, found = includeElement(list1, "Bar")
+       True(t, ok)
+       True(t, found)
+
+       ok, found = includeElement(list2, 1)
+       True(t, ok)
+       True(t, found)
+
+       ok, found = includeElement(list2, 2)
+       True(t, ok)
+       True(t, found)
+
+       ok, found = includeElement(list1, "Foo!")
+       True(t, ok)
+       False(t, found)
+
+       ok, found = includeElement(list2, 3)
+       True(t, ok)
+       False(t, found)
+
+       ok, found = includeElement(list2, "1")
+       True(t, ok)
+       False(t, found)
+
+       ok, found = includeElement(simpleMap, "Foo")
+       True(t, ok)
+       True(t, found)
+
+       ok, found = includeElement(simpleMap, "Bar")
+       True(t, ok)
+       False(t, found)
+
+       ok, found = includeElement(1433, "1")
+       False(t, ok)
+       False(t, found)
+}
+
+func TestCondition(t *testing.T) {
+       mockT := new(testing.T)
+
+       if !Condition(mockT, func() bool { return true }, "Truth") {
+               t.Error("Condition should return true")
+       }
+
+       if Condition(mockT, func() bool { return false }, "Lie") {
+               t.Error("Condition should return false")
+       }
+
+}
+
+func TestDidPanic(t *testing.T) {
+
+       if funcDidPanic, _ := didPanic(func() {
+               panic("Panic!")
+       }); !funcDidPanic {
+               t.Error("didPanic should return true")
+       }
+
+       if funcDidPanic, _ := didPanic(func() {
+       }); funcDidPanic {
+               t.Error("didPanic should return false")
+       }
+
+}
+
+func TestPanics(t *testing.T) {
+
+       mockT := new(testing.T)
+
+       if !Panics(mockT, func() {
+               panic("Panic!")
+       }) {
+               t.Error("Panics should return true")
+       }
+
+       if Panics(mockT, func() {
+       }) {
+               t.Error("Panics should return false")
+       }
+
+}
+
+func TestNotPanics(t *testing.T) {
+
+       mockT := new(testing.T)
+
+       if !NotPanics(mockT, func() {
+       }) {
+               t.Error("NotPanics should return true")
+       }
+
+       if NotPanics(mockT, func() {
+               panic("Panic!")
+       }) {
+               t.Error("NotPanics should return false")
+       }
+
+}
+
+func TestNoError(t *testing.T) {
+
+       mockT := new(testing.T)
+
+       // start with a nil error
+       var err error
+
+       True(t, NoError(mockT, err), "NoError should return True for nil arg")
+
+       // now set an error
+       err = errors.New("some error")
+
+       False(t, NoError(mockT, err), "NoError with error should return False")
+
+}
+
+func TestError(t *testing.T) {
+
+       mockT := new(testing.T)
+
+       // start with a nil error
+       var err error
+
+       False(t, Error(mockT, err), "Error should return False for nil arg")
+
+       // now set an error
+       err = errors.New("some error")
+
+       True(t, Error(mockT, err), "Error with error should return True")
+
+}
+
+func TestEqualError(t *testing.T) {
+       mockT := new(testing.T)
+
+       // start with a nil error
+       var err error
+       False(t, EqualError(mockT, err, ""),
+               "EqualError should return false for nil arg")
+
+       // now set an error
+       err = errors.New("some error")
+       False(t, EqualError(mockT, err, "Not some error"),
+               "EqualError should return false for different error string")
+       True(t, EqualError(mockT, err, "some error"),
+               "EqualError should return true")
+}
+
+func Test_isEmpty(t *testing.T) {
+
+       chWithValue := make(chan struct{}, 1)
+       chWithValue <- struct{}{}
+
+       True(t, isEmpty(""))
+       True(t, isEmpty(nil))
+       True(t, isEmpty([]string{}))
+       True(t, isEmpty(0))
+       True(t, isEmpty(int32(0)))
+       True(t, isEmpty(int64(0)))
+       True(t, isEmpty(false))
+       True(t, isEmpty(map[string]string{}))
+       True(t, isEmpty(new(time.Time)))
+       True(t, isEmpty(time.Time{}))
+       True(t, isEmpty(make(chan struct{})))
+       False(t, isEmpty("something"))
+       False(t, isEmpty(errors.New("something")))
+       False(t, isEmpty([]string{"something"}))
+       False(t, isEmpty(1))
+       False(t, isEmpty(true))
+       False(t, isEmpty(map[string]string{"Hello": "World"}))
+       False(t, isEmpty(chWithValue))
+
+}
+
+func TestEmpty(t *testing.T) {
+
+       mockT := new(testing.T)
+       chWithValue := make(chan struct{}, 1)
+       chWithValue <- struct{}{}
+       var tiP *time.Time
+       var tiNP time.Time
+       var s *string
+       var f *os.File
+
+       True(t, Empty(mockT, ""), "Empty string is empty")
+       True(t, Empty(mockT, nil), "Nil is empty")
+       True(t, Empty(mockT, []string{}), "Empty string array is empty")
+       True(t, Empty(mockT, 0), "Zero int value is empty")
+       True(t, Empty(mockT, false), "False value is empty")
+       True(t, Empty(mockT, make(chan struct{})), "Channel without values is empty")
+       True(t, Empty(mockT, s), "Nil string pointer is empty")
+       True(t, Empty(mockT, f), "Nil os.File pointer is empty")
+       True(t, Empty(mockT, tiP), "Nil time.Time pointer is empty")
+       True(t, Empty(mockT, tiNP), "time.Time is empty")
+
+       False(t, Empty(mockT, "something"), "Non Empty string is not empty")
+       False(t, Empty(mockT, errors.New("something")), "Non nil object is not empty")
+       False(t, Empty(mockT, []string{"something"}), "Non empty string array is not empty")
+       False(t, Empty(mockT, 1), "Non-zero int value is not empty")
+       False(t, Empty(mockT, true), "True value is not empty")
+       False(t, Empty(mockT, chWithValue), "Channel with values is not empty")
+}
+
+func TestNotEmpty(t *testing.T) {
+
+       mockT := new(testing.T)
+       chWithValue := make(chan struct{}, 1)
+       chWithValue <- struct{}{}
+
+       False(t, NotEmpty(mockT, ""), "Empty string is empty")
+       False(t, NotEmpty(mockT, nil), "Nil is empty")
+       False(t, NotEmpty(mockT, []string{}), "Empty string array is empty")
+       False(t, NotEmpty(mockT, 0), "Zero int value is empty")
+       False(t, NotEmpty(mockT, false), "False value is empty")
+       False(t, NotEmpty(mockT, make(chan struct{})), "Channel without values is empty")
+
+       True(t, NotEmpty(mockT, "something"), "Non Empty string is not empty")
+       True(t, NotEmpty(mockT, errors.New("something")), "Non nil object is not empty")
+       True(t, NotEmpty(mockT, []string{"something"}), "Non empty string array is not empty")
+       True(t, NotEmpty(mockT, 1), "Non-zero int value is not empty")
+       True(t, NotEmpty(mockT, true), "True value is not empty")
+       True(t, NotEmpty(mockT, chWithValue), "Channel with values is not empty")
+}
+
+func Test_getLen(t *testing.T) {
+       falseCases := []interface{}{
+               nil,
+               0,
+               true,
+               false,
+               'A',
+               struct{}{},
+       }
+       for _, v := range falseCases {
+               ok, l := getLen(v)
+               False(t, ok, "Expected getLen fail to get length of %#v", v)
+               Equal(t, 0, l, "getLen should return 0 for %#v", v)
+       }
+
+       ch := make(chan int, 5)
+       ch <- 1
+       ch <- 2
+       ch <- 3
+       trueCases := []struct {
+               v interface{}
+               l int
+       }{
+               {[]int{1, 2, 3}, 3},
+               {[...]int{1, 2, 3}, 3},
+               {"ABC", 3},
+               {map[int]int{1: 2, 2: 4, 3: 6}, 3},
+               {ch, 3},
+
+               {[]int{}, 0},
+               {map[int]int{}, 0},
+               {make(chan int), 0},
+
+               {[]int(nil), 0},
+               {map[int]int(nil), 0},
+               {(chan int)(nil), 0},
+       }
+
+       for _, c := range trueCases {
+               ok, l := getLen(c.v)
+               True(t, ok, "Expected getLen success to get length of %#v", c.v)
+               Equal(t, c.l, l)
+       }
+}
+
+func TestLen(t *testing.T) {
+       mockT := new(testing.T)
+
+       False(t, Len(mockT, nil, 0), "nil does not have length")
+       False(t, Len(mockT, 0, 0), "int does not have length")
+       False(t, Len(mockT, true, 0), "true does not have length")
+       False(t, Len(mockT, false, 0), "false does not have length")
+       False(t, Len(mockT, 'A', 0), "Rune does not have length")
+       False(t, Len(mockT, struct{}{}, 0), "Struct does not have length")
+
+       ch := make(chan int, 5)
+       ch <- 1
+       ch <- 2
+       ch <- 3
+
+       cases := []struct {
+               v interface{}
+               l int
+       }{
+               {[]int{1, 2, 3}, 3},
+               {[...]int{1, 2, 3}, 3},
+               {"ABC", 3},
+               {map[int]int{1: 2, 2: 4, 3: 6}, 3},
+               {ch, 3},
+
+               {[]int{}, 0},
+               {map[int]int{}, 0},
+               {make(chan int), 0},
+
+               {[]int(nil), 0},
+               {map[int]int(nil), 0},
+               {(chan int)(nil), 0},
+       }
+
+       for _, c := range cases {
+               True(t, Len(mockT, c.v, c.l), "%#v have %d items", c.v, c.l)
+       }
+
+       cases = []struct {
+               v interface{}
+               l int
+       }{
+               {[]int{1, 2, 3}, 4},
+               {[...]int{1, 2, 3}, 2},
+               {"ABC", 2},
+               {map[int]int{1: 2, 2: 4, 3: 6}, 4},
+               {ch, 2},
+
+               {[]int{}, 1},
+               {map[int]int{}, 1},
+               {make(chan int), 1},
+
+               {[]int(nil), 1},
+               {map[int]int(nil), 1},
+               {(chan int)(nil), 1},
+       }
+
+       for _, c := range cases {
+               False(t, Len(mockT, c.v, c.l), "%#v have %d items", c.v, c.l)
+       }
+}
+
+func TestWithinDuration(t *testing.T) {
+
+       mockT := new(testing.T)
+       a := time.Now()
+       b := a.Add(10 * time.Second)
+
+       True(t, WithinDuration(mockT, a, b, 10*time.Second), "A 10s difference is within a 10s time difference")
+       True(t, WithinDuration(mockT, b, a, 10*time.Second), "A 10s difference is within a 10s time difference")
+
+       False(t, WithinDuration(mockT, a, b, 9*time.Second), "A 10s difference is not within a 9s time difference")
+       False(t, WithinDuration(mockT, b, a, 9*time.Second), "A 10s difference is not within a 9s time difference")
+
+       False(t, WithinDuration(mockT, a, b, -9*time.Second), "A 10s difference is not within a 9s time difference")
+       False(t, WithinDuration(mockT, b, a, -9*time.Second), "A 10s difference is not within a 9s time difference")
+
+       False(t, WithinDuration(mockT, a, b, -11*time.Second), "A 10s difference is not within a 9s time difference")
+       False(t, WithinDuration(mockT, b, a, -11*time.Second), "A 10s difference is not within a 9s time difference")
+}
+
+func TestInDelta(t *testing.T) {
+       mockT := new(testing.T)
+
+       True(t, InDelta(mockT, 1.001, 1, 0.01), "|1.001 - 1| <= 0.01")
+       True(t, InDelta(mockT, 1, 1.001, 0.01), "|1 - 1.001| <= 0.01")
+       True(t, InDelta(mockT, 1, 2, 1), "|1 - 2| <= 1")
+       False(t, InDelta(mockT, 1, 2, 0.5), "Expected |1 - 2| <= 0.5 to fail")
+       False(t, InDelta(mockT, 2, 1, 0.5), "Expected |2 - 1| <= 0.5 to fail")
+       False(t, InDelta(mockT, "", nil, 1), "Expected non numerals to fail")
+       False(t, InDelta(mockT, 42, math.NaN(), 0.01), "Expected NaN for actual to fail")
+       False(t, InDelta(mockT, math.NaN(), 42, 0.01), "Expected NaN for expected to fail")
+
+       cases := []struct {
+               a, b  interface{}
+               delta float64
+       }{
+               {uint8(2), uint8(1), 1},
+               {uint16(2), uint16(1), 1},
+               {uint32(2), uint32(1), 1},
+               {uint64(2), uint64(1), 1},
+
+               {int(2), int(1), 1},
+               {int8(2), int8(1), 1},
+               {int16(2), int16(1), 1},
+               {int32(2), int32(1), 1},
+               {int64(2), int64(1), 1},
+
+               {float32(2), float32(1), 1},
+               {float64(2), float64(1), 1},
+       }
+
+       for _, tc := range cases {
+               True(t, InDelta(mockT, tc.a, tc.b, tc.delta), "Expected |%V - %V| <= %v", tc.a, tc.b, tc.delta)
+       }
+}
+
+func TestInDeltaSlice(t *testing.T) {
+       mockT := new(testing.T)
+
+       True(t, InDeltaSlice(mockT,
+               []float64{1.001, 0.999},
+               []float64{1, 1},
+               0.1), "{1.001, 0.009} is element-wise close to {1, 1} in delta=0.1")
+
+       True(t, InDeltaSlice(mockT,
+               []float64{1, 2},
+               []float64{0, 3},
+               1), "{1, 2} is element-wise close to {0, 3} in delta=1")
+
+       False(t, InDeltaSlice(mockT,
+               []float64{1, 2},
+               []float64{0, 3},
+               0.1), "{1, 2} is not element-wise close to {0, 3} in delta=0.1")
+
+       False(t, InDeltaSlice(mockT, "", nil, 1), "Expected non numeral slices to fail")
+}
+
+func TestInEpsilon(t *testing.T) {
+       mockT := new(testing.T)
+
+       cases := []struct {
+               a, b    interface{}
+               epsilon float64
+       }{
+               {uint8(2), uint16(2), .001},
+               {2.1, 2.2, 0.1},
+               {2.2, 2.1, 0.1},
+               {-2.1, -2.2, 0.1},
+               {-2.2, -2.1, 0.1},
+               {uint64(100), uint8(101), 0.01},
+               {0.1, -0.1, 2},
+               {0.1, 0, 2},
+       }
+
+       for _, tc := range cases {
+               True(t, InEpsilon(t, tc.a, tc.b, tc.epsilon, "Expected %V and %V to have a relative difference of %v", tc.a, tc.b, tc.epsilon), "test: %q", tc)
+       }
+
+       cases = []struct {
+               a, b    interface{}
+               epsilon float64
+       }{
+               {uint8(2), int16(-2), .001},
+               {uint64(100), uint8(102), 0.01},
+               {2.1, 2.2, 0.001},
+               {2.2, 2.1, 0.001},
+               {2.1, -2.2, 1},
+               {2.1, "bla-bla", 0},
+               {0.1, -0.1, 1.99},
+               {0, 0.1, 2}, // expected must be different to zero
+       }
+
+       for _, tc := range cases {
+               False(t, InEpsilon(mockT, tc.a, tc.b, tc.epsilon, "Expected %V and %V to have a relative difference of %v", tc.a, tc.b, tc.epsilon))
+       }
+
+}
+
+func TestInEpsilonSlice(t *testing.T) {
+       mockT := new(testing.T)
+
+       True(t, InEpsilonSlice(mockT,
+               []float64{2.2, 2.0},
+               []float64{2.1, 2.1},
+               0.06), "{2.2, 2.0} is element-wise close to {2.1, 2.1} in espilon=0.06")
+
+       False(t, InEpsilonSlice(mockT,
+               []float64{2.2, 2.0},
+               []float64{2.1, 2.1},
+               0.04), "{2.2, 2.0} is not element-wise close to {2.1, 2.1} in espilon=0.04")
+
+       False(t, InEpsilonSlice(mockT, "", nil, 1), "Expected non numeral slices to fail")
+}
+
+func TestRegexp(t *testing.T) {
+       mockT := new(testing.T)
+
+       cases := []struct {
+               rx, str string
+       }{
+               {"^start", "start of the line"},
+               {"end$", "in the end"},
+               {"[0-9]{3}[.-]?[0-9]{2}[.-]?[0-9]{2}", "My phone number is 650.12.34"},
+       }
+
+       for _, tc := range cases {
+               True(t, Regexp(mockT, tc.rx, tc.str))
+               True(t, Regexp(mockT, regexp.MustCompile(tc.rx), tc.str))
+               False(t, NotRegexp(mockT, tc.rx, tc.str))
+               False(t, NotRegexp(mockT, regexp.MustCompile(tc.rx), tc.str))
+       }
+
+       cases = []struct {
+               rx, str string
+       }{
+               {"^asdfastart", "Not the start of the line"},
+               {"end$", "in the end."},
+               {"[0-9]{3}[.-]?[0-9]{2}[.-]?[0-9]{2}", "My phone number is 650.12a.34"},
+       }
+
+       for _, tc := range cases {
+               False(t, Regexp(mockT, tc.rx, tc.str), "Expected \"%s\" to not match \"%s\"", tc.rx, tc.str)
+               False(t, Regexp(mockT, regexp.MustCompile(tc.rx), tc.str))
+               True(t, NotRegexp(mockT, tc.rx, tc.str))
+               True(t, NotRegexp(mockT, regexp.MustCompile(tc.rx), tc.str))
+       }
+}
+
+func testAutogeneratedFunction() {
+       defer func() {
+               if err := recover(); err == nil {
+                       panic("did not panic")
+               }
+               CallerInfo()
+       }()
+       t := struct {
+               io.Closer
+       }{}
+       var c io.Closer
+       c = t
+       c.Close()
+}
+
+func TestCallerInfoWithAutogeneratedFunctions(t *testing.T) {
+       NotPanics(t, func() {
+               testAutogeneratedFunction()
+       })
+}
+
+func TestZero(t *testing.T) {
+       mockT := new(testing.T)
+
+       for _, test := range zeros {
+               True(t, Zero(mockT, test, "%#v is not the %v zero value", test, reflect.TypeOf(test)))
+       }
+
+       for _, test := range nonZeros {
+               False(t, Zero(mockT, test, "%#v is not the %v zero value", test, reflect.TypeOf(test)))
+       }
+}
+
+func TestNotZero(t *testing.T) {
+       mockT := new(testing.T)
+
+       for _, test := range zeros {
+               False(t, NotZero(mockT, test, "%#v is not the %v zero value", test, reflect.TypeOf(test)))
+       }
+
+       for _, test := range nonZeros {
+               True(t, NotZero(mockT, test, "%#v is not the %v zero value", test, reflect.TypeOf(test)))
+       }
+}
+
+func TestJSONEq_EqualSONString(t *testing.T) {
+       mockT := new(testing.T)
+       True(t, JSONEq(mockT, `{"hello": "world", "foo": "bar"}`, `{"hello": "world", "foo": "bar"}`))
+}
+
+func TestJSONEq_EquivalentButNotEqual(t *testing.T) {
+       mockT := new(testing.T)
+       True(t, JSONEq(mockT, `{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`))
+}
+
+func TestJSONEq_HashOfArraysAndHashes(t *testing.T) {
+       mockT := new(testing.T)
+       True(t, JSONEq(mockT, "{\r\n\t\"numeric\": 1.5,\r\n\t\"array\": [{\"foo\": \"bar\"}, 1, \"string\", [\"nested\", \"array\", 5.5]],\r\n\t\"hash\": {\"nested\": \"hash\", \"nested_slice\": [\"this\", \"is\", \"nested\"]},\r\n\t\"string\": \"foo\"\r\n}",
+               "{\r\n\t\"numeric\": 1.5,\r\n\t\"hash\": {\"nested\": \"hash\", \"nested_slice\": [\"this\", \"is\", \"nested\"]},\r\n\t\"string\": \"foo\",\r\n\t\"array\": [{\"foo\": \"bar\"}, 1, \"string\", [\"nested\", \"array\", 5.5]]\r\n}"))
+}
+
+func TestJSONEq_Array(t *testing.T) {
+       mockT := new(testing.T)
+       True(t, JSONEq(mockT, `["foo", {"hello": "world", "nested": "hash"}]`, `["foo", {"nested": "hash", "hello": "world"}]`))
+}
+
+func TestJSONEq_HashAndArrayNotEquivalent(t *testing.T) {
+       mockT := new(testing.T)
+       False(t, JSONEq(mockT, `["foo", {"hello": "world", "nested": "hash"}]`, `{"foo": "bar", {"nested": "hash", "hello": "world"}}`))
+}
+
+func TestJSONEq_HashesNotEquivalent(t *testing.T) {
+       mockT := new(testing.T)
+       False(t, JSONEq(mockT, `{"foo": "bar"}`, `{"foo": "bar", "hello": "world"}`))
+}
+
+func TestJSONEq_ActualIsNotJSON(t *testing.T) {
+       mockT := new(testing.T)
+       False(t, JSONEq(mockT, `{"foo": "bar"}`, "Not JSON"))
+}
+
+func TestJSONEq_ExpectedIsNotJSON(t *testing.T) {
+       mockT := new(testing.T)
+       False(t, JSONEq(mockT, "Not JSON", `{"foo": "bar", "hello": "world"}`))
+}
+
+func TestJSONEq_ExpectedAndActualNotJSON(t *testing.T) {
+       mockT := new(testing.T)
+       False(t, JSONEq(mockT, "Not JSON", "Not JSON"))
+}
+
+func TestJSONEq_ArraysOfDifferentOrder(t *testing.T) {
+       mockT := new(testing.T)
+       False(t, JSONEq(mockT, `["foo", {"hello": "world", "nested": "hash"}]`, `[{ "hello": "world", "nested": "hash"}, "foo"]`))
+}
+
+func TestDiff(t *testing.T) {
+       expected := `
+
+Diff:
+--- Expected
++++ Actual
+@@ -1,3 +1,3 @@
+ (struct { foo string }) {
+- foo: (string) (len=5) "hello"
++ foo: (string) (len=3) "bar"
+ }
+`
+       actual := diff(
+               struct{ foo string }{"hello"},
+               struct{ foo string }{"bar"},
+       )
+       Equal(t, expected, actual)
+
+       expected = `
+
+Diff:
+--- Expected
++++ Actual
+@@ -2,5 +2,5 @@
+  (int) 1,
+- (int) 2,
+  (int) 3,
+- (int) 4
++ (int) 5,
++ (int) 7
+ }
+`
+       actual = diff(
+               []int{1, 2, 3, 4},
+               []int{1, 3, 5, 7},
+       )
+       Equal(t, expected, actual)
+
+       expected = `
+
+Diff:
+--- Expected
++++ Actual
+@@ -2,4 +2,4 @@
+  (int) 1,
+- (int) 2,
+- (int) 3
++ (int) 3,
++ (int) 5
+ }
+`
+       actual = diff(
+               []int{1, 2, 3, 4}[0:3],
+               []int{1, 3, 5, 7}[0:3],
+       )
+       Equal(t, expected, actual)
+
+       expected = `
+
+Diff:
+--- Expected
++++ Actual
+@@ -1,6 +1,6 @@
+ (map[string]int) (len=4) {
+- (string) (len=4) "four": (int) 4,
++ (string) (len=4) "five": (int) 5,
+  (string) (len=3) "one": (int) 1,
+- (string) (len=5) "three": (int) 3,
+- (string) (len=3) "two": (int) 2
++ (string) (len=5) "seven": (int) 7,
++ (string) (len=5) "three": (int) 3
+ }
+`
+
+       actual = diff(
+               map[string]int{"one": 1, "two": 2, "three": 3, "four": 4},
+               map[string]int{"one": 1, "three": 3, "five": 5, "seven": 7},
+       )
+       Equal(t, expected, actual)
+}
+
+func TestDiffEmptyCases(t *testing.T) {
+       Equal(t, "", diff(nil, nil))
+       Equal(t, "", diff(struct{ foo string }{}, nil))
+       Equal(t, "", diff(nil, struct{ foo string }{}))
+       Equal(t, "", diff(1, 2))
+       Equal(t, "", diff(1, 2))
+       Equal(t, "", diff([]int{1}, []bool{true}))
+}
+
+type mockTestingT struct {
+}
+
+func (m *mockTestingT) Errorf(format string, args ...interface{}) {}
+
+func TestFailNowWithPlainTestingT(t *testing.T) {
+       mockT := &mockTestingT{}
+
+       Panics(t, func() {
+               FailNow(mockT, "failed")
+       }, "should panic since mockT is missing FailNow()")
+}
+
+type mockFailNowTestingT struct {
+}
+
+func (m *mockFailNowTestingT) Errorf(format string, args ...interface{}) {}
+
+func (m *mockFailNowTestingT) FailNow() {}
+
+func TestFailNowWithFullTestingT(t *testing.T) {
+       mockT := &mockFailNowTestingT{}
+
+       NotPanics(t, func() {
+               FailNow(mockT, "failed")
+       }, "should call mockT.FailNow() rather than panicking")
+}
diff --git a/vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/assert/doc.go b/vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/assert/doc.go
new file mode 100644 (file)
index 0000000..c9dccc4
--- /dev/null
@@ -0,0 +1,45 @@
+// Package assert provides a set of comprehensive testing tools for use with the normal Go testing system.
+//
+// Example Usage
+//
+// The following is a complete example using assert in a standard test function:
+//    import (
+//      "testing"
+//      "github.com/stretchr/testify/assert"
+//    )
+//
+//    func TestSomething(t *testing.T) {
+//
+//      var a string = "Hello"
+//      var b string = "Hello"
+//
+//      assert.Equal(t, a, b, "The two words should be the same.")
+//
+//    }
+//
+// if you assert many times, use the format below:
+//
+//    import (
+//      "testing"
+//      "github.com/stretchr/testify/assert"
+//    )
+//
+//    func TestSomething(t *testing.T) {
+//      assert := assert.New(t)
+//
+//      var a string = "Hello"
+//      var b string = "Hello"
+//
+//      assert.Equal(a, b, "The two words should be the same.")
+//    }
+//
+// Assertions
+//
+// Assertions allow you to easily write test code, and are global funcs in the `assert` package.
+// All assertion functions take, as the first argument, the `*testing.T` object provided by the
+// testing framework. This allows the assertion funcs to write the failings and other details to
+// the correct place.
+//
+// Every assertion function also takes an optional string message as the final argument,
+// allowing custom error messages to be appended to the message the assertion method outputs.
+package assert
diff --git a/vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/assert/errors.go b/vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/assert/errors.go
new file mode 100644 (file)
index 0000000..ac9dc9d
--- /dev/null
@@ -0,0 +1,10 @@
+package assert
+
+import (
+       "errors"
+)
+
+// AnError is an error instance useful for testing.  If the code does not care
+// about error specifics, and only needs to return the error for example, this
+// error should be used to make the test code more readable.
+var AnError = errors.New("assert.AnError general error for testing")
diff --git a/vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/assert/forward_assertions.go b/vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/assert/forward_assertions.go
new file mode 100644 (file)
index 0000000..b867e95
--- /dev/null
@@ -0,0 +1,16 @@
+package assert
+
+// Assertions provides assertion methods around the
+// TestingT interface.
+type Assertions struct {
+       t TestingT
+}
+
+// New makes a new Assertions object for the specified TestingT.
+func New(t TestingT) *Assertions {
+       return &Assertions{
+               t: t,
+       }
+}
+
+//go:generate go run ../_codegen/main.go -output-package=assert -template=assertion_forward.go.tmpl
diff --git a/vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/assert/forward_assertions_test.go b/vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/assert/forward_assertions_test.go
new file mode 100644 (file)
index 0000000..22e1df1
--- /dev/null
@@ -0,0 +1,611 @@
+package assert
+
+import (
+       "errors"
+       "regexp"
+       "testing"
+       "time"
+)
+
+func TestImplementsWrapper(t *testing.T) {
+       assert := New(new(testing.T))
+
+       if !assert.Implements((*AssertionTesterInterface)(nil), new(AssertionTesterConformingObject)) {
+               t.Error("Implements method should return true: AssertionTesterConformingObject implements AssertionTesterInterface")
+       }
+       if assert.Implements((*AssertionTesterInterface)(nil), new(AssertionTesterNonConformingObject)) {
+               t.Error("Implements method should return false: AssertionTesterNonConformingObject does not implements AssertionTesterInterface")
+       }
+}
+
+func TestIsTypeWrapper(t *testing.T) {
+       assert := New(new(testing.T))
+
+       if !assert.IsType(new(AssertionTesterConformingObject), new(AssertionTesterConformingObject)) {
+               t.Error("IsType should return true: AssertionTesterConformingObject is the same type as AssertionTesterConformingObject")
+       }
+       if assert.IsType(new(AssertionTesterConformingObject), new(AssertionTesterNonConformingObject)) {
+               t.Error("IsType should return false: AssertionTesterConformingObject is not the same type as AssertionTesterNonConformingObject")
+       }
+
+}
+
+func TestEqualWrapper(t *testing.T) {
+       assert := New(new(testing.T))
+
+       if !assert.Equal("Hello World", "Hello World") {
+               t.Error("Equal should return true")
+       }
+       if !assert.Equal(123, 123) {
+               t.Error("Equal should return true")
+       }
+       if !assert.Equal(123.5, 123.5) {
+               t.Error("Equal should return true")
+       }
+       if !assert.Equal([]byte("Hello World"), []byte("Hello World")) {
+               t.Error("Equal should return true")
+       }
+       if !assert.Equal(nil, nil) {
+               t.Error("Equal should return true")
+       }
+}
+
+func TestEqualValuesWrapper(t *testing.T) {
+       assert := New(new(testing.T))
+
+       if !assert.EqualValues(uint32(10), int32(10)) {
+               t.Error("EqualValues should return true")
+       }
+}
+
+func TestNotNilWrapper(t *testing.T) {
+       assert := New(new(testing.T))
+
+       if !assert.NotNil(new(AssertionTesterConformingObject)) {
+               t.Error("NotNil should return true: object is not nil")
+       }
+       if assert.NotNil(nil) {
+               t.Error("NotNil should return false: object is nil")
+       }
+
+}
+
+func TestNilWrapper(t *testing.T) {
+       assert := New(new(testing.T))
+
+       if !assert.Nil(nil) {
+               t.Error("Nil should return true: object is nil")
+       }
+       if assert.Nil(new(AssertionTesterConformingObject)) {
+               t.Error("Nil should return false: object is not nil")
+       }
+
+}
+
+func TestTrueWrapper(t *testing.T) {
+       assert := New(new(testing.T))
+
+       if !assert.True(true) {
+               t.Error("True should return true")
+       }
+       if assert.True(false) {
+               t.Error("True should return false")
+       }
+
+}
+
+func TestFalseWrapper(t *testing.T) {
+       assert := New(new(testing.T))
+
+       if !assert.False(false) {
+               t.Error("False should return true")
+       }
+       if assert.False(true) {
+               t.Error("False should return false")
+       }
+
+}
+
+func TestExactlyWrapper(t *testing.T) {
+       assert := New(new(testing.T))
+
+       a := float32(1)
+       b := float64(1)
+       c := float32(1)
+       d := float32(2)
+
+       if assert.Exactly(a, b) {
+               t.Error("Exactly should return false")
+       }
+       if assert.Exactly(a, d) {
+               t.Error("Exactly should return false")
+       }
+       if !assert.Exactly(a, c) {
+               t.Error("Exactly should return true")
+       }
+
+       if assert.Exactly(nil, a) {
+               t.Error("Exactly should return false")
+       }
+       if assert.Exactly(a, nil) {
+               t.Error("Exactly should return false")
+       }
+
+}
+
+func TestNotEqualWrapper(t *testing.T) {
+
+       assert := New(new(testing.T))
+
+       if !assert.NotEqual("Hello World", "Hello World!") {
+               t.Error("NotEqual should return true")
+       }
+       if !assert.NotEqual(123, 1234) {
+               t.Error("NotEqual should return true")
+       }
+       if !assert.NotEqual(123.5, 123.55) {
+               t.Error("NotEqual should return true")
+       }
+       if !assert.NotEqual([]byte("Hello World"), []byte("Hello World!")) {
+               t.Error("NotEqual should return true")
+       }
+       if !assert.NotEqual(nil, new(AssertionTesterConformingObject)) {
+               t.Error("NotEqual should return true")
+       }
+}
+
+func TestContainsWrapper(t *testing.T) {
+
+       assert := New(new(testing.T))
+       list := []string{"Foo", "Bar"}
+
+       if !assert.Contains("Hello World", "Hello") {
+               t.Error("Contains should return true: \"Hello World\" contains \"Hello\"")
+       }
+       if assert.Contains("Hello World", "Salut") {
+               t.Error("Contains should return false: \"Hello World\" does not contain \"Salut\"")
+       }
+
+       if !assert.Contains(list, "Foo") {
+               t.Error("Contains should return true: \"[\"Foo\", \"Bar\"]\" contains \"Foo\"")
+       }
+       if assert.Contains(list, "Salut") {
+               t.Error("Contains should return false: \"[\"Foo\", \"Bar\"]\" does not contain \"Salut\"")
+       }
+
+}
+
+func TestNotContainsWrapper(t *testing.T) {
+
+       assert := New(new(testing.T))
+       list := []string{"Foo", "Bar"}
+
+       if !assert.NotContains("Hello World", "Hello!") {
+               t.Error("NotContains should return true: \"Hello World\" does not contain \"Hello!\"")
+       }
+       if assert.NotContains("Hello World", "Hello") {
+               t.Error("NotContains should return false: \"Hello World\" contains \"Hello\"")
+       }
+
+       if !assert.NotContains(list, "Foo!") {
+               t.Error("NotContains should return true: \"[\"Foo\", \"Bar\"]\" does not contain \"Foo!\"")
+       }
+       if assert.NotContains(list, "Foo") {
+               t.Error("NotContains should return false: \"[\"Foo\", \"Bar\"]\" contains \"Foo\"")
+       }
+
+}
+
+func TestConditionWrapper(t *testing.T) {
+
+       assert := New(new(testing.T))
+
+       if !assert.Condition(func() bool { return true }, "Truth") {
+               t.Error("Condition should return true")
+       }
+
+       if assert.Condition(func() bool { return false }, "Lie") {
+               t.Error("Condition should return false")
+       }
+
+}
+
+func TestDidPanicWrapper(t *testing.T) {
+
+       if funcDidPanic, _ := didPanic(func() {
+               panic("Panic!")
+       }); !funcDidPanic {
+               t.Error("didPanic should return true")
+       }
+
+       if funcDidPanic, _ := didPanic(func() {
+       }); funcDidPanic {
+               t.Error("didPanic should return false")
+       }
+
+}
+
+func TestPanicsWrapper(t *testing.T) {
+
+       assert := New(new(testing.T))
+
+       if !assert.Panics(func() {
+               panic("Panic!")
+       }) {
+               t.Error("Panics should return true")
+       }
+
+       if assert.Panics(func() {
+       }) {
+               t.Error("Panics should return false")
+       }
+
+}
+
+func TestNotPanicsWrapper(t *testing.T) {
+
+       assert := New(new(testing.T))
+
+       if !assert.NotPanics(func() {
+       }) {
+               t.Error("NotPanics should return true")
+       }
+
+       if assert.NotPanics(func() {
+               panic("Panic!")
+       }) {
+               t.Error("NotPanics should return false")
+       }
+
+}
+
+func TestNoErrorWrapper(t *testing.T) {
+       assert := New(t)
+       mockAssert := New(new(testing.T))
+
+       // start with a nil error
+       var err error
+
+       assert.True(mockAssert.NoError(err), "NoError should return True for nil arg")
+
+       // now set an error
+       err = errors.New("Some error")
+
+       assert.False(mockAssert.NoError(err), "NoError with error should return False")
+
+}
+
+func TestErrorWrapper(t *testing.T) {
+       assert := New(t)
+       mockAssert := New(new(testing.T))
+
+       // start with a nil error
+       var err error
+
+       assert.False(mockAssert.Error(err), "Error should return False for nil arg")
+
+       // now set an error
+       err = errors.New("Some error")
+
+       assert.True(mockAssert.Error(err), "Error with error should return True")
+
+}
+
+func TestEqualErrorWrapper(t *testing.T) {
+       assert := New(t)
+       mockAssert := New(new(testing.T))
+
+       // start with a nil error
+       var err error
+       assert.False(mockAssert.EqualError(err, ""),
+               "EqualError should return false for nil arg")
+
+       // now set an error
+       err = errors.New("some error")
+       assert.False(mockAssert.EqualError(err, "Not some error"),
+               "EqualError should return false for different error string")
+       assert.True(mockAssert.EqualError(err, "some error"),
+               "EqualError should return true")
+}
+
+func TestEmptyWrapper(t *testing.T) {
+       assert := New(t)
+       mockAssert := New(new(testing.T))
+
+       assert.True(mockAssert.Empty(""), "Empty string is empty")
+       assert.True(mockAssert.Empty(nil), "Nil is empty")
+       assert.True(mockAssert.Empty([]string{}), "Empty string array is empty")
+       assert.True(mockAssert.Empty(0), "Zero int value is empty")
+       assert.True(mockAssert.Empty(false), "False value is empty")
+
+       assert.False(mockAssert.Empty("something"), "Non Empty string is not empty")
+       assert.False(mockAssert.Empty(errors.New("something")), "Non nil object is not empty")
+       assert.False(mockAssert.Empty([]string{"something"}), "Non empty string array is not empty")
+       assert.False(mockAssert.Empty(1), "Non-zero int value is not empty")
+       assert.False(mockAssert.Empty(true), "True value is not empty")
+
+}
+
+func TestNotEmptyWrapper(t *testing.T) {
+       assert := New(t)
+       mockAssert := New(new(testing.T))
+
+       assert.False(mockAssert.NotEmpty(""), "Empty string is empty")
+       assert.False(mockAssert.NotEmpty(nil), "Nil is empty")
+       assert.False(mockAssert.NotEmpty([]string{}), "Empty string array is empty")
+       assert.False(mockAssert.NotEmpty(0), "Zero int value is empty")
+       assert.False(mockAssert.NotEmpty(false), "False value is empty")
+
+       assert.True(mockAssert.NotEmpty("something"), "Non Empty string is not empty")
+       assert.True(mockAssert.NotEmpty(errors.New("something")), "Non nil object is not empty")
+       assert.True(mockAssert.NotEmpty([]string{"something"}), "Non empty string array is not empty")
+       assert.True(mockAssert.NotEmpty(1), "Non-zero int value is not empty")
+       assert.True(mockAssert.NotEmpty(true), "True value is not empty")
+
+}
+
+func TestLenWrapper(t *testing.T) {
+       assert := New(t)
+       mockAssert := New(new(testing.T))
+
+       assert.False(mockAssert.Len(nil, 0), "nil does not have length")
+       assert.False(mockAssert.Len(0, 0), "int does not have length")
+       assert.False(mockAssert.Len(true, 0), "true does not have length")
+       assert.False(mockAssert.Len(false, 0), "false does not have length")
+       assert.False(mockAssert.Len('A', 0), "Rune does not have length")
+       assert.False(mockAssert.Len(struct{}{}, 0), "Struct does not have length")
+
+       ch := make(chan int, 5)
+       ch <- 1
+       ch <- 2
+       ch <- 3
+
+       cases := []struct {
+               v interface{}
+               l int
+       }{
+               {[]int{1, 2, 3}, 3},
+               {[...]int{1, 2, 3}, 3},
+               {"ABC", 3},
+               {map[int]int{1: 2, 2: 4, 3: 6}, 3},
+               {ch, 3},
+
+               {[]int{}, 0},
+               {map[int]int{}, 0},
+               {make(chan int), 0},
+
+               {[]int(nil), 0},
+               {map[int]int(nil), 0},
+               {(chan int)(nil), 0},
+       }
+
+       for _, c := range cases {
+               assert.True(mockAssert.Len(c.v, c.l), "%#v have %d items", c.v, c.l)
+       }
+}
+
+func TestWithinDurationWrapper(t *testing.T) {
+       assert := New(t)
+       mockAssert := New(new(testing.T))
+       a := time.Now()
+       b := a.Add(10 * time.Second)
+
+       assert.True(mockAssert.WithinDuration(a, b, 10*time.Second), "A 10s difference is within a 10s time difference")
+       assert.True(mockAssert.WithinDuration(b, a, 10*time.Second), "A 10s difference is within a 10s time difference")
+
+       assert.False(mockAssert.WithinDuration(a, b, 9*time.Second), "A 10s difference is not within a 9s time difference")
+       assert.False(mockAssert.WithinDuration(b, a, 9*time.Second), "A 10s difference is not within a 9s time difference")
+
+       assert.False(mockAssert.WithinDuration(a, b, -9*time.Second), "A 10s difference is not within a 9s time difference")
+       assert.False(mockAssert.WithinDuration(b, a, -9*time.Second), "A 10s difference is not within a 9s time difference")
+
+       assert.False(mockAssert.WithinDuration(a, b, -11*time.Second), "A 10s difference is not within a 9s time difference")
+       assert.False(mockAssert.WithinDuration(b, a, -11*time.Second), "A 10s difference is not within a 9s time difference")
+}
+
+func TestInDeltaWrapper(t *testing.T) {
+       assert := New(new(testing.T))
+
+       True(t, assert.InDelta(1.001, 1, 0.01), "|1.001 - 1| <= 0.01")
+       True(t, assert.InDelta(1, 1.001, 0.01), "|1 - 1.001| <= 0.01")
+       True(t, assert.InDelta(1, 2, 1), "|1 - 2| <= 1")
+       False(t, assert.InDelta(1, 2, 0.5), "Expected |1 - 2| <= 0.5 to fail")
+       False(t, assert.InDelta(2, 1, 0.5), "Expected |2 - 1| <= 0.5 to fail")
+       False(t, assert.InDelta("", nil, 1), "Expected non numerals to fail")
+
+       cases := []struct {
+               a, b  interface{}
+               delta float64
+       }{
+               {uint8(2), uint8(1), 1},
+               {uint16(2), uint16(1), 1},
+               {uint32(2), uint32(1), 1},
+               {uint64(2), uint64(1), 1},
+
+               {int(2), int(1), 1},
+               {int8(2), int8(1), 1},
+               {int16(2), int16(1), 1},
+               {int32(2), int32(1), 1},
+               {int64(2), int64(1), 1},
+
+               {float32(2), float32(1), 1},
+               {float64(2), float64(1), 1},
+       }
+
+       for _, tc := range cases {
+               True(t, assert.InDelta(tc.a, tc.b, tc.delta), "Expected |%V - %V| <= %v", tc.a, tc.b, tc.delta)
+       }
+}
+
+func TestInEpsilonWrapper(t *testing.T) {
+       assert := New(new(testing.T))
+
+       cases := []struct {
+               a, b    interface{}
+               epsilon float64
+       }{
+               {uint8(2), uint16(2), .001},
+               {2.1, 2.2, 0.1},
+               {2.2, 2.1, 0.1},
+               {-2.1, -2.2, 0.1},
+               {-2.2, -2.1, 0.1},
+               {uint64(100), uint8(101), 0.01},
+               {0.1, -0.1, 2},
+       }
+
+       for _, tc := range cases {
+               True(t, assert.InEpsilon(tc.a, tc.b, tc.epsilon, "Expected %V and %V to have a relative difference of %v", tc.a, tc.b, tc.epsilon))
+       }
+
+       cases = []struct {
+               a, b    interface{}
+               epsilon float64
+       }{
+               {uint8(2), int16(-2), .001},
+               {uint64(100), uint8(102), 0.01},
+               {2.1, 2.2, 0.001},
+               {2.2, 2.1, 0.001},
+               {2.1, -2.2, 1},
+               {2.1, "bla-bla", 0},
+               {0.1, -0.1, 1.99},
+       }
+
+       for _, tc := range cases {
+               False(t, assert.InEpsilon(tc.a, tc.b, tc.epsilon, "Expected %V and %V to have a relative difference of %v", tc.a, tc.b, tc.epsilon))
+       }
+}
+
+func TestRegexpWrapper(t *testing.T) {
+
+       assert := New(new(testing.T))
+
+       cases := []struct {
+               rx, str string
+       }{
+               {"^start", "start of the line"},
+               {"end$", "in the end"},
+               {"[0-9]{3}[.-]?[0-9]{2}[.-]?[0-9]{2}", "My phone number is 650.12.34"},
+       }
+
+       for _, tc := range cases {
+               True(t, assert.Regexp(tc.rx, tc.str))
+               True(t, assert.Regexp(regexp.MustCompile(tc.rx), tc.str))
+               False(t, assert.NotRegexp(tc.rx, tc.str))
+               False(t, assert.NotRegexp(regexp.MustCompile(tc.rx), tc.str))
+       }
+
+       cases = []struct {
+               rx, str string
+       }{
+               {"^asdfastart", "Not the start of the line"},
+               {"end$", "in the end."},
+               {"[0-9]{3}[.-]?[0-9]{2}[.-]?[0-9]{2}", "My phone number is 650.12a.34"},
+       }
+
+       for _, tc := range cases {
+               False(t, assert.Regexp(tc.rx, tc.str), "Expected \"%s\" to not match \"%s\"", tc.rx, tc.str)
+               False(t, assert.Regexp(regexp.MustCompile(tc.rx), tc.str))
+               True(t, assert.NotRegexp(tc.rx, tc.str))
+               True(t, assert.NotRegexp(regexp.MustCompile(tc.rx), tc.str))
+       }
+}
+
+func TestZeroWrapper(t *testing.T) {
+       assert := New(t)
+       mockAssert := New(new(testing.T))
+
+       for _, test := range zeros {
+               assert.True(mockAssert.Zero(test), "Zero should return true for %v", test)
+       }
+
+       for _, test := range nonZeros {
+               assert.False(mockAssert.Zero(test), "Zero should return false for %v", test)
+       }
+}
+
+func TestNotZeroWrapper(t *testing.T) {
+       assert := New(t)
+       mockAssert := New(new(testing.T))
+
+       for _, test := range zeros {
+               assert.False(mockAssert.NotZero(test), "Zero should return true for %v", test)
+       }
+
+       for _, test := range nonZeros {
+               assert.True(mockAssert.NotZero(test), "Zero should return false for %v", test)
+       }
+}
+
+func TestJSONEqWrapper_EqualSONString(t *testing.T) {
+       assert := New(new(testing.T))
+       if !assert.JSONEq(`{"hello": "world", "foo": "bar"}`, `{"hello": "world", "foo": "bar"}`) {
+               t.Error("JSONEq should return true")
+       }
+
+}
+
+func TestJSONEqWrapper_EquivalentButNotEqual(t *testing.T) {
+       assert := New(new(testing.T))
+       if !assert.JSONEq(`{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`) {
+               t.Error("JSONEq should return true")
+       }
+
+}
+
+func TestJSONEqWrapper_HashOfArraysAndHashes(t *testing.T) {
+       assert := New(new(testing.T))
+       if !assert.JSONEq("{\r\n\t\"numeric\": 1.5,\r\n\t\"array\": [{\"foo\": \"bar\"}, 1, \"string\", [\"nested\", \"array\", 5.5]],\r\n\t\"hash\": {\"nested\": \"hash\", \"nested_slice\": [\"this\", \"is\", \"nested\"]},\r\n\t\"string\": \"foo\"\r\n}",
+               "{\r\n\t\"numeric\": 1.5,\r\n\t\"hash\": {\"nested\": \"hash\", \"nested_slice\": [\"this\", \"is\", \"nested\"]},\r\n\t\"string\": \"foo\",\r\n\t\"array\": [{\"foo\": \"bar\"}, 1, \"string\", [\"nested\", \"array\", 5.5]]\r\n}") {
+               t.Error("JSONEq should return true")
+       }
+}
+
+func TestJSONEqWrapper_Array(t *testing.T) {
+       assert := New(new(testing.T))
+       if !assert.JSONEq(`["foo", {"hello": "world", "nested": "hash"}]`, `["foo", {"nested": "hash", "hello": "world"}]`) {
+               t.Error("JSONEq should return true")
+       }
+
+}
+
+func TestJSONEqWrapper_HashAndArrayNotEquivalent(t *testing.T) {
+       assert := New(new(testing.T))
+       if assert.JSONEq(`["foo", {"hello": "world", "nested": "hash"}]`, `{"foo": "bar", {"nested": "hash", "hello": "world"}}`) {
+               t.Error("JSONEq should return false")
+       }
+}
+
+func TestJSONEqWrapper_HashesNotEquivalent(t *testing.T) {
+       assert := New(new(testing.T))
+       if assert.JSONEq(`{"foo": "bar"}`, `{"foo": "bar", "hello": "world"}`) {
+               t.Error("JSONEq should return false")
+       }
+}
+
+func TestJSONEqWrapper_ActualIsNotJSON(t *testing.T) {
+       assert := New(new(testing.T))
+       if assert.JSONEq(`{"foo": "bar"}`, "Not JSON") {
+               t.Error("JSONEq should return false")
+       }
+}
+
+func TestJSONEqWrapper_ExpectedIsNotJSON(t *testing.T) {
+       assert := New(new(testing.T))
+       if assert.JSONEq("Not JSON", `{"foo": "bar", "hello": "world"}`) {
+               t.Error("JSONEq should return false")
+       }
+}
+
+func TestJSONEqWrapper_ExpectedAndActualNotJSON(t *testing.T) {
+       assert := New(new(testing.T))
+       if assert.JSONEq("Not JSON", "Not JSON") {
+               t.Error("JSONEq should return false")
+       }
+}
+
+func TestJSONEqWrapper_ArraysOfDifferentOrder(t *testing.T) {
+       assert := New(new(testing.T))
+       if assert.JSONEq(`["foo", {"hello": "world", "nested": "hash"}]`, `[{ "hello": "world", "nested": "hash"}, "foo"]`) {
+               t.Error("JSONEq should return false")
+       }
+}
diff --git a/vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/assert/http_assertions.go b/vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/assert/http_assertions.go
new file mode 100644 (file)
index 0000000..e1b9442
--- /dev/null
@@ -0,0 +1,106 @@
+package assert
+
+import (
+       "fmt"
+       "net/http"
+       "net/http/httptest"
+       "net/url"
+       "strings"
+)
+
+// httpCode is a helper that returns HTTP code of the response. It returns -1
+// if building a new request fails.
+func httpCode(handler http.HandlerFunc, method, url string, values url.Values) int {
+       w := httptest.NewRecorder()
+       req, err := http.NewRequest(method, url+"?"+values.Encode(), nil)
+       if err != nil {
+               return -1
+       }
+       handler(w, req)
+       return w.Code
+}
+
+// HTTPSuccess asserts that a specified handler returns a success status code.
+//
+//  assert.HTTPSuccess(t, myHandler, "POST", "http://www.google.com", nil)
+//
+// Returns whether the assertion was successful (true) or not (false).
+func HTTPSuccess(t TestingT, handler http.HandlerFunc, method, url string, values url.Values) bool {
+       code := httpCode(handler, method, url, values)
+       if code == -1 {
+               return false
+       }
+       return code >= http.StatusOK && code <= http.StatusPartialContent
+}
+
+// HTTPRedirect asserts that a specified handler returns a redirect status code.
+//
+//  assert.HTTPRedirect(t, myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}}
+//
+// Returns whether the assertion was successful (true) or not (false).
+func HTTPRedirect(t TestingT, handler http.HandlerFunc, method, url string, values url.Values) bool {
+       code := httpCode(handler, method, url, values)
+       if code == -1 {
+               return false
+       }
+       return code >= http.StatusMultipleChoices && code <= http.StatusTemporaryRedirect
+}
+
+// HTTPError asserts that a specified handler returns an error status code.
+//
+//  assert.HTTPError(t, myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}}
+//
+// Returns whether the assertion was successful (true) or not (false).
+func HTTPError(t TestingT, handler http.HandlerFunc, method, url string, values url.Values) bool {
+       code := httpCode(handler, method, url, values)
+       if code == -1 {
+               return false
+       }
+       return code >= http.StatusBadRequest
+}
+
+// HTTPBody is a helper that returns HTTP body of the response. It returns
+// empty string if building a new request fails.
+func HTTPBody(handler http.HandlerFunc, method, url string, values url.Values) string {
+       w := httptest.NewRecorder()
+       req, err := http.NewRequest(method, url+"?"+values.Encode(), nil)
+       if err != nil {
+               return ""
+       }
+       handler(w, req)
+       return w.Body.String()
+}
+
+// HTTPBodyContains asserts that a specified handler returns a
+// body that contains a string.
+//
+//  assert.HTTPBodyContains(t, myHandler, "www.google.com", nil, "I'm Feeling Lucky")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func HTTPBodyContains(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, str interface{}) bool {
+       body := HTTPBody(handler, method, url, values)
+
+       contains := strings.Contains(body, fmt.Sprint(str))
+       if !contains {
+               Fail(t, fmt.Sprintf("Expected response body for \"%s\" to contain \"%s\" but found \"%s\"", url+"?"+values.Encode(), str, body))
+       }
+
+       return contains
+}
+
+// HTTPBodyNotContains asserts that a specified handler returns a
+// body that does not contain a string.
+//
+//  assert.HTTPBodyNotContains(t, myHandler, "www.google.com", nil, "I'm Feeling Lucky")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func HTTPBodyNotContains(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, str interface{}) bool {
+       body := HTTPBody(handler, method, url, values)
+
+       contains := strings.Contains(body, fmt.Sprint(str))
+       if contains {
+               Fail(t, "Expected response body for %s to NOT contain \"%s\" but found \"%s\"", url+"?"+values.Encode(), str, body)
+       }
+
+       return !contains
+}
diff --git a/vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/assert/http_assertions_test.go b/vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/assert/http_assertions_test.go
new file mode 100644 (file)
index 0000000..684c2d5
--- /dev/null
@@ -0,0 +1,86 @@
+package assert
+
+import (
+       "fmt"
+       "net/http"
+       "net/url"
+       "testing"
+)
+
+func httpOK(w http.ResponseWriter, r *http.Request) {
+       w.WriteHeader(http.StatusOK)
+}
+
+func httpRedirect(w http.ResponseWriter, r *http.Request) {
+       w.WriteHeader(http.StatusTemporaryRedirect)
+}
+
+func httpError(w http.ResponseWriter, r *http.Request) {
+       w.WriteHeader(http.StatusInternalServerError)
+}
+
+func TestHTTPStatuses(t *testing.T) {
+       assert := New(t)
+       mockT := new(testing.T)
+
+       assert.Equal(HTTPSuccess(mockT, httpOK, "GET", "/", nil), true)
+       assert.Equal(HTTPSuccess(mockT, httpRedirect, "GET", "/", nil), false)
+       assert.Equal(HTTPSuccess(mockT, httpError, "GET", "/", nil), false)
+
+       assert.Equal(HTTPRedirect(mockT, httpOK, "GET", "/", nil), false)
+       assert.Equal(HTTPRedirect(mockT, httpRedirect, "GET", "/", nil), true)
+       assert.Equal(HTTPRedirect(mockT, httpError, "GET", "/", nil), false)
+
+       assert.Equal(HTTPError(mockT, httpOK, "GET", "/", nil), false)
+       assert.Equal(HTTPError(mockT, httpRedirect, "GET", "/", nil), false)
+       assert.Equal(HTTPError(mockT, httpError, "GET", "/", nil), true)
+}
+
+func TestHTTPStatusesWrapper(t *testing.T) {
+       assert := New(t)
+       mockAssert := New(new(testing.T))
+
+       assert.Equal(mockAssert.HTTPSuccess(httpOK, "GET", "/", nil), true)
+       assert.Equal(mockAssert.HTTPSuccess(httpRedirect, "GET", "/", nil), false)
+       assert.Equal(mockAssert.HTTPSuccess(httpError, "GET", "/", nil), false)
+
+       assert.Equal(mockAssert.HTTPRedirect(httpOK, "GET", "/", nil), false)
+       assert.Equal(mockAssert.HTTPRedirect(httpRedirect, "GET", "/", nil), true)
+       assert.Equal(mockAssert.HTTPRedirect(httpError, "GET", "/", nil), false)
+
+       assert.Equal(mockAssert.HTTPError(httpOK, "GET", "/", nil), false)
+       assert.Equal(mockAssert.HTTPError(httpRedirect, "GET", "/", nil), false)
+       assert.Equal(mockAssert.HTTPError(httpError, "GET", "/", nil), true)
+}
+
+func httpHelloName(w http.ResponseWriter, r *http.Request) {
+       name := r.FormValue("name")
+       w.Write([]byte(fmt.Sprintf("Hello, %s!", name)))
+}
+
+func TestHttpBody(t *testing.T) {
+       assert := New(t)
+       mockT := new(testing.T)
+
+       assert.True(HTTPBodyContains(mockT, httpHelloName, "GET", "/", url.Values{"name": []string{"World"}}, "Hello, World!"))
+       assert.True(HTTPBodyContains(mockT, httpHelloName, "GET", "/", url.Values{"name": []string{"World"}}, "World"))
+       assert.False(HTTPBodyContains(mockT, httpHelloName, "GET", "/", url.Values{"name": []string{"World"}}, "world"))
+
+       assert.False(HTTPBodyNotContains(mockT, httpHelloName, "GET", "/", url.Values{"name": []string{"World"}}, "Hello, World!"))
+       assert.False(HTTPBodyNotContains(mockT, httpHelloName, "GET", "/", url.Values{"name": []string{"World"}}, "World"))
+       assert.True(HTTPBodyNotContains(mockT, httpHelloName, "GET", "/", url.Values{"name": []string{"World"}}, "world"))
+}
+
+func TestHttpBodyWrappers(t *testing.T) {
+       assert := New(t)
+       mockAssert := New(new(testing.T))
+
+       assert.True(mockAssert.HTTPBodyContains(httpHelloName, "GET", "/", url.Values{"name": []string{"World"}}, "Hello, World!"))
+       assert.True(mockAssert.HTTPBodyContains(httpHelloName, "GET", "/", url.Values{"name": []string{"World"}}, "World"))
+       assert.False(mockAssert.HTTPBodyContains(httpHelloName, "GET", "/", url.Values{"name": []string{"World"}}, "world"))
+
+       assert.False(mockAssert.HTTPBodyNotContains(httpHelloName, "GET", "/", url.Values{"name": []string{"World"}}, "Hello, World!"))
+       assert.False(mockAssert.HTTPBodyNotContains(httpHelloName, "GET", "/", url.Values{"name": []string{"World"}}, "World"))
+       assert.True(mockAssert.HTTPBodyNotContains(httpHelloName, "GET", "/", url.Values{"name": []string{"World"}}, "world"))
+
+}
diff --git a/vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/doc.go b/vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/doc.go
new file mode 100644 (file)
index 0000000..377d5cc
--- /dev/null
@@ -0,0 +1,22 @@
+// Package testify is a set of packages that provide many tools for testifying that your code will behave as you intend.
+//
+// testify contains the following packages:
+//
+// The assert package provides a comprehensive set of assertion functions that tie in to the Go testing system.
+//
+// The http package contains tools to make it easier to test http activity using the Go testing system.
+//
+// The mock package provides a system by which it is possible to mock your objects and verify calls are happening as expected.
+//
+// The suite package provides a basic structure for using structs as testing suites, and methods on those structs as tests.  It includes setup/teardown functionality in the way of interfaces.
+package testify
+
+// blank imports help docs.
+import (
+       // assert package
+       _ "github.com/stretchr/testify/assert"
+       // http package
+       _ "github.com/stretchr/testify/http"
+       // mock package
+       _ "github.com/stretchr/testify/mock"
+)
diff --git a/vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/http/doc.go b/vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/http/doc.go
new file mode 100644 (file)
index 0000000..695167c
--- /dev/null
@@ -0,0 +1,2 @@
+// Package http DEPRECATED USE net/http/httptest
+package http
diff --git a/vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/http/test_response_writer.go b/vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/http/test_response_writer.go
new file mode 100644 (file)
index 0000000..5c3f813
--- /dev/null
@@ -0,0 +1,49 @@
+package http
+
+import (
+       "net/http"
+)
+
+// TestResponseWriter DEPRECATED: We recommend you use http://golang.org/pkg/net/http/httptest instead.
+type TestResponseWriter struct {
+
+       // StatusCode is the last int written by the call to WriteHeader(int)
+       StatusCode int
+
+       // Output is a string containing the written bytes using the Write([]byte) func.
+       Output string
+
+       // header is the internal storage of the http.Header object
+       header http.Header
+}
+
+// Header DEPRECATED: We recommend you use http://golang.org/pkg/net/http/httptest instead.
+func (rw *TestResponseWriter) Header() http.Header {
+
+       if rw.header == nil {
+               rw.header = make(http.Header)
+       }
+
+       return rw.header
+}
+
+// Write DEPRECATED: We recommend you use http://golang.org/pkg/net/http/httptest instead.
+func (rw *TestResponseWriter) Write(bytes []byte) (int, error) {
+
+       // assume 200 success if no header has been set
+       if rw.StatusCode == 0 {
+               rw.WriteHeader(200)
+       }
+
+       // add these bytes to the output string
+       rw.Output = rw.Output + string(bytes)
+
+       // return normal values
+       return 0, nil
+
+}
+
+// WriteHeader DEPRECATED: We recommend you use http://golang.org/pkg/net/http/httptest instead.
+func (rw *TestResponseWriter) WriteHeader(i int) {
+       rw.StatusCode = i
+}
diff --git a/vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/http/test_round_tripper.go b/vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/http/test_round_tripper.go
new file mode 100644 (file)
index 0000000..b1e32f1
--- /dev/null
@@ -0,0 +1,17 @@
+package http
+
+import (
+       "github.com/stretchr/testify/mock"
+       "net/http"
+)
+
+// TestRoundTripper DEPRECATED USE net/http/httptest
+type TestRoundTripper struct {
+       mock.Mock
+}
+
+// RoundTrip DEPRECATED USE net/http/httptest
+func (t *TestRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
+       args := t.Called(req)
+       return args.Get(0).(*http.Response), args.Error(1)
+}
diff --git a/vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/mock/doc.go b/vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/mock/doc.go
new file mode 100644 (file)
index 0000000..7324128
--- /dev/null
@@ -0,0 +1,44 @@
+// Package mock provides a system by which it is possible to mock your objects
+// and verify calls are happening as expected.
+//
+// Example Usage
+//
+// The mock package provides an object, Mock, that tracks activity on another object.  It is usually
+// embedded into a test object as shown below:
+//
+//   type MyTestObject struct {
+//     // add a Mock object instance
+//     mock.Mock
+//
+//     // other fields go here as normal
+//   }
+//
+// When implementing the methods of an interface, you wire your functions up
+// to call the Mock.Called(args...) method, and return the appropriate values.
+//
+// For example, to mock a method that saves the name and age of a person and returns
+// the year of their birth or an error, you might write this:
+//
+//     func (o *MyTestObject) SavePersonDetails(firstname, lastname string, age int) (int, error) {
+//       args := o.Called(firstname, lastname, age)
+//       return args.Int(0), args.Error(1)
+//     }
+//
+// The Int, Error and Bool methods are examples of strongly typed getters that take the argument
+// index position. Given this argument list:
+//
+//     (12, true, "Something")
+//
+// You could read them out strongly typed like this:
+//
+//     args.Int(0)
+//     args.Bool(1)
+//     args.String(2)
+//
+// For objects of your own type, use the generic Arguments.Get(index) method and make a type assertion:
+//
+//     return args.Get(0).(*MyObject), args.Get(1).(*AnotherObjectOfMine)
+//
+// This may cause a panic if the object you are getting is nil (the type assertion will fail), in those
+// cases you should check for nil first.
+package mock
diff --git a/vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/mock/mock.go b/vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/mock/mock.go
new file mode 100644 (file)
index 0000000..cba9009
--- /dev/null
@@ -0,0 +1,693 @@
+package mock
+
+import (
+       "fmt"
+       "reflect"
+       "regexp"
+       "runtime"
+       "strings"
+       "sync"
+       "time"
+
+       "github.com/stretchr/objx"
+       "github.com/stretchr/testify/assert"
+)
+
+// TestingT is an interface wrapper around *testing.T
+type TestingT interface {
+       Logf(format string, args ...interface{})
+       Errorf(format string, args ...interface{})
+       FailNow()
+}
+
+/*
+       Call
+*/
+
+// Call represents a method call and is used for setting expectations,
+// as well as recording activity.
+type Call struct {
+       Parent *Mock
+
+       // The name of the method that was or will be called.
+       Method string
+
+       // Holds the arguments of the method.
+       Arguments Arguments
+
+       // Holds the arguments that should be returned when
+       // this method is called.
+       ReturnArguments Arguments
+
+       // The number of times to return the return arguments when setting
+       // expectations. 0 means to always return the value.
+       Repeatability int
+
+       // Amount of times this call has been called
+       totalCalls int
+
+       // Holds a channel that will be used to block the Return until it either
+       // recieves a message or is closed. nil means it returns immediately.
+       WaitFor <-chan time.Time
+
+       // Holds a handler used to manipulate arguments content that are passed by
+       // reference. It's useful when mocking methods such as unmarshalers or
+       // decoders.
+       RunFn func(Arguments)
+}
+
+func newCall(parent *Mock, methodName string, methodArguments ...interface{}) *Call {
+       return &Call{
+               Parent:          parent,
+               Method:          methodName,
+               Arguments:       methodArguments,
+               ReturnArguments: make([]interface{}, 0),
+               Repeatability:   0,
+               WaitFor:         nil,
+               RunFn:           nil,
+       }
+}
+
+func (c *Call) lock() {
+       c.Parent.mutex.Lock()
+}
+
+func (c *Call) unlock() {
+       c.Parent.mutex.Unlock()
+}
+
+// Return specifies the return arguments for the expectation.
+//
+//    Mock.On("DoSomething").Return(errors.New("failed"))
+func (c *Call) Return(returnArguments ...interface{}) *Call {
+       c.lock()
+       defer c.unlock()
+
+       c.ReturnArguments = returnArguments
+
+       return c
+}
+
+// Once indicates that that the mock should only return the value once.
+//
+//    Mock.On("MyMethod", arg1, arg2).Return(returnArg1, returnArg2).Once()
+func (c *Call) Once() *Call {
+       return c.Times(1)
+}
+
+// Twice indicates that that the mock should only return the value twice.
+//
+//    Mock.On("MyMethod", arg1, arg2).Return(returnArg1, returnArg2).Twice()
+func (c *Call) Twice() *Call {
+       return c.Times(2)
+}
+
+// Times indicates that that the mock should only return the indicated number
+// of times.
+//
+//    Mock.On("MyMethod", arg1, arg2).Return(returnArg1, returnArg2).Times(5)
+func (c *Call) Times(i int) *Call {
+       c.lock()
+       defer c.unlock()
+       c.Repeatability = i
+       return c
+}
+
+// WaitUntil sets the channel that will block the mock's return until its closed
+// or a message is received.
+//
+//    Mock.On("MyMethod", arg1, arg2).WaitUntil(time.After(time.Second))
+func (c *Call) WaitUntil(w <-chan time.Time) *Call {
+       c.lock()
+       defer c.unlock()
+       c.WaitFor = w
+       return c
+}
+
+// After sets how long to block until the call returns
+//
+//    Mock.On("MyMethod", arg1, arg2).After(time.Second)
+func (c *Call) After(d time.Duration) *Call {
+       return c.WaitUntil(time.After(d))
+}
+
+// Run sets a handler to be called before returning. It can be used when
+// mocking a method such as unmarshalers that takes a pointer to a struct and
+// sets properties in such struct
+//
+//    Mock.On("Unmarshal", AnythingOfType("*map[string]interface{}").Return().Run(func(args Arguments) {
+//     arg := args.Get(0).(*map[string]interface{})
+//     arg["foo"] = "bar"
+//    })
+func (c *Call) Run(fn func(Arguments)) *Call {
+       c.lock()
+       defer c.unlock()
+       c.RunFn = fn
+       return c
+}
+
+// On chains a new expectation description onto the mocked interface. This
+// allows syntax like.
+//
+//    Mock.
+//       On("MyMethod", 1).Return(nil).
+//       On("MyOtherMethod", 'a', 'b', 'c').Return(errors.New("Some Error"))
+func (c *Call) On(methodName string, arguments ...interface{}) *Call {
+       return c.Parent.On(methodName, arguments...)
+}
+
+// Mock is the workhorse used to track activity on another object.
+// For an example of its usage, refer to the "Example Usage" section at the top
+// of this document.
+type Mock struct {
+       // Represents the calls that are expected of
+       // an object.
+       ExpectedCalls []*Call
+
+       // Holds the calls that were made to this mocked object.
+       Calls []Call
+
+       // TestData holds any data that might be useful for testing.  Testify ignores
+       // this data completely allowing you to do whatever you like with it.
+       testData objx.Map
+
+       mutex sync.Mutex
+}
+
+// TestData holds any data that might be useful for testing.  Testify ignores
+// this data completely allowing you to do whatever you like with it.
+func (m *Mock) TestData() objx.Map {
+
+       if m.testData == nil {
+               m.testData = make(objx.Map)
+       }
+
+       return m.testData
+}
+
+/*
+       Setting expectations
+*/
+
+// On starts a description of an expectation of the specified method
+// being called.
+//
+//     Mock.On("MyMethod", arg1, arg2)
+func (m *Mock) On(methodName string, arguments ...interface{}) *Call {
+       for _, arg := range arguments {
+               if v := reflect.ValueOf(arg); v.Kind() == reflect.Func {
+                       panic(fmt.Sprintf("cannot use Func in expectations. Use mock.AnythingOfType(\"%T\")", arg))
+               }
+       }
+
+       m.mutex.Lock()
+       defer m.mutex.Unlock()
+       c := newCall(m, methodName, arguments...)
+       m.ExpectedCalls = append(m.ExpectedCalls, c)
+       return c
+}
+
+// /*
+//     Recording and responding to activity
+// */
+
+func (m *Mock) findExpectedCall(method string, arguments ...interface{}) (int, *Call) {
+       m.mutex.Lock()
+       defer m.mutex.Unlock()
+       for i, call := range m.ExpectedCalls {
+               if call.Method == method && call.Repeatability > -1 {
+
+                       _, diffCount := call.Arguments.Diff(arguments)
+                       if diffCount == 0 {
+                               return i, call
+                       }
+
+               }
+       }
+       return -1, nil
+}
+
+func (m *Mock) findClosestCall(method string, arguments ...interface{}) (bool, *Call) {
+       diffCount := 0
+       var closestCall *Call
+
+       for _, call := range m.expectedCalls() {
+               if call.Method == method {
+
+                       _, tempDiffCount := call.Arguments.Diff(arguments)
+                       if tempDiffCount < diffCount || diffCount == 0 {
+                               diffCount = tempDiffCount
+                               closestCall = call
+                       }
+
+               }
+       }
+
+       if closestCall == nil {
+               return false, nil
+       }
+
+       return true, closestCall
+}
+
+func callString(method string, arguments Arguments, includeArgumentValues bool) string {
+
+       var argValsString string
+       if includeArgumentValues {
+               var argVals []string
+               for argIndex, arg := range arguments {
+                       argVals = append(argVals, fmt.Sprintf("%d: %#v", argIndex, arg))
+               }
+               argValsString = fmt.Sprintf("\n\t\t%s", strings.Join(argVals, "\n\t\t"))
+       }
+
+       return fmt.Sprintf("%s(%s)%s", method, arguments.String(), argValsString)
+}
+
+// Called tells the mock object that a method has been called, and gets an array
+// of arguments to return.  Panics if the call is unexpected (i.e. not preceded by
+// appropriate .On .Return() calls)
+// If Call.WaitFor is set, blocks until the channel is closed or receives a message.
+func (m *Mock) Called(arguments ...interface{}) Arguments {
+       // get the calling function's name
+       pc, _, _, ok := runtime.Caller(1)
+       if !ok {
+               panic("Couldn't get the caller information")
+       }
+       functionPath := runtime.FuncForPC(pc).Name()
+       //Next four lines are required to use GCCGO function naming conventions.
+       //For Ex:  github_com_docker_libkv_store_mock.WatchTree.pN39_github_com_docker_libkv_store_mock.Mock
+       //uses inteface information unlike golang github.com/docker/libkv/store/mock.(*Mock).WatchTree
+       //With GCCGO we need to remove interface information starting from pN<dd>.
+       re := regexp.MustCompile("\\.pN\\d+_")
+       if re.MatchString(functionPath) {
+               functionPath = re.Split(functionPath, -1)[0]
+       }
+       parts := strings.Split(functionPath, ".")
+       functionName := parts[len(parts)-1]
+
+       found, call := m.findExpectedCall(functionName, arguments...)
+
+       if found < 0 {
+               // we have to fail here - because we don't know what to do
+               // as the return arguments.  This is because:
+               //
+               //   a) this is a totally unexpected call to this method,
+               //   b) the arguments are not what was expected, or
+               //   c) the developer has forgotten to add an accompanying On...Return pair.
+
+               closestFound, closestCall := m.findClosestCall(functionName, arguments...)
+
+               if closestFound {
+                       panic(fmt.Sprintf("\n\nmock: Unexpected Method Call\n-----------------------------\n\n%s\n\nThe closest call I have is: \n\n%s\n", callString(functionName, arguments, true), callString(functionName, closestCall.Arguments, true)))
+               } else {
+                       panic(fmt.Sprintf("\nassert: mock: I don't know what to return because the method call was unexpected.\n\tEither do Mock.On(\"%s\").Return(...) first, or remove the %s() call.\n\tThis method was unexpected:\n\t\t%s\n\tat: %s", functionName, functionName, callString(functionName, arguments, true), assert.CallerInfo()))
+               }
+       } else {
+               m.mutex.Lock()
+               switch {
+               case call.Repeatability == 1:
+                       call.Repeatability = -1
+                       call.totalCalls++
+
+               case call.Repeatability > 1:
+                       call.Repeatability--
+                       call.totalCalls++
+
+               case call.Repeatability == 0:
+                       call.totalCalls++
+               }
+               m.mutex.Unlock()
+       }
+
+       // add the call
+       m.mutex.Lock()
+       m.Calls = append(m.Calls, *newCall(m, functionName, arguments...))
+       m.mutex.Unlock()
+
+       // block if specified
+       if call.WaitFor != nil {
+               <-call.WaitFor
+       }
+
+       if call.RunFn != nil {
+               call.RunFn(arguments)
+       }
+
+       return call.ReturnArguments
+}
+
+/*
+       Assertions
+*/
+
+// AssertExpectationsForObjects asserts that everything specified with On and Return
+// of the specified objects was in fact called as expected.
+//
+// Calls may have occurred in any order.
+func AssertExpectationsForObjects(t TestingT, testObjects ...interface{}) bool {
+       var success = true
+       for _, obj := range testObjects {
+               mockObj := obj.(Mock)
+               success = success && mockObj.AssertExpectations(t)
+       }
+       return success
+}
+
+// AssertExpectations asserts that everything specified with On and Return was
+// in fact called as expected.  Calls may have occurred in any order.
+func (m *Mock) AssertExpectations(t TestingT) bool {
+       var somethingMissing bool
+       var failedExpectations int
+
+       // iterate through each expectation
+       expectedCalls := m.expectedCalls()
+       for _, expectedCall := range expectedCalls {
+               if !m.methodWasCalled(expectedCall.Method, expectedCall.Arguments) && expectedCall.totalCalls == 0 {
+                       somethingMissing = true
+                       failedExpectations++
+                       t.Logf("\u274C\t%s(%s)", expectedCall.Method, expectedCall.Arguments.String())
+               } else {
+                       m.mutex.Lock()
+                       if expectedCall.Repeatability > 0 {
+                               somethingMissing = true
+                               failedExpectations++
+                       } else {
+                               t.Logf("\u2705\t%s(%s)", expectedCall.Method, expectedCall.Arguments.String())
+                       }
+                       m.mutex.Unlock()
+               }
+       }
+
+       if somethingMissing {
+               t.Errorf("FAIL: %d out of %d expectation(s) were met.\n\tThe code you are testing needs to make %d more call(s).\n\tat: %s", len(expectedCalls)-failedExpectations, len(expectedCalls), failedExpectations, assert.CallerInfo())
+       }
+
+       return !somethingMissing
+}
+
+// AssertNumberOfCalls asserts that the method was called expectedCalls times.
+func (m *Mock) AssertNumberOfCalls(t TestingT, methodName string, expectedCalls int) bool {
+       var actualCalls int
+       for _, call := range m.calls() {
+               if call.Method == methodName {
+                       actualCalls++
+               }
+       }
+       return assert.Equal(t, expectedCalls, actualCalls, fmt.Sprintf("Expected number of calls (%d) does not match the actual number of calls (%d).", expectedCalls, actualCalls))
+}
+
+// AssertCalled asserts that the method was called.
+// It can produce a false result when an argument is a pointer type and the underlying value changed after calling the mocked method.
+func (m *Mock) AssertCalled(t TestingT, methodName string, arguments ...interface{}) bool {
+       if !assert.True(t, m.methodWasCalled(methodName, arguments), fmt.Sprintf("The \"%s\" method should have been called with %d argument(s), but was not.", methodName, len(arguments))) {
+               t.Logf("%v", m.expectedCalls())
+               return false
+       }
+       return true
+}
+
+// AssertNotCalled asserts that the method was not called.
+// It can produce a false result when an argument is a pointer type and the underlying value changed after calling the mocked method.
+func (m *Mock) AssertNotCalled(t TestingT, methodName string, arguments ...interface{}) bool {
+       if !assert.False(t, m.methodWasCalled(methodName, arguments), fmt.Sprintf("The \"%s\" method was called with %d argument(s), but should NOT have been.", methodName, len(arguments))) {
+               t.Logf("%v", m.expectedCalls())
+               return false
+       }
+       return true
+}
+
+func (m *Mock) methodWasCalled(methodName string, expected []interface{}) bool {
+       for _, call := range m.calls() {
+               if call.Method == methodName {
+
+                       _, differences := Arguments(expected).Diff(call.Arguments)
+
+                       if differences == 0 {
+                               // found the expected call
+                               return true
+                       }
+
+               }
+       }
+       // we didn't find the expected call
+       return false
+}
+
+func (m *Mock) expectedCalls() []*Call {
+       m.mutex.Lock()
+       defer m.mutex.Unlock()
+       return append([]*Call{}, m.ExpectedCalls...)
+}
+
+func (m *Mock) calls() []Call {
+       m.mutex.Lock()
+       defer m.mutex.Unlock()
+       return append([]Call{}, m.Calls...)
+}
+
+/*
+       Arguments
+*/
+
+// Arguments holds an array of method arguments or return values.
+type Arguments []interface{}
+
+const (
+       // Anything is used in Diff and Assert when the argument being tested
+       // shouldn't be taken into consideration.
+       Anything string = "mock.Anything"
+)
+
+// AnythingOfTypeArgument is a string that contains the type of an argument
+// for use when type checking.  Used in Diff and Assert.
+type AnythingOfTypeArgument string
+
+// AnythingOfType returns an AnythingOfTypeArgument object containing the
+// name of the type to check for.  Used in Diff and Assert.
+//
+// For example:
+//     Assert(t, AnythingOfType("string"), AnythingOfType("int"))
+func AnythingOfType(t string) AnythingOfTypeArgument {
+       return AnythingOfTypeArgument(t)
+}
+
+// argumentMatcher performs custom argument matching, returning whether or
+// not the argument is matched by the expectation fixture function.
+type argumentMatcher struct {
+       // fn is a function which accepts one argument, and returns a bool.
+       fn reflect.Value
+}
+
+func (f argumentMatcher) Matches(argument interface{}) bool {
+       expectType := f.fn.Type().In(0)
+
+       if reflect.TypeOf(argument).AssignableTo(expectType) {
+               result := f.fn.Call([]reflect.Value{reflect.ValueOf(argument)})
+               return result[0].Bool()
+       }
+       return false
+}
+
+func (f argumentMatcher) String() string {
+       return fmt.Sprintf("func(%s) bool", f.fn.Type().In(0).Name())
+}
+
+// MatchedBy can be used to match a mock call based on only certain properties
+// from a complex struct or some calculation. It takes a function that will be
+// evaluated with the called argument and will return true when there's a match
+// and false otherwise.
+//
+// Example:
+// m.On("Do", MatchedBy(func(req *http.Request) bool { return req.Host == "example.com" }))
+//
+// |fn|, must be a function accepting a single argument (of the expected type)
+// which returns a bool. If |fn| doesn't match the required signature,
+// MathedBy() panics.
+func MatchedBy(fn interface{}) argumentMatcher {
+       fnType := reflect.TypeOf(fn)
+
+       if fnType.Kind() != reflect.Func {
+               panic(fmt.Sprintf("assert: arguments: %s is not a func", fn))
+       }
+       if fnType.NumIn() != 1 {
+               panic(fmt.Sprintf("assert: arguments: %s does not take exactly one argument", fn))
+       }
+       if fnType.NumOut() != 1 || fnType.Out(0).Kind() != reflect.Bool {
+               panic(fmt.Sprintf("assert: arguments: %s does not return a bool", fn))
+       }
+
+       return argumentMatcher{fn: reflect.ValueOf(fn)}
+}
+
+// Get Returns the argument at the specified index.
+func (args Arguments) Get(index int) interface{} {
+       if index+1 > len(args) {
+               panic(fmt.Sprintf("assert: arguments: Cannot call Get(%d) because there are %d argument(s).", index, len(args)))
+       }
+       return args[index]
+}
+
+// Is gets whether the objects match the arguments specified.
+func (args Arguments) Is(objects ...interface{}) bool {
+       for i, obj := range args {
+               if obj != objects[i] {
+                       return false
+               }
+       }
+       return true
+}
+
+// Diff gets a string describing the differences between the arguments
+// and the specified objects.
+//
+// Returns the diff string and number of differences found.
+func (args Arguments) Diff(objects []interface{}) (string, int) {
+
+       var output = "\n"
+       var differences int
+
+       var maxArgCount = len(args)
+       if len(objects) > maxArgCount {
+               maxArgCount = len(objects)
+       }
+
+       for i := 0; i < maxArgCount; i++ {
+               var actual, expected interface{}
+
+               if len(objects) <= i {
+                       actual = "(Missing)"
+               } else {
+                       actual = objects[i]
+               }
+
+               if len(args) <= i {
+                       expected = "(Missing)"
+               } else {
+                       expected = args[i]
+               }
+
+               if matcher, ok := expected.(argumentMatcher); ok {
+                       if matcher.Matches(actual) {
+                               output = fmt.Sprintf("%s\t%d: \u2705  %s matched by %s\n", output, i, actual, matcher)
+                       } else {
+                               differences++
+                               output = fmt.Sprintf("%s\t%d: \u2705  %s not matched by %s\n", output, i, actual, matcher)
+                       }
+               } else if reflect.TypeOf(expected) == reflect.TypeOf((*AnythingOfTypeArgument)(nil)).Elem() {
+
+                       // type checking
+                       if reflect.TypeOf(actual).Name() != string(expected.(AnythingOfTypeArgument)) && reflect.TypeOf(actual).String() != string(expected.(AnythingOfTypeArgument)) {
+                               // not match
+                               differences++
+                               output = fmt.Sprintf("%s\t%d: \u274C  type %s != type %s - %s\n", output, i, expected, reflect.TypeOf(actual).Name(), actual)
+                       }
+
+               } else {
+
+                       // normal checking
+
+                       if assert.ObjectsAreEqual(expected, Anything) || assert.ObjectsAreEqual(actual, Anything) || assert.ObjectsAreEqual(actual, expected) {
+                               // match
+                               output = fmt.Sprintf("%s\t%d: \u2705  %s == %s\n", output, i, actual, expected)
+                       } else {
+                               // not match
+                               differences++
+                               output = fmt.Sprintf("%s\t%d: \u274C  %s != %s\n", output, i, actual, expected)
+                       }
+               }
+
+       }
+
+       if differences == 0 {
+               return "No differences.", differences
+       }
+
+       return output, differences
+
+}
+
+// Assert compares the arguments with the specified objects and fails if
+// they do not exactly match.
+func (args Arguments) Assert(t TestingT, objects ...interface{}) bool {
+
+       // get the differences
+       diff, diffCount := args.Diff(objects)
+
+       if diffCount == 0 {
+               return true
+       }
+
+       // there are differences... report them...
+       t.Logf(diff)
+       t.Errorf("%sArguments do not match.", assert.CallerInfo())
+
+       return false
+
+}
+
+// String gets the argument at the specified index. Panics if there is no argument, or
+// if the argument is of the wrong type.
+//
+// If no index is provided, String() returns a complete string representation
+// of the arguments.
+func (args Arguments) String(indexOrNil ...int) string {
+
+       if len(indexOrNil) == 0 {
+               // normal String() method - return a string representation of the args
+               var argsStr []string
+               for _, arg := range args {
+                       argsStr = append(argsStr, fmt.Sprintf("%s", reflect.TypeOf(arg)))
+               }
+               return strings.Join(argsStr, ",")
+       } else if len(indexOrNil) == 1 {
+               // Index has been specified - get the argument at that index
+               var index = indexOrNil[0]
+               var s string
+               var ok bool
+               if s, ok = args.Get(index).(string); !ok {
+                       panic(fmt.Sprintf("assert: arguments: String(%d) failed because object wasn't correct type: %s", index, args.Get(index)))
+               }
+               return s
+       }
+
+       panic(fmt.Sprintf("assert: arguments: Wrong number of arguments passed to String.  Must be 0 or 1, not %d", len(indexOrNil)))
+
+}
+
+// Int gets the argument at the specified index. Panics if there is no argument, or
+// if the argument is of the wrong type.
+func (args Arguments) Int(index int) int {
+       var s int
+       var ok bool
+       if s, ok = args.Get(index).(int); !ok {
+               panic(fmt.Sprintf("assert: arguments: Int(%d) failed because object wasn't correct type: %v", index, args.Get(index)))
+       }
+       return s
+}
+
+// Error gets the argument at the specified index. Panics if there is no argument, or
+// if the argument is of the wrong type.
+func (args Arguments) Error(index int) error {
+       obj := args.Get(index)
+       var s error
+       var ok bool
+       if obj == nil {
+               return nil
+       }
+       if s, ok = obj.(error); !ok {
+               panic(fmt.Sprintf("assert: arguments: Error(%d) failed because object wasn't correct type: %v", index, args.Get(index)))
+       }
+       return s
+}
+
+// Bool gets the argument at the specified index. Panics if there is no argument, or
+// if the argument is of the wrong type.
+func (args Arguments) Bool(index int) bool {
+       var s bool
+       var ok bool
+       if s, ok = args.Get(index).(bool); !ok {
+               panic(fmt.Sprintf("assert: arguments: Bool(%d) failed because object wasn't correct type: %v", index, args.Get(index)))
+       }
+       return s
+}
diff --git a/vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/mock/mock_test.go b/vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/mock/mock_test.go
new file mode 100644 (file)
index 0000000..166c324
--- /dev/null
@@ -0,0 +1,1130 @@
+package mock
+
+import (
+       "errors"
+       "github.com/stretchr/testify/assert"
+       "github.com/stretchr/testify/require"
+       "testing"
+       "time"
+)
+
+/*
+       Test objects
+*/
+
+// ExampleInterface represents an example interface.
+type ExampleInterface interface {
+       TheExampleMethod(a, b, c int) (int, error)
+}
+
+// TestExampleImplementation is a test implementation of ExampleInterface
+type TestExampleImplementation struct {
+       Mock
+}
+
+func (i *TestExampleImplementation) TheExampleMethod(a, b, c int) (int, error) {
+       args := i.Called(a, b, c)
+       return args.Int(0), errors.New("Whoops")
+}
+
+func (i *TestExampleImplementation) TheExampleMethod2(yesorno bool) {
+       i.Called(yesorno)
+}
+
+type ExampleType struct {
+       ran bool
+}
+
+func (i *TestExampleImplementation) TheExampleMethod3(et *ExampleType) error {
+       args := i.Called(et)
+       return args.Error(0)
+}
+
+func (i *TestExampleImplementation) TheExampleMethodFunc(fn func(string) error) error {
+       args := i.Called(fn)
+       return args.Error(0)
+}
+
+func (i *TestExampleImplementation) TheExampleMethodVariadic(a ...int) error {
+       args := i.Called(a)
+       return args.Error(0)
+}
+
+func (i *TestExampleImplementation) TheExampleMethodVariadicInterface(a ...interface{}) error {
+       args := i.Called(a)
+       return args.Error(0)
+}
+
+type ExampleFuncType func(string) error
+
+func (i *TestExampleImplementation) TheExampleMethodFuncType(fn ExampleFuncType) error {
+       args := i.Called(fn)
+       return args.Error(0)
+}
+
+/*
+       Mock
+*/
+
+func Test_Mock_TestData(t *testing.T) {
+
+       var mockedService = new(TestExampleImplementation)
+
+       if assert.NotNil(t, mockedService.TestData()) {
+
+               mockedService.TestData().Set("something", 123)
+               assert.Equal(t, 123, mockedService.TestData().Get("something").Data())
+       }
+}
+
+func Test_Mock_On(t *testing.T) {
+
+       // make a test impl object
+       var mockedService = new(TestExampleImplementation)
+
+       c := mockedService.On("TheExampleMethod")
+       assert.Equal(t, []*Call{c}, mockedService.ExpectedCalls)
+       assert.Equal(t, "TheExampleMethod", c.Method)
+}
+
+func Test_Mock_Chained_On(t *testing.T) {
+       // make a test impl object
+       var mockedService = new(TestExampleImplementation)
+
+       mockedService.
+               On("TheExampleMethod", 1, 2, 3).
+               Return(0).
+               On("TheExampleMethod3", AnythingOfType("*mock.ExampleType")).
+               Return(nil)
+
+       expectedCalls := []*Call{
+               &Call{
+                       Parent:          &mockedService.Mock,
+                       Method:          "TheExampleMethod",
+                       Arguments:       []interface{}{1, 2, 3},
+                       ReturnArguments: []interface{}{0},
+               },
+               &Call{
+                       Parent:          &mockedService.Mock,
+                       Method:          "TheExampleMethod3",
+                       Arguments:       []interface{}{AnythingOfType("*mock.ExampleType")},
+                       ReturnArguments: []interface{}{nil},
+               },
+       }
+       assert.Equal(t, expectedCalls, mockedService.ExpectedCalls)
+}
+
+func Test_Mock_On_WithArgs(t *testing.T) {
+
+       // make a test impl object
+       var mockedService = new(TestExampleImplementation)
+
+       c := mockedService.On("TheExampleMethod", 1, 2, 3, 4)
+
+       assert.Equal(t, []*Call{c}, mockedService.ExpectedCalls)
+       assert.Equal(t, "TheExampleMethod", c.Method)
+       assert.Equal(t, Arguments{1, 2, 3, 4}, c.Arguments)
+}
+
+func Test_Mock_On_WithFuncArg(t *testing.T) {
+
+       // make a test impl object
+       var mockedService = new(TestExampleImplementation)
+
+       c := mockedService.
+               On("TheExampleMethodFunc", AnythingOfType("func(string) error")).
+               Return(nil)
+
+       assert.Equal(t, []*Call{c}, mockedService.ExpectedCalls)
+       assert.Equal(t, "TheExampleMethodFunc", c.Method)
+       assert.Equal(t, 1, len(c.Arguments))
+       assert.Equal(t, AnythingOfType("func(string) error"), c.Arguments[0])
+
+       fn := func(string) error { return nil }
+
+       assert.NotPanics(t, func() {
+               mockedService.TheExampleMethodFunc(fn)
+       })
+}
+
+func Test_Mock_On_WithIntArgMatcher(t *testing.T) {
+       var mockedService TestExampleImplementation
+
+       mockedService.On("TheExampleMethod",
+               MatchedBy(func(a int) bool {
+                       return a == 1
+               }), MatchedBy(func(b int) bool {
+                       return b == 2
+               }), MatchedBy(func(c int) bool {
+                       return c == 3
+               })).Return(0, nil)
+
+       assert.Panics(t, func() {
+               mockedService.TheExampleMethod(1, 2, 4)
+       })
+       assert.Panics(t, func() {
+               mockedService.TheExampleMethod(2, 2, 3)
+       })
+       assert.NotPanics(t, func() {
+               mockedService.TheExampleMethod(1, 2, 3)
+       })
+}
+
+func Test_Mock_On_WithPtrArgMatcher(t *testing.T) {
+       var mockedService TestExampleImplementation
+
+       mockedService.On("TheExampleMethod3",
+               MatchedBy(func(a *ExampleType) bool { return a.ran == true }),
+       ).Return(nil)
+
+       mockedService.On("TheExampleMethod3",
+               MatchedBy(func(a *ExampleType) bool { return a.ran == false }),
+       ).Return(errors.New("error"))
+
+       assert.Equal(t, mockedService.TheExampleMethod3(&ExampleType{true}), nil)
+       assert.EqualError(t, mockedService.TheExampleMethod3(&ExampleType{false}), "error")
+}
+
+func Test_Mock_On_WithFuncArgMatcher(t *testing.T) {
+       var mockedService TestExampleImplementation
+
+       fixture1, fixture2 := errors.New("fixture1"), errors.New("fixture2")
+
+       mockedService.On("TheExampleMethodFunc",
+               MatchedBy(func(a func(string) error) bool { return a("string") == fixture1 }),
+       ).Return(errors.New("fixture1"))
+
+       mockedService.On("TheExampleMethodFunc",
+               MatchedBy(func(a func(string) error) bool { return a("string") == fixture2 }),
+       ).Return(errors.New("fixture2"))
+
+       assert.EqualError(t, mockedService.TheExampleMethodFunc(
+               func(string) error { return fixture1 }), "fixture1")
+       assert.EqualError(t, mockedService.TheExampleMethodFunc(
+               func(string) error { return fixture2 }), "fixture2")
+}
+
+func Test_Mock_On_WithVariadicFunc(t *testing.T) {
+
+       // make a test impl object
+       var mockedService = new(TestExampleImplementation)
+
+       c := mockedService.
+               On("TheExampleMethodVariadic", []int{1, 2, 3}).
+               Return(nil)
+
+       assert.Equal(t, []*Call{c}, mockedService.ExpectedCalls)
+       assert.Equal(t, 1, len(c.Arguments))
+       assert.Equal(t, []int{1, 2, 3}, c.Arguments[0])
+
+       assert.NotPanics(t, func() {
+               mockedService.TheExampleMethodVariadic(1, 2, 3)
+       })
+       assert.Panics(t, func() {
+               mockedService.TheExampleMethodVariadic(1, 2)
+       })
+
+}
+
+func Test_Mock_On_WithVariadicFuncWithInterface(t *testing.T) {
+
+       // make a test impl object
+       var mockedService = new(TestExampleImplementation)
+
+       c := mockedService.On("TheExampleMethodVariadicInterface", []interface{}{1, 2, 3}).
+               Return(nil)
+
+       assert.Equal(t, []*Call{c}, mockedService.ExpectedCalls)
+       assert.Equal(t, 1, len(c.Arguments))
+       assert.Equal(t, []interface{}{1, 2, 3}, c.Arguments[0])
+
+       assert.NotPanics(t, func() {
+               mockedService.TheExampleMethodVariadicInterface(1, 2, 3)
+       })
+       assert.Panics(t, func() {
+               mockedService.TheExampleMethodVariadicInterface(1, 2)
+       })
+
+}
+
+func Test_Mock_On_WithVariadicFuncWithEmptyInterfaceArray(t *testing.T) {
+
+       // make a test impl object
+       var mockedService = new(TestExampleImplementation)
+
+       var expected []interface{}
+       c := mockedService.
+               On("TheExampleMethodVariadicInterface", expected).
+               Return(nil)
+
+       assert.Equal(t, []*Call{c}, mockedService.ExpectedCalls)
+       assert.Equal(t, 1, len(c.Arguments))
+       assert.Equal(t, expected, c.Arguments[0])
+
+       assert.NotPanics(t, func() {
+               mockedService.TheExampleMethodVariadicInterface()
+       })
+       assert.Panics(t, func() {
+               mockedService.TheExampleMethodVariadicInterface(1, 2)
+       })
+
+}
+
+func Test_Mock_On_WithFuncPanics(t *testing.T) {
+       // make a test impl object
+       var mockedService = new(TestExampleImplementation)
+
+       assert.Panics(t, func() {
+               mockedService.On("TheExampleMethodFunc", func(string) error { return nil })
+       })
+}
+
+func Test_Mock_On_WithFuncTypeArg(t *testing.T) {
+
+       // make a test impl object
+       var mockedService = new(TestExampleImplementation)
+
+       c := mockedService.
+               On("TheExampleMethodFuncType", AnythingOfType("mock.ExampleFuncType")).
+               Return(nil)
+
+       assert.Equal(t, []*Call{c}, mockedService.ExpectedCalls)
+       assert.Equal(t, 1, len(c.Arguments))
+       assert.Equal(t, AnythingOfType("mock.ExampleFuncType"), c.Arguments[0])
+
+       fn := func(string) error { return nil }
+       assert.NotPanics(t, func() {
+               mockedService.TheExampleMethodFuncType(fn)
+       })
+}
+
+func Test_Mock_Return(t *testing.T) {
+
+       // make a test impl object
+       var mockedService = new(TestExampleImplementation)
+
+       c := mockedService.
+               On("TheExampleMethod", "A", "B", true).
+               Return(1, "two", true)
+
+       require.Equal(t, []*Call{c}, mockedService.ExpectedCalls)
+
+       call := mockedService.ExpectedCalls[0]
+
+       assert.Equal(t, "TheExampleMethod", call.Method)
+       assert.Equal(t, "A", call.Arguments[0])
+       assert.Equal(t, "B", call.Arguments[1])
+       assert.Equal(t, true, call.Arguments[2])
+       assert.Equal(t, 1, call.ReturnArguments[0])
+       assert.Equal(t, "two", call.ReturnArguments[1])
+       assert.Equal(t, true, call.ReturnArguments[2])
+       assert.Equal(t, 0, call.Repeatability)
+       assert.Nil(t, call.WaitFor)
+}
+
+func Test_Mock_Return_WaitUntil(t *testing.T) {
+
+       // make a test impl object
+       var mockedService = new(TestExampleImplementation)
+       ch := time.After(time.Second)
+
+       c := mockedService.Mock.
+               On("TheExampleMethod", "A", "B", true).
+               WaitUntil(ch).
+               Return(1, "two", true)
+
+       // assert that the call was created
+       require.Equal(t, []*Call{c}, mockedService.ExpectedCalls)
+
+       call := mockedService.ExpectedCalls[0]
+
+       assert.Equal(t, "TheExampleMethod", call.Method)
+       assert.Equal(t, "A", call.Arguments[0])
+       assert.Equal(t, "B", call.Arguments[1])
+       assert.Equal(t, true, call.Arguments[2])
+       assert.Equal(t, 1, call.ReturnArguments[0])
+       assert.Equal(t, "two", call.ReturnArguments[1])
+       assert.Equal(t, true, call.ReturnArguments[2])
+       assert.Equal(t, 0, call.Repeatability)
+       assert.Equal(t, ch, call.WaitFor)
+}
+
+func Test_Mock_Return_After(t *testing.T) {
+
+       // make a test impl object
+       var mockedService = new(TestExampleImplementation)
+
+       c := mockedService.Mock.
+               On("TheExampleMethod", "A", "B", true).
+               Return(1, "two", true).
+               After(time.Second)
+
+       require.Equal(t, []*Call{c}, mockedService.ExpectedCalls)
+
+       call := mockedService.Mock.ExpectedCalls[0]
+
+       assert.Equal(t, "TheExampleMethod", call.Method)
+       assert.Equal(t, "A", call.Arguments[0])
+       assert.Equal(t, "B", call.Arguments[1])
+       assert.Equal(t, true, call.Arguments[2])
+       assert.Equal(t, 1, call.ReturnArguments[0])
+       assert.Equal(t, "two", call.ReturnArguments[1])
+       assert.Equal(t, true, call.ReturnArguments[2])
+       assert.Equal(t, 0, call.Repeatability)
+       assert.NotEqual(t, nil, call.WaitFor)
+
+}
+
+func Test_Mock_Return_Run(t *testing.T) {
+
+       // make a test impl object
+       var mockedService = new(TestExampleImplementation)
+
+       fn := func(args Arguments) {
+               arg := args.Get(0).(*ExampleType)
+               arg.ran = true
+       }
+
+       c := mockedService.Mock.
+               On("TheExampleMethod3", AnythingOfType("*mock.ExampleType")).
+               Return(nil).
+               Run(fn)
+
+       require.Equal(t, []*Call{c}, mockedService.ExpectedCalls)
+
+       call := mockedService.Mock.ExpectedCalls[0]
+
+       assert.Equal(t, "TheExampleMethod3", call.Method)
+       assert.Equal(t, AnythingOfType("*mock.ExampleType"), call.Arguments[0])
+       assert.Equal(t, nil, call.ReturnArguments[0])
+       assert.Equal(t, 0, call.Repeatability)
+       assert.NotEqual(t, nil, call.WaitFor)
+       assert.NotNil(t, call.Run)
+
+       et := ExampleType{}
+       assert.Equal(t, false, et.ran)
+       mockedService.TheExampleMethod3(&et)
+       assert.Equal(t, true, et.ran)
+}
+
+func Test_Mock_Return_Run_Out_Of_Order(t *testing.T) {
+       // make a test impl object
+       var mockedService = new(TestExampleImplementation)
+       f := func(args Arguments) {
+               arg := args.Get(0).(*ExampleType)
+               arg.ran = true
+       }
+
+       c := mockedService.Mock.
+               On("TheExampleMethod3", AnythingOfType("*mock.ExampleType")).
+               Run(f).
+               Return(nil)
+
+       require.Equal(t, []*Call{c}, mockedService.ExpectedCalls)
+
+       call := mockedService.Mock.ExpectedCalls[0]
+
+       assert.Equal(t, "TheExampleMethod3", call.Method)
+       assert.Equal(t, AnythingOfType("*mock.ExampleType"), call.Arguments[0])
+       assert.Equal(t, nil, call.ReturnArguments[0])
+       assert.Equal(t, 0, call.Repeatability)
+       assert.NotEqual(t, nil, call.WaitFor)
+       assert.NotNil(t, call.Run)
+}
+
+func Test_Mock_Return_Once(t *testing.T) {
+
+       // make a test impl object
+       var mockedService = new(TestExampleImplementation)
+
+       c := mockedService.On("TheExampleMethod", "A", "B", true).
+               Return(1, "two", true).
+               Once()
+
+       require.Equal(t, []*Call{c}, mockedService.ExpectedCalls)
+
+       call := mockedService.ExpectedCalls[0]
+
+       assert.Equal(t, "TheExampleMethod", call.Method)
+       assert.Equal(t, "A", call.Arguments[0])
+       assert.Equal(t, "B", call.Arguments[1])
+       assert.Equal(t, true, call.Arguments[2])
+       assert.Equal(t, 1, call.ReturnArguments[0])
+       assert.Equal(t, "two", call.ReturnArguments[1])
+       assert.Equal(t, true, call.ReturnArguments[2])
+       assert.Equal(t, 1, call.Repeatability)
+       assert.Nil(t, call.WaitFor)
+}
+
+func Test_Mock_Return_Twice(t *testing.T) {
+
+       // make a test impl object
+       var mockedService = new(TestExampleImplementation)
+
+       c := mockedService.
+               On("TheExampleMethod", "A", "B", true).
+               Return(1, "two", true).
+               Twice()
+
+       require.Equal(t, []*Call{c}, mockedService.ExpectedCalls)
+
+       call := mockedService.ExpectedCalls[0]
+
+       assert.Equal(t, "TheExampleMethod", call.Method)
+       assert.Equal(t, "A", call.Arguments[0])
+       assert.Equal(t, "B", call.Arguments[1])
+       assert.Equal(t, true, call.Arguments[2])
+       assert.Equal(t, 1, call.ReturnArguments[0])
+       assert.Equal(t, "two", call.ReturnArguments[1])
+       assert.Equal(t, true, call.ReturnArguments[2])
+       assert.Equal(t, 2, call.Repeatability)
+       assert.Nil(t, call.WaitFor)
+}
+
+func Test_Mock_Return_Times(t *testing.T) {
+
+       // make a test impl object
+       var mockedService = new(TestExampleImplementation)
+
+       c := mockedService.
+               On("TheExampleMethod", "A", "B", true).
+               Return(1, "two", true).
+               Times(5)
+
+       require.Equal(t, []*Call{c}, mockedService.ExpectedCalls)
+
+       call := mockedService.ExpectedCalls[0]
+
+       assert.Equal(t, "TheExampleMethod", call.Method)
+       assert.Equal(t, "A", call.Arguments[0])
+       assert.Equal(t, "B", call.Arguments[1])
+       assert.Equal(t, true, call.Arguments[2])
+       assert.Equal(t, 1, call.ReturnArguments[0])
+       assert.Equal(t, "two", call.ReturnArguments[1])
+       assert.Equal(t, true, call.ReturnArguments[2])
+       assert.Equal(t, 5, call.Repeatability)
+       assert.Nil(t, call.WaitFor)
+}
+
+func Test_Mock_Return_Nothing(t *testing.T) {
+
+       // make a test impl object
+       var mockedService = new(TestExampleImplementation)
+
+       c := mockedService.
+               On("TheExampleMethod", "A", "B", true).
+               Return()
+
+       require.Equal(t, []*Call{c}, mockedService.ExpectedCalls)
+
+       call := mockedService.ExpectedCalls[0]
+
+       assert.Equal(t, "TheExampleMethod", call.Method)
+       assert.Equal(t, "A", call.Arguments[0])
+       assert.Equal(t, "B", call.Arguments[1])
+       assert.Equal(t, true, call.Arguments[2])
+       assert.Equal(t, 0, len(call.ReturnArguments))
+}
+
+func Test_Mock_findExpectedCall(t *testing.T) {
+
+       m := new(Mock)
+       m.On("One", 1).Return("one")
+       m.On("Two", 2).Return("two")
+       m.On("Two", 3).Return("three")
+
+       f, c := m.findExpectedCall("Two", 3)
+
+       if assert.Equal(t, 2, f) {
+               if assert.NotNil(t, c) {
+                       assert.Equal(t, "Two", c.Method)
+                       assert.Equal(t, 3, c.Arguments[0])
+                       assert.Equal(t, "three", c.ReturnArguments[0])
+               }
+       }
+
+}
+
+func Test_Mock_findExpectedCall_For_Unknown_Method(t *testing.T) {
+
+       m := new(Mock)
+       m.On("One", 1).Return("one")
+       m.On("Two", 2).Return("two")
+       m.On("Two", 3).Return("three")
+
+       f, _ := m.findExpectedCall("Two")
+
+       assert.Equal(t, -1, f)
+
+}
+
+func Test_Mock_findExpectedCall_Respects_Repeatability(t *testing.T) {
+
+       m := new(Mock)
+       m.On("One", 1).Return("one")
+       m.On("Two", 2).Return("two").Once()
+       m.On("Two", 3).Return("three").Twice()
+       m.On("Two", 3).Return("three").Times(8)
+
+       f, c := m.findExpectedCall("Two", 3)
+
+       if assert.Equal(t, 2, f) {
+               if assert.NotNil(t, c) {
+                       assert.Equal(t, "Two", c.Method)
+                       assert.Equal(t, 3, c.Arguments[0])
+                       assert.Equal(t, "three", c.ReturnArguments[0])
+               }
+       }
+
+}
+
+func Test_callString(t *testing.T) {
+
+       assert.Equal(t, `Method(int,bool,string)`, callString("Method", []interface{}{1, true, "something"}, false))
+
+}
+
+func Test_Mock_Called(t *testing.T) {
+
+       var mockedService = new(TestExampleImplementation)
+
+       mockedService.On("Test_Mock_Called", 1, 2, 3).Return(5, "6", true)
+
+       returnArguments := mockedService.Called(1, 2, 3)
+
+       if assert.Equal(t, 1, len(mockedService.Calls)) {
+               assert.Equal(t, "Test_Mock_Called", mockedService.Calls[0].Method)
+               assert.Equal(t, 1, mockedService.Calls[0].Arguments[0])
+               assert.Equal(t, 2, mockedService.Calls[0].Arguments[1])
+               assert.Equal(t, 3, mockedService.Calls[0].Arguments[2])
+       }
+
+       if assert.Equal(t, 3, len(returnArguments)) {
+               assert.Equal(t, 5, returnArguments[0])
+               assert.Equal(t, "6", returnArguments[1])
+               assert.Equal(t, true, returnArguments[2])
+       }
+
+}
+
+func asyncCall(m *Mock, ch chan Arguments) {
+       ch <- m.Called(1, 2, 3)
+}
+
+func Test_Mock_Called_blocks(t *testing.T) {
+
+       var mockedService = new(TestExampleImplementation)
+
+       mockedService.Mock.On("asyncCall", 1, 2, 3).Return(5, "6", true).After(2 * time.Millisecond)
+
+       ch := make(chan Arguments)
+
+       go asyncCall(&mockedService.Mock, ch)
+
+       select {
+       case <-ch:
+               t.Fatal("should have waited")
+       case <-time.After(1 * time.Millisecond):
+       }
+
+       returnArguments := <-ch
+
+       if assert.Equal(t, 1, len(mockedService.Mock.Calls)) {
+               assert.Equal(t, "asyncCall", mockedService.Mock.Calls[0].Method)
+               assert.Equal(t, 1, mockedService.Mock.Calls[0].Arguments[0])
+               assert.Equal(t, 2, mockedService.Mock.Calls[0].Arguments[1])
+               assert.Equal(t, 3, mockedService.Mock.Calls[0].Arguments[2])
+       }
+
+       if assert.Equal(t, 3, len(returnArguments)) {
+               assert.Equal(t, 5, returnArguments[0])
+               assert.Equal(t, "6", returnArguments[1])
+               assert.Equal(t, true, returnArguments[2])
+       }
+
+}
+
+func Test_Mock_Called_For_Bounded_Repeatability(t *testing.T) {
+
+       var mockedService = new(TestExampleImplementation)
+
+       mockedService.
+               On("Test_Mock_Called_For_Bounded_Repeatability", 1, 2, 3).
+               Return(5, "6", true).
+               Once()
+       mockedService.
+               On("Test_Mock_Called_For_Bounded_Repeatability", 1, 2, 3).
+               Return(-1, "hi", false)
+
+       returnArguments1 := mockedService.Called(1, 2, 3)
+       returnArguments2 := mockedService.Called(1, 2, 3)
+
+       if assert.Equal(t, 2, len(mockedService.Calls)) {
+               assert.Equal(t, "Test_Mock_Called_For_Bounded_Repeatability", mockedService.Calls[0].Method)
+               assert.Equal(t, 1, mockedService.Calls[0].Arguments[0])
+               assert.Equal(t, 2, mockedService.Calls[0].Arguments[1])
+               assert.Equal(t, 3, mockedService.Calls[0].Arguments[2])
+
+               assert.Equal(t, "Test_Mock_Called_For_Bounded_Repeatability", mockedService.Calls[1].Method)
+               assert.Equal(t, 1, mockedService.Calls[1].Arguments[0])
+               assert.Equal(t, 2, mockedService.Calls[1].Arguments[1])
+               assert.Equal(t, 3, mockedService.Calls[1].Arguments[2])
+       }
+
+       if assert.Equal(t, 3, len(returnArguments1)) {
+               assert.Equal(t, 5, returnArguments1[0])
+               assert.Equal(t, "6", returnArguments1[1])
+               assert.Equal(t, true, returnArguments1[2])
+       }
+
+       if assert.Equal(t, 3, len(returnArguments2)) {
+               assert.Equal(t, -1, returnArguments2[0])
+               assert.Equal(t, "hi", returnArguments2[1])
+               assert.Equal(t, false, returnArguments2[2])
+       }
+
+}
+
+func Test_Mock_Called_For_SetTime_Expectation(t *testing.T) {
+
+       var mockedService = new(TestExampleImplementation)
+
+       mockedService.On("TheExampleMethod", 1, 2, 3).Return(5, "6", true).Times(4)
+
+       mockedService.TheExampleMethod(1, 2, 3)
+       mockedService.TheExampleMethod(1, 2, 3)
+       mockedService.TheExampleMethod(1, 2, 3)
+       mockedService.TheExampleMethod(1, 2, 3)
+       assert.Panics(t, func() {
+               mockedService.TheExampleMethod(1, 2, 3)
+       })
+
+}
+
+func Test_Mock_Called_Unexpected(t *testing.T) {
+
+       var mockedService = new(TestExampleImplementation)
+
+       // make sure it panics if no expectation was made
+       assert.Panics(t, func() {
+               mockedService.Called(1, 2, 3)
+       }, "Calling unexpected method should panic")
+
+}
+
+func Test_AssertExpectationsForObjects_Helper(t *testing.T) {
+
+       var mockedService1 = new(TestExampleImplementation)
+       var mockedService2 = new(TestExampleImplementation)
+       var mockedService3 = new(TestExampleImplementation)
+
+       mockedService1.On("Test_AssertExpectationsForObjects_Helper", 1).Return()
+       mockedService2.On("Test_AssertExpectationsForObjects_Helper", 2).Return()
+       mockedService3.On("Test_AssertExpectationsForObjects_Helper", 3).Return()
+
+       mockedService1.Called(1)
+       mockedService2.Called(2)
+       mockedService3.Called(3)
+
+       assert.True(t, AssertExpectationsForObjects(t, mockedService1.Mock, mockedService2.Mock, mockedService3.Mock))
+
+}
+
+func Test_AssertExpectationsForObjects_Helper_Failed(t *testing.T) {
+
+       var mockedService1 = new(TestExampleImplementation)
+       var mockedService2 = new(TestExampleImplementation)
+       var mockedService3 = new(TestExampleImplementation)
+
+       mockedService1.On("Test_AssertExpectationsForObjects_Helper_Failed", 1).Return()
+       mockedService2.On("Test_AssertExpectationsForObjects_Helper_Failed", 2).Return()
+       mockedService3.On("Test_AssertExpectationsForObjects_Helper_Failed", 3).Return()
+
+       mockedService1.Called(1)
+       mockedService3.Called(3)
+
+       tt := new(testing.T)
+       assert.False(t, AssertExpectationsForObjects(tt, mockedService1.Mock, mockedService2.Mock, mockedService3.Mock))
+
+}
+
+func Test_Mock_AssertExpectations(t *testing.T) {
+
+       var mockedService = new(TestExampleImplementation)
+
+       mockedService.On("Test_Mock_AssertExpectations", 1, 2, 3).Return(5, 6, 7)
+
+       tt := new(testing.T)
+       assert.False(t, mockedService.AssertExpectations(tt))
+
+       // make the call now
+       mockedService.Called(1, 2, 3)
+
+       // now assert expectations
+       assert.True(t, mockedService.AssertExpectations(tt))
+
+}
+
+func Test_Mock_AssertExpectations_Placeholder_NoArgs(t *testing.T) {
+
+       var mockedService = new(TestExampleImplementation)
+
+       mockedService.On("Test_Mock_AssertExpectations_Placeholder_NoArgs").Return(5, 6, 7).Once()
+       mockedService.On("Test_Mock_AssertExpectations_Placeholder_NoArgs").Return(7, 6, 5)
+
+       tt := new(testing.T)
+       assert.False(t, mockedService.AssertExpectations(tt))
+
+       // make the call now
+       mockedService.Called()
+
+       // now assert expectations
+       assert.True(t, mockedService.AssertExpectations(tt))
+
+}
+
+func Test_Mock_AssertExpectations_Placeholder(t *testing.T) {
+
+       var mockedService = new(TestExampleImplementation)
+
+       mockedService.On("Test_Mock_AssertExpectations_Placeholder", 1, 2, 3).Return(5, 6, 7).Once()
+       mockedService.On("Test_Mock_AssertExpectations_Placeholder", 3, 2, 1).Return(7, 6, 5)
+
+       tt := new(testing.T)
+       assert.False(t, mockedService.AssertExpectations(tt))
+
+       // make the call now
+       mockedService.Called(1, 2, 3)
+
+       // now assert expectations
+       assert.False(t, mockedService.AssertExpectations(tt))
+
+       // make call to the second expectation
+       mockedService.Called(3, 2, 1)
+
+       // now assert expectations again
+       assert.True(t, mockedService.AssertExpectations(tt))
+}
+
+func Test_Mock_AssertExpectations_With_Pointers(t *testing.T) {
+
+       var mockedService = new(TestExampleImplementation)
+
+       mockedService.On("Test_Mock_AssertExpectations_With_Pointers", &struct{ Foo int }{1}).Return(1)
+       mockedService.On("Test_Mock_AssertExpectations_With_Pointers", &struct{ Foo int }{2}).Return(2)
+
+       tt := new(testing.T)
+       assert.False(t, mockedService.AssertExpectations(tt))
+
+       s := struct{ Foo int }{1}
+       // make the calls now
+       mockedService.Called(&s)
+       s.Foo = 2
+       mockedService.Called(&s)
+
+       // now assert expectations
+       assert.True(t, mockedService.AssertExpectations(tt))
+
+}
+
+func Test_Mock_AssertExpectationsCustomType(t *testing.T) {
+
+       var mockedService = new(TestExampleImplementation)
+
+       mockedService.On("TheExampleMethod3", AnythingOfType("*mock.ExampleType")).Return(nil).Once()
+
+       tt := new(testing.T)
+       assert.False(t, mockedService.AssertExpectations(tt))
+
+       // make the call now
+       mockedService.TheExampleMethod3(&ExampleType{})
+
+       // now assert expectations
+       assert.True(t, mockedService.AssertExpectations(tt))
+
+}
+
+func Test_Mock_AssertExpectations_With_Repeatability(t *testing.T) {
+
+       var mockedService = new(TestExampleImplementation)
+
+       mockedService.On("Test_Mock_AssertExpectations_With_Repeatability", 1, 2, 3).Return(5, 6, 7).Twice()
+
+       tt := new(testing.T)
+       assert.False(t, mockedService.AssertExpectations(tt))
+
+       // make the call now
+       mockedService.Called(1, 2, 3)
+
+       assert.False(t, mockedService.AssertExpectations(tt))
+
+       mockedService.Called(1, 2, 3)
+
+       // now assert expectations
+       assert.True(t, mockedService.AssertExpectations(tt))
+
+}
+
+func Test_Mock_TwoCallsWithDifferentArguments(t *testing.T) {
+
+       var mockedService = new(TestExampleImplementation)
+
+       mockedService.On("Test_Mock_TwoCallsWithDifferentArguments", 1, 2, 3).Return(5, 6, 7)
+       mockedService.On("Test_Mock_TwoCallsWithDifferentArguments", 4, 5, 6).Return(5, 6, 7)
+
+       args1 := mockedService.Called(1, 2, 3)
+       assert.Equal(t, 5, args1.Int(0))
+       assert.Equal(t, 6, args1.Int(1))
+       assert.Equal(t, 7, args1.Int(2))
+
+       args2 := mockedService.Called(4, 5, 6)
+       assert.Equal(t, 5, args2.Int(0))
+       assert.Equal(t, 6, args2.Int(1))
+       assert.Equal(t, 7, args2.Int(2))
+
+}
+
+func Test_Mock_AssertNumberOfCalls(t *testing.T) {
+
+       var mockedService = new(TestExampleImplementation)
+
+       mockedService.On("Test_Mock_AssertNumberOfCalls", 1, 2, 3).Return(5, 6, 7)
+
+       mockedService.Called(1, 2, 3)
+       assert.True(t, mockedService.AssertNumberOfCalls(t, "Test_Mock_AssertNumberOfCalls", 1))
+
+       mockedService.Called(1, 2, 3)
+       assert.True(t, mockedService.AssertNumberOfCalls(t, "Test_Mock_AssertNumberOfCalls", 2))
+
+}
+
+func Test_Mock_AssertCalled(t *testing.T) {
+
+       var mockedService = new(TestExampleImplementation)
+
+       mockedService.On("Test_Mock_AssertCalled", 1, 2, 3).Return(5, 6, 7)
+
+       mockedService.Called(1, 2, 3)
+
+       assert.True(t, mockedService.AssertCalled(t, "Test_Mock_AssertCalled", 1, 2, 3))
+
+}
+
+func Test_Mock_AssertCalled_WithAnythingOfTypeArgument(t *testing.T) {
+
+       var mockedService = new(TestExampleImplementation)
+
+       mockedService.
+               On("Test_Mock_AssertCalled_WithAnythingOfTypeArgument", Anything, Anything, Anything).
+               Return()
+
+       mockedService.Called(1, "two", []uint8("three"))
+
+       assert.True(t, mockedService.AssertCalled(t, "Test_Mock_AssertCalled_WithAnythingOfTypeArgument", AnythingOfType("int"), AnythingOfType("string"), AnythingOfType("[]uint8")))
+
+}
+
+func Test_Mock_AssertCalled_WithArguments(t *testing.T) {
+
+       var mockedService = new(TestExampleImplementation)
+
+       mockedService.On("Test_Mock_AssertCalled_WithArguments", 1, 2, 3).Return(5, 6, 7)
+
+       mockedService.Called(1, 2, 3)
+
+       tt := new(testing.T)
+       assert.True(t, mockedService.AssertCalled(tt, "Test_Mock_AssertCalled_WithArguments", 1, 2, 3))
+       assert.False(t, mockedService.AssertCalled(tt, "Test_Mock_AssertCalled_WithArguments", 2, 3, 4))
+
+}
+
+func Test_Mock_AssertCalled_WithArguments_With_Repeatability(t *testing.T) {
+
+       var mockedService = new(TestExampleImplementation)
+
+       mockedService.On("Test_Mock_AssertCalled_WithArguments_With_Repeatability", 1, 2, 3).Return(5, 6, 7).Once()
+       mockedService.On("Test_Mock_AssertCalled_WithArguments_With_Repeatability", 2, 3, 4).Return(5, 6, 7).Once()
+
+       mockedService.Called(1, 2, 3)
+       mockedService.Called(2, 3, 4)
+
+       tt := new(testing.T)
+       assert.True(t, mockedService.AssertCalled(tt, "Test_Mock_AssertCalled_WithArguments_With_Repeatability", 1, 2, 3))
+       assert.True(t, mockedService.AssertCalled(tt, "Test_Mock_AssertCalled_WithArguments_With_Repeatability", 2, 3, 4))
+       assert.False(t, mockedService.AssertCalled(tt, "Test_Mock_AssertCalled_WithArguments_With_Repeatability", 3, 4, 5))
+
+}
+
+func Test_Mock_AssertNotCalled(t *testing.T) {
+
+       var mockedService = new(TestExampleImplementation)
+
+       mockedService.On("Test_Mock_AssertNotCalled", 1, 2, 3).Return(5, 6, 7)
+
+       mockedService.Called(1, 2, 3)
+
+       assert.True(t, mockedService.AssertNotCalled(t, "Test_Mock_NotCalled"))
+
+}
+
+/*
+       Arguments helper methods
+*/
+func Test_Arguments_Get(t *testing.T) {
+
+       var args = Arguments([]interface{}{"string", 123, true})
+
+       assert.Equal(t, "string", args.Get(0).(string))
+       assert.Equal(t, 123, args.Get(1).(int))
+       assert.Equal(t, true, args.Get(2).(bool))
+
+}
+
+func Test_Arguments_Is(t *testing.T) {
+
+       var args = Arguments([]interface{}{"string", 123, true})
+
+       assert.True(t, args.Is("string", 123, true))
+       assert.False(t, args.Is("wrong", 456, false))
+
+}
+
+func Test_Arguments_Diff(t *testing.T) {
+
+       var args = Arguments([]interface{}{"Hello World", 123, true})
+       var diff string
+       var count int
+       diff, count = args.Diff([]interface{}{"Hello World", 456, "false"})
+
+       assert.Equal(t, 2, count)
+       assert.Contains(t, diff, `%!s(int=456) != %!s(int=123)`)
+       assert.Contains(t, diff, `false != %!s(bool=true)`)
+
+}
+
+func Test_Arguments_Diff_DifferentNumberOfArgs(t *testing.T) {
+
+       var args = Arguments([]interface{}{"string", 123, true})
+       var diff string
+       var count int
+       diff, count = args.Diff([]interface{}{"string", 456, "false", "extra"})
+
+       assert.Equal(t, 3, count)
+       assert.Contains(t, diff, `extra != (Missing)`)
+
+}
+
+func Test_Arguments_Diff_WithAnythingArgument(t *testing.T) {
+
+       var args = Arguments([]interface{}{"string", 123, true})
+       var count int
+       _, count = args.Diff([]interface{}{"string", Anything, true})
+
+       assert.Equal(t, 0, count)
+
+}
+
+func Test_Arguments_Diff_WithAnythingArgument_InActualToo(t *testing.T) {
+
+       var args = Arguments([]interface{}{"string", Anything, true})
+       var count int
+       _, count = args.Diff([]interface{}{"string", 123, true})
+
+       assert.Equal(t, 0, count)
+
+}
+
+func Test_Arguments_Diff_WithAnythingOfTypeArgument(t *testing.T) {
+
+       var args = Arguments([]interface{}{"string", AnythingOfType("int"), true})
+       var count int
+       _, count = args.Diff([]interface{}{"string", 123, true})
+
+       assert.Equal(t, 0, count)
+
+}
+
+func Test_Arguments_Diff_WithAnythingOfTypeArgument_Failing(t *testing.T) {
+
+       var args = Arguments([]interface{}{"string", AnythingOfType("string"), true})
+       var count int
+       var diff string
+       diff, count = args.Diff([]interface{}{"string", 123, true})
+
+       assert.Equal(t, 1, count)
+       assert.Contains(t, diff, `string != type int - %!s(int=123)`)
+
+}
+
+func Test_Arguments_Diff_WithArgMatcher(t *testing.T) {
+       matchFn := func(a int) bool {
+               return a == 123
+       }
+       var args = Arguments([]interface{}{"string", MatchedBy(matchFn), true})
+
+       diff, count := args.Diff([]interface{}{"string", 124, true})
+       assert.Equal(t, 1, count)
+       assert.Contains(t, diff, `%!s(int=124) not matched by func(int) bool`)
+
+       diff, count = args.Diff([]interface{}{"string", false, true})
+       assert.Equal(t, 1, count)
+       assert.Contains(t, diff, `%!s(bool=false) not matched by func(int) bool`)
+
+       diff, count = args.Diff([]interface{}{"string", 123, false})
+       assert.Contains(t, diff, `%!s(int=123) matched by func(int) bool`)
+
+       diff, count = args.Diff([]interface{}{"string", 123, true})
+       assert.Equal(t, 0, count)
+       assert.Contains(t, diff, `No differences.`)
+}
+
+func Test_Arguments_Assert(t *testing.T) {
+
+       var args = Arguments([]interface{}{"string", 123, true})
+
+       assert.True(t, args.Assert(t, "string", 123, true))
+
+}
+
+func Test_Arguments_String_Representation(t *testing.T) {
+
+       var args = Arguments([]interface{}{"string", 123, true})
+       assert.Equal(t, `string,int,bool`, args.String())
+
+}
+
+func Test_Arguments_String(t *testing.T) {
+
+       var args = Arguments([]interface{}{"string", 123, true})
+       assert.Equal(t, "string", args.String(0))
+
+}
+
+func Test_Arguments_Error(t *testing.T) {
+
+       var err = errors.New("An Error")
+       var args = Arguments([]interface{}{"string", 123, true, err})
+       assert.Equal(t, err, args.Error(3))
+
+}
+
+func Test_Arguments_Error_Nil(t *testing.T) {
+
+       var args = Arguments([]interface{}{"string", 123, true, nil})
+       assert.Equal(t, nil, args.Error(3))
+
+}
+
+func Test_Arguments_Int(t *testing.T) {
+
+       var args = Arguments([]interface{}{"string", 123, true})
+       assert.Equal(t, 123, args.Int(1))
+
+}
+
+func Test_Arguments_Bool(t *testing.T) {
+
+       var args = Arguments([]interface{}{"string", 123, true})
+       assert.Equal(t, true, args.Bool(2))
+
+}
diff --git a/vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/package_test.go b/vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/package_test.go
new file mode 100644 (file)
index 0000000..7ac5d6d
--- /dev/null
@@ -0,0 +1,12 @@
+package testify
+
+import (
+       "github.com/stretchr/testify/assert"
+       "testing"
+)
+
+func TestImports(t *testing.T) {
+       if assert.Equal(t, 1, 1) != true {
+               t.Error("Something is wrong.")
+       }
+}
diff --git a/vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/require/doc.go b/vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/require/doc.go
new file mode 100644 (file)
index 0000000..169de39
--- /dev/null
@@ -0,0 +1,28 @@
+// Package require implements the same assertions as the `assert` package but
+// stops test execution when a test fails.
+//
+// Example Usage
+//
+// The following is a complete example using require in a standard test function:
+//    import (
+//      "testing"
+//      "github.com/stretchr/testify/require"
+//    )
+//
+//    func TestSomething(t *testing.T) {
+//
+//      var a string = "Hello"
+//      var b string = "Hello"
+//
+//      require.Equal(t, a, b, "The two words should be the same.")
+//
+//    }
+//
+// Assertions
+//
+// The `require` package have same global functions as in the `assert` package,
+// but instead of returning a boolean result they call `t.FailNow()`.
+//
+// Every assertion function also takes an optional string message as the final argument,
+// allowing custom error messages to be appended to the message the assertion method outputs.
+package require
diff --git a/vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/require/forward_requirements.go b/vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/require/forward_requirements.go
new file mode 100644 (file)
index 0000000..d3c2ab9
--- /dev/null
@@ -0,0 +1,16 @@
+package require
+
+// Assertions provides assertion methods around the
+// TestingT interface.
+type Assertions struct {
+       t TestingT
+}
+
+// New makes a new Assertions object for the specified TestingT.
+func New(t TestingT) *Assertions {
+       return &Assertions{
+               t: t,
+       }
+}
+
+//go:generate go run ../_codegen/main.go -output-package=require -template=require_forward.go.tmpl
diff --git a/vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/require/forward_requirements_test.go b/vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/require/forward_requirements_test.go
new file mode 100644 (file)
index 0000000..b120ae3
--- /dev/null
@@ -0,0 +1,385 @@
+package require
+
+import (
+       "errors"
+       "testing"
+       "time"
+)
+
+func TestImplementsWrapper(t *testing.T) {
+       require := New(t)
+
+       require.Implements((*AssertionTesterInterface)(nil), new(AssertionTesterConformingObject))
+
+       mockT := new(MockT)
+       mockRequire := New(mockT)
+       mockRequire.Implements((*AssertionTesterInterface)(nil), new(AssertionTesterNonConformingObject))
+       if !mockT.Failed {
+               t.Error("Check should fail")
+       }
+}
+
+func TestIsTypeWrapper(t *testing.T) {
+       require := New(t)
+       require.IsType(new(AssertionTesterConformingObject), new(AssertionTesterConformingObject))
+
+       mockT := new(MockT)
+       mockRequire := New(mockT)
+       mockRequire.IsType(new(AssertionTesterConformingObject), new(AssertionTesterNonConformingObject))
+       if !mockT.Failed {
+               t.Error("Check should fail")
+       }
+}
+
+func TestEqualWrapper(t *testing.T) {
+       require := New(t)
+       require.Equal(1, 1)
+
+       mockT := new(MockT)
+       mockRequire := New(mockT)
+       mockRequire.Equal(1, 2)
+       if !mockT.Failed {
+               t.Error("Check should fail")
+       }
+}
+
+func TestNotEqualWrapper(t *testing.T) {
+       require := New(t)
+       require.NotEqual(1, 2)
+
+       mockT := new(MockT)
+       mockRequire := New(mockT)
+       mockRequire.NotEqual(2, 2)
+       if !mockT.Failed {
+               t.Error("Check should fail")
+       }
+}
+
+func TestExactlyWrapper(t *testing.T) {
+       require := New(t)
+
+       a := float32(1)
+       b := float32(1)
+       c := float64(1)
+
+       require.Exactly(a, b)
+
+       mockT := new(MockT)
+       mockRequire := New(mockT)
+       mockRequire.Exactly(a, c)
+       if !mockT.Failed {
+               t.Error("Check should fail")
+       }
+}
+
+func TestNotNilWrapper(t *testing.T) {
+       require := New(t)
+       require.NotNil(t, new(AssertionTesterConformingObject))
+
+       mockT := new(MockT)
+       mockRequire := New(mockT)
+       mockRequire.NotNil(nil)
+       if !mockT.Failed {
+               t.Error("Check should fail")
+       }
+}
+
+func TestNilWrapper(t *testing.T) {
+       require := New(t)
+       require.Nil(nil)
+
+       mockT := new(MockT)
+       mockRequire := New(mockT)
+       mockRequire.Nil(new(AssertionTesterConformingObject))
+       if !mockT.Failed {
+               t.Error("Check should fail")
+       }
+}
+
+func TestTrueWrapper(t *testing.T) {
+       require := New(t)
+       require.True(true)
+
+       mockT := new(MockT)
+       mockRequire := New(mockT)
+       mockRequire.True(false)
+       if !mockT.Failed {
+               t.Error("Check should fail")
+       }
+}
+
+func TestFalseWrapper(t *testing.T) {
+       require := New(t)
+       require.False(false)
+
+       mockT := new(MockT)
+       mockRequire := New(mockT)
+       mockRequire.False(true)
+       if !mockT.Failed {
+               t.Error("Check should fail")
+       }
+}
+
+func TestContainsWrapper(t *testing.T) {
+       require := New(t)
+       require.Contains("Hello World", "Hello")
+
+       mockT := new(MockT)
+       mockRequire := New(mockT)
+       mockRequire.Contains("Hello World", "Salut")
+       if !mockT.Failed {
+               t.Error("Check should fail")
+       }
+}
+
+func TestNotContainsWrapper(t *testing.T) {
+       require := New(t)
+       require.NotContains("Hello World", "Hello!")
+
+       mockT := new(MockT)
+       mockRequire := New(mockT)
+       mockRequire.NotContains("Hello World", "Hello")
+       if !mockT.Failed {
+               t.Error("Check should fail")
+       }
+}
+
+func TestPanicsWrapper(t *testing.T) {
+       require := New(t)
+       require.Panics(func() {
+               panic("Panic!")
+       })
+
+       mockT := new(MockT)
+       mockRequire := New(mockT)
+       mockRequire.Panics(func() {})
+       if !mockT.Failed {
+               t.Error("Check should fail")
+       }
+}
+
+func TestNotPanicsWrapper(t *testing.T) {
+       require := New(t)
+       require.NotPanics(func() {})
+
+       mockT := new(MockT)
+       mockRequire := New(mockT)
+       mockRequire.NotPanics(func() {
+               panic("Panic!")
+       })
+       if !mockT.Failed {
+               t.Error("Check should fail")
+       }
+}
+
+func TestNoErrorWrapper(t *testing.T) {
+       require := New(t)
+       require.NoError(nil)
+
+       mockT := new(MockT)
+       mockRequire := New(mockT)
+       mockRequire.NoError(errors.New("some error"))
+       if !mockT.Failed {
+               t.Error("Check should fail")
+       }
+}
+
+func TestErrorWrapper(t *testing.T) {
+       require := New(t)
+       require.Error(errors.New("some error"))
+
+       mockT := new(MockT)
+       mockRequire := New(mockT)
+       mockRequire.Error(nil)
+       if !mockT.Failed {
+               t.Error("Check should fail")
+       }
+}
+
+func TestEqualErrorWrapper(t *testing.T) {
+       require := New(t)
+       require.EqualError(errors.New("some error"), "some error")
+
+       mockT := new(MockT)
+       mockRequire := New(mockT)
+       mockRequire.EqualError(errors.New("some error"), "Not some error")
+       if !mockT.Failed {
+               t.Error("Check should fail")
+       }
+}
+
+func TestEmptyWrapper(t *testing.T) {
+       require := New(t)
+       require.Empty("")
+
+       mockT := new(MockT)
+       mockRequire := New(mockT)
+       mockRequire.Empty("x")
+       if !mockT.Failed {
+               t.Error("Check should fail")
+       }
+}
+
+func TestNotEmptyWrapper(t *testing.T) {
+       require := New(t)
+       require.NotEmpty("x")
+
+       mockT := new(MockT)
+       mockRequire := New(mockT)
+       mockRequire.NotEmpty("")
+       if !mockT.Failed {
+               t.Error("Check should fail")
+       }
+}
+
+func TestWithinDurationWrapper(t *testing.T) {
+       require := New(t)
+       a := time.Now()
+       b := a.Add(10 * time.Second)
+
+       require.WithinDuration(a, b, 15*time.Second)
+
+       mockT := new(MockT)
+       mockRequire := New(mockT)
+       mockRequire.WithinDuration(a, b, 5*time.Second)
+       if !mockT.Failed {
+               t.Error("Check should fail")
+       }
+}
+
+func TestInDeltaWrapper(t *testing.T) {
+       require := New(t)
+       require.InDelta(1.001, 1, 0.01)
+
+       mockT := new(MockT)
+       mockRequire := New(mockT)
+       mockRequire.InDelta(1, 2, 0.5)
+       if !mockT.Failed {
+               t.Error("Check should fail")
+       }
+}
+
+func TestZeroWrapper(t *testing.T) {
+       require := New(t)
+       require.Zero(0)
+
+       mockT := new(MockT)
+       mockRequire := New(mockT)
+       mockRequire.Zero(1)
+       if !mockT.Failed {
+               t.Error("Check should fail")
+       }
+}
+
+func TestNotZeroWrapper(t *testing.T) {
+       require := New(t)
+       require.NotZero(1)
+
+       mockT := new(MockT)
+       mockRequire := New(mockT)
+       mockRequire.NotZero(0)
+       if !mockT.Failed {
+               t.Error("Check should fail")
+       }
+}
+
+func TestJSONEqWrapper_EqualSONString(t *testing.T) {
+       mockT := new(MockT)
+       mockRequire := New(mockT)
+
+       mockRequire.JSONEq(`{"hello": "world", "foo": "bar"}`, `{"hello": "world", "foo": "bar"}`)
+       if mockT.Failed {
+               t.Error("Check should pass")
+       }
+}
+
+func TestJSONEqWrapper_EquivalentButNotEqual(t *testing.T) {
+       mockT := new(MockT)
+       mockRequire := New(mockT)
+
+       mockRequire.JSONEq(`{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`)
+       if mockT.Failed {
+               t.Error("Check should pass")
+       }
+}
+
+func TestJSONEqWrapper_HashOfArraysAndHashes(t *testing.T) {
+       mockT := new(MockT)
+       mockRequire := New(mockT)
+
+       mockRequire.JSONEq("{\r\n\t\"numeric\": 1.5,\r\n\t\"array\": [{\"foo\": \"bar\"}, 1, \"string\", [\"nested\", \"array\", 5.5]],\r\n\t\"hash\": {\"nested\": \"hash\", \"nested_slice\": [\"this\", \"is\", \"nested\"]},\r\n\t\"string\": \"foo\"\r\n}",
+               "{\r\n\t\"numeric\": 1.5,\r\n\t\"hash\": {\"nested\": \"hash\", \"nested_slice\": [\"this\", \"is\", \"nested\"]},\r\n\t\"string\": \"foo\",\r\n\t\"array\": [{\"foo\": \"bar\"}, 1, \"string\", [\"nested\", \"array\", 5.5]]\r\n}")
+       if mockT.Failed {
+               t.Error("Check should pass")
+       }
+}
+
+func TestJSONEqWrapper_Array(t *testing.T) {
+       mockT := new(MockT)
+       mockRequire := New(mockT)
+
+       mockRequire.JSONEq(`["foo", {"hello": "world", "nested": "hash"}]`, `["foo", {"nested": "hash", "hello": "world"}]`)
+       if mockT.Failed {
+               t.Error("Check should pass")
+       }
+}
+
+func TestJSONEqWrapper_HashAndArrayNotEquivalent(t *testing.T) {
+       mockT := new(MockT)
+       mockRequire := New(mockT)
+
+       mockRequire.JSONEq(`["foo", {"hello": "world", "nested": "hash"}]`, `{"foo": "bar", {"nested": "hash", "hello": "world"}}`)
+       if !mockT.Failed {
+               t.Error("Check should fail")
+       }
+}
+
+func TestJSONEqWrapper_HashesNotEquivalent(t *testing.T) {
+       mockT := new(MockT)
+       mockRequire := New(mockT)
+
+       mockRequire.JSONEq(`{"foo": "bar"}`, `{"foo": "bar", "hello": "world"}`)
+       if !mockT.Failed {
+               t.Error("Check should fail")
+       }
+}
+
+func TestJSONEqWrapper_ActualIsNotJSON(t *testing.T) {
+       mockT := new(MockT)
+       mockRequire := New(mockT)
+
+       mockRequire.JSONEq(`{"foo": "bar"}`, "Not JSON")
+       if !mockT.Failed {
+               t.Error("Check should fail")
+       }
+}
+
+func TestJSONEqWrapper_ExpectedIsNotJSON(t *testing.T) {
+       mockT := new(MockT)
+       mockRequire := New(mockT)
+
+       mockRequire.JSONEq("Not JSON", `{"foo": "bar", "hello": "world"}`)
+       if !mockT.Failed {
+               t.Error("Check should fail")
+       }
+}
+
+func TestJSONEqWrapper_ExpectedAndActualNotJSON(t *testing.T) {
+       mockT := new(MockT)
+       mockRequire := New(mockT)
+
+       mockRequire.JSONEq("Not JSON", "Not JSON")
+       if !mockT.Failed {
+               t.Error("Check should fail")
+       }
+}
+
+func TestJSONEqWrapper_ArraysOfDifferentOrder(t *testing.T) {
+       mockT := new(MockT)
+       mockRequire := New(mockT)
+
+       mockRequire.JSONEq(`["foo", {"hello": "world", "nested": "hash"}]`, `[{ "hello": "world", "nested": "hash"}, "foo"]`)
+       if !mockT.Failed {
+               t.Error("Check should fail")
+       }
+}
diff --git a/vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/require/require.go b/vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/require/require.go
new file mode 100644 (file)
index 0000000..1bcfcb0
--- /dev/null
@@ -0,0 +1,464 @@
+/*
+* CODE GENERATED AUTOMATICALLY WITH github.com/stretchr/testify/_codegen
+* THIS FILE MUST NOT BE EDITED BY HAND
+*/
+
+package require
+
+import (
+
+       assert "github.com/stretchr/testify/assert"
+       http "net/http"
+       url "net/url"
+       time "time"
+)
+
+
+// Condition uses a Comparison to assert a complex condition.
+func Condition(t TestingT, comp assert.Comparison, msgAndArgs ...interface{}) {
+  if !assert.Condition(t, comp, msgAndArgs...) {
+    t.FailNow()
+  }
+}
+
+
+// Contains asserts that the specified string, list(array, slice...) or map contains the
+// specified substring or element.
+// 
+//    assert.Contains(t, "Hello World", "World", "But 'Hello World' does contain 'World'")
+//    assert.Contains(t, ["Hello", "World"], "World", "But ["Hello", "World"] does contain 'World'")
+//    assert.Contains(t, {"Hello": "World"}, "Hello", "But {'Hello': 'World'} does contain 'Hello'")
+// 
+// Returns whether the assertion was successful (true) or not (false).
+func Contains(t TestingT, s interface{}, contains interface{}, msgAndArgs ...interface{}) {
+  if !assert.Contains(t, s, contains, msgAndArgs...) {
+    t.FailNow()
+  }
+}
+
+
+// Empty asserts that the specified object is empty.  I.e. nil, "", false, 0 or either
+// a slice or a channel with len == 0.
+// 
+//  assert.Empty(t, obj)
+// 
+// Returns whether the assertion was successful (true) or not (false).
+func Empty(t TestingT, object interface{}, msgAndArgs ...interface{}) {
+  if !assert.Empty(t, object, msgAndArgs...) {
+    t.FailNow()
+  }
+}
+
+
+// Equal asserts that two objects are equal.
+// 
+//    assert.Equal(t, 123, 123, "123 and 123 should be equal")
+// 
+// Returns whether the assertion was successful (true) or not (false).
+func Equal(t TestingT, expected interface{}, actual interface{}, msgAndArgs ...interface{}) {
+  if !assert.Equal(t, expected, actual, msgAndArgs...) {
+    t.FailNow()
+  }
+}
+
+
+// EqualError asserts that a function returned an error (i.e. not `nil`)
+// and that it is equal to the provided error.
+// 
+//   actualObj, err := SomeFunction()
+//   if assert.Error(t, err, "An error was expected") {
+//        assert.Equal(t, err, expectedError)
+//   }
+// 
+// Returns whether the assertion was successful (true) or not (false).
+func EqualError(t TestingT, theError error, errString string, msgAndArgs ...interface{}) {
+  if !assert.EqualError(t, theError, errString, msgAndArgs...) {
+    t.FailNow()
+  }
+}
+
+
+// EqualValues asserts that two objects are equal or convertable to the same types
+// and equal.
+// 
+//    assert.EqualValues(t, uint32(123), int32(123), "123 and 123 should be equal")
+// 
+// Returns whether the assertion was successful (true) or not (false).
+func EqualValues(t TestingT, expected interface{}, actual interface{}, msgAndArgs ...interface{}) {
+  if !assert.EqualValues(t, expected, actual, msgAndArgs...) {
+    t.FailNow()
+  }
+}
+
+
+// Error asserts that a function returned an error (i.e. not `nil`).
+// 
+//   actualObj, err := SomeFunction()
+//   if assert.Error(t, err, "An error was expected") {
+//        assert.Equal(t, err, expectedError)
+//   }
+// 
+// Returns whether the assertion was successful (true) or not (false).
+func Error(t TestingT, err error, msgAndArgs ...interface{}) {
+  if !assert.Error(t, err, msgAndArgs...) {
+    t.FailNow()
+  }
+}
+
+
+// Exactly asserts that two objects are equal is value and type.
+// 
+//    assert.Exactly(t, int32(123), int64(123), "123 and 123 should NOT be equal")
+// 
+// Returns whether the assertion was successful (true) or not (false).
+func Exactly(t TestingT, expected interface{}, actual interface{}, msgAndArgs ...interface{}) {
+  if !assert.Exactly(t, expected, actual, msgAndArgs...) {
+    t.FailNow()
+  }
+}
+
+
+// Fail reports a failure through
+func Fail(t TestingT, failureMessage string, msgAndArgs ...interface{}) {
+  if !assert.Fail(t, failureMessage, msgAndArgs...) {
+    t.FailNow()
+  }
+}
+
+
+// FailNow fails test
+func FailNow(t TestingT, failureMessage string, msgAndArgs ...interface{}) {
+  if !assert.FailNow(t, failureMessage, msgAndArgs...) {
+    t.FailNow()
+  }
+}
+
+
+// False asserts that the specified value is false.
+// 
+//    assert.False(t, myBool, "myBool should be false")
+// 
+// Returns whether the assertion was successful (true) or not (false).
+func False(t TestingT, value bool, msgAndArgs ...interface{}) {
+  if !assert.False(t, value, msgAndArgs...) {
+    t.FailNow()
+  }
+}
+
+
+// HTTPBodyContains asserts that a specified handler returns a
+// body that contains a string.
+// 
+//  assert.HTTPBodyContains(t, myHandler, "www.google.com", nil, "I'm Feeling Lucky")
+// 
+// Returns whether the assertion was successful (true) or not (false).
+func HTTPBodyContains(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, str interface{}) {
+  if !assert.HTTPBodyContains(t, handler, method, url, values, str) {
+    t.FailNow()
+  }
+}
+
+
+// HTTPBodyNotContains asserts that a specified handler returns a
+// body that does not contain a string.
+// 
+//  assert.HTTPBodyNotContains(t, myHandler, "www.google.com", nil, "I'm Feeling Lucky")
+// 
+// Returns whether the assertion was successful (true) or not (false).
+func HTTPBodyNotContains(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, str interface{}) {
+  if !assert.HTTPBodyNotContains(t, handler, method, url, values, str) {
+    t.FailNow()
+  }
+}
+
+
+// HTTPError asserts that a specified handler returns an error status code.
+// 
+//  assert.HTTPError(t, myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}}
+// 
+// Returns whether the assertion was successful (true) or not (false).
+func HTTPError(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values) {
+  if !assert.HTTPError(t, handler, method, url, values) {
+    t.FailNow()
+  }
+}
+
+
+// HTTPRedirect asserts that a specified handler returns a redirect status code.
+// 
+//  assert.HTTPRedirect(t, myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}}
+// 
+// Returns whether the assertion was successful (true) or not (false).
+func HTTPRedirect(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values) {
+  if !assert.HTTPRedirect(t, handler, method, url, values) {
+    t.FailNow()
+  }
+}
+
+
+// HTTPSuccess asserts that a specified handler returns a success status code.
+// 
+//  assert.HTTPSuccess(t, myHandler, "POST", "http://www.google.com", nil)
+// 
+// Returns whether the assertion was successful (true) or not (false).
+func HTTPSuccess(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values) {
+  if !assert.HTTPSuccess(t, handler, method, url, values) {
+    t.FailNow()
+  }
+}
+
+
+// Implements asserts that an object is implemented by the specified interface.
+// 
+//    assert.Implements(t, (*MyInterface)(nil), new(MyObject), "MyObject")
+func Implements(t TestingT, interfaceObject interface{}, object interface{}, msgAndArgs ...interface{}) {
+  if !assert.Implements(t, interfaceObject, object, msgAndArgs...) {
+    t.FailNow()
+  }
+}
+
+
+// InDelta asserts that the two numerals are within delta of each other.
+// 
+//      assert.InDelta(t, math.Pi, (22 / 7.0), 0.01)
+// 
+// Returns whether the assertion was successful (true) or not (false).
+func InDelta(t TestingT, expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) {
+  if !assert.InDelta(t, expected, actual, delta, msgAndArgs...) {
+    t.FailNow()
+  }
+}
+
+
+// InDeltaSlice is the same as InDelta, except it compares two slices.
+func InDeltaSlice(t TestingT, expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) {
+  if !assert.InDeltaSlice(t, expected, actual, delta, msgAndArgs...) {
+    t.FailNow()
+  }
+}
+
+
+// InEpsilon asserts that expected and actual have a relative error less than epsilon
+// 
+// Returns whether the assertion was successful (true) or not (false).
+func InEpsilon(t TestingT, expected interface{}, actual interface{}, epsilon float64, msgAndArgs ...interface{}) {
+  if !assert.InEpsilon(t, expected, actual, epsilon, msgAndArgs...) {
+    t.FailNow()
+  }
+}
+
+
+// InEpsilonSlice is the same as InEpsilon, except it compares two slices.
+func InEpsilonSlice(t TestingT, expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) {
+  if !assert.InEpsilonSlice(t, expected, actual, delta, msgAndArgs...) {
+    t.FailNow()
+  }
+}
+
+
+// IsType asserts that the specified objects are of the same type.
+func IsType(t TestingT, expectedType interface{}, object interface{}, msgAndArgs ...interface{}) {
+  if !assert.IsType(t, expectedType, object, msgAndArgs...) {
+    t.FailNow()
+  }
+}
+
+
+// JSONEq asserts that two JSON strings are equivalent.
+// 
+//  assert.JSONEq(t, `{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`)
+// 
+// Returns whether the assertion was successful (true) or not (false).
+func JSONEq(t TestingT, expected string, actual string, msgAndArgs ...interface{}) {
+  if !assert.JSONEq(t, expected, actual, msgAndArgs...) {
+    t.FailNow()
+  }
+}
+
+
+// Len asserts that the specified object has specific length.
+// Len also fails if the object has a type that len() not accept.
+// 
+//    assert.Len(t, mySlice, 3, "The size of slice is not 3")
+// 
+// Returns whether the assertion was successful (true) or not (false).
+func Len(t TestingT, object interface{}, length int, msgAndArgs ...interface{}) {
+  if !assert.Len(t, object, length, msgAndArgs...) {
+    t.FailNow()
+  }
+}
+
+
+// Nil asserts that the specified object is nil.
+// 
+//    assert.Nil(t, err, "err should be nothing")
+// 
+// Returns whether the assertion was successful (true) or not (false).
+func Nil(t TestingT, object interface{}, msgAndArgs ...interface{}) {
+  if !assert.Nil(t, object, msgAndArgs...) {
+    t.FailNow()
+  }
+}
+
+
+// NoError asserts that a function returned no error (i.e. `nil`).
+// 
+//   actualObj, err := SomeFunction()
+//   if assert.NoError(t, err) {
+//        assert.Equal(t, actualObj, expectedObj)
+//   }
+// 
+// Returns whether the assertion was successful (true) or not (false).
+func NoError(t TestingT, err error, msgAndArgs ...interface{}) {
+  if !assert.NoError(t, err, msgAndArgs...) {
+    t.FailNow()
+  }
+}
+
+
+// NotContains asserts that the specified string, list(array, slice...) or map does NOT contain the
+// specified substring or element.
+// 
+//    assert.NotContains(t, "Hello World", "Earth", "But 'Hello World' does NOT contain 'Earth'")
+//    assert.NotContains(t, ["Hello", "World"], "Earth", "But ['Hello', 'World'] does NOT contain 'Earth'")
+//    assert.NotContains(t, {"Hello": "World"}, "Earth", "But {'Hello': 'World'} does NOT contain 'Earth'")
+// 
+// Returns whether the assertion was successful (true) or not (false).
+func NotContains(t TestingT, s interface{}, contains interface{}, msgAndArgs ...interface{}) {
+  if !assert.NotContains(t, s, contains, msgAndArgs...) {
+    t.FailNow()
+  }
+}
+
+
+// NotEmpty asserts that the specified object is NOT empty.  I.e. not nil, "", false, 0 or either
+// a slice or a channel with len == 0.
+// 
+//  if assert.NotEmpty(t, obj) {
+//    assert.Equal(t, "two", obj[1])
+//  }
+// 
+// Returns whether the assertion was successful (true) or not (false).
+func NotEmpty(t TestingT, object interface{}, msgAndArgs ...interface{}) {
+  if !assert.NotEmpty(t, object, msgAndArgs...) {
+    t.FailNow()
+  }
+}
+
+
+// NotEqual asserts that the specified values are NOT equal.
+// 
+//    assert.NotEqual(t, obj1, obj2, "two objects shouldn't be equal")
+// 
+// Returns whether the assertion was successful (true) or not (false).
+func NotEqual(t TestingT, expected interface{}, actual interface{}, msgAndArgs ...interface{}) {
+  if !assert.NotEqual(t, expected, actual, msgAndArgs...) {
+    t.FailNow()
+  }
+}
+
+
+// NotNil asserts that the specified object is not nil.
+// 
+//    assert.NotNil(t, err, "err should be something")
+// 
+// Returns whether the assertion was successful (true) or not (false).
+func NotNil(t TestingT, object interface{}, msgAndArgs ...interface{}) {
+  if !assert.NotNil(t, object, msgAndArgs...) {
+    t.FailNow()
+  }
+}
+
+
+// NotPanics asserts that the code inside the specified PanicTestFunc does NOT panic.
+// 
+//   assert.NotPanics(t, func(){
+//     RemainCalm()
+//   }, "Calling RemainCalm() should NOT panic")
+// 
+// Returns whether the assertion was successful (true) or not (false).
+func NotPanics(t TestingT, f assert.PanicTestFunc, msgAndArgs ...interface{}) {
+  if !assert.NotPanics(t, f, msgAndArgs...) {
+    t.FailNow()
+  }
+}
+
+
+// NotRegexp asserts that a specified regexp does not match a string.
+// 
+//  assert.NotRegexp(t, regexp.MustCompile("starts"), "it's starting")
+//  assert.NotRegexp(t, "^start", "it's not starting")
+// 
+// Returns whether the assertion was successful (true) or not (false).
+func NotRegexp(t TestingT, rx interface{}, str interface{}, msgAndArgs ...interface{}) {
+  if !assert.NotRegexp(t, rx, str, msgAndArgs...) {
+    t.FailNow()
+  }
+}
+
+
+// NotZero asserts that i is not the zero value for its type and returns the truth.
+func NotZero(t TestingT, i interface{}, msgAndArgs ...interface{}) {
+  if !assert.NotZero(t, i, msgAndArgs...) {
+    t.FailNow()
+  }
+}
+
+
+// Panics asserts that the code inside the specified PanicTestFunc panics.
+// 
+//   assert.Panics(t, func(){
+//     GoCrazy()
+//   }, "Calling GoCrazy() should panic")
+// 
+// Returns whether the assertion was successful (true) or not (false).
+func Panics(t TestingT, f assert.PanicTestFunc, msgAndArgs ...interface{}) {
+  if !assert.Panics(t, f, msgAndArgs...) {
+    t.FailNow()
+  }
+}
+
+
+// Regexp asserts that a specified regexp matches a string.
+// 
+//  assert.Regexp(t, regexp.MustCompile("start"), "it's starting")
+//  assert.Regexp(t, "start...$", "it's not starting")
+// 
+// Returns whether the assertion was successful (true) or not (false).
+func Regexp(t TestingT, rx interface{}, str interface{}, msgAndArgs ...interface{}) {
+  if !assert.Regexp(t, rx, str, msgAndArgs...) {
+    t.FailNow()
+  }
+}
+
+
+// True asserts that the specified value is true.
+// 
+//    assert.True(t, myBool, "myBool should be true")
+// 
+// Returns whether the assertion was successful (true) or not (false).
+func True(t TestingT, value bool, msgAndArgs ...interface{}) {
+  if !assert.True(t, value, msgAndArgs...) {
+    t.FailNow()
+  }
+}
+
+
+// WithinDuration asserts that the two times are within duration delta of each other.
+// 
+//   assert.WithinDuration(t, time.Now(), time.Now(), 10*time.Second, "The difference should not be more than 10s")
+// 
+// Returns whether the assertion was successful (true) or not (false).
+func WithinDuration(t TestingT, expected time.Time, actual time.Time, delta time.Duration, msgAndArgs ...interface{}) {
+  if !assert.WithinDuration(t, expected, actual, delta, msgAndArgs...) {
+    t.FailNow()
+  }
+}
+
+
+// Zero asserts that i is the zero value for its type and returns the truth.
+func Zero(t TestingT, i interface{}, msgAndArgs ...interface{}) {
+  if !assert.Zero(t, i, msgAndArgs...) {
+    t.FailNow()
+  }
+}
diff --git a/vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/require/require.go.tmpl b/vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/require/require.go.tmpl
new file mode 100644 (file)
index 0000000..ab1b1e9
--- /dev/null
@@ -0,0 +1,6 @@
+{{.Comment}}
+func {{.DocInfo.Name}}(t TestingT, {{.Params}}) {
+  if !assert.{{.DocInfo.Name}}(t, {{.ForwardedParams}}) {
+    t.FailNow()
+  }
+}
diff --git a/vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/require/require_forward.go b/vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/require/require_forward.go
new file mode 100644 (file)
index 0000000..58324f1
--- /dev/null
@@ -0,0 +1,388 @@
+/*
+* CODE GENERATED AUTOMATICALLY WITH github.com/stretchr/testify/_codegen
+* THIS FILE MUST NOT BE EDITED BY HAND
+*/
+
+package require
+
+import (
+
+       assert "github.com/stretchr/testify/assert"
+       http "net/http"
+       url "net/url"
+       time "time"
+)
+
+
+// Condition uses a Comparison to assert a complex condition.
+func (a *Assertions) Condition(comp assert.Comparison, msgAndArgs ...interface{}) {
+       Condition(a.t, comp, msgAndArgs...)
+}
+
+
+// Contains asserts that the specified string, list(array, slice...) or map contains the
+// specified substring or element.
+// 
+//    a.Contains("Hello World", "World", "But 'Hello World' does contain 'World'")
+//    a.Contains(["Hello", "World"], "World", "But ["Hello", "World"] does contain 'World'")
+//    a.Contains({"Hello": "World"}, "Hello", "But {'Hello': 'World'} does contain 'Hello'")
+// 
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) Contains(s interface{}, contains interface{}, msgAndArgs ...interface{}) {
+       Contains(a.t, s, contains, msgAndArgs...)
+}
+
+
+// Empty asserts that the specified object is empty.  I.e. nil, "", false, 0 or either
+// a slice or a channel with len == 0.
+// 
+//  a.Empty(obj)
+// 
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) Empty(object interface{}, msgAndArgs ...interface{}) {
+       Empty(a.t, object, msgAndArgs...)
+}
+
+
+// Equal asserts that two objects are equal.
+// 
+//    a.Equal(123, 123, "123 and 123 should be equal")
+// 
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) Equal(expected interface{}, actual interface{}, msgAndArgs ...interface{}) {
+       Equal(a.t, expected, actual, msgAndArgs...)
+}
+
+
+// EqualError asserts that a function returned an error (i.e. not `nil`)
+// and that it is equal to the provided error.
+// 
+//   actualObj, err := SomeFunction()
+//   if assert.Error(t, err, "An error was expected") {
+//        assert.Equal(t, err, expectedError)
+//   }
+// 
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) EqualError(theError error, errString string, msgAndArgs ...interface{}) {
+       EqualError(a.t, theError, errString, msgAndArgs...)
+}
+
+
+// EqualValues asserts that two objects are equal or convertable to the same types
+// and equal.
+// 
+//    a.EqualValues(uint32(123), int32(123), "123 and 123 should be equal")
+// 
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) EqualValues(expected interface{}, actual interface{}, msgAndArgs ...interface{}) {
+       EqualValues(a.t, expected, actual, msgAndArgs...)
+}
+
+
+// Error asserts that a function returned an error (i.e. not `nil`).
+// 
+//   actualObj, err := SomeFunction()
+//   if a.Error(err, "An error was expected") {
+//        assert.Equal(t, err, expectedError)
+//   }
+// 
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) Error(err error, msgAndArgs ...interface{}) {
+       Error(a.t, err, msgAndArgs...)
+}
+
+
+// Exactly asserts that two objects are equal is value and type.
+// 
+//    a.Exactly(int32(123), int64(123), "123 and 123 should NOT be equal")
+// 
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) Exactly(expected interface{}, actual interface{}, msgAndArgs ...interface{}) {
+       Exactly(a.t, expected, actual, msgAndArgs...)
+}
+
+
+// Fail reports a failure through
+func (a *Assertions) Fail(failureMessage string, msgAndArgs ...interface{}) {
+       Fail(a.t, failureMessage, msgAndArgs...)
+}
+
+
+// FailNow fails test
+func (a *Assertions) FailNow(failureMessage string, msgAndArgs ...interface{}) {
+       FailNow(a.t, failureMessage, msgAndArgs...)
+}
+
+
+// False asserts that the specified value is false.
+// 
+//    a.False(myBool, "myBool should be false")
+// 
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) False(value bool, msgAndArgs ...interface{}) {
+       False(a.t, value, msgAndArgs...)
+}
+
+
+// HTTPBodyContains asserts that a specified handler returns a
+// body that contains a string.
+// 
+//  a.HTTPBodyContains(myHandler, "www.google.com", nil, "I'm Feeling Lucky")
+// 
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) HTTPBodyContains(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}) {
+       HTTPBodyContains(a.t, handler, method, url, values, str)
+}
+
+
+// HTTPBodyNotContains asserts that a specified handler returns a
+// body that does not contain a string.
+// 
+//  a.HTTPBodyNotContains(myHandler, "www.google.com", nil, "I'm Feeling Lucky")
+// 
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) HTTPBodyNotContains(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}) {
+       HTTPBodyNotContains(a.t, handler, method, url, values, str)
+}
+
+
+// HTTPError asserts that a specified handler returns an error status code.
+// 
+//  a.HTTPError(myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}}
+// 
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) HTTPError(handler http.HandlerFunc, method string, url string, values url.Values) {
+       HTTPError(a.t, handler, method, url, values)
+}
+
+
+// HTTPRedirect asserts that a specified handler returns a redirect status code.
+// 
+//  a.HTTPRedirect(myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}}
+// 
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) HTTPRedirect(handler http.HandlerFunc, method string, url string, values url.Values) {
+       HTTPRedirect(a.t, handler, method, url, values)
+}
+
+
+// HTTPSuccess asserts that a specified handler returns a success status code.
+// 
+//  a.HTTPSuccess(myHandler, "POST", "http://www.google.com", nil)
+// 
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) HTTPSuccess(handler http.HandlerFunc, method string, url string, values url.Values) {
+       HTTPSuccess(a.t, handler, method, url, values)
+}
+
+
+// Implements asserts that an object is implemented by the specified interface.
+// 
+//    a.Implements((*MyInterface)(nil), new(MyObject), "MyObject")
+func (a *Assertions) Implements(interfaceObject interface{}, object interface{}, msgAndArgs ...interface{}) {
+       Implements(a.t, interfaceObject, object, msgAndArgs...)
+}
+
+
+// InDelta asserts that the two numerals are within delta of each other.
+// 
+//      a.InDelta(math.Pi, (22 / 7.0), 0.01)
+// 
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) InDelta(expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) {
+       InDelta(a.t, expected, actual, delta, msgAndArgs...)
+}
+
+
+// InDeltaSlice is the same as InDelta, except it compares two slices.
+func (a *Assertions) InDeltaSlice(expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) {
+       InDeltaSlice(a.t, expected, actual, delta, msgAndArgs...)
+}
+
+
+// InEpsilon asserts that expected and actual have a relative error less than epsilon
+// 
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) InEpsilon(expected interface{}, actual interface{}, epsilon float64, msgAndArgs ...interface{}) {
+       InEpsilon(a.t, expected, actual, epsilon, msgAndArgs...)
+}
+
+
+// InEpsilonSlice is the same as InEpsilon, except it compares two slices.
+func (a *Assertions) InEpsilonSlice(expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) {
+       InEpsilonSlice(a.t, expected, actual, delta, msgAndArgs...)
+}
+
+
+// IsType asserts that the specified objects are of the same type.
+func (a *Assertions) IsType(expectedType interface{}, object interface{}, msgAndArgs ...interface{}) {
+       IsType(a.t, expectedType, object, msgAndArgs...)
+}
+
+
+// JSONEq asserts that two JSON strings are equivalent.
+// 
+//  a.JSONEq(`{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`)
+// 
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) JSONEq(expected string, actual string, msgAndArgs ...interface{}) {
+       JSONEq(a.t, expected, actual, msgAndArgs...)
+}
+
+
+// Len asserts that the specified object has specific length.
+// Len also fails if the object has a type that len() not accept.
+// 
+//    a.Len(mySlice, 3, "The size of slice is not 3")
+// 
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) Len(object interface{}, length int, msgAndArgs ...interface{}) {
+       Len(a.t, object, length, msgAndArgs...)
+}
+
+
+// Nil asserts that the specified object is nil.
+// 
+//    a.Nil(err, "err should be nothing")
+// 
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) Nil(object interface{}, msgAndArgs ...interface{}) {
+       Nil(a.t, object, msgAndArgs...)
+}
+
+
+// NoError asserts that a function returned no error (i.e. `nil`).
+// 
+//   actualObj, err := SomeFunction()
+//   if a.NoError(err) {
+//        assert.Equal(t, actualObj, expectedObj)
+//   }
+// 
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) NoError(err error, msgAndArgs ...interface{}) {
+       NoError(a.t, err, msgAndArgs...)
+}
+
+
+// NotContains asserts that the specified string, list(array, slice...) or map does NOT contain the
+// specified substring or element.
+// 
+//    a.NotContains("Hello World", "Earth", "But 'Hello World' does NOT contain 'Earth'")
+//    a.NotContains(["Hello", "World"], "Earth", "But ['Hello', 'World'] does NOT contain 'Earth'")
+//    a.NotContains({"Hello": "World"}, "Earth", "But {'Hello': 'World'} does NOT contain 'Earth'")
+// 
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) NotContains(s interface{}, contains interface{}, msgAndArgs ...interface{}) {
+       NotContains(a.t, s, contains, msgAndArgs...)
+}
+
+
+// NotEmpty asserts that the specified object is NOT empty.  I.e. not nil, "", false, 0 or either
+// a slice or a channel with len == 0.
+// 
+//  if a.NotEmpty(obj) {
+//    assert.Equal(t, "two", obj[1])
+//  }
+// 
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) NotEmpty(object interface{}, msgAndArgs ...interface{}) {
+       NotEmpty(a.t, object, msgAndArgs...)
+}
+
+
+// NotEqual asserts that the specified values are NOT equal.
+// 
+//    a.NotEqual(obj1, obj2, "two objects shouldn't be equal")
+// 
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) NotEqual(expected interface{}, actual interface{}, msgAndArgs ...interface{}) {
+       NotEqual(a.t, expected, actual, msgAndArgs...)
+}
+
+
+// NotNil asserts that the specified object is not nil.
+// 
+//    a.NotNil(err, "err should be something")
+// 
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) NotNil(object interface{}, msgAndArgs ...interface{}) {
+       NotNil(a.t, object, msgAndArgs...)
+}
+
+
+// NotPanics asserts that the code inside the specified PanicTestFunc does NOT panic.
+// 
+//   a.NotPanics(func(){
+//     RemainCalm()
+//   }, "Calling RemainCalm() should NOT panic")
+// 
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) NotPanics(f assert.PanicTestFunc, msgAndArgs ...interface{}) {
+       NotPanics(a.t, f, msgAndArgs...)
+}
+
+
+// NotRegexp asserts that a specified regexp does not match a string.
+// 
+//  a.NotRegexp(regexp.MustCompile("starts"), "it's starting")
+//  a.NotRegexp("^start", "it's not starting")
+// 
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) NotRegexp(rx interface{}, str interface{}, msgAndArgs ...interface{}) {
+       NotRegexp(a.t, rx, str, msgAndArgs...)
+}
+
+
+// NotZero asserts that i is not the zero value for its type and returns the truth.
+func (a *Assertions) NotZero(i interface{}, msgAndArgs ...interface{}) {
+       NotZero(a.t, i, msgAndArgs...)
+}
+
+
+// Panics asserts that the code inside the specified PanicTestFunc panics.
+// 
+//   a.Panics(func(){
+//     GoCrazy()
+//   }, "Calling GoCrazy() should panic")
+// 
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) Panics(f assert.PanicTestFunc, msgAndArgs ...interface{}) {
+       Panics(a.t, f, msgAndArgs...)
+}
+
+
+// Regexp asserts that a specified regexp matches a string.
+// 
+//  a.Regexp(regexp.MustCompile("start"), "it's starting")
+//  a.Regexp("start...$", "it's not starting")
+// 
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) Regexp(rx interface{}, str interface{}, msgAndArgs ...interface{}) {
+       Regexp(a.t, rx, str, msgAndArgs...)
+}
+
+
+// True asserts that the specified value is true.
+// 
+//    a.True(myBool, "myBool should be true")
+// 
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) True(value bool, msgAndArgs ...interface{}) {
+       True(a.t, value, msgAndArgs...)
+}
+
+
+// WithinDuration asserts that the two times are within duration delta of each other.
+// 
+//   a.WithinDuration(time.Now(), time.Now(), 10*time.Second, "The difference should not be more than 10s")
+// 
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) WithinDuration(expected time.Time, actual time.Time, delta time.Duration, msgAndArgs ...interface{}) {
+       WithinDuration(a.t, expected, actual, delta, msgAndArgs...)
+}
+
+
+// Zero asserts that i is the zero value for its type and returns the truth.
+func (a *Assertions) Zero(i interface{}, msgAndArgs ...interface{}) {
+       Zero(a.t, i, msgAndArgs...)
+}
diff --git a/vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/require/require_forward.go.tmpl b/vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/require/require_forward.go.tmpl
new file mode 100644 (file)
index 0000000..b93569e
--- /dev/null
@@ -0,0 +1,4 @@
+{{.CommentWithoutT "a"}}
+func (a *Assertions) {{.DocInfo.Name}}({{.Params}}) {
+       {{.DocInfo.Name}}(a.t, {{.ForwardedParams}})
+}
diff --git a/vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/require/requirements.go b/vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/require/requirements.go
new file mode 100644 (file)
index 0000000..4114756
--- /dev/null
@@ -0,0 +1,9 @@
+package require
+
+// TestingT is an interface wrapper around *testing.T
+type TestingT interface {
+       Errorf(format string, args ...interface{})
+       FailNow()
+}
+
+//go:generate go run ../_codegen/main.go -output-package=require -template=require.go.tmpl
diff --git a/vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/require/requirements_test.go b/vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/require/requirements_test.go
new file mode 100644 (file)
index 0000000..d2ccc99
--- /dev/null
@@ -0,0 +1,369 @@
+package require
+
+import (
+       "errors"
+       "testing"
+       "time"
+)
+
+// AssertionTesterInterface defines an interface to be used for testing assertion methods
+type AssertionTesterInterface interface {
+       TestMethod()
+}
+
+// AssertionTesterConformingObject is an object that conforms to the AssertionTesterInterface interface
+type AssertionTesterConformingObject struct {
+}
+
+func (a *AssertionTesterConformingObject) TestMethod() {
+}
+
+// AssertionTesterNonConformingObject is an object that does not conform to the AssertionTesterInterface interface
+type AssertionTesterNonConformingObject struct {
+}
+
+type MockT struct {
+       Failed bool
+}
+
+func (t *MockT) FailNow() {
+       t.Failed = true
+}
+
+func (t *MockT) Errorf(format string, args ...interface{}) {
+       _, _ = format, args
+}
+
+func TestImplements(t *testing.T) {
+
+       Implements(t, (*AssertionTesterInterface)(nil), new(AssertionTesterConformingObject))
+
+       mockT := new(MockT)
+       Implements(mockT, (*AssertionTesterInterface)(nil), new(AssertionTesterNonConformingObject))
+       if !mockT.Failed {
+               t.Error("Check should fail")
+       }
+}
+
+func TestIsType(t *testing.T) {
+
+       IsType(t, new(AssertionTesterConformingObject), new(AssertionTesterConformingObject))
+
+       mockT := new(MockT)
+       IsType(mockT, new(AssertionTesterConformingObject), new(AssertionTesterNonConformingObject))
+       if !mockT.Failed {
+               t.Error("Check should fail")
+       }
+}
+
+func TestEqual(t *testing.T) {
+
+       Equal(t, 1, 1)
+
+       mockT := new(MockT)
+       Equal(mockT, 1, 2)
+       if !mockT.Failed {
+               t.Error("Check should fail")
+       }
+
+}
+
+func TestNotEqual(t *testing.T) {
+
+       NotEqual(t, 1, 2)
+       mockT := new(MockT)
+       NotEqual(mockT, 2, 2)
+       if !mockT.Failed {
+               t.Error("Check should fail")
+       }
+}
+
+func TestExactly(t *testing.T) {
+
+       a := float32(1)
+       b := float32(1)
+       c := float64(1)
+
+       Exactly(t, a, b)
+
+       mockT := new(MockT)
+       Exactly(mockT, a, c)
+       if !mockT.Failed {
+               t.Error("Check should fail")
+       }
+}
+
+func TestNotNil(t *testing.T) {
+
+       NotNil(t, new(AssertionTesterConformingObject))
+
+       mockT := new(MockT)
+       NotNil(mockT, nil)
+       if !mockT.Failed {
+               t.Error("Check should fail")
+       }
+}
+
+func TestNil(t *testing.T) {
+
+       Nil(t, nil)
+
+       mockT := new(MockT)
+       Nil(mockT, new(AssertionTesterConformingObject))
+       if !mockT.Failed {
+               t.Error("Check should fail")
+       }
+}
+
+func TestTrue(t *testing.T) {
+
+       True(t, true)
+
+       mockT := new(MockT)
+       True(mockT, false)
+       if !mockT.Failed {
+               t.Error("Check should fail")
+       }
+}
+
+func TestFalse(t *testing.T) {
+
+       False(t, false)
+
+       mockT := new(MockT)
+       False(mockT, true)
+       if !mockT.Failed {
+               t.Error("Check should fail")
+       }
+}
+
+func TestContains(t *testing.T) {
+
+       Contains(t, "Hello World", "Hello")
+
+       mockT := new(MockT)
+       Contains(mockT, "Hello World", "Salut")
+       if !mockT.Failed {
+               t.Error("Check should fail")
+       }
+}
+
+func TestNotContains(t *testing.T) {
+
+       NotContains(t, "Hello World", "Hello!")
+
+       mockT := new(MockT)
+       NotContains(mockT, "Hello World", "Hello")
+       if !mockT.Failed {
+               t.Error("Check should fail")
+       }
+}
+
+func TestPanics(t *testing.T) {
+
+       Panics(t, func() {
+               panic("Panic!")
+       })
+
+       mockT := new(MockT)
+       Panics(mockT, func() {})
+       if !mockT.Failed {
+               t.Error("Check should fail")
+       }
+}
+
+func TestNotPanics(t *testing.T) {
+
+       NotPanics(t, func() {})
+
+       mockT := new(MockT)
+       NotPanics(mockT, func() {
+               panic("Panic!")
+       })
+       if !mockT.Failed {
+               t.Error("Check should fail")
+       }
+}
+
+func TestNoError(t *testing.T) {
+
+       NoError(t, nil)
+
+       mockT := new(MockT)
+       NoError(mockT, errors.New("some error"))
+       if !mockT.Failed {
+               t.Error("Check should fail")
+       }
+}
+
+func TestError(t *testing.T) {
+
+       Error(t, errors.New("some error"))
+
+       mockT := new(MockT)
+       Error(mockT, nil)
+       if !mockT.Failed {
+               t.Error("Check should fail")
+       }
+}
+
+func TestEqualError(t *testing.T) {
+
+       EqualError(t, errors.New("some error"), "some error")
+
+       mockT := new(MockT)
+       EqualError(mockT, errors.New("some error"), "Not some error")
+       if !mockT.Failed {
+               t.Error("Check should fail")
+       }
+}
+
+func TestEmpty(t *testing.T) {
+
+       Empty(t, "")
+
+       mockT := new(MockT)
+       Empty(mockT, "x")
+       if !mockT.Failed {
+               t.Error("Check should fail")
+       }
+}
+
+func TestNotEmpty(t *testing.T) {
+
+       NotEmpty(t, "x")
+
+       mockT := new(MockT)
+       NotEmpty(mockT, "")
+       if !mockT.Failed {
+               t.Error("Check should fail")
+       }
+}
+
+func TestWithinDuration(t *testing.T) {
+
+       a := time.Now()
+       b := a.Add(10 * time.Second)
+
+       WithinDuration(t, a, b, 15*time.Second)
+
+       mockT := new(MockT)
+       WithinDuration(mockT, a, b, 5*time.Second)
+       if !mockT.Failed {
+               t.Error("Check should fail")
+       }
+}
+
+func TestInDelta(t *testing.T) {
+
+       InDelta(t, 1.001, 1, 0.01)
+
+       mockT := new(MockT)
+       InDelta(mockT, 1, 2, 0.5)
+       if !mockT.Failed {
+               t.Error("Check should fail")
+       }
+}
+
+func TestZero(t *testing.T) {
+
+       Zero(t, "")
+
+       mockT := new(MockT)
+       Zero(mockT, "x")
+       if !mockT.Failed {
+               t.Error("Check should fail")
+       }
+}
+
+func TestNotZero(t *testing.T) {
+
+       NotZero(t, "x")
+
+       mockT := new(MockT)
+       NotZero(mockT, "")
+       if !mockT.Failed {
+               t.Error("Check should fail")
+       }
+}
+
+func TestJSONEq_EqualSONString(t *testing.T) {
+       mockT := new(MockT)
+       JSONEq(mockT, `{"hello": "world", "foo": "bar"}`, `{"hello": "world", "foo": "bar"}`)
+       if mockT.Failed {
+               t.Error("Check should pass")
+       }
+}
+
+func TestJSONEq_EquivalentButNotEqual(t *testing.T) {
+       mockT := new(MockT)
+       JSONEq(mockT, `{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`)
+       if mockT.Failed {
+               t.Error("Check should pass")
+       }
+}
+
+func TestJSONEq_HashOfArraysAndHashes(t *testing.T) {
+       mockT := new(MockT)
+       JSONEq(mockT, "{\r\n\t\"numeric\": 1.5,\r\n\t\"array\": [{\"foo\": \"bar\"}, 1, \"string\", [\"nested\", \"array\", 5.5]],\r\n\t\"hash\": {\"nested\": \"hash\", \"nested_slice\": [\"this\", \"is\", \"nested\"]},\r\n\t\"string\": \"foo\"\r\n}",
+               "{\r\n\t\"numeric\": 1.5,\r\n\t\"hash\": {\"nested\": \"hash\", \"nested_slice\": [\"this\", \"is\", \"nested\"]},\r\n\t\"string\": \"foo\",\r\n\t\"array\": [{\"foo\": \"bar\"}, 1, \"string\", [\"nested\", \"array\", 5.5]]\r\n}")
+       if mockT.Failed {
+               t.Error("Check should pass")
+       }
+}
+
+func TestJSONEq_Array(t *testing.T) {
+       mockT := new(MockT)
+       JSONEq(mockT, `["foo", {"hello": "world", "nested": "hash"}]`, `["foo", {"nested": "hash", "hello": "world"}]`)
+       if mockT.Failed {
+               t.Error("Check should pass")
+       }
+}
+
+func TestJSONEq_HashAndArrayNotEquivalent(t *testing.T) {
+       mockT := new(MockT)
+       JSONEq(mockT, `["foo", {"hello": "world", "nested": "hash"}]`, `{"foo": "bar", {"nested": "hash", "hello": "world"}}`)
+       if !mockT.Failed {
+               t.Error("Check should fail")
+       }
+}
+
+func TestJSONEq_HashesNotEquivalent(t *testing.T) {
+       mockT := new(MockT)
+       JSONEq(mockT, `{"foo": "bar"}`, `{"foo": "bar", "hello": "world"}`)
+       if !mockT.Failed {
+               t.Error("Check should fail")
+       }
+}
+
+func TestJSONEq_ActualIsNotJSON(t *testing.T) {
+       mockT := new(MockT)
+       JSONEq(mockT, `{"foo": "bar"}`, "Not JSON")
+       if !mockT.Failed {
+               t.Error("Check should fail")
+       }
+}
+
+func TestJSONEq_ExpectedIsNotJSON(t *testing.T) {
+       mockT := new(MockT)
+       JSONEq(mockT, "Not JSON", `{"foo": "bar", "hello": "world"}`)
+       if !mockT.Failed {
+               t.Error("Check should fail")
+       }
+}
+
+func TestJSONEq_ExpectedAndActualNotJSON(t *testing.T) {
+       mockT := new(MockT)
+       JSONEq(mockT, "Not JSON", "Not JSON")
+       if !mockT.Failed {
+               t.Error("Check should fail")
+       }
+}
+
+func TestJSONEq_ArraysOfDifferentOrder(t *testing.T) {
+       mockT := new(MockT)
+       JSONEq(mockT, `["foo", {"hello": "world", "nested": "hash"}]`, `[{ "hello": "world", "nested": "hash"}, "foo"]`)
+       if !mockT.Failed {
+               t.Error("Check should fail")
+       }
+}
diff --git a/vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/suite/doc.go b/vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/suite/doc.go
new file mode 100644 (file)
index 0000000..f91a245
--- /dev/null
@@ -0,0 +1,65 @@
+// Package suite contains logic for creating testing suite structs
+// and running the methods on those structs as tests.  The most useful
+// piece of this package is that you can create setup/teardown methods
+// on your testing suites, which will run before/after the whole suite
+// or individual tests (depending on which interface(s) you
+// implement).
+//
+// A testing suite is usually built by first extending the built-in
+// suite functionality from suite.Suite in testify.  Alternatively,
+// you could reproduce that logic on your own if you wanted (you
+// just need to implement the TestingSuite interface from
+// suite/interfaces.go).
+//
+// After that, you can implement any of the interfaces in
+// suite/interfaces.go to add setup/teardown functionality to your
+// suite, and add any methods that start with "Test" to add tests.
+// Methods that do not match any suite interfaces and do not begin
+// with "Test" will not be run by testify, and can safely be used as
+// helper methods.
+//
+// Once you've built your testing suite, you need to run the suite
+// (using suite.Run from testify) inside any function that matches the
+// identity that "go test" is already looking for (i.e.
+// func(*testing.T)).
+//
+// Regular expression to select test suites specified command-line
+// argument "-run". Regular expression to select the methods
+// of test suites specified command-line argument "-m".
+// Suite object has assertion methods.
+//
+// A crude example:
+//     // Basic imports
+//     import (
+//         "testing"
+//         "github.com/stretchr/testify/assert"
+//         "github.com/stretchr/testify/suite"
+//     )
+//
+//     // Define the suite, and absorb the built-in basic suite
+//     // functionality from testify - including a T() method which
+//     // returns the current testing context
+//     type ExampleTestSuite struct {
+//         suite.Suite
+//         VariableThatShouldStartAtFive int
+//     }
+//
+//     // Make sure that VariableThatShouldStartAtFive is set to five
+//     // before each test
+//     func (suite *ExampleTestSuite) SetupTest() {
+//         suite.VariableThatShouldStartAtFive = 5
+//     }
+//
+//     // All methods that begin with "Test" are run as tests within a
+//     // suite.
+//     func (suite *ExampleTestSuite) TestExample() {
+//         assert.Equal(suite.T(), 5, suite.VariableThatShouldStartAtFive)
+//         suite.Equal(5, suite.VariableThatShouldStartAtFive)
+//     }
+//
+//     // In order for 'go test' to run this suite, we need to create
+//     // a normal test function and pass our suite to suite.Run
+//     func TestExampleTestSuite(t *testing.T) {
+//         suite.Run(t, new(ExampleTestSuite))
+//     }
+package suite
diff --git a/vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/suite/interfaces.go b/vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/suite/interfaces.go
new file mode 100644 (file)
index 0000000..2096947
--- /dev/null
@@ -0,0 +1,34 @@
+package suite
+
+import "testing"
+
+// TestingSuite can store and return the current *testing.T context
+// generated by 'go test'.
+type TestingSuite interface {
+       T() *testing.T
+       SetT(*testing.T)
+}
+
+// SetupAllSuite has a SetupSuite method, which will run before the
+// tests in the suite are run.
+type SetupAllSuite interface {
+       SetupSuite()
+}
+
+// SetupTestSuite has a SetupTest method, which will run before each
+// test in the suite.
+type SetupTestSuite interface {
+       SetupTest()
+}
+
+// TearDownAllSuite has a TearDownSuite method, which will run after
+// all the tests in the suite have been run.
+type TearDownAllSuite interface {
+       TearDownSuite()
+}
+
+// TearDownTestSuite has a TearDownTest method, which will run after
+// each test in the suite.
+type TearDownTestSuite interface {
+       TearDownTest()
+}
diff --git a/vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/suite/suite.go b/vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/suite/suite.go
new file mode 100644 (file)
index 0000000..f831e25
--- /dev/null
@@ -0,0 +1,115 @@
+package suite
+
+import (
+       "flag"
+       "fmt"
+       "os"
+       "reflect"
+       "regexp"
+       "testing"
+
+       "github.com/stretchr/testify/assert"
+       "github.com/stretchr/testify/require"
+)
+
+var matchMethod = flag.String("m", "", "regular expression to select tests of the suite to run")
+
+// Suite is a basic testing suite with methods for storing and
+// retrieving the current *testing.T context.
+type Suite struct {
+       *assert.Assertions
+       require *require.Assertions
+       t       *testing.T
+}
+
+// T retrieves the current *testing.T context.
+func (suite *Suite) T() *testing.T {
+       return suite.t
+}
+
+// SetT sets the current *testing.T context.
+func (suite *Suite) SetT(t *testing.T) {
+       suite.t = t
+       suite.Assertions = assert.New(t)
+       suite.require = require.New(t)
+}
+
+// Require returns a require context for suite.
+func (suite *Suite) Require() *require.Assertions {
+       if suite.require == nil {
+               suite.require = require.New(suite.T())
+       }
+       return suite.require
+}
+
+// Assert returns an assert context for suite.  Normally, you can call
+// `suite.NoError(expected, actual)`, but for situations where the embedded
+// methods are overridden (for example, you might want to override
+// assert.Assertions with require.Assertions), this method is provided so you
+// can call `suite.Assert().NoError()`.
+func (suite *Suite) Assert() *assert.Assertions {
+       if suite.Assertions == nil {
+               suite.Assertions = assert.New(suite.T())
+       }
+       return suite.Assertions
+}
+
+// Run takes a testing suite and runs all of the tests attached
+// to it.
+func Run(t *testing.T, suite TestingSuite) {
+       suite.SetT(t)
+
+       if setupAllSuite, ok := suite.(SetupAllSuite); ok {
+               setupAllSuite.SetupSuite()
+       }
+       defer func() {
+               if tearDownAllSuite, ok := suite.(TearDownAllSuite); ok {
+                       tearDownAllSuite.TearDownSuite()
+               }
+       }()
+
+       methodFinder := reflect.TypeOf(suite)
+       tests := []testing.InternalTest{}
+       for index := 0; index < methodFinder.NumMethod(); index++ {
+               method := methodFinder.Method(index)
+               ok, err := methodFilter(method.Name)
+               if err != nil {
+                       fmt.Fprintf(os.Stderr, "testify: invalid regexp for -m: %s\n", err)
+                       os.Exit(1)
+               }
+               if ok {
+                       test := testing.InternalTest{
+                               Name: method.Name,
+                               F: func(t *testing.T) {
+                                       parentT := suite.T()
+                                       suite.SetT(t)
+                                       if setupTestSuite, ok := suite.(SetupTestSuite); ok {
+                                               setupTestSuite.SetupTest()
+                                       }
+                                       defer func() {
+                                               if tearDownTestSuite, ok := suite.(TearDownTestSuite); ok {
+                                                       tearDownTestSuite.TearDownTest()
+                                               }
+                                               suite.SetT(parentT)
+                                       }()
+                                       method.Func.Call([]reflect.Value{reflect.ValueOf(suite)})
+                               },
+                       }
+                       tests = append(tests, test)
+               }
+       }
+
+       if !testing.RunTests(func(_, _ string) (bool, error) { return true, nil },
+               tests) {
+               t.Fail()
+       }
+}
+
+// Filtering method according to set regular expression
+// specified command-line argument -m
+func methodFilter(name string) (bool, error) {
+       if ok, _ := regexp.MatchString("^Test", name); !ok {
+               return false, nil
+       }
+       return regexp.MatchString(*matchMethod, name)
+}
diff --git a/vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/suite/suite_test.go b/vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/suite/suite_test.go
new file mode 100644 (file)
index 0000000..c7c4e88
--- /dev/null
@@ -0,0 +1,239 @@
+package suite
+
+import (
+       "errors"
+       "io/ioutil"
+       "os"
+       "testing"
+
+       "github.com/stretchr/testify/assert"
+)
+
+// SuiteRequireTwice is intended to test the usage of suite.Require in two
+// different tests
+type SuiteRequireTwice struct{ Suite }
+
+// TestSuiteRequireTwice checks for regressions of issue #149 where
+// suite.requirements was not initialised in suite.SetT()
+// A regression would result on these tests panicking rather than failing.
+func TestSuiteRequireTwice(t *testing.T) {
+       ok := testing.RunTests(
+               func(_, _ string) (bool, error) { return true, nil },
+               []testing.InternalTest{{
+                       Name: "TestSuiteRequireTwice",
+                       F: func(t *testing.T) {
+                               suite := new(SuiteRequireTwice)
+                               Run(t, suite)
+                       },
+               }},
+       )
+       assert.Equal(t, false, ok)
+}
+
+func (s *SuiteRequireTwice) TestRequireOne() {
+       r := s.Require()
+       r.Equal(1, 2)
+}
+
+func (s *SuiteRequireTwice) TestRequireTwo() {
+       r := s.Require()
+       r.Equal(1, 2)
+}
+
+// This suite is intended to store values to make sure that only
+// testing-suite-related methods are run.  It's also a fully
+// functional example of a testing suite, using setup/teardown methods
+// and a helper method that is ignored by testify.  To make this look
+// more like a real world example, all tests in the suite perform some
+// type of assertion.
+type SuiteTester struct {
+       // Include our basic suite logic.
+       Suite
+
+       // Keep counts of how many times each method is run.
+       SetupSuiteRunCount    int
+       TearDownSuiteRunCount int
+       SetupTestRunCount     int
+       TearDownTestRunCount  int
+       TestOneRunCount       int
+       TestTwoRunCount       int
+       NonTestMethodRunCount int
+}
+
+type SuiteSkipTester struct {
+       // Include our basic suite logic.
+       Suite
+
+       // Keep counts of how many times each method is run.
+       SetupSuiteRunCount    int
+       TearDownSuiteRunCount int
+}
+
+// The SetupSuite method will be run by testify once, at the very
+// start of the testing suite, before any tests are run.
+func (suite *SuiteTester) SetupSuite() {
+       suite.SetupSuiteRunCount++
+}
+
+func (suite *SuiteSkipTester) SetupSuite() {
+       suite.SetupSuiteRunCount++
+       suite.T().Skip()
+}
+
+// The TearDownSuite method will be run by testify once, at the very
+// end of the testing suite, after all tests have been run.
+func (suite *SuiteTester) TearDownSuite() {
+       suite.TearDownSuiteRunCount++
+}
+
+func (suite *SuiteSkipTester) TearDownSuite() {
+       suite.TearDownSuiteRunCount++
+}
+
+// The SetupTest method will be run before every test in the suite.
+func (suite *SuiteTester) SetupTest() {
+       suite.SetupTestRunCount++
+}
+
+// The TearDownTest method will be run after every test in the suite.
+func (suite *SuiteTester) TearDownTest() {
+       suite.TearDownTestRunCount++
+}
+
+// Every method in a testing suite that begins with "Test" will be run
+// as a test.  TestOne is an example of a test.  For the purposes of
+// this example, we've included assertions in the tests, since most
+// tests will issue assertions.
+func (suite *SuiteTester) TestOne() {
+       beforeCount := suite.TestOneRunCount
+       suite.TestOneRunCount++
+       assert.Equal(suite.T(), suite.TestOneRunCount, beforeCount+1)
+       suite.Equal(suite.TestOneRunCount, beforeCount+1)
+}
+
+// TestTwo is another example of a test.
+func (suite *SuiteTester) TestTwo() {
+       beforeCount := suite.TestTwoRunCount
+       suite.TestTwoRunCount++
+       assert.NotEqual(suite.T(), suite.TestTwoRunCount, beforeCount)
+       suite.NotEqual(suite.TestTwoRunCount, beforeCount)
+}
+
+func (suite *SuiteTester) TestSkip() {
+       suite.T().Skip()
+}
+
+// NonTestMethod does not begin with "Test", so it will not be run by
+// testify as a test in the suite.  This is useful for creating helper
+// methods for your tests.
+func (suite *SuiteTester) NonTestMethod() {
+       suite.NonTestMethodRunCount++
+}
+
+// TestRunSuite will be run by the 'go test' command, so within it, we
+// can run our suite using the Run(*testing.T, TestingSuite) function.
+func TestRunSuite(t *testing.T) {
+       suiteTester := new(SuiteTester)
+       Run(t, suiteTester)
+
+       // Normally, the test would end here.  The following are simply
+       // some assertions to ensure that the Run function is working as
+       // intended - they are not part of the example.
+
+       // The suite was only run once, so the SetupSuite and TearDownSuite
+       // methods should have each been run only once.
+       assert.Equal(t, suiteTester.SetupSuiteRunCount, 1)
+       assert.Equal(t, suiteTester.TearDownSuiteRunCount, 1)
+
+       // There are three test methods (TestOne, TestTwo, and TestSkip), so
+       // the SetupTest and TearDownTest methods (which should be run once for
+       // each test) should have been run three times.
+       assert.Equal(t, suiteTester.SetupTestRunCount, 3)
+       assert.Equal(t, suiteTester.TearDownTestRunCount, 3)
+
+       // Each test should have been run once.
+       assert.Equal(t, suiteTester.TestOneRunCount, 1)
+       assert.Equal(t, suiteTester.TestTwoRunCount, 1)
+
+       // Methods that don't match the test method identifier shouldn't
+       // have been run at all.
+       assert.Equal(t, suiteTester.NonTestMethodRunCount, 0)
+
+       suiteSkipTester := new(SuiteSkipTester)
+       Run(t, suiteSkipTester)
+
+       // The suite was only run once, so the SetupSuite and TearDownSuite
+       // methods should have each been run only once, even though SetupSuite
+       // called Skip()
+       assert.Equal(t, suiteSkipTester.SetupSuiteRunCount, 1)
+       assert.Equal(t, suiteSkipTester.TearDownSuiteRunCount, 1)
+
+}
+
+func TestSuiteGetters(t *testing.T) {
+       suite := new(SuiteTester)
+       suite.SetT(t)
+       assert.NotNil(t, suite.Assert())
+       assert.Equal(t, suite.Assertions, suite.Assert())
+       assert.NotNil(t, suite.Require())
+       assert.Equal(t, suite.require, suite.Require())
+}
+
+type SuiteLoggingTester struct {
+       Suite
+}
+
+func (s *SuiteLoggingTester) TestLoggingPass() {
+       s.T().Log("TESTLOGPASS")
+}
+
+func (s *SuiteLoggingTester) TestLoggingFail() {
+       s.T().Log("TESTLOGFAIL")
+       assert.NotNil(s.T(), nil) // expected to fail
+}
+
+type StdoutCapture struct {
+       oldStdout *os.File
+       readPipe  *os.File
+}
+
+func (sc *StdoutCapture) StartCapture() {
+       sc.oldStdout = os.Stdout
+       sc.readPipe, os.Stdout, _ = os.Pipe()
+}
+
+func (sc *StdoutCapture) StopCapture() (string, error) {
+       if sc.oldStdout == nil || sc.readPipe == nil {
+               return "", errors.New("StartCapture not called before StopCapture")
+       }
+       os.Stdout.Close()
+       os.Stdout = sc.oldStdout
+       bytes, err := ioutil.ReadAll(sc.readPipe)
+       if err != nil {
+               return "", err
+       }
+       return string(bytes), nil
+}
+
+func TestSuiteLogging(t *testing.T) {
+       testT := testing.T{}
+
+       suiteLoggingTester := new(SuiteLoggingTester)
+
+       capture := StdoutCapture{}
+       capture.StartCapture()
+       Run(&testT, suiteLoggingTester)
+       output, err := capture.StopCapture()
+
+       assert.Nil(t, err, "Got an error trying to capture stdout!")
+
+       // Failed tests' output is always printed
+       assert.Contains(t, output, "TESTLOGFAIL")
+
+       if testing.Verbose() {
+               // In verbose mode, output from successful tests is also printed
+               assert.Contains(t, output, "TESTLOGPASS")
+       } else {
+               assert.NotContains(t, output, "TESTLOGPASS")
+       }
+}
diff --git a/vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/vendor/github.com/davecgh/go-spew/LICENSE b/vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/vendor/github.com/davecgh/go-spew/LICENSE
new file mode 100644 (file)
index 0000000..2a7cfd2
--- /dev/null
@@ -0,0 +1,13 @@
+Copyright (c) 2012-2013 Dave Collins <dave@davec.name>
+
+Permission to use, copy, modify, and distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
diff --git a/vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/vendor/github.com/davecgh/go-spew/spew/bypass.go b/vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/vendor/github.com/davecgh/go-spew/spew/bypass.go
new file mode 100644 (file)
index 0000000..565bf58
--- /dev/null
@@ -0,0 +1,151 @@
+// Copyright (c) 2015 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 and "-tags disableunsafe"
+// is not added to the go build command line.
+// +build !appengine,!disableunsafe
+
+package spew
+
+import (
+       "reflect"
+       "unsafe"
+)
+
+const (
+       // UnsafeDisabled is a build-time constant which specifies whether or
+       // not access to the unsafe package is available.
+       UnsafeDisabled = false
+
+       // ptrSize is the size of a pointer on the current arch.
+       ptrSize = unsafe.Sizeof((*byte)(nil))
+)
+
+var (
+       // offsetPtr, offsetScalar, and offsetFlag are the offsets for the
+       // internal reflect.Value fields.  These values are valid before golang
+       // commit ecccf07e7f9d which changed the format.  The are also valid
+       // after commit 82f48826c6c7 which changed the format again to mirror
+       // the original format.  Code in the init function updates these offsets
+       // as necessary.
+       offsetPtr    = uintptr(ptrSize)
+       offsetScalar = uintptr(0)
+       offsetFlag   = uintptr(ptrSize * 2)
+
+       // flagKindWidth and flagKindShift indicate various bits that the
+       // reflect package uses internally to track kind information.
+       //
+       // flagRO indicates whether or not the value field of a reflect.Value is
+       // read-only.
+       //
+       // flagIndir indicates whether the value field of a reflect.Value is
+       // the actual data or a pointer to the data.
+       //
+       // These values are valid before golang commit 90a7c3c86944 which
+       // changed their positions.  Code in the init function updates these
+       // flags as necessary.
+       flagKindWidth = uintptr(5)
+       flagKindShift = uintptr(flagKindWidth - 1)
+       flagRO        = uintptr(1 << 0)
+       flagIndir     = uintptr(1 << 1)
+)
+
+func init() {
+       // Older versions of reflect.Value stored small integers directly in the
+       // ptr field (which is named val in the older versions).  Versions
+       // between commits ecccf07e7f9d and 82f48826c6c7 added a new field named
+       // scalar for this purpose which unfortunately came before the flag
+       // field, so the offset of the flag field is different for those
+       // versions.
+       //
+       // This code constructs a new reflect.Value from a known small integer
+       // and checks if the size of the reflect.Value struct indicates it has
+       // the scalar field. When it does, the offsets are updated accordingly.
+       vv := reflect.ValueOf(0xf00)
+       if unsafe.Sizeof(vv) == (ptrSize * 4) {
+               offsetScalar = ptrSize * 2
+               offsetFlag = ptrSize * 3
+       }
+
+       // Commit 90a7c3c86944 changed the flag positions such that the low
+       // order bits are the kind.  This code extracts the kind from the flags
+       // field and ensures it's the correct type.  When it's not, the flag
+       // order has been changed to the newer format, so the flags are updated
+       // accordingly.
+       upf := unsafe.Pointer(uintptr(unsafe.Pointer(&vv)) + offsetFlag)
+       upfv := *(*uintptr)(upf)
+       flagKindMask := uintptr((1<<flagKindWidth - 1) << flagKindShift)
+       if (upfv&flagKindMask)>>flagKindShift != uintptr(reflect.Int) {
+               flagKindShift = 0
+               flagRO = 1 << 5
+               flagIndir = 1 << 6
+
+               // Commit adf9b30e5594 modified the flags to separate the
+               // flagRO flag into two bits which specifies whether or not the
+               // field is embedded.  This causes flagIndir to move over a bit
+               // and means that flagRO is the combination of either of the
+               // original flagRO bit and the new bit.
+               //
+               // This code detects the change by extracting what used to be
+               // the indirect bit to ensure it's set.  When it's not, the flag
+               // order has been changed to the newer format, so the flags are
+               // updated accordingly.
+               if upfv&flagIndir == 0 {
+                       flagRO = 3 << 5
+                       flagIndir = 1 << 7
+               }
+       }
+}
+
+// unsafeReflectValue converts the passed reflect.Value into a one that bypasses
+// the typical safety restrictions preventing access to unaddressable and
+// unexported data.  It works by digging the raw pointer to the underlying
+// value out of the protected value and generating a new unprotected (unsafe)
+// reflect.Value to it.
+//
+// This allows us to check for implementations of the Stringer and error
+// interfaces to be used for pretty printing ordinarily unaddressable and
+// inaccessible values such as unexported struct fields.
+func unsafeReflectValue(v reflect.Value) (rv reflect.Value) {
+       indirects := 1
+       vt := v.Type()
+       upv := unsafe.Pointer(uintptr(unsafe.Pointer(&v)) + offsetPtr)
+       rvf := *(*uintptr)(unsafe.Pointer(uintptr(unsafe.Pointer(&v)) + offsetFlag))
+       if rvf&flagIndir != 0 {
+               vt = reflect.PtrTo(v.Type())
+               indirects++
+       } else if offsetScalar != 0 {
+               // The value is in the scalar field when it's not one of the
+               // reference types.
+               switch vt.Kind() {
+               case reflect.Uintptr:
+               case reflect.Chan:
+               case reflect.Func:
+               case reflect.Map:
+               case reflect.Ptr:
+               case reflect.UnsafePointer:
+               default:
+                       upv = unsafe.Pointer(uintptr(unsafe.Pointer(&v)) +
+                               offsetScalar)
+               }
+       }
+
+       pv := reflect.NewAt(vt, upv)
+       rv = pv
+       for i := 0; i < indirects; i++ {
+               rv = rv.Elem()
+       }
+       return rv
+}
diff --git a/vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/vendor/github.com/davecgh/go-spew/spew/bypasssafe.go b/vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/vendor/github.com/davecgh/go-spew/spew/bypasssafe.go
new file mode 100644 (file)
index 0000000..457e412
--- /dev/null
@@ -0,0 +1,37 @@
+// Copyright (c) 2015 Dave Collins <dave@davec.name>
+//
+// Permission to use, copy, modify, and distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+// NOTE: Due to the following build constraints, this file will only be compiled
+// when either the code is running on Google App Engine or "-tags disableunsafe"
+// is added to the go build command line.
+// +build appengine disableunsafe
+
+package spew
+
+import "reflect"
+
+const (
+       // UnsafeDisabled is a build-time constant which specifies whether or
+       // not access to the unsafe package is available.
+       UnsafeDisabled = true
+)
+
+// unsafeReflectValue typically converts the passed reflect.Value into a one
+// that bypasses the typical safety restrictions preventing access to
+// unaddressable and unexported data.  However, doing this relies on access to
+// the unsafe package.  This is a stub version which simply returns the passed
+// reflect.Value when the unsafe package is not available.
+func unsafeReflectValue(v reflect.Value) reflect.Value {
+       return v
+}
diff --git a/vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/vendor/github.com/davecgh/go-spew/spew/common.go b/vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/vendor/github.com/davecgh/go-spew/spew/common.go
new file mode 100644 (file)
index 0000000..14f02dc
--- /dev/null
@@ -0,0 +1,341 @@
+/*
+ * Copyright (c) 2013 Dave Collins <dave@davec.name>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+package spew
+
+import (
+       "bytes"
+       "fmt"
+       "io"
+       "reflect"
+       "sort"
+       "strconv"
+)
+
+// Some constants in the form of bytes to avoid string overhead.  This mirrors
+// the technique used in the fmt package.
+var (
+       panicBytes            = []byte("(PANIC=")
+       plusBytes             = []byte("+")
+       iBytes                = []byte("i")
+       trueBytes             = []byte("true")
+       falseBytes            = []byte("false")
+       interfaceBytes        = []byte("(interface {})")
+       commaNewlineBytes     = []byte(",\n")
+       newlineBytes          = []byte("\n")
+       openBraceBytes        = []byte("{")
+       openBraceNewlineBytes = []byte("{\n")
+       closeBraceBytes       = []byte("}")
+       asteriskBytes         = []byte("*")
+       colonBytes            = []byte(":")
+       colonSpaceBytes       = []byte(": ")
+       openParenBytes        = []byte("(")
+       closeParenBytes       = []byte(")")
+       spaceBytes            = []byte(" ")
+       pointerChainBytes     = []byte("->")
+       nilAngleBytes         = []byte("<nil>")
+       maxNewlineBytes       = []byte("<max depth reached>\n")
+       maxShortBytes         = []byte("<max>")
+       circularBytes         = []byte("<already shown>")
+       circularShortBytes    = []byte("<shown>")
+       invalidAngleBytes     = []byte("<invalid>")
+       openBracketBytes      = []byte("[")
+       closeBracketBytes     = []byte("]")
+       percentBytes          = []byte("%")
+       precisionBytes        = []byte(".")
+       openAngleBytes        = []byte("<")
+       closeAngleBytes       = []byte(">")
+       openMapBytes          = []byte("map[")
+       closeMapBytes         = []byte("]")
+       lenEqualsBytes        = []byte("len=")
+       capEqualsBytes        = []byte("cap=")
+)
+
+// hexDigits is used to map a decimal value to a hex digit.
+var hexDigits = "0123456789abcdef"
+
+// catchPanic handles any panics that might occur during the handleMethods
+// calls.
+func catchPanic(w io.Writer, v reflect.Value) {
+       if err := recover(); err != nil {
+               w.Write(panicBytes)
+               fmt.Fprintf(w, "%v", err)
+               w.Write(closeParenBytes)
+       }
+}
+
+// handleMethods attempts to call the Error and String methods on the underlying
+// type the passed reflect.Value represents and outputes the result to Writer w.
+//
+// It handles panics in any called methods by catching and displaying the error
+// as the formatted value.
+func handleMethods(cs *ConfigState, w io.Writer, v reflect.Value) (handled bool) {
+       // We need an interface to check if the type implements the error or
+       // Stringer interface.  However, the reflect package won't give us an
+       // interface on certain things like unexported struct fields in order
+       // to enforce visibility rules.  We use unsafe, when it's available,
+       // to bypass these restrictions since this package does not mutate the
+       // values.
+       if !v.CanInterface() {
+               if UnsafeDisabled {
+                       return false
+               }
+
+               v = unsafeReflectValue(v)
+       }
+
+       // Choose whether or not to do error and Stringer interface lookups against
+       // the base type or a pointer to the base type depending on settings.
+       // Technically calling one of these methods with a pointer receiver can
+       // mutate the value, however, types which choose to satisify an error or
+       // Stringer interface with a pointer receiver should not be mutating their
+       // state inside these interface methods.
+       if !cs.DisablePointerMethods && !UnsafeDisabled && !v.CanAddr() {
+               v = unsafeReflectValue(v)
+       }
+       if v.CanAddr() {
+               v = v.Addr()
+       }
+
+       // Is it an error or Stringer?
+       switch iface := v.Interface().(type) {
+       case error:
+               defer catchPanic(w, v)
+               if cs.ContinueOnMethod {
+                       w.Write(openParenBytes)
+                       w.Write([]byte(iface.Error()))
+                       w.Write(closeParenBytes)
+                       w.Write(spaceBytes)
+                       return false
+               }
+
+               w.Write([]byte(iface.Error()))
+               return true
+
+       case fmt.Stringer:
+               defer catchPanic(w, v)
+               if cs.ContinueOnMethod {
+                       w.Write(openParenBytes)
+                       w.Write([]byte(iface.String()))
+                       w.Write(closeParenBytes)
+                       w.Write(spaceBytes)
+                       return false
+               }
+               w.Write([]byte(iface.String()))
+               return true
+       }
+       return false
+}
+
+// printBool outputs a boolean value as true or false to Writer w.
+func printBool(w io.Writer, val bool) {
+       if val {
+               w.Write(trueBytes)
+       } else {
+               w.Write(falseBytes)
+       }
+}
+
+// printInt outputs a signed integer value to Writer w.
+func printInt(w io.Writer, val int64, base int) {
+       w.Write([]byte(strconv.FormatInt(val, base)))
+}
+
+// printUint outputs an unsigned integer value to Writer w.
+func printUint(w io.Writer, val uint64, base int) {
+       w.Write([]byte(strconv.FormatUint(val, base)))
+}
+
+// printFloat outputs a floating point value using the specified precision,
+// which is expected to be 32 or 64bit, to Writer w.
+func printFloat(w io.Writer, val float64, precision int) {
+       w.Write([]byte(strconv.FormatFloat(val, 'g', -1, precision)))
+}
+
+// printComplex outputs a complex value using the specified float precision
+// for the real and imaginary parts to Writer w.
+func printComplex(w io.Writer, c complex128, floatPrecision int) {
+       r := real(c)
+       w.Write(openParenBytes)
+       w.Write([]byte(strconv.FormatFloat(r, 'g', -1, floatPrecision)))
+       i := imag(c)
+       if i >= 0 {
+               w.Write(plusBytes)
+       }
+       w.Write([]byte(strconv.FormatFloat(i, 'g', -1, floatPrecision)))
+       w.Write(iBytes)
+       w.Write(closeParenBytes)
+}
+
+// printHexPtr outputs a uintptr formatted as hexidecimal with a leading '0x'
+// prefix to Writer w.
+func printHexPtr(w io.Writer, p uintptr) {
+       // Null pointer.
+       num := uint64(p)
+       if num == 0 {
+               w.Write(nilAngleBytes)
+               return
+       }
+
+       // Max uint64 is 16 bytes in hex + 2 bytes for '0x' prefix
+       buf := make([]byte, 18)
+
+       // It's simpler to construct the hex string right to left.
+       base := uint64(16)
+       i := len(buf) - 1
+       for num >= base {
+               buf[i] = hexDigits[num%base]
+               num /= base
+               i--
+       }
+       buf[i] = hexDigits[num]
+
+       // Add '0x' prefix.
+       i--
+       buf[i] = 'x'
+       i--
+       buf[i] = '0'
+
+       // Strip unused leading bytes.
+       buf = buf[i:]
+       w.Write(buf)
+}
+
+// valuesSorter implements sort.Interface to allow a slice of reflect.Value
+// elements to be sorted.
+type valuesSorter struct {
+       values  []reflect.Value
+       strings []string // either nil or same len and values
+       cs      *ConfigState
+}
+
+// newValuesSorter initializes a valuesSorter instance, which holds a set of
+// surrogate keys on which the data should be sorted.  It uses flags in
+// ConfigState to decide if and how to populate those surrogate keys.
+func newValuesSorter(values []reflect.Value, cs *ConfigState) sort.Interface {
+       vs := &valuesSorter{values: values, cs: cs}
+       if canSortSimply(vs.values[0].Kind()) {
+               return vs
+       }
+       if !cs.DisableMethods {
+               vs.strings = make([]string, len(values))
+               for i := range vs.values {
+                       b := bytes.Buffer{}
+                       if !handleMethods(cs, &b, vs.values[i]) {
+                               vs.strings = nil
+                               break
+                       }
+                       vs.strings[i] = b.String()
+               }
+       }
+       if vs.strings == nil && cs.SpewKeys {
+               vs.strings = make([]string, len(values))
+               for i := range vs.values {
+                       vs.strings[i] = Sprintf("%#v", vs.values[i].Interface())
+               }
+       }
+       return vs
+}
+
+// canSortSimply tests whether a reflect.Kind is a primitive that can be sorted
+// directly, or whether it should be considered for sorting by surrogate keys
+// (if the ConfigState allows it).
+func canSortSimply(kind reflect.Kind) bool {
+       // This switch parallels valueSortLess, except for the default case.
+       switch kind {
+       case reflect.Bool:
+               return true
+       case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int:
+               return true
+       case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint:
+               return true
+       case reflect.Float32, reflect.Float64:
+               return true
+       case reflect.String:
+               return true
+       case reflect.Uintptr:
+               return true
+       case reflect.Array:
+               return true
+       }
+       return false
+}
+
+// Len returns the number of values in the slice.  It is part of the
+// sort.Interface implementation.
+func (s *valuesSorter) Len() int {
+       return len(s.values)
+}
+
+// Swap swaps the values at the passed indices.  It is part of the
+// sort.Interface implementation.
+func (s *valuesSorter) Swap(i, j int) {
+       s.values[i], s.values[j] = s.values[j], s.values[i]
+       if s.strings != nil {
+               s.strings[i], s.strings[j] = s.strings[j], s.strings[i]
+       }
+}
+
+// valueSortLess returns whether the first value should sort before the second
+// value.  It is used by valueSorter.Less as part of the sort.Interface
+// implementation.
+func valueSortLess(a, b reflect.Value) bool {
+       switch a.Kind() {
+       case reflect.Bool:
+               return !a.Bool() && b.Bool()
+       case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int:
+               return a.Int() < b.Int()
+       case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint:
+               return a.Uint() < b.Uint()
+       case reflect.Float32, reflect.Float64:
+               return a.Float() < b.Float()
+       case reflect.String:
+               return a.String() < b.String()
+       case reflect.Uintptr:
+               return a.Uint() < b.Uint()
+       case reflect.Array:
+               // Compare the contents of both arrays.
+               l := a.Len()
+               for i := 0; i < l; i++ {
+                       av := a.Index(i)
+                       bv := b.Index(i)
+                       if av.Interface() == bv.Interface() {
+                               continue
+                       }
+                       return valueSortLess(av, bv)
+               }
+       }
+       return a.String() < b.String()
+}
+
+// Less returns whether the value at index i should sort before the
+// value at index j.  It is part of the sort.Interface implementation.
+func (s *valuesSorter) Less(i, j int) bool {
+       if s.strings == nil {
+               return valueSortLess(s.values[i], s.values[j])
+       }
+       return s.strings[i] < s.strings[j]
+}
+
+// sortValues is a sort function that handles both native types and any type that
+// can be converted to error or Stringer.  Other inputs are sorted according to
+// their Value.String() value to ensure display stability.
+func sortValues(values []reflect.Value, cs *ConfigState) {
+       if len(values) == 0 {
+               return
+       }
+       sort.Sort(newValuesSorter(values, cs))
+}
diff --git a/vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/vendor/github.com/davecgh/go-spew/spew/config.go b/vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/vendor/github.com/davecgh/go-spew/spew/config.go
new file mode 100644 (file)
index 0000000..ee1ab07
--- /dev/null
@@ -0,0 +1,297 @@
+/*
+ * Copyright (c) 2013 Dave Collins <dave@davec.name>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+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 "disableunsafe" build tag specified.
+       DisablePointerMethods 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: " "}
+}
diff --git a/vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/vendor/github.com/davecgh/go-spew/spew/doc.go b/vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/vendor/github.com/davecgh/go-spew/spew/doc.go
new file mode 100644 (file)
index 0000000..5be0c40
--- /dev/null
@@ -0,0 +1,202 @@
+/*
+ * Copyright (c) 2013 Dave Collins <dave@davec.name>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+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.
+
+       * 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
diff --git a/vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/vendor/github.com/davecgh/go-spew/spew/dump.go b/vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/vendor/github.com/davecgh/go-spew/spew/dump.go
new file mode 100644 (file)
index 0000000..a0ff95e
--- /dev/null
@@ -0,0 +1,509 @@
+/*
+ * Copyright (c) 2013 Dave Collins <dave@davec.name>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+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 len(pointerChain) > 0 {
+               d.w.Write(openParenBytes)
+               for i, addr := range pointerChain {
+                       if i > 0 {
+                               d.w.Write(pointerChainBytes)
+                       }
+                       printHexPtr(d.w, addr)
+               }
+               d.w.Write(closeParenBytes)
+       }
+
+       // Display dereferenced value.
+       d.w.Write(openParenBytes)
+       switch {
+       case nilFound == true:
+               d.w.Write(nilAngleBytes)
+
+       case cycleFound == true:
+               d.w.Write(circularBytes)
+
+       default:
+               d.ignoreNextType = true
+               d.dump(ve)
+       }
+       d.w.Write(closeParenBytes)
+}
+
+// dumpSlice handles formatting of arrays and slices.  Byte (uint8 under
+// reflection) arrays and slices are dumped in hexdump -C fashion.
+func (d *dumpState) dumpSlice(v reflect.Value) {
+       // Determine whether this type should be hex dumped or not.  Also,
+       // for types which should be hexdumped, try to use the underlying data
+       // first, then fall back to trying to convert them to a uint8 slice.
+       var buf []uint8
+       doConvert := false
+       doHexDump := false
+       numEntries := v.Len()
+       if numEntries > 0 {
+               vt := v.Index(0).Type()
+               vts := vt.String()
+               switch {
+               // C types that need to be converted.
+               case cCharRE.MatchString(vts):
+                       fallthrough
+               case cUnsignedCharRE.MatchString(vts):
+                       fallthrough
+               case cUint8tCharRE.MatchString(vts):
+                       doConvert = true
+
+               // Try to use existing uint8 slices and fall back to converting
+               // and copying if that fails.
+               case vt.Kind() == reflect.Uint8:
+                       // We need an addressable interface to convert the type
+                       // to a byte slice.  However, the reflect package won't
+                       // give us an interface on certain things like
+                       // unexported struct fields in order to enforce
+                       // visibility rules.  We use unsafe, when available, to
+                       // bypass these restrictions since this package does not
+                       // mutate the values.
+                       vs := v
+                       if !vs.CanInterface() || !vs.CanAddr() {
+                               vs = unsafeReflectValue(vs)
+                       }
+                       if !UnsafeDisabled {
+                               vs = vs.Slice(0, numEntries)
+
+                               // Use the existing uint8 slice if it can be
+                               // type asserted.
+                               iface := vs.Interface()
+                               if slice, ok := iface.([]uint8); ok {
+                                       buf = slice
+                                       doHexDump = true
+                                       break
+                               }
+                       }
+
+                       // The underlying data needs to be converted if it can't
+                       // be type asserted to a uint8 slice.
+                       doConvert = true
+               }
+
+               // Copy and convert the underlying type if needed.
+               if doConvert && vt.ConvertibleTo(uint8Type) {
+                       // Convert and copy each element into a uint8 byte
+                       // slice.
+                       buf = make([]uint8, numEntries)
+                       for i := 0; i < numEntries; i++ {
+                               vv := v.Index(i)
+                               buf[i] = uint8(vv.Convert(uint8Type).Uint())
+                       }
+                       doHexDump = true
+               }
+       }
+
+       // Hexdump the entire slice as needed.
+       if doHexDump {
+               indent := strings.Repeat(d.cs.Indent, d.depth)
+               str := indent + hex.Dump(buf)
+               str = strings.Replace(str, "\n", "\n"+indent, -1)
+               str = strings.TrimRight(str, d.cs.Indent)
+               d.w.Write([]byte(str))
+               return
+       }
+
+       // Recursively call dump for each item.
+       for i := 0; i < numEntries; i++ {
+               d.dump(d.unpackValue(v.Index(i)))
+               if i < (numEntries - 1) {
+                       d.w.Write(commaNewlineBytes)
+               } else {
+                       d.w.Write(newlineBytes)
+               }
+       }
+}
+
+// dump is the main workhorse for dumping a value.  It uses the passed reflect
+// value to figure out what kind of object we are dealing with and formats it
+// appropriately.  It is a recursive function, however circular data structures
+// are detected and handled properly.
+func (d *dumpState) dump(v reflect.Value) {
+       // Handle invalid reflect values immediately.
+       kind := v.Kind()
+       if kind == reflect.Invalid {
+               d.w.Write(invalidAngleBytes)
+               return
+       }
+
+       // Handle pointers specially.
+       if kind == reflect.Ptr {
+               d.indent()
+               d.dumpPtr(v)
+               return
+       }
+
+       // Print type information unless already handled elsewhere.
+       if !d.ignoreNextType {
+               d.indent()
+               d.w.Write(openParenBytes)
+               d.w.Write([]byte(v.Type().String()))
+               d.w.Write(closeParenBytes)
+               d.w.Write(spaceBytes)
+       }
+       d.ignoreNextType = false
+
+       // Display length and capacity if the built-in len and cap functions
+       // work with the value's kind and the len/cap itself is non-zero.
+       valueLen, valueCap := 0, 0
+       switch v.Kind() {
+       case reflect.Array, reflect.Slice, reflect.Chan:
+               valueLen, valueCap = v.Len(), v.Cap()
+       case reflect.Map, reflect.String:
+               valueLen = v.Len()
+       }
+       if valueLen != 0 || valueCap != 0 {
+               d.w.Write(openParenBytes)
+               if valueLen != 0 {
+                       d.w.Write(lenEqualsBytes)
+                       printInt(d.w, int64(valueLen), 10)
+               }
+               if 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...)
+}
diff --git a/vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/vendor/github.com/davecgh/go-spew/spew/format.go b/vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/vendor/github.com/davecgh/go-spew/spew/format.go
new file mode 100644 (file)
index 0000000..ecf3b80
--- /dev/null
@@ -0,0 +1,419 @@
+/*
+ * Copyright (c) 2013 Dave Collins <dave@davec.name>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+package spew
+
+import (
+       "bytes"
+       "fmt"
+       "reflect"
+       "strconv"
+       "strings"
+)
+
+// supportedFlags is a list of all the character flags supported by fmt package.
+const supportedFlags = "0-+# "
+
+// formatState implements the fmt.Formatter interface and contains information
+// about the state of a formatting operation.  The NewFormatter function can
+// be used to get a new Formatter which can be used directly as arguments
+// in standard fmt package printing calls.
+type formatState struct {
+       value          interface{}
+       fs             fmt.State
+       depth          int
+       pointers       map[uintptr]int
+       ignoreNextType bool
+       cs             *ConfigState
+}
+
+// buildDefaultFormat recreates the original format string without precision
+// and width information to pass in to fmt.Sprintf in the case of an
+// unrecognized type.  Unless new types are added to the language, this
+// function won't ever be called.
+func (f *formatState) buildDefaultFormat() (format string) {
+       buf := bytes.NewBuffer(percentBytes)
+
+       for _, flag := range supportedFlags {
+               if f.fs.Flag(int(flag)) {
+                       buf.WriteRune(flag)
+               }
+       }
+
+       buf.WriteRune('v')
+
+       format = buf.String()
+       return format
+}
+
+// constructOrigFormat recreates the original format string including precision
+// and width information to pass along to the standard fmt package.  This allows
+// automatic deferral of all format strings this package doesn't support.
+func (f *formatState) constructOrigFormat(verb rune) (format string) {
+       buf := bytes.NewBuffer(percentBytes)
+
+       for _, flag := range supportedFlags {
+               if f.fs.Flag(int(flag)) {
+                       buf.WriteRune(flag)
+               }
+       }
+
+       if width, ok := f.fs.Width(); ok {
+               buf.WriteString(strconv.Itoa(width))
+       }
+
+       if precision, ok := f.fs.Precision(); ok {
+               buf.Write(precisionBytes)
+               buf.WriteString(strconv.Itoa(precision))
+       }
+
+       buf.WriteRune(verb)
+
+       format = buf.String()
+       return format
+}
+
+// unpackValue returns values inside of non-nil interfaces when possible and
+// ensures that types for values which have been unpacked from an interface
+// are displayed when the show types flag is also set.
+// This is useful for data types like structs, arrays, slices, and maps which
+// can contain varying types packed inside an interface.
+func (f *formatState) unpackValue(v reflect.Value) reflect.Value {
+       if v.Kind() == reflect.Interface {
+               f.ignoreNextType = false
+               if !v.IsNil() {
+                       v = v.Elem()
+               }
+       }
+       return v
+}
+
+// formatPtr handles formatting of pointers by indirecting them as necessary.
+func (f *formatState) formatPtr(v reflect.Value) {
+       // Display nil if top level pointer is nil.
+       showTypes := f.fs.Flag('#')
+       if v.IsNil() && (!showTypes || f.ignoreNextType) {
+               f.fs.Write(nilAngleBytes)
+               return
+       }
+
+       // Remove pointers at or below the current depth from map used to detect
+       // circular refs.
+       for k, depth := range f.pointers {
+               if depth >= f.depth {
+                       delete(f.pointers, k)
+               }
+       }
+
+       // Keep list of all dereferenced pointers to possibly show later.
+       pointerChain := make([]uintptr, 0)
+
+       // Figure out how many levels of indirection there are by derferencing
+       // pointers and unpacking interfaces down the chain while detecting circular
+       // references.
+       nilFound := false
+       cycleFound := false
+       indirects := 0
+       ve := v
+       for ve.Kind() == reflect.Ptr {
+               if ve.IsNil() {
+                       nilFound = true
+                       break
+               }
+               indirects++
+               addr := ve.Pointer()
+               pointerChain = append(pointerChain, addr)
+               if pd, ok := f.pointers[addr]; ok && pd < f.depth {
+                       cycleFound = true
+                       indirects--
+                       break
+               }
+               f.pointers[addr] = f.depth
+
+               ve = ve.Elem()
+               if ve.Kind() == reflect.Interface {
+                       if ve.IsNil() {
+                               nilFound = true
+                               break
+                       }
+                       ve = ve.Elem()
+               }
+       }
+
+       // Display type or indirection level depending on flags.
+       if showTypes && !f.ignoreNextType {
+               f.fs.Write(openParenBytes)
+               f.fs.Write(bytes.Repeat(asteriskBytes, indirects))
+               f.fs.Write([]byte(ve.Type().String()))
+               f.fs.Write(closeParenBytes)
+       } else {
+               if nilFound || cycleFound {
+                       indirects += strings.Count(ve.Type().String(), "*")
+               }
+               f.fs.Write(openAngleBytes)
+               f.fs.Write([]byte(strings.Repeat("*", indirects)))
+               f.fs.Write(closeAngleBytes)
+       }
+
+       // Display pointer information depending on flags.
+       if f.fs.Flag('+') && (len(pointerChain) > 0) {
+               f.fs.Write(openParenBytes)
+               for i, addr := range pointerChain {
+                       if i > 0 {
+                               f.fs.Write(pointerChainBytes)
+                       }
+                       printHexPtr(f.fs, addr)
+               }
+               f.fs.Write(closeParenBytes)
+       }
+
+       // Display dereferenced value.
+       switch {
+       case nilFound == true:
+               f.fs.Write(nilAngleBytes)
+
+       case cycleFound == true:
+               f.fs.Write(circularShortBytes)
+
+       default:
+               f.ignoreNextType = true
+               f.format(ve)
+       }
+}
+
+// format is the main workhorse for providing the Formatter interface.  It
+// uses the passed reflect value to figure out what kind of object we are
+// dealing with and formats it appropriately.  It is a recursive function,
+// however circular data structures are detected and handled properly.
+func (f *formatState) format(v reflect.Value) {
+       // Handle invalid reflect values immediately.
+       kind := v.Kind()
+       if kind == reflect.Invalid {
+               f.fs.Write(invalidAngleBytes)
+               return
+       }
+
+       // Handle pointers specially.
+       if kind == reflect.Ptr {
+               f.formatPtr(v)
+               return
+       }
+
+       // Print type information unless already handled elsewhere.
+       if !f.ignoreNextType && f.fs.Flag('#') {
+               f.fs.Write(openParenBytes)
+               f.fs.Write([]byte(v.Type().String()))
+               f.fs.Write(closeParenBytes)
+       }
+       f.ignoreNextType = false
+
+       // Call Stringer/error interfaces if they exist and the handle methods
+       // flag is enabled.
+       if !f.cs.DisableMethods {
+               if (kind != reflect.Invalid) && (kind != reflect.Interface) {
+                       if handled := handleMethods(f.cs, f.fs, v); handled {
+                               return
+                       }
+               }
+       }
+
+       switch kind {
+       case reflect.Invalid:
+               // Do nothing.  We should never get here since invalid has already
+               // been handled above.
+
+       case reflect.Bool:
+               printBool(f.fs, v.Bool())
+
+       case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int:
+               printInt(f.fs, v.Int(), 10)
+
+       case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint:
+               printUint(f.fs, v.Uint(), 10)
+
+       case reflect.Float32:
+               printFloat(f.fs, v.Float(), 32)
+
+       case reflect.Float64:
+               printFloat(f.fs, v.Float(), 64)
+
+       case reflect.Complex64:
+               printComplex(f.fs, v.Complex(), 32)
+
+       case reflect.Complex128:
+               printComplex(f.fs, v.Complex(), 64)
+
+       case reflect.Slice:
+               if v.IsNil() {
+                       f.fs.Write(nilAngleBytes)
+                       break
+               }
+               fallthrough
+
+       case reflect.Array:
+               f.fs.Write(openBracketBytes)
+               f.depth++
+               if (f.cs.MaxDepth != 0) && (f.depth > f.cs.MaxDepth) {
+                       f.fs.Write(maxShortBytes)
+               } else {
+                       numEntries := v.Len()
+                       for i := 0; i < numEntries; i++ {
+                               if i > 0 {
+                                       f.fs.Write(spaceBytes)
+                               }
+                               f.ignoreNextType = true
+                               f.format(f.unpackValue(v.Index(i)))
+                       }
+               }
+               f.depth--
+               f.fs.Write(closeBracketBytes)
+
+       case reflect.String:
+               f.fs.Write([]byte(v.String()))
+
+       case reflect.Interface:
+               // The only time we should get here is for nil interfaces due to
+               // unpackValue calls.
+               if v.IsNil() {
+                       f.fs.Write(nilAngleBytes)
+               }
+
+       case reflect.Ptr:
+               // Do nothing.  We should never get here since pointers have already
+               // been handled above.
+
+       case reflect.Map:
+               // nil maps should be indicated as different than empty maps
+               if v.IsNil() {
+                       f.fs.Write(nilAngleBytes)
+                       break
+               }
+
+               f.fs.Write(openMapBytes)
+               f.depth++
+               if (f.cs.MaxDepth != 0) && (f.depth > f.cs.MaxDepth) {
+                       f.fs.Write(maxShortBytes)
+               } else {
+                       keys := v.MapKeys()
+                       if f.cs.SortKeys {
+                               sortValues(keys, f.cs)
+                       }
+                       for i, key := range keys {
+                               if i > 0 {
+                                       f.fs.Write(spaceBytes)
+                               }
+                               f.ignoreNextType = true
+                               f.format(f.unpackValue(key))
+                               f.fs.Write(colonBytes)
+                               f.ignoreNextType = true
+                               f.format(f.unpackValue(v.MapIndex(key)))
+                       }
+               }
+               f.depth--
+               f.fs.Write(closeMapBytes)
+
+       case reflect.Struct:
+               numFields := v.NumField()
+               f.fs.Write(openBraceBytes)
+               f.depth++
+               if (f.cs.MaxDepth != 0) && (f.depth > f.cs.MaxDepth) {
+                       f.fs.Write(maxShortBytes)
+               } else {
+                       vt := v.Type()
+                       for i := 0; i < numFields; i++ {
+                               if i > 0 {
+                                       f.fs.Write(spaceBytes)
+                               }
+                               vtf := vt.Field(i)
+                               if f.fs.Flag('+') || f.fs.Flag('#') {
+                                       f.fs.Write([]byte(vtf.Name))
+                                       f.fs.Write(colonBytes)
+                               }
+                               f.format(f.unpackValue(v.Field(i)))
+                       }
+               }
+               f.depth--
+               f.fs.Write(closeBraceBytes)
+
+       case reflect.Uintptr:
+               printHexPtr(f.fs, uintptr(v.Uint()))
+
+       case reflect.UnsafePointer, reflect.Chan, reflect.Func:
+               printHexPtr(f.fs, v.Pointer())
+
+       // There were not any other types at the time this code was written, but
+       // fall back to letting the default fmt package handle it if any get added.
+       default:
+               format := f.buildDefaultFormat()
+               if v.CanInterface() {
+                       fmt.Fprintf(f.fs, format, v.Interface())
+               } else {
+                       fmt.Fprintf(f.fs, format, v.String())
+               }
+       }
+}
+
+// Format satisfies the fmt.Formatter interface. See NewFormatter for usage
+// details.
+func (f *formatState) Format(fs fmt.State, verb rune) {
+       f.fs = fs
+
+       // Use standard formatting for verbs that are not v.
+       if verb != 'v' {
+               format := f.constructOrigFormat(verb)
+               fmt.Fprintf(fs, format, f.value)
+               return
+       }
+
+       if f.value == nil {
+               if fs.Flag('#') {
+                       fs.Write(interfaceBytes)
+               }
+               fs.Write(nilAngleBytes)
+               return
+       }
+
+       f.format(reflect.ValueOf(f.value))
+}
+
+// newFormatter is a helper function to consolidate the logic from the various
+// public methods which take varying config states.
+func newFormatter(cs *ConfigState, v interface{}) fmt.Formatter {
+       fs := &formatState{value: v, cs: cs}
+       fs.pointers = make(map[uintptr]int)
+       return fs
+}
+
+/*
+NewFormatter returns a custom formatter that satisfies the fmt.Formatter
+interface.  As a result, it integrates cleanly with standard fmt package
+printing functions.  The formatter is useful for inline printing of smaller data
+types similar to the standard %v format specifier.
+
+The custom formatter only responds to the %v (most compact), %+v (adds pointer
+addresses), %#v (adds types), or %#+v (adds types and pointer addresses) verb
+combinations.  Any other verbs such as %x and %q will be sent to the the
+standard fmt package for formatting.  In addition, the custom formatter ignores
+the width and precision arguments (however they will still work on the format
+specifiers not handled by the custom formatter).
+
+Typically this function shouldn't be called directly.  It is much easier to make
+use of the custom formatter by calling one of the convenience functions such as
+Printf, Println, or Fprintf.
+*/
+func NewFormatter(v interface{}) fmt.Formatter {
+       return newFormatter(&Config, v)
+}
diff --git a/vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/vendor/github.com/davecgh/go-spew/spew/spew.go b/vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/vendor/github.com/davecgh/go-spew/spew/spew.go
new file mode 100644 (file)
index 0000000..d8233f5
--- /dev/null
@@ -0,0 +1,148 @@
+/*
+ * Copyright (c) 2013 Dave Collins <dave@davec.name>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+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
+}
diff --git a/vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/vendor/github.com/pmezard/go-difflib/LICENSE b/vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/vendor/github.com/pmezard/go-difflib/LICENSE
new file mode 100644 (file)
index 0000000..c67dad6
--- /dev/null
@@ -0,0 +1,27 @@
+Copyright (c) 2013, Patrick Mezard
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+    Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+    Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+    The names of its contributors may not be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/vendor/github.com/pmezard/go-difflib/difflib/difflib.go b/vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/vendor/github.com/pmezard/go-difflib/difflib/difflib.go
new file mode 100644 (file)
index 0000000..64cc40f
--- /dev/null
@@ -0,0 +1,758 @@
+// Package difflib is a partial port of Python difflib module.
+//
+// It provides tools to compare sequences of strings and generate textual diffs.
+//
+// The following class and functions have been ported:
+//
+// - SequenceMatcher
+//
+// - unified_diff
+//
+// - context_diff
+//
+// Getting unified diffs was the main goal of the port. Keep in mind this code
+// is mostly suitable to output text differences in a human friendly way, there
+// are no guarantees generated diffs are consumable by patch(1).
+package difflib
+
+import (
+       "bufio"
+       "bytes"
+       "fmt"
+       "io"
+       "strings"
+)
+
+func min(a, b int) int {
+       if a < b {
+               return a
+       }
+       return b
+}
+
+func max(a, b int) int {
+       if a > b {
+               return a
+       }
+       return b
+}
+
+func calculateRatio(matches, length int) float64 {
+       if length > 0 {
+               return 2.0 * float64(matches) / float64(length)
+       }
+       return 1.0
+}
+
+type Match struct {
+       A    int
+       B    int
+       Size int
+}
+
+type OpCode struct {
+       Tag byte
+       I1  int
+       I2  int
+       J1  int
+       J2  int
+}
+
+// SequenceMatcher compares sequence of strings. The basic
+// algorithm predates, and is a little fancier than, an algorithm
+// published in the late 1980's by Ratcliff and Obershelp under the
+// hyperbolic name "gestalt pattern matching".  The basic idea is to find
+// the longest contiguous matching subsequence that contains no "junk"
+// elements (R-O doesn't address junk).  The same idea is then applied
+// recursively to the pieces of the sequences to the left and to the right
+// of the matching subsequence.  This does not yield minimal edit
+// sequences, but does tend to yield matches that "look right" to people.
+//
+// SequenceMatcher tries to compute a "human-friendly diff" between two
+// sequences.  Unlike e.g. UNIX(tm) diff, the fundamental notion is the
+// longest *contiguous* & junk-free matching subsequence.  That's what
+// catches peoples' eyes.  The Windows(tm) windiff has another interesting
+// notion, pairing up elements that appear uniquely in each sequence.
+// That, and the method here, appear to yield more intuitive difference
+// reports than does diff.  This method appears to be the least vulnerable
+// to synching up on blocks of "junk lines", though (like blank lines in
+// ordinary text files, or maybe "<P>" lines in HTML files).  That may be
+// because this is the only method of the 3 that has a *concept* of
+// "junk" <wink>.
+//
+// Timing:  Basic R-O is cubic time worst case and quadratic time expected
+// case.  SequenceMatcher is quadratic time for the worst case and has
+// expected-case behavior dependent in a complicated way on how many
+// elements the sequences have in common; best case time is linear.
+type SequenceMatcher struct {
+       a              []string
+       b              []string
+       b2j            map[string][]int
+       IsJunk         func(string) bool
+       autoJunk       bool
+       bJunk          map[string]struct{}
+       matchingBlocks []Match
+       fullBCount     map[string]int
+       bPopular       map[string]struct{}
+       opCodes        []OpCode
+}
+
+func NewMatcher(a, b []string) *SequenceMatcher {
+       m := SequenceMatcher{autoJunk: true}
+       m.SetSeqs(a, b)
+       return &m
+}
+
+func NewMatcherWithJunk(a, b []string, autoJunk bool,
+       isJunk func(string) bool) *SequenceMatcher {
+
+       m := SequenceMatcher{IsJunk: isJunk, autoJunk: autoJunk}
+       m.SetSeqs(a, b)
+       return &m
+}
+
+// Set two sequences to be compared.
+func (m *SequenceMatcher) SetSeqs(a, b []string) {
+       m.SetSeq1(a)
+       m.SetSeq2(b)
+}
+
+// Set the first sequence to be compared. The second sequence to be compared is
+// not changed.
+//
+// SequenceMatcher computes and caches detailed information about the second
+// sequence, so if you want to compare one sequence S against many sequences,
+// use .SetSeq2(s) once and call .SetSeq1(x) repeatedly for each of the other
+// sequences.
+//
+// See also SetSeqs() and SetSeq2().
+func (m *SequenceMatcher) SetSeq1(a []string) {
+       if &a == &m.a {
+               return
+       }
+       m.a = a
+       m.matchingBlocks = nil
+       m.opCodes = nil
+}
+
+// Set the second sequence to be compared. The first sequence to be compared is
+// not changed.
+func (m *SequenceMatcher) SetSeq2(b []string) {
+       if &b == &m.b {
+               return
+       }
+       m.b = b
+       m.matchingBlocks = nil
+       m.opCodes = nil
+       m.fullBCount = nil
+       m.chainB()
+}
+
+func (m *SequenceMatcher) chainB() {
+       // Populate line -> index mapping
+       b2j := map[string][]int{}
+       for i, s := range m.b {
+               indices := b2j[s]
+               indices = append(indices, i)
+               b2j[s] = indices
+       }
+
+       // Purge junk elements
+       m.bJunk = map[string]struct{}{}
+       if m.IsJunk != nil {
+               junk := m.bJunk
+               for s, _ := range b2j {
+                       if m.IsJunk(s) {
+                               junk[s] = struct{}{}
+                       }
+               }
+               for s, _ := range junk {
+                       delete(b2j, s)
+               }
+       }
+
+       // Purge remaining popular elements
+       popular := map[string]struct{}{}
+       n := len(m.b)
+       if m.autoJunk && n >= 200 {
+               ntest := n/100 + 1
+               for s, indices := range b2j {
+                       if len(indices) > ntest {
+                               popular[s] = struct{}{}
+                       }
+               }
+               for s, _ := range popular {
+                       delete(b2j, s)
+               }
+       }
+       m.bPopular = popular
+       m.b2j = b2j
+}
+
+func (m *SequenceMatcher) isBJunk(s string) bool {
+       _, ok := m.bJunk[s]
+       return ok
+}
+
+// Find longest matching block in a[alo:ahi] and b[blo:bhi].
+//
+// If IsJunk is not defined:
+//
+// Return (i,j,k) such that a[i:i+k] is equal to b[j:j+k], where
+//     alo <= i <= i+k <= ahi
+//     blo <= j <= j+k <= bhi
+// and for all (i',j',k') meeting those conditions,
+//     k >= k'
+//     i <= i'
+//     and if i == i', j <= j'
+//
+// In other words, of all maximal matching blocks, return one that
+// starts earliest in a, and of all those maximal matching blocks that
+// start earliest in a, return the one that starts earliest in b.
+//
+// If IsJunk is defined, first the longest matching block is
+// determined as above, but with the additional restriction that no
+// junk element appears in the block.  Then that block is extended as
+// far as possible by matching (only) junk elements on both sides.  So
+// the resulting block never matches on junk except as identical junk
+// happens to be adjacent to an "interesting" match.
+//
+// If no blocks match, return (alo, blo, 0).
+func (m *SequenceMatcher) findLongestMatch(alo, ahi, blo, bhi int) Match {
+       // CAUTION:  stripping common prefix or suffix would be incorrect.
+       // E.g.,
+       //    ab
+       //    acab
+       // Longest matching block is "ab", but if common prefix is
+       // stripped, it's "a" (tied with "b").  UNIX(tm) diff does so
+       // strip, so ends up claiming that ab is changed to acab by
+       // inserting "ca" in the middle.  That's minimal but unintuitive:
+       // "it's obvious" that someone inserted "ac" at the front.
+       // Windiff ends up at the same place as diff, but by pairing up
+       // the unique 'b's and then matching the first two 'a's.
+       besti, bestj, bestsize := alo, blo, 0
+
+       // find longest junk-free match
+       // during an iteration of the loop, j2len[j] = length of longest
+       // junk-free match ending with a[i-1] and b[j]
+       j2len := map[int]int{}
+       for i := alo; i != ahi; i++ {
+               // look at all instances of a[i] in b; note that because
+               // b2j has no junk keys, the loop is skipped if a[i] is junk
+               newj2len := map[int]int{}
+               for _, j := range m.b2j[m.a[i]] {
+                       // a[i] matches b[j]
+                       if j < blo {
+                               continue
+                       }
+                       if j >= bhi {
+                               break
+                       }
+                       k := j2len[j-1] + 1
+                       newj2len[j] = k
+                       if k > bestsize {
+                               besti, bestj, bestsize = i-k+1, j-k+1, k
+                       }
+               }
+               j2len = newj2len
+       }
+
+       // Extend the best by non-junk elements on each end.  In particular,
+       // "popular" non-junk elements aren't in b2j, which greatly speeds
+       // the inner loop above, but also means "the best" match so far
+       // doesn't contain any junk *or* popular non-junk elements.
+       for besti > alo && bestj > blo && !m.isBJunk(m.b[bestj-1]) &&
+               m.a[besti-1] == m.b[bestj-1] {
+               besti, bestj, bestsize = besti-1, bestj-1, bestsize+1
+       }
+       for besti+bestsize < ahi && bestj+bestsize < bhi &&
+               !m.isBJunk(m.b[bestj+bestsize]) &&
+               m.a[besti+bestsize] == m.b[bestj+bestsize] {
+               bestsize += 1
+       }
+
+       // Now that we have a wholly interesting match (albeit possibly
+       // empty!), we may as well suck up the matching junk on each
+       // side of it too.  Can't think of a good reason not to, and it
+       // saves post-processing the (possibly considerable) expense of
+       // figuring out what to do with it.  In the case of an empty
+       // interesting match, this is clearly the right thing to do,
+       // because no other kind of match is possible in the regions.
+       for besti > alo && bestj > blo && m.isBJunk(m.b[bestj-1]) &&
+               m.a[besti-1] == m.b[bestj-1] {
+               besti, bestj, bestsize = besti-1, bestj-1, bestsize+1
+       }
+       for besti+bestsize < ahi && bestj+bestsize < bhi &&
+               m.isBJunk(m.b[bestj+bestsize]) &&
+               m.a[besti+bestsize] == m.b[bestj+bestsize] {
+               bestsize += 1
+       }
+
+       return Match{A: besti, B: bestj, Size: bestsize}
+}
+
+// Return list of triples describing matching subsequences.
+//
+// Each triple is of the form (i, j, n), and means that
+// a[i:i+n] == b[j:j+n].  The triples are monotonically increasing in
+// i and in j. It's also guaranteed that if (i, j, n) and (i', j', n') are
+// adjacent triples in the list, and the second is not the last triple in the
+// list, then i+n != i' or j+n != j'. IOW, adjacent triples never describe
+// adjacent equal blocks.
+//
+// The last triple is a dummy, (len(a), len(b), 0), and is the only
+// triple with n==0.
+func (m *SequenceMatcher) GetMatchingBlocks() []Match {
+       if m.matchingBlocks != nil {
+               return m.matchingBlocks
+       }
+
+       var matchBlocks func(alo, ahi, blo, bhi int, matched []Match) []Match
+       matchBlocks = func(alo, ahi, blo, bhi int, matched []Match) []Match {
+               match := m.findLongestMatch(alo, ahi, blo, bhi)
+               i, j, k := match.A, match.B, match.Size
+               if match.Size > 0 {
+                       if alo < i && blo < j {
+                               matched = matchBlocks(alo, i, blo, j, matched)
+                       }
+                       matched = append(matched, match)
+                       if i+k < ahi && j+k < bhi {
+                               matched = matchBlocks(i+k, ahi, j+k, bhi, matched)
+                       }
+               }
+               return matched
+       }
+       matched := matchBlocks(0, len(m.a), 0, len(m.b), nil)
+
+       // It's possible that we have adjacent equal blocks in the
+       // matching_blocks list now.
+       nonAdjacent := []Match{}
+       i1, j1, k1 := 0, 0, 0
+       for _, b := range matched {
+               // Is this block adjacent to i1, j1, k1?
+               i2, j2, k2 := b.A, b.B, b.Size
+               if i1+k1 == i2 && j1+k1 == j2 {
+                       // Yes, so collapse them -- this just increases the length of
+                       // the first block by the length of the second, and the first
+                       // block so lengthened remains the block to compare against.
+                       k1 += k2
+               } else {
+                       // Not adjacent.  Remember the first block (k1==0 means it's
+                       // the dummy we started with), and make the second block the
+                       // new block to compare against.
+                       if k1 > 0 {
+                               nonAdjacent = append(nonAdjacent, Match{i1, j1, k1})
+                       }
+                       i1, j1, k1 = i2, j2, k2
+               }
+       }
+       if k1 > 0 {
+               nonAdjacent = append(nonAdjacent, Match{i1, j1, k1})
+       }
+
+       nonAdjacent = append(nonAdjacent, Match{len(m.a), len(m.b), 0})
+       m.matchingBlocks = nonAdjacent
+       return m.matchingBlocks
+}
+
+// Return list of 5-tuples describing how to turn a into b.
+//
+// Each tuple is of the form (tag, i1, i2, j1, j2).  The first tuple
+// has i1 == j1 == 0, and remaining tuples have i1 == the i2 from the
+// tuple preceding it, and likewise for j1 == the previous j2.
+//
+// The tags are characters, with these meanings:
+//
+// 'r' (replace):  a[i1:i2] should be replaced by b[j1:j2]
+//
+// 'd' (delete):   a[i1:i2] should be deleted, j1==j2 in this case.
+//
+// 'i' (insert):   b[j1:j2] should be inserted at a[i1:i1], i1==i2 in this case.
+//
+// 'e' (equal):    a[i1:i2] == b[j1:j2]
+func (m *SequenceMatcher) GetOpCodes() []OpCode {
+       if m.opCodes != nil {
+               return m.opCodes
+       }
+       i, j := 0, 0
+       matching := m.GetMatchingBlocks()
+       opCodes := make([]OpCode, 0, len(matching))
+       for _, m := range matching {
+               //  invariant:  we've pumped out correct diffs to change
+               //  a[:i] into b[:j], and the next matching block is
+               //  a[ai:ai+size] == b[bj:bj+size]. So we need to pump
+               //  out a diff to change a[i:ai] into b[j:bj], pump out
+               //  the matching block, and move (i,j) beyond the match
+               ai, bj, size := m.A, m.B, m.Size
+               tag := byte(0)
+               if i < ai && j < bj {
+                       tag = 'r'
+               } else if i < ai {
+                       tag = 'd'
+               } else if j < bj {
+                       tag = 'i'
+               }
+               if tag > 0 {
+                       opCodes = append(opCodes, OpCode{tag, i, ai, j, bj})
+               }
+               i, j = ai+size, bj+size
+               // the list of matching blocks is terminated by a
+               // sentinel with size 0
+               if size > 0 {
+                       opCodes = append(opCodes, OpCode{'e', ai, i, bj, j})
+               }
+       }
+       m.opCodes = opCodes
+       return m.opCodes
+}
+
+// Isolate change clusters by eliminating ranges with no changes.
+//
+// Return a generator of groups with up to n lines of context.
+// Each group is in the same format as returned by GetOpCodes().
+func (m *SequenceMatcher) GetGroupedOpCodes(n int) [][]OpCode {
+       if n < 0 {
+               n = 3
+       }
+       codes := m.GetOpCodes()
+       if len(codes) == 0 {
+               codes = []OpCode{OpCode{'e', 0, 1, 0, 1}}
+       }
+       // Fixup leading and trailing groups if they show no changes.
+       if codes[0].Tag == 'e' {
+               c := codes[0]
+               i1, i2, j1, j2 := c.I1, c.I2, c.J1, c.J2
+               codes[0] = OpCode{c.Tag, max(i1, i2-n), i2, max(j1, j2-n), j2}
+       }
+       if codes[len(codes)-1].Tag == 'e' {
+               c := codes[len(codes)-1]
+               i1, i2, j1, j2 := c.I1, c.I2, c.J1, c.J2
+               codes[len(codes)-1] = OpCode{c.Tag, i1, min(i2, i1+n), j1, min(j2, j1+n)}
+       }
+       nn := n + n
+       groups := [][]OpCode{}
+       group := []OpCode{}
+       for _, c := range codes {
+               i1, i2, j1, j2 := c.I1, c.I2, c.J1, c.J2
+               // End the current group and start a new one whenever
+               // there is a large range with no changes.
+               if c.Tag == 'e' && i2-i1 > nn {
+                       group = append(group, OpCode{c.Tag, i1, min(i2, i1+n),
+                               j1, min(j2, j1+n)})
+                       groups = append(groups, group)
+                       group = []OpCode{}
+                       i1, j1 = max(i1, i2-n), max(j1, j2-n)
+               }
+               group = append(group, OpCode{c.Tag, i1, i2, j1, j2})
+       }
+       if len(group) > 0 && !(len(group) == 1 && group[0].Tag == 'e') {
+               groups = append(groups, group)
+       }
+       return groups
+}
+
+// Return a measure of the sequences' similarity (float in [0,1]).
+//
+// Where T is the total number of elements in both sequences, and
+// M is the number of matches, this is 2.0*M / T.
+// Note that this is 1 if the sequences are identical, and 0 if
+// they have nothing in common.
+//
+// .Ratio() is expensive to compute if you haven't already computed
+// .GetMatchingBlocks() or .GetOpCodes(), in which case you may
+// want to try .QuickRatio() or .RealQuickRation() first to get an
+// upper bound.
+func (m *SequenceMatcher) Ratio() float64 {
+       matches := 0
+       for _, m := range m.GetMatchingBlocks() {
+               matches += m.Size
+       }
+       return calculateRatio(matches, len(m.a)+len(m.b))
+}
+
+// Return an upper bound on ratio() relatively quickly.
+//
+// This isn't defined beyond that it is an upper bound on .Ratio(), and
+// is faster to compute.
+func (m *SequenceMatcher) QuickRatio() float64 {
+       // viewing a and b as multisets, set matches to the cardinality
+       // of their intersection; this counts the number of matches
+       // without regard to order, so is clearly an upper bound
+       if m.fullBCount == nil {
+               m.fullBCount = map[string]int{}
+               for _, s := range m.b {
+                       m.fullBCount[s] = m.fullBCount[s] + 1
+               }
+       }
+
+       // avail[x] is the number of times x appears in 'b' less the
+       // number of times we've seen it in 'a' so far ... kinda
+       avail := map[string]int{}
+       matches := 0
+       for _, s := range m.a {
+               n, ok := avail[s]
+               if !ok {
+                       n = m.fullBCount[s]
+               }
+               avail[s] = n - 1
+               if n > 0 {
+                       matches += 1
+               }
+       }
+       return calculateRatio(matches, len(m.a)+len(m.b))
+}
+
+// Return an upper bound on ratio() very quickly.
+//
+// This isn't defined beyond that it is an upper bound on .Ratio(), and
+// is faster to compute than either .Ratio() or .QuickRatio().
+func (m *SequenceMatcher) RealQuickRatio() float64 {
+       la, lb := len(m.a), len(m.b)
+       return calculateRatio(min(la, lb), la+lb)
+}
+
+// Convert range to the "ed" format
+func formatRangeUnified(start, stop int) string {
+       // Per the diff spec at http://www.unix.org/single_unix_specification/
+       beginning := start + 1 // lines start numbering with one
+       length := stop - start
+       if length == 1 {
+               return fmt.Sprintf("%d", beginning)
+       }
+       if length == 0 {
+               beginning -= 1 // empty ranges begin at line just before the range
+       }
+       return fmt.Sprintf("%d,%d", beginning, length)
+}
+
+// Unified diff parameters
+type UnifiedDiff struct {
+       A        []string // First sequence lines
+       FromFile string   // First file name
+       FromDate string   // First file time
+       B        []string // Second sequence lines
+       ToFile   string   // Second file name
+       ToDate   string   // Second file time
+       Eol      string   // Headers end of line, defaults to LF
+       Context  int      // Number of context lines
+}
+
+// Compare two sequences of lines; generate the delta as a unified diff.
+//
+// Unified diffs are a compact way of showing line changes and a few
+// lines of context.  The number of context lines is set by 'n' which
+// defaults to three.
+//
+// By default, the diff control lines (those with ---, +++, or @@) are
+// created with a trailing newline.  This is helpful so that inputs
+// created from file.readlines() result in diffs that are suitable for
+// file.writelines() since both the inputs and outputs have trailing
+// newlines.
+//
+// For inputs that do not have trailing newlines, set the lineterm
+// argument to "" so that the output will be uniformly newline free.
+//
+// The unidiff format normally has a header for filenames and modification
+// times.  Any or all of these may be specified using strings for
+// 'fromfile', 'tofile', 'fromfiledate', and 'tofiledate'.
+// The modification times are normally expressed in the ISO 8601 format.
+func WriteUnifiedDiff(writer io.Writer, diff UnifiedDiff) error {
+       buf := bufio.NewWriter(writer)
+       defer buf.Flush()
+       w := func(format string, args ...interface{}) error {
+               _, err := buf.WriteString(fmt.Sprintf(format, args...))
+               return err
+       }
+
+       if len(diff.Eol) == 0 {
+               diff.Eol = "\n"
+       }
+
+       started := false
+       m := NewMatcher(diff.A, diff.B)
+       for _, g := range m.GetGroupedOpCodes(diff.Context) {
+               if !started {
+                       started = true
+                       fromDate := ""
+                       if len(diff.FromDate) > 0 {
+                               fromDate = "\t" + diff.FromDate
+                       }
+                       toDate := ""
+                       if len(diff.ToDate) > 0 {
+                               toDate = "\t" + diff.ToDate
+                       }
+                       err := w("--- %s%s%s", diff.FromFile, fromDate, diff.Eol)
+                       if err != nil {
+                               return err
+                       }
+                       err = w("+++ %s%s%s", diff.ToFile, toDate, diff.Eol)
+                       if err != nil {
+                               return err
+                       }
+               }
+               first, last := g[0], g[len(g)-1]
+               range1 := formatRangeUnified(first.I1, last.I2)
+               range2 := formatRangeUnified(first.J1, last.J2)
+               if err := w("@@ -%s +%s @@%s", range1, range2, diff.Eol); err != nil {
+                       return err
+               }
+               for _, c := range g {
+                       i1, i2, j1, j2 := c.I1, c.I2, c.J1, c.J2
+                       if c.Tag == 'e' {
+                               for _, line := range diff.A[i1:i2] {
+                                       if err := w(" " + line); err != nil {
+                                               return err
+                                       }
+                               }
+                               continue
+                       }
+                       if c.Tag == 'r' || c.Tag == 'd' {
+                               for _, line := range diff.A[i1:i2] {
+                                       if err := w("-" + line); err != nil {
+                                               return err
+                                       }
+                               }
+                       }
+                       if c.Tag == 'r' || c.Tag == 'i' {
+                               for _, line := range diff.B[j1:j2] {
+                                       if err := w("+" + line); err != nil {
+                                               return err
+                                       }
+                               }
+                       }
+               }
+       }
+       return nil
+}
+
+// Like WriteUnifiedDiff but returns the diff a string.
+func GetUnifiedDiffString(diff UnifiedDiff) (string, error) {
+       w := &bytes.Buffer{}
+       err := WriteUnifiedDiff(w, diff)
+       return string(w.Bytes()), err
+}
+
+// Convert range to the "ed" format.
+func formatRangeContext(start, stop int) string {
+       // Per the diff spec at http://www.unix.org/single_unix_specification/
+       beginning := start + 1 // lines start numbering with one
+       length := stop - start
+       if length == 0 {
+               beginning -= 1 // empty ranges begin at line just before the range
+       }
+       if length <= 1 {
+               return fmt.Sprintf("%d", beginning)
+       }
+       return fmt.Sprintf("%d,%d", beginning, beginning+length-1)
+}
+
+type ContextDiff UnifiedDiff
+
+// Compare two sequences of lines; generate the delta as a context diff.
+//
+// Context diffs are a compact way of showing line changes and a few
+// lines of context. The number of context lines is set by diff.Context
+// which defaults to three.
+//
+// By default, the diff control lines (those with *** or ---) are
+// created with a trailing newline.
+//
+// For inputs that do not have trailing newlines, set the diff.Eol
+// argument to "" so that the output will be uniformly newline free.
+//
+// The context diff format normally has a header for filenames and
+// modification times.  Any or all of these may be specified using
+// strings for diff.FromFile, diff.ToFile, diff.FromDate, diff.ToDate.
+// The modification times are normally expressed in the ISO 8601 format.
+// If not specified, the strings default to blanks.
+func WriteContextDiff(writer io.Writer, diff ContextDiff) error {
+       buf := bufio.NewWriter(writer)
+       defer buf.Flush()
+       var diffErr error
+       w := func(format string, args ...interface{}) {
+               _, err := buf.WriteString(fmt.Sprintf(format, args...))
+               if diffErr == nil && err != nil {
+                       diffErr = err
+               }
+       }
+
+       if len(diff.Eol) == 0 {
+               diff.Eol = "\n"
+       }
+
+       prefix := map[byte]string{
+               'i': "+ ",
+               'd': "- ",
+               'r': "! ",
+               'e': "  ",
+       }
+
+       started := false
+       m := NewMatcher(diff.A, diff.B)
+       for _, g := range m.GetGroupedOpCodes(diff.Context) {
+               if !started {
+                       started = true
+                       fromDate := ""
+                       if len(diff.FromDate) > 0 {
+                               fromDate = "\t" + diff.FromDate
+                       }
+                       toDate := ""
+                       if len(diff.ToDate) > 0 {
+                               toDate = "\t" + diff.ToDate
+                       }
+                       w("*** %s%s%s", diff.FromFile, fromDate, diff.Eol)
+                       w("--- %s%s%s", diff.ToFile, toDate, diff.Eol)
+               }
+
+               first, last := g[0], g[len(g)-1]
+               w("***************" + diff.Eol)
+
+               range1 := formatRangeContext(first.I1, last.I2)
+               w("*** %s ****%s", range1, diff.Eol)
+               for _, c := range g {
+                       if c.Tag == 'r' || c.Tag == 'd' {
+                               for _, cc := range g {
+                                       if cc.Tag == 'i' {
+                                               continue
+                                       }
+                                       for _, line := range diff.A[cc.I1:cc.I2] {
+                                               w(prefix[cc.Tag] + line)
+                                       }
+                               }
+                               break
+                       }
+               }
+
+               range2 := formatRangeContext(first.J1, last.J2)
+               w("--- %s ----%s", range2, diff.Eol)
+               for _, c := range g {
+                       if c.Tag == 'r' || c.Tag == 'i' {
+                               for _, cc := range g {
+                                       if cc.Tag == 'd' {
+                                               continue
+                                       }
+                                       for _, line := range diff.B[cc.J1:cc.J2] {
+                                               w(prefix[cc.Tag] + line)
+                                       }
+                               }
+                               break
+                       }
+               }
+       }
+       return diffErr
+}
+
+// Like WriteContextDiff but returns the diff a string.
+func GetContextDiffString(diff ContextDiff) (string, error) {
+       w := &bytes.Buffer{}
+       err := WriteContextDiff(w, diff)
+       return string(w.Bytes()), err
+}
+
+// Split a string on "\n" while preserving them. The output can be used
+// as input for UnifiedDiff and ContextDiff structures.
+func SplitLines(s string) []string {
+       lines := strings.SplitAfter(s, "\n")
+       lines[len(lines)-1] += "\n"
+       return lines
+}
diff --git a/vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/vendor/github.com/stretchr/objx/.gitignore b/vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/vendor/github.com/stretchr/objx/.gitignore
new file mode 100644 (file)
index 0000000..0026861
--- /dev/null
@@ -0,0 +1,22 @@
+# Compiled Object files, Static and Dynamic libs (Shared Objects)
+*.o
+*.a
+*.so
+
+# Folders
+_obj
+_test
+
+# Architecture specific extensions/prefixes
+*.[568vq]
+[568vq].out
+
+*.cgo1.go
+*.cgo2.c
+_cgo_defun.c
+_cgo_gotypes.go
+_cgo_export.*
+
+_testmain.go
+
+*.exe
diff --git a/vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/vendor/github.com/stretchr/objx/LICENSE.md b/vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/vendor/github.com/stretchr/objx/LICENSE.md
new file mode 100644 (file)
index 0000000..2199945
--- /dev/null
@@ -0,0 +1,23 @@
+objx - by Mat Ryer and Tyler Bunnell
+
+The MIT License (MIT)
+
+Copyright (c) 2014 Stretchr, Inc.
+
+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.
diff --git a/vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/vendor/github.com/stretchr/objx/README.md b/vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/vendor/github.com/stretchr/objx/README.md
new file mode 100644 (file)
index 0000000..4aa1806
--- /dev/null
@@ -0,0 +1,3 @@
+# objx
+
+  * Jump into the [API Documentation](http://godoc.org/github.com/stretchr/objx)
diff --git a/vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/vendor/github.com/stretchr/objx/accessors.go b/vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/vendor/github.com/stretchr/objx/accessors.go
new file mode 100644 (file)
index 0000000..721bcac
--- /dev/null
@@ -0,0 +1,179 @@
+package objx
+
+import (
+       "fmt"
+       "regexp"
+       "strconv"
+       "strings"
+)
+
+// arrayAccesRegexString is the regex used to extract the array number
+// from the access path
+const arrayAccesRegexString = `^(.+)\[([0-9]+)\]$`
+
+// arrayAccesRegex is the compiled arrayAccesRegexString
+var arrayAccesRegex = regexp.MustCompile(arrayAccesRegexString)
+
+// Get gets the value using the specified selector and
+// returns it inside a new Obj object.
+//
+// If it cannot find the value, Get will return a nil
+// value inside an instance of Obj.
+//
+// Get can only operate directly on map[string]interface{} and []interface.
+//
+// Example
+//
+// To access the title of the third chapter of the second book, do:
+//
+//    o.Get("books[1].chapters[2].title")
+func (m Map) Get(selector string) *Value {
+       rawObj := access(m, selector, nil, false, false)
+       return &Value{data: rawObj}
+}
+
+// Set sets the value using the specified selector and
+// returns the object on which Set was called.
+//
+// Set can only operate directly on map[string]interface{} and []interface
+//
+// Example
+//
+// To set the title of the third chapter of the second book, do:
+//
+//    o.Set("books[1].chapters[2].title","Time to Go")
+func (m Map) Set(selector string, value interface{}) Map {
+       access(m, selector, value, true, false)
+       return m
+}
+
+// access accesses the object using the selector and performs the
+// appropriate action.
+func access(current, selector, value interface{}, isSet, panics bool) interface{} {
+
+       switch selector.(type) {
+       case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64:
+
+               if array, ok := current.([]interface{}); ok {
+                       index := intFromInterface(selector)
+
+                       if index >= len(array) {
+                               if panics {
+                                       panic(fmt.Sprintf("objx: Index %d is out of range. Slice only contains %d items.", index, len(array)))
+                               }
+                               return nil
+                       }
+
+                       return array[index]
+               }
+
+               return nil
+
+       case string:
+
+               selStr := selector.(string)
+               selSegs := strings.SplitN(selStr, PathSeparator, 2)
+               thisSel := selSegs[0]
+               index := -1
+               var err error
+
+               // https://github.com/stretchr/objx/issues/12
+               if strings.Contains(thisSel, "[") {
+
+                       arrayMatches := arrayAccesRegex.FindStringSubmatch(thisSel)
+
+                       if len(arrayMatches) > 0 {
+
+                               // Get the key into the map
+                               thisSel = arrayMatches[1]
+
+                               // Get the index into the array at the key
+                               index, err = strconv.Atoi(arrayMatches[2])
+
+                               if err != nil {
+                                       // This should never happen. If it does, something has gone
+                                       // seriously wrong. Panic.
+                                       panic("objx: Array index is not an integer.  Must use array[int].")
+                               }
+
+                       }
+               }
+
+               if curMap, ok := current.(Map); ok {
+                       current = map[string]interface{}(curMap)
+               }
+
+               // get the object in question
+               switch current.(type) {
+               case map[string]interface{}:
+                       curMSI := current.(map[string]interface{})
+                       if len(selSegs) <= 1 && isSet {
+                               curMSI[thisSel] = value
+                               return nil
+                       } else {
+                               current = curMSI[thisSel]
+                       }
+               default:
+                       current = nil
+               }
+
+               if current == nil && panics {
+                       panic(fmt.Sprintf("objx: '%v' invalid on object.", selector))
+               }
+
+               // do we need to access the item of an array?
+               if index > -1 {
+                       if array, ok := current.([]interface{}); ok {
+                               if index < len(array) {
+                                       current = array[index]
+                               } else {
+                                       if panics {
+                                               panic(fmt.Sprintf("objx: Index %d is out of range. Slice only contains %d items.", index, len(array)))
+                                       }
+                                       current = nil
+                               }
+                       }
+               }
+
+               if len(selSegs) > 1 {
+                       current = access(current, selSegs[1], value, isSet, panics)
+               }
+
+       }
+
+       return current
+
+}
+
+// intFromInterface converts an interface object to the largest
+// representation of an unsigned integer using a type switch and
+// assertions
+func intFromInterface(selector interface{}) int {
+       var value int
+       switch selector.(type) {
+       case int:
+               value = selector.(int)
+       case int8:
+               value = int(selector.(int8))
+       case int16:
+               value = int(selector.(int16))
+       case int32:
+               value = int(selector.(int32))
+       case int64:
+               value = int(selector.(int64))
+       case uint:
+               value = int(selector.(uint))
+       case uint8:
+               value = int(selector.(uint8))
+       case uint16:
+               value = int(selector.(uint16))
+       case uint32:
+               value = int(selector.(uint32))
+       case uint64:
+               value = int(selector.(uint64))
+       default:
+               panic("objx: array access argument is not an integer type (this should never happen)")
+       }
+
+       return value
+}
diff --git a/vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/vendor/github.com/stretchr/objx/codegen/array-access.txt b/vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/vendor/github.com/stretchr/objx/codegen/array-access.txt
new file mode 100644 (file)
index 0000000..3060234
--- /dev/null
@@ -0,0 +1,14 @@
+  case []{1}:
+    a := object.([]{1})
+    if isSet {
+      a[index] = value.({1})
+    } else {
+      if index >= len(a) {
+        if panics {
+          panic(fmt.Sprintf("objx: Index %d is out of range because the []{1} only contains %d items.", index, len(a)))
+        }
+        return nil
+      } else {
+        return a[index]
+      }
+    }
diff --git a/vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/vendor/github.com/stretchr/objx/codegen/index.html b/vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/vendor/github.com/stretchr/objx/codegen/index.html
new file mode 100644 (file)
index 0000000..379ffc3
--- /dev/null
@@ -0,0 +1,86 @@
+<html>
+       <head>
+       <title>
+               Codegen
+       </title>
+       <style>
+               body {
+                       width: 800px;
+                       margin: auto;
+               }
+               textarea {
+                       width: 100%;
+                       min-height: 100px;
+                       font-family: Courier;
+               }
+       </style>
+       </head>
+       <body>
+
+               <h2>
+                       Template
+               </h2>
+               <p>
+                       Use <code>{x}</code> as a placeholder for each argument.
+               </p>
+               <textarea id="template"></textarea>
+
+               <h2>
+                       Arguments (comma separated)
+               </h2>
+               <p>
+                       One block per line
+               </p>
+               <textarea id="args"></textarea>
+
+               <h2>
+                       Output
+               </h2>
+               <input id="go" type="button" value="Generate code" />
+
+               <textarea id="output"></textarea>
+
+               <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
+               <script>
+
+                       $(function(){
+
+                               $("#go").click(function(){
+
+                                       var output = ""
+                                       var template = $("#template").val()
+                                       var args = $("#args").val()
+
+                                       // collect the args
+                                       var argLines = args.split("\n")
+                                       for (var line in argLines) {
+
+                                               var argLine = argLines[line];
+                                               var thisTemp = template
+
+                                               // get individual args
+                                               var args = argLine.split(",")
+
+                                               for (var argI in args) {
+                                                       var argText = args[argI];
+                                                       var argPlaceholder = "{" + argI + "}";
+
+                                                       while (thisTemp.indexOf(argPlaceholder) > -1) {
+                                                               thisTemp = thisTemp.replace(argPlaceholder, argText);
+                                                       }
+
+                                               }
+
+                                               output += thisTemp
+
+                                       }
+
+                                       $("#output").val(output);
+
+                               });
+
+                       });
+
+               </script>
+       </body>
+</html>
diff --git a/vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/vendor/github.com/stretchr/objx/codegen/template.txt b/vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/vendor/github.com/stretchr/objx/codegen/template.txt
new file mode 100644 (file)
index 0000000..b396900
--- /dev/null
@@ -0,0 +1,286 @@
+/*
+       {4} ({1} and []{1})
+       --------------------------------------------------
+*/
+
+// {4} gets the value as a {1}, returns the optionalDefault
+// value or a system default object if the value is the wrong type.
+func (v *Value) {4}(optionalDefault ...{1}) {1} {
+       if s, ok := v.data.({1}); ok {
+               return s
+       }
+       if len(optionalDefault) == 1 {
+               return optionalDefault[0]
+       }
+       return {3}
+}
+
+// Must{4} gets the value as a {1}.
+//
+// Panics if the object is not a {1}.
+func (v *Value) Must{4}() {1} {
+       return v.data.({1})
+}
+
+// {4}Slice gets the value as a []{1}, returns the optionalDefault
+// value or nil if the value is not a []{1}.
+func (v *Value) {4}Slice(optionalDefault ...[]{1}) []{1} {
+       if s, ok := v.data.([]{1}); ok {
+               return s
+       }
+       if len(optionalDefault) == 1 {
+               return optionalDefault[0]
+       }
+       return nil
+}
+
+// Must{4}Slice gets the value as a []{1}.
+//
+// Panics if the object is not a []{1}.
+func (v *Value) Must{4}Slice() []{1} {
+       return v.data.([]{1})
+}
+
+// Is{4} gets whether the object contained is a {1} or not.
+func (v *Value) Is{4}() bool {
+  _, ok := v.data.({1})
+  return ok
+}
+
+// Is{4}Slice gets whether the object contained is a []{1} or not.
+func (v *Value) Is{4}Slice() bool {
+       _, ok := v.data.([]{1})
+       return ok
+}
+
+// Each{4} calls the specified callback for each object
+// in the []{1}.
+//
+// Panics if the object is the wrong type.
+func (v *Value) Each{4}(callback func(int, {1}) bool) *Value {
+
+       for index, val := range v.Must{4}Slice() {
+               carryon := callback(index, val)
+               if carryon == false {
+                       break
+               }
+       }
+
+       return v
+
+}
+
+// Where{4} uses the specified decider function to select items
+// from the []{1}.  The object contained in the result will contain
+// only the selected items.
+func (v *Value) Where{4}(decider func(int, {1}) bool) *Value {
+
+       var selected []{1}
+
+       v.Each{4}(func(index int, val {1}) bool {
+               shouldSelect := decider(index, val)
+               if shouldSelect == false {
+                       selected = append(selected, val)
+               }
+               return true
+       })
+
+       return &Value{data:selected}
+
+}
+
+// Group{4} uses the specified grouper function to group the items
+// keyed by the return of the grouper.  The object contained in the
+// result will contain a map[string][]{1}.
+func (v *Value) Group{4}(grouper func(int, {1}) string) *Value {
+
+       groups := make(map[string][]{1})
+
+       v.Each{4}(func(index int, val {1}) bool {
+               group := grouper(index, val)
+               if _, ok := groups[group]; !ok {
+                       groups[group] = make([]{1}, 0)
+               }
+               groups[group] = append(groups[group], val)
+               return true
+       })
+
+       return &Value{data:groups}
+
+}
+
+// Replace{4} uses the specified function to replace each {1}s
+// by iterating each item.  The data in the returned result will be a
+// []{1} containing the replaced items.
+func (v *Value) Replace{4}(replacer func(int, {1}) {1}) *Value {
+
+       arr := v.Must{4}Slice()
+       replaced := make([]{1}, len(arr))
+
+       v.Each{4}(func(index int, val {1}) bool {
+               replaced[index] = replacer(index, val)
+               return true
+       })
+
+       return &Value{data:replaced}
+
+}
+
+// Collect{4} uses the specified collector function to collect a value
+// for each of the {1}s in the slice.  The data returned will be a
+// []interface{}.
+func (v *Value) Collect{4}(collector func(int, {1}) interface{}) *Value {
+
+       arr := v.Must{4}Slice()
+       collected := make([]interface{}, len(arr))
+
+       v.Each{4}(func(index int, val {1}) bool {
+               collected[index] = collector(index, val)
+               return true
+       })
+
+       return &Value{data:collected}
+}
+
+// ************************************************************
+// TESTS
+// ************************************************************
+
+func Test{4}(t *testing.T) {
+
+  val := {1}( {2} )
+       m := map[string]interface{}{"value": val, "nothing": nil}
+       assert.Equal(t, val, New(m).Get("value").{4}())
+       assert.Equal(t, val, New(m).Get("value").Must{4}())
+       assert.Equal(t, {1}({3}), New(m).Get("nothing").{4}())
+       assert.Equal(t, val, New(m).Get("nothing").{4}({2}))
+
+       assert.Panics(t, func() {
+               New(m).Get("age").Must{4}()
+       })
+
+}
+
+func Test{4}Slice(t *testing.T) {
+
+  val := {1}( {2} )
+       m := map[string]interface{}{"value": []{1}{ val }, "nothing": nil}
+       assert.Equal(t, val, New(m).Get("value").{4}Slice()[0])
+       assert.Equal(t, val, New(m).Get("value").Must{4}Slice()[0])
+       assert.Equal(t, []{1}(nil), New(m).Get("nothing").{4}Slice())
+       assert.Equal(t, val, New(m).Get("nothing").{4}Slice( []{1}{ {1}({2}) } )[0])
+
+       assert.Panics(t, func() {
+               New(m).Get("nothing").Must{4}Slice()
+       })
+
+}
+
+func TestIs{4}(t *testing.T) {
+
+       var v *Value
+
+       v = &Value{data: {1}({2})}
+       assert.True(t, v.Is{4}())
+
+       v = &Value{data: []{1}{ {1}({2}) }}
+       assert.True(t, v.Is{4}Slice())
+
+}
+
+func TestEach{4}(t *testing.T) {
+
+       v := &Value{data: []{1}{ {1}({2}), {1}({2}), {1}({2}), {1}({2}), {1}({2}) }}
+       count := 0
+       replacedVals := make([]{1}, 0)
+       assert.Equal(t, v, v.Each{4}(func(i int, val {1}) bool {
+
+               count++
+               replacedVals = append(replacedVals, val)
+
+               // abort early
+               if i == 2 {
+                       return false
+               }
+
+               return true
+
+       }))
+
+       assert.Equal(t, count, 3)
+       assert.Equal(t, replacedVals[0], v.Must{4}Slice()[0])
+       assert.Equal(t, replacedVals[1], v.Must{4}Slice()[1])
+       assert.Equal(t, replacedVals[2], v.Must{4}Slice()[2])
+
+}
+
+func TestWhere{4}(t *testing.T) {
+
+       v := &Value{data: []{1}{ {1}({2}), {1}({2}), {1}({2}), {1}({2}), {1}({2}), {1}({2}) }}
+
+       selected := v.Where{4}(func(i int, val {1}) bool {
+               return i%2==0
+       }).Must{4}Slice()
+
+       assert.Equal(t, 3, len(selected))
+
+}
+
+func TestGroup{4}(t *testing.T) {
+
+       v := &Value{data: []{1}{ {1}({2}), {1}({2}), {1}({2}), {1}({2}), {1}({2}), {1}({2}) }}
+
+       grouped := v.Group{4}(func(i int, val {1}) string {
+               return fmt.Sprintf("%v", i%2==0)
+       }).data.(map[string][]{1})
+
+       assert.Equal(t, 2, len(grouped))
+       assert.Equal(t, 3, len(grouped["true"]))
+       assert.Equal(t, 3, len(grouped["false"]))
+
+}
+
+func TestReplace{4}(t *testing.T) {
+
+       v := &Value{data: []{1}{ {1}({2}), {1}({2}), {1}({2}), {1}({2}), {1}({2}), {1}({2}) }}
+
+       rawArr := v.Must{4}Slice()
+
+       replaced := v.Replace{4}(func(index int, val {1}) {1} {
+               if index < len(rawArr)-1 {
+                       return rawArr[index+1]
+               }
+               return rawArr[0]
+       })
+
+       replacedArr := replaced.Must{4}Slice()
+       if assert.Equal(t, 6, len(replacedArr)) {
+               assert.Equal(t, replacedArr[0], rawArr[1])
+               assert.Equal(t, replacedArr[1], rawArr[2])
+               assert.Equal(t, replacedArr[2], rawArr[3])
+               assert.Equal(t, replacedArr[3], rawArr[4])
+               assert.Equal(t, replacedArr[4], rawArr[5])
+               assert.Equal(t, replacedArr[5], rawArr[0])
+       }
+
+}
+
+func TestCollect{4}(t *testing.T) {
+
+       v := &Value{data: []{1}{ {1}({2}), {1}({2}), {1}({2}), {1}({2}), {1}({2}), {1}({2}) }}
+
+       collected := v.Collect{4}(func(index int, val {1}) interface{} {
+               return index
+       })
+
+       collectedArr := collected.MustInterSlice()
+       if assert.Equal(t, 6, len(collectedArr)) {
+               assert.Equal(t, collectedArr[0], 0)
+               assert.Equal(t, collectedArr[1], 1)
+               assert.Equal(t, collectedArr[2], 2)
+               assert.Equal(t, collectedArr[3], 3)
+               assert.Equal(t, collectedArr[4], 4)
+               assert.Equal(t, collectedArr[5], 5)
+       }
+
+}
diff --git a/vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/vendor/github.com/stretchr/objx/codegen/types_list.txt b/vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/vendor/github.com/stretchr/objx/codegen/types_list.txt
new file mode 100644 (file)
index 0000000..069d43d
--- /dev/null
@@ -0,0 +1,20 @@
+Interface,interface{},"something",nil,Inter
+Map,map[string]interface{},map[string]interface{}{"name":"Tyler"},nil,MSI
+ObjxMap,(Map),New(1),New(nil),ObjxMap
+Bool,bool,true,false,Bool
+String,string,"hello","",Str
+Int,int,1,0,Int
+Int8,int8,1,0,Int8
+Int16,int16,1,0,Int16
+Int32,int32,1,0,Int32
+Int64,int64,1,0,Int64
+Uint,uint,1,0,Uint
+Uint8,uint8,1,0,Uint8
+Uint16,uint16,1,0,Uint16
+Uint32,uint32,1,0,Uint32
+Uint64,uint64,1,0,Uint64
+Uintptr,uintptr,1,0,Uintptr
+Float32,float32,1,0,Float32
+Float64,float64,1,0,Float64
+Complex64,complex64,1,0,Complex64
+Complex128,complex128,1,0,Complex128
diff --git a/vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/vendor/github.com/stretchr/objx/constants.go b/vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/vendor/github.com/stretchr/objx/constants.go
new file mode 100644 (file)
index 0000000..f9eb42a
--- /dev/null
@@ -0,0 +1,13 @@
+package objx
+
+const (
+       // PathSeparator is the character used to separate the elements
+       // of the keypath.
+       //
+       // For example, `location.address.city`
+       PathSeparator string = "."
+
+       // SignatureSeparator is the character that is used to
+       // separate the Base64 string from the security signature.
+       SignatureSeparator = "_"
+)
diff --git a/vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/vendor/github.com/stretchr/objx/conversions.go b/vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/vendor/github.com/stretchr/objx/conversions.go
new file mode 100644 (file)
index 0000000..9cdfa9f
--- /dev/null
@@ -0,0 +1,117 @@
+package objx
+
+import (
+       "bytes"
+       "encoding/base64"
+       "encoding/json"
+       "errors"
+       "fmt"
+       "net/url"
+)
+
+// JSON converts the contained object to a JSON string
+// representation
+func (m Map) JSON() (string, error) {
+
+       result, err := json.Marshal(m)
+
+       if err != nil {
+               err = errors.New("objx: JSON encode failed with: " + err.Error())
+       }
+
+       return string(result), err
+
+}
+
+// MustJSON converts the contained object to a JSON string
+// representation and panics if there is an error
+func (m Map) MustJSON() string {
+       result, err := m.JSON()
+       if err != nil {
+               panic(err.Error())
+       }
+       return result
+}
+
+// Base64 converts the contained object to a Base64 string
+// representation of the JSON string representation
+func (m Map) Base64() (string, error) {
+
+       var buf bytes.Buffer
+
+       jsonData, err := m.JSON()
+       if err != nil {
+               return "", err
+       }
+
+       encoder := base64.NewEncoder(base64.StdEncoding, &buf)
+       encoder.Write([]byte(jsonData))
+       encoder.Close()
+
+       return buf.String(), nil
+
+}
+
+// MustBase64 converts the contained object to a Base64 string
+// representation of the JSON string representation and panics
+// if there is an error
+func (m Map) MustBase64() string {
+       result, err := m.Base64()
+       if err != nil {
+               panic(err.Error())
+       }
+       return result
+}
+
+// SignedBase64 converts the contained object to a Base64 string
+// representation of the JSON string representation and signs it
+// using the provided key.
+func (m Map) SignedBase64(key string) (string, error) {
+
+       base64, err := m.Base64()
+       if err != nil {
+               return "", err
+       }
+
+       sig := HashWithKey(base64, key)
+
+       return base64 + SignatureSeparator + sig, nil
+
+}
+
+// MustSignedBase64 converts the contained object to a Base64 string
+// representation of the JSON string representation and signs it
+// using the provided key and panics if there is an error
+func (m Map) MustSignedBase64(key string) string {
+       result, err := m.SignedBase64(key)
+       if err != nil {
+               panic(err.Error())
+       }
+       return result
+}
+
+/*
+       URL Query
+       ------------------------------------------------
+*/
+
+// URLValues creates a url.Values object from an Obj. This
+// function requires that the wrapped object be a map[string]interface{}
+func (m Map) URLValues() url.Values {
+
+       vals := make(url.Values)
+
+       for k, v := range m {
+               //TODO: can this be done without sprintf?
+               vals.Set(k, fmt.Sprintf("%v", v))
+       }
+
+       return vals
+}
+
+// URLQuery gets an encoded URL query representing the given
+// Obj. This function requires that the wrapped object be a
+// map[string]interface{}
+func (m Map) URLQuery() (string, error) {
+       return m.URLValues().Encode(), nil
+}
diff --git a/vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/vendor/github.com/stretchr/objx/doc.go b/vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/vendor/github.com/stretchr/objx/doc.go
new file mode 100644 (file)
index 0000000..47bf85e
--- /dev/null
@@ -0,0 +1,72 @@
+// objx - Go package for dealing with maps, slices, JSON and other data.
+//
+// Overview
+//
+// Objx provides the `objx.Map` type, which is a `map[string]interface{}` that exposes
+// a powerful `Get` method (among others) that allows you to easily and quickly get
+// access to data within the map, without having to worry too much about type assertions,
+// missing data, default values etc.
+//
+// Pattern
+//
+// Objx uses a preditable pattern to make access data from within `map[string]interface{}'s
+// easy.
+//
+// Call one of the `objx.` functions to create your `objx.Map` to get going:
+//
+//     m, err := objx.FromJSON(json)
+//
+// NOTE: Any methods or functions with the `Must` prefix will panic if something goes wrong,
+// the rest will be optimistic and try to figure things out without panicking.
+//
+// Use `Get` to access the value you're interested in.  You can use dot and array
+// notation too:
+//
+//     m.Get("places[0].latlng")
+//
+// Once you have saught the `Value` you're interested in, you can use the `Is*` methods
+// to determine its type.
+//
+//     if m.Get("code").IsStr() { /* ... */ }
+//
+// Or you can just assume the type, and use one of the strong type methods to
+// extract the real value:
+//
+//     m.Get("code").Int()
+//
+// If there's no value there (or if it's the wrong type) then a default value
+// will be returned, or you can be explicit about the default value.
+//
+//     Get("code").Int(-1)
+//
+// If you're dealing with a slice of data as a value, Objx provides many useful
+// methods for iterating, manipulating and selecting that data.  You can find out more
+// by exploring the index below.
+//
+// Reading data
+//
+// A simple example of how to use Objx:
+//
+//     // use MustFromJSON to make an objx.Map from some JSON
+//     m := objx.MustFromJSON(`{"name": "Mat", "age": 30}`)
+//
+//     // get the details
+//     name := m.Get("name").Str()
+//     age := m.Get("age").Int()
+//
+//     // get their nickname (or use their name if they
+//     // don't have one)
+//     nickname := m.Get("nickname").Str(name)
+//
+// Ranging
+//
+// Since `objx.Map` is a `map[string]interface{}` you can treat it as such.  For
+// example, to `range` the data, do what you would expect:
+//
+//     m := objx.MustFromJSON(json)
+//     for key, value := range m {
+//
+//       /* ... do your magic ... */
+//
+//     }
+package objx
diff --git a/vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/vendor/github.com/stretchr/objx/map.go b/vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/vendor/github.com/stretchr/objx/map.go
new file mode 100644 (file)
index 0000000..eb6ed8e
--- /dev/null
@@ -0,0 +1,222 @@
+package objx
+
+import (
+       "encoding/base64"
+       "encoding/json"
+       "errors"
+       "io/ioutil"
+       "net/url"
+       "strings"
+)
+
+// MSIConvertable is an interface that defines methods for converting your
+// custom types to a map[string]interface{} representation.
+type MSIConvertable interface {
+       // MSI gets a map[string]interface{} (msi) representing the
+       // object.
+       MSI() map[string]interface{}
+}
+
+// Map provides extended functionality for working with
+// untyped data, in particular map[string]interface (msi).
+type Map map[string]interface{}
+
+// Value returns the internal value instance
+func (m Map) Value() *Value {
+       return &Value{data: m}
+}
+
+// Nil represents a nil Map.
+var Nil Map = New(nil)
+
+// New creates a new Map containing the map[string]interface{} in the data argument.
+// If the data argument is not a map[string]interface, New attempts to call the
+// MSI() method on the MSIConvertable interface to create one.
+func New(data interface{}) Map {
+       if _, ok := data.(map[string]interface{}); !ok {
+               if converter, ok := data.(MSIConvertable); ok {
+                       data = converter.MSI()
+               } else {
+                       return nil
+               }
+       }
+       return Map(data.(map[string]interface{}))
+}
+
+// MSI creates a map[string]interface{} and puts it inside a new Map.
+//
+// The arguments follow a key, value pattern.
+//
+// Panics
+//
+// Panics if any key arugment is non-string or if there are an odd number of arguments.
+//
+// Example
+//
+// To easily create Maps:
+//
+//     m := objx.MSI("name", "Mat", "age", 29, "subobj", objx.MSI("active", true))
+//
+//     // creates an Map equivalent to
+//     m := objx.New(map[string]interface{}{"name": "Mat", "age": 29, "subobj": map[string]interface{}{"active": true}})
+func MSI(keyAndValuePairs ...interface{}) Map {
+
+       newMap := make(map[string]interface{})
+       keyAndValuePairsLen := len(keyAndValuePairs)
+
+       if keyAndValuePairsLen%2 != 0 {
+               panic("objx: MSI must have an even number of arguments following the 'key, value' pattern.")
+       }
+
+       for i := 0; i < keyAndValuePairsLen; i = i + 2 {
+
+               key := keyAndValuePairs[i]
+               value := keyAndValuePairs[i+1]
+
+               // make sure the key is a string
+               keyString, keyStringOK := key.(string)
+               if !keyStringOK {
+                       panic("objx: MSI must follow 'string, interface{}' pattern.  " + keyString + " is not a valid key.")
+               }
+
+               newMap[keyString] = value
+
+       }
+
+       return New(newMap)
+}
+
+// ****** Conversion Constructors
+
+// MustFromJSON creates a new Map containing the data specified in the
+// jsonString.
+//
+// Panics if the JSON is invalid.
+func MustFromJSON(jsonString string) Map {
+       o, err := FromJSON(jsonString)
+
+       if err != nil {
+               panic("objx: MustFromJSON failed with error: " + err.Error())
+       }
+
+       return o
+}
+
+// FromJSON creates a new Map containing the data specified in the
+// jsonString.
+//
+// Returns an error if the JSON is invalid.
+func FromJSON(jsonString string) (Map, error) {
+
+       var data interface{}
+       err := json.Unmarshal([]byte(jsonString), &data)
+
+       if err != nil {
+               return Nil, err
+       }
+
+       return New(data), nil
+
+}
+
+// FromBase64 creates a new Obj containing the data specified
+// in the Base64 string.
+//
+// The string is an encoded JSON string returned by Base64
+func FromBase64(base64String string) (Map, error) {
+
+       decoder := base64.NewDecoder(base64.StdEncoding, strings.NewReader(base64String))
+
+       decoded, err := ioutil.ReadAll(decoder)
+       if err != nil {
+               return nil, err
+       }
+
+       return FromJSON(string(decoded))
+}
+
+// MustFromBase64 creates a new Obj containing the data specified
+// in the Base64 string and panics if there is an error.
+//
+// The string is an encoded JSON string returned by Base64
+func MustFromBase64(base64String string) Map {
+
+       result, err := FromBase64(base64String)
+
+       if err != nil {
+               panic("objx: MustFromBase64 failed with error: " + err.Error())
+       }
+
+       return result
+}
+
+// FromSignedBase64 creates a new Obj containing the data specified
+// in the Base64 string.
+//
+// The string is an encoded JSON string returned by SignedBase64
+func FromSignedBase64(base64String, key string) (Map, error) {
+       parts := strings.Split(base64String, SignatureSeparator)
+       if len(parts) != 2 {
+               return nil, errors.New("objx: Signed base64 string is malformed.")
+       }
+
+       sig := HashWithKey(parts[0], key)
+       if parts[1] != sig {
+               return nil, errors.New("objx: Signature for base64 data does not match.")
+       }
+
+       return FromBase64(parts[0])
+}
+
+// MustFromSignedBase64 creates a new Obj containing the data specified
+// in the Base64 string and panics if there is an error.
+//
+// The string is an encoded JSON string returned by Base64
+func MustFromSignedBase64(base64String, key string) Map {
+
+       result, err := FromSignedBase64(base64String, key)
+
+       if err != nil {
+               panic("objx: MustFromSignedBase64 failed with error: " + err.Error())
+       }
+
+       return result
+}
+
+// FromURLQuery generates a new Obj by parsing the specified
+// query.
+//
+// For queries with multiple values, the first value is selected.
+func FromURLQuery(query string) (Map, error) {
+
+       vals, err := url.ParseQuery(query)
+
+       if err != nil {
+               return nil, err
+       }
+
+       m := make(map[string]interface{})
+       for k, vals := range vals {
+               m[k] = vals[0]
+       }
+
+       return New(m), nil
+}
+
+// MustFromURLQuery generates a new Obj by parsing the specified
+// query.
+//
+// For queries with multiple values, the first value is selected.
+//
+// Panics if it encounters an error
+func MustFromURLQuery(query string) Map {
+
+       o, err := FromURLQuery(query)
+
+       if err != nil {
+               panic("objx: MustFromURLQuery failed with error: " + err.Error())
+       }
+
+       return o
+
+}
diff --git a/vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/vendor/github.com/stretchr/objx/mutations.go b/vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/vendor/github.com/stretchr/objx/mutations.go
new file mode 100644 (file)
index 0000000..b35c863
--- /dev/null
@@ -0,0 +1,81 @@
+package objx
+
+// Exclude returns a new Map with the keys in the specified []string
+// excluded.
+func (d Map) Exclude(exclude []string) Map {
+
+       excluded := make(Map)
+       for k, v := range d {
+               var shouldInclude bool = true
+               for _, toExclude := range exclude {
+                       if k == toExclude {
+                               shouldInclude = false
+                               break
+                       }
+               }
+               if shouldInclude {
+                       excluded[k] = v
+               }
+       }
+
+       return excluded
+}
+
+// Copy creates a shallow copy of the Obj.
+func (m Map) Copy() Map {
+       copied := make(map[string]interface{})
+       for k, v := range m {
+               copied[k] = v
+       }
+       return New(copied)
+}
+
+// Merge blends the specified map with a copy of this map and returns the result.
+//
+// Keys that appear in both will be selected from the specified map.
+// This method requires that the wrapped object be a map[string]interface{}
+func (m Map) Merge(merge Map) Map {
+       return m.Copy().MergeHere(merge)
+}
+
+// Merge blends the specified map with this map and returns the current map.
+//
+// Keys that appear in both will be selected from the specified map.  The original map
+// will be modified. This method requires that
+// the wrapped object be a map[string]interface{}
+func (m Map) MergeHere(merge Map) Map {
+
+       for k, v := range merge {
+               m[k] = v
+       }
+
+       return m
+
+}
+
+// Transform builds a new Obj giving the transformer a chance
+// to change the keys and values as it goes. This method requires that
+// the wrapped object be a map[string]interface{}
+func (m Map) Transform(transformer func(key string, value interface{}) (string, interface{})) Map {
+       newMap := make(map[string]interface{})
+       for k, v := range m {
+               modifiedKey, modifiedVal := transformer(k, v)
+               newMap[modifiedKey] = modifiedVal
+       }
+       return New(newMap)
+}
+
+// TransformKeys builds a new map using the specified key mapping.
+//
+// Unspecified keys will be unaltered.
+// This method requires that the wrapped object be a map[string]interface{}
+func (m Map) TransformKeys(mapping map[string]string) Map {
+       return m.Transform(func(key string, value interface{}) (string, interface{}) {
+
+               if newKey, ok := mapping[key]; ok {
+                       return newKey, value
+               }
+
+               return key, value
+       })
+}
diff --git a/vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/vendor/github.com/stretchr/objx/security.go b/vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/vendor/github.com/stretchr/objx/security.go
new file mode 100644 (file)
index 0000000..fdd6be9
--- /dev/null
@@ -0,0 +1,14 @@
+package objx
+
+import (
+       "crypto/sha1"
+       "encoding/hex"
+)
+
+// HashWithKey hashes the specified string using the security
+// key.
+func HashWithKey(data, key string) string {
+       hash := sha1.New()
+       hash.Write([]byte(data + ":" + key))
+       return hex.EncodeToString(hash.Sum(nil))
+}
diff --git a/vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/vendor/github.com/stretchr/objx/tests.go b/vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/vendor/github.com/stretchr/objx/tests.go
new file mode 100644 (file)
index 0000000..d9e0b47
--- /dev/null
@@ -0,0 +1,17 @@
+package objx
+
+// Has gets whether there is something at the specified selector
+// or not.
+//
+// If m is nil, Has will always return false.
+func (m Map) Has(selector string) bool {
+       if m == nil {
+               return false
+       }
+       return !m.Get(selector).IsNil()
+}
+
+// IsNil gets whether the data is nil or not.
+func (v *Value) IsNil() bool {
+       return v == nil || v.data == nil
+}
diff --git a/vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/vendor/github.com/stretchr/objx/type_specific_codegen.go b/vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/vendor/github.com/stretchr/objx/type_specific_codegen.go
new file mode 100644 (file)
index 0000000..f3ecb29
--- /dev/null
@@ -0,0 +1,2881 @@
+package objx
+
+/*
+       Inter (interface{} and []interface{})
+       --------------------------------------------------
+*/
+
+// Inter gets the value as a interface{}, returns the optionalDefault
+// value or a system default object if the value is the wrong type.
+func (v *Value) Inter(optionalDefault ...interface{}) interface{} {
+       if s, ok := v.data.(interface{}); ok {
+               return s
+       }
+       if len(optionalDefault) == 1 {
+               return optionalDefault[0]
+       }
+       return nil
+}
+
+// MustInter gets the value as a interface{}.
+//
+// Panics if the object is not a interface{}.
+func (v *Value) MustInter() interface{} {
+       return v.data.(interface{})
+}
+
+// InterSlice gets the value as a []interface{}, returns the optionalDefault
+// value or nil if the value is not a []interface{}.
+func (v *Value) InterSlice(optionalDefault ...[]interface{}) []interface{} {
+       if s, ok := v.data.([]interface{}); ok {
+               return s
+       }
+       if len(optionalDefault) == 1 {
+               return optionalDefault[0]
+       }
+       return nil
+}
+
+// MustInterSlice gets the value as a []interface{}.
+//
+// Panics if the object is not a []interface{}.
+func (v *Value) MustInterSlice() []interface{} {
+       return v.data.([]interface{})
+}
+
+// IsInter gets whether the object contained is a interface{} or not.
+func (v *Value) IsInter() bool {
+       _, ok := v.data.(interface{})
+       return ok
+}
+
+// IsInterSlice gets whether the object contained is a []interface{} or not.
+func (v *Value) IsInterSlice() bool {
+       _, ok := v.data.([]interface{})
+       return ok
+}
+
+// EachInter calls the specified callback for each object
+// in the []interface{}.
+//
+// Panics if the object is the wrong type.
+func (v *Value) EachInter(callback func(int, interface{}) bool) *Value {
+
+       for index, val := range v.MustInterSlice() {
+               carryon := callback(index, val)
+               if carryon == false {
+                       break
+               }
+       }
+
+       return v
+
+}
+
+// WhereInter uses the specified decider function to select items
+// from the []interface{}.  The object contained in the result will contain
+// only the selected items.
+func (v *Value) WhereInter(decider func(int, interface{}) bool) *Value {
+
+       var selected []interface{}
+
+       v.EachInter(func(index int, val interface{}) bool {
+               shouldSelect := decider(index, val)
+               if shouldSelect == false {
+                       selected = append(selected, val)
+               }
+               return true
+       })
+
+       return &Value{data: selected}
+
+}
+
+// GroupInter uses the specified grouper function to group the items
+// keyed by the return of the grouper.  The object contained in the
+// result will contain a map[string][]interface{}.
+func (v *Value) GroupInter(grouper func(int, interface{}) string) *Value {
+
+       groups := make(map[string][]interface{})
+
+       v.EachInter(func(index int, val interface{}) bool {
+               group := grouper(index, val)
+               if _, ok := groups[group]; !ok {
+                       groups[group] = make([]interface{}, 0)
+               }
+               groups[group] = append(groups[group], val)
+               return true
+       })
+
+       return &Value{data: groups}
+
+}
+
+// ReplaceInter uses the specified function to replace each interface{}s
+// by iterating each item.  The data in the returned result will be a
+// []interface{} containing the replaced items.
+func (v *Value) ReplaceInter(replacer func(int, interface{}) interface{}) *Value {
+
+       arr := v.MustInterSlice()
+       replaced := make([]interface{}, len(arr))
+
+       v.EachInter(func(index int, val interface{}) bool {
+               replaced[index] = replacer(index, val)
+               return true
+       })
+
+       return &Value{data: replaced}
+
+}
+
+// CollectInter uses the specified collector function to collect a value
+// for each of the interface{}s in the slice.  The data returned will be a
+// []interface{}.
+func (v *Value) CollectInter(collector func(int, interface{}) interface{}) *Value {
+
+       arr := v.MustInterSlice()
+       collected := make([]interface{}, len(arr))
+
+       v.EachInter(func(index int, val interface{}) bool {
+               collected[index] = collector(index, val)
+               return true
+       })
+
+       return &Value{data: collected}
+}
+
+/*
+       MSI (map[string]interface{} and []map[string]interface{})
+       --------------------------------------------------
+*/
+
+// MSI gets the value as a map[string]interface{}, returns the optionalDefault
+// value or a system default object if the value is the wrong type.
+func (v *Value) MSI(optionalDefault ...map[string]interface{}) map[string]interface{} {
+       if s, ok := v.data.(map[string]interface{}); ok {
+               return s
+       }
+       if len(optionalDefault) == 1 {
+               return optionalDefault[0]
+       }
+       return nil
+}
+
+// MustMSI gets the value as a map[string]interface{}.
+//
+// Panics if the object is not a map[string]interface{}.
+func (v *Value) MustMSI() map[string]interface{} {
+       return v.data.(map[string]interface{})
+}
+
+// MSISlice gets the value as a []map[string]interface{}, returns the optionalDefault
+// value or nil if the value is not a []map[string]interface{}.
+func (v *Value) MSISlice(optionalDefault ...[]map[string]interface{}) []map[string]interface{} {
+       if s, ok := v.data.([]map[string]interface{}); ok {
+               return s
+       }
+       if len(optionalDefault) == 1 {
+               return optionalDefault[0]
+       }
+       return nil
+}
+
+// MustMSISlice gets the value as a []map[string]interface{}.
+//
+// Panics if the object is not a []map[string]interface{}.
+func (v *Value) MustMSISlice() []map[string]interface{} {
+       return v.data.([]map[string]interface{})
+}
+
+// IsMSI gets whether the object contained is a map[string]interface{} or not.
+func (v *Value) IsMSI() bool {
+       _, ok := v.data.(map[string]interface{})
+       return ok
+}
+
+// IsMSISlice gets whether the object contained is a []map[string]interface{} or not.
+func (v *Value) IsMSISlice() bool {
+       _, ok := v.data.([]map[string]interface{})
+       return ok
+}
+
+// EachMSI calls the specified callback for each object
+// in the []map[string]interface{}.
+//
+// Panics if the object is the wrong type.
+func (v *Value) EachMSI(callback func(int, map[string]interface{}) bool) *Value {
+
+       for index, val := range v.MustMSISlice() {
+               carryon := callback(index, val)
+               if carryon == false {
+                       break
+               }
+       }
+
+       return v
+
+}
+
+// WhereMSI uses the specified decider function to select items
+// from the []map[string]interface{}.  The object contained in the result will contain
+// only the selected items.
+func (v *Value) WhereMSI(decider func(int, map[string]interface{}) bool) *Value {
+
+       var selected []map[string]interface{}
+
+       v.EachMSI(func(index int, val map[string]interface{}) bool {
+               shouldSelect := decider(index, val)
+               if shouldSelect == false {
+                       selected = append(selected, val)
+               }
+               return true
+       })
+
+       return &Value{data: selected}
+
+}
+
+// GroupMSI uses the specified grouper function to group the items
+// keyed by the return of the grouper.  The object contained in the
+// result will contain a map[string][]map[string]interface{}.
+func (v *Value) GroupMSI(grouper func(int, map[string]interface{}) string) *Value {
+
+       groups := make(map[string][]map[string]interface{})
+
+       v.EachMSI(func(index int, val map[string]interface{}) bool {
+               group := grouper(index, val)
+               if _, ok := groups[group]; !ok {
+                       groups[group] = make([]map[string]interface{}, 0)
+               }
+               groups[group] = append(groups[group], val)
+               return true
+       })
+
+       return &Value{data: groups}
+
+}
+
+// ReplaceMSI uses the specified function to replace each map[string]interface{}s
+// by iterating each item.  The data in the returned result will be a
+// []map[string]interface{} containing the replaced items.
+func (v *Value) ReplaceMSI(replacer func(int, map[string]interface{}) map[string]interface{}) *Value {
+
+       arr := v.MustMSISlice()
+       replaced := make([]map[string]interface{}, len(arr))
+
+       v.EachMSI(func(index int, val map[string]interface{}) bool {
+               replaced[index] = replacer(index, val)
+               return true
+       })
+
+       return &Value{data: replaced}
+
+}
+
+// CollectMSI uses the specified collector function to collect a value
+// for each of the map[string]interface{}s in the slice.  The data returned will be a
+// []interface{}.
+func (v *Value) CollectMSI(collector func(int, map[string]interface{}) interface{}) *Value {
+
+       arr := v.MustMSISlice()
+       collected := make([]interface{}, len(arr))
+
+       v.EachMSI(func(index int, val map[string]interface{}) bool {
+               collected[index] = collector(index, val)
+               return true
+       })
+
+       return &Value{data: collected}
+}
+
+/*
+       ObjxMap ((Map) and [](Map))
+       --------------------------------------------------
+*/
+
+// ObjxMap gets the value as a (Map), returns the optionalDefault
+// value or a system default object if the value is the wrong type.
+func (v *Value) ObjxMap(optionalDefault ...(Map)) Map {
+       if s, ok := v.data.((Map)); ok {
+               return s
+       }
+       if len(optionalDefault) == 1 {
+               return optionalDefault[0]
+       }
+       return New(nil)
+}
+
+// MustObjxMap gets the value as a (Map).
+//
+// Panics if the object is not a (Map).
+func (v *Value) MustObjxMap() Map {
+       return v.data.((Map))
+}
+
+// ObjxMapSlice gets the value as a [](Map), returns the optionalDefault
+// value or nil if the value is not a [](Map).
+func (v *Value) ObjxMapSlice(optionalDefault ...[](Map)) [](Map) {
+       if s, ok := v.data.([](Map)); ok {
+               return s
+       }
+       if len(optionalDefault) == 1 {
+               return optionalDefault[0]
+       }
+       return nil
+}
+
+// MustObjxMapSlice gets the value as a [](Map).
+//
+// Panics if the object is not a [](Map).
+func (v *Value) MustObjxMapSlice() [](Map) {
+       return v.data.([](Map))
+}
+
+// IsObjxMap gets whether the object contained is a (Map) or not.
+func (v *Value) IsObjxMap() bool {
+       _, ok := v.data.((Map))
+       return ok
+}
+
+// IsObjxMapSlice gets whether the object contained is a [](Map) or not.
+func (v *Value) IsObjxMapSlice() bool {
+       _, ok := v.data.([](Map))
+       return ok
+}
+
+// EachObjxMap calls the specified callback for each object
+// in the [](Map).
+//
+// Panics if the object is the wrong type.
+func (v *Value) EachObjxMap(callback func(int, Map) bool) *Value {
+
+       for index, val := range v.MustObjxMapSlice() {
+               carryon := callback(index, val)
+               if carryon == false {
+                       break
+               }
+       }
+
+       return v
+
+}
+
+// WhereObjxMap uses the specified decider function to select items
+// from the [](Map).  The object contained in the result will contain
+// only the selected items.
+func (v *Value) WhereObjxMap(decider func(int, Map) bool) *Value {
+
+       var selected [](Map)
+
+       v.EachObjxMap(func(index int, val Map) bool {
+               shouldSelect := decider(index, val)
+               if shouldSelect == false {
+                       selected = append(selected, val)
+               }
+               return true
+       })
+
+       return &Value{data: selected}
+
+}
+
+// GroupObjxMap uses the specified grouper function to group the items
+// keyed by the return of the grouper.  The object contained in the
+// result will contain a map[string][](Map).
+func (v *Value) GroupObjxMap(grouper func(int, Map) string) *Value {
+
+       groups := make(map[string][](Map))
+
+       v.EachObjxMap(func(index int, val Map) bool {
+               group := grouper(index, val)
+               if _, ok := groups[group]; !ok {
+                       groups[group] = make([](Map), 0)
+               }
+               groups[group] = append(groups[group], val)
+               return true
+       })
+
+       return &Value{data: groups}
+
+}
+
+// ReplaceObjxMap uses the specified function to replace each (Map)s
+// by iterating each item.  The data in the returned result will be a
+// [](Map) containing the replaced items.
+func (v *Value) ReplaceObjxMap(replacer func(int, Map) Map) *Value {
+
+       arr := v.MustObjxMapSlice()
+       replaced := make([](Map), len(arr))
+
+       v.EachObjxMap(func(index int, val Map) bool {
+               replaced[index] = replacer(index, val)
+               return true
+       })
+
+       return &Value{data: replaced}
+
+}
+
+// CollectObjxMap uses the specified collector function to collect a value
+// for each of the (Map)s in the slice.  The data returned will be a
+// []interface{}.
+func (v *Value) CollectObjxMap(collector func(int, Map) interface{}) *Value {
+
+       arr := v.MustObjxMapSlice()
+       collected := make([]interface{}, len(arr))
+
+       v.EachObjxMap(func(index int, val Map) bool {
+               collected[index] = collector(index, val)
+               return true
+       })
+
+       return &Value{data: collected}
+}
+
+/*
+       Bool (bool and []bool)
+       --------------------------------------------------
+*/
+
+// Bool gets the value as a bool, returns the optionalDefault
+// value or a system default object if the value is the wrong type.
+func (v *Value) Bool(optionalDefault ...bool) bool {
+       if s, ok := v.data.(bool); ok {
+               return s
+       }
+       if len(optionalDefault) == 1 {
+               return optionalDefault[0]
+       }
+       return false
+}
+
+// MustBool gets the value as a bool.
+//
+// Panics if the object is not a bool.
+func (v *Value) MustBool() bool {
+       return v.data.(bool)
+}
+
+// BoolSlice gets the value as a []bool, returns the optionalDefault
+// value or nil if the value is not a []bool.
+func (v *Value) BoolSlice(optionalDefault ...[]bool) []bool {
+       if s, ok := v.data.([]bool); ok {
+               return s
+       }
+       if len(optionalDefault) == 1 {
+               return optionalDefault[0]
+       }
+       return nil
+}
+
+// MustBoolSlice gets the value as a []bool.
+//
+// Panics if the object is not a []bool.
+func (v *Value) MustBoolSlice() []bool {
+       return v.data.([]bool)
+}
+
+// IsBool gets whether the object contained is a bool or not.
+func (v *Value) IsBool() bool {
+       _, ok := v.data.(bool)
+       return ok
+}
+
+// IsBoolSlice gets whether the object contained is a []bool or not.
+func (v *Value) IsBoolSlice() bool {
+       _, ok := v.data.([]bool)
+       return ok
+}
+
+// EachBool calls the specified callback for each object
+// in the []bool.
+//
+// Panics if the object is the wrong type.
+func (v *Value) EachBool(callback func(int, bool) bool) *Value {
+
+       for index, val := range v.MustBoolSlice() {
+               carryon := callback(index, val)
+               if carryon == false {
+                       break
+               }
+       }
+
+       return v
+
+}
+
+// WhereBool uses the specified decider function to select items
+// from the []bool.  The object contained in the result will contain
+// only the selected items.
+func (v *Value) WhereBool(decider func(int, bool) bool) *Value {
+
+       var selected []bool
+
+       v.EachBool(func(index int, val bool) bool {
+               shouldSelect := decider(index, val)
+               if shouldSelect == false {
+                       selected = append(selected, val)
+               }
+               return true
+       })
+
+       return &Value{data: selected}
+
+}
+
+// GroupBool uses the specified grouper function to group the items
+// keyed by the return of the grouper.  The object contained in the
+// result will contain a map[string][]bool.
+func (v *Value) GroupBool(grouper func(int, bool) string) *Value {
+
+       groups := make(map[string][]bool)
+
+       v.EachBool(func(index int, val bool) bool {
+               group := grouper(index, val)
+               if _, ok := groups[group]; !ok {
+                       groups[group] = make([]bool, 0)
+               }
+               groups[group] = append(groups[group], val)
+               return true
+       })
+
+       return &Value{data: groups}
+
+}
+
+// ReplaceBool uses the specified function to replace each bools
+// by iterating each item.  The data in the returned result will be a
+// []bool containing the replaced items.
+func (v *Value) ReplaceBool(replacer func(int, bool) bool) *Value {
+
+       arr := v.MustBoolSlice()
+       replaced := make([]bool, len(arr))
+
+       v.EachBool(func(index int, val bool) bool {
+               replaced[index] = replacer(index, val)
+               return true
+       })
+
+       return &Value{data: replaced}
+
+}
+
+// CollectBool uses the specified collector function to collect a value
+// for each of the bools in the slice.  The data returned will be a
+// []interface{}.
+func (v *Value) CollectBool(collector func(int, bool) interface{}) *Value {
+
+       arr := v.MustBoolSlice()
+       collected := make([]interface{}, len(arr))
+
+       v.EachBool(func(index int, val bool) bool {
+               collected[index] = collector(index, val)
+               return true
+       })
+
+       return &Value{data: collected}
+}
+
+/*
+       Str (string and []string)
+       --------------------------------------------------
+*/
+
+// Str gets the value as a string, returns the optionalDefault
+// value or a system default object if the value is the wrong type.
+func (v *Value) Str(optionalDefault ...string) string {
+       if s, ok := v.data.(string); ok {
+               return s
+       }
+       if len(optionalDefault) == 1 {
+               return optionalDefault[0]
+       }
+       return ""
+}
+
+// MustStr gets the value as a string.
+//
+// Panics if the object is not a string.
+func (v *Value) MustStr() string {
+       return v.data.(string)
+}
+
+// StrSlice gets the value as a []string, returns the optionalDefault
+// value or nil if the value is not a []string.
+func (v *Value) StrSlice(optionalDefault ...[]string) []string {
+       if s, ok := v.data.([]string); ok {
+               return s
+       }
+       if len(optionalDefault) == 1 {
+               return optionalDefault[0]
+       }
+       return nil
+}
+
+// MustStrSlice gets the value as a []string.
+//
+// Panics if the object is not a []string.
+func (v *Value) MustStrSlice() []string {
+       return v.data.([]string)
+}
+
+// IsStr gets whether the object contained is a string or not.
+func (v *Value) IsStr() bool {
+       _, ok := v.data.(string)
+       return ok
+}
+
+// IsStrSlice gets whether the object contained is a []string or not.
+func (v *Value) IsStrSlice() bool {
+       _, ok := v.data.([]string)
+       return ok
+}
+
+// EachStr calls the specified callback for each object
+// in the []string.
+//
+// Panics if the object is the wrong type.
+func (v *Value) EachStr(callback func(int, string) bool) *Value {
+
+       for index, val := range v.MustStrSlice() {
+               carryon := callback(index, val)
+               if carryon == false {
+                       break
+               }
+       }
+
+       return v
+
+}
+
+// WhereStr uses the specified decider function to select items
+// from the []string.  The object contained in the result will contain
+// only the selected items.
+func (v *Value) WhereStr(decider func(int, string) bool) *Value {
+
+       var selected []string
+
+       v.EachStr(func(index int, val string) bool {
+               shouldSelect := decider(index, val)
+               if shouldSelect == false {
+                       selected = append(selected, val)
+               }
+               return true
+       })
+
+       return &Value{data: selected}
+
+}
+
+// GroupStr uses the specified grouper function to group the items
+// keyed by the return of the grouper.  The object contained in the
+// result will contain a map[string][]string.
+func (v *Value) GroupStr(grouper func(int, string) string) *Value {
+
+       groups := make(map[string][]string)
+
+       v.EachStr(func(index int, val string) bool {
+               group := grouper(index, val)
+               if _, ok := groups[group]; !ok {
+                       groups[group] = make([]string, 0)
+               }
+               groups[group] = append(groups[group], val)
+               return true
+       })
+
+       return &Value{data: groups}
+
+}
+
+// ReplaceStr uses the specified function to replace each strings
+// by iterating each item.  The data in the returned result will be a
+// []string containing the replaced items.
+func (v *Value) ReplaceStr(replacer func(int, string) string) *Value {
+
+       arr := v.MustStrSlice()
+       replaced := make([]string, len(arr))
+
+       v.EachStr(func(index int, val string) bool {
+               replaced[index] = replacer(index, val)
+               return true
+       })
+
+       return &Value{data: replaced}
+
+}
+
+// CollectStr uses the specified collector function to collect a value
+// for each of the strings in the slice.  The data returned will be a
+// []interface{}.
+func (v *Value) CollectStr(collector func(int, string) interface{}) *Value {
+
+       arr := v.MustStrSlice()
+       collected := make([]interface{}, len(arr))
+
+       v.EachStr(func(index int, val string) bool {
+               collected[index] = collector(index, val)
+               return true
+       })
+
+       return &Value{data: collected}
+}
+
+/*
+       Int (int and []int)
+       --------------------------------------------------
+*/
+
+// Int gets the value as a int, returns the optionalDefault
+// value or a system default object if the value is the wrong type.
+func (v *Value) Int(optionalDefault ...int) int {
+       if s, ok := v.data.(int); ok {
+               return s
+       }
+       if len(optionalDefault) == 1 {
+               return optionalDefault[0]
+       }
+       return 0
+}
+
+// MustInt gets the value as a int.
+//
+// Panics if the object is not a int.
+func (v *Value) MustInt() int {
+       return v.data.(int)
+}
+
+// IntSlice gets the value as a []int, returns the optionalDefault
+// value or nil if the value is not a []int.
+func (v *Value) IntSlice(optionalDefault ...[]int) []int {
+       if s, ok := v.data.([]int); ok {
+               return s
+       }
+       if len(optionalDefault) == 1 {
+               return optionalDefault[0]
+       }
+       return nil
+}
+
+// MustIntSlice gets the value as a []int.
+//
+// Panics if the object is not a []int.
+func (v *Value) MustIntSlice() []int {
+       return v.data.([]int)
+}
+
+// IsInt gets whether the object contained is a int or not.
+func (v *Value) IsInt() bool {
+       _, ok := v.data.(int)
+       return ok
+}
+
+// IsIntSlice gets whether the object contained is a []int or not.
+func (v *Value) IsIntSlice() bool {
+       _, ok := v.data.([]int)
+       return ok
+}
+
+// EachInt calls the specified callback for each object
+// in the []int.
+//
+// Panics if the object is the wrong type.
+func (v *Value) EachInt(callback func(int, int) bool) *Value {
+
+       for index, val := range v.MustIntSlice() {
+               carryon := callback(index, val)
+               if carryon == false {
+                       break
+               }
+       }
+
+       return v
+
+}
+
+// WhereInt uses the specified decider function to select items
+// from the []int.  The object contained in the result will contain
+// only the selected items.
+func (v *Value) WhereInt(decider func(int, int) bool) *Value {
+
+       var selected []int
+
+       v.EachInt(func(index int, val int) bool {
+               shouldSelect := decider(index, val)
+               if shouldSelect == false {
+                       selected = append(selected, val)
+               }
+               return true
+       })
+
+       return &Value{data: selected}
+
+}
+
+// GroupInt uses the specified grouper function to group the items
+// keyed by the return of the grouper.  The object contained in the
+// result will contain a map[string][]int.
+func (v *Value) GroupInt(grouper func(int, int) string) *Value {
+
+       groups := make(map[string][]int)
+
+       v.EachInt(func(index int, val int) bool {
+               group := grouper(index, val)
+               if _, ok := groups[group]; !ok {
+                       groups[group] = make([]int, 0)
+               }
+               groups[group] = append(groups[group], val)
+               return true
+       })
+
+       return &Value{data: groups}
+
+}
+
+// ReplaceInt uses the specified function to replace each ints
+// by iterating each item.  The data in the returned result will be a
+// []int containing the replaced items.
+func (v *Value) ReplaceInt(replacer func(int, int) int) *Value {
+
+       arr := v.MustIntSlice()
+       replaced := make([]int, len(arr))
+
+       v.EachInt(func(index int, val int) bool {
+               replaced[index] = replacer(index, val)
+               return true
+       })
+
+       return &Value{data: replaced}
+
+}
+
+// CollectInt uses the specified collector function to collect a value
+// for each of the ints in the slice.  The data returned will be a
+// []interface{}.
+func (v *Value) CollectInt(collector func(int, int) interface{}) *Value {
+
+       arr := v.MustIntSlice()
+       collected := make([]interface{}, len(arr))
+
+       v.EachInt(func(index int, val int) bool {
+               collected[index] = collector(index, val)
+               return true
+       })
+
+       return &Value{data: collected}
+}
+
+/*
+       Int8 (int8 and []int8)
+       --------------------------------------------------
+*/
+
+// Int8 gets the value as a int8, returns the optionalDefault
+// value or a system default object if the value is the wrong type.
+func (v *Value) Int8(optionalDefault ...int8) int8 {
+       if s, ok := v.data.(int8); ok {
+               return s
+       }
+       if len(optionalDefault) == 1 {
+               return optionalDefault[0]
+       }
+       return 0
+}
+
+// MustInt8 gets the value as a int8.
+//
+// Panics if the object is not a int8.
+func (v *Value) MustInt8() int8 {
+       return v.data.(int8)
+}
+
+// Int8Slice gets the value as a []int8, returns the optionalDefault
+// value or nil if the value is not a []int8.
+func (v *Value) Int8Slice(optionalDefault ...[]int8) []int8 {
+       if s, ok := v.data.([]int8); ok {
+               return s
+       }
+       if len(optionalDefault) == 1 {
+               return optionalDefault[0]
+       }
+       return nil
+}
+
+// MustInt8Slice gets the value as a []int8.
+//
+// Panics if the object is not a []int8.
+func (v *Value) MustInt8Slice() []int8 {
+       return v.data.([]int8)
+}
+
+// IsInt8 gets whether the object contained is a int8 or not.
+func (v *Value) IsInt8() bool {
+       _, ok := v.data.(int8)
+       return ok
+}
+
+// IsInt8Slice gets whether the object contained is a []int8 or not.
+func (v *Value) IsInt8Slice() bool {
+       _, ok := v.data.([]int8)
+       return ok
+}
+
+// EachInt8 calls the specified callback for each object
+// in the []int8.
+//
+// Panics if the object is the wrong type.
+func (v *Value) EachInt8(callback func(int, int8) bool) *Value {
+
+       for index, val := range v.MustInt8Slice() {
+               carryon := callback(index, val)
+               if carryon == false {
+                       break
+               }
+       }
+
+       return v
+
+}
+
+// WhereInt8 uses the specified decider function to select items
+// from the []int8.  The object contained in the result will contain
+// only the selected items.
+func (v *Value) WhereInt8(decider func(int, int8) bool) *Value {
+
+       var selected []int8
+
+       v.EachInt8(func(index int, val int8) bool {
+               shouldSelect := decider(index, val)
+               if shouldSelect == false {
+                       selected = append(selected, val)
+               }
+               return true
+       })
+
+       return &Value{data: selected}
+
+}
+
+// GroupInt8 uses the specified grouper function to group the items
+// keyed by the return of the grouper.  The object contained in the
+// result will contain a map[string][]int8.
+func (v *Value) GroupInt8(grouper func(int, int8) string) *Value {
+
+       groups := make(map[string][]int8)
+
+       v.EachInt8(func(index int, val int8) bool {
+               group := grouper(index, val)
+               if _, ok := groups[group]; !ok {
+                       groups[group] = make([]int8, 0)
+               }
+               groups[group] = append(groups[group], val)
+               return true
+       })
+
+       return &Value{data: groups}
+
+}
+
+// ReplaceInt8 uses the specified function to replace each int8s
+// by iterating each item.  The data in the returned result will be a
+// []int8 containing the replaced items.
+func (v *Value) ReplaceInt8(replacer func(int, int8) int8) *Value {
+
+       arr := v.MustInt8Slice()
+       replaced := make([]int8, len(arr))
+
+       v.EachInt8(func(index int, val int8) bool {
+               replaced[index] = replacer(index, val)
+               return true
+       })
+
+       return &Value{data: replaced}
+
+}
+
+// CollectInt8 uses the specified collector function to collect a value
+// for each of the int8s in the slice.  The data returned will be a
+// []interface{}.
+func (v *Value) CollectInt8(collector func(int, int8) interface{}) *Value {
+
+       arr := v.MustInt8Slice()
+       collected := make([]interface{}, len(arr))
+
+       v.EachInt8(func(index int, val int8) bool {
+               collected[index] = collector(index, val)
+               return true
+       })
+
+       return &Value{data: collected}
+}
+
+/*
+       Int16 (int16 and []int16)
+       --------------------------------------------------
+*/
+
+// Int16 gets the value as a int16, returns the optionalDefault
+// value or a system default object if the value is the wrong type.
+func (v *Value) Int16(optionalDefault ...int16) int16 {
+       if s, ok := v.data.(int16); ok {
+               return s
+       }
+       if len(optionalDefault) == 1 {
+               return optionalDefault[0]
+       }
+       return 0
+}
+
+// MustInt16 gets the value as a int16.
+//
+// Panics if the object is not a int16.
+func (v *Value) MustInt16() int16 {
+       return v.data.(int16)
+}
+
+// Int16Slice gets the value as a []int16, returns the optionalDefault
+// value or nil if the value is not a []int16.
+func (v *Value) Int16Slice(optionalDefault ...[]int16) []int16 {
+       if s, ok := v.data.([]int16); ok {
+               return s
+       }
+       if len(optionalDefault) == 1 {
+               return optionalDefault[0]
+       }
+       return nil
+}
+
+// MustInt16Slice gets the value as a []int16.
+//
+// Panics if the object is not a []int16.
+func (v *Value) MustInt16Slice() []int16 {
+       return v.data.([]int16)
+}
+
+// IsInt16 gets whether the object contained is a int16 or not.
+func (v *Value) IsInt16() bool {
+       _, ok := v.data.(int16)
+       return ok
+}
+
+// IsInt16Slice gets whether the object contained is a []int16 or not.
+func (v *Value) IsInt16Slice() bool {
+       _, ok := v.data.([]int16)
+       return ok
+}
+
+// EachInt16 calls the specified callback for each object
+// in the []int16.
+//
+// Panics if the object is the wrong type.
+func (v *Value) EachInt16(callback func(int, int16) bool) *Value {
+
+       for index, val := range v.MustInt16Slice() {
+               carryon := callback(index, val)
+               if carryon == false {
+                       break
+               }
+       }
+
+       return v
+
+}
+
+// WhereInt16 uses the specified decider function to select items
+// from the []int16.  The object contained in the result will contain
+// only the selected items.
+func (v *Value) WhereInt16(decider func(int, int16) bool) *Value {
+
+       var selected []int16
+
+       v.EachInt16(func(index int, val int16) bool {
+               shouldSelect := decider(index, val)
+               if shouldSelect == false {
+                       selected = append(selected, val)
+               }
+               return true
+       })
+
+       return &Value{data: selected}
+
+}
+
+// GroupInt16 uses the specified grouper function to group the items
+// keyed by the return of the grouper.  The object contained in the
+// result will contain a map[string][]int16.
+func (v *Value) GroupInt16(grouper func(int, int16) string) *Value {
+
+       groups := make(map[string][]int16)
+
+       v.EachInt16(func(index int, val int16) bool {
+               group := grouper(index, val)
+               if _, ok := groups[group]; !ok {
+                       groups[group] = make([]int16, 0)
+               }
+               groups[group] = append(groups[group], val)
+               return true
+       })
+
+       return &Value{data: groups}
+
+}
+
+// ReplaceInt16 uses the specified function to replace each int16s
+// by iterating each item.  The data in the returned result will be a
+// []int16 containing the replaced items.
+func (v *Value) ReplaceInt16(replacer func(int, int16) int16) *Value {
+
+       arr := v.MustInt16Slice()
+       replaced := make([]int16, len(arr))
+
+       v.EachInt16(func(index int, val int16) bool {
+               replaced[index] = replacer(index, val)
+               return true
+       })
+
+       return &Value{data: replaced}
+
+}
+
+// CollectInt16 uses the specified collector function to collect a value
+// for each of the int16s in the slice.  The data returned will be a
+// []interface{}.
+func (v *Value) CollectInt16(collector func(int, int16) interface{}) *Value {
+
+       arr := v.MustInt16Slice()
+       collected := make([]interface{}, len(arr))
+
+       v.EachInt16(func(index int, val int16) bool {
+               collected[index] = collector(index, val)
+               return true
+       })
+
+       return &Value{data: collected}
+}
+
+/*
+       Int32 (int32 and []int32)
+       --------------------------------------------------
+*/
+
+// Int32 gets the value as a int32, returns the optionalDefault
+// value or a system default object if the value is the wrong type.
+func (v *Value) Int32(optionalDefault ...int32) int32 {
+       if s, ok := v.data.(int32); ok {
+               return s
+       }
+       if len(optionalDefault) == 1 {
+               return optionalDefault[0]
+       }
+       return 0
+}
+
+// MustInt32 gets the value as a int32.
+//
+// Panics if the object is not a int32.
+func (v *Value) MustInt32() int32 {
+       return v.data.(int32)
+}
+
+// Int32Slice gets the value as a []int32, returns the optionalDefault
+// value or nil if the value is not a []int32.
+func (v *Value) Int32Slice(optionalDefault ...[]int32) []int32 {
+       if s, ok := v.data.([]int32); ok {
+               return s
+       }
+       if len(optionalDefault) == 1 {
+               return optionalDefault[0]
+       }
+       return nil
+}
+
+// MustInt32Slice gets the value as a []int32.
+//
+// Panics if the object is not a []int32.
+func (v *Value) MustInt32Slice() []int32 {
+       return v.data.([]int32)
+}
+
+// IsInt32 gets whether the object contained is a int32 or not.
+func (v *Value) IsInt32() bool {
+       _, ok := v.data.(int32)
+       return ok
+}
+
+// IsInt32Slice gets whether the object contained is a []int32 or not.
+func (v *Value) IsInt32Slice() bool {
+       _, ok := v.data.([]int32)
+       return ok
+}
+
+// EachInt32 calls the specified callback for each object
+// in the []int32.
+//
+// Panics if the object is the wrong type.
+func (v *Value) EachInt32(callback func(int, int32) bool) *Value {
+
+       for index, val := range v.MustInt32Slice() {
+               carryon := callback(index, val)
+               if carryon == false {
+                       break
+               }
+       }
+
+       return v
+
+}
+
+// WhereInt32 uses the specified decider function to select items
+// from the []int32.  The object contained in the result will contain
+// only the selected items.
+func (v *Value) WhereInt32(decider func(int, int32) bool) *Value {
+
+       var selected []int32
+
+       v.EachInt32(func(index int, val int32) bool {
+               shouldSelect := decider(index, val)
+               if shouldSelect == false {
+                       selected = append(selected, val)
+               }
+               return true
+       })
+
+       return &Value{data: selected}
+
+}
+
+// GroupInt32 uses the specified grouper function to group the items
+// keyed by the return of the grouper.  The object contained in the
+// result will contain a map[string][]int32.
+func (v *Value) GroupInt32(grouper func(int, int32) string) *Value {
+
+       groups := make(map[string][]int32)
+
+       v.EachInt32(func(index int, val int32) bool {
+               group := grouper(index, val)
+               if _, ok := groups[group]; !ok {
+                       groups[group] = make([]int32, 0)
+               }
+               groups[group] = append(groups[group], val)
+               return true
+       })
+
+       return &Value{data: groups}
+
+}
+
+// ReplaceInt32 uses the specified function to replace each int32s
+// by iterating each item.  The data in the returned result will be a
+// []int32 containing the replaced items.
+func (v *Value) ReplaceInt32(replacer func(int, int32) int32) *Value {
+
+       arr := v.MustInt32Slice()
+       replaced := make([]int32, len(arr))
+
+       v.EachInt32(func(index int, val int32) bool {
+               replaced[index] = replacer(index, val)
+               return true
+       })
+
+       return &Value{data: replaced}
+
+}
+
+// CollectInt32 uses the specified collector function to collect a value
+// for each of the int32s in the slice.  The data returned will be a
+// []interface{}.
+func (v *Value) CollectInt32(collector func(int, int32) interface{}) *Value {
+
+       arr := v.MustInt32Slice()
+       collected := make([]interface{}, len(arr))
+
+       v.EachInt32(func(index int, val int32) bool {
+               collected[index] = collector(index, val)
+               return true
+       })
+
+       return &Value{data: collected}
+}
+
+/*
+       Int64 (int64 and []int64)
+       --------------------------------------------------
+*/
+
+// Int64 gets the value as a int64, returns the optionalDefault
+// value or a system default object if the value is the wrong type.
+func (v *Value) Int64(optionalDefault ...int64) int64 {
+       if s, ok := v.data.(int64); ok {
+               return s
+       }
+       if len(optionalDefault) == 1 {
+               return optionalDefault[0]
+       }
+       return 0
+}
+
+// MustInt64 gets the value as a int64.
+//
+// Panics if the object is not a int64.
+func (v *Value) MustInt64() int64 {
+       return v.data.(int64)
+}
+
+// Int64Slice gets the value as a []int64, returns the optionalDefault
+// value or nil if the value is not a []int64.
+func (v *Value) Int64Slice(optionalDefault ...[]int64) []int64 {
+       if s, ok := v.data.([]int64); ok {
+               return s
+       }
+       if len(optionalDefault) == 1 {
+               return optionalDefault[0]
+       }
+       return nil
+}
+
+// MustInt64Slice gets the value as a []int64.
+//
+// Panics if the object is not a []int64.
+func (v *Value) MustInt64Slice() []int64 {
+       return v.data.([]int64)
+}
+
+// IsInt64 gets whether the object contained is a int64 or not.
+func (v *Value) IsInt64() bool {
+       _, ok := v.data.(int64)
+       return ok
+}
+
+// IsInt64Slice gets whether the object contained is a []int64 or not.
+func (v *Value) IsInt64Slice() bool {
+       _, ok := v.data.([]int64)
+       return ok
+}
+
+// EachInt64 calls the specified callback for each object
+// in the []int64.
+//
+// Panics if the object is the wrong type.
+func (v *Value) EachInt64(callback func(int, int64) bool) *Value {
+
+       for index, val := range v.MustInt64Slice() {
+               carryon := callback(index, val)
+               if carryon == false {
+                       break
+               }
+       }
+
+       return v
+
+}
+
+// WhereInt64 uses the specified decider function to select items
+// from the []int64.  The object contained in the result will contain
+// only the selected items.
+func (v *Value) WhereInt64(decider func(int, int64) bool) *Value {
+
+       var selected []int64
+
+       v.EachInt64(func(index int, val int64) bool {
+               shouldSelect := decider(index, val)
+               if shouldSelect == false {
+                       selected = append(selected, val)
+               }
+               return true
+       })
+
+       return &Value{data: selected}
+
+}
+
+// GroupInt64 uses the specified grouper function to group the items
+// keyed by the return of the grouper.  The object contained in the
+// result will contain a map[string][]int64.
+func (v *Value) GroupInt64(grouper func(int, int64) string) *Value {
+
+       groups := make(map[string][]int64)
+
+       v.EachInt64(func(index int, val int64) bool {
+               group := grouper(index, val)
+               if _, ok := groups[group]; !ok {
+                       groups[group] = make([]int64, 0)
+               }
+               groups[group] = append(groups[group], val)
+               return true
+       })
+
+       return &Value{data: groups}
+
+}
+
+// ReplaceInt64 uses the specified function to replace each int64s
+// by iterating each item.  The data in the returned result will be a
+// []int64 containing the replaced items.
+func (v *Value) ReplaceInt64(replacer func(int, int64) int64) *Value {
+
+       arr := v.MustInt64Slice()
+       replaced := make([]int64, len(arr))
+
+       v.EachInt64(func(index int, val int64) bool {
+               replaced[index] = replacer(index, val)
+               return true
+       })
+
+       return &Value{data: replaced}
+
+}
+
+// CollectInt64 uses the specified collector function to collect a value
+// for each of the int64s in the slice.  The data returned will be a
+// []interface{}.
+func (v *Value) CollectInt64(collector func(int, int64) interface{}) *Value {
+
+       arr := v.MustInt64Slice()
+       collected := make([]interface{}, len(arr))
+
+       v.EachInt64(func(index int, val int64) bool {
+               collected[index] = collector(index, val)
+               return true
+       })
+
+       return &Value{data: collected}
+}
+
+/*
+       Uint (uint and []uint)
+       --------------------------------------------------
+*/
+
+// Uint gets the value as a uint, returns the optionalDefault
+// value or a system default object if the value is the wrong type.
+func (v *Value) Uint(optionalDefault ...uint) uint {
+       if s, ok := v.data.(uint); ok {
+               return s
+       }
+       if len(optionalDefault) == 1 {
+               return optionalDefault[0]
+       }
+       return 0
+}
+
+// MustUint gets the value as a uint.
+//
+// Panics if the object is not a uint.
+func (v *Value) MustUint() uint {
+       return v.data.(uint)
+}
+
+// UintSlice gets the value as a []uint, returns the optionalDefault
+// value or nil if the value is not a []uint.
+func (v *Value) UintSlice(optionalDefault ...[]uint) []uint {
+       if s, ok := v.data.([]uint); ok {
+               return s
+       }
+       if len(optionalDefault) == 1 {
+               return optionalDefault[0]
+       }
+       return nil
+}
+
+// MustUintSlice gets the value as a []uint.
+//
+// Panics if the object is not a []uint.
+func (v *Value) MustUintSlice() []uint {
+       return v.data.([]uint)
+}
+
+// IsUint gets whether the object contained is a uint or not.
+func (v *Value) IsUint() bool {
+       _, ok := v.data.(uint)
+       return ok
+}
+
+// IsUintSlice gets whether the object contained is a []uint or not.
+func (v *Value) IsUintSlice() bool {
+       _, ok := v.data.([]uint)
+       return ok
+}
+
+// EachUint calls the specified callback for each object
+// in the []uint.
+//
+// Panics if the object is the wrong type.
+func (v *Value) EachUint(callback func(int, uint) bool) *Value {
+
+       for index, val := range v.MustUintSlice() {
+               carryon := callback(index, val)
+               if carryon == false {
+                       break
+               }
+       }
+
+       return v
+
+}
+
+// WhereUint uses the specified decider function to select items
+// from the []uint.  The object contained in the result will contain
+// only the selected items.
+func (v *Value) WhereUint(decider func(int, uint) bool) *Value {
+
+       var selected []uint
+
+       v.EachUint(func(index int, val uint) bool {
+               shouldSelect := decider(index, val)
+               if shouldSelect == false {
+                       selected = append(selected, val)
+               }
+               return true
+       })
+
+       return &Value{data: selected}
+
+}
+
+// GroupUint uses the specified grouper function to group the items
+// keyed by the return of the grouper.  The object contained in the
+// result will contain a map[string][]uint.
+func (v *Value) GroupUint(grouper func(int, uint) string) *Value {
+
+       groups := make(map[string][]uint)
+
+       v.EachUint(func(index int, val uint) bool {
+               group := grouper(index, val)
+               if _, ok := groups[group]; !ok {
+                       groups[group] = make([]uint, 0)
+               }
+               groups[group] = append(groups[group], val)
+               return true
+       })
+
+       return &Value{data: groups}
+
+}
+
+// ReplaceUint uses the specified function to replace each uints
+// by iterating each item.  The data in the returned result will be a
+// []uint containing the replaced items.
+func (v *Value) ReplaceUint(replacer func(int, uint) uint) *Value {
+
+       arr := v.MustUintSlice()
+       replaced := make([]uint, len(arr))
+
+       v.EachUint(func(index int, val uint) bool {
+               replaced[index] = replacer(index, val)
+               return true
+       })
+
+       return &Value{data: replaced}
+
+}
+
+// CollectUint uses the specified collector function to collect a value
+// for each of the uints in the slice.  The data returned will be a
+// []interface{}.
+func (v *Value) CollectUint(collector func(int, uint) interface{}) *Value {
+
+       arr := v.MustUintSlice()
+       collected := make([]interface{}, len(arr))
+
+       v.EachUint(func(index int, val uint) bool {
+               collected[index] = collector(index, val)
+               return true
+       })
+
+       return &Value{data: collected}
+}
+
+/*
+       Uint8 (uint8 and []uint8)
+       --------------------------------------------------
+*/
+
+// Uint8 gets the value as a uint8, returns the optionalDefault
+// value or a system default object if the value is the wrong type.
+func (v *Value) Uint8(optionalDefault ...uint8) uint8 {
+       if s, ok := v.data.(uint8); ok {
+               return s
+       }
+       if len(optionalDefault) == 1 {
+               return optionalDefault[0]
+       }
+       return 0
+}
+
+// MustUint8 gets the value as a uint8.
+//
+// Panics if the object is not a uint8.
+func (v *Value) MustUint8() uint8 {
+       return v.data.(uint8)
+}
+
+// Uint8Slice gets the value as a []uint8, returns the optionalDefault
+// value or nil if the value is not a []uint8.
+func (v *Value) Uint8Slice(optionalDefault ...[]uint8) []uint8 {
+       if s, ok := v.data.([]uint8); ok {
+               return s
+       }
+       if len(optionalDefault) == 1 {
+               return optionalDefault[0]
+       }
+       return nil
+}
+
+// MustUint8Slice gets the value as a []uint8.
+//
+// Panics if the object is not a []uint8.
+func (v *Value) MustUint8Slice() []uint8 {
+       return v.data.([]uint8)
+}
+
+// IsUint8 gets whether the object contained is a uint8 or not.
+func (v *Value) IsUint8() bool {
+       _, ok := v.data.(uint8)
+       return ok
+}
+
+// IsUint8Slice gets whether the object contained is a []uint8 or not.
+func (v *Value) IsUint8Slice() bool {
+       _, ok := v.data.([]uint8)
+       return ok
+}
+
+// EachUint8 calls the specified callback for each object
+// in the []uint8.
+//
+// Panics if the object is the wrong type.
+func (v *Value) EachUint8(callback func(int, uint8) bool) *Value {
+
+       for index, val := range v.MustUint8Slice() {
+               carryon := callback(index, val)
+               if carryon == false {
+                       break
+               }
+       }
+
+       return v
+
+}
+
+// WhereUint8 uses the specified decider function to select items
+// from the []uint8.  The object contained in the result will contain
+// only the selected items.
+func (v *Value) WhereUint8(decider func(int, uint8) bool) *Value {
+
+       var selected []uint8
+
+       v.EachUint8(func(index int, val uint8) bool {
+               shouldSelect := decider(index, val)
+               if shouldSelect == false {
+                       selected = append(selected, val)
+               }
+               return true
+       })
+
+       return &Value{data: selected}
+
+}
+
+// GroupUint8 uses the specified grouper function to group the items
+// keyed by the return of the grouper.  The object contained in the
+// result will contain a map[string][]uint8.
+func (v *Value) GroupUint8(grouper func(int, uint8) string) *Value {
+
+       groups := make(map[string][]uint8)
+
+       v.EachUint8(func(index int, val uint8) bool {
+               group := grouper(index, val)
+               if _, ok := groups[group]; !ok {
+                       groups[group] = make([]uint8, 0)
+               }
+               groups[group] = append(groups[group], val)
+               return true
+       })
+
+       return &Value{data: groups}
+
+}
+
+// ReplaceUint8 uses the specified function to replace each uint8s
+// by iterating each item.  The data in the returned result will be a
+// []uint8 containing the replaced items.
+func (v *Value) ReplaceUint8(replacer func(int, uint8) uint8) *Value {
+
+       arr := v.MustUint8Slice()
+       replaced := make([]uint8, len(arr))
+
+       v.EachUint8(func(index int, val uint8) bool {
+               replaced[index] = replacer(index, val)
+               return true
+       })
+
+       return &Value{data: replaced}
+
+}
+
+// CollectUint8 uses the specified collector function to collect a value
+// for each of the uint8s in the slice.  The data returned will be a
+// []interface{}.
+func (v *Value) CollectUint8(collector func(int, uint8) interface{}) *Value {
+
+       arr := v.MustUint8Slice()
+       collected := make([]interface{}, len(arr))
+
+       v.EachUint8(func(index int, val uint8) bool {
+               collected[index] = collector(index, val)
+               return true
+       })
+
+       return &Value{data: collected}
+}
+
+/*
+       Uint16 (uint16 and []uint16)
+       --------------------------------------------------
+*/
+
+// Uint16 gets the value as a uint16, returns the optionalDefault
+// value or a system default object if the value is the wrong type.
+func (v *Value) Uint16(optionalDefault ...uint16) uint16 {
+       if s, ok := v.data.(uint16); ok {
+               return s
+       }
+       if len(optionalDefault) == 1 {
+               return optionalDefault[0]
+       }
+       return 0
+}
+
+// MustUint16 gets the value as a uint16.
+//
+// Panics if the object is not a uint16.
+func (v *Value) MustUint16() uint16 {
+       return v.data.(uint16)
+}
+
+// Uint16Slice gets the value as a []uint16, returns the optionalDefault
+// value or nil if the value is not a []uint16.
+func (v *Value) Uint16Slice(optionalDefault ...[]uint16) []uint16 {
+       if s, ok := v.data.([]uint16); ok {
+               return s
+       }
+       if len(optionalDefault) == 1 {
+               return optionalDefault[0]
+       }
+       return nil
+}
+
+// MustUint16Slice gets the value as a []uint16.
+//
+// Panics if the object is not a []uint16.
+func (v *Value) MustUint16Slice() []uint16 {
+       return v.data.([]uint16)
+}
+
+// IsUint16 gets whether the object contained is a uint16 or not.
+func (v *Value) IsUint16() bool {
+       _, ok := v.data.(uint16)
+       return ok
+}
+
+// IsUint16Slice gets whether the object contained is a []uint16 or not.
+func (v *Value) IsUint16Slice() bool {
+       _, ok := v.data.([]uint16)
+       return ok
+}
+
+// EachUint16 calls the specified callback for each object
+// in the []uint16.
+//
+// Panics if the object is the wrong type.
+func (v *Value) EachUint16(callback func(int, uint16) bool) *Value {
+
+       for index, val := range v.MustUint16Slice() {
+               carryon := callback(index, val)
+               if carryon == false {
+                       break
+               }
+       }
+
+       return v
+
+}
+
+// WhereUint16 uses the specified decider function to select items
+// from the []uint16.  The object contained in the result will contain
+// only the selected items.
+func (v *Value) WhereUint16(decider func(int, uint16) bool) *Value {
+
+       var selected []uint16
+
+       v.EachUint16(func(index int, val uint16) bool {
+               shouldSelect := decider(index, val)
+               if shouldSelect == false {
+                       selected = append(selected, val)
+               }
+               return true
+       })
+
+       return &Value{data: selected}
+
+}
+
+// GroupUint16 uses the specified grouper function to group the items
+// keyed by the return of the grouper.  The object contained in the
+// result will contain a map[string][]uint16.
+func (v *Value) GroupUint16(grouper func(int, uint16) string) *Value {
+
+       groups := make(map[string][]uint16)
+
+       v.EachUint16(func(index int, val uint16) bool {
+               group := grouper(index, val)
+               if _, ok := groups[group]; !ok {
+                       groups[group] = make([]uint16, 0)
+               }
+               groups[group] = append(groups[group], val)
+               return true
+       })
+
+       return &Value{data: groups}
+
+}
+
+// ReplaceUint16 uses the specified function to replace each uint16s
+// by iterating each item.  The data in the returned result will be a
+// []uint16 containing the replaced items.
+func (v *Value) ReplaceUint16(replacer func(int, uint16) uint16) *Value {
+
+       arr := v.MustUint16Slice()
+       replaced := make([]uint16, len(arr))
+
+       v.EachUint16(func(index int, val uint16) bool {
+               replaced[index] = replacer(index, val)
+               return true
+       })
+
+       return &Value{data: replaced}
+
+}
+
+// CollectUint16 uses the specified collector function to collect a value
+// for each of the uint16s in the slice.  The data returned will be a
+// []interface{}.
+func (v *Value) CollectUint16(collector func(int, uint16) interface{}) *Value {
+
+       arr := v.MustUint16Slice()
+       collected := make([]interface{}, len(arr))
+
+       v.EachUint16(func(index int, val uint16) bool {
+               collected[index] = collector(index, val)
+               return true
+       })
+
+       return &Value{data: collected}
+}
+
+/*
+       Uint32 (uint32 and []uint32)
+       --------------------------------------------------
+*/
+
+// Uint32 gets the value as a uint32, returns the optionalDefault
+// value or a system default object if the value is the wrong type.
+func (v *Value) Uint32(optionalDefault ...uint32) uint32 {
+       if s, ok := v.data.(uint32); ok {
+               return s
+       }
+       if len(optionalDefault) == 1 {
+               return optionalDefault[0]
+       }
+       return 0
+}
+
+// MustUint32 gets the value as a uint32.
+//
+// Panics if the object is not a uint32.
+func (v *Value) MustUint32() uint32 {
+       return v.data.(uint32)
+}
+
+// Uint32Slice gets the value as a []uint32, returns the optionalDefault
+// value or nil if the value is not a []uint32.
+func (v *Value) Uint32Slice(optionalDefault ...[]uint32) []uint32 {
+       if s, ok := v.data.([]uint32); ok {
+               return s
+       }
+       if len(optionalDefault) == 1 {
+               return optionalDefault[0]
+       }
+       return nil
+}
+
+// MustUint32Slice gets the value as a []uint32.
+//
+// Panics if the object is not a []uint32.
+func (v *Value) MustUint32Slice() []uint32 {
+       return v.data.([]uint32)
+}
+
+// IsUint32 gets whether the object contained is a uint32 or not.
+func (v *Value) IsUint32() bool {
+       _, ok := v.data.(uint32)
+       return ok
+}
+
+// IsUint32Slice gets whether the object contained is a []uint32 or not.
+func (v *Value) IsUint32Slice() bool {
+       _, ok := v.data.([]uint32)
+       return ok
+}
+
+// EachUint32 calls the specified callback for each object
+// in the []uint32.
+//
+// Panics if the object is the wrong type.
+func (v *Value) EachUint32(callback func(int, uint32) bool) *Value {
+
+       for index, val := range v.MustUint32Slice() {
+               carryon := callback(index, val)
+               if carryon == false {
+                       break
+               }
+       }
+
+       return v
+
+}
+
+// WhereUint32 uses the specified decider function to select items
+// from the []uint32.  The object contained in the result will contain
+// only the selected items.
+func (v *Value) WhereUint32(decider func(int, uint32) bool) *Value {
+
+       var selected []uint32
+
+       v.EachUint32(func(index int, val uint32) bool {
+               shouldSelect := decider(index, val)
+               if shouldSelect == false {
+                       selected = append(selected, val)
+               }
+               return true
+       })
+
+       return &Value{data: selected}
+
+}
+
+// GroupUint32 uses the specified grouper function to group the items
+// keyed by the return of the grouper.  The object contained in the
+// result will contain a map[string][]uint32.
+func (v *Value) GroupUint32(grouper func(int, uint32) string) *Value {
+
+       groups := make(map[string][]uint32)
+
+       v.EachUint32(func(index int, val uint32) bool {
+               group := grouper(index, val)
+               if _, ok := groups[group]; !ok {
+                       groups[group] = make([]uint32, 0)
+               }
+               groups[group] = append(groups[group], val)
+               return true
+       })
+
+       return &Value{data: groups}
+
+}
+
+// ReplaceUint32 uses the specified function to replace each uint32s
+// by iterating each item.  The data in the returned result will be a
+// []uint32 containing the replaced items.
+func (v *Value) ReplaceUint32(replacer func(int, uint32) uint32) *Value {
+
+       arr := v.MustUint32Slice()
+       replaced := make([]uint32, len(arr))
+
+       v.EachUint32(func(index int, val uint32) bool {
+               replaced[index] = replacer(index, val)
+               return true
+       })
+
+       return &Value{data: replaced}
+
+}
+
+// CollectUint32 uses the specified collector function to collect a value
+// for each of the uint32s in the slice.  The data returned will be a
+// []interface{}.
+func (v *Value) CollectUint32(collector func(int, uint32) interface{}) *Value {
+
+       arr := v.MustUint32Slice()
+       collected := make([]interface{}, len(arr))
+
+       v.EachUint32(func(index int, val uint32) bool {
+               collected[index] = collector(index, val)
+               return true
+       })
+
+       return &Value{data: collected}
+}
+
+/*
+       Uint64 (uint64 and []uint64)
+       --------------------------------------------------
+*/
+
+// Uint64 gets the value as a uint64, returns the optionalDefault
+// value or a system default object if the value is the wrong type.
+func (v *Value) Uint64(optionalDefault ...uint64) uint64 {
+       if s, ok := v.data.(uint64); ok {
+               return s
+       }
+       if len(optionalDefault) == 1 {
+               return optionalDefault[0]
+       }
+       return 0
+}
+
+// MustUint64 gets the value as a uint64.
+//
+// Panics if the object is not a uint64.
+func (v *Value) MustUint64() uint64 {
+       return v.data.(uint64)
+}
+
+// Uint64Slice gets the value as a []uint64, returns the optionalDefault
+// value or nil if the value is not a []uint64.
+func (v *Value) Uint64Slice(optionalDefault ...[]uint64) []uint64 {
+       if s, ok := v.data.([]uint64); ok {
+               return s
+       }
+       if len(optionalDefault) == 1 {
+               return optionalDefault[0]
+       }
+       return nil
+}
+
+// MustUint64Slice gets the value as a []uint64.
+//
+// Panics if the object is not a []uint64.
+func (v *Value) MustUint64Slice() []uint64 {
+       return v.data.([]uint64)
+}
+
+// IsUint64 gets whether the object contained is a uint64 or not.
+func (v *Value) IsUint64() bool {
+       _, ok := v.data.(uint64)
+       return ok
+}
+
+// IsUint64Slice gets whether the object contained is a []uint64 or not.
+func (v *Value) IsUint64Slice() bool {
+       _, ok := v.data.([]uint64)
+       return ok
+}
+
+// EachUint64 calls the specified callback for each object
+// in the []uint64.
+//
+// Panics if the object is the wrong type.
+func (v *Value) EachUint64(callback func(int, uint64) bool) *Value {
+
+       for index, val := range v.MustUint64Slice() {
+               carryon := callback(index, val)
+               if carryon == false {
+                       break
+               }
+       }
+
+       return v
+
+}
+
+// WhereUint64 uses the specified decider function to select items
+// from the []uint64.  The object contained in the result will contain
+// only the selected items.
+func (v *Value) WhereUint64(decider func(int, uint64) bool) *Value {
+
+       var selected []uint64
+
+       v.EachUint64(func(index int, val uint64) bool {
+               shouldSelect := decider(index, val)
+               if shouldSelect == false {
+                       selected = append(selected, val)
+               }
+               return true
+       })
+
+       return &Value{data: selected}
+
+}
+
+// GroupUint64 uses the specified grouper function to group the items
+// keyed by the return of the grouper.  The object contained in the
+// result will contain a map[string][]uint64.
+func (v *Value) GroupUint64(grouper func(int, uint64) string) *Value {
+
+       groups := make(map[string][]uint64)
+
+       v.EachUint64(func(index int, val uint64) bool {
+               group := grouper(index, val)
+               if _, ok := groups[group]; !ok {
+                       groups[group] = make([]uint64, 0)
+               }
+               groups[group] = append(groups[group], val)
+               return true
+       })
+
+       return &Value{data: groups}
+
+}
+
+// ReplaceUint64 uses the specified function to replace each uint64s
+// by iterating each item.  The data in the returned result will be a
+// []uint64 containing the replaced items.
+func (v *Value) ReplaceUint64(replacer func(int, uint64) uint64) *Value {
+
+       arr := v.MustUint64Slice()
+       replaced := make([]uint64, len(arr))
+
+       v.EachUint64(func(index int, val uint64) bool {
+               replaced[index] = replacer(index, val)
+               return true
+       })
+
+       return &Value{data: replaced}
+
+}
+
+// CollectUint64 uses the specified collector function to collect a value
+// for each of the uint64s in the slice.  The data returned will be a
+// []interface{}.
+func (v *Value) CollectUint64(collector func(int, uint64) interface{}) *Value {
+
+       arr := v.MustUint64Slice()
+       collected := make([]interface{}, len(arr))
+
+       v.EachUint64(func(index int, val uint64) bool {
+               collected[index] = collector(index, val)
+               return true
+       })
+
+       return &Value{data: collected}
+}
+
+/*
+       Uintptr (uintptr and []uintptr)
+       --------------------------------------------------
+*/
+
+// Uintptr gets the value as a uintptr, returns the optionalDefault
+// value or a system default object if the value is the wrong type.
+func (v *Value) Uintptr(optionalDefault ...uintptr) uintptr {
+       if s, ok := v.data.(uintptr); ok {
+               return s
+       }
+       if len(optionalDefault) == 1 {
+               return optionalDefault[0]
+       }
+       return 0
+}
+
+// MustUintptr gets the value as a uintptr.
+//
+// Panics if the object is not a uintptr.
+func (v *Value) MustUintptr() uintptr {
+       return v.data.(uintptr)
+}
+
+// UintptrSlice gets the value as a []uintptr, returns the optionalDefault
+// value or nil if the value is not a []uintptr.
+func (v *Value) UintptrSlice(optionalDefault ...[]uintptr) []uintptr {
+       if s, ok := v.data.([]uintptr); ok {
+               return s
+       }
+       if len(optionalDefault) == 1 {
+               return optionalDefault[0]
+       }
+       return nil
+}
+
+// MustUintptrSlice gets the value as a []uintptr.
+//
+// Panics if the object is not a []uintptr.
+func (v *Value) MustUintptrSlice() []uintptr {
+       return v.data.([]uintptr)
+}
+
+// IsUintptr gets whether the object contained is a uintptr or not.
+func (v *Value) IsUintptr() bool {
+       _, ok := v.data.(uintptr)
+       return ok
+}
+
+// IsUintptrSlice gets whether the object contained is a []uintptr or not.
+func (v *Value) IsUintptrSlice() bool {
+       _, ok := v.data.([]uintptr)
+       return ok
+}
+
+// EachUintptr calls the specified callback for each object
+// in the []uintptr.
+//
+// Panics if the object is the wrong type.
+func (v *Value) EachUintptr(callback func(int, uintptr) bool) *Value {
+
+       for index, val := range v.MustUintptrSlice() {
+               carryon := callback(index, val)
+               if carryon == false {
+                       break
+               }
+       }
+
+       return v
+
+}
+
+// WhereUintptr uses the specified decider function to select items
+// from the []uintptr.  The object contained in the result will contain
+// only the selected items.
+func (v *Value) WhereUintptr(decider func(int, uintptr) bool) *Value {
+
+       var selected []uintptr
+
+       v.EachUintptr(func(index int, val uintptr) bool {
+               shouldSelect := decider(index, val)
+               if shouldSelect == false {
+                       selected = append(selected, val)
+               }
+               return true
+       })
+
+       return &Value{data: selected}
+
+}
+
+// GroupUintptr uses the specified grouper function to group the items
+// keyed by the return of the grouper.  The object contained in the
+// result will contain a map[string][]uintptr.
+func (v *Value) GroupUintptr(grouper func(int, uintptr) string) *Value {
+
+       groups := make(map[string][]uintptr)
+
+       v.EachUintptr(func(index int, val uintptr) bool {
+               group := grouper(index, val)
+               if _, ok := groups[group]; !ok {
+                       groups[group] = make([]uintptr, 0)
+               }
+               groups[group] = append(groups[group], val)
+               return true
+       })
+
+       return &Value{data: groups}
+
+}
+
+// ReplaceUintptr uses the specified function to replace each uintptrs
+// by iterating each item.  The data in the returned result will be a
+// []uintptr containing the replaced items.
+func (v *Value) ReplaceUintptr(replacer func(int, uintptr) uintptr) *Value {
+
+       arr := v.MustUintptrSlice()
+       replaced := make([]uintptr, len(arr))
+
+       v.EachUintptr(func(index int, val uintptr) bool {
+               replaced[index] = replacer(index, val)
+               return true
+       })
+
+       return &Value{data: replaced}
+
+}
+
+// CollectUintptr uses the specified collector function to collect a value
+// for each of the uintptrs in the slice.  The data returned will be a
+// []interface{}.
+func (v *Value) CollectUintptr(collector func(int, uintptr) interface{}) *Value {
+
+       arr := v.MustUintptrSlice()
+       collected := make([]interface{}, len(arr))
+
+       v.EachUintptr(func(index int, val uintptr) bool {
+               collected[index] = collector(index, val)
+               return true
+       })
+
+       return &Value{data: collected}
+}
+
+/*
+       Float32 (float32 and []float32)
+       --------------------------------------------------
+*/
+
+// Float32 gets the value as a float32, returns the optionalDefault
+// value or a system default object if the value is the wrong type.
+func (v *Value) Float32(optionalDefault ...float32) float32 {
+       if s, ok := v.data.(float32); ok {
+               return s
+       }
+       if len(optionalDefault) == 1 {
+               return optionalDefault[0]
+       }
+       return 0
+}
+
+// MustFloat32 gets the value as a float32.
+//
+// Panics if the object is not a float32.
+func (v *Value) MustFloat32() float32 {
+       return v.data.(float32)
+}
+
+// Float32Slice gets the value as a []float32, returns the optionalDefault
+// value or nil if the value is not a []float32.
+func (v *Value) Float32Slice(optionalDefault ...[]float32) []float32 {
+       if s, ok := v.data.([]float32); ok {
+               return s
+       }
+       if len(optionalDefault) == 1 {
+               return optionalDefault[0]
+       }
+       return nil
+}
+
+// MustFloat32Slice gets the value as a []float32.
+//
+// Panics if the object is not a []float32.
+func (v *Value) MustFloat32Slice() []float32 {
+       return v.data.([]float32)
+}
+
+// IsFloat32 gets whether the object contained is a float32 or not.
+func (v *Value) IsFloat32() bool {
+       _, ok := v.data.(float32)
+       return ok
+}
+
+// IsFloat32Slice gets whether the object contained is a []float32 or not.
+func (v *Value) IsFloat32Slice() bool {
+       _, ok := v.data.([]float32)
+       return ok
+}
+
+// EachFloat32 calls the specified callback for each object
+// in the []float32.
+//
+// Panics if the object is the wrong type.
+func (v *Value) EachFloat32(callback func(int, float32) bool) *Value {
+
+       for index, val := range v.MustFloat32Slice() {
+               carryon := callback(index, val)
+               if carryon == false {
+                       break
+               }
+       }
+
+       return v
+
+}
+
+// WhereFloat32 uses the specified decider function to select items
+// from the []float32.  The object contained in the result will contain
+// only the selected items.
+func (v *Value) WhereFloat32(decider func(int, float32) bool) *Value {
+
+       var selected []float32
+
+       v.EachFloat32(func(index int, val float32) bool {
+               shouldSelect := decider(index, val)
+               if shouldSelect == false {
+                       selected = append(selected, val)
+               }
+               return true
+       })
+
+       return &Value{data: selected}
+
+}
+
+// GroupFloat32 uses the specified grouper function to group the items
+// keyed by the return of the grouper.  The object contained in the
+// result will contain a map[string][]float32.
+func (v *Value) GroupFloat32(grouper func(int, float32) string) *Value {
+
+       groups := make(map[string][]float32)
+
+       v.EachFloat32(func(index int, val float32) bool {
+               group := grouper(index, val)
+               if _, ok := groups[group]; !ok {
+                       groups[group] = make([]float32, 0)
+               }
+               groups[group] = append(groups[group], val)
+               return true
+       })
+
+       return &Value{data: groups}
+
+}
+
+// ReplaceFloat32 uses the specified function to replace each float32s
+// by iterating each item.  The data in the returned result will be a
+// []float32 containing the replaced items.
+func (v *Value) ReplaceFloat32(replacer func(int, float32) float32) *Value {
+
+       arr := v.MustFloat32Slice()
+       replaced := make([]float32, len(arr))
+
+       v.EachFloat32(func(index int, val float32) bool {
+               replaced[index] = replacer(index, val)
+               return true
+       })
+
+       return &Value{data: replaced}
+
+}
+
+// CollectFloat32 uses the specified collector function to collect a value
+// for each of the float32s in the slice.  The data returned will be a
+// []interface{}.
+func (v *Value) CollectFloat32(collector func(int, float32) interface{}) *Value {
+
+       arr := v.MustFloat32Slice()
+       collected := make([]interface{}, len(arr))
+
+       v.EachFloat32(func(index int, val float32) bool {
+               collected[index] = collector(index, val)
+               return true
+       })
+
+       return &Value{data: collected}
+}
+
+/*
+       Float64 (float64 and []float64)
+       --------------------------------------------------
+*/
+
+// Float64 gets the value as a float64, returns the optionalDefault
+// value or a system default object if the value is the wrong type.
+func (v *Value) Float64(optionalDefault ...float64) float64 {
+       if s, ok := v.data.(float64); ok {
+               return s
+       }
+       if len(optionalDefault) == 1 {
+               return optionalDefault[0]
+       }
+       return 0
+}
+
+// MustFloat64 gets the value as a float64.
+//
+// Panics if the object is not a float64.
+func (v *Value) MustFloat64() float64 {
+       return v.data.(float64)
+}
+
+// Float64Slice gets the value as a []float64, returns the optionalDefault
+// value or nil if the value is not a []float64.
+func (v *Value) Float64Slice(optionalDefault ...[]float64) []float64 {
+       if s, ok := v.data.([]float64); ok {
+               return s
+       }
+       if len(optionalDefault) == 1 {
+               return optionalDefault[0]
+       }
+       return nil
+}
+
+// MustFloat64Slice gets the value as a []float64.
+//
+// Panics if the object is not a []float64.
+func (v *Value) MustFloat64Slice() []float64 {
+       return v.data.([]float64)
+}
+
+// IsFloat64 gets whether the object contained is a float64 or not.
+func (v *Value) IsFloat64() bool {
+       _, ok := v.data.(float64)
+       return ok
+}
+
+// IsFloat64Slice gets whether the object contained is a []float64 or not.
+func (v *Value) IsFloat64Slice() bool {
+       _, ok := v.data.([]float64)
+       return ok
+}
+
+// EachFloat64 calls the specified callback for each object
+// in the []float64.
+//
+// Panics if the object is the wrong type.
+func (v *Value) EachFloat64(callback func(int, float64) bool) *Value {
+
+       for index, val := range v.MustFloat64Slice() {
+               carryon := callback(index, val)
+               if carryon == false {
+                       break
+               }
+       }
+
+       return v
+
+}
+
+// WhereFloat64 uses the specified decider function to select items
+// from the []float64.  The object contained in the result will contain
+// only the selected items.
+func (v *Value) WhereFloat64(decider func(int, float64) bool) *Value {
+
+       var selected []float64
+
+       v.EachFloat64(func(index int, val float64) bool {
+               shouldSelect := decider(index, val)
+               if shouldSelect == false {
+                       selected = append(selected, val)
+               }
+               return true
+       })
+
+       return &Value{data: selected}
+
+}
+
+// GroupFloat64 uses the specified grouper function to group the items
+// keyed by the return of the grouper.  The object contained in the
+// result will contain a map[string][]float64.
+func (v *Value) GroupFloat64(grouper func(int, float64) string) *Value {
+
+       groups := make(map[string][]float64)
+
+       v.EachFloat64(func(index int, val float64) bool {
+               group := grouper(index, val)
+               if _, ok := groups[group]; !ok {
+                       groups[group] = make([]float64, 0)
+               }
+               groups[group] = append(groups[group], val)
+               return true
+       })
+
+       return &Value{data: groups}
+
+}
+
+// ReplaceFloat64 uses the specified function to replace each float64s
+// by iterating each item.  The data in the returned result will be a
+// []float64 containing the replaced items.
+func (v *Value) ReplaceFloat64(replacer func(int, float64) float64) *Value {
+
+       arr := v.MustFloat64Slice()
+       replaced := make([]float64, len(arr))
+
+       v.EachFloat64(func(index int, val float64) bool {
+               replaced[index] = replacer(index, val)
+               return true
+       })
+
+       return &Value{data: replaced}
+
+}
+
+// CollectFloat64 uses the specified collector function to collect a value
+// for each of the float64s in the slice.  The data returned will be a
+// []interface{}.
+func (v *Value) CollectFloat64(collector func(int, float64) interface{}) *Value {
+
+       arr := v.MustFloat64Slice()
+       collected := make([]interface{}, len(arr))
+
+       v.EachFloat64(func(index int, val float64) bool {
+               collected[index] = collector(index, val)
+               return true
+       })
+
+       return &Value{data: collected}
+}
+
+/*
+       Complex64 (complex64 and []complex64)
+       --------------------------------------------------
+*/
+
+// Complex64 gets the value as a complex64, returns the optionalDefault
+// value or a system default object if the value is the wrong type.
+func (v *Value) Complex64(optionalDefault ...complex64) complex64 {
+       if s, ok := v.data.(complex64); ok {
+               return s
+       }
+       if len(optionalDefault) == 1 {
+               return optionalDefault[0]
+       }
+       return 0
+}
+
+// MustComplex64 gets the value as a complex64.
+//
+// Panics if the object is not a complex64.
+func (v *Value) MustComplex64() complex64 {
+       return v.data.(complex64)
+}
+
+// Complex64Slice gets the value as a []complex64, returns the optionalDefault
+// value or nil if the value is not a []complex64.
+func (v *Value) Complex64Slice(optionalDefault ...[]complex64) []complex64 {
+       if s, ok := v.data.([]complex64); ok {
+               return s
+       }
+       if len(optionalDefault) == 1 {
+               return optionalDefault[0]
+       }
+       return nil
+}
+
+// MustComplex64Slice gets the value as a []complex64.
+//
+// Panics if the object is not a []complex64.
+func (v *Value) MustComplex64Slice() []complex64 {
+       return v.data.([]complex64)
+}
+
+// IsComplex64 gets whether the object contained is a complex64 or not.
+func (v *Value) IsComplex64() bool {
+       _, ok := v.data.(complex64)
+       return ok
+}
+
+// IsComplex64Slice gets whether the object contained is a []complex64 or not.
+func (v *Value) IsComplex64Slice() bool {
+       _, ok := v.data.([]complex64)
+       return ok
+}
+
+// EachComplex64 calls the specified callback for each object
+// in the []complex64.
+//
+// Panics if the object is the wrong type.
+func (v *Value) EachComplex64(callback func(int, complex64) bool) *Value {
+
+       for index, val := range v.MustComplex64Slice() {
+               carryon := callback(index, val)
+               if carryon == false {
+                       break
+               }
+       }
+
+       return v
+
+}
+
+// WhereComplex64 uses the specified decider function to select items
+// from the []complex64.  The object contained in the result will contain
+// only the selected items.
+func (v *Value) WhereComplex64(decider func(int, complex64) bool) *Value {
+
+       var selected []complex64
+
+       v.EachComplex64(func(index int, val complex64) bool {
+               shouldSelect := decider(index, val)
+               if shouldSelect == false {
+                       selected = append(selected, val)
+               }
+               return true
+       })
+
+       return &Value{data: selected}
+
+}
+
+// GroupComplex64 uses the specified grouper function to group the items
+// keyed by the return of the grouper.  The object contained in the
+// result will contain a map[string][]complex64.
+func (v *Value) GroupComplex64(grouper func(int, complex64) string) *Value {
+
+       groups := make(map[string][]complex64)
+
+       v.EachComplex64(func(index int, val complex64) bool {
+               group := grouper(index, val)
+               if _, ok := groups[group]; !ok {
+                       groups[group] = make([]complex64, 0)
+               }
+               groups[group] = append(groups[group], val)
+               return true
+       })
+
+       return &Value{data: groups}
+
+}
+
+// ReplaceComplex64 uses the specified function to replace each complex64s
+// by iterating each item.  The data in the returned result will be a
+// []complex64 containing the replaced items.
+func (v *Value) ReplaceComplex64(replacer func(int, complex64) complex64) *Value {
+
+       arr := v.MustComplex64Slice()
+       replaced := make([]complex64, len(arr))
+
+       v.EachComplex64(func(index int, val complex64) bool {
+               replaced[index] = replacer(index, val)
+               return true
+       })
+
+       return &Value{data: replaced}
+
+}
+
+// CollectComplex64 uses the specified collector function to collect a value
+// for each of the complex64s in the slice.  The data returned will be a
+// []interface{}.
+func (v *Value) CollectComplex64(collector func(int, complex64) interface{}) *Value {
+
+       arr := v.MustComplex64Slice()
+       collected := make([]interface{}, len(arr))
+
+       v.EachComplex64(func(index int, val complex64) bool {
+               collected[index] = collector(index, val)
+               return true
+       })
+
+       return &Value{data: collected}
+}
+
+/*
+       Complex128 (complex128 and []complex128)
+       --------------------------------------------------
+*/
+
+// Complex128 gets the value as a complex128, returns the optionalDefault
+// value or a system default object if the value is the wrong type.
+func (v *Value) Complex128(optionalDefault ...complex128) complex128 {
+       if s, ok := v.data.(complex128); ok {
+               return s
+       }
+       if len(optionalDefault) == 1 {
+               return optionalDefault[0]
+       }
+       return 0
+}
+
+// MustComplex128 gets the value as a complex128.
+//
+// Panics if the object is not a complex128.
+func (v *Value) MustComplex128() complex128 {
+       return v.data.(complex128)
+}
+
+// Complex128Slice gets the value as a []complex128, returns the optionalDefault
+// value or nil if the value is not a []complex128.
+func (v *Value) Complex128Slice(optionalDefault ...[]complex128) []complex128 {
+       if s, ok := v.data.([]complex128); ok {
+               return s
+       }
+       if len(optionalDefault) == 1 {
+               return optionalDefault[0]
+       }
+       return nil
+}
+
+// MustComplex128Slice gets the value as a []complex128.
+//
+// Panics if the object is not a []complex128.
+func (v *Value) MustComplex128Slice() []complex128 {
+       return v.data.([]complex128)
+}
+
+// IsComplex128 gets whether the object contained is a complex128 or not.
+func (v *Value) IsComplex128() bool {
+       _, ok := v.data.(complex128)
+       return ok
+}
+
+// IsComplex128Slice gets whether the object contained is a []complex128 or not.
+func (v *Value) IsComplex128Slice() bool {
+       _, ok := v.data.([]complex128)
+       return ok
+}
+
+// EachComplex128 calls the specified callback for each object
+// in the []complex128.
+//
+// Panics if the object is the wrong type.
+func (v *Value) EachComplex128(callback func(int, complex128) bool) *Value {
+
+       for index, val := range v.MustComplex128Slice() {
+               carryon := callback(index, val)
+               if carryon == false {
+                       break
+               }
+       }
+
+       return v
+
+}
+
+// WhereComplex128 uses the specified decider function to select items
+// from the []complex128.  The object contained in the result will contain
+// only the selected items.
+func (v *Value) WhereComplex128(decider func(int, complex128) bool) *Value {
+
+       var selected []complex128
+
+       v.EachComplex128(func(index int, val complex128) bool {
+               shouldSelect := decider(index, val)
+               if shouldSelect == false {
+                       selected = append(selected, val)
+               }
+               return true
+       })
+
+       return &Value{data: selected}
+
+}
+
+// GroupComplex128 uses the specified grouper function to group the items
+// keyed by the return of the grouper.  The object contained in the
+// result will contain a map[string][]complex128.
+func (v *Value) GroupComplex128(grouper func(int, complex128) string) *Value {
+
+       groups := make(map[string][]complex128)
+
+       v.EachComplex128(func(index int, val complex128) bool {
+               group := grouper(index, val)
+               if _, ok := groups[group]; !ok {
+                       groups[group] = make([]complex128, 0)
+               }
+               groups[group] = append(groups[group], val)
+               return true
+       })
+
+       return &Value{data: groups}
+
+}
+
+// ReplaceComplex128 uses the specified function to replace each complex128s
+// by iterating each item.  The data in the returned result will be a
+// []complex128 containing the replaced items.
+func (v *Value) ReplaceComplex128(replacer func(int, complex128) complex128) *Value {
+
+       arr := v.MustComplex128Slice()
+       replaced := make([]complex128, len(arr))
+
+       v.EachComplex128(func(index int, val complex128) bool {
+               replaced[index] = replacer(index, val)
+               return true
+       })
+
+       return &Value{data: replaced}
+
+}
+
+// CollectComplex128 uses the specified collector function to collect a value
+// for each of the complex128s in the slice.  The data returned will be a
+// []interface{}.
+func (v *Value) CollectComplex128(collector func(int, complex128) interface{}) *Value {
+
+       arr := v.MustComplex128Slice()
+       collected := make([]interface{}, len(arr))
+
+       v.EachComplex128(func(index int, val complex128) bool {
+               collected[index] = collector(index, val)
+               return true
+       })
+
+       return &Value{data: collected}
+}
diff --git a/vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/vendor/github.com/stretchr/objx/value.go b/vendor/github.com/git-lfs/gitobj/vendor/github.com/stretchr/testify/vendor/github.com/stretchr/objx/value.go
new file mode 100644 (file)
index 0000000..7aaef06
--- /dev/null
@@ -0,0 +1,13 @@
+package objx
+
+// Value provides methods for extracting interface{} data in various
+// types.
+type Value struct {
+       // data contains the raw data being managed by this Value
+       data interface{}
+}
+
+// Data returns the raw data contained by this Value
+func (v *Value) Data() interface{} {
+       return v.data
+}
index e0bfd24..27f650c 100644 (file)
@@ -2,6 +2,7 @@ package wildmatch
 
 import (
        "fmt"
+       "path/filepath"
        "strings"
        "unicode"
        "unicode/utf8"
@@ -11,6 +12,16 @@ import (
 type opt func(w *Wildmatch)
 
 var (
+       // Basename allows the receiving Wildmatch to match paths where the
+       // pattern matches only the basename of the path when the pattern does
+       // not contain directory separators.
+       //
+       // If the pattern contains directory separators, or if this option is
+       // not given, the entire path will be matched.
+       Basename opt = func(w *Wildmatch) {
+               w.basename = true
+       }
+
        // CaseFold allows the receiving Wildmatch to match paths with
        // different case structuring as in the pattern.
        CaseFold opt = func(w *Wildmatch) {
@@ -37,6 +48,10 @@ type Wildmatch struct {
        // p is the raw pattern used to derive the token set.
        p string
 
+       // basename indicates that this Wildmatch instance matches basenames
+       // when possible (i.e., when there are no directory separators in the
+       // pattern).
+       basename bool
        // caseFold allows the instance Wildmatch to match patterns with the
        // same character but different case structures.
        caseFold bool
@@ -59,7 +74,11 @@ func NewWildmatch(p string, opts ...opt) *Wildmatch {
                w.p = strings.ToLower(w.p)
        }
 
-       w.ts = parseTokens(strings.Split(w.p, string(sep)))
+       parts := strings.Split(w.p, string(sep))
+       if len(parts) > 1 {
+               w.basename = false
+       }
+       w.ts = parseTokens(parts)
 
        return w
 }
@@ -164,6 +183,12 @@ func (w *Wildmatch) Match(t string) bool {
 // returns a slice of remaining directory paths, and whether or not there was a
 // disagreement while matching.
 func (w *Wildmatch) consume(t string) ([]string, bool) {
+       if w.basename {
+               // If the receiving Wildmatch has basename set, the pattern
+               // matches only the basename of the given "t".
+               t = filepath.Base(t)
+       }
+
        if w.caseFold {
                // If the receiving Wildmatch is case insensitive, the pattern
                // "w.p" will be lower-case.
index 06761ff..9d35743 100644 (file)
@@ -597,6 +597,41 @@ var Cases = []*Case{
                Subject: `foo-a.txt`,
                Match:   false,
        },
+       {
+               Pattern: `*.txt`,
+               Subject: `file.txt`,
+               Opts:    []opt{Basename},
+               Match:   true,
+       },
+       {
+               Pattern: `*.txt`,
+               Subject: `path/to/file.txt`,
+               Opts:    []opt{Basename},
+               Match:   true,
+       },
+       {
+               Pattern: `path/to/*.txt`,
+               Subject: `path/to/file.txt`,
+               Opts:    []opt{Basename},
+               Match:   true,
+       },
+       {
+               Pattern: `path/to/*.txt`,
+               Subject: `path/to/file.txt`,
+               Match:   true,
+       },
+       {
+               Pattern: `path/to/*.txt`,
+               Subject: `outside/of/path/to/file.txt`,
+               Opts:    []opt{Basename},
+               Match:   false,
+       },
+       {
+               Pattern: `path/to/*.txt`,
+               Subject: `path/to/some/intermediaries/to/file.txt`,
+               Opts:    []opt{Basename},
+               Match:   false,
+       },
 }
 
 func TestWildmatch(t *testing.T) {
index 8cc05ae..a32767e 100644 (file)
@@ -3,8 +3,8 @@
        {
                "FileVersion": {
                        "Major": 2,
-                       "Minor": 4,
-                       "Patch": 2,
+                       "Minor": 5,
+                       "Patch": 0,
                        "Build": 0
                }
        },
@@ -13,7 +13,7 @@
                "FileDescription": "Git LFS",
                "LegalCopyright": "GitHub, Inc. and Git LFS contributors",
                "ProductName": "Git Large File Storage (LFS)",
-               "ProductVersion": "2.4.2"
+               "ProductVersion": "2.5.0"
        },
        "IconPath": "script/windows-installer/git-lfs-logo.ico"
 }