Golang import path best practice

13,014

Solution 1

The answer to your question:

I don't know what is the proper way to define the import path for local packages.

As @JimB said:

If you want to use the Go tools you need to follow the conventions. If you want go get to work, then you need to import it with the full name, otherwise put it wherever you want in GOPATH

So you need to use the complete import path github.com/levin/foo if you want go get to work, and you should do it this way if you expect other people to use your package.

The answer to your second question:

Wouldn't it cause much rework if I move my codes to Bitbucket or I host my own git server in AWS?

There is a way to use a custom domain name as import path and still host your code wherever you want, it's called a vanity import path I think. You just need to add some meta tags to the html file that gets served in the import file that you use.

This article explains how to do it, but in summary, in the file that gets served in your custom domain when the custom import path is accessed, you need to add a go-import meta tag that points to where you hosted the code. The article uses github.com/foo/bar as example of where you are hosting your code and foo.com/bar as your real import path.

So in the file that gets served when accessing foo.com/bar there should be a meta tag like this:

<meta name="go-import" content="golang.org/x/tools git http://github.com/foo/bar">

And you continue to host your code in github. Then if you change the hosting place to your code you just change the value of the meta tag, but all the code that uses the package continue to use the exact same import path "foo.com/bar.

The only issue with this is that now your project can get imported by 2 different paths: foo.com/bar and github.com/foo/bar. To fix this they have canonical imports which only allow the package to be imported using the custom path and not the github one, it's only adding a comment next to the package name on each package file:

package bar // import "foo.com/bar"

This is the only way to avoid the issue you have. You can use @srxf answer if you are using a package that is just going to be used locally just know that the go tools are not going to work with that code (like go get). If you want the code to work as it is intended then this is the way to go.

As a comment, I know it feels silly importing github.com/levin/foo for a local package, but if you use that package in another package (say foo2) and someone else imports foo2, this allows the compiler to know exactly where to get the dependencies for foo2, because all the import in the code include the whole route, not the name of a local file. This way people can always get the dependencies they need for your package without having to include those files in your repo, and without having to configure anything for it to work. It's not perfect but it's the way go works, they call it convention over configuration or something like that.

Solution 2

This question should probably be re-answered as of Go 1.11 with the introduction of Go Modules. Modules can be used to solve this "local path" dilemma as well as pesky projects outside the scope of GOPATH. You may now initialize your project via...

go mod init <main package name>

You may then reference a local package by their package name. Like this...

go mod init app

Then (assuming you have another local package called "models") reference within your file

import (
  "app/models"
)

Refs:

https://github.com/golang/go/wiki/Modules

Accessing local packages within a go module (go 1.11)

Share:
13,014

Related videos on Youtube

Levin Kwong
Author by

Levin Kwong

Updated on September 16, 2022

Comments

  • Levin Kwong
    Levin Kwong about 1 year

    I am currently working on a private project using Golang (and I am new to it).

    But I have the problem that I don't know what is the proper way to define the import path for local packages.

    I have the same feeling as the author from this link https://medium.com/@c9s/golang-the-annoying-remote-import-path-c6c7e76517e5

    In short, if I host a project foo in Github. I feel strange to use github.com/levin/foo as import path instead of just foo. Wouldn't it cause much rework if I move my codes to Bitbucket or I host my own git server in AWS?

    And worse, I can rewrite my code to change the import path, but how would people using my code in theirs notify the change of repo? And I feel no sense to ask others to update their codes.

    I am new to Golang so feel free to say something like "your question is not even valid".

    • JimB
      JimB about 6 years
      If you want to use the Go tools you need to follow the conventions. If you want go get to work, then you need to import it with the full name, otherwise put it wherever you want in GOPATH.
  • Levin Kwong
    Levin Kwong about 6 years
    @Topo Thanks! I may need time to digest.
  • Levin Kwong
    Levin Kwong about 6 years
    @Topo Let say I use github.com/foo/bar at first, and later I changed to foo.com/bar. Also, I use canonical import after the change of repo. What exactly will happen in someone else project that originally has the code import "github.com/foo/bar" ???
  • Topo
    Topo about 6 years
    If they keep working with the same version of your code than before, then it will keep working because the restriction is on the go command locally. But if they git pull the code to get the version with the new change then they will get this error: can't load package: package github.com/foo/bar: code in directory $GOPATH/src/github.com/foo/bar expects import "foo.com/bar". Also if they try to go get the code using the github path it will give them an error. So it's better to do it sooner rather than later.
  • Topo
    Topo about 6 years
    @LevinKwong Although a quick google search for the error and/or a comment on the project README will probably let them know what the issue is and fix it, so it's not the worst case, but if you are just starting your project I think you should do it. If it's an old project people already use, you can let them know in advance, do the vanity import and then at a later date do the canonical import so they have time to fix it.