mirror of https://github.com/k3s-io/k3s
Remove third_party/forked/godep
parent
b3527f41f0
commit
7f246d461b
|
@ -404,34 +404,6 @@ kube::util::ensure_clean_working_dir() {
|
||||||
done 1>&2
|
done 1>&2
|
||||||
}
|
}
|
||||||
|
|
||||||
# Ensure that the given godep version is installed and in the path. Almost
|
|
||||||
# nobody should use any version but the default.
|
|
||||||
#
|
|
||||||
# Sets:
|
|
||||||
# KUBE_GODEP: The path to the godep binary
|
|
||||||
#
|
|
||||||
kube::util::ensure_godep_version() {
|
|
||||||
local godep_target_version=${1:-"v80-k8s-r1"} # this version is known to work
|
|
||||||
|
|
||||||
# If KUBE_GODEP is already set, and it's the right version, then use it.
|
|
||||||
if [[ -n "${KUBE_GODEP:-}" && "$(${KUBE_GODEP:?} version 2>/dev/null)" == *"godep ${godep_target_version}"* ]]; then
|
|
||||||
kube::log::status "Using ${KUBE_GODEP}"
|
|
||||||
return
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Otherwise, install forked godep
|
|
||||||
kube::log::status "Installing godep version ${godep_target_version}"
|
|
||||||
GOBIN="${KUBE_OUTPUT_BINPATH}" go install k8s.io/kubernetes/third_party/forked/godep
|
|
||||||
export KUBE_GODEP="${KUBE_OUTPUT_BINPATH}/godep"
|
|
||||||
kube::log::status "Installed ${KUBE_GODEP}"
|
|
||||||
|
|
||||||
# Verify that the installed godep from fork is what we expect
|
|
||||||
if [[ "$(${KUBE_GODEP:?} version 2>/dev/null)" != *"godep ${godep_target_version}"* ]]; then
|
|
||||||
kube::log::error "Expected godep ${godep_target_version} from ${KUBE_GODEP}, got $(${KUBE_GODEP:?} version)"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
# Ensure that none of the staging repos is checked out in the GOPATH because this
|
# Ensure that none of the staging repos is checked out in the GOPATH because this
|
||||||
# easily confused godep.
|
# easily confused godep.
|
||||||
kube::util::ensure_no_staging_repos_in_gopath() {
|
kube::util::ensure_no_staging_repos_in_gopath() {
|
||||||
|
|
|
@ -22,7 +22,6 @@ filegroup(
|
||||||
"//third_party/forked/etcd221/wal:all-srcs",
|
"//third_party/forked/etcd221/wal:all-srcs",
|
||||||
"//third_party/forked/etcd237/pkg/fileutil:all-srcs",
|
"//third_party/forked/etcd237/pkg/fileutil:all-srcs",
|
||||||
"//third_party/forked/etcd237/wal:all-srcs",
|
"//third_party/forked/etcd237/wal:all-srcs",
|
||||||
"//third_party/forked/godep:all-srcs",
|
|
||||||
"//third_party/forked/golang/expansion:all-srcs",
|
"//third_party/forked/golang/expansion:all-srcs",
|
||||||
"//third_party/forked/golang/reflect:all-srcs",
|
"//third_party/forked/golang/reflect:all-srcs",
|
||||||
"//third_party/forked/golang/template:all-srcs",
|
"//third_party/forked/golang/template:all-srcs",
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
/godep
|
|
|
@ -1,34 +0,0 @@
|
||||||
language: go
|
|
||||||
sudo: false
|
|
||||||
go: 1.6
|
|
||||||
script:
|
|
||||||
# Godep's unit tests run git, and git complains
|
|
||||||
# if we don't set these config parameters.
|
|
||||||
# We put dummy values here because they don't matter.
|
|
||||||
- git config --global user.email "you@example.com"
|
|
||||||
- git config --global user.name "Your Name"
|
|
||||||
- test -z "$(go fmt)"
|
|
||||||
- go vet
|
|
||||||
- go test -v
|
|
||||||
- go test -v -race
|
|
||||||
- test -z "$(goimports -l .)"
|
|
||||||
before_install:
|
|
||||||
- go get golang.org/x/tools/cmd/goimports
|
|
||||||
before_deploy:
|
|
||||||
- export OS_TARGETS="linux darwin windows"
|
|
||||||
- export ARCH_TARGETS="386 amd64"
|
|
||||||
- go get github.com/mitchellh/gox
|
|
||||||
- gox -os "$OS_TARGETS" -arch="$ARCH_TARGETS"
|
|
||||||
deploy:
|
|
||||||
skip_cleanup: true
|
|
||||||
provider: releases
|
|
||||||
api_key:
|
|
||||||
secure: Q1JP8LziaXMTxFmNXiyC1YhS9e4M4WnI6UDjRTMf6mm1LZeJyUFOCCtXnifL7RyCIR1hpjp6s8M1aWE+NpuweF96IZI3Uk4ASx5C8FePC4qvhsCdtJ2sLD2GTIrp9b0MS9/+ao20AIbpVDSaLaF9IjqXpMxMyM0P8P5coRTkwItlGxmQbVJW3YuiYcPa8UojwM4EyafO2CIoUKapW8lwb9KcimBJV8PfF/XZjPVhMkn2ABhh5Hqbn2zBJtvPYMMzi0CnY50JQF5LwN3vGTMpTsRP+lOLCNbOWfkl+2hgG7VpKrtx+cX62knOodpF457sIJ31KUzmeLUVBejTGb1zuVeTojuyi8Huo8YBIBCcN+p3Dqd+n2ZK45mIrheGiEJIkf/vI4MI6A01Nu/o+xU0IPsVfAL/xU5j5nntEGfFWVoclPrl9qcfqf74xdRcARzcCJVmdc8iw49DBDHJfnPa3zxzVz//00+Rz6mZXmhk+Npk/HLLNW59vmJIjP+8XOtPor7dST9HrS1a9AcnmIjNuw9yfbwK5769SDVxCKgqNwXW/Dy5F39aIH5AL4I4y9hCEeeT8ctvSJHGOyiB9MWU5jnt5tluPtz5opG51tFXnIYP/XaWpTfO+eJ6x55pbwT+n3LfRS5l1POM+jGAFF1MFWwc14RY7qynEIEzm4Wb/UE=
|
|
||||||
file:
|
|
||||||
- godep_darwin_amd64
|
|
||||||
- godep_linux_amd64
|
|
||||||
- godep_windows_386.exe
|
|
||||||
- godep_windows_amd64.exe
|
|
||||||
on:
|
|
||||||
tags: true
|
|
||||||
repo: tools/godep
|
|
|
@ -1,57 +0,0 @@
|
||||||
load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
|
|
||||||
|
|
||||||
licenses(["notice"])
|
|
||||||
|
|
||||||
go_library(
|
|
||||||
name = "go_default_library",
|
|
||||||
srcs = [
|
|
||||||
"dep.go",
|
|
||||||
"diff.go",
|
|
||||||
"doc.go",
|
|
||||||
"errors.go",
|
|
||||||
"get.go",
|
|
||||||
"go.go",
|
|
||||||
"godepfile.go",
|
|
||||||
"license.go",
|
|
||||||
"list.go",
|
|
||||||
"main.go",
|
|
||||||
"msg.go",
|
|
||||||
"path.go",
|
|
||||||
"pkg.go",
|
|
||||||
"restore.go",
|
|
||||||
"rewrite.go",
|
|
||||||
"save.go",
|
|
||||||
"update.go",
|
|
||||||
"util.go",
|
|
||||||
"vcs.go",
|
|
||||||
"version.go",
|
|
||||||
],
|
|
||||||
importpath = "k8s.io/kubernetes/third_party/forked/godep",
|
|
||||||
visibility = ["//visibility:private"],
|
|
||||||
deps = [
|
|
||||||
"//vendor/github.com/kr/fs:go_default_library",
|
|
||||||
"//vendor/github.com/kr/pretty:go_default_library",
|
|
||||||
"//vendor/github.com/pmezard/go-difflib/difflib:go_default_library",
|
|
||||||
"//vendor/golang.org/x/tools/go/vcs:go_default_library",
|
|
||||||
],
|
|
||||||
)
|
|
||||||
|
|
||||||
go_binary(
|
|
||||||
name = "godep",
|
|
||||||
embed = [":go_default_library"],
|
|
||||||
visibility = ["//visibility:public"],
|
|
||||||
)
|
|
||||||
|
|
||||||
filegroup(
|
|
||||||
name = "package-srcs",
|
|
||||||
srcs = glob(["**"]),
|
|
||||||
tags = ["automanaged"],
|
|
||||||
visibility = ["//visibility:private"],
|
|
||||||
)
|
|
||||||
|
|
||||||
filegroup(
|
|
||||||
name = "all-srcs",
|
|
||||||
srcs = [":package-srcs"],
|
|
||||||
tags = ["automanaged"],
|
|
||||||
visibility = ["//visibility:public"],
|
|
||||||
)
|
|
|
@ -1,412 +0,0 @@
|
||||||
#v80 (2018/01/26)
|
|
||||||
|
|
||||||
* Address lin/vet feedback.
|
|
||||||
|
|
||||||
#v79 (2017/02/01)
|
|
||||||
|
|
||||||
* Fixes #531: fullPackageInDir didn't capture the error from fillPackage()
|
|
||||||
|
|
||||||
#v78 (2017/01/19)
|
|
||||||
|
|
||||||
* Don't use build.ImportDir when discovering packages for the package spec. Fixes #529
|
|
||||||
|
|
||||||
#v77 (2017/01/13)
|
|
||||||
|
|
||||||
* Don't include quotes around hg revisions
|
|
||||||
|
|
||||||
#v76 (2017/01/10)
|
|
||||||
|
|
||||||
* Default to vendor being on unless older go versions.
|
|
||||||
|
|
||||||
#v75 (2016/11/02)
|
|
||||||
|
|
||||||
* Add "AUTHORS" and "CONTRIBUTORS" to legal files list: https://github.com/tools/godep/pull/522
|
|
||||||
|
|
||||||
#v74 (2016/06/01)
|
|
||||||
|
|
||||||
* Enable vendor/ on go1.7
|
|
||||||
* No longer use a godep workspace, use vendor/ (yay!)
|
|
||||||
* Notify that support for Godep workspaces will be removed once go1.8 ships
|
|
||||||
|
|
||||||
#v73 (2016/05/31)
|
|
||||||
|
|
||||||
* Fix permission changes on Windows via @alexbrand. Closes #481.
|
|
||||||
|
|
||||||
#v72 (2016/05/27)
|
|
||||||
|
|
||||||
* Improve handling of git remote show origin. Should help in cases where remote HEAD is ambiguous.
|
|
||||||
* Add ISSUE_TEMPLATE
|
|
||||||
|
|
||||||
#v71 (2016/05/24)
|
|
||||||
|
|
||||||
* Preserve permissions on copied files.
|
|
||||||
|
|
||||||
#v70 (2016/05/20)
|
|
||||||
|
|
||||||
* Fix the May changelog dates
|
|
||||||
* No need to call build.Import, we already have the root of the dependency. Fixes an additional comment on #365
|
|
||||||
|
|
||||||
#v69 (2016/05/16)
|
|
||||||
|
|
||||||
* Make sure `devel-<short sha>` enabled `vendor/` unless there is a classic Godep _workspace already.
|
|
||||||
|
|
||||||
#v68 (2016/05/16)
|
|
||||||
|
|
||||||
* `devel-<short sha>` is always considered newer than any released go version
|
|
||||||
|
|
||||||
#v67 (2016/05/13)
|
|
||||||
|
|
||||||
* Attempt to handle missing deps a little better.
|
|
||||||
|
|
||||||
#v66 (2016/05/10)
|
|
||||||
|
|
||||||
* Use `git remote show origin` to find the default branch when restoring a git based package repository that is in detached head state
|
|
||||||
|
|
||||||
#v65 (2016/05/09)
|
|
||||||
|
|
||||||
* Rewrite update so that it considers new transitive dependencies, both in the same repo and outside of it.
|
|
||||||
|
|
||||||
#v64 (2016/05/09)
|
|
||||||
|
|
||||||
* godep update golang.org/x/tools/go/vcs
|
|
||||||
|
|
||||||
#v63 (2016/05/03)
|
|
||||||
|
|
||||||
* Support recording devel-<short sha> so development versions of Go can be matched
|
|
||||||
|
|
||||||
#v62 (2016/04/07)
|
|
||||||
|
|
||||||
* Note new go1.6+ behavior of not checking out master in README / restore help text.
|
|
||||||
|
|
||||||
#v61 (2016/04/06)
|
|
||||||
|
|
||||||
* Obey go version build tags based on recorded major go version. Fixes #448.
|
|
||||||
|
|
||||||
#v60 (2016/03/18)
|
|
||||||
|
|
||||||
* Make the $GOPATH check a warning.
|
|
||||||
|
|
||||||
#v59 (2016/03/18)
|
|
||||||
|
|
||||||
* Enforce requirement to be inside of a go src directory. A lot of time is usually spent
|
|
||||||
tracking down bug reports where people are doign stuff from outside of their $GOPATH. This
|
|
||||||
should help with that, at least until there it time to properly test godep use outside of a
|
|
||||||
$GOPATH and fix the issues.
|
|
||||||
|
|
||||||
#v58 (2016/03/15)
|
|
||||||
|
|
||||||
* Add GodepVersion to Godeps.json file so that as godep changes / adds features / fixes bugs we can know which version of godep most recently wrote out the file.
|
|
||||||
|
|
||||||
#v57 (2016/03/07)
|
|
||||||
|
|
||||||
* Don't use `git rev-parse --show-toplevel` to determine git repo roots as it resolves symlinks: https://github.com/tools/godep/pull/418
|
|
||||||
|
|
||||||
# v56 (2016/02/26)
|
|
||||||
|
|
||||||
* replace path comparisons with case insensitive pathEqual()
|
|
||||||
* add versionString() to debug output
|
|
||||||
* Send log output to Stderr
|
|
||||||
|
|
||||||
# v55 2016/02/22
|
|
||||||
|
|
||||||
* re-saved deps to clean out extra stuff (see v54; godep restore; godep save -r=false; rm -rf Godeps; godep save -r). We're still using a workspace with rewrites so users of older go version can still go get this tool.
|
|
||||||
* Replace simple == with strings.EqualFold in listFiles to avoid problems with case insensitive filesystems ("Code" != "code" when doing a byte by byte comparison)
|
|
||||||
|
|
||||||
# v54 2016/02/22
|
|
||||||
|
|
||||||
* Update some docs around vendor/
|
|
||||||
* More precise recording of dependencies. Removed recursive copying of sub directories of a package (precise vendoring). This should allow using `./...` with the go tool for compilation of project using `vendor/`. See https://github.com/tools/godep/pull/415
|
|
||||||
|
|
||||||
# v53 2016/02/11
|
|
||||||
|
|
||||||
* Disable VendorExperiment if a godep workspace already exists.
|
|
||||||
|
|
||||||
# v52 2016/01/27
|
|
||||||
|
|
||||||
* Trim 'rc' out of go version strings when determining major version.
|
|
||||||
|
|
||||||
# v51 2016/01/21
|
|
||||||
|
|
||||||
* Trim 'beta' out of go version strings when determining major version.
|
|
||||||
|
|
||||||
# v50 2016/01/19
|
|
||||||
|
|
||||||
* More verbose output on save -v.
|
|
||||||
|
|
||||||
# v49 2016/01/13
|
|
||||||
|
|
||||||
* Add UK spelling license/licence to the pile + fix up a bunch of typos
|
|
||||||
* Clarify tag handling in docs
|
|
||||||
|
|
||||||
# v48 2016/01/13
|
|
||||||
|
|
||||||
* Abort restore if there is no $GOPATH set.
|
|
||||||
|
|
||||||
# v47 2016/01/12
|
|
||||||
|
|
||||||
* Dev versions of go should honor the current meaning of GO15VENDOREXPERIMENT
|
|
||||||
|
|
||||||
# v46 2016/01/03
|
|
||||||
|
|
||||||
* Record "devel" when the release is a devel release of go (compiled from git).
|
|
||||||
|
|
||||||
# v45 2015/12/28
|
|
||||||
|
|
||||||
* Upcase windows drive letters before comparing. Fixes #383.
|
|
||||||
|
|
||||||
# v44 2015/12/23
|
|
||||||
|
|
||||||
* Clean package roots when attempting to find a vendor directory so we don't loop forever.
|
|
||||||
* Fixes 382
|
|
||||||
|
|
||||||
# v43 2015/12/22
|
|
||||||
|
|
||||||
* Better error messages when parsing Godeps.json: Fixes #372
|
|
||||||
|
|
||||||
# v42 2015/12/22
|
|
||||||
|
|
||||||
* Fix a bunch of GO15VENDOREXPERIMENT issues
|
|
||||||
* Find package directories better. Previously we used build.FindOnly which didn't work the way I expected it to (any dir would work w/o error).
|
|
||||||
* Set the VendorExperiment bool based on go version as 1.6 defaults to on.
|
|
||||||
* A bunch of extra debugging for use while sanity checking myself.
|
|
||||||
* vendor flag for test structs.
|
|
||||||
* Some tests for vendor/ stuff:
|
|
||||||
* Basic Test
|
|
||||||
* Transitive
|
|
||||||
* Transitive, across GOPATHs + collapse vendor/ directories.
|
|
||||||
* Should Fix #358
|
|
||||||
|
|
||||||
# v41 2015/12/17
|
|
||||||
|
|
||||||
* Don't rewrite packages outside of the project. This would happen if you specified
|
|
||||||
an external package for vendoring when you ran `goodep save -r ./... github.com/some/other/package`
|
|
||||||
|
|
||||||
# v40 2015/12/17
|
|
||||||
|
|
||||||
* When downloading a dependency, create the base directory if needed.
|
|
||||||
|
|
||||||
# v39 2015/12/16
|
|
||||||
|
|
||||||
* Record only the major go version (ex. go1.5) instead of the complete string.
|
|
||||||
|
|
||||||
# v38 2015/12/16
|
|
||||||
|
|
||||||
* Replace `go get`, further fix up restore error handling/reporting.
|
|
||||||
* Fixes #186
|
|
||||||
* Don't bother restoring/downloading if already done.
|
|
||||||
|
|
||||||
# v37 2015/12/15
|
|
||||||
|
|
||||||
* Change up how download/restore works a little
|
|
||||||
* Try to load the package after downloading/restoring. Previously
|
|
||||||
that was done too early in the process.
|
|
||||||
* make previous verbose output debug output
|
|
||||||
* report a typed error instead of a string from listPackage so it can
|
|
||||||
be asserted to provide a nicer error.
|
|
||||||
* Catch go get errors that say there are no go files found. See code
|
|
||||||
comment as to why.
|
|
||||||
* do *all* downloading during download phase.
|
|
||||||
|
|
||||||
# v36 2015/12/14
|
|
||||||
|
|
||||||
* Fixes #358: Using wrong variable. Will add test after release.
|
|
||||||
|
|
||||||
# v35 2015/12/11
|
|
||||||
|
|
||||||
* Fixes #356: Major performance regressions in v34
|
|
||||||
* Enable cpu profiling via flag on save.
|
|
||||||
* Cache packages by dir
|
|
||||||
* Don't do a full import pass on deps for packages in the GOROOT
|
|
||||||
* create a bit less garbage at times
|
|
||||||
* Generalize -v & -d flags
|
|
||||||
|
|
||||||
# v34 2015/12/08
|
|
||||||
|
|
||||||
* We now use build.Context to help locate packages only and do our own parsing (via go/ast).
|
|
||||||
* Fixes reported issues caused by v33 (Removal of `go list`):
|
|
||||||
* #345: Bug in godep restore
|
|
||||||
* #346: Fix loading a dot package
|
|
||||||
* #348: Godep save issue when importing lib/pq
|
|
||||||
* #350: undefined: build.MultiplePackageError
|
|
||||||
* #351: stow away helper files
|
|
||||||
* #353: cannot find package "appengine"
|
|
||||||
* Don't process imports of `.go` files tagged with the `appengine` build tag.
|
|
||||||
|
|
||||||
# v33 2015/12/07
|
|
||||||
|
|
||||||
* Replace the use of `go list`. This is a large change although all existing tests pass.
|
|
||||||
* Don't process the imports of `.go` files with the `ignore` build tag.
|
|
||||||
|
|
||||||
# v32 2015/12/02
|
|
||||||
|
|
||||||
* Eval Symlinks in Contains() check.
|
|
||||||
|
|
||||||
# v31 2015/12/02
|
|
||||||
|
|
||||||
* In restore, mention which package had the problem -- @shurcool
|
|
||||||
|
|
||||||
# v30 2015/11/25
|
|
||||||
|
|
||||||
* Add `-t` flag to the `godep get` command.
|
|
||||||
|
|
||||||
# v29 2015/11/17
|
|
||||||
|
|
||||||
* Temp work around to fix issue with LICENSE files.
|
|
||||||
|
|
||||||
# v28 2015/11/09
|
|
||||||
|
|
||||||
* Make `version` an actual command.
|
|
||||||
|
|
||||||
# v27 2015/11/06
|
|
||||||
|
|
||||||
* run command once during restore -v
|
|
||||||
|
|
||||||
# v26 2015/11/05
|
|
||||||
|
|
||||||
* Better fix for the issue fixed in v25: All update paths are now path.Clean()'d
|
|
||||||
|
|
||||||
# v25 2015/11/05
|
|
||||||
|
|
||||||
* `godep update package/` == `godep update package`. Fixes #313
|
|
||||||
|
|
||||||
# v24 2015/11/05
|
|
||||||
|
|
||||||
* Honor -t during update. Fixes #312
|
|
||||||
|
|
||||||
# v23 2015/11/05
|
|
||||||
|
|
||||||
* Do not use --debug to find full revision name for mercurial repositories
|
|
||||||
|
|
||||||
# v22 2015/11/14
|
|
||||||
|
|
||||||
* s/GOVENDOREXPERIMENT/GO15VENDOREXPERIMENT :-(
|
|
||||||
|
|
||||||
# v21 2015/11/13
|
|
||||||
|
|
||||||
* Fix #310: Case insensitive fs issue
|
|
||||||
|
|
||||||
# v20 2015/11/13
|
|
||||||
|
|
||||||
* Attempt to include license files when vendoring. (@client9)
|
|
||||||
|
|
||||||
# v19 2015/11/3
|
|
||||||
|
|
||||||
* Fix conflict error message. Revisions were swapped. Also better selection of package that needs update.
|
|
||||||
|
|
||||||
# v18 2015/10/16
|
|
||||||
|
|
||||||
* Improve error message when trying to save a conflicting revision.
|
|
||||||
|
|
||||||
# v17 2015/10/15
|
|
||||||
|
|
||||||
* Fix for v16 bug. All vcs list commands now produce paths relative to the root of the vcs.
|
|
||||||
|
|
||||||
# v16 2015/10/15
|
|
||||||
|
|
||||||
* Determine repo root using vcs commands and use that instead of dep.dir
|
|
||||||
|
|
||||||
# v15 2015/10/14
|
|
||||||
|
|
||||||
* Update .travis.yml file to do releases to github
|
|
||||||
|
|
||||||
# v14 2015/10/08
|
|
||||||
|
|
||||||
* Don't print out a workspace path when GO15VENDOREXPERIMENT is active. The vendor/ directory is not a valid workspace, so can't be added to your $GOPATH.
|
|
||||||
|
|
||||||
# v13 2015/10/07
|
|
||||||
|
|
||||||
* Do restores in 2 separate steps, first download all deps and then check out the recorded revisions.
|
|
||||||
* Update Changelog date format
|
|
||||||
|
|
||||||
# v12 2015/09/22
|
|
||||||
|
|
||||||
* Extract errors into separate file.
|
|
||||||
|
|
||||||
# v11 2015/08/22
|
|
||||||
|
|
||||||
* Amend code to pass golint.
|
|
||||||
|
|
||||||
# v10 2015/09/21
|
|
||||||
|
|
||||||
* Analyse vendored package test dependencies.
|
|
||||||
* Update documentation.
|
|
||||||
|
|
||||||
# v9 2015/09/17
|
|
||||||
|
|
||||||
* Don't save test dependencies by default.
|
|
||||||
|
|
||||||
# v8 2015/09/17
|
|
||||||
|
|
||||||
* Reorganize code.
|
|
||||||
|
|
||||||
# v7 2015/09/09
|
|
||||||
|
|
||||||
* Add verbose flag.
|
|
||||||
* Skip untracked files.
|
|
||||||
* Add VCS list command.
|
|
||||||
|
|
||||||
# v6 2015/09/04
|
|
||||||
|
|
||||||
* Revert ignoring testdata directories and instead ignore it while
|
|
||||||
processing Go files and copy the whole directory unmodified.
|
|
||||||
|
|
||||||
# v5 2015/09/04
|
|
||||||
|
|
||||||
* Fix vcs selection in restore command to work as go get does
|
|
||||||
|
|
||||||
# v4 2015/09/03
|
|
||||||
|
|
||||||
* Remove the deprecated copy option.
|
|
||||||
|
|
||||||
# v3 2015/08/26
|
|
||||||
|
|
||||||
* Ignore testdata directories
|
|
||||||
|
|
||||||
# v2 2015/08/11
|
|
||||||
|
|
||||||
* Include command line packages in the set to copy
|
|
||||||
|
|
||||||
This is a simplification to how we define the behavior
|
|
||||||
of the save command. Now it has two distinct package
|
|
||||||
parameters, the "root set" and the "destination", and
|
|
||||||
they have clearer roles. The packages listed on the
|
|
||||||
command line form the root set; they and all their
|
|
||||||
dependencies will be copied into the Godeps directory.
|
|
||||||
Additionally, the destination (always ".") will form the
|
|
||||||
initial list of "seen" import paths to exclude from
|
|
||||||
copying.
|
|
||||||
|
|
||||||
In the common case, the root set is equal to the
|
|
||||||
destination, so the effective behavior doesn't change.
|
|
||||||
This is primarily just a simpler definition. However, if
|
|
||||||
the user specifies a package on the command line that
|
|
||||||
lives outside of . then that package will be copied.
|
|
||||||
|
|
||||||
As a side effect, there's a simplification to the way we
|
|
||||||
add packages to the initial "seen" set. Formerly, to
|
|
||||||
avoid copying dependencies unnecessarily, we would try
|
|
||||||
to find the root of the VCS repo for each package in the
|
|
||||||
root set, and mark the import path of the entire repo as
|
|
||||||
seen. This meant for a repo at path C, if destination
|
|
||||||
C/S imports C/T, we would not copy C/T into C/S/Godeps.
|
|
||||||
Now we don't treat the repo root specially, and as
|
|
||||||
mentioned above, the destination alone is considered
|
|
||||||
seen.
|
|
||||||
|
|
||||||
This also means we don't require listed packages to be
|
|
||||||
in VCS unless they're outside of the destination.
|
|
||||||
|
|
||||||
# v1 2015/07/20
|
|
||||||
|
|
||||||
* godep version command
|
|
||||||
|
|
||||||
Output the version as well as some godep runtime information that is
|
|
||||||
useful for debugging user's issues.
|
|
||||||
|
|
||||||
The version const would be bumped each time a PR is merged into master
|
|
||||||
to ensure that we'll be able to tell which version someone got when they
|
|
||||||
did a `go get github.com/tools/godep`.
|
|
||||||
|
|
||||||
# Older changes
|
|
||||||
|
|
||||||
Many and more, see `git log -p`
|
|
|
@ -1,22 +0,0 @@
|
||||||
## Why do I need to check in `vendor/`?
|
|
||||||
|
|
||||||
godep's primary concern is to allow you to repeatably build your project. Your
|
|
||||||
dependencies are part of that project. Without them it won't build. Not
|
|
||||||
committing `vendor/` adds additional external dependencies that are outside of
|
|
||||||
your control. In Go, fetching packages is tied to multiple external systems
|
|
||||||
(DNS, web servers, etc). Over time other developers or code hosting sites may
|
|
||||||
discontinue service, delete code, force push, or take any number of other
|
|
||||||
actions that may make a package unreachable. Therefore it's the opinion of the
|
|
||||||
godep authors that `vendor/` should always be checked in.
|
|
||||||
|
|
||||||
## Should I use `godep restore`?
|
|
||||||
|
|
||||||
Probably not, unless you **need** to. Situations where you would **need** to are:
|
|
||||||
|
|
||||||
1. Using older Godep Workspaces (`Godeps/_workspace`) and not using `godep go
|
|
||||||
<cmd>`.
|
|
||||||
1. Resetting the state of $GOPATH to what is in your `Godeps.json` file in order
|
|
||||||
to cleanly re-vendor everything w/o upgrading/changing any deps. This is
|
|
||||||
useful when [migrating](https://github.com/tools/godep#migrating-to-vendor)
|
|
||||||
from workspaces to `vendor` or when a bug is fixed in `godep` that cleans up
|
|
||||||
a previous vendoring error.
|
|
|
@ -1,28 +0,0 @@
|
||||||
Copyright © 2013 Keith Rarick.
|
|
||||||
Portions Copyright (c) 2012 The Go Authors. All rights reserved.
|
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without
|
|
||||||
modification, are permitted provided that the following conditions are
|
|
||||||
met:
|
|
||||||
|
|
||||||
* Redistributions of source code must retain the above copyright
|
|
||||||
notice, this list of conditions and the following disclaimer.
|
|
||||||
* Redistributions in binary form must reproduce the above
|
|
||||||
copyright notice, this list of conditions and the following disclaimer
|
|
||||||
in the documentation and/or other materials provided with the
|
|
||||||
distribution.
|
|
||||||
* Neither the name of Google Inc. nor the names of its
|
|
||||||
contributors may be used to endorse or promote products derived from
|
|
||||||
this software without specific prior written permission.
|
|
||||||
|
|
||||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
||||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
||||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
||||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
||||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
||||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
||||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
||||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
||||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
||||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
@ -1,209 +0,0 @@
|
||||||
# Godep - Archived
|
|
||||||
|
|
||||||
Please use [dep](https://github.com/golang/dep) or another tool instead.
|
|
||||||
|
|
||||||
The rest of this readme is preserved for those that may still need its contents.
|
|
||||||
|
|
||||||
[![Build Status](https://travis-ci.org/tools/godep.svg)](https://travis-ci.org/tools/godep)
|
|
||||||
|
|
||||||
[![GoDoc](https://godoc.org/github.com/tools/godep?status.svg)](https://godoc.org/github.com/tools/godep)
|
|
||||||
|
|
||||||
godep helps build packages reproducibly by fixing their dependencies.
|
|
||||||
|
|
||||||
This tool assumes you are working in a standard Go workspace, as described [here](http://golang.org/doc/code.html). We
|
|
||||||
expect godep to build on Go 1.4* or newer, but you can use it on any project that works with Go 1 or newer.
|
|
||||||
|
|
||||||
Please check the [FAQ](FAQ.md) if you have a question.
|
|
||||||
|
|
||||||
## Golang Dep
|
|
||||||
|
|
||||||
The Go community now has the [dep](https://github.com/golang/dep) project to
|
|
||||||
manage dependencies. Please consider trying to migrate from Godep to dep. If there
|
|
||||||
is an issue preventing you from migrating please file an issue with dep so the
|
|
||||||
problem can be corrected. Godep will continue to be supported for some time but
|
|
||||||
is considered to be in a state of support rather than active feature development.
|
|
||||||
|
|
||||||
## Install
|
|
||||||
|
|
||||||
```console
|
|
||||||
go get github.com/tools/godep
|
|
||||||
```
|
|
||||||
|
|
||||||
## How to use godep with a new project
|
|
||||||
|
|
||||||
Assuming you've got everything working already, so you can build your project
|
|
||||||
with `go install` and test it with `go test`, it's one command to start using:
|
|
||||||
|
|
||||||
```console
|
|
||||||
godep save
|
|
||||||
```
|
|
||||||
|
|
||||||
This will save a list of dependencies to the file `Godeps/Godeps.json` and copy
|
|
||||||
their source code into `vendor/` (or `Godeps/_workspace/` when using older
|
|
||||||
versions of Go). Godep does **not copy**:
|
|
||||||
|
|
||||||
- files from source repositories that are not tracked in version control.
|
|
||||||
- `*_test.go` files.
|
|
||||||
- `testdata` directories.
|
|
||||||
- files outside of the go packages.
|
|
||||||
|
|
||||||
Godep does not process the imports of `.go` files with either the `ignore`
|
|
||||||
or `appengine` build tags.
|
|
||||||
|
|
||||||
Test files and testdata directories can be saved by adding `-t`.
|
|
||||||
|
|
||||||
Read over the contents of `vendor/` and make sure it looks reasonable. Then
|
|
||||||
commit the `Godeps/` and `vendor/` directories to version control.
|
|
||||||
|
|
||||||
## The deprecated `-r` flag
|
|
||||||
|
|
||||||
For older versions of Go, the `-r` flag tells save to automatically rewrite
|
|
||||||
package import paths. This allows your code to refer directly to the copied
|
|
||||||
dependencies in `Godeps/_workspace`. So, a package C that depends on package
|
|
||||||
D will actually import `C/Godeps/_workspace/src/D`. This makes C's repo
|
|
||||||
self-contained and causes `go get` to build C with the right version of all
|
|
||||||
dependencies.
|
|
||||||
|
|
||||||
If you don't use `-r`, when using older version of Go, then in order to use the
|
|
||||||
fixed dependencies and get reproducible builds, you must make sure that **every
|
|
||||||
time** you run a Go-related command, you wrap it in one of these two ways:
|
|
||||||
|
|
||||||
- If the command you are running is just `go`, run it as `godep go ...`, e.g.
|
|
||||||
`godep go install -v ./...`
|
|
||||||
- When using a different command, set your `$GOPATH` using `godep path` as
|
|
||||||
described below.
|
|
||||||
|
|
||||||
`-r` isn't necessary with go1.6+ and isn't allowed.
|
|
||||||
|
|
||||||
## Additional Operations
|
|
||||||
|
|
||||||
### Restore
|
|
||||||
|
|
||||||
The `godep restore` installs the
|
|
||||||
package versions specified in `Godeps/Godeps.json` to your `$GOPATH`. This
|
|
||||||
modifies the state of packages in your `$GOPATH`. NOTE: `godep restore` leaves
|
|
||||||
git repositories in a detached state. `go1.6`+ no longer checks out the master
|
|
||||||
branch when doing a `go get`, see [here](https://github.com/golang/go/commit/42206598671a44111c8f726ad33dc7b265bdf669).
|
|
||||||
|
|
||||||
> If you run `godep restore` in your main `$GOPATH` `go get -u` will fail on packages that are behind master.
|
|
||||||
|
|
||||||
Please see the [FAQ](https://github.com/tools/godep/blob/master/FAQ.md#should-i-use-godep-restore) section about restore.
|
|
||||||
|
|
||||||
### Edit-test Cycle
|
|
||||||
|
|
||||||
1. Edit code
|
|
||||||
1. Run `godep go test`
|
|
||||||
1. (repeat)
|
|
||||||
|
|
||||||
### Add a Dependency
|
|
||||||
|
|
||||||
To add a new package foo/bar, do this:
|
|
||||||
|
|
||||||
1. Run `go get foo/bar`
|
|
||||||
1. Edit your code to import foo/bar.
|
|
||||||
1. Run `godep save` (or `godep save ./...`).
|
|
||||||
|
|
||||||
### Update a Dependency
|
|
||||||
|
|
||||||
To update a package from your `$GOPATH`, do this:
|
|
||||||
|
|
||||||
1. Run `go get -u foo/bar`
|
|
||||||
1. Run `godep update foo/bar`.
|
|
||||||
|
|
||||||
You can use the `...` wildcard, for example `godep update foo/...`. Before comitting the change, you'll probably want to
|
|
||||||
inspect the changes to Godeps, for example with `git diff`, and make sure it looks reasonable.
|
|
||||||
|
|
||||||
## Multiple Packages
|
|
||||||
|
|
||||||
If your repository has more than one package, you're probably accustomed to
|
|
||||||
running commands like `go test ./...`, `go install ./...`, and `go fmt ./...`.
|
|
||||||
Similarly, you should run `godep save ./...` to capture the dependencies of all
|
|
||||||
packages in your application.
|
|
||||||
|
|
||||||
## File Format
|
|
||||||
|
|
||||||
Godeps is a json file with the following structure:
|
|
||||||
|
|
||||||
```go
|
|
||||||
type Godeps struct {
|
|
||||||
ImportPath string
|
|
||||||
GoVersion string // Abridged output of 'go version'.
|
|
||||||
GodepVersion string // Abridged output of 'godep version'
|
|
||||||
Packages []string // Arguments to godep save, if any.
|
|
||||||
Deps []struct {
|
|
||||||
ImportPath string
|
|
||||||
Comment string // Description of commit, if present.
|
|
||||||
Rev string // VCS-specific commit ID.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Example Godeps:
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"ImportPath": "github.com/kr/hk",
|
|
||||||
"GoVersion": "go1.6",
|
|
||||||
"Deps": [
|
|
||||||
{
|
|
||||||
"ImportPath": "code.google.com/p/go-netrc/netrc",
|
|
||||||
"Rev": "28676070ab99"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ImportPath": "github.com/kr/binarydist",
|
|
||||||
"Rev": "3380ade90f8b0dfa3e363fd7d7e941fa857d0d13"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Migrating to vendor/
|
|
||||||
|
|
||||||
Godep supports the Go 1.5+ vendor/
|
|
||||||
[experiment](https://github.com/golang/go/commit/183cc0cd41f06f83cb7a2490a499e3f9101befff)
|
|
||||||
utilizing the same environment variable that the go tooling itself supports
|
|
||||||
(`GO15VENDOREXPERIMENT`).
|
|
||||||
|
|
||||||
godep mostly works the same way as the `go` command line tool. If you have go
|
|
||||||
1.5.X and set `GO15VENDOREXPERIMENT=1` or have go1.6.X (or devel) `vendor/`
|
|
||||||
is enabled. **Unless** you already have a `Godeps/_workspace`. This is a safety
|
|
||||||
feature and godep warns you about this.
|
|
||||||
|
|
||||||
When `vendor/` is enabled godep will write the vendored code into the top level
|
|
||||||
`./vendor/` directory. A `./Godeps/Godeps.json` file is created to track
|
|
||||||
the dependencies and revisions. `vendor/` is not compatible with rewrites.
|
|
||||||
|
|
||||||
There is currently no automated migration between the old Godeps workspace and
|
|
||||||
the vendor directory, but the following steps should work:
|
|
||||||
|
|
||||||
```term
|
|
||||||
# just to be safe
|
|
||||||
$ unset GO15VENDOREXPERIMENT
|
|
||||||
|
|
||||||
# restore currently vendored deps to the $GOPATH
|
|
||||||
$ godep restore
|
|
||||||
|
|
||||||
# The next line is only needed to automatically undo rewritten imports that were
|
|
||||||
# created with godep save -r.
|
|
||||||
$ godep save -r=false <pkg spec>
|
|
||||||
|
|
||||||
# Remove the old Godeps folder
|
|
||||||
$ rm -rf Godeps
|
|
||||||
|
|
||||||
# If on go1.5.X to enable `vendor/`
|
|
||||||
$ export GO15VENDOREXPERIMENT=1
|
|
||||||
|
|
||||||
# re-analyze deps and save to `vendor/`.
|
|
||||||
$ godep save <pkg spec>
|
|
||||||
|
|
||||||
# Add the changes to your VCS
|
|
||||||
$ git add -A . ; git commit -am "Godep workspace -> vendor/"
|
|
||||||
|
|
||||||
# You should see your Godeps/_workspace/src files "moved" to vendor/.
|
|
||||||
```
|
|
||||||
|
|
||||||
## Releasing
|
|
||||||
|
|
||||||
1. Increment the version in `version.go`.
|
|
||||||
1. Tag the commit with the same version number.
|
|
||||||
1. Update `Changelog.md`.
|
|
|
@ -1,128 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
"os/exec"
|
|
||||||
"sort"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
// A Dependency is a specific revision of a package.
|
|
||||||
type Dependency struct {
|
|
||||||
ImportPath string
|
|
||||||
Comment string `json:",omitempty"` // Description of commit, if present.
|
|
||||||
Rev string // VCS-specific commit ID.
|
|
||||||
|
|
||||||
// used by command save & update
|
|
||||||
ws string // workspace
|
|
||||||
root string // import path to repo root
|
|
||||||
dir string // full path to package
|
|
||||||
|
|
||||||
// used by command update
|
|
||||||
matched bool // selected for update by command line
|
|
||||||
pkg *Package
|
|
||||||
missing bool // packages is missing
|
|
||||||
|
|
||||||
// used by command go
|
|
||||||
vcs *VCS
|
|
||||||
}
|
|
||||||
|
|
||||||
func eqDeps(a, b []Dependency) bool {
|
|
||||||
ok := true
|
|
||||||
for _, da := range a {
|
|
||||||
for _, db := range b {
|
|
||||||
if da.ImportPath == db.ImportPath && da.Rev != db.Rev {
|
|
||||||
ok = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ok
|
|
||||||
}
|
|
||||||
|
|
||||||
// containsPathPrefix returns whether any string in a
|
|
||||||
// is s or a directory containing s.
|
|
||||||
// For example, pattern ["a"] matches "a" and "a/b"
|
|
||||||
// (but not "ab").
|
|
||||||
func containsPathPrefix(pats []string, s string) bool {
|
|
||||||
for _, pat := range pats {
|
|
||||||
if pat == s || strings.HasPrefix(s, pat+"/") {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func uniq(a []string) []string {
|
|
||||||
var s string
|
|
||||||
var i int
|
|
||||||
if !sort.StringsAreSorted(a) {
|
|
||||||
sort.Strings(a)
|
|
||||||
}
|
|
||||||
for _, t := range a {
|
|
||||||
if t != s {
|
|
||||||
a[i] = t
|
|
||||||
i++
|
|
||||||
s = t
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return a[:i]
|
|
||||||
}
|
|
||||||
|
|
||||||
// trimGoVersion and return the major version
|
|
||||||
func trimGoVersion(version string) (string, error) {
|
|
||||||
if version == "devel" {
|
|
||||||
return "devel", nil
|
|
||||||
}
|
|
||||||
if strings.HasPrefix(version, "devel+") || strings.HasPrefix(version, "devel-") {
|
|
||||||
return strings.Replace(version, "devel+", "devel-", 1), nil
|
|
||||||
}
|
|
||||||
p := strings.Split(version, ".")
|
|
||||||
if len(p) < 2 {
|
|
||||||
return "", fmt.Errorf("Error determining major go version from: %q", version)
|
|
||||||
}
|
|
||||||
var split string
|
|
||||||
switch {
|
|
||||||
case strings.Contains(p[1], "beta"):
|
|
||||||
split = "beta"
|
|
||||||
case strings.Contains(p[1], "rc"):
|
|
||||||
split = "rc"
|
|
||||||
}
|
|
||||||
if split != "" {
|
|
||||||
p[1] = strings.Split(p[1], split)[0]
|
|
||||||
}
|
|
||||||
return p[0] + "." + p[1], nil
|
|
||||||
}
|
|
||||||
|
|
||||||
var goVersionTestOutput = ""
|
|
||||||
|
|
||||||
func getGoVersion() (string, error) {
|
|
||||||
// For testing purposes only
|
|
||||||
if goVersionTestOutput != "" {
|
|
||||||
return goVersionTestOutput, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Godep might have been compiled with a different
|
|
||||||
// version, so we can't just use runtime.Version here.
|
|
||||||
cmd := exec.Command("go", "version")
|
|
||||||
cmd.Stderr = os.Stderr
|
|
||||||
out, err := cmd.Output()
|
|
||||||
return string(out), err
|
|
||||||
}
|
|
||||||
|
|
||||||
// goVersion returns the major version string of the Go compiler
|
|
||||||
// currently installed, e.g. "go1.5".
|
|
||||||
func goVersion() (string, error) {
|
|
||||||
out, err := getGoVersion()
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
gv := strings.Split(out, " ")
|
|
||||||
if len(gv) < 4 {
|
|
||||||
return "", fmt.Errorf("Error splitting output of `go version`: Expected 4 or more elements, but there are < 4: %q", out)
|
|
||||||
}
|
|
||||||
if gv[2] == "devel" {
|
|
||||||
return trimGoVersion(gv[2] + gv[3])
|
|
||||||
}
|
|
||||||
return trimGoVersion(gv[2])
|
|
||||||
}
|
|
|
@ -1,74 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"fmt"
|
|
||||||
"log"
|
|
||||||
|
|
||||||
"github.com/pmezard/go-difflib/difflib"
|
|
||||||
)
|
|
||||||
|
|
||||||
var cmdDiff = &Command{
|
|
||||||
Name: "diff",
|
|
||||||
Short: "shows the diff between current and previously saved set of dependencies",
|
|
||||||
Long: `
|
|
||||||
Shows the difference, in a unified diff format, between the
|
|
||||||
current set of dependencies and those generated on a
|
|
||||||
previous 'go save' execution.
|
|
||||||
`,
|
|
||||||
Run: runDiff,
|
|
||||||
OnlyInGOPATH: true,
|
|
||||||
}
|
|
||||||
|
|
||||||
func runDiff(cmd *Command, args []string) {
|
|
||||||
gold, err := loadDefaultGodepsFile()
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalln(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
pkgs := []string{"."}
|
|
||||||
dot, err := LoadPackages(pkgs...)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalln(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
gnew := &Godeps{
|
|
||||||
ImportPath: dot[0].ImportPath,
|
|
||||||
GoVersion: gold.GoVersion,
|
|
||||||
}
|
|
||||||
|
|
||||||
err = gnew.fill(dot, dot[0].ImportPath)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalln(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
diff, err := diffStr(&gold, gnew)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalln(err)
|
|
||||||
}
|
|
||||||
fmt.Println(diff)
|
|
||||||
}
|
|
||||||
|
|
||||||
// diffStr returns a unified diff string of two Godeps.
|
|
||||||
func diffStr(a, b *Godeps) (string, error) {
|
|
||||||
var ab, bb bytes.Buffer
|
|
||||||
|
|
||||||
_, err := a.writeTo(&ab)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalln(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = b.writeTo(&bb)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalln(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
diff := difflib.UnifiedDiff{
|
|
||||||
A: difflib.SplitLines(ab.String()),
|
|
||||||
B: difflib.SplitLines(bb.String()),
|
|
||||||
FromFile: b.file(),
|
|
||||||
ToFile: "$GOPATH",
|
|
||||||
Context: 10,
|
|
||||||
}
|
|
||||||
return difflib.GetUnifiedDiffString(diff)
|
|
||||||
}
|
|
|
@ -1,22 +0,0 @@
|
||||||
/*
|
|
||||||
|
|
||||||
Command godep helps build packages reproducibly by fixing
|
|
||||||
their dependencies.
|
|
||||||
|
|
||||||
Example Usage
|
|
||||||
|
|
||||||
Save currently-used dependencies to file Godeps:
|
|
||||||
|
|
||||||
$ godep save
|
|
||||||
|
|
||||||
Build project using saved dependencies:
|
|
||||||
|
|
||||||
$ godep go install
|
|
||||||
|
|
||||||
or
|
|
||||||
|
|
||||||
$ GOPATH=`godep path`:$GOPATH
|
|
||||||
$ go install
|
|
||||||
|
|
||||||
*/
|
|
||||||
package main
|
|
|
@ -1,18 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import "errors"
|
|
||||||
|
|
||||||
var (
|
|
||||||
errorLoadingDeps = errors.New("error loading dependencies")
|
|
||||||
errorLoadingPackages = errors.New("error loading packages")
|
|
||||||
errorCopyingSourceCode = errors.New("error copying source code")
|
|
||||||
errorNoPackagesUpdatable = errors.New("no packages can be updated")
|
|
||||||
)
|
|
||||||
|
|
||||||
type errPackageNotFound struct {
|
|
||||||
path string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e errPackageNotFound) Error() string {
|
|
||||||
return "Package (" + e.path + ") not found"
|
|
||||||
}
|
|
|
@ -1,96 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"log"
|
|
||||||
"os"
|
|
||||||
"os/exec"
|
|
||||||
)
|
|
||||||
|
|
||||||
var cmdGet = &Command{
|
|
||||||
Name: "get",
|
|
||||||
Args: "[-t] [packages]",
|
|
||||||
Short: "download and install packages with specified dependencies",
|
|
||||||
Long: `
|
|
||||||
Get downloads to GOPATH the packages named by the import paths, and installs
|
|
||||||
them with the dependencies specified in their Godeps files.
|
|
||||||
|
|
||||||
If any of the packages do not have Godeps files, those are installed
|
|
||||||
as if by go get.
|
|
||||||
|
|
||||||
If -t is given, dependencies of test files are also downloaded and installed.
|
|
||||||
|
|
||||||
For more about specifying packages, see 'go help packages'.
|
|
||||||
`,
|
|
||||||
Run: runGet,
|
|
||||||
OnlyInGOPATH: true,
|
|
||||||
}
|
|
||||||
|
|
||||||
var getT bool
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
cmdGet.Flag.BoolVar(&getT, "t", false, "get test dependencies")
|
|
||||||
}
|
|
||||||
|
|
||||||
func runGet(cmd *Command, args []string) {
|
|
||||||
if len(args) == 0 {
|
|
||||||
args = []string{"."}
|
|
||||||
}
|
|
||||||
|
|
||||||
cmdArgs := []interface{}{"get", "-d"}
|
|
||||||
if verbose {
|
|
||||||
cmdArgs = append(cmdArgs, "-v")
|
|
||||||
}
|
|
||||||
|
|
||||||
if getT {
|
|
||||||
cmdArgs = append(cmdArgs, "-t")
|
|
||||||
}
|
|
||||||
|
|
||||||
err := command("go", append(cmdArgs, args)...).Run()
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalln(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// group import paths by Godeps location
|
|
||||||
groups := make(map[string][]string)
|
|
||||||
ps, err := LoadPackages(args...)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalln(err)
|
|
||||||
}
|
|
||||||
for _, pkg := range ps {
|
|
||||||
if pkg.Error.Err != "" {
|
|
||||||
log.Fatalln(pkg.Error.Err)
|
|
||||||
}
|
|
||||||
dir, _ := findInParents(pkg.Dir, "Godeps")
|
|
||||||
groups[dir] = append(groups[dir], pkg.ImportPath)
|
|
||||||
}
|
|
||||||
for dir, packages := range groups {
|
|
||||||
var c *exec.Cmd
|
|
||||||
if dir == "" {
|
|
||||||
c = command("go", "install", packages)
|
|
||||||
} else {
|
|
||||||
c = command("godep", "go", "install", packages)
|
|
||||||
c.Dir = dir
|
|
||||||
}
|
|
||||||
if err := c.Run(); err != nil {
|
|
||||||
log.Fatalln(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// command is like exec.Command, but the returned
|
|
||||||
// Cmd inherits stderr from the current process, and
|
|
||||||
// elements of args may be either string or []string.
|
|
||||||
func command(name string, args ...interface{}) *exec.Cmd {
|
|
||||||
var a []string
|
|
||||||
for _, arg := range args {
|
|
||||||
switch v := arg.(type) {
|
|
||||||
case string:
|
|
||||||
a = append(a, v)
|
|
||||||
case []string:
|
|
||||||
a = append(a, v...)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
c := exec.Command(name, a...)
|
|
||||||
c.Stderr = os.Stderr
|
|
||||||
return c
|
|
||||||
}
|
|
|
@ -1,129 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"log"
|
|
||||||
"os"
|
|
||||||
"os/exec"
|
|
||||||
"path/filepath"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
var cmdGo = &Command{
|
|
||||||
Name: "go",
|
|
||||||
Args: "command [arguments]",
|
|
||||||
Short: "run the go tool with saved dependencies",
|
|
||||||
Long: `
|
|
||||||
Go runs the go tool with a modified GOPATH giving access to
|
|
||||||
dependencies saved in Godeps.
|
|
||||||
|
|
||||||
Any go tool command can run this way, but "godep go get"
|
|
||||||
is unnecessary and has been disabled. Instead, use
|
|
||||||
"godep go install".
|
|
||||||
`,
|
|
||||||
Run: runGo,
|
|
||||||
OnlyInGOPATH: true,
|
|
||||||
}
|
|
||||||
|
|
||||||
// Find the godep GOPATH for this file tree and run the go tool.
|
|
||||||
func runGo(cmd *Command, args []string) {
|
|
||||||
gopath := prepareGopath()
|
|
||||||
if s := os.Getenv("GOPATH"); s != "" {
|
|
||||||
gopath += string(os.PathListSeparator) + os.Getenv("GOPATH")
|
|
||||||
}
|
|
||||||
if len(args) > 0 && args[0] == "get" {
|
|
||||||
log.Printf("invalid subcommand: %q", "go get")
|
|
||||||
fmt.Fprintln(os.Stderr, "Use 'godep go install' instead.")
|
|
||||||
fmt.Fprintln(os.Stderr, "Run 'godep help go' for usage.")
|
|
||||||
os.Exit(2)
|
|
||||||
}
|
|
||||||
c := exec.Command("go", args...)
|
|
||||||
c.Env = append(envNoGopath(), "GOPATH="+gopath)
|
|
||||||
c.Stdin = os.Stdin
|
|
||||||
c.Stdout = os.Stdout
|
|
||||||
c.Stderr = os.Stderr
|
|
||||||
err := c.Run()
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalln("go", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// prepareGopath reads dependency information from the filesystem
|
|
||||||
// entry name, fetches any necessary code, and returns a gopath
|
|
||||||
// causing the specified dependencies to be used.
|
|
||||||
func prepareGopath() (gopath string) {
|
|
||||||
dir, isDir := findGodeps()
|
|
||||||
if dir == "" {
|
|
||||||
log.Fatalln("No Godeps found (or in any parent directory)")
|
|
||||||
}
|
|
||||||
if !isDir {
|
|
||||||
log.Fatalln(strings.TrimSpace(needSource))
|
|
||||||
}
|
|
||||||
return filepath.Join(dir, "Godeps", "_workspace")
|
|
||||||
}
|
|
||||||
|
|
||||||
// findGodeps looks for a directory entry "Godeps" in the
|
|
||||||
// current directory or any parent, and returns the containing
|
|
||||||
// directory and whether the entry itself is a directory.
|
|
||||||
// If Godeps can't be found, findGodeps returns "".
|
|
||||||
// For any other error, it exits the program.
|
|
||||||
func findGodeps() (dir string, isDir bool) {
|
|
||||||
wd, err := os.Getwd()
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalln(err)
|
|
||||||
}
|
|
||||||
return findInParents(wd, "Godeps")
|
|
||||||
}
|
|
||||||
|
|
||||||
// isRoot returns true iff a path is a root.
|
|
||||||
// On Unix: "/".
|
|
||||||
// On Windows: "C:\", "D:\", ...
|
|
||||||
func isRoot(p string) bool {
|
|
||||||
p = filepath.Clean(p)
|
|
||||||
volume := filepath.VolumeName(p)
|
|
||||||
|
|
||||||
p = strings.TrimPrefix(p, volume)
|
|
||||||
p = filepath.ToSlash(p)
|
|
||||||
|
|
||||||
return p == "/"
|
|
||||||
}
|
|
||||||
|
|
||||||
// findInParents returns the path to the directory containing name
|
|
||||||
// in dir or any ancestor, and whether name itself is a directory.
|
|
||||||
// If name cannot be found, findInParents returns the empty string.
|
|
||||||
func findInParents(dir, name string) (container string, isDir bool) {
|
|
||||||
for {
|
|
||||||
fi, err := os.Stat(filepath.Join(dir, name))
|
|
||||||
if os.IsNotExist(err) && isRoot(dir) {
|
|
||||||
return "", false
|
|
||||||
}
|
|
||||||
if os.IsNotExist(err) {
|
|
||||||
dir = filepath.Dir(dir)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalln(err)
|
|
||||||
}
|
|
||||||
return dir, fi.IsDir()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func envNoGopath() (a []string) {
|
|
||||||
for _, s := range os.Environ() {
|
|
||||||
if !strings.HasPrefix(s, "GOPATH=") {
|
|
||||||
a = append(a, s)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return a
|
|
||||||
}
|
|
||||||
|
|
||||||
const needSource = `
|
|
||||||
outdated Godeps missing source code
|
|
||||||
|
|
||||||
This dependency list was created with an old version of godep.
|
|
||||||
|
|
||||||
To work around this, you have two options:
|
|
||||||
1. Run 'godep restore', and try again.
|
|
||||||
2. Ask the maintainer to switch to a newer version of godep,
|
|
||||||
then try again with the updated package.
|
|
||||||
`
|
|
|
@ -1,218 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"log"
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
godepsFile = filepath.Join("Godeps", "Godeps.json")
|
|
||||||
oldGodepsFile = filepath.Join("Godeps")
|
|
||||||
)
|
|
||||||
|
|
||||||
// Godeps describes what a package needs to be rebuilt reproducibly.
|
|
||||||
// It's the same information stored in file Godeps.
|
|
||||||
type Godeps struct {
|
|
||||||
ImportPath string
|
|
||||||
GoVersion string
|
|
||||||
GodepVersion string
|
|
||||||
Packages []string `json:",omitempty"` // Arguments to save, if any.
|
|
||||||
Deps []Dependency
|
|
||||||
isOldFile bool
|
|
||||||
}
|
|
||||||
|
|
||||||
func loadGodepsFile(path string) (Godeps, error) {
|
|
||||||
var g Godeps
|
|
||||||
f, err := os.Open(path)
|
|
||||||
if err != nil {
|
|
||||||
return g, err
|
|
||||||
}
|
|
||||||
defer f.Close()
|
|
||||||
err = json.NewDecoder(f).Decode(&g)
|
|
||||||
if err != nil {
|
|
||||||
err = fmt.Errorf("Unable to parse %s: %s", path, err.Error())
|
|
||||||
}
|
|
||||||
return g, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func loadDefaultGodepsFile() (Godeps, error) {
|
|
||||||
var g Godeps
|
|
||||||
var err error
|
|
||||||
g, err = loadGodepsFile(godepsFile)
|
|
||||||
if err != nil {
|
|
||||||
if os.IsNotExist(err) {
|
|
||||||
var err1 error
|
|
||||||
g, err1 = loadGodepsFile(oldGodepsFile)
|
|
||||||
if err1 != nil {
|
|
||||||
if os.IsNotExist(err1) {
|
|
||||||
return g, err
|
|
||||||
}
|
|
||||||
return g, err1
|
|
||||||
}
|
|
||||||
g.isOldFile = true
|
|
||||||
return g, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return g, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// pkgs is the list of packages to read dependencies for
|
|
||||||
func (g *Godeps) fill(pkgs []*Package, destImportPath string) error {
|
|
||||||
debugln("fill", destImportPath)
|
|
||||||
ppln(pkgs)
|
|
||||||
var err1 error
|
|
||||||
var path, testImports []string
|
|
||||||
dipp := []string{destImportPath}
|
|
||||||
for _, p := range pkgs {
|
|
||||||
if p.Standard {
|
|
||||||
log.Println("ignoring stdlib package:", p.ImportPath)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if p.Error.Err != "" {
|
|
||||||
log.Println(p.Error.Err)
|
|
||||||
err1 = errorLoadingPackages
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
path = append(path, p.ImportPath)
|
|
||||||
path = append(path, p.Deps...)
|
|
||||||
testImports = append(testImports, p.TestImports...)
|
|
||||||
testImports = append(testImports, p.XTestImports...)
|
|
||||||
}
|
|
||||||
ps, err := LoadPackages(testImports...)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
for _, p := range ps {
|
|
||||||
if p.Standard {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if p.Error.Err != "" {
|
|
||||||
log.Println(p.Error.Err)
|
|
||||||
err1 = errorLoadingPackages
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
path = append(path, p.ImportPath)
|
|
||||||
path = append(path, p.Deps...)
|
|
||||||
}
|
|
||||||
debugln("path", path)
|
|
||||||
for i, p := range path {
|
|
||||||
path[i] = unqualify(p)
|
|
||||||
}
|
|
||||||
path = uniq(path)
|
|
||||||
debugln("uniq, unqualify'd path", path)
|
|
||||||
ps, err = LoadPackages(path...)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
for _, pkg := range ps {
|
|
||||||
if pkg.Error.Err != "" {
|
|
||||||
log.Println(pkg.Error.Err)
|
|
||||||
err1 = errorLoadingDeps
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if pkg.Standard || containsPathPrefix(dipp, pkg.ImportPath) {
|
|
||||||
debugln("standard or dest skipping", pkg.ImportPath)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
vcs, reporoot, err := VCSFromDir(pkg.Dir, filepath.Join(pkg.Root, "src"))
|
|
||||||
if err != nil {
|
|
||||||
log.Println(err)
|
|
||||||
err1 = errorLoadingDeps
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
id, err := vcs.identify(pkg.Dir)
|
|
||||||
if err != nil {
|
|
||||||
log.Println(err)
|
|
||||||
err1 = errorLoadingDeps
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if vcs.isDirty(pkg.Dir, id) {
|
|
||||||
log.Println("dirty working tree (please commit changes):", pkg.Dir)
|
|
||||||
err1 = errorLoadingDeps
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
comment := vcs.describe(pkg.Dir, id)
|
|
||||||
g.Deps = append(g.Deps, Dependency{
|
|
||||||
ImportPath: pkg.ImportPath,
|
|
||||||
Rev: id,
|
|
||||||
Comment: comment,
|
|
||||||
dir: pkg.Dir,
|
|
||||||
ws: pkg.Root,
|
|
||||||
root: filepath.ToSlash(reporoot),
|
|
||||||
vcs: vcs,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
return err1
|
|
||||||
}
|
|
||||||
|
|
||||||
func (g *Godeps) copy() *Godeps {
|
|
||||||
h := *g
|
|
||||||
h.Deps = make([]Dependency, len(g.Deps))
|
|
||||||
copy(h.Deps, g.Deps)
|
|
||||||
return &h
|
|
||||||
}
|
|
||||||
|
|
||||||
func (g *Godeps) file() string {
|
|
||||||
if g.isOldFile {
|
|
||||||
return oldGodepsFile
|
|
||||||
}
|
|
||||||
return godepsFile
|
|
||||||
}
|
|
||||||
|
|
||||||
func (g *Godeps) save() (int64, error) {
|
|
||||||
f, err := os.Create(g.file())
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
defer f.Close()
|
|
||||||
return g.writeTo(f)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (g *Godeps) writeTo(w io.Writer) (int64, error) {
|
|
||||||
g.GodepVersion = fmt.Sprintf("v%s", version) // godep always writes its current version.
|
|
||||||
b, err := json.MarshalIndent(g, "", "\t")
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
n, err := w.Write(append(b, '\n'))
|
|
||||||
return int64(n), err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (g *Godeps) addOrUpdateDeps(deps []Dependency) {
|
|
||||||
var missing []Dependency
|
|
||||||
for _, d := range deps {
|
|
||||||
var found bool
|
|
||||||
for i := range g.Deps {
|
|
||||||
if g.Deps[i].ImportPath == d.ImportPath {
|
|
||||||
g.Deps[i] = d
|
|
||||||
found = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !found {
|
|
||||||
missing = append(missing, d)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
g.Deps = append(g.Deps, missing...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (g *Godeps) removeDeps(deps []Dependency) {
|
|
||||||
var f []Dependency
|
|
||||||
for i := range g.Deps {
|
|
||||||
var found bool
|
|
||||||
for _, d := range deps {
|
|
||||||
if g.Deps[i].ImportPath == d.ImportPath {
|
|
||||||
found = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !found {
|
|
||||||
f = append(f, g.Deps[i])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
g.Deps = f
|
|
||||||
}
|
|
|
@ -1,59 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
// LicenseFilePrefix is a list of filename prefixes that indicate it
|
|
||||||
// might contain a software license
|
|
||||||
var LicenseFilePrefix = []string{
|
|
||||||
"licence", // UK spelling
|
|
||||||
"license", // US spelling
|
|
||||||
"copying",
|
|
||||||
"unlicense",
|
|
||||||
"copyright",
|
|
||||||
"copyleft",
|
|
||||||
"authors",
|
|
||||||
"contributors",
|
|
||||||
}
|
|
||||||
|
|
||||||
// LegalFileSubstring are substrings that indicate the file is likely
|
|
||||||
// to contain some type of legal declaration. "legal" is often used
|
|
||||||
// that it might moved to LicenseFilePrefix
|
|
||||||
var LegalFileSubstring = []string{
|
|
||||||
"legal",
|
|
||||||
"notice",
|
|
||||||
"disclaimer",
|
|
||||||
"patent",
|
|
||||||
"third-party",
|
|
||||||
"thirdparty",
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsLicenseFile returns true if the filename might be contain a
|
|
||||||
// software license
|
|
||||||
func IsLicenseFile(filename string) bool {
|
|
||||||
lowerfile := strings.ToLower(filename)
|
|
||||||
for _, prefix := range LicenseFilePrefix {
|
|
||||||
if strings.HasPrefix(lowerfile, prefix) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsLegalFile returns true if the file is likely to contain some type
|
|
||||||
// of of legal declaration or licensing information
|
|
||||||
func IsLegalFile(filename string) bool {
|
|
||||||
lowerfile := strings.ToLower(filename)
|
|
||||||
for _, prefix := range LicenseFilePrefix {
|
|
||||||
if strings.HasPrefix(lowerfile, prefix) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for _, substring := range LegalFileSubstring {
|
|
||||||
if strings.Contains(lowerfile, substring) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
|
@ -1,601 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"go/build"
|
|
||||||
"go/parser"
|
|
||||||
"go/token"
|
|
||||||
"log"
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
"regexp"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
"unicode"
|
|
||||||
|
|
||||||
pathpkg "path"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
gorootSrc = filepath.Join(build.Default.GOROOT, "src")
|
|
||||||
ignoreTags = []string{"appengine", "ignore"} //TODO: appengine is a special case for now: https://github.com/tools/godep/issues/353
|
|
||||||
versionMatch = regexp.MustCompile(`\Ago\d+\.\d+\z`)
|
|
||||||
versionNegativeMatch = regexp.MustCompile(`\A\!go\d+\.\d+\z`)
|
|
||||||
)
|
|
||||||
|
|
||||||
type errorMissingDep struct {
|
|
||||||
i, dir string // import, dir
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e errorMissingDep) Error() string {
|
|
||||||
return "Unable to find dependent package " + e.i + " in context of " + e.dir
|
|
||||||
}
|
|
||||||
|
|
||||||
// packageContext is used to track an import and which package imported it.
|
|
||||||
type packageContext struct {
|
|
||||||
pkg *build.Package // package that imports the import
|
|
||||||
imp string // import
|
|
||||||
}
|
|
||||||
|
|
||||||
// depScanner tracks the processed and to be processed packageContexts
|
|
||||||
type depScanner struct {
|
|
||||||
processed []packageContext
|
|
||||||
todo []packageContext
|
|
||||||
}
|
|
||||||
|
|
||||||
// Next package and import to process
|
|
||||||
func (ds *depScanner) Next() (*build.Package, string) {
|
|
||||||
c := ds.todo[0]
|
|
||||||
ds.processed = append(ds.processed, c)
|
|
||||||
ds.todo = ds.todo[1:]
|
|
||||||
return c.pkg, c.imp
|
|
||||||
}
|
|
||||||
|
|
||||||
// Continue looping?
|
|
||||||
func (ds *depScanner) Continue() bool {
|
|
||||||
return len(ds.todo) > 0
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add a package and imports to the depScanner. Skips already processed/pending package/import combos
|
|
||||||
func (ds *depScanner) Add(pkg *build.Package, imports ...string) {
|
|
||||||
NextImport:
|
|
||||||
for _, i := range imports {
|
|
||||||
if i == "C" {
|
|
||||||
i = "runtime/cgo"
|
|
||||||
}
|
|
||||||
for _, epc := range ds.processed {
|
|
||||||
if pkg.Dir == epc.pkg.Dir && i == epc.imp {
|
|
||||||
debugln("ctxts epc.pkg.Dir == pkg.Dir && i == epc.imp, skipping", epc.pkg.Dir, i)
|
|
||||||
continue NextImport
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for _, epc := range ds.todo {
|
|
||||||
if pkg.Dir == epc.pkg.Dir && i == epc.imp {
|
|
||||||
debugln("ctxts epc.pkg.Dir == pkg.Dir && i == epc.imp, skipping", epc.pkg.Dir, i)
|
|
||||||
continue NextImport
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pc := packageContext{pkg, i}
|
|
||||||
debugln("Adding pc:", pc.pkg.Dir, pc.imp)
|
|
||||||
ds.todo = append(ds.todo, pc)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
pkgCache = make(map[string]*build.Package) // dir => *build.Package
|
|
||||||
)
|
|
||||||
|
|
||||||
// returns the package in dir either from a cache or by importing it and then caching it
|
|
||||||
func fullPackageInDir(dir string) (*build.Package, error) {
|
|
||||||
var err error
|
|
||||||
pkg, ok := pkgCache[dir]
|
|
||||||
if !ok {
|
|
||||||
pkg, _ = build.ImportDir(dir, build.FindOnly)
|
|
||||||
if pkg.Goroot {
|
|
||||||
pkg, err = build.ImportDir(pkg.Dir, 0)
|
|
||||||
} else {
|
|
||||||
err = fillPackage(pkg)
|
|
||||||
}
|
|
||||||
if err == nil {
|
|
||||||
pkgCache[dir] = pkg
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return pkg, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// listPackage specified by path
|
|
||||||
func listPackage(path string) (*Package, error) {
|
|
||||||
debugln("listPackage", path)
|
|
||||||
var lp *build.Package
|
|
||||||
dir, err := findDirForPath(path, nil)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
lp, err = fullPackageInDir(dir)
|
|
||||||
p := &Package{
|
|
||||||
Dir: lp.Dir,
|
|
||||||
Root: lp.Root,
|
|
||||||
ImportPath: lp.ImportPath,
|
|
||||||
XTestImports: lp.XTestImports,
|
|
||||||
TestImports: lp.TestImports,
|
|
||||||
GoFiles: lp.GoFiles,
|
|
||||||
CgoFiles: lp.CgoFiles,
|
|
||||||
TestGoFiles: lp.TestGoFiles,
|
|
||||||
XTestGoFiles: lp.XTestGoFiles,
|
|
||||||
IgnoredGoFiles: lp.IgnoredGoFiles,
|
|
||||||
}
|
|
||||||
p.Standard = lp.Goroot && lp.ImportPath != "" && !strings.Contains(lp.ImportPath, ".")
|
|
||||||
if err != nil || p.Standard {
|
|
||||||
return p, err
|
|
||||||
}
|
|
||||||
debugln("Looking For Package:", path, "in", dir)
|
|
||||||
ppln(lp)
|
|
||||||
|
|
||||||
ds := depScanner{}
|
|
||||||
ds.Add(lp, lp.Imports...)
|
|
||||||
for ds.Continue() {
|
|
||||||
ip, i := ds.Next()
|
|
||||||
|
|
||||||
debugf("Processing import %s for %s\n", i, ip.Dir)
|
|
||||||
pdir, err := findDirForPath(i, ip)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
dp, err := fullPackageInDir(pdir)
|
|
||||||
if err != nil { // This really should happen in this context though
|
|
||||||
ppln(err)
|
|
||||||
return nil, errorMissingDep{i: i, dir: ip.Dir}
|
|
||||||
}
|
|
||||||
ppln(dp)
|
|
||||||
if !dp.Goroot {
|
|
||||||
// Don't bother adding packages in GOROOT to the dependency scanner, they don't import things from outside of it.
|
|
||||||
ds.Add(dp, dp.Imports...)
|
|
||||||
}
|
|
||||||
debugln("lp:")
|
|
||||||
ppln(lp)
|
|
||||||
debugln("ip:")
|
|
||||||
ppln(ip)
|
|
||||||
if lp == ip {
|
|
||||||
debugln("lp == ip")
|
|
||||||
p.Imports = append(p.Imports, dp.ImportPath)
|
|
||||||
}
|
|
||||||
p.Deps = append(p.Deps, dp.ImportPath)
|
|
||||||
p.Dependencies = addDependency(p.Dependencies, dp)
|
|
||||||
}
|
|
||||||
p.Imports = uniq(p.Imports)
|
|
||||||
p.Deps = uniq(p.Deps)
|
|
||||||
debugln("Done Looking For Package:", path, "in", dir)
|
|
||||||
ppln(p)
|
|
||||||
return p, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func addDependency(deps []build.Package, d *build.Package) []build.Package {
|
|
||||||
for i := range deps {
|
|
||||||
if deps[i].Dir == d.Dir {
|
|
||||||
return deps
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return append(deps, *d)
|
|
||||||
}
|
|
||||||
|
|
||||||
// finds the directory for the given import path in the context of the provided build.Package (if provided)
|
|
||||||
func findDirForPath(path string, ip *build.Package) (string, error) {
|
|
||||||
debugln("findDirForPath", path, ip)
|
|
||||||
var search []string
|
|
||||||
|
|
||||||
if build.IsLocalImport(path) {
|
|
||||||
dir := path
|
|
||||||
if !filepath.IsAbs(dir) {
|
|
||||||
if abs, err := filepath.Abs(dir); err == nil {
|
|
||||||
// interpret relative to current directory
|
|
||||||
dir = abs
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return dir, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// We need to check to see if the import exists in vendor/ folders up the hierarchy of the importing package
|
|
||||||
if VendorExperiment && ip != nil {
|
|
||||||
debugln("resolving vendor posibilities:", ip.Dir, ip.Root)
|
|
||||||
cr := cleanPath(ip.Root)
|
|
||||||
|
|
||||||
for base := cleanPath(ip.Dir); !pathEqual(base, cr); base = cleanPath(filepath.Dir(base)) {
|
|
||||||
s := filepath.Join(base, "vendor", path)
|
|
||||||
debugln("Adding search dir:", s)
|
|
||||||
search = append(search, s)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, base := range build.Default.SrcDirs() {
|
|
||||||
search = append(search, filepath.Join(base, path))
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, dir := range search {
|
|
||||||
debugln("searching", dir)
|
|
||||||
fi, err := stat(dir)
|
|
||||||
if err == nil && fi.IsDir() {
|
|
||||||
return dir, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return "", errPackageNotFound{path}
|
|
||||||
}
|
|
||||||
|
|
||||||
type statEntry struct {
|
|
||||||
fi os.FileInfo
|
|
||||||
err error
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
statCache = make(map[string]statEntry)
|
|
||||||
)
|
|
||||||
|
|
||||||
func clearStatCache() {
|
|
||||||
statCache = make(map[string]statEntry)
|
|
||||||
}
|
|
||||||
|
|
||||||
func stat(p string) (os.FileInfo, error) {
|
|
||||||
if e, ok := statCache[p]; ok {
|
|
||||||
return e.fi, e.err
|
|
||||||
}
|
|
||||||
fi, err := os.Stat(p)
|
|
||||||
statCache[p] = statEntry{fi, err}
|
|
||||||
return fi, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// fillPackage full of info. Assumes p.Dir is set at a minimum
|
|
||||||
func fillPackage(p *build.Package) error {
|
|
||||||
if p.Goroot {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if p.SrcRoot == "" {
|
|
||||||
for _, base := range build.Default.SrcDirs() {
|
|
||||||
if strings.HasPrefix(p.Dir, base) {
|
|
||||||
p.SrcRoot = base
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if p.SrcRoot == "" {
|
|
||||||
return errors.New("Unable to find SrcRoot for package " + p.ImportPath)
|
|
||||||
}
|
|
||||||
|
|
||||||
if p.Root == "" {
|
|
||||||
p.Root = filepath.Dir(p.SrcRoot)
|
|
||||||
}
|
|
||||||
|
|
||||||
var buildMatch = "+build "
|
|
||||||
var buildFieldSplit = func(r rune) bool {
|
|
||||||
return unicode.IsSpace(r) || r == ','
|
|
||||||
}
|
|
||||||
|
|
||||||
debugln("Filling package:", p.ImportPath, "from", p.Dir)
|
|
||||||
gofiles, err := filepath.Glob(filepath.Join(p.Dir, "*.go"))
|
|
||||||
if err != nil {
|
|
||||||
debugln("Error globbing", err)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(gofiles) == 0 {
|
|
||||||
return &build.NoGoError{Dir: p.Dir}
|
|
||||||
}
|
|
||||||
|
|
||||||
var testImports []string
|
|
||||||
var imports []string
|
|
||||||
NextFile:
|
|
||||||
for _, file := range gofiles {
|
|
||||||
debugln(file)
|
|
||||||
pf, err := parser.ParseFile(token.NewFileSet(), file, nil, parser.ImportsOnly|parser.ParseComments)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
testFile := strings.HasSuffix(file, "_test.go")
|
|
||||||
fname := filepath.Base(file)
|
|
||||||
for _, c := range pf.Comments {
|
|
||||||
ct := c.Text()
|
|
||||||
if i := strings.Index(ct, buildMatch); i != -1 {
|
|
||||||
for _, t := range strings.FieldsFunc(ct[i+len(buildMatch):], buildFieldSplit) {
|
|
||||||
for _, tag := range ignoreTags {
|
|
||||||
if t == tag {
|
|
||||||
p.IgnoredGoFiles = append(p.IgnoredGoFiles, fname)
|
|
||||||
continue NextFile
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if versionMatch.MatchString(t) && !isSameOrNewer(t, majorGoVersion) {
|
|
||||||
debugln("Adding", fname, "to ignored list because of version tag", t)
|
|
||||||
p.IgnoredGoFiles = append(p.IgnoredGoFiles, fname)
|
|
||||||
continue NextFile
|
|
||||||
}
|
|
||||||
if versionNegativeMatch.MatchString(t) && isSameOrNewer(t[1:], majorGoVersion) {
|
|
||||||
debugln("Adding", fname, "to ignored list because of version tag", t)
|
|
||||||
p.IgnoredGoFiles = append(p.IgnoredGoFiles, fname)
|
|
||||||
continue NextFile
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if testFile {
|
|
||||||
p.TestGoFiles = append(p.TestGoFiles, fname)
|
|
||||||
} else {
|
|
||||||
p.GoFiles = append(p.GoFiles, fname)
|
|
||||||
}
|
|
||||||
for _, is := range pf.Imports {
|
|
||||||
name, err := strconv.Unquote(is.Path.Value)
|
|
||||||
if err != nil {
|
|
||||||
return err // can't happen?
|
|
||||||
}
|
|
||||||
if testFile {
|
|
||||||
testImports = append(testImports, name)
|
|
||||||
} else {
|
|
||||||
imports = append(imports, name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
imports = uniq(imports)
|
|
||||||
testImports = uniq(testImports)
|
|
||||||
p.Imports = imports
|
|
||||||
p.TestImports = testImports
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// All of the following functions were vendored from go proper. Locations are noted in comments, but may change in future Go versions.
|
|
||||||
|
|
||||||
// importPaths returns the import paths to use for the given command line.
|
|
||||||
// $GOROOT/src/cmd/main.go:366
|
|
||||||
func importPaths(args []string) []string {
|
|
||||||
debugf("importPathsNoDotExpansion(%q) == ", args)
|
|
||||||
args = importPathsNoDotExpansion(args)
|
|
||||||
debugf("%q\n", args)
|
|
||||||
var out []string
|
|
||||||
for _, a := range args {
|
|
||||||
if strings.Contains(a, "...") {
|
|
||||||
if build.IsLocalImport(a) {
|
|
||||||
debugf("build.IsLocalImport(%q) == true\n", a)
|
|
||||||
pkgs := allPackagesInFS(a)
|
|
||||||
debugf("allPackagesInFS(%q) == %q\n", a, pkgs)
|
|
||||||
out = append(out, pkgs...)
|
|
||||||
} else {
|
|
||||||
debugf("build.IsLocalImport(%q) == false\n", a)
|
|
||||||
pkgs := allPackages(a)
|
|
||||||
debugf("allPackages(%q) == %q\n", a, pkgs)
|
|
||||||
out = append(out, allPackages(a)...)
|
|
||||||
}
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
out = append(out, a)
|
|
||||||
}
|
|
||||||
return out
|
|
||||||
}
|
|
||||||
|
|
||||||
// importPathsNoDotExpansion returns the import paths to use for the given
|
|
||||||
// command line, but it does no ... expansion.
|
|
||||||
// $GOROOT/src/cmd/main.go:332
|
|
||||||
func importPathsNoDotExpansion(args []string) []string {
|
|
||||||
if len(args) == 0 {
|
|
||||||
return []string{"."}
|
|
||||||
}
|
|
||||||
var out []string
|
|
||||||
for _, a := range args {
|
|
||||||
// Arguments are supposed to be import paths, but
|
|
||||||
// as a courtesy to Windows developers, rewrite \ to /
|
|
||||||
// in command-line arguments. Handles .\... and so on.
|
|
||||||
if filepath.Separator == '\\' {
|
|
||||||
a = strings.Replace(a, `\`, `/`, -1)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Put argument in canonical form, but preserve leading ./.
|
|
||||||
if strings.HasPrefix(a, "./") {
|
|
||||||
a = "./" + pathpkg.Clean(a)
|
|
||||||
if a == "./." {
|
|
||||||
a = "."
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
a = pathpkg.Clean(a)
|
|
||||||
}
|
|
||||||
if a == "all" || a == "std" || a == "cmd" {
|
|
||||||
out = append(out, allPackages(a)...)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
out = append(out, a)
|
|
||||||
}
|
|
||||||
return out
|
|
||||||
}
|
|
||||||
|
|
||||||
// allPackagesInFS is like allPackages but is passed a pattern
|
|
||||||
// beginning ./ or ../, meaning it should scan the tree rooted
|
|
||||||
// at the given directory. There are ... in the pattern too.
|
|
||||||
// $GOROOT/src/cmd/main.go:620
|
|
||||||
func allPackagesInFS(pattern string) []string {
|
|
||||||
pkgs := matchPackagesInFS(pattern)
|
|
||||||
if len(pkgs) == 0 {
|
|
||||||
fmt.Fprintf(os.Stderr, "warning: %q matched no packages\n", pattern)
|
|
||||||
}
|
|
||||||
return pkgs
|
|
||||||
}
|
|
||||||
|
|
||||||
// allPackages returns all the packages that can be found
|
|
||||||
// under the $GOPATH directories and $GOROOT matching pattern.
|
|
||||||
// The pattern is either "all" (all packages), "std" (standard packages),
|
|
||||||
// "cmd" (standard commands), or a path including "...".
|
|
||||||
// $GOROOT/src/cmd/main.go:542
|
|
||||||
func allPackages(pattern string) []string {
|
|
||||||
pkgs := matchPackages(pattern)
|
|
||||||
if len(pkgs) == 0 {
|
|
||||||
fmt.Fprintf(os.Stderr, "warning: %q matched no packages\n", pattern)
|
|
||||||
}
|
|
||||||
return pkgs
|
|
||||||
}
|
|
||||||
|
|
||||||
// $GOROOT/src/cmd/main.go:554
|
|
||||||
// This has been changed to not use build.ImportDir
|
|
||||||
func matchPackages(pattern string) []string {
|
|
||||||
match := func(string) bool { return true }
|
|
||||||
treeCanMatch := func(string) bool { return true }
|
|
||||||
if pattern != "all" && pattern != "std" && pattern != "cmd" {
|
|
||||||
match = matchPattern(pattern)
|
|
||||||
treeCanMatch = treeCanMatchPattern(pattern)
|
|
||||||
}
|
|
||||||
|
|
||||||
have := map[string]bool{
|
|
||||||
"builtin": true, // ignore pseudo-package that exists only for documentation
|
|
||||||
}
|
|
||||||
if !build.Default.CgoEnabled {
|
|
||||||
have["runtime/cgo"] = true // ignore during walk
|
|
||||||
}
|
|
||||||
var pkgs []string
|
|
||||||
|
|
||||||
for _, src := range build.Default.SrcDirs() {
|
|
||||||
if (pattern == "std" || pattern == "cmd") && src != gorootSrc {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
src = filepath.Clean(src) + string(filepath.Separator)
|
|
||||||
root := src
|
|
||||||
if pattern == "cmd" {
|
|
||||||
root += "cmd" + string(filepath.Separator)
|
|
||||||
}
|
|
||||||
filepath.Walk(root, func(path string, fi os.FileInfo, err error) error {
|
|
||||||
if err != nil || !fi.IsDir() || path == src {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Avoid .foo, _foo, and testdata directory trees.
|
|
||||||
_, elem := filepath.Split(path)
|
|
||||||
if strings.HasPrefix(elem, ".") || strings.HasPrefix(elem, "_") || elem == "testdata" {
|
|
||||||
return filepath.SkipDir
|
|
||||||
}
|
|
||||||
|
|
||||||
name := filepath.ToSlash(path[len(src):])
|
|
||||||
if pattern == "std" && (strings.Contains(name, ".") || name == "cmd") {
|
|
||||||
// The name "std" is only the standard library.
|
|
||||||
// If the name has a dot, assume it's a domain name for go get,
|
|
||||||
// and if the name is cmd, it's the root of the command tree.
|
|
||||||
return filepath.SkipDir
|
|
||||||
}
|
|
||||||
if !treeCanMatch(name) {
|
|
||||||
return filepath.SkipDir
|
|
||||||
}
|
|
||||||
if have[name] {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
have[name] = true
|
|
||||||
if !match(name) {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
ap, err := filepath.Abs(path)
|
|
||||||
if err != nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
if _, err = fullPackageInDir(ap); err != nil {
|
|
||||||
debugf("matchPackage(%q) ap=%q Error: %q\n", ap, pattern, err)
|
|
||||||
if _, noGo := err.(*build.NoGoError); noGo {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pkgs = append(pkgs, name)
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
}
|
|
||||||
return pkgs
|
|
||||||
}
|
|
||||||
|
|
||||||
// treeCanMatchPattern(pattern)(name) reports whether
|
|
||||||
// name or children of name can possibly match pattern.
|
|
||||||
// Pattern is the same limited glob accepted by matchPattern.
|
|
||||||
// $GOROOT/src/cmd/main.go:527
|
|
||||||
func treeCanMatchPattern(pattern string) func(name string) bool {
|
|
||||||
wildCard := false
|
|
||||||
if i := strings.Index(pattern, "..."); i >= 0 {
|
|
||||||
wildCard = true
|
|
||||||
pattern = pattern[:i]
|
|
||||||
}
|
|
||||||
return func(name string) bool {
|
|
||||||
return len(name) <= len(pattern) && hasPathPrefix(pattern, name) ||
|
|
||||||
wildCard && strings.HasPrefix(name, pattern)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// hasPathPrefix reports whether the path s begins with the
|
|
||||||
// elements in prefix.
|
|
||||||
// $GOROOT/src/cmd/main.go:489
|
|
||||||
func hasPathPrefix(s, prefix string) bool {
|
|
||||||
switch {
|
|
||||||
default:
|
|
||||||
return false
|
|
||||||
case len(s) == len(prefix):
|
|
||||||
return s == prefix
|
|
||||||
case len(s) > len(prefix):
|
|
||||||
if prefix != "" && prefix[len(prefix)-1] == '/' {
|
|
||||||
return strings.HasPrefix(s, prefix)
|
|
||||||
}
|
|
||||||
return s[len(prefix)] == '/' && s[:len(prefix)] == prefix
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// $GOROOT/src/cmd/go/main.go:631
|
|
||||||
// This has been changed to not use build.ImportDir
|
|
||||||
func matchPackagesInFS(pattern string) []string {
|
|
||||||
// Find directory to begin the scan.
|
|
||||||
// Could be smarter but this one optimization
|
|
||||||
// is enough for now, since ... is usually at the
|
|
||||||
// end of a path.
|
|
||||||
i := strings.Index(pattern, "...")
|
|
||||||
dir, _ := pathpkg.Split(pattern[:i])
|
|
||||||
|
|
||||||
// pattern begins with ./ or ../.
|
|
||||||
// path.Clean will discard the ./ but not the ../.
|
|
||||||
// We need to preserve the ./ for pattern matching
|
|
||||||
// and in the returned import paths.
|
|
||||||
prefix := ""
|
|
||||||
if strings.HasPrefix(pattern, "./") {
|
|
||||||
prefix = "./"
|
|
||||||
}
|
|
||||||
match := matchPattern(pattern)
|
|
||||||
|
|
||||||
var pkgs []string
|
|
||||||
filepath.Walk(dir, func(path string, fi os.FileInfo, err error) error {
|
|
||||||
if err != nil || !fi.IsDir() {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
if path == dir {
|
|
||||||
// filepath.Walk starts at dir and recurses. For the recursive case,
|
|
||||||
// the path is the result of filepath.Join, which calls filepath.Clean.
|
|
||||||
// The initial case is not Cleaned, though, so we do this explicitly.
|
|
||||||
//
|
|
||||||
// This converts a path like "./io/" to "io". Without this step, running
|
|
||||||
// "cd $GOROOT/src; go list ./io/..." would incorrectly skip the io
|
|
||||||
// package, because prepending the prefix "./" to the unclean path would
|
|
||||||
// result in "././io", and match("././io") returns false.
|
|
||||||
path = filepath.Clean(path)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Avoid .foo, _foo, and testdata directory trees, but do not avoid "." or "..".
|
|
||||||
_, elem := filepath.Split(path)
|
|
||||||
dot := strings.HasPrefix(elem, ".") && elem != "." && elem != ".."
|
|
||||||
if dot || strings.HasPrefix(elem, "_") || elem == "testdata" {
|
|
||||||
return filepath.SkipDir
|
|
||||||
}
|
|
||||||
|
|
||||||
name := prefix + filepath.ToSlash(path)
|
|
||||||
if !match(name) {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
ap, err := filepath.Abs(path)
|
|
||||||
if err != nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
if _, err = fullPackageInDir(ap); err != nil {
|
|
||||||
debugf("matchPackageInFS(%q) ap=%q Error: %q\n", ap, pattern, err)
|
|
||||||
if _, noGo := err.(*build.NoGoError); !noGo {
|
|
||||||
log.Print(err)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
pkgs = append(pkgs, name)
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
return pkgs
|
|
||||||
}
|
|
|
@ -1,255 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"flag"
|
|
||||||
"fmt"
|
|
||||||
"go/build"
|
|
||||||
"io"
|
|
||||||
"log"
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
"runtime/pprof"
|
|
||||||
"strings"
|
|
||||||
"text/template"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
cpuprofile string
|
|
||||||
verbose bool // Verbose flag for commands that support it
|
|
||||||
debug bool // Debug flag for commands that support it
|
|
||||||
majorGoVersion string
|
|
||||||
VendorExperiment bool
|
|
||||||
sep string
|
|
||||||
)
|
|
||||||
|
|
||||||
// Command is an implementation of a godep command
|
|
||||||
// like godep save or godep go.
|
|
||||||
type Command struct {
|
|
||||||
// Run runs the command.
|
|
||||||
// The args are the arguments after the command name.
|
|
||||||
Run func(cmd *Command, args []string)
|
|
||||||
|
|
||||||
// Name of the command
|
|
||||||
Name string
|
|
||||||
|
|
||||||
// Args the command would expect
|
|
||||||
Args string
|
|
||||||
|
|
||||||
// Short is the short description shown in the 'godep help' output.
|
|
||||||
Short string
|
|
||||||
|
|
||||||
// Long is the long message shown in the
|
|
||||||
// 'godep help <this-command>' output.
|
|
||||||
Long string
|
|
||||||
|
|
||||||
// Flag is a set of flags specific to this command.
|
|
||||||
Flag flag.FlagSet
|
|
||||||
|
|
||||||
// OnlyInGOPATH limits this command to being run only while inside of a GOPATH
|
|
||||||
OnlyInGOPATH bool
|
|
||||||
}
|
|
||||||
|
|
||||||
// UsageExit prints usage information and exits.
|
|
||||||
func (c *Command) UsageExit() {
|
|
||||||
fmt.Fprintf(os.Stderr, "Args: godep %s [-v] [-d] %s\n\n", c.Name, c.Args)
|
|
||||||
fmt.Fprintf(os.Stderr, "Run 'godep help %s' for help.\n", c.Name)
|
|
||||||
os.Exit(2)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Commands lists the available commands and help topics.
|
|
||||||
// The order here is the order in which they are printed
|
|
||||||
// by 'godep help'.
|
|
||||||
var commands = []*Command{
|
|
||||||
cmdSave,
|
|
||||||
cmdGo,
|
|
||||||
cmdGet,
|
|
||||||
cmdPath,
|
|
||||||
cmdRestore,
|
|
||||||
cmdUpdate,
|
|
||||||
cmdDiff,
|
|
||||||
cmdVersion,
|
|
||||||
}
|
|
||||||
|
|
||||||
// VendorExperiment is the Go 1.5 vendor directory experiment flag, see
|
|
||||||
// https://github.com/golang/go/commit/183cc0cd41f06f83cb7a2490a499e3f9101befff
|
|
||||||
// Honor the env var unless the project already has an old school godep workspace
|
|
||||||
func determineVendor(v string) bool {
|
|
||||||
go15ve := os.Getenv("GO15VENDOREXPERIMENT")
|
|
||||||
var ev bool
|
|
||||||
switch v {
|
|
||||||
case "go1", "go1.1", "go1.2", "go1.3", "go1.4":
|
|
||||||
ev = false
|
|
||||||
case "go1.5":
|
|
||||||
ev = go15ve == "1"
|
|
||||||
case "go1.6":
|
|
||||||
ev = go15ve != "0"
|
|
||||||
default: //go1.7+, devel*
|
|
||||||
ev = true
|
|
||||||
}
|
|
||||||
|
|
||||||
ws := filepath.Join("Godeps", "_workspace")
|
|
||||||
s, err := os.Stat(ws)
|
|
||||||
if err == nil && s.IsDir() {
|
|
||||||
log.Printf("WARNING: Godep workspaces (./Godeps/_workspace) are deprecated and support for them will be removed when go1.8 is released.")
|
|
||||||
if ev {
|
|
||||||
log.Printf("WARNING: Go version (%s) & $GO15VENDOREXPERIMENT=%s wants to enable the vendor experiment, but disabling because a Godep workspace (%s) exists\n", v, go15ve, ws)
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
return ev
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
log.SetFlags(0)
|
|
||||||
log.SetPrefix("godep: ")
|
|
||||||
log.SetOutput(os.Stderr)
|
|
||||||
|
|
||||||
flag.Usage = usageExit
|
|
||||||
flag.Parse()
|
|
||||||
args := flag.Args()
|
|
||||||
if len(args) < 1 {
|
|
||||||
usageExit()
|
|
||||||
}
|
|
||||||
|
|
||||||
if args[0] == "help" {
|
|
||||||
help(args[1:])
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
var err error
|
|
||||||
majorGoVersion, err = goVersion()
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, cmd := range commands {
|
|
||||||
if cmd.Name == args[0] {
|
|
||||||
if cmd.OnlyInGOPATH {
|
|
||||||
checkInGOPATH()
|
|
||||||
}
|
|
||||||
|
|
||||||
VendorExperiment = determineVendor(majorGoVersion)
|
|
||||||
// sep is the signature set of path elements that
|
|
||||||
// precede the original path of an imported package.
|
|
||||||
sep = defaultSep(VendorExperiment)
|
|
||||||
|
|
||||||
cmd.Flag.BoolVar(&verbose, "v", false, "enable verbose output")
|
|
||||||
cmd.Flag.BoolVar(&debug, "d", false, "enable debug output")
|
|
||||||
cmd.Flag.StringVar(&cpuprofile, "cpuprofile", "", "Write cpu profile to this file")
|
|
||||||
cmd.Flag.Usage = func() { cmd.UsageExit() }
|
|
||||||
cmd.Flag.Parse(args[1:])
|
|
||||||
|
|
||||||
debugln("versionString()", versionString())
|
|
||||||
debugln("majorGoVersion", majorGoVersion)
|
|
||||||
debugln("VendorExperiment", VendorExperiment)
|
|
||||||
debugln("sep", sep)
|
|
||||||
|
|
||||||
if cpuprofile != "" {
|
|
||||||
f, err := os.Create(cpuprofile)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
pprof.StartCPUProfile(f)
|
|
||||||
defer pprof.StopCPUProfile()
|
|
||||||
}
|
|
||||||
cmd.Run(cmd, cmd.Flag.Args())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Fprintf(os.Stderr, "godep: unknown command %q\n", args[0])
|
|
||||||
fmt.Fprintf(os.Stderr, "Run 'godep help' for usage.\n")
|
|
||||||
os.Exit(2)
|
|
||||||
}
|
|
||||||
|
|
||||||
func subPath(sub, path string) bool {
|
|
||||||
ls := strings.ToLower(sub)
|
|
||||||
lp := strings.ToLower(path)
|
|
||||||
if ls == lp {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return strings.HasPrefix(ls, lp)
|
|
||||||
}
|
|
||||||
|
|
||||||
func checkInGOPATH() {
|
|
||||||
pwd, err := os.Getwd()
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal("Unable to determine current working directory", err)
|
|
||||||
}
|
|
||||||
dirs := build.Default.SrcDirs()
|
|
||||||
for _, p := range dirs {
|
|
||||||
if ok := subPath(pwd, p); ok {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Println("[WARNING]: godep should only be used inside a valid go package directory and")
|
|
||||||
log.Println("[WARNING]: may not function correctly. You are probably outside of your $GOPATH.")
|
|
||||||
log.Printf("[WARNING]:\tCurrent Directory: %s\n", pwd)
|
|
||||||
log.Printf("[WARNING]:\t$GOPATH: %s\n", os.Getenv("GOPATH"))
|
|
||||||
}
|
|
||||||
|
|
||||||
var usageTemplate = `
|
|
||||||
Godep is a tool for managing Go package dependencies.
|
|
||||||
|
|
||||||
Usage:
|
|
||||||
|
|
||||||
godep command [arguments]
|
|
||||||
|
|
||||||
The commands are:
|
|
||||||
{{range .}}
|
|
||||||
{{.Name | printf "%-8s"}} {{.Short}}{{end}}
|
|
||||||
|
|
||||||
Use "godep help [command]" for more information about a command.
|
|
||||||
`
|
|
||||||
|
|
||||||
var helpTemplate = `
|
|
||||||
Args: godep {{.Name}} [-v] [-d] {{.Args}}
|
|
||||||
|
|
||||||
{{.Long | trim}}
|
|
||||||
|
|
||||||
If -v is given, verbose output is enabled.
|
|
||||||
|
|
||||||
If -d is given, debug output is enabled (you probably don't want this, see -v).
|
|
||||||
|
|
||||||
`
|
|
||||||
|
|
||||||
func help(args []string) {
|
|
||||||
if len(args) == 0 {
|
|
||||||
printUsage(os.Stdout)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if len(args) != 1 {
|
|
||||||
fmt.Fprintf(os.Stderr, "usage: godep help command\n\n")
|
|
||||||
fmt.Fprintf(os.Stderr, "Too many arguments given.\n")
|
|
||||||
os.Exit(2)
|
|
||||||
}
|
|
||||||
for _, cmd := range commands {
|
|
||||||
if cmd.Name == args[0] {
|
|
||||||
tmpl(os.Stdout, helpTemplate, cmd)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func usageExit() {
|
|
||||||
printUsage(os.Stderr)
|
|
||||||
os.Exit(2)
|
|
||||||
}
|
|
||||||
|
|
||||||
func printUsage(w io.Writer) {
|
|
||||||
tmpl(w, usageTemplate, commands)
|
|
||||||
}
|
|
||||||
|
|
||||||
// tmpl executes the given template text on data, writing the result to w.
|
|
||||||
func tmpl(w io.Writer, text string, data interface{}) {
|
|
||||||
t := template.New("top")
|
|
||||||
t.Funcs(template.FuncMap{
|
|
||||||
"trim": strings.TrimSpace,
|
|
||||||
})
|
|
||||||
template.Must(t.Parse(strings.TrimSpace(text) + "\n\n"))
|
|
||||||
if err := t.Execute(w, data); err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,35 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"log"
|
|
||||||
|
|
||||||
"github.com/kr/pretty"
|
|
||||||
)
|
|
||||||
|
|
||||||
func debugln(a ...interface{}) (int, error) {
|
|
||||||
if debug {
|
|
||||||
return fmt.Println(a...)
|
|
||||||
}
|
|
||||||
return 0, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func verboseln(a ...interface{}) {
|
|
||||||
if verbose {
|
|
||||||
log.Println(a...)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func debugf(format string, a ...interface{}) (int, error) {
|
|
||||||
if debug {
|
|
||||||
return fmt.Printf(format, a...)
|
|
||||||
}
|
|
||||||
return 0, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func ppln(a ...interface{}) (int, error) {
|
|
||||||
if debug {
|
|
||||||
return pretty.Println(a...)
|
|
||||||
}
|
|
||||||
return 0, nil
|
|
||||||
}
|
|
|
@ -1,36 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
)
|
|
||||||
|
|
||||||
var cmdPath = &Command{
|
|
||||||
Name: "path",
|
|
||||||
Short: "print GOPATH for dependency code",
|
|
||||||
Long: `
|
|
||||||
Command path prints a path for use in env var GOPATH
|
|
||||||
that makes available the specified version of each dependency.
|
|
||||||
|
|
||||||
The printed path does not include any GOPATH value from
|
|
||||||
the environment.
|
|
||||||
|
|
||||||
For more about how GOPATH works, see 'go help gopath'.
|
|
||||||
`,
|
|
||||||
Run: runPath,
|
|
||||||
OnlyInGOPATH: true,
|
|
||||||
}
|
|
||||||
|
|
||||||
// Print the gopath that points to
|
|
||||||
// the included dependency code.
|
|
||||||
func runPath(cmd *Command, args []string) {
|
|
||||||
if len(args) != 0 {
|
|
||||||
cmd.UsageExit()
|
|
||||||
}
|
|
||||||
if VendorExperiment {
|
|
||||||
fmt.Fprintln(os.Stderr, "Error: GO15VENDOREXPERIMENT is enabled and the vendor/ directory is not a valid Go workspace.")
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
gopath := prepareGopath()
|
|
||||||
fmt.Println(gopath)
|
|
||||||
}
|
|
|
@ -1,94 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"go/build"
|
|
||||||
"os"
|
|
||||||
"regexp"
|
|
||||||
"sort"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Package represents a Go package.
|
|
||||||
type Package struct {
|
|
||||||
Dir string
|
|
||||||
Root string
|
|
||||||
ImportPath string
|
|
||||||
Deps []string
|
|
||||||
Standard bool
|
|
||||||
Processed bool
|
|
||||||
|
|
||||||
GoFiles []string
|
|
||||||
CgoFiles []string
|
|
||||||
IgnoredGoFiles []string
|
|
||||||
|
|
||||||
TestGoFiles []string
|
|
||||||
TestImports []string
|
|
||||||
XTestGoFiles []string
|
|
||||||
XTestImports []string
|
|
||||||
|
|
||||||
Error struct {
|
|
||||||
Err string
|
|
||||||
}
|
|
||||||
|
|
||||||
// --- New stuff for now
|
|
||||||
Imports []string
|
|
||||||
Dependencies []build.Package
|
|
||||||
}
|
|
||||||
|
|
||||||
// LoadPackages loads the named packages
|
|
||||||
// Unlike the go tool, an empty argument list is treated as an empty list; "."
|
|
||||||
// must be given explicitly if desired.
|
|
||||||
// IgnoredGoFiles will be processed and their dependencies resolved recursively
|
|
||||||
func LoadPackages(names ...string) (a []*Package, err error) {
|
|
||||||
debugln("LoadPackages", names)
|
|
||||||
if len(names) == 0 {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
pkgs := strings.Split(ignorePackages, ",")
|
|
||||||
sort.Strings(pkgs)
|
|
||||||
for _, i := range importPaths(names) {
|
|
||||||
p, err := listPackage(i)
|
|
||||||
if err != nil {
|
|
||||||
if len(pkgs) > 0 {
|
|
||||||
idx := sort.SearchStrings(pkgs, i)
|
|
||||||
if idx < len(pkgs) && pkgs[idx] == i {
|
|
||||||
fmt.Fprintf(os.Stderr, "warning: ignoring package %q \n", i)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
a = append(a, p)
|
|
||||||
}
|
|
||||||
return a, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *Package) allGoFiles() []string {
|
|
||||||
var a []string
|
|
||||||
a = append(a, p.GoFiles...)
|
|
||||||
a = append(a, p.CgoFiles...)
|
|
||||||
a = append(a, p.TestGoFiles...)
|
|
||||||
a = append(a, p.XTestGoFiles...)
|
|
||||||
a = append(a, p.IgnoredGoFiles...)
|
|
||||||
return a
|
|
||||||
}
|
|
||||||
|
|
||||||
// matchPattern(pattern)(name) reports whether
|
|
||||||
// name matches pattern. Pattern is a limited glob
|
|
||||||
// pattern in which '...' means 'any string' and there
|
|
||||||
// is no other special syntax.
|
|
||||||
// Taken from $GOROOT/src/cmd/go/main.go.
|
|
||||||
func matchPattern(pattern string) func(name string) bool {
|
|
||||||
re := regexp.QuoteMeta(pattern)
|
|
||||||
re = strings.Replace(re, `\.\.\.`, `.*`, -1)
|
|
||||||
// Special case: foo/... matches foo too.
|
|
||||||
if strings.HasSuffix(re, `/.*`) {
|
|
||||||
re = re[:len(re)-len(`/.*`)] + `(/.*)?`
|
|
||||||
}
|
|
||||||
reg := regexp.MustCompile(`^` + re + `$`)
|
|
||||||
return func(name string) bool {
|
|
||||||
return reg.MatchString(name)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,195 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"go/build"
|
|
||||||
"log"
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
|
|
||||||
"golang.org/x/tools/go/vcs"
|
|
||||||
)
|
|
||||||
|
|
||||||
var cmdRestore = &Command{
|
|
||||||
Name: "restore",
|
|
||||||
Short: "check out listed dependency versions in GOPATH",
|
|
||||||
Long: `
|
|
||||||
Restore checks out the Godeps-specified version of each package in GOPATH.
|
|
||||||
|
|
||||||
NOTE: restore leaves git repositories in a detached state. go1.6+ no longer
|
|
||||||
checks out the master branch when doing a "go get", see:
|
|
||||||
https://github.com/golang/go/commit/42206598671a44111c8f726ad33dc7b265bdf669.
|
|
||||||
|
|
||||||
`,
|
|
||||||
Run: runRestore,
|
|
||||||
OnlyInGOPATH: true,
|
|
||||||
}
|
|
||||||
|
|
||||||
// Three phases:
|
|
||||||
// 1. Download all deps
|
|
||||||
// 2. Restore all deps (checkout the recorded rev)
|
|
||||||
// 3. Attempt to load all deps as a simple consistency check
|
|
||||||
func runRestore(cmd *Command, args []string) {
|
|
||||||
if len(build.Default.GOPATH) == 0 {
|
|
||||||
log.Println("Error restore requires GOPATH but it is empty.")
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
var hadError bool
|
|
||||||
checkErr := func(s string) {
|
|
||||||
if hadError {
|
|
||||||
log.Println(s)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
g, err := loadDefaultGodepsFile()
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalln(err)
|
|
||||||
}
|
|
||||||
for i, dep := range g.Deps {
|
|
||||||
verboseln("Downloading dependency (if needed):", dep.ImportPath)
|
|
||||||
err := download(&dep)
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("error downloading dep (%s): %s\n", dep.ImportPath, err)
|
|
||||||
hadError = true
|
|
||||||
}
|
|
||||||
g.Deps[i] = dep
|
|
||||||
}
|
|
||||||
checkErr("Error downloading some deps. Aborting restore and check.")
|
|
||||||
for _, dep := range g.Deps {
|
|
||||||
verboseln("Restoring dependency (if needed):", dep.ImportPath)
|
|
||||||
err := restore(dep)
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("error restoring dep (%s): %s\n", dep.ImportPath, err)
|
|
||||||
hadError = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
checkErr("Error restoring some deps. Aborting check.")
|
|
||||||
for _, dep := range g.Deps {
|
|
||||||
verboseln("Checking dependency:", dep.ImportPath)
|
|
||||||
_, err := LoadPackages(dep.ImportPath)
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("Dep (%s) restored, but was unable to load it with error:\n\t%s\n", dep.ImportPath, err)
|
|
||||||
if me, ok := err.(errorMissingDep); ok {
|
|
||||||
log.Println("\tThis may be because the dependencies were saved with an older version of godep (< v33).")
|
|
||||||
log.Printf("\tTry `go get %s`. Then `godep save` to update deps.\n", me.i)
|
|
||||||
}
|
|
||||||
hadError = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
checkErr("Error checking some deps.")
|
|
||||||
}
|
|
||||||
|
|
||||||
var downloaded = make(map[string]bool)
|
|
||||||
|
|
||||||
// download the given dependency.
|
|
||||||
// 2 Passes: 1) go get -d <pkg>, 2) git pull (if necessary)
|
|
||||||
func download(dep *Dependency) error {
|
|
||||||
|
|
||||||
rr, err := vcs.RepoRootForImportPath(dep.ImportPath, debug)
|
|
||||||
if err != nil {
|
|
||||||
debugln("Error determining repo root for", dep.ImportPath)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
ppln("rr", rr)
|
|
||||||
|
|
||||||
dep.vcs = cmd[rr.VCS]
|
|
||||||
|
|
||||||
// try to find an existing directory in the GOPATHs
|
|
||||||
for _, gp := range filepath.SplitList(build.Default.GOPATH) {
|
|
||||||
t := filepath.Join(gp, "src", rr.Root)
|
|
||||||
fi, err := os.Stat(t)
|
|
||||||
if err != nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if fi.IsDir() {
|
|
||||||
dep.root = t
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If none found, just pick the first GOPATH entry (AFAICT that's what go get does)
|
|
||||||
if dep.root == "" {
|
|
||||||
dep.root = filepath.Join(filepath.SplitList(build.Default.GOPATH)[0], "src", rr.Root)
|
|
||||||
}
|
|
||||||
ppln("dep", dep)
|
|
||||||
|
|
||||||
if downloaded[rr.Repo] {
|
|
||||||
verboseln("Skipping already downloaded repo", rr.Repo)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
fi, err := os.Stat(dep.root)
|
|
||||||
if err != nil {
|
|
||||||
if os.IsNotExist(err) {
|
|
||||||
if err := os.MkdirAll(filepath.Dir(dep.root), os.ModePerm); err != nil {
|
|
||||||
debugln("Error creating base dir of", dep.root)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
err := rr.VCS.CreateAtRev(dep.root, rr.Repo, dep.Rev)
|
|
||||||
debugln("CreatedAtRev", dep.root, rr.Repo, dep.Rev)
|
|
||||||
if err != nil {
|
|
||||||
debugln("CreateAtRev error", err)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
downloaded[rr.Repo] = true
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
debugln("Error checking repo root for", dep.ImportPath, "at", dep.root, ":", err)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if !fi.IsDir() {
|
|
||||||
return errors.New("repo root src dir exists, but isn't a directory for " + dep.ImportPath + " at " + dep.root)
|
|
||||||
}
|
|
||||||
|
|
||||||
if !dep.vcs.exists(dep.root, dep.Rev) {
|
|
||||||
debugln("Updating existing", dep.root)
|
|
||||||
if dep.vcs == vcsGit {
|
|
||||||
detached, err := gitDetached(dep.root)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if detached {
|
|
||||||
db, err := gitDefaultBranch(dep.root)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if err := gitCheckout(dep.root, db); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
dep.vcs.vcs.Download(dep.root)
|
|
||||||
downloaded[rr.Repo] = true
|
|
||||||
}
|
|
||||||
|
|
||||||
debugln("Nothing to download")
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
var restored = make(map[string]string) // dep.root -> dep.Rev
|
|
||||||
|
|
||||||
// restore checks out the given revision.
|
|
||||||
func restore(dep Dependency) error {
|
|
||||||
rev, ok := restored[dep.root]
|
|
||||||
debugln(rev)
|
|
||||||
debugln(ok)
|
|
||||||
debugln(dep.root)
|
|
||||||
if ok {
|
|
||||||
if rev != dep.Rev {
|
|
||||||
return errors.New("Wanted to restore rev " + dep.Rev + ", already restored rev " + rev + " for another package in the repo")
|
|
||||||
}
|
|
||||||
verboseln("Skipping already restored repo")
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
debugln("Restoring:", dep.ImportPath, dep.Rev)
|
|
||||||
err := dep.vcs.RevSync(dep.root, dep.Rev)
|
|
||||||
if err == nil {
|
|
||||||
restored[dep.root] = dep.Rev
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
|
|
@ -1,171 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"log"
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"go/ast"
|
|
||||||
"go/parser"
|
|
||||||
"go/printer"
|
|
||||||
"go/token"
|
|
||||||
|
|
||||||
"github.com/kr/fs"
|
|
||||||
)
|
|
||||||
|
|
||||||
// rewrite visits the go files in pkgs, plus all go files
|
|
||||||
// in the directory tree Godeps, rewriting import statements
|
|
||||||
// according to the rules for func qualify.
|
|
||||||
func rewrite(pkgs []*Package, qual string, paths []string) error {
|
|
||||||
for _, path := range pkgFiles(pkgs) {
|
|
||||||
debugln("rewrite", path)
|
|
||||||
err := rewriteTree(path, qual, paths)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return rewriteTree("Godeps", qual, paths)
|
|
||||||
}
|
|
||||||
|
|
||||||
// pkgFiles returns the full filesystem path to all go files in pkgs.
|
|
||||||
func pkgFiles(pkgs []*Package) []string {
|
|
||||||
var a []string
|
|
||||||
for _, pkg := range pkgs {
|
|
||||||
for _, s := range pkg.allGoFiles() {
|
|
||||||
a = append(a, filepath.Join(pkg.Dir, s))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return a
|
|
||||||
}
|
|
||||||
|
|
||||||
// rewriteTree recursively visits the go files in path, rewriting
|
|
||||||
// import statements according to the rules for func qualify.
|
|
||||||
// This function ignores the 'testdata' directory.
|
|
||||||
func rewriteTree(path, qual string, paths []string) error {
|
|
||||||
w := fs.Walk(path)
|
|
||||||
for w.Step() {
|
|
||||||
if w.Err() != nil {
|
|
||||||
log.Println("rewrite:", w.Err())
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
s := w.Stat()
|
|
||||||
if s.IsDir() && s.Name() == "testdata" {
|
|
||||||
w.SkipDir()
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if strings.HasSuffix(w.Path(), ".go") {
|
|
||||||
err := rewriteGoFile(w.Path(), qual, paths)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// rewriteGoFile rewrites import statements in the named file
|
|
||||||
// according to the rules for func qualify.
|
|
||||||
func rewriteGoFile(name, qual string, paths []string) error {
|
|
||||||
debugln("rewriteGoFile", name, ",", qual, ",", paths)
|
|
||||||
printerConfig := &printer.Config{Mode: printer.TabIndent | printer.UseSpaces, Tabwidth: 8}
|
|
||||||
fset := token.NewFileSet()
|
|
||||||
f, err := parser.ParseFile(fset, name, nil, parser.ParseComments)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
var changed bool
|
|
||||||
for _, s := range f.Imports {
|
|
||||||
name, err := strconv.Unquote(s.Path.Value)
|
|
||||||
if err != nil {
|
|
||||||
return err // can't happen
|
|
||||||
}
|
|
||||||
q := qualify(unqualify(name), qual, paths)
|
|
||||||
if q != name {
|
|
||||||
s.Path.Value = strconv.Quote(q)
|
|
||||||
changed = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !changed {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
var buffer bytes.Buffer
|
|
||||||
if err = printerConfig.Fprint(&buffer, fset, f); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
fset = token.NewFileSet()
|
|
||||||
f, err = parser.ParseFile(fset, name, &buffer, parser.ParseComments)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
ast.SortImports(fset, f)
|
|
||||||
tpath := name + ".temp"
|
|
||||||
t, err := os.Create(tpath)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if err = printerConfig.Fprint(t, fset, f); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if err = t.Close(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
// This is required before the rename on windows.
|
|
||||||
if err = os.Remove(name); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return os.Rename(tpath, name)
|
|
||||||
}
|
|
||||||
|
|
||||||
func defaultSep(experiment bool) string {
|
|
||||||
if experiment {
|
|
||||||
return "/vendor/"
|
|
||||||
}
|
|
||||||
return "/Godeps/_workspace/src/"
|
|
||||||
}
|
|
||||||
|
|
||||||
func relativeVendorTarget(experiment bool) string {
|
|
||||||
full := defaultSep(experiment)
|
|
||||||
if full[0] == '/' {
|
|
||||||
full = full[1:]
|
|
||||||
}
|
|
||||||
return filepath.FromSlash(full)
|
|
||||||
}
|
|
||||||
|
|
||||||
// unqualify returns the part of importPath after the last
|
|
||||||
// occurrence of the signature path elements
|
|
||||||
// (Godeps/_workspace/src) that always precede imported
|
|
||||||
// packages in rewritten import paths.
|
|
||||||
//
|
|
||||||
// For example,
|
|
||||||
// unqualify(C) = C
|
|
||||||
// unqualify(D/Godeps/_workspace/src/C) = C
|
|
||||||
func unqualify(importPath string) string {
|
|
||||||
if i := strings.LastIndex(importPath, sep); i != -1 {
|
|
||||||
importPath = importPath[i+len(sep):]
|
|
||||||
}
|
|
||||||
return importPath
|
|
||||||
}
|
|
||||||
|
|
||||||
// qualify qualifies importPath with its corresponding import
|
|
||||||
// path in the Godeps src copy of package pkg. If importPath
|
|
||||||
// is a directory lexically contained in a path in paths,
|
|
||||||
// it will be qualified with package pkg; otherwise, it will
|
|
||||||
// be returned unchanged.
|
|
||||||
//
|
|
||||||
// For example, given paths {D, T} and pkg C,
|
|
||||||
// importPath returns
|
|
||||||
// C C
|
|
||||||
// fmt fmt
|
|
||||||
// D C/Godeps/_workspace/src/D
|
|
||||||
// D/P C/Godeps/_workspace/src/D/P
|
|
||||||
// T C/Godeps/_workspace/src/T
|
|
||||||
func qualify(importPath, pkg string, paths []string) string {
|
|
||||||
if containsPathPrefix(paths, importPath) {
|
|
||||||
return pkg + sep + importPath
|
|
||||||
}
|
|
||||||
return importPath
|
|
||||||
}
|
|
|
@ -1,613 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bufio"
|
|
||||||
"bytes"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"go/build"
|
|
||||||
"io"
|
|
||||||
"io/ioutil"
|
|
||||||
"log"
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
"regexp"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/kr/fs"
|
|
||||||
)
|
|
||||||
|
|
||||||
var cmdSave = &Command{
|
|
||||||
Name: "save",
|
|
||||||
Args: "[-r] [-t] [packages]",
|
|
||||||
Short: "list and copy dependencies into Godeps",
|
|
||||||
Long: `
|
|
||||||
|
|
||||||
Save writes a list of the named packages and their dependencies along
|
|
||||||
with the exact source control revision of each package, and copies
|
|
||||||
their source code into a subdirectory. Packages inside "." are excluded
|
|
||||||
from the list to be copied.
|
|
||||||
|
|
||||||
The list is written to Godeps/Godeps.json, and source code for all
|
|
||||||
dependencies is copied into either Godeps/_workspace or, if the vendor
|
|
||||||
experiment is turned on, vendor/.
|
|
||||||
|
|
||||||
The dependency list is a JSON document with the following structure:
|
|
||||||
|
|
||||||
type Godeps struct {
|
|
||||||
ImportPath string
|
|
||||||
GoVersion string // Abridged output of 'go version'.
|
|
||||||
Packages []string // Arguments to godep save, if any.
|
|
||||||
Deps []struct {
|
|
||||||
ImportPath string
|
|
||||||
Comment string // Tag or description of commit.
|
|
||||||
Rev string // VCS-specific commit ID.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Any packages already present in the list will be left unchanged.
|
|
||||||
To update a dependency to a newer revision, use 'godep update'.
|
|
||||||
|
|
||||||
If -r is given, import statements will be rewritten to refer directly
|
|
||||||
to the copied source code. This is not compatible with the vendor
|
|
||||||
experiment. Note that this will not rewrite the statements in the
|
|
||||||
files outside the project.
|
|
||||||
|
|
||||||
If -t is given, test files (*_test.go files + testdata directories) are
|
|
||||||
also saved.
|
|
||||||
|
|
||||||
For more about specifying packages, see 'go help packages'.
|
|
||||||
`,
|
|
||||||
Run: runSave,
|
|
||||||
OnlyInGOPATH: true,
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
saveR, saveT bool
|
|
||||||
ignorePackages string
|
|
||||||
)
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
cmdSave.Flag.BoolVar(&saveR, "r", false, "rewrite import paths")
|
|
||||||
cmdSave.Flag.BoolVar(&saveT, "t", false, "save test files")
|
|
||||||
cmdSave.Flag.StringVar(&ignorePackages, "i", "", "list of packages to ignore separated by commas")
|
|
||||||
}
|
|
||||||
|
|
||||||
func runSave(cmd *Command, args []string) {
|
|
||||||
if VendorExperiment && saveR {
|
|
||||||
log.Println("flag -r is incompatible with the vendoring experiment")
|
|
||||||
cmd.UsageExit()
|
|
||||||
}
|
|
||||||
err := save(args)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalln(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func dotPackage() (*build.Package, error) {
|
|
||||||
dir, err := filepath.Abs(".")
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return build.ImportDir(dir, build.FindOnly)
|
|
||||||
}
|
|
||||||
|
|
||||||
func projectPackages(dDir string, a []*Package) []*Package {
|
|
||||||
var projPkgs []*Package
|
|
||||||
dotDir := fmt.Sprintf("%s%c", dDir, filepath.Separator)
|
|
||||||
for _, p := range a {
|
|
||||||
pkgDir := fmt.Sprintf("%s%c", p.Dir, filepath.Separator)
|
|
||||||
if strings.HasPrefix(pkgDir, dotDir) {
|
|
||||||
projPkgs = append(projPkgs, p)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return projPkgs
|
|
||||||
}
|
|
||||||
|
|
||||||
func save(pkgs []string) error {
|
|
||||||
var err error
|
|
||||||
dp, err := dotPackage()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
debugln("dotPackageImportPath:", dp.ImportPath)
|
|
||||||
debugln("dotPackageDir:", dp.Dir)
|
|
||||||
|
|
||||||
cv, err := goVersion()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
verboseln("Go Version:", cv)
|
|
||||||
|
|
||||||
gold, err := loadDefaultGodepsFile()
|
|
||||||
if err != nil {
|
|
||||||
if !os.IsNotExist(err) {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
verboseln("No old Godeps.json found.")
|
|
||||||
gold.GoVersion = cv
|
|
||||||
}
|
|
||||||
|
|
||||||
printVersionWarnings(gold.GoVersion)
|
|
||||||
if len(gold.GoVersion) == 0 {
|
|
||||||
gold.GoVersion = majorGoVersion
|
|
||||||
} else {
|
|
||||||
majorGoVersion, err = trimGoVersion(gold.GoVersion)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("Unable to determine go major version from value specified in %s: %s\n", gold.file(), gold.GoVersion)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
gnew := &Godeps{
|
|
||||||
ImportPath: dp.ImportPath,
|
|
||||||
GoVersion: gold.GoVersion,
|
|
||||||
}
|
|
||||||
|
|
||||||
switch len(pkgs) {
|
|
||||||
case 0:
|
|
||||||
pkgs = []string{"."}
|
|
||||||
default:
|
|
||||||
gnew.Packages = pkgs
|
|
||||||
}
|
|
||||||
|
|
||||||
verboseln("Finding dependencies for", pkgs)
|
|
||||||
a, err := LoadPackages(pkgs...)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, p := range a {
|
|
||||||
verboseln("Found package:", p.ImportPath)
|
|
||||||
verboseln("\tDeps:", strings.Join(p.Deps, " "))
|
|
||||||
}
|
|
||||||
ppln(a)
|
|
||||||
|
|
||||||
projA := projectPackages(dp.Dir, a)
|
|
||||||
debugln("Filtered projectPackages")
|
|
||||||
ppln(projA)
|
|
||||||
|
|
||||||
verboseln("Computing new Godeps.json file")
|
|
||||||
err = gnew.fill(a, dp.ImportPath)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
debugln("New Godeps Filled")
|
|
||||||
ppln(gnew)
|
|
||||||
|
|
||||||
if gnew.Deps == nil {
|
|
||||||
gnew.Deps = make([]Dependency, 0) // produce json [], not null
|
|
||||||
}
|
|
||||||
gdisk := gnew.copy()
|
|
||||||
err = carryVersions(&gold, gnew)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if gold.isOldFile {
|
|
||||||
// If we are migrating from an old format file,
|
|
||||||
// we require that the listed version of every
|
|
||||||
// dependency must be installed in GOPATH, so it's
|
|
||||||
// available to copy.
|
|
||||||
if !eqDeps(gnew.Deps, gdisk.Deps) {
|
|
||||||
return errors.New(strings.TrimSpace(needRestore))
|
|
||||||
}
|
|
||||||
gold = Godeps{}
|
|
||||||
}
|
|
||||||
os.Remove("Godeps") // remove regular file if present; ignore error
|
|
||||||
readme := filepath.Join("Godeps", "Readme")
|
|
||||||
err = writeFile(readme, strings.TrimSpace(Readme)+"\n")
|
|
||||||
if err != nil {
|
|
||||||
log.Println(err)
|
|
||||||
}
|
|
||||||
_, err = gnew.save()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
verboseln("Computing diff between old and new deps")
|
|
||||||
// We use a name starting with "_" so the go tool
|
|
||||||
// ignores this directory when traversing packages
|
|
||||||
// starting at the project's root. For example,
|
|
||||||
// godep go list ./...
|
|
||||||
srcdir := filepath.FromSlash(strings.Trim(sep, "/"))
|
|
||||||
rem := subDeps(gold.Deps, gnew.Deps)
|
|
||||||
ppln(rem)
|
|
||||||
add := subDeps(gnew.Deps, gold.Deps)
|
|
||||||
ppln(add)
|
|
||||||
if len(rem) > 0 {
|
|
||||||
verboseln("Deps to remove:")
|
|
||||||
for _, r := range rem {
|
|
||||||
verboseln("\t", r.ImportPath)
|
|
||||||
}
|
|
||||||
verboseln("Removing unused dependencies")
|
|
||||||
err = removeSrc(srcdir, rem)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if len(add) > 0 {
|
|
||||||
verboseln("Deps to add:")
|
|
||||||
for _, a := range add {
|
|
||||||
verboseln("\t", a.ImportPath)
|
|
||||||
}
|
|
||||||
verboseln("Adding new dependencies")
|
|
||||||
err = copySrc(srcdir, add)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !VendorExperiment {
|
|
||||||
f, _ := filepath.Split(srcdir)
|
|
||||||
writeVCSIgnore(f)
|
|
||||||
}
|
|
||||||
var rewritePaths []string
|
|
||||||
if saveR {
|
|
||||||
for _, dep := range gnew.Deps {
|
|
||||||
rewritePaths = append(rewritePaths, dep.ImportPath)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
verboseln("Rewriting paths (if necessary)")
|
|
||||||
ppln(rewritePaths)
|
|
||||||
return rewrite(projA, dp.ImportPath, rewritePaths)
|
|
||||||
}
|
|
||||||
|
|
||||||
func printVersionWarnings(ov string) {
|
|
||||||
var warning bool
|
|
||||||
cv, err := goVersion()
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
// Trim the old version because we may have saved it w/o trimming it
|
|
||||||
// cv is already trimmed by goVersion()
|
|
||||||
tov, err := trimGoVersion(ov)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if tov != ov {
|
|
||||||
log.Printf("WARNING: Recorded go version (%s) with minor version string found.\n", ov)
|
|
||||||
warning = true
|
|
||||||
}
|
|
||||||
if cv != tov {
|
|
||||||
log.Printf("WARNING: Recorded major go version (%s) and in-use major go version (%s) differ.\n", tov, cv)
|
|
||||||
warning = true
|
|
||||||
}
|
|
||||||
if warning {
|
|
||||||
log.Println("To record current major go version run `godep update -goversion`.")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type revError struct {
|
|
||||||
ImportPath string
|
|
||||||
WantRev string
|
|
||||||
HavePath string
|
|
||||||
HaveRev string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (v *revError) Error() string {
|
|
||||||
return fmt.Sprintf("cannot save %s at revision %s: already have %s at revision %s.\n"+
|
|
||||||
"Run `godep update %s' first.", v.ImportPath, v.WantRev, v.HavePath, v.HaveRev, v.HavePath)
|
|
||||||
}
|
|
||||||
|
|
||||||
// carryVersions copies Rev and Comment from a to b for
|
|
||||||
// each dependency with an identical ImportPath. For any
|
|
||||||
// dependency in b that appears to be from the same repo
|
|
||||||
// as one in a (for example, a parent or child directory),
|
|
||||||
// the Rev must already match - otherwise it is an error.
|
|
||||||
func carryVersions(a, b *Godeps) error {
|
|
||||||
for i := range b.Deps {
|
|
||||||
err := carryVersion(a, &b.Deps[i])
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func carryVersion(a *Godeps, db *Dependency) error {
|
|
||||||
// First see if this exact package is already in the list.
|
|
||||||
for _, da := range a.Deps {
|
|
||||||
if db.ImportPath == da.ImportPath {
|
|
||||||
db.Rev = da.Rev
|
|
||||||
db.Comment = da.Comment
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// No exact match, check for child or sibling package.
|
|
||||||
// We can't handle mismatched versions for packages in
|
|
||||||
// the same repo, so report that as an error.
|
|
||||||
for _, da := range a.Deps {
|
|
||||||
if strings.HasPrefix(db.ImportPath, da.ImportPath+"/") ||
|
|
||||||
strings.HasPrefix(da.ImportPath, db.root+"/") {
|
|
||||||
if da.Rev != db.Rev {
|
|
||||||
return &revError{
|
|
||||||
ImportPath: db.ImportPath,
|
|
||||||
WantRev: db.Rev,
|
|
||||||
HavePath: da.ImportPath,
|
|
||||||
HaveRev: da.Rev,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// No related package in the list, must be a new repo.
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// subDeps returns a - b, using ImportPath for equality.
|
|
||||||
func subDeps(a, b []Dependency) (diff []Dependency) {
|
|
||||||
Diff:
|
|
||||||
for _, da := range a {
|
|
||||||
for _, db := range b {
|
|
||||||
if da.ImportPath == db.ImportPath {
|
|
||||||
continue Diff
|
|
||||||
}
|
|
||||||
}
|
|
||||||
diff = append(diff, da)
|
|
||||||
}
|
|
||||||
return diff
|
|
||||||
}
|
|
||||||
|
|
||||||
func removeSrc(srcdir string, deps []Dependency) error {
|
|
||||||
for _, dep := range deps {
|
|
||||||
path := filepath.FromSlash(dep.ImportPath)
|
|
||||||
err := os.RemoveAll(filepath.Join(srcdir, path))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func copySrc(dir string, deps []Dependency) error {
|
|
||||||
// mapping to see if we visited a parent directory already
|
|
||||||
visited := make(map[string]bool)
|
|
||||||
ok := true
|
|
||||||
for _, dep := range deps {
|
|
||||||
debugln("copySrc for", dep.ImportPath)
|
|
||||||
srcdir := filepath.Join(dep.ws, "src")
|
|
||||||
rel, err := filepath.Rel(srcdir, dep.dir)
|
|
||||||
debugln("srcdir", srcdir)
|
|
||||||
debugln("rel", rel)
|
|
||||||
debugln("err", err)
|
|
||||||
if err != nil { // this should never happen
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
dstpkgroot := filepath.Join(dir, rel)
|
|
||||||
err = os.RemoveAll(dstpkgroot)
|
|
||||||
if err != nil {
|
|
||||||
log.Println(err)
|
|
||||||
ok = false
|
|
||||||
}
|
|
||||||
|
|
||||||
// copy actual dependency
|
|
||||||
vf := dep.vcs.listFiles(dep.dir)
|
|
||||||
debugln("vf", vf)
|
|
||||||
w := fs.Walk(dep.dir)
|
|
||||||
for w.Step() {
|
|
||||||
err = copyPkgFile(vf, dir, srcdir, w)
|
|
||||||
if err != nil {
|
|
||||||
log.Println(err)
|
|
||||||
ok = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Look for legal files in root
|
|
||||||
// some packages are imports as a sub-package but license info
|
|
||||||
// is at root: exampleorg/common has license file in exampleorg
|
|
||||||
//
|
|
||||||
if dep.ImportPath == dep.root {
|
|
||||||
// we are already at root
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// prevent copying twice This could happen if we have
|
|
||||||
// two subpackages listed someorg/common and
|
|
||||||
// someorg/anotherpack which has their license in
|
|
||||||
// the parent dir of someorg
|
|
||||||
rootdir := filepath.Join(srcdir, filepath.FromSlash(dep.root))
|
|
||||||
if visited[rootdir] {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
visited[rootdir] = true
|
|
||||||
vf = dep.vcs.listFiles(rootdir)
|
|
||||||
w = fs.Walk(rootdir)
|
|
||||||
for w.Step() {
|
|
||||||
fname := filepath.Base(w.Path())
|
|
||||||
if IsLegalFile(fname) && !strings.Contains(w.Path(), sep) {
|
|
||||||
err = copyPkgFile(vf, dir, srcdir, w)
|
|
||||||
if err != nil {
|
|
||||||
log.Println(err)
|
|
||||||
ok = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if !ok {
|
|
||||||
return errorCopyingSourceCode
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func copyPkgFile(vf vcsFiles, dstroot, srcroot string, w *fs.Walker) error {
|
|
||||||
if w.Err() != nil {
|
|
||||||
return w.Err()
|
|
||||||
}
|
|
||||||
name := w.Stat().Name()
|
|
||||||
if w.Stat().IsDir() {
|
|
||||||
if name[0] == '.' || name[0] == '_' || (!saveT && name == "testdata") {
|
|
||||||
// Skip directories starting with '.' or '_' or
|
|
||||||
// 'testdata' (last is only skipped if saveT is false)
|
|
||||||
w.SkipDir()
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
rel, err := filepath.Rel(srcroot, w.Path())
|
|
||||||
if err != nil { // this should never happen
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if !saveT && strings.HasSuffix(name, "_test.go") {
|
|
||||||
if verbose {
|
|
||||||
log.Printf("save: skipping test file: %s", w.Path())
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
if !vf.Contains(w.Path()) {
|
|
||||||
if verbose {
|
|
||||||
log.Printf("save: skipping untracked file: %s", w.Path())
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return copyFile(filepath.Join(dstroot, rel), w.Path())
|
|
||||||
}
|
|
||||||
|
|
||||||
// copyFile copies a regular file from src to dst.
|
|
||||||
// dst is opened with os.Create.
|
|
||||||
// If the file name ends with .go,
|
|
||||||
// copyFile strips canonical import path annotations.
|
|
||||||
// These are comments of the form:
|
|
||||||
// package foo // import "bar/foo"
|
|
||||||
// package foo /* import "bar/foo" */
|
|
||||||
func copyFile(dst, src string) error {
|
|
||||||
err := os.MkdirAll(filepath.Dir(dst), 0777)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
linkDst, err := os.Readlink(src)
|
|
||||||
if err == nil {
|
|
||||||
return os.Symlink(linkDst, dst)
|
|
||||||
}
|
|
||||||
|
|
||||||
si, err := stat(src)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
r, err := os.Open(src)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer r.Close()
|
|
||||||
|
|
||||||
w, err := os.Create(dst)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if err := os.Chmod(dst, si.Mode()); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if strings.HasSuffix(dst, ".go") {
|
|
||||||
debugln("Copy Without Import Comment", w, r)
|
|
||||||
err = copyWithoutImportComment(w, r)
|
|
||||||
} else {
|
|
||||||
debugln("Copy (plain)", w, r)
|
|
||||||
_, err = io.Copy(w, r)
|
|
||||||
}
|
|
||||||
err1 := w.Close()
|
|
||||||
if err == nil {
|
|
||||||
err = err1
|
|
||||||
}
|
|
||||||
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func copyWithoutImportComment(w io.Writer, r io.Reader) error {
|
|
||||||
b := bufio.NewReader(r)
|
|
||||||
for {
|
|
||||||
l, err := b.ReadBytes('\n')
|
|
||||||
eof := err == io.EOF
|
|
||||||
if err != nil && err != io.EOF {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we have data then write it out...
|
|
||||||
if len(l) > 0 {
|
|
||||||
// Strip off \n if it exists because stripImportComment
|
|
||||||
_, err := w.Write(append(stripImportComment(bytes.TrimRight(l, "\n")), '\n'))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if eof {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const (
|
|
||||||
importAnnotation = `import\s+(?:"[^"]*"|` + "`[^`]*`" + `)`
|
|
||||||
importComment = `(?://\s*` + importAnnotation + `\s*$|/\*\s*` + importAnnotation + `\s*\*/)`
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
importCommentRE = regexp.MustCompile(`^\s*(package\s+\w+)\s+` + importComment + `(.*)`)
|
|
||||||
pkgPrefix = []byte("package ")
|
|
||||||
)
|
|
||||||
|
|
||||||
// stripImportComment returns line with its import comment removed.
|
|
||||||
// If s is not a package statement containing an import comment,
|
|
||||||
// it is returned unaltered.
|
|
||||||
// FIXME: expects lines w/o a \n at the end
|
|
||||||
// See also http://golang.org/s/go14customimport.
|
|
||||||
func stripImportComment(line []byte) []byte {
|
|
||||||
if !bytes.HasPrefix(line, pkgPrefix) {
|
|
||||||
// Fast path; this will skip all but one line in the file.
|
|
||||||
// This assumes there is no whitespace before the keyword.
|
|
||||||
return line
|
|
||||||
}
|
|
||||||
if m := importCommentRE.FindSubmatch(line); m != nil {
|
|
||||||
return append(m[1], m[2]...)
|
|
||||||
}
|
|
||||||
return line
|
|
||||||
}
|
|
||||||
|
|
||||||
// Func writeVCSIgnore writes "ignore" files inside dir for known VCSs,
|
|
||||||
// so that dir/pkg and dir/bin don't accidentally get committed.
|
|
||||||
// It logs any errors it encounters.
|
|
||||||
func writeVCSIgnore(dir string) {
|
|
||||||
// Currently git is the only VCS for which we know how to do this.
|
|
||||||
// Mercurial and Bazaar have similar mechanisms, but they apparently
|
|
||||||
// require writing files outside of dir.
|
|
||||||
const ignore = "/pkg\n/bin\n"
|
|
||||||
name := filepath.Join(dir, ".gitignore")
|
|
||||||
err := writeFile(name, ignore)
|
|
||||||
if err != nil {
|
|
||||||
log.Println(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// writeFile is like ioutil.WriteFile but it creates
|
|
||||||
// intermediate directories with os.MkdirAll.
|
|
||||||
func writeFile(name, body string) error {
|
|
||||||
err := os.MkdirAll(filepath.Dir(name), 0777)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return ioutil.WriteFile(name, []byte(body), 0666)
|
|
||||||
}
|
|
||||||
|
|
||||||
const (
|
|
||||||
// Readme contains the README text.
|
|
||||||
Readme = `
|
|
||||||
This directory tree is generated automatically by godep.
|
|
||||||
|
|
||||||
Please do not edit.
|
|
||||||
|
|
||||||
See https://github.com/tools/godep for more information.
|
|
||||||
`
|
|
||||||
needRestore = `
|
|
||||||
mismatched versions while migrating
|
|
||||||
|
|
||||||
It looks like you are switching from the old Godeps format
|
|
||||||
(from flag -copy=false). The old format is just a file; it
|
|
||||||
doesn't contain source code. For this migration, godep needs
|
|
||||||
the appropriate version of each dependency to be installed in
|
|
||||||
GOPATH, so that the source code is available to copy.
|
|
||||||
|
|
||||||
To fix this, run 'godep restore'.
|
|
||||||
`
|
|
||||||
)
|
|
|
@ -1,292 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"go/parser"
|
|
||||||
"go/token"
|
|
||||||
"log"
|
|
||||||
"os"
|
|
||||||
"path"
|
|
||||||
"path/filepath"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
var cmdUpdate = &Command{
|
|
||||||
Name: "update",
|
|
||||||
Args: "[-goversion] [packages]",
|
|
||||||
Short: "update selected packages or the go version",
|
|
||||||
Long: `
|
|
||||||
Update changes the named dependency packages to use the
|
|
||||||
revision of each currently installed in GOPATH. New code will
|
|
||||||
be copied into the Godeps workspace or vendor folder and the
|
|
||||||
new revision will be written to the manifest.
|
|
||||||
|
|
||||||
If -goversion is specified, update the recorded go version.
|
|
||||||
|
|
||||||
For more about specifying packages, see 'go help packages'.
|
|
||||||
`,
|
|
||||||
Run: runUpdate,
|
|
||||||
OnlyInGOPATH: true,
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
updateGoVer bool
|
|
||||||
)
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
cmdUpdate.Flag.BoolVar(&saveT, "t", false, "save test files during update")
|
|
||||||
cmdUpdate.Flag.BoolVar(&updateGoVer, "goversion", false, "update the recorded go version")
|
|
||||||
}
|
|
||||||
|
|
||||||
func runUpdate(cmd *Command, args []string) {
|
|
||||||
if updateGoVer {
|
|
||||||
err := updateGoVersion()
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalln(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if len(args) > 0 {
|
|
||||||
err := update(args)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalln(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func updateGoVersion() error {
|
|
||||||
gold, err := loadDefaultGodepsFile()
|
|
||||||
if err != nil {
|
|
||||||
if !os.IsNotExist(err) {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
cv, err := goVersion()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
gv := gold.GoVersion
|
|
||||||
gold.GoVersion = cv
|
|
||||||
_, err = gold.save()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if gv != cv {
|
|
||||||
log.Println("Updated major go version to", cv)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func update(args []string) error {
|
|
||||||
if len(args) == 0 {
|
|
||||||
args = []string{"."}
|
|
||||||
}
|
|
||||||
g, err := loadDefaultGodepsFile()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
for _, arg := range args {
|
|
||||||
arg := path.Clean(arg)
|
|
||||||
any := markMatches(arg, g.Deps)
|
|
||||||
if !any {
|
|
||||||
log.Println("not in manifest:", arg)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
deps, rdeps, err := LoadVCSAndUpdate(g.Deps)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if len(deps) == 0 {
|
|
||||||
return errorNoPackagesUpdatable
|
|
||||||
}
|
|
||||||
g.addOrUpdateDeps(deps)
|
|
||||||
g.removeDeps(rdeps)
|
|
||||||
if _, err = g.save(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
srcdir := relativeVendorTarget(VendorExperiment)
|
|
||||||
if err := removeSrc(filepath.FromSlash(strings.Trim(sep, "/")), rdeps); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
copySrc(srcdir, deps)
|
|
||||||
|
|
||||||
ok, err := needRewrite(g.Packages)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
var rewritePaths []string
|
|
||||||
if ok {
|
|
||||||
for _, dep := range g.Deps {
|
|
||||||
rewritePaths = append(rewritePaths, dep.ImportPath)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return rewrite(nil, g.ImportPath, rewritePaths)
|
|
||||||
}
|
|
||||||
|
|
||||||
func needRewrite(importPaths []string) (bool, error) {
|
|
||||||
if len(importPaths) == 0 {
|
|
||||||
importPaths = []string{"."}
|
|
||||||
}
|
|
||||||
a, err := LoadPackages(importPaths...)
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
for _, p := range a {
|
|
||||||
for _, name := range p.allGoFiles() {
|
|
||||||
path := filepath.Join(p.Dir, name)
|
|
||||||
hasSep, err := hasRewrittenImportStatement(path)
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
if hasSep {
|
|
||||||
return true, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func hasRewrittenImportStatement(path string) (bool, error) {
|
|
||||||
fset := token.NewFileSet()
|
|
||||||
f, err := parser.ParseFile(fset, path, nil, 0)
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
for _, s := range f.Imports {
|
|
||||||
name, _ := strconv.Unquote(s.Path.Value)
|
|
||||||
if strings.Contains(name, sep) {
|
|
||||||
return true, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// markMatches marks each entry in deps with an import path that
|
|
||||||
// matches pat. It returns whether any matches occurred.
|
|
||||||
func markMatches(pat string, deps []Dependency) (matched bool) {
|
|
||||||
f := matchPattern(pat)
|
|
||||||
for i, dep := range deps {
|
|
||||||
if f(dep.ImportPath) {
|
|
||||||
deps[i].matched = true
|
|
||||||
matched = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return matched
|
|
||||||
}
|
|
||||||
|
|
||||||
func fillDeps(deps []Dependency) ([]Dependency, error) {
|
|
||||||
for i := range deps {
|
|
||||||
if deps[i].pkg != nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
ps, err := LoadPackages(deps[i].ImportPath)
|
|
||||||
if err != nil {
|
|
||||||
if _, ok := err.(errPackageNotFound); ok {
|
|
||||||
deps[i].missing = true
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if len(ps) > 1 {
|
|
||||||
panic("More than one package found for " + deps[i].ImportPath)
|
|
||||||
}
|
|
||||||
p := ps[0]
|
|
||||||
deps[i].pkg = p
|
|
||||||
deps[i].dir = p.Dir
|
|
||||||
deps[i].ws = p.Root
|
|
||||||
|
|
||||||
vcs, reporoot, err := VCSFromDir(p.Dir, filepath.Join(p.Root, "src"))
|
|
||||||
if err != nil {
|
|
||||||
return nil, errorLoadingDeps
|
|
||||||
}
|
|
||||||
deps[i].root = filepath.ToSlash(reporoot)
|
|
||||||
deps[i].vcs = vcs
|
|
||||||
}
|
|
||||||
|
|
||||||
return deps, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// LoadVCSAndUpdate loads and updates a set of dependencies.
|
|
||||||
func LoadVCSAndUpdate(deps []Dependency) ([]Dependency, []Dependency, error) {
|
|
||||||
var err1 error
|
|
||||||
|
|
||||||
deps, err := fillDeps(deps)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
repoMask := make(map[string]bool)
|
|
||||||
for i := range deps {
|
|
||||||
if !deps[i].matched {
|
|
||||||
repoMask[deps[i].root] = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Determine if we need any new packages because of new transitive imports
|
|
||||||
for _, dep := range deps {
|
|
||||||
if !dep.matched || dep.missing {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
for _, dp := range dep.pkg.Dependencies {
|
|
||||||
if dp.Goroot {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
var have bool
|
|
||||||
for _, d := range deps {
|
|
||||||
if d.ImportPath == dp.ImportPath {
|
|
||||||
have = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !have {
|
|
||||||
deps = append(deps, Dependency{ImportPath: dp.ImportPath, matched: true})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
deps, err = fillDeps(deps)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
var toUpdate, toRemove []Dependency
|
|
||||||
for _, d := range deps {
|
|
||||||
if !d.matched || repoMask[d.root] {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if d.missing {
|
|
||||||
toRemove = append(toRemove, d)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
toUpdate = append(toUpdate, d)
|
|
||||||
}
|
|
||||||
|
|
||||||
debugln("toUpdate")
|
|
||||||
ppln(toUpdate)
|
|
||||||
|
|
||||||
var toCopy []Dependency
|
|
||||||
for _, d := range toUpdate {
|
|
||||||
id, err := d.vcs.identify(d.dir)
|
|
||||||
if err != nil {
|
|
||||||
log.Println(err)
|
|
||||||
err1 = errorLoadingDeps
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if d.vcs.isDirty(d.dir, id) {
|
|
||||||
log.Println("dirty working tree (please commit changes):", d.dir)
|
|
||||||
}
|
|
||||||
d.Rev = id
|
|
||||||
d.Comment = d.vcs.describe(d.dir, id)
|
|
||||||
toCopy = append(toCopy, d)
|
|
||||||
}
|
|
||||||
debugln("toCopy")
|
|
||||||
ppln(toCopy)
|
|
||||||
|
|
||||||
if err1 != nil {
|
|
||||||
return nil, nil, err1
|
|
||||||
}
|
|
||||||
return toCopy, toRemove, nil
|
|
||||||
}
|
|
|
@ -1,36 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"path/filepath"
|
|
||||||
"runtime"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
// driveLetterToUpper converts Windows path's drive letters to uppercase. This
|
|
||||||
// is needed when comparing 2 paths with different drive letter case.
|
|
||||||
func driveLetterToUpper(path string) string {
|
|
||||||
if runtime.GOOS != "windows" || path == "" {
|
|
||||||
return path
|
|
||||||
}
|
|
||||||
|
|
||||||
p := path
|
|
||||||
|
|
||||||
// If path's drive letter is lowercase, change it to uppercase.
|
|
||||||
if len(p) >= 2 && p[1] == ':' && 'a' <= p[0] && p[0] <= 'z' {
|
|
||||||
p = string(p[0]+'A'-'a') + p[1:]
|
|
||||||
}
|
|
||||||
|
|
||||||
return p
|
|
||||||
}
|
|
||||||
|
|
||||||
// clean the path and ensure that a drive letter is upper case (if it exists).
|
|
||||||
func cleanPath(path string) string {
|
|
||||||
return driveLetterToUpper(filepath.Clean(path))
|
|
||||||
}
|
|
||||||
|
|
||||||
// deal with case insensitive filesystems and other weirdness
|
|
||||||
func pathEqual(a, b string) bool {
|
|
||||||
a = cleanPath(a)
|
|
||||||
b = cleanPath(b)
|
|
||||||
return strings.EqualFold(a, b)
|
|
||||||
}
|
|
|
@ -1,293 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
"os/exec"
|
|
||||||
"path/filepath"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"golang.org/x/tools/go/vcs"
|
|
||||||
)
|
|
||||||
|
|
||||||
// VCS represents a version control system.
|
|
||||||
type VCS struct {
|
|
||||||
vcs *vcs.Cmd
|
|
||||||
|
|
||||||
IdentifyCmd string
|
|
||||||
DescribeCmd string
|
|
||||||
DiffCmd string
|
|
||||||
ListCmd string
|
|
||||||
RootCmd string
|
|
||||||
|
|
||||||
// run in sandbox repos
|
|
||||||
ExistsCmd string
|
|
||||||
}
|
|
||||||
|
|
||||||
var vcsBzr = &VCS{
|
|
||||||
vcs: vcs.ByCmd("bzr"),
|
|
||||||
|
|
||||||
IdentifyCmd: "version-info --custom --template {revision_id}",
|
|
||||||
DescribeCmd: "revno", // TODO(kr): find tag names if possible
|
|
||||||
DiffCmd: "diff -r {rev}",
|
|
||||||
ListCmd: "ls --from-root -R",
|
|
||||||
RootCmd: "root",
|
|
||||||
}
|
|
||||||
|
|
||||||
var vcsGit = &VCS{
|
|
||||||
vcs: vcs.ByCmd("git"),
|
|
||||||
|
|
||||||
IdentifyCmd: "rev-parse HEAD",
|
|
||||||
DescribeCmd: "describe --tags --abbrev=14",
|
|
||||||
DiffCmd: "diff {rev}",
|
|
||||||
ListCmd: "ls-files --full-name",
|
|
||||||
RootCmd: "rev-parse --show-cdup",
|
|
||||||
|
|
||||||
ExistsCmd: "cat-file -e {rev}",
|
|
||||||
}
|
|
||||||
|
|
||||||
var vcsHg = &VCS{
|
|
||||||
vcs: vcs.ByCmd("hg"),
|
|
||||||
|
|
||||||
IdentifyCmd: "parents --template {node}",
|
|
||||||
DescribeCmd: "log -r . --template {latesttag}-{latesttagdistance}",
|
|
||||||
DiffCmd: "diff -r {rev}",
|
|
||||||
ListCmd: "status --all --no-status",
|
|
||||||
RootCmd: "root",
|
|
||||||
|
|
||||||
ExistsCmd: "cat -r {rev} .",
|
|
||||||
}
|
|
||||||
|
|
||||||
var cmd = map[*vcs.Cmd]*VCS{
|
|
||||||
vcsBzr.vcs: vcsBzr,
|
|
||||||
vcsGit.vcs: vcsGit,
|
|
||||||
vcsHg.vcs: vcsHg,
|
|
||||||
}
|
|
||||||
|
|
||||||
// VCSFromDir returns a VCS value from a directory.
|
|
||||||
func VCSFromDir(dir, srcRoot string) (*VCS, string, error) {
|
|
||||||
vcscmd, reporoot, err := vcs.FromDir(dir, srcRoot)
|
|
||||||
if err != nil {
|
|
||||||
return nil, "", fmt.Errorf("error while inspecting %q: %v", dir, err)
|
|
||||||
}
|
|
||||||
vcsext := cmd[vcscmd]
|
|
||||||
if vcsext == nil {
|
|
||||||
return nil, "", fmt.Errorf("%s is unsupported: %s", vcscmd.Name, dir)
|
|
||||||
}
|
|
||||||
return vcsext, reporoot, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (v *VCS) identify(dir string) (string, error) {
|
|
||||||
out, err := v.runOutput(dir, v.IdentifyCmd)
|
|
||||||
return string(bytes.TrimSpace(out)), err
|
|
||||||
}
|
|
||||||
|
|
||||||
func absRoot(dir, out string) string {
|
|
||||||
if filepath.IsAbs(out) {
|
|
||||||
return filepath.Clean(out)
|
|
||||||
}
|
|
||||||
return filepath.Join(dir, out)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (v *VCS) root(dir string) (string, error) {
|
|
||||||
out, err := v.runOutput(dir, v.RootCmd)
|
|
||||||
return absRoot(dir, string(bytes.TrimSpace(out))), err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (v *VCS) describe(dir, rev string) string {
|
|
||||||
out, err := v.runOutputVerboseOnly(dir, v.DescribeCmd, "rev", rev)
|
|
||||||
if err != nil {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
return string(bytes.TrimSpace(out))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (v *VCS) isDirty(dir, rev string) bool {
|
|
||||||
out, err := v.runOutput(dir, v.DiffCmd, "rev", rev)
|
|
||||||
return err != nil || len(out) != 0
|
|
||||||
}
|
|
||||||
|
|
||||||
type vcsFiles map[string]bool
|
|
||||||
|
|
||||||
func (vf vcsFiles) Contains(path string) bool {
|
|
||||||
// Fast path, we have the path
|
|
||||||
if vf[path] {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// Slow path for case insensitive filesystems
|
|
||||||
// See #310
|
|
||||||
for f := range vf {
|
|
||||||
if pathEqual(f, path) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
// git's root command (maybe other vcs as well) resolve symlinks, so try that too
|
|
||||||
// FIXME: rev-parse --show-cdup + extra logic will fix this for git but also need to validate the other vcs commands. This is maybe temporary.
|
|
||||||
p, err := filepath.EvalSymlinks(path)
|
|
||||||
if err != nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
if pathEqual(f, p) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// No matches by either method
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// listFiles tracked by the VCS in the repo that contains dir, converted to absolute path.
|
|
||||||
func (v *VCS) listFiles(dir string) vcsFiles {
|
|
||||||
root, err := v.root(dir)
|
|
||||||
debugln("vcs dir", dir)
|
|
||||||
debugln("vcs root", root)
|
|
||||||
ppln(v)
|
|
||||||
if err != nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
out, err := v.runOutput(dir, v.ListCmd)
|
|
||||||
if err != nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
files := make(vcsFiles)
|
|
||||||
for _, file := range bytes.Split(out, []byte{'\n'}) {
|
|
||||||
if len(file) > 0 {
|
|
||||||
path, err := filepath.Abs(filepath.Join(root, string(file)))
|
|
||||||
if err != nil {
|
|
||||||
panic(err) // this should not happen
|
|
||||||
}
|
|
||||||
|
|
||||||
if pathEqual(filepath.Dir(path), dir) {
|
|
||||||
files[path] = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return files
|
|
||||||
}
|
|
||||||
|
|
||||||
func (v *VCS) exists(dir, rev string) bool {
|
|
||||||
err := v.runVerboseOnly(dir, v.ExistsCmd, "rev", rev)
|
|
||||||
return err == nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// RevSync checks out the revision given by rev in dir.
|
|
||||||
// The dir must exist and rev must be a valid revision.
|
|
||||||
func (v *VCS) RevSync(dir, rev string) error {
|
|
||||||
return v.run(dir, v.vcs.TagSyncCmd, "tag", rev)
|
|
||||||
}
|
|
||||||
|
|
||||||
// run runs the command line cmd in the given directory.
|
|
||||||
// keyval is a list of key, value pairs. run expands
|
|
||||||
// instances of {key} in cmd into value, but only after
|
|
||||||
// splitting cmd into individual arguments.
|
|
||||||
// If an error occurs, run prints the command line and the
|
|
||||||
// command's combined stdout+stderr to standard error.
|
|
||||||
// Otherwise run discards the command's output.
|
|
||||||
func (v *VCS) run(dir string, cmdline string, kv ...string) error {
|
|
||||||
_, err := v.run1(dir, cmdline, kv, true)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// runVerboseOnly is like run but only generates error output to standard error in verbose mode.
|
|
||||||
func (v *VCS) runVerboseOnly(dir string, cmdline string, kv ...string) error {
|
|
||||||
_, err := v.run1(dir, cmdline, kv, false)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// runOutput is like run but returns the output of the command.
|
|
||||||
func (v *VCS) runOutput(dir string, cmdline string, kv ...string) ([]byte, error) {
|
|
||||||
return v.run1(dir, cmdline, kv, true)
|
|
||||||
}
|
|
||||||
|
|
||||||
// runOutputVerboseOnly is like runOutput but only generates error output to standard error in verbose mode.
|
|
||||||
func (v *VCS) runOutputVerboseOnly(dir string, cmdline string, kv ...string) ([]byte, error) {
|
|
||||||
return v.run1(dir, cmdline, kv, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
// run1 is the generalized implementation of run and runOutput.
|
|
||||||
func (v *VCS) run1(dir string, cmdline string, kv []string, verbose bool) ([]byte, error) {
|
|
||||||
m := make(map[string]string)
|
|
||||||
for i := 0; i < len(kv); i += 2 {
|
|
||||||
m[kv[i]] = kv[i+1]
|
|
||||||
}
|
|
||||||
args := strings.Fields(cmdline)
|
|
||||||
for i, arg := range args {
|
|
||||||
args[i] = expand(m, arg)
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err := exec.LookPath(v.vcs.Cmd)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Fprintf(os.Stderr, "godep: missing %s command.\n", v.vcs.Name)
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
cmd := exec.Command(v.vcs.Cmd, args...)
|
|
||||||
cmd.Dir = dir
|
|
||||||
var buf bytes.Buffer
|
|
||||||
cmd.Stdout = &buf
|
|
||||||
cmd.Stderr = &buf
|
|
||||||
err = cmd.Run()
|
|
||||||
out := buf.Bytes()
|
|
||||||
if err != nil {
|
|
||||||
if verbose {
|
|
||||||
fmt.Fprintf(os.Stderr, "# cd %s; %s %s\n", dir, v.vcs.Cmd, strings.Join(args, " "))
|
|
||||||
os.Stderr.Write(out)
|
|
||||||
}
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return out, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func expand(m map[string]string, s string) string {
|
|
||||||
for k, v := range m {
|
|
||||||
s = strings.Replace(s, "{"+k+"}", v, -1)
|
|
||||||
}
|
|
||||||
return s
|
|
||||||
}
|
|
||||||
|
|
||||||
func gitDetached(r string) (bool, error) {
|
|
||||||
o, err := vcsGit.runOutput(r, "status")
|
|
||||||
if err != nil {
|
|
||||||
return false, errors.New("unable to determine git status " + err.Error())
|
|
||||||
}
|
|
||||||
return bytes.Contains(o, []byte("HEAD detached at")), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func gitDefaultBranch(r string) (string, error) {
|
|
||||||
o, err := vcsGit.runOutput(r, "remote show origin")
|
|
||||||
if err != nil {
|
|
||||||
return "", errors.New("Running git remote show origin errored with: " + err.Error())
|
|
||||||
}
|
|
||||||
return gitDetermineDefaultBranch(r, string(o))
|
|
||||||
}
|
|
||||||
|
|
||||||
func gitDetermineDefaultBranch(r, o string) (string, error) {
|
|
||||||
e := "Unable to determine HEAD branch: "
|
|
||||||
hb := "HEAD branch:"
|
|
||||||
lbcfgp := "Local branch configured for 'git pull':"
|
|
||||||
s := strings.Index(o, hb)
|
|
||||||
if s < 0 {
|
|
||||||
b := strings.Index(o, lbcfgp)
|
|
||||||
if b < 0 {
|
|
||||||
return "", errors.New(e + "Remote HEAD is ambiguous. Before godep can pull new commits you will need to:" + `
|
|
||||||
cd ` + r + `
|
|
||||||
git checkout <a HEAD branch>
|
|
||||||
Here is what was reported:
|
|
||||||
` + o)
|
|
||||||
}
|
|
||||||
s = b + len(lbcfgp)
|
|
||||||
} else {
|
|
||||||
s += len(hb)
|
|
||||||
}
|
|
||||||
f := strings.Fields(o[s:])
|
|
||||||
if len(f) < 3 {
|
|
||||||
return "", errors.New(e + "git output too short")
|
|
||||||
}
|
|
||||||
return f[0], nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func gitCheckout(r, b string) error {
|
|
||||||
return vcsGit.run(r, "checkout "+b)
|
|
||||||
}
|
|
|
@ -1,63 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"log"
|
|
||||||
"runtime"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
const version = "80-k8s-r1"
|
|
||||||
|
|
||||||
var cmdVersion = &Command{
|
|
||||||
Name: "version",
|
|
||||||
Short: "show version info",
|
|
||||||
Long: `
|
|
||||||
|
|
||||||
Displays the version of godep as well as the target OS, architecture and go runtime version.
|
|
||||||
`,
|
|
||||||
Run: runVersion,
|
|
||||||
}
|
|
||||||
|
|
||||||
func versionString() string {
|
|
||||||
return fmt.Sprintf("godep v%s (%s/%s/%s)", version, runtime.GOOS, runtime.GOARCH, runtime.Version())
|
|
||||||
}
|
|
||||||
|
|
||||||
func runVersion(cmd *Command, args []string) {
|
|
||||||
fmt.Printf("%s\n", versionString())
|
|
||||||
}
|
|
||||||
|
|
||||||
func GoVersionFields(c rune) bool {
|
|
||||||
return c == 'g' || c == 'o' || c == '.'
|
|
||||||
}
|
|
||||||
|
|
||||||
// isSameOrNewer go version (goA.B)
|
|
||||||
// go1.6 >= go1.6 == true
|
|
||||||
// go1.5 >= go1.6 == false
|
|
||||||
func isSameOrNewer(base, check string) bool {
|
|
||||||
if base == check {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
if strings.HasPrefix(check, "devel-") {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
bp := strings.FieldsFunc(base, GoVersionFields)
|
|
||||||
cp := strings.FieldsFunc(check, GoVersionFields)
|
|
||||||
if len(bp) < 2 || len(cp) < 2 {
|
|
||||||
log.Fatalf("Error comparing %s to %s\n", base, check)
|
|
||||||
}
|
|
||||||
if bp[0] == cp[0] { // We only have go version 1 right now
|
|
||||||
bm, err := strconv.Atoi(bp[1])
|
|
||||||
// These errors are unlikely and there is nothing nice to do here anyway
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
cm, err := strconv.Atoi(cp[1])
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
return cm >= bm
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
Loading…
Reference in New Issue