Proper way to import a package - go

Being new to Go this is the way I'm currently importing a package that I created. As an example:
folder path: loader\types
filename: types.go
package types
func SomeVal() string {
return "ABC"
}
folder path: loader
filename: main.go
package main
import (
"loader/types
)
func main() {
fmt.PrintLn(SomeVal())
}
My question is I create another application name tester and want to reuse the types.go code, I would have to do the following
folder path: tester\types
filename: types.go
package types
func SomeVal() string {
return "ABC"
}
folder path: tester
filename: main.go
package main
import (
"tester/types"
)
func main() {
fmt.PrintLn(SomeVal())
}
Is there a way to avoid calling the root folder "tester" or "loader" in the import from the main.go files? The issue I'm facing is that I have another package
folder path: loader\view
filename: view.go
package view
import (
"loader/types"
)
func AnotherValue() string {
return SomeVal()
}
So if I decide to use both loader/types and loader/view in another project, I would have to change the root folder when importing.
Again I'm new to Go so I could be looking at it incorrectly.
Thanks

If you want to use your modules (loader) which contains types and view packages in other project (e.g. in other repositories), you would need to transform loader into a reusable module/library. Go makes use of Git for this.
This involves creating a go.mod file to indicate that this project is a valid Go module. As you said, https://go.dev/doc/tutorial/create-module is a good starting point.
Usually, you can put this module in your repository, or in github, and so the module name should be the Git repo path, e.g. gihub.com/adviner/loader, something that you would put on top of your go.mod file.
go.mod in loader project:
module github.com/adviner/loader
go 1.19
If this module is hosted in public repo like github, Go will be able to retrieve it later. If you host it in a private repository that requires authentication to download, read more about using the GOPRIVATE environment variable from https://go.dev/ref/mod#environment-variables. Another approach is to just store this module in your local directory and use replace when using this module from another project.
It is a best practice that a Go project always have a go.mod file. So when you create a new project, let's say projecta, you might have a go.mod like this:
module github.com/adviner/projecta
go 1.19
require (
github.com/adviner/loader v1.0.0
)
replace (
github.com/adviner/loader => ../path/to/loader
)
We can use replace to replace the module with a local path so Go does not try to look for the module in github.com. This is not meant to be a permanent solution though. Usually you can just put your library in github or other private repository and remove the replace statement so you can work on the same project without having to transfer the loader module from one device to another.
PS. v1.0.0 here is the version that is tagged in your loader module. It is usually a tag that is added in your Git commit. If you don't have any Git tag in the commit you can use the commit ID.
PS. When naming your module github.com/adviner/loader, importing packages inside loader should now be done like so (even in the loader project itself): import github.com/adviner/loader/view and no longer loader/view.
Reference to go.mod and Go module system can be found here: https://go.dev/ref/mod

Related

How do I import a project within a Go Workspace?

I have a monorepo with multiple modules within it. Some of the modules are libraries, others are entry points that will produce binaries.
Here's my workspace project:
https://github.com/alshdavid/go-workspace-example
I have my "bar" library here which I would like to make available for import by consumers outside of this mono repo.
package main
import (
"fmt"
"github.com/alshdavid/bar"
// Or maybe: "github.com/alshdavid/gotest/modules/bar"
)
func main() {
fmt.Println(bar.Bar)
}
Trying to install the package from the workspace git repo results in failure.
go get github.com/alshdavid/gotest
go get github.com/alshdavid/gotest/modules/bar
go get github.com/alshdavid/bar # worth a shot
Is there an argument I should pass to go get that instructs to to look for a module in a nested folder or should I instead set up a pipeline that pushes my nested module to its own repository?
You must be working inside a module i.e. ran: go mod init in each of your modules in your mono repo.
For example, in your case I am assuming you have module named bar and you want to import module bar inside another module e.g. foo.
A module has a go.mod file. Inside go.mod file of your foo module you can add the following:
replace github.com/alshdavid/bar => ../bar
You can read more about this here
I just needed the complete path in the go.mod file

Conflict in repo name and module name

I created the github.com project qjson/qjson-go that contains the package name qjson that you can see here. I named the github project this way because github.com/qjson/ contains other projects for different languages (e.g. qjson-c).
Unfortunately, I get the following error when I try to import the project as github.com/qjson/qjson-go:
$ go mod tidy
go: finding module for package github.com/qjson/qjson-go
go: downloading github.com/qjson/qjson-go v0.0.0-20210128102242-170c47e2db46
github.com/xxx/xxx imports
github.com/qjson/qjson-go: module github.com/qjson/qjson-go#latest found (v0.0.0-20210128102242-170c47e2db46), but does not contain package github.com/qjson/qjson-go
I’m apparently doing it wrong. I understand that due to the import statement we are then expected to use gjson-go as package identifier.
What must I do so that the git project can be named qjson-go and the package qjson ?
I assume that one solution is to create a sub-directory named qjson inside qjson-go and move all package files in it. The user would then import "github.com/qson/qson-go/qjson". Is that correct ? Is there another solution avoiding the stutter ?
This program works as expected:
package main
import (
"fmt"
"github.com/qjson/qjson-go/qjson"
)
func main() {
fmt.Println(qjson.ErrDivisionByZero)
}
The issue is that you are using this file structure:
qjson/engine.go
qjson/errors.go
When you should just be putting them at the top level, like this:
engine.go
errors.go
So you can either fix the directory, and tag a new version, or just leave the
files as is, and change your imports to match what I have above.

Project structure and importing packages

I'm just starting to learn Go and I'm wondering how to best organize my project and import packages. I created a project at $GOPATH/src/my_project. It contains the file main.go and the folder foo containing the file bar.go.
$GOPATH/src/my_project
main.go
foo/
bar.go
My main.go looks as follows
package main
import (
"./foo"
"fmt"
)
func main() {
fmt.Println("Main")
foo.Baz()
}
Here is the foo.go
package foo
import "fmt"
func Baz() {
fmt.Println("Baz")
}
It works the way I expect it to, but I wonder if this is really the right way to structure a project and import packages, because most tutorials only import packages from github and never from local.
Thanks for your answers..
Relative imports are possible in Go but they are not encouraged to be used.
Instead you always use the full path of the package. In your case that would be my_project/foo. This is is relative to the GOPATH/src folder.
However, since we have Go modules now which make things a tiny bit more complicated to start with but have a lot of advantages in the long run.
Just earlier today I gave a step by step guide on how to set up a new project with Go modules: After go install the import doesn't recognize the package
The module name in this guide is the basis for your project then and all paths in the module build on that path. Let me give an example:
Let's say you name your module github.com/yourName/myProject. Then you can import the subpackage foo with github.com/yourName/myProject/foo.
Note: The module path should be the same as the git URL, that way you can just get the module with go get. If you don't plan on ever uploading the project to github or another git URL, you should still choose a unique name. Starting with a domain you own is a good idea -- for uniqueness.

How to share a local module in Go 1.11+ for Golang using monolithic repo architecture outside GOPATH [duplicate]

I've created a library as the module for personal use outside of "GOPATH" in "database" folder with this command "go mod init database," and I don't know:
How to use/import this module in another module?
OS: Windows 7, Go: v1.11
The easiest and working out-of-the-box solution is to put your database package / module into a VCS (e.g. github.com), so other packages (inside other modules) can simply refer to it by importing it like:
import "github.com/someone/database"
If you do so, you don't even have to fiddle with the go.mod files manually, everything will be taken care of by the go tool: it will automatically recognize and resolve this dependency, download and install the required package, and will also update go.mod automatically.
Staying entirely on local disk
If you don't want to use a VCS (e.g. you're just experimenting or you haven't decided what to use yet), then you can still do it. The how is detailed in the official Go Wiki: Can I work entirely outside of VCS on my local filesystem?
So you created a database folder outside of GOPATH, and you created a module in it. And you created another module, let's call it main, and you want to use this database package.
What you must do is:
go.mod of your main module must list the database package as a "requirement". Give a temporary VCS name to your database package:
require (
example.com/me/database v0.0.0
)
You must tell the go tool where this package is located, because the full package name we used is just a temporary / fantasy name. Use the replace directive to make this database package point to a folder on your local disk; you may use absolute and relative paths:
replace example.com/me/database => ../database
And that's all.
Working example
Let's see a working example. Let's create a pretty module. Create a pretty folder with 2 files in it:
pretty.go:
package pretty
import "fmt"
func Pretty(v ...interface{}) {
fmt.Println(v...)
}
go.mod (can be created by running go mod init pretty):
module pretty
Now let's create another, main module. Let's create a folder osinf (it may be whatever) next to the pretty folder. 2 files in it:
osinf.go (note we intend to use our pretty package / module, we import it by "example.com/me/pretty"):
package main
import "example.com/me/pretty"
func main() {
pretty.Pretty("hi")
pretty.Pretty([]int{1, 3, 5})
}
go.mod:
module main
require example.com/me/pretty v0.0.0
replace example.com/me/pretty => ../pretty
And that's all.
Running go run osinf.go in the osinf folder, the output is:
hi
[1 3 5]
Run:
go mod init yellow
Then create a file yellow.go:
package yellow
func Mix(s string) string {
return s + "Yellow"
}
Then create a file orange/orange.go:
package main
import "yellow"
func main() {
s := yellow.Mix("Red")
println(s)
}
Then build:
go build
https://golang.org/doc/code.html

Accessing local packages within a go module (go 1.11)

I'm trying out Go's new modules system and am having trouble accessing local packages. The following project is in a folder on my desktop outside my gopath.
My project structure looks like:
/
- /platform
- platform.go
- main.go
- go.mod
// platform.go
package platform
import "fmt"
func Print() {
fmt.Println("Hi")
}
// main.go
package main
import "platform"
func main() {
platform.Print()
}
go build main.go tells me
cannot find module for path platform
Let me define this first modules are collections of packages. In Go 11, I use go modules like the following:
If both packages are in the same project, you could just do the following:
In go.mod:
module github.com/userName/moduleName
and inside your main.go
import "github.com/userName/moduleName/platform"
However, if they are separate modules, i.e different physical paths and you still want to import local packages without publishing this remotely to github for example, you could achieve this by using replace directive.
Given the module name github.com/otherModule and platform, as you've called it, is the only package inside there. In your main module's go.mod add the following lines:
module github.com/userName/mainModule
require "github.com/userName/otherModule" v0.0.0
replace "github.com/userName/otherModule" v0.0.0 => "local physical path to the otherModule"
Note: The path should point to the root directory of the module, and can be absolute or relative.
Inside main.go, to import a specific package like platform from otherModule:
import "github.com/userName/otherModule/platform"
Here's a gentle introduction to Golang Modules
I would strongly suggest you to use go toolchain which takes care of these issues out of the box. Visual Studio Code with vscode-go plugin is really useful.
Problem here is that Go requires relative paths with respect to your $GOPATH/src or module in import statement. Depending on where you are in your GOPATH, import path should include that as well. In this case, import statement must include go module path in go.mod
GOPATH
Assume your project resides here:
$GOPATH/src/github.com/myuser/myproject
Your import path should be:
import "github.com/myuser/myproject/platform"
VGO
Assume your go.mod file is:
module example.com/myuser/myproject
Your import path should be:
import "example.com/myuser/myproject/platform"
As someone new to go I didn't immediately understand the accepted answer – which is great, by the way. Here's a shorter answer for those very new people!
In go modules/packages are expressed as urls that you import in your code:
import your.org/internal/fancy_module
But wait! My code isn't at a url, what's happening??
This is the cleverness of go. You pretend there's a url even when there isn't one. Because:
This makes including easier as no matter where your file is located the import uses the same url (the code stays the same even if the files move!)
You can have packages that having naming conflicts. So google.com/go-api/user doesn't conflict with the definitions at your.org/internal/user
Someday you might publish a url on GitHub and all the code will just work
That's all great Evan, but how do I import a relative path?
Good question! You can import by changing your go.mod file to have this line:
module fancy_module
go 1.16
replace your.org/fancy_module => ../path/to/fancy_module
Given the Golang Project structure
/
- /platform
- platform.go
- main.go
- go.mod
To access the methods or structs...etc (which are public) from local packages of /platform is simple, shown below
// main.go
package main
import (
p "./platform"
)
func main() {
p.Print()
}
this should work

Resources