How to separate code in different directory by 'go mod'? - go

My source directory layout like
mywork/libA
mywork/libA/liba.go
mywork/libA/go.mod
mywork/progB
mywork/progB/go.mod
mywork/progB/progb.go
In mywork/libA/ directory, I type go mod init example.com/mywork/liba.
In mywork/progB/ directory, I type go mod init example.com/mywork/progb.
libA/liba.go
package liba
func Hi() string { return "hi" }
libA/go.mod
module example.com/mywork/liba
go 1.13
progB/progb.go
package main
import "example.com/mywork/liba"
func main() { println("progb:", liba.Hi()) }
progB/go.mod
module example.com/mywork/progb
go 1.13
The go build in libA directory is workable. But the go build failed in progB and shows
build example.com/mywork/progb: cannot load example.com/mywork/liba: cannot find module providing package example.com/mywork/liba
How to correct it?

progB/go.mod should add require and replace statements in https://github.com/golang/go/wiki/Modules#can-i-work-entirely-outside-of-vcs-on-my-local-filesystem
module example.com/mywork/progb
require example.com/mywork/liba v0.0.0
replace example.com/mywork/liba => ../libA
go 1.13

Related

Go: import package from the same module in the same local directory

I want to create new package mycompany that will be published on Github at github.com/mycompany/mycompany-go (something similar to stripe-go or chargebee-go for example).
So I have created a folder ~/Desktop/mycompany-go on my MacOS. Then inside that folder I run go mod init github.com/mycompany/mycompany-go.
I have only these files in that local folder:
// go.mod
module github.com/mycompany/mycompany-go
go 1.19
// something.go
package mycompany
type Something struct {
Title string
}
// main.go
package main
import (
"github.com/mycompany/mycompany-go/mycompany"
)
func main() {
s := mycompany.Something {
Title: "Example",
}
}
However I get this error:
$ go run main.go
main.go:4:3: no required module provides package github.com/mycompany/mycompany-go/mycompany; to add it:
go get github.com/mycompany/mycompany-go/mycompany
I think that this is a wrong suggestion, because I need to use the local version, in the local folder, not get a remote version.
Basically I need to import a local package, from the same folder, from the same module.
What should I do? What's wrong with the above code?
You can't mix multiple packages in the same folder.
If you create a folder mycompany and put something.go inside it, that should fix the problem
The Go tool assumes one package per directory. Declare the package as main in something.go.
-- main.go --
package main
import "fmt"
func main() {
s := Something{
Title: "Example",
}
fmt.Println(s)
}
-- go.mod --
module github.com/mycompany/mycompany-go
go 1.19
-- something.go --
package main
type Something struct {
Title string
}
Runnable example: https://go.dev/play/p/kGBd5etzemK

Get missing package golang.org/x/text/encoding/unicode import cycle

I'm trying to reproduce this go issue, but can't easily build their example:
$ cat main.go
package main
import ("fmt"; "golang.org/x/text/encoding/unicode")
func main() {
res, err := unicode.UTF16(unicode.BigEndian, unicode.UseBOM).NewDecoder().String(" ")
fmt.Println(res, err)
}
$ go mod init golang.org/x/text/encoding/unicode
go: creating new go.mod: module golang.org/x/text/encoding/unicode
go: to add module requirements and sums:
go mod tidy
$ go mod tidy 1>/dev/null 2>/dev/null
$ go build main.go
package command-line-arguments
imports golang.org/x/text/encoding/unicode
imports golang.org/x/text/encoding/unicode: import cycle not allowed
go mod init golang.org/x/text/encoding/unicode
I suspect you should not initialise a project with a module name using the same name as your import.
Try:
go mod init test

Creating a project with Go modules

I'm trying to understand Go modules and create a simple hello world program. Go version: 1.16.2
/project1
/project1/main.go
/project1/helpers/helpers.go
helpers.go will contain some utility method like:
package ???
import "fmt"
func DoSomething() {
fmt.Println("Doing something in helpers.go")
}
main.go will use methods from helpers.go like this:
package main
import "??"
func main() {
helpers.DoSomething()
}
VSCode is not allowing me to do this and has a red underline on helpers.
What am I missing here? How can I achieve this?
Edit 1: Adding go.mod and package names:
So I ran go mod init helpers in /helpers folder and came out with this:
/project1/helpers/helpers.go
/project1/helpers/go.mod
go.mod
module helpers
go 1.16
My main.go now looks like this:
package main
import (
"fmt"
"helpers"
)
func main() {
fmt.Println("blah")
helpers.DoHelperMethod()
}
Your project should have only one go.mod file and it should be in the root of the project. You can cd into the project's directory and do go mod init <module_name> where <module_name> in your case can be project1.
For example, once you've initialized the module, your project should look something like the following:
/project1/helpers/helpers.go
/project1/main.go
/project1/go.mod
go.mod
module project1
go 1.16
main.go
package main
import "project1/helpers"
func main() { helpers.DoHelperMethod() }
helpers/helpers.go
package helpers
func DoHelperMethod() {
// ...
}

Go get error while getting major version module dependency

I have an executable go module and i am trying to execute the below command
go get github.com/saipraveen-a/number-manipulation/v2
and get this error:
module github.com/saipraveen-a/number-manipulation#upgrade found (v1.0.1), but does not contain package github.com/saipraveen-a/number-manipulation/v2
number-manipulation is a non-executable go module with the following tags
v1.0.0, v1.0.1 and v2.0.0.
I am new to go. So someone please tell me what is the issue here.
Module with main package
app.go
package main
import (
"fmt"
"github.com/saipraveen-a/number-manipulation/calc"
calcNew "github.com/saipraveen-a/number-manipulation/v2/calc"
)
func main() {
result := calc.Add(1, 2)
fmt.Println("calc.Add(1,2) =>", result)
result = calc.Add(1, 2, 3, 4, 5)
fmt.Println("calc.Add(1,2,3,4,5) =>", result)
newResult, err = calcNew.Add()
if err != nil {
fmt.Println("Error: =>", error)
} else {
fmt.Println("calcNew.Add(1,2,3,4) =>", calcNew.Add(1, 2, 3, 4))
}
}
go.mod
module main
go 1.14
require github.com/saipraveen-a/number-manipulation v1.0.1
go version go1.14.3 darwin/amd64
go env
GO111MODULE=""
GOPATH="/Users/<user-id>/Golang"
GOMOD="/Users/<user-id>/GoModules/main/go.mod"
I tried set GO111MODULE=on; but that doesnt change the value of GO111MODULE
# go build app.go
go: finding module for package github.com/saipraveen-a/number-manipulation/v2/calc
app.go:7:2: module github.com/saipraveen-a/number-manipulation#latest found (v1.0.1), but does not contain package github.com/saipraveen-a/number-manipulation/v2/calc
Your github module go.mod file looks like:
module github.com/saipraveen-a/number-manipulation
go 1.14
Whereas your client code is importing v2:
calcNew "github.com/saipraveen-a/number-manipulation/v2/calc"
If you want to use the version tagged v2.0.0 you need to change the github module's go.mod file to:
module github.com/saipraveen-a/number-manipulation/v2
go 1.14
Note that this forces you to change also import paths within the library itself.
And then require the v2 path into your client go.mod file:
module main
go 1.14
require github.com/saipraveen-a/number-manipulation/v2 v2.0.0

Go import from package's vendor

How can I specify to import/use a package from the vendor instead from the GOPATH/GOROOT?
$GOPATH/src/
$GOPATH/src/github.com/
$GOPATH/src/github.com/myproject/mypkg
$GOPATH/src/github.com/myproject/mypkg/mypkgfile1.go
package mypkg
import "github.com/someproject/somepkg" // importing from vendor
type MyStruct struct {
Config somepkg.SomeStruct1
}
func New(config somepkg.SomeStruct1) MyStruct {...}
func (m *MyStruct) DoSomething() {
a := somepkg.SomeStruct1{}
b := somepkg.SomeStruct2{}
// do something with 'a' and 'b'
out := somepkg.SomeFunc(a)
}
func (m *MyStruct) MyFunc(input SomeStruct1) (output SomeStruct2, err error) {...}
$GOPATH/src/github.com/myproject/mypkg/mypkgfile2.go
$GOPATH/src/github.com/myproject/mypkg/vendor/github.com/someproject/somepkg/
$GOPATH/src/github.com/myproject/mypkg/vendor/github.com/someproject/somepkg/somepkgfile1.go
package somepkg
type SomeStruct1 struct {...}
type SomeStruct2 struct {...}
func SomeFunc(input SomeStruct1) (output SomeStruct2) {...}
$GOPATH/src/github.com/myproject/mypkg/go.mod
module gitHub.com/myproject/mypkg
go 1.1.4
require github.com/someproject/somepkg v1.0.0
$GOPATH/src/github.com/someproject/somepkg/somepkgfile1.go
package somepkg
type SomeStruct1 struct {...}
type SomeStruct2 struct {...}
func SomeFunc() {...}
$GOPATH/src/github.com/someproject/somepkg/go.mod
module gitHub.com/someproject/somepkg
go 1.1.4
require github.com/someproject/somepkg v1.0.0
$GOPATH/src/github.com/anotherproject/anotherpkpg/somepkgfile1.go
package main
import (
"github.com/someproject/somepkg"
"github.com/myproject/mypkg"
)
func main() {
// do something with somepkg
somepkg.SomeFunc()
s := somepkg.SomeStruct1{...}
myData := mypkg.New(s)
m := mypkg.MyFunc()
x := somepkg.SomeStruct1{...}
y := mypkg.MyFunc(x)
}
$GOPATH/src/github.com/someproject/somepkg/go.mod
module gitHub.com/someproject/somepkg
go 1.1.4
require (
github.com/myproject/mypkg v1.0.0
github.com/someproject/somepkg v1.0.0
)
When I'm building/running anotherpkpg/main.go I keep getting a type mismatch error like:
cannot use &s (type *"someproject/somepkg".SomeStruct1) as type *"myproject/mypkg/vendor/github.com/someproject/somepkg".SomeStruct1 in argument to mypkg.New
Its not possible at all to be able do this? I get it that type mismatch can occur if the somepkg are of different version/releases. But There is no way to reference the vendored somepkg? I would think it would get even more complex when i
vendor directories work differently in GOPATH mode than in module mode.
Since github.com/myproject/mypkg/go.mod exists, you are presumably building github.com/myproject/mypkg and its dependencies in module mode. In module mode, only the vendor contents for the main module are used, and vendor directories for other packages are always ignored, so each package has exactly one location and one definition. (With -mod=vendor each package is loaded from your vendor directory; with -mod=readonly or -mod=mod each package is loaded from the module cache.)
Since github.com/anotherproject/anotherpkg/go.mod does not exist, Go 1.15 and earlier will by default build it in GOPATH mode. In GOPATH mode, the import statements within each directory refer to the packages in the vendor subtrees of all parent directories, and the vendored packages are treated as distinct packages even if they share the same import path.
The right long-term fix for your situation is probably to start building github.com/anotherproject/anotherpkg in module mode, and to use a replace directive if needed to point it at your working copy of github.com/myproject/mypkg.
You can set that up using a sequence of commands like:
# Enable module mode for anotherpkg.
cd $GOPATH/src/github.com/anotherproject/anotherpkg
go mod init github.com/anotherproject/anotherpkg
# Use the local copy of github.com/myproject/mypkg instead of the latest GitHub snapshot.
go mod edit -replace github.com/myproject/mypkg=$GOPATH/src/github.com/myproject/mypkg
go get -d github.com/myproject/mypkg
# Resolve any additional missing dependencies to their latest versions.
go mod tidy

Resources