Local repository for go modules

7,223 views
Skip to first unread message

Ignazio Di Napoli

unread,
Aug 16, 2018, 12:12:11 PM8/16/18
to golang-nuts
I'd like to experiment with modules, in a local directory. I know I can do it setting GOPROXY to a file:/// url. 
But what about looking for my own modules in a local folder, and the others normally (optionally through the proxy)? Is there a simple proxy I can configure in this way? Thank you.

Zellyn

unread,
Aug 16, 2018, 1:40:04 PM8/16/18
to golang-nuts
I think Project Athens is what you want? https://github.com/gomods/athens

thepud...@gmail.com

unread,
Aug 16, 2018, 2:20:10 PM8/16/18
to golang-nuts
Hi Ignazio,

Athens is one option, but there are also possible options depending on what you are trying to accomplish.

Could you say a few more words about your use case?

If you are doing something simple, like experimenting with creating a hello world module in something like /tmp/hello, then I'm not sure you would need to do anything special after you cd to /tmp/hello and create the go.mod file in /tmp/hello. A module is defined by a tree of Go source files with a go.mod file in the tree's root directory, so if you are inside /tmp/hello or a subdirectory, the go commands will find that go.mod file, and things should 'just work' (where all of that is on your local filesystem, with no direct tie to VCS or anything else).

If you are doing something more complex, some related questions might be-- are you creating these modules from scratch? If not, where are they coming from (GitHub, other VCS, manually copied, ___)? Is there a go 1.10 / GOPATH based workflow you already have that you are trying to map to a modules-based approach? Roughly how many modules?

The `replace` directive in go.mod is particularly flexible, and might be part of the answer. It gives additional control in the top-level `go.mod` for what is actually used to satisfy a dependency found in the Go source or go.mod files. One sample use case is if you need to fix something in a dependency, you can have a local fork and use a `replace example.com/original/import/path => your/forked/import/path` in your top-level `go.mod` (without needing to update the import paths in the actual source code). The `replace` directive allows you to supply another import path that might be another module located in VCS (GitHub or elsewhere), or you can specify the location to be on your local filesystem, which might be what you are after here, but not sure.

In any event, sorry if this is not helpful or not very specific...

--thepudds

Ignazio Di Napoli

unread,
Aug 16, 2018, 5:41:01 PM8/16/18
to golang-nuts
On Thursday, August 16, 2018 at 8:20:10 PM UTC+2, thepud...@gmail.com wrote:
Could you say a few more words about your use case?

Thank you. Looking at design docs, I think Athens can do what I'm looking for, but maybe it is a little "too much", and either docs are incomplete or I'm unable to find them (e.g.: how do I configure the proxy to tell where to find private modules?).

Let me explain my needs better.
I have developed a fairly big library I can't/don't want to publish. It could be mapped in several modules, maybe twenty. 
There is no VCS, only a tree in my own file system.

Now, I want the programs I develop to became module based and use those private modules along with other public modules.

So my idea was: I put my modules as they where in non-existant example.com.
Then, configure a proxy so that if host is example.com it returns the local file. If it is from any other url, get the remote file (optionally using a proxy). 
Is my idea correct? Has anyone already configured something like it?

Another solution could be to run a local webserver serving the files, then configure hosts file adding `127.0.0.1 example.com`, and configure a proxy exception. 
But I though a more specific solution was available (like, in effect, Athens).

Thank you.

thepud...@gmail.com

unread,
Aug 16, 2018, 7:04:20 PM8/16/18
to golang-nuts
   "There is no VCS, only a tree in my own file system."

Hi Ignazio,

I think you could go down the Athens path if you wanted to, but I don't think you need to do so.

I suspect the 'replace' directive I described in my earlier post in this thread might be sufficient for what you describe, because it lets you map from an import path like "example.com/me/foo" to something on your local filesystem.

Here is a simple example. This is a 'hello' module that imports a trivial 'goodbye' module, both of which reside on my local filesystem. Neither is checked in to a VCS. The 'hello' module also imports "rsc.io/quote" (just to show a normal import grabbed from the Internet).

Here is the file structure on my local system, all outside of GOPATH:

    /tmp/playground/hello
    |-- go.mod
    `-- hello.go
    /tmp/playground/goodbye
    |-- go.mod
    `-- goodbye.go

Here is the 'go.mod' file for the main package showing a sample use of the 'replace' directive to translate an import path of "example.com/me/goodbye" to a relative filesystem path on my local computer:

    ==> /tmp/playground/hello/go.mod <==
    

    require (
     example.com/me/goodbye v0.0.0
     rsc.io/quote v1.5.2
    )

    replace example.com/me/goodbye => ../goodbye

That's the most interesting bit. 

That 'go.mod' also happens shows a require for "rsc.io/quote" because I happened to use that as well, where that code is obtained behind the scenes from GitHub.

And to round out the example, here are the rest of the files:

    ==> /tmp/playground/hello/hello.go <==
    package main

    import (
     "fmt"

     "rsc.io/quote"
    )

    func main() {
     fmt.Println(quote.Hello())
     fmt.Println(goodbye.Goodbye())
    }

    
    ==> /tmp/playground/goodbye/go.mod <==


    ==> /tmp/playground/goodbye/goodbye.go <==
    package goodbye

    func  Goodbye() string {
          return "Goodbye"
    }

And running it from  /tmp/playground/hello/hello.go shows:

    $ go run .
   Hello, world.
   Goodbye

Hope that helps, or is at least food for thought,
--thepudds

Ignazio Di Napoli

unread,
Aug 17, 2018, 3:39:05 AM8/17/18
to golang-nuts
On Friday, August 17, 2018 at 1:04:20 AM UTC+2, thepud...@gmail.com wrote:
I suspect the 'replace' directive I described in my earlier post in this thread might be sufficient for what you describe, because it lets you map from an import path like "example.com/me/foo" to something on your local filesystem.

Thank you very much, that seems to be the easiest solution.

Paul Jolly

unread,
Sep 7, 2018, 7:30:49 AM9/7/18
to golang-nuts
I think you could go down the Athens path if you wanted to, but I don't think you need to do so.

Reply all
Reply to author
Forward
0 new messages