├── LICENSE.txt ├── README.md └── go-getter /LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Joe Walnes 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | go-getter: Like "go get", but different 2 | ======================================= 3 | 4 | A very small shell script that fetches Go packages pinned to your preferred 5 | version. 6 | 7 | For creating consistent and repeatable builds. 8 | 9 | 10 | 5 second tutorial 11 | ----------------- 12 | 13 | To install specific git revisions of Go packages into your `GOPATH`: 14 | ``` 15 | $ cat Gofile 16 | github.com/lib/pq 8910d1c3a4bda5c97c50bc38543953f1f1e1f8bb 17 | github.com/julienschmidt/httprouter b59a38004596b696aca7aa2adccfa68760864d86 18 | github.com/hashicorp/golang-lru d85392d6bc30546d352f52f2632814cde4201d44 19 | bitbucket.org/cranej/go-mvc 7:65b80632192a 20 | bitbucket.org/binet/go-ctypes 4:0344428b46d0 21 | launchpad.net/mgo 1 22 | 23 | $ go-getter Gofile 24 | ``` 25 | 26 | Uhh that's it. 27 | 28 | Background 29 | ---------- 30 | 31 | If you program [Go](https://golang.org/) you are no doubt familiar with its 32 | package manager `go get`. 33 | 34 | Like everything about Go, it's fantastically opinionated: you depend on the 35 | HEAD version of a package and it's the package author's responsibility to 36 | ensure HEAD *always* contains a good version and maintains backwards 37 | compatibility. 38 | 39 | In a perfect world, that's great. *Except it's not always the case.* Libraries 40 | evolve, behaviors change, APIs evolve, regressions come and go, performance 41 | fluctuates, bad things sometimes appear in HEAD, even if only for a short period 42 | of time. 43 | 44 | `go-getter` is an alternative to `go get` that has a stronger opinion: **Given 45 | an identical source tree, building a project tomorrow should give you the same 46 | result as building it today, and yesterday, and in 2 years time.** 47 | 48 | Because it sucks when you need to cut an emergency release and the code no 49 | longer compiles due to something out of your control. 50 | 51 | 52 | Installation 53 | ------------ 54 | 55 | Grab [go-getter](https://raw.githubusercontent.com/joewalnes/go-getter/master/go-getter). It's a very small shell script. Don't forget to `chmod +x`. 56 | 57 | 58 | Usage 59 | ----- 60 | 61 | Create a file to declare your package dependencies and git/svn/hg/bzr hash versions. 62 | I call my file `Gofile` but you can call it anything. 63 | 64 | ``` 65 | # List packages and git hashes of versions you want 66 | 67 | github.com/lib/pq 8910d1c3a4bda5c97c50bc38543953f1f1e1f8bb 68 | github.com/julienschmidt/httprouter b59a38004596b696aca7aa2adccfa68760864d86 69 | github.com/hashicorp/golang-lru d85392d6bc30546d352f52f2632814cde4201d44 70 | bitbucket.org/cranej/go-mvc 7:65b80632192a 71 | bitbucket.org/binet/go-ctypes 4:0344428b46d0 72 | launchpad.net/mgo 1 73 | ``` 74 | 75 | Then run: 76 | ``` 77 | $ go-getter Gofile 78 | ``` 79 | 80 | This will ensure that your packages are installed in the correct place in your 81 | `GOPATH`. You can run it repeatedly and it will ensure packages are always at 82 | your desired version. 83 | 84 | 85 | FAQ 86 | --- 87 | 88 | #### Why should I agree with your opinion over that of the Go team? 89 | 90 | We both have opinions. They're both right. I can't choose for you. 91 | 92 | #### You know there are loads of these out there already, right? 93 | 94 | Yep, I tried a few. Some of them were written in Go, which lead to a 95 | bootstrapping issue (you had to go get them, but which version were you 96 | getting?). Others were too complicated or confusing for me. I just want 97 | to download dependencies. 98 | 99 | #### Are you crazy? This is just a lame 37 line shell script - I could write that 100 | 101 | Me too. That's why I did. 102 | 103 | #### How does this handle transitive dependencies (ie. deps of deps)? 104 | 105 | It doesn't. By design. If you depend libraries that depend on other libraries, 106 | you must explicitly list them, that way you can state the versions of those 107 | libraries too. 108 | 109 | #### How do I find the current version of a hash for the package I want to use? 110 | 111 | View the latest commit on GitHub. You'll see it there. 112 | 113 | #### Do you accept pull requests? 114 | 115 | Probably not. Your best bet is to fork it and publicize your better version. 116 | 117 | #### Is this available in brew, apt, yum, etc? 118 | 119 | No. It's a teeny tiny shell script. Just check it in to your project and run 120 | it from there. 121 | 122 | #### I read somewhere that a better way to do this is 'vendoring'? 123 | 124 | That basically means taking a snapshot of the code and including it in your 125 | own repository. Yes, it's even better as you are isolated from remote 126 | repositories being deleted. But it's also annoying because you have to check 127 | all the code into your own repo. This is a pragmatic middle ground that gives 128 | you most of the advantages of vendoring, without repository bloat. 129 | 130 | #### How do I use this if I'm a library author? 131 | 132 | You don't. It's for top-level (main) programs only. 133 | 134 | #### What if you have multiple top level programs that require different package versions? 135 | 136 | Use different `GOPATH`s. I typically have one GOPATH per main project. 137 | 138 | #### Who did this? 139 | 140 | Initially @joewalnes. Then @sriniprash made it work properly. 141 | 142 | Architectural diagram 143 | --------------------- 144 | 145 | I love gophers too. 146 | 147 | ![Gophers ready!](http://i.imgur.com/MmNPB.gif "Gophers ready!") 148 | -------------------------------------------------------------------------------- /go-getter: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Like 'go get' but with pinned package versions. https://github.com/joewalnes/go-getter 3 | set -e 4 | : ${GOPATH?"GOPATH not set"} 5 | : ${1?"Usage: $0 [path-to-go-deps]"} 6 | sed -e 's/#.*//' $1 | grep -v -e '^[[:space:]]*$' | while read PKG HASH; do 7 | echo "$PKG ($HASH)" 8 | DEST=$GOPATH/src/$PKG 9 | go get -d -u $PKG || true 10 | FOUND_VCS=0 11 | while [[ "$DEST" != "$GOPATH/src" ]] && [[ -d $DEST ]] 12 | do 13 | cd $DEST 14 | if [ -d "$DEST/.git" ]; then 15 | FOUND_VCS=1 16 | git checkout -q $HASH 17 | break 18 | elif [ -d "$DEST/.hg" ]; then 19 | FOUND_VCS=1 20 | hg update -q -c $HASH 21 | break 22 | elif [ -d "$DEST/.bzr" ]; then 23 | FOUND_VCS=1 24 | bzr update -q -r $HASH 25 | break 26 | elif [ -d "$DEST/.svn" ]; then 27 | FOUND_VCS=1 28 | svn update -q -r $HASH 29 | break 30 | else 31 | DEST="$(readlink -f $DEST/..)" 32 | fi 33 | done 34 | if [ $FOUND_VCS -eq 0 ]; then 35 | echo "WARNING: Unrecognized VCS system for the golang package $PKG" 36 | fi 37 | done 38 | --------------------------------------------------------------------------------