How do I import a project within a Go Workspace? - go

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

Related

Proper way to import a package

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

Go 'mod init' creating new folders? what is the significance of path?

Just 3 days experience in Go language. Hope an example will be more apt to understand my confusion.
root#freebsd1:/usr/home/arun/go-start/src/test2 # go mod init f1/f2/f3/f4/f5/hello
go: creating new go.mod: module f1/f2/f3/f4/f5/hello
root#freebsd1:/usr/home/arun/go-start/src/test2 #
Here in above example go mod init is creating all these folders(f1/f2/f3/f4/f5/hello)?. I searched a lot, couldn't find any such folders in system. Then what is the significance of this path.
Even though below command will not run if this path is not mentioned as it is
# go install f1/f2/f3/f4/f5/hello
--:EDIT:--
May be this will help someone later ( Just walk through the steps to understand this in a proper way, especially for newbies )
I am planning to create a program 'calculator' and will upload in GitHub later.
I will keep the functions in different packages like sum,multiply etc
first step #go mod init github.com/go-arun/calculator( Don't confuse here , this is just an assumption that, in future I may create a repository in github for this project )
created folder sum(one of the package folder , and created sum.go inside )
See those in by system:
1.
root#debian1:/home/arun/lab# go mod init github.com/go-arun/calculator
go: creating new go.mod: module github.com/go-arun/calculator
root#debian1:/home/arun/lab# cat go.mod
module github.com/go-arun/calculator
go 1.15
2.
root#debian1:/home/arun/lab# cat sum/sum.go
package sum
import "fmt"
func Sum(num1,num2 int)(){
fmt.Println(num1+num2)
}
3.
root#debian1:/home/arun/lab# cat main.go
package main
import(
"github.com/go-arun/calculator/sum"
)
func main(){
n1 := 10
n2 := 10
sum.Sum(n1,n2)
}
4.
root#debian1:/home/arun/lab# tree
.
|-- go.mod
|-- main.go
`-- sum
`-- sum.go
go mod init does not create those folders. You pass the "module path" to go mod init which is recorded in the go.mod file it creates.
The "module path" is the import path prefix corresponding to the module root. The module path and the relative path to the module root together form the complete import path which must be unique in an app.
So for example if your module contains a folder named foo (and a package foo in it), it is imported by a path being modulepath/foo. In your case it would be f1/f2/f3/f4/f5/hello/foo.
It is allowed for moduleA to contain a foo package, and also for moduleB to have a foo package. When used / imported, first would be imported like moduleA/foo the latter like moduleB/foo, so it's unambiguous which one you're importing. The module path is like a namespace.
It's recommended to use a module path that corresponds to a repository you plan or will publish your module to, so when you do, go get will be able to automatically fetch, build and install your module. For example you may choose a module path github.com/bob/hello, so when you publish your module, everyone can get it by simply using import "github.com/bob/hello" in their app.
Also note that you don't need to publish your code to a remote repo before you can build it. But it's still recommended to follow this pattern so you'll have less work to make it work in the future if you decide to publish it. Nothing to lose here.
More in the docs: Command go: Defining a module
Also: How to Write Go Code: Code organization

Organize local code in packages using Go modules

I can not find a way to factor out some code from main.go into a local package when using Go modules (go version >= 1.11) outside of $GOPATH.
I am not importing any external dependencies that need to be included into go.mod, I am just trying to organize locally the source code of this Go module.
The file main.go:
package main
// this import does not work
import "./stuff"
func main() {
stuff.PrintBaz()
}
The file ./stuff/bar.go (pretending to be a local package):
package stuff
import "log"
type Bar struct {
Baz int
}
func PrintBaz() {
baz := Bar{42}
log.Printf("Bar struct: %v", baz)
}
The file go.mod (command go mod init foo):
module foo
go 1.12
When executing go run main.go:
If I import "./stuff", then I see build command-line-arguments: cannot find module for path _/home/<PATH_TO>/fooprj/stuff.
If I import "stuff", then I see build command-line-arguments: cannot load stuff: cannot find module providing package stuff.
If I import stuff "./stuff" with a package alias, then I see again: build command-line-arguments: cannot find module for path _/home/<PATH_TO>/fooprj/stuff.
I can not find a way to make local packages work with go modules.
What's wrong with the code above?
How can I import local packages into other Go code inside a project defined with Go modules (file go.mod)?
Module structure
The most common and easiest approach is:
Use a single go.mod per repository, and
Place the single go.mod file in the repository root, and
Use the repository name as the module path declared in the module line in the go.mod
(If you are using a custom import path such as me.io/mymod rather than using a VCS host based import path, then you would use the custom import path instead of the repository name in your go.mod).
For example, if your repo is github.com/my/repo, then you would place a single go.mod in the repo root, with the first line reading module github.com/my/repo. That can be created by cd'ing to the repo root and running go mod init github.com/my/repo. When working with the repo locally, the repo directory can be located wherever is convenient on your filesystem. (If you do not have a repo, see below).
Following this helps you stay on the happy path with modules, and it avoids multiple subtleties.
Russ Cox commented in #26664:
For all but power users, you probably want to adopt the usual convention that one repo = one module. It's important for long-term evolution of code storage options that a repo can contain multiple modules, but it's almost certainly not something you want to do by default.
There is much more about multi-module repositories in the "Multi-module Repositories" FAQ section on the modules wiki. Those 6 or so FAQs in that section should be read in their entirety by anyone considering veering off the recommendation above.
Arranging packages within a module
Once you have set up your go.mod, you can arrange your packages in directories however you see fit in directories underneath the directory containing the go.mod, as well as in the directory with the go.mod. Three good articles about how to arrange your code in packages:
https://rakyll.org/style-packages/
https://medium.com/#benbjohnson/standard-package-layout-7cdbc8391fc1#.ds38va3pp
https://www.goinggo.net/2017/02/design-philosophy-on-packaging.html
Those articles are classics that pre-date the introduction of modules, but the philosophies in them still apply to how to arrange your packages within a module.
Importing other packages in the same module
When importing another package with modules, you always use the full path including the module path. This is true even when importing another package in the same module. For example, if a module declared its identity in its go.mod as module github.com/my/repo, and you had this organization:
repo/
├── go.mod <<<<< Note go.mod is located in repo root
├── pkg1
│   └── pkg1.go
└── pkg2
└── pkg2.go
Then pkg1 would import its peer package as import "github.com/my/repo/pkg2". Note that you cannot use relative import paths like import "../pkg2" or import "./subpkg". (This is part of what OP hit above with import "./stuff").
Modules vs. repositories vs. packages vs. import paths
A Go module is a collection of related Go packages that are versioned together as a single unit. Modules record precise dependency requirements and create reproducible builds.
Summarizing the relationship between repositories, modules, and packages:
A repository contains one or more Go modules (most often exactly one module in the repository root).
Each module contains one or more Go packages.
Each package consists of one or more Go source files that all reside in a single directory.
Each Go source code file:
declares its own package with a package foo statement, which must be consistent for all Go files in a single package directory.
automatically has access to other Go source code in the same package, without explicitly importing its own package.
imports code from another package via an import path supplied in an import statement such as import "github.com/my/repo/pkg1". The import path always starts with the module path of that package, regardless of whether that package is in the same module or a different module.
A single module can be used to build multiple executable binaries, but the func main() {...} entry point for each binary must be in its own package main, with each package main in a distinct directory.
Local-only modules
You can create, build and run modules without ever publishing them or placing them on a VCS server.
A module is defined by a tree of Go source files with a go.mod file in the tree's root directory, so you can pick a directory on your local filesystem to serve as the root of your module and place your go.mod there. Everything described above still applies, except there does not need to be a repo.
For example:
some-directory/
├── go.mod <<<< go.mod at module root declaring 'module example.com/foo'
├── pkg1
│ └── pkg1.go
└── pkg2
└── pkg2.go
If the module path in the first line of that go.mod reads module example.com/foo, then pkg1 would import its peer package as import "example.com/foo/pkg2".
Of course, you can start with a local-only module without a repo, then later start tracking it in a local repo or publish it to a VCS server.
Even for local-only modules, it is a good idea to give the module a globally unique name, such as go mod init my.org/foo, or go mod init github.com/some/repo as if it will be published someday, even if that repo does not yet exist. (If you are in a hurry, it is possible to use a shorter module name without a dot or leading hostname component, such as go mod init temp or go mod init m, but it won’t be fetchable by the go command, and you run the risk of colliding with a current or future standard library package or otherwise seeing confusing error messages later).
If you have multiple local modules, you can point them at each other via replace directives or via the Go 1.18+ workspace feature, though those are more complex workflows than placing everything for a given project in a single module.
Next steps
If you are new to Go modules, it is worthwhile to go through the official "Create a Go Module" tutorial from the Go project. This will likely save you time overall.
If you are stuck right now with an error message related to modules or import paths, there's a very good chance the error will make much more sense after completing the tutorial.
First you have to choose a name for your project and write it to go.mod file. This name belongs to root directory of the project. Each new package you create must be located inside its own subdirectory and its name should match directory name.
go.mod:
module myprojectname
or (preferred way, see #thepudd's answer for details)
module github.com/myname/myproject
Then import your project's packages like:
import myprojectname/stuff
or
import github.com/myname/myproject/stuff
Files of package stuff should be located inside project's stuff directory. You name these files as you like.
Also it's possible to create deeper project structure. For instance, you decided to separate source code files from other ones (like app configs, docker files, static files, etc...). Let's move stuff directory inside pkg, every go file inside pkg/stuff still have stuff package name. To import stuff package just write:
import myprojectname/pkg/stuff
Nothing stops you from creating more levels in the hierarchy like github.com/myuser/myproject/pkg/db/provider/postgresql, where:
github.com/myuser/myproject - project name.
postgresql - package name.
pkg/db/provider/postgresql - path to the package relative to project's root.
You can read more about go modules here: https://github.com/golang/go/wiki/Modules
Check out this repository to get useful information about various patterns used in project organizing: https://github.com/golang-standards/project-layout If you go inside pkg directory you will find out which open source projects use pkg directory in their structure.

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

How do I resolve "cannot find module for path X" importing a local Go module?

In my Go project, I want to break out some generic functionality into a Go module, separate from the main project. I'm doing this outside of GOPATH in keeping with go's future. I don't want to publish the module on GitHub or anywhere else.
All my attempts to import this module into the main project result in:
cannot find module for path X
I've run go mod init X in the module's folder. The contents of its go.mod file is:
module X
Building or installing this module seems to do nothing. I've found no sign of it in $GOPATH/pgk/mod.
I've tried a variety of import statements:
import "X"
import "../x" (relative path to the module directory)
import "../x/X" (path to the directory + module name)
Help!
So you wrote a Go "library" module X which:
you don't want to publish on GitHub or elsewhere
you want to import and use in your project (the "main" module).
Use a replace directive along with require
In your main module's go.mod, add the following lines:
require "X" v0.0.0
replace "X" v0.0.0 => "{local path to the X module}"
The path should point to the root directory of X. It can be absolute or relative.
To import package util from module X:
import "X/util"
(You don't import modules. You import packages from modules.)
Explanation
Go's module functionality is designed for publicly published modules. Normally, a module's name is both its unique identifier and the path to its public repo. When your go.mod declares a module dependency with the require directive, Go will automatically find and retrieve the specified version of the module at that path.
If, for example, your go.mod file contains require github.com/some/dependency v1.2.3, Go will retrieve the module from GitHub at that path. But if it contains require X v0.0.0, "X" isn't an actual path and you will get the error cannot find module for path X.
The replace directive allows you to specify a replacement path for a given module identifier and version. There are many reasons you'd want to do this, such as to test changes to a module before pushing them to the public repo. But you can also use it to bind a module identifier to local code you don't ever intend to publish.
More details in the Go Modules documentation:
Can I work entirely outside of VCS on my local filesystem?
When should I use the replace directive?
Hope this helps.
If you don't want to use Go modules, you don't need to. As of Go v1.13, by default, go modules are used. Therefore, you need to tell explicitly if you don't want to do this.
Example:
main.go:
package main
import (
"fmt"
"./pakk"
)
func main() {
fmt.Println("Hello" + pakk.World())
}
pakk/pakk.go:
package pakk
func World() string {
return " world"
}
In this case, running go run main.go will output
build command-line-arguments: cannot find module for path .../pakk
but running
GO111MODULE=off go run main.go
will output
Hello world
Spent 4 days figuring this out. Very disapointed, but the way to import ./X
is as following:
first issue this magic command:
go mod init poop/strawberry/monkey
then you can EASILLY import your ./X folder:
import (
"poop/strawberry/monkey/X"
)
Folder structure:
./X/X.go
./main.go
./go.mod
contents of go.mod:
module poop/strawberry/monkey
this is the awesome solution from go module creators
https://go.dev/ref/mod#go-mod-init
module path: A path that identifies a module and acts as a prefix for package import paths within the module. For example, "golang.org/x/net"
go mod init api.com
// "api.com" name your app , it's alike swift 's bundle identifier , your can also "whatever.youlike"
myExample
Error ? Go cannot resolve the path to your modules, this is probably from misconfiguration or (not configuring) of the "go.mod" file used for project dependency tracking.
Solution lets assume your project folder looks like below;
/
|-- folderOne/
|-- folderTwo/
|-- folderThree/
|-- main.go
And the main.go script imports the modules folderOne,folderTwo and folderFour's script (folderfour.go) imports the module folderThree.
folderOne:
execute in the commandline:
go mod init github.com/../folderOne (i.e path from github.com folder to folderOnes)
The go mod init command creates a go.mod file to track your code's dependencies
folderTwo:
execute in the commandline:
go mod init github.com/../folderTwo (i.e path from github.com folder to folderTwos)
The go mod init command creates a go.mod file to track your code's dependencies
folderThree:
execute in the commandline:
go mod init github.com/../folderThree (i.e path from github.com folder to folderThrees)
The go mod init command creates a go.mod file to track your code's dependencies
folderFour:
execute in the commandline:
go mod init github.com/../folderThree (i.e path from github.com folder to folderFour)
Go to the folderFours script and import the module folderThree i.e
import "github.com/../folderThree"
in folderfours commandline:
$ go mod edit -replace github.com/{pathto}/folderThree=./folderThree**
then execute: go mod tidy
in your projects root folder execute the command: go mod init github.com/../ProjectRootDirectory (i.e path from github.com folder to ProjectRootDirectory)
then to import the modules, i.e folderThree, folderTwo, folderOne
execute the following at the projects root folder(ie folder with main.go)
$ go mod edit -replace github.com/{pathto}/folderOne=./folderOne
$ go mod edit -replace github.com/{pathto}/folderTwo=./folderTwo
$ go mod edit -replace github.com/{pathto}/folderFour=./folderFour
then execute;
$ go mod tidy
and then
$ go run main.go

Resources