<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Gopath on Roberto Selbach</title><link>https://rselbach.com/tags/gopath/</link><description>Recent content in Gopath on Roberto Selbach</description><generator>Hugo</generator><language>en-US</language><lastBuildDate>Thu, 08 May 2014 17:55:00 +0000</lastBuildDate><atom:link href="https://rselbach.com/tags/gopath/index.xml" rel="self" type="application/rss+xml"/><item><title>GOPATH is not a versioning system</title><link>https://rselbach.com/gopath-is-not-a-versioning-system/</link><pubDate>Thu, 08 May 2014 17:55:00 +0000</pubDate><guid>https://rselbach.com/gopath-is-not-a-versioning-system/</guid><description>&lt;p&gt;I reproduced a build failure only after deleting my &lt;code&gt;GOPATH&lt;/code&gt;. That sentence contains most of the problem.&lt;/p&gt;
&lt;p&gt;My normal workspace had this shape:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$GOPATH/
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; src/example.com/service
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; src/github.com/some/dependency
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; pkg/darwin_amd64
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; bin
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;go get&lt;/code&gt; fetched the dependency&amp;rsquo;s current source into the expected import path. My machine had an older checkout that still provided a function the service used. A fresh machine fetched a newer revision where the function had changed. The import path named a repository location, not the exact source revision I had tested.&lt;/p&gt;
&lt;p&gt;I briefly considered copying dependencies under a random directory in the service. In 2014 the go command does not define vendoring semantics that make such a copy transparently override the canonical import. Rewriting imports to local copies creates new package identities and a permanent maintenance chore.&lt;/p&gt;
&lt;p&gt;For deployable applications, I record the repository revisions and make the build checkout those revisions into an isolated &lt;code&gt;GOPATH&lt;/code&gt;. Some teams use scripts; others use emerging third-party dependency tools. None is yet the universal answer. Libraries have an even harder choice because pinning their transitive world can conflict with the application assembling the final program.&lt;/p&gt;
&lt;p&gt;I also keep import paths canonical. Relative imports make a package depend on where it happens to sit and behave poorly outside a narrow local experiment.&lt;/p&gt;
&lt;p&gt;The decisive experiment was a new empty workspace:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ mkdir /tmp/service-build
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ GOPATH=/tmp/service-build go get example.com/service/cmd/server
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;That made every source checkout visible under one disposable root. I recorded &lt;code&gt;git rev-parse HEAD&lt;/code&gt; for each dependency and reproduced the working set by checking out those revisions. The script fails if a revision cannot be fetched; silently falling back to a branch tip would restore the original uncertainty.&lt;/p&gt;
&lt;p&gt;Import-path compatibility remains social rather than solver-enforced. If upstream makes an incompatible change at the same path, the go command cannot select &amp;ldquo;the old API&amp;rdquo; from the import statement. Forking under a new path changes package identity, so values from original and forked packages are distinct even when declarations match.&lt;/p&gt;
&lt;p&gt;For every recorded revision I also keep its canonical repository URL. Import paths can redirect discovery, and repeatability requires knowing both what commit was selected and where the build expects to obtain it.&lt;/p&gt;
&lt;p&gt;GOPATH solves workspace layout and import discovery well. It does not solve repeatable dependency selection. Saying that plainly avoids a lot of mystical advice about cleaning &lt;code&gt;$GOPATH/pkg&lt;/code&gt;. My build was not stale; its input was unspecified.&lt;/p&gt;</description></item><item><title>GOPATH is a workspace, not a package</title><link>https://rselbach.com/gopath-is-a-workspace-not-a-package/</link><pubDate>Wed, 18 Apr 2012 20:40:00 +0000</pubDate><guid>https://rselbach.com/gopath-is-a-workspace-not-a-package/</guid><description>&lt;p&gt;I set &lt;code&gt;GOPATH&lt;/code&gt; to the directory containing one package and then wondered why &lt;code&gt;go install&lt;/code&gt; produced a peculiar path. The variable was innocent. I had mistaken the whole workspace for one shelf in it.&lt;/p&gt;
&lt;p&gt;A minimal workspace has a recognizable shape:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$GOPATH/
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; src/example.org/hello/hello.go
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; pkg/
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; bin/
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Source lives below &lt;code&gt;src&lt;/code&gt; in directories corresponding to import paths. Installed package objects go below &lt;code&gt;pkg&lt;/code&gt;, arranged for the target system. Installed commands go in &lt;code&gt;bin&lt;/code&gt;. &lt;code&gt;GOPATH&lt;/code&gt; names the root containing those areas, not &lt;code&gt;src&lt;/code&gt; itself and not the package directory.&lt;/p&gt;
&lt;p&gt;The surprise was that import paths and disk paths line up without making imports relative. Code can import &lt;code&gt;example.org/hello&lt;/code&gt;; the &lt;code&gt;go&lt;/code&gt; command searches the workspace&amp;rsquo;s &lt;code&gt;src/example.org/hello&lt;/code&gt;. The source does not need to know how many &lt;code&gt;..&lt;/code&gt; components separate two packages on my machine.&lt;/p&gt;
&lt;p&gt;This is a workspace convention, not a global registry. I can keep more than one workspace and select one through the environment. A &lt;code&gt;GOPATH&lt;/code&gt; list can also provide multiple roots, although source and installation behaviour deserve attention when doing that. For a small project, one root is easier to reason about.&lt;/p&gt;
&lt;p&gt;I prefer an import path that reflects where a package is expected to live, even before publishing it. It avoids renaming every import when the code leaves a scratch directory. I also keep third-party packages in the workspace layout rather than copying their files into my package and erasing their identity.&lt;/p&gt;
&lt;p&gt;The caveat is that the workspace does not pin dependency versions. If I update a dependency in place, every package using that workspace sees the update on its next build. Reproducible releases therefore still require discipline about the exact source revisions checked out. The layout organizes code; it does not make dependency history disappear.&lt;/p&gt;
&lt;p&gt;There is also no need to set &lt;code&gt;GOROOT&lt;/code&gt; to the workspace. &lt;code&gt;GOROOT&lt;/code&gt; identifies the Go installation and standard library. &lt;code&gt;GOPATH&lt;/code&gt; identifies my code and other non-standard packages. Giving both variables the same value is less configuration than performance art.&lt;/p&gt;
&lt;p&gt;After moving my package under &lt;code&gt;src&lt;/code&gt; and pointing &lt;code&gt;GOPATH&lt;/code&gt; at the parent workspace, &lt;code&gt;go build&lt;/code&gt;, &lt;code&gt;go test&lt;/code&gt;, and &lt;code&gt;go install&lt;/code&gt; behaved as advertised. The directory tree is opinionated, but at least it has the courtesy to be visible.&lt;/p&gt;</description></item></channel></rss>