Hellogopher – Just “git clone” and “make” any Go project
github.com
github.com
I love the Go language but the development environment tooling is just awful (aside from some great things like gofmt). This requirement of having files in specific folders to be able to build, the (lack of a sane) vendoring system, both problems keep popping up and spawning new solutions over and over. There is no excuse for a modern language to force people to learn how to use the tools before they can even start using the language. Tools should work for the user, not the other way around. Other languages get this right, so why can't Go?
Kudos to the author for spending some time to document and publish their solution to this specific issue. If these projects get enough traction, like govendor, perhaps the language authors will at some point incorporate the most popular solutions into the language platform. At least it'll save everyone else from rewriting the same tool.
I'd be interested in reading a bit more about the problems you experienced. Can you recommend any articles or blog postings that describe what kinds of problems people tend to have?
I also use a Makefile to setup an ad hoc GOPATH to workaround this.
I'm not thrilled about the GOPATH either. Not least because there is no really clean solution for actively developing code inside the GOPATH and working with GitHub.
Also, I would have liked dependencies to be automatically downloaded and installed in a local cache rather than me having to crap it into the GOPATH by manually issuing a "go get". I had hoped we were done with that.
But I can live with it because it requires no explanation to new developers on a project.
Using some hack to "solve" problems means forcing developers to learn even more stuff before getting started on projects. And one might say "but it is only one small thing", but that has sort of been the mantra in the Java world. And it isn't so small when you spend 2 weeks learning Java and 5 years learning about the little small things that have been put in any non-trivial project.
Even if it does, I'm a big fan of still mentioning it in the README. For my Go projects, it's usually just one sentence: "This project is go-gettable, or you can make && make check && make install". Avoids a lot of useless confusion.
Actually, I'm starting to think that the solution is to have per project GOPATH instead and build switching into the shell or the editor. Because messing with Makefiles is just about the last thing I'd like to do (it never stops there. it always escalates)
Moreover, an integrated package management tool to build the vendor folder is coming soon [2]. We're getting there, now that the problem is getting more understood!
[0]: https://research.swtch.com/go2017
[1]: https://github.com/golang/go/issues/17271
[2]: https://blog.gopheracademy.com/advent-2016/saga-go-dependenc...
The more I experience go, the more I feel like the core team existed in a bubble away from the past 25 years of advancement in programming languages. They're stuck solving the problems they had with C, without the benefit of learning from or improving on any other modern languages or toolsets.
>Other languages get this right, so why can't Go?
Which one? I mean just compare this with other languages/systems that supposedly get it right, e.g. Java with Maven oder node.js with npm. They are complex monsters under the hood, ready to break for sometimes uncontrollable reasons.
I really like the Go philosophy of being able to build and install cross-platform without any Makefile or even autoconf. As a developer I can choose whether to work with plain vi, Sublime or Eclipse with Go plugin.
The only scripts I ended up writing were unit test automation (find -d . and then calling go test) and .deb pkg generation.
IMHO the Go devs should rather communicate more why things are designed the way they are. Another often disputed feature is no generics. I really miss them as well, but maybe Go is just not well suited for every problem. Writing a linear algebra is probably better done in C++ or Scala than Go. Go is really good for building reliable Server software however.
Yeah, it is really that simple. In my experience, most people are confused by this due to its simplicity. It feels like you missed a step or two coming from other toolchains.
I think the problem with Go is that it's attracted a lot of developers from languages like Python where you just install the runtime and a shebang at the top for the code then call it as if it were a native ELF. No AOT language can work that simply. But given a choice between makefiles and the Go CLI, I'd take the Go design every time.
I recommend reading https://github.com/cloudflare/hellogopher#why for more insight.
There’s also a gif demo https://twitter.com/FiloSottile/status/822745605806112768
EDIT: uploaded the keynote I gave at Golab where I present the problem and introduce this project https://vimeo.com/200469720
There is no way a standalone tool couldn't reproduce this behavior on Windows, and the eventual integrated solution definitely will, but it's just beyond the scope of hellogopher and outside my expertise.
Or does it actually do anything else (except "break" windows builds - or rather introduce a system complementary to "got get" that isn't quite as cross platform as go itself)?
It doesn't break anything, since you can still use go get, go build, or anything that worked before. It doesn't help Windows users, but it doesn't hurt them.
The default gopath does not help there. Sure, if a user knows how to use go's insane global-project-directory-bullshit then they don't need this, but since it's a go-specific bullshit, they might not.
Every sane language lets you have a directory where you want for each unrelated project. Only go dictates some crazy tree and defaults to creating it for you in $HOME
And isn't "fixing" "go get" better than adding a dependency on make?
(and I guess this project in a sense is a way to fix "go get", but it seems thrasher fragile; any one project might end up with a broken makefile by accident)..
This includes downloading the Go binaries for your platform, building three C libraries, fixing gopath, and automatically determining packages for `go get`.
all:
go buildBut then go comes along and is like 'no, you MUST check this out in this particular location'. And also that location has to be 6 directory layers deep, for some reason. It's just pointlessly broken when compared to every other language, where a project is self-contained within a directory.
I think regarding convenience Go is top notch. Regarding "weirdness" it's in the middle between Unix C and Java.
That still has the same issue of all my projects following a logical structure, except for anything written in go / with a component written in go, which has at $RANDOM_LOCATION.
Plus, I think `go get` doesn't work with our internal company git server, but I'm not 100% about it.
Wellll... if you are not reeeally using Go but only for short snippets or smaller projects you can place the code anywhere you like. (Except for the external deps afaik, but even that might work with ./vendors/) In your imports you need to then use relative paths. Haven't used this coding style since some time but you can totally do that. Of course you loose some goodies like having super isolated modules but it sounds you're not after that anyway.
Disclaimer: I've used this coding style for a few 1 kLoC+ projects, but I later changed to the recommended way.
>Plus, I think `go get` doesn't work with our internal company git server, but I'm not 100% about it.
You can still manually git/hg/... clone but yeah...
thing.go:10:2: cannot find package "whatever/thing/frob" in any of:
/usr/lib/go-1.7/src/whatever/thing/frob (from $GOROOT)
($GOPATH not set)
So I go looking for GOPATH documentation, and it tells me I need to put all my source dependencies in one directory. That's unlike everything else on the planet, but OK. I do that, and set GOPATH=~/go.Now:
thing.go:10:2: cannot find package "whatever/thing/frob" in any of:
/usr/lib/go-1.7/src/whatever/thing/frob (from $GOROOT)
/home/ctz/go/src/whatever/thing/frob (from $GOROOT)
($GOPATH not set)
OK, so do I need to set GOPATH as well? thing.go:4:2: cannot find package "bytes" in any of:
/home/ctz/go/src/bytes (from $GOROOT)
($GOPATH not set)
thing.go:8:2: cannot find package "container/list" in any of:
/home/ctz/go/src/container/list (from $GOROOT)
($GOPATH not set)
That seems worse.Now somebody teaches me about 'go get'. Great!
package whatever/thing/frob: unrecognized import path "whatever/thing/frob" (import path does not begin with hostname)
(To be clear, I now can build all the golang code I want. This post is more indicative of my experience getting started a few years ago. In my opinion, GOPATH is a terrible design decision.)Yes, you need to install your deps separately. (If the maintainer decides not to use vendors/ and not check it into git) With C, the classic ./configure && make && make install also expects you to install your dependencies manually. Using Go you have a canonical way to do it. Also if you don't plan to hack on it, it's probably a got idea to go with binary packages. If there are none, the tool is probably not exactly meant for production anyway.
Thank goodness for the inclusion of sensible vendoring, by the way! Go's default system broke a lot of older code because of the native vendoring system (if you can call it that).
I would really prefer it ./vendor would be .gitignored (like .virtualenv or node_modules) and `make deps` would parse the source and fetch the deps, sort of like `go get` does. Bundling all the dependencies in your own repo just feels wrong to me. Especially if it's not git submodules (and I've heard submodules are frowned upon by those who have tried them - I've haven't had such necessity, so don't hold any opinion). At least very similar approaches had led to some really bad experiences I had in early 2000's with PHP (it was typical to bundle vendored deps there because of relative lack of package management).
For example, you could modify the Makefile to run "gvt restore" before building. However, I warmly recommend checking vendor/ in: not doing so requires the user to have gvt (or whatever tool), breaks go get, and adds unnecessary external dependencies (think left-pad).
More details here https://github.com/FiloSottile/gvt#alternative-not-checking-...
Is there any suggestions/best practices how to maintain `vendor/` under the source control? I mean, handling updates, branch merges and all the disaster that accidental local patches may bring - this sort of stuff?
there are no good upstream suggestions on how to deal with vendor.
My preference is to use to use http://glide.sh/ and store 'glide.yaml' and 'glide.lock' in the repo, at which point the vendor folder can be recreated to the correct versions without needing to parse code or checkin vendor.
Glide is also really good at handling updates, pulling from alternate sources, tracking alternate branch names, etc etc.
So my workaround is something like the following, where I generate a coverage report for each package to later concatenate them into a final coverage report
``` for i in $(go list ./... | grep -v 'vendor') do coverName="$(basename $i).coverraw" go test --ldflags '-extldflags "-static"' -v -race -coverprofile="${coverName}" "${i}" | tee -a "${test_outfile}" done```
It does exactly what you want, and it handles overlapping coverage blocks (if two packages have tests that run the same portion of code), which just concatenating will mess up. (It uses gocovmerge behind the scenes, but it will be hidden from you.)
It would be nice to include something like go2xunit so you can hook the results up to the Jenkins coverage reports.
Instead, you run hellogopher with CI=1, and it drops logs and artifacts in fixed locations, that you can then post-process as you like.
go2xunit -input "${test_outfile}" -output "${GO_TEST_JUNIT_FILENAME}"
For Jenkins compatible coverage reports you must concatenate all cover profiles and use `gocov` for conversion: echo "creating coverage report"
all_coverage_rawfile=$(mktemp tmptest.XXX)
# concatenate all raw report
echo -e "mode: atomic\n$(cat *.coverraw | grep -v 'mode: atomic')" > "${all_coverage_rawfile}"
go tool cover -html="${all_coverage_rawfile}" -o "${GO_COVERAGE_FILENAME_HTML}"
gocov convert "${all_coverage_rawfile}" | gocov-xml > "${GO_COVERAGE_FILENAME_XML}"
Edit: fix typoIt is quite a bit of coverage and Makefile magic, but it generates coverage results. The same file also allows us to wire in sharness testing (cli tests) to generate coverage report. It is quite important for us as we don't test cli in unit tests just in the sharness.
-------
The magic happens here: https://github.com/ipfs/go-ipfs/blob/ce00f384dc244f04ec7d87e...
Each package has its one coverage target, for each package I collect dependencies that are in our testing scope and then I create go test cover call that includes those dependencies.
Which means, newer posts have a higher weight. As time goes by, the score lowers. The constant gravity can be adjusted to lower or raise how fast this occurs.