How to pass arguments via go generate - go

Here is how my project is structure
├── cmd
│   ├── orders
│   │   ├── main.go
└── scripts
└── codegenerator.go
the codegenerator.go file is the file where i have put my code to generate the code. Here is the logic for codegenerator.go
rename main.go to old_main.go
read from old_main.go line by line and write to a new file called main.go
insert new lines/code blocks based on markers/placeholder in main.go
remove old_main.go file
The go:generate directive is in main.go like this
//go:generate go run ../../scripts/codegenerator.go
I ran go generate from command line and wanted to pass in 3 arguments so that they can be utilized in codegenerator.go. here is my command and the errors i got (i executed this command on path cmd/orders)
$ go generate arg_one arg_two arg_three
can't load package: package arg_one: unknown import path "arg_one": cannot find module providing package arg_one
can't load package: package arg_two: unknown import path "arg_two": cannot find module providing package arg_two
can't load package: package arg_three: unknown import path "arg_three": cannot find module providing package arg_three
So the questions are
Am i running go generate properly?
How can i pass in arguments from go generate command line to the target script

While I agree you may be better off using another solution, there isn't anything preventing usage of env vars (os specifics may vary)
➜ /tmp cat foo.go
package main
//go:generate python run.py $ARG
func main() {}
➜ /tmp cat run.py
import sys
print sys.argv[1]
➜ /tmp ARG=poop go generate foo.go
poop

Related

Importing external functions and logic from another go file inside same directory

I am new to golang and have been loving it so far. So far I've been writing all my applications logic inside the main.go and it is starting to get quite cumbersome with so much text on the screen. I cannot for the life of me figure out how to import external functions that are located in another .go file. Here is a basic example of what I'm trying to accomplish
main.go
package main
func main() {
SayHello() //THIS IS THE FUNCTION IMPORTED FROM hello.go
{
hello.go
package hello
import "fmt"
func SayHello() {
fmt.Println("Hello!")
{
project structure
/
-main.go
-hello.go
I know this is a fairly simple question but everything I try will result in an error in my console. All I want in this example is to export the SayHello function from the hello.go file into the main.go file, and as far as I understand anything exported must start with a capital letter. The whole go.mod file and package declaration at the top if each file confuses me and I have not been able to figure this out for hours.
You can only have a single package per directory. If you want the code in hello.go to live in a separate package, you need to move it into a subdirectory.
First, this assumes that you've initialized your project using go mod init <something>. For the purposes of this example, we'll start with:
go mod init example
This creates our go.mod file. Next, we set up the correct directory structure:
.
├── go.mod
├── hello
│   └── hello.go
└── main.go
hello.go is correct as written (well, once you fix the syntax errors in your posted code). We'll need to add an import to main.go:
package main
import "example/hello"
func main() {
hello.SayHello() //THIS IS THE FUNCTION IMPORTED FROM hello.go
}
This will build an executable that produces the expected output:
$ go build
$ ./example
Hello!

SIMPLE godoc Hello world

Trying to serve a godoc on a simple, flat code folder. The online docs do not explain how to achieve this SIMPLE task.
So, creating this simple structure,
/tmp/testgodoc$ tree
.
└── src
├── main (just the binary)
└── main.go
1 directory, 2 files
where main.go is simply
/tmp/testgodoc$ cat src/main.go
// Hello godoc
package main
import "fmt"
// Say Hello
func main() {
fmt.Println("Hello")
}
When running either in GOPATH or module modes, opening localhost:6060 in a browser does not give the expected result of documenting current folder.
Running in module mode give this output and result:
/tmp/testgodoc$ ~/go/bin/godoc -goroot=. -http=:6060
using module mode; GOMOD=/dev/null
(when Ctrl-C:) cannot find package "." in:
/src/main
^C
And running in GOPATH mode seems to point to the local standard library:
/tmp/testgodoc$ GO111MODULE=off ~/go/bin/godoc -goroot=. -http=:6060
using GOPATH mode
^C
You should put your main package into a subdirectory, maybe like this:
~/go/src/testGoDoc$ tree
├── cmd
│ └── main.go
├── go.mod
└── pkg
└── test1
└── test_package.go
and by this you can run both commands:
godoc -http=:6060 #http://localhost:6060/pkg/<module name inside go.mod>/
and
GO111MODULE=off godoc -http=:6060 #http://localhost:6060/pkg/testGoDoc/

Could not import local modules in Golang

I am trying to import local modules, but I am unable to import it using go mod. I initially built my project using go mod int github.com/AP/Ch2-GOMS
Note my environment is go1.14 and I am using VSCode as my editor.
This is my folder structure
Ch2-GOMS
│ ├── go.mod
│ ├── handlers
│ │ └── hello.go
│ └── main.go
My main.go code:
package main
import (
"log"
"net/http"
"os"
"github.com/AP/Ch2-GOMS/handlers" // This gives "could not import github.com/AP/Ch2-GOMS/handlers" lint error
)
func main() {
l := log.New(os.Stdout, "product-api", log.LstdFlags)
hh := handlers.NewHello(l)
sm := http.NewServeMux()
sm.Handle("/", hh)
http.ListenAndServe(":9090", nil)
}
I cannot see auto-complete for my local modules such as handlers.NewHello.
go build generated go.mod contents:
module github.com/AP/Ch2-GOMS
go 1.14
I am also getting You are neither in a module nor in your GOPATH. Please see https://github.com/golang/go/wiki/Modules for information on how to set up your Go project. warning in VScode, even though i have set GO111MODULE=on in my ~/.bashrc file
Read: Ian Lance Taylor's comment (Go's Core Team)
I know of three ways:
Method 1 (The best way):
# Inside
# Ch2-GOMS
# │ ├── go.mod
# │ ├── handlers
# │ │ └── hello.go
# │ └── main.go
# In Ch2-GOMS
go mod init github.com/AP/Ch2-GOMS
# In main.go
# Add import "github.com/AP/Ch2-GOMS/handlers"
# But, make sure:
# handlers/hello.go has a package name "package handlers"
You must be doing something wrong and that's why it's not working.
Method 2 (The good way):
# Inside
# Ch2-GOMS
# │ ├── go.mod
# │ ├── handlers
# │ │ └── hello.go
# │ └── main.go
# Inside the handlers package
cd Ch2-GOMS/handlers
go mod init github.com/AP/Ch2-GOMS/handlers # Generates go.mod
go build # Updates go.mod and go.sum
# Change directory to top-level (Ch2-GOMS)
cd ..
go mod init github.com/AP/Ch2-GOMS # Skip if already done
go build # Must fail for github.com/AP/Ch2-GOMS/handlers
vi go.mod
Inside Ch2-GOMS/go.mod and add the following line:
# Open go.mod for editing and add the below line at the bottom (Not inside require)
replace github.com/AP/Ch2-GOMS/handlers => ./handlers
# replace asks to replace the mentioned package with the path that you mentioned
# so it won't further look packages elsewhere and would look inside that's handlers package located there itself
Method 3 (The very quick hack way for the impatient):
Turn off Go Modules GO111MODULE=off
Remove go.mod file
# Check: echo $GOPATH
# If $GOPATH is set
mkdir -p $GOPATH/src/github.com/AP/Ch2-GOMS
cd $GOPATH/src/github.com/AP/Ch2-GOMS
# If $GOPATH is unset
mkdir -p ~/go/src/github.com/AP/Ch2-GOMS
cd ~/go/src/github.com/AP/Ch2-GOMS
# Now create a symbolic link
ln -s <full path to your package> handlers
Reason: During the build, the compiler first looks in vendor, then GOPATH, then GOROOT. So, due to the symlink, VSCode's go related tools will also work correctly due to the symlink provided as it relies on GOPATH (They don't work outside of GOPATH)
Below are the steps-
on main folder - go mod init
2.go mod tidy
3.go to the folder where main file is present
4.install the package via
go get <package name>
5.go build
Before above steps your project path should be
project path = GOPATH/src/<project_name>
Along with there should be 2 more folder parallel with src folder
src
pkg
bin
when ever you install any package it should be go inside pkg folder
and after doing go mod tidy there should be one file generated
go.mod
List item
go mod tidy alone at root folder did it for me
If you want to import local modules, you need to map the module path such that it can find the code in your local file system.
First use the go mod edit command to replace any imports to module to the local file
$ go mod edit -replace example.com/greetings=../greetings
The command specifies that example.com/greetings should be replaced with ../greetings for the purpose of locating the dependency. After you run the command, the go.mod file in the current directory should include a replace directive in its mod file
After that use the go mod tidy command to synchronize dependencies, adding those required by code where you imported but not yet traced by the current module
$ go mod tidy
Referred from the official documentation

How to fix Go build error "can't load package" with Go modules?

I'm setting up a new project using Go modules with this tutorial, and then trying to build it.
The module is located in a folder outside of the $GOPATH with the following structure:
example.com
├── my-project
├── ├── main
├── ├── ├── main.go
├── ├── go.mod
I've run go mod init example.com/my-project in directory example.com/my-project and created the go.mod file shown above.
main.go has basic contents:
package main
import (
"fmt"
)
func main(){
fmt.Println("Hello, world!")
}
After attempting to run go build in directory example.com/my-project, I receive the following error message:
can't load package: package example.com/my-project: unknown import path "example.com/my-project": cannot find module providing package example.com/my-project.
I've also attempted to run go build in directory /, outside of example.com/my-project, and I get similar, failing results:
can't load package: package .: no Go files in ...
I'm probably getting some basic thing wrong, so thanks for your patience and any help you can give.
no need for the directory main,
just move your main.go and go.mod to example.com/my-project and it will work.
Project root should look like:
.
├── go.mod
└── main.go
In my case it was that the variables GOMOD and GOWORK were taking other values different from the project I solved it by executing the command go env and verifying the values of those variables and deleting the files of that address.
Then I removed the go.mod and go.sum file from the project and ran the following commands again:
go mod init projectName
go mod tidy
go run ./...
And it worked perfectly.

How can I resolve dependencies in nested application binary in Go project?

This sounds stupid, but I am trying for build my new golang project for a while now and I am stuck with following error
can't load package: package github.com/kuskmen/yamq/cmd/yamq-client: found packages main (main.go) and yamqclient (yamq-client.go) in C:\projects\yamq\cmd\yamq-client
I know this should be straightforward to fix, but I come from .NET and I am still not experienced in Go projects and its dependency resolution model hence the struggle.
My project structure looks like so
/yamq
/cmd
/yamq-client // yamq client application binary
main.go // package main
yamq-client.go // package yamqclient
/yamq-server // yamq server application binary
main.go // package main
yamq-server.go // package yamqserver
go.mod // contains only "module github.com/kuskmen/yamq" for now
... // some library files that will probably be moved to /shared folder
so far so good, when I do go build in outermost directory ( /yamq ) it is building successfully (or at least it is not showing any errors), but when I try to build either yamq-client or yamq-server binaries I get the aforementioned error and every time I try to google it or find something useful I got some old article or answer that dates back 2013-2016 that suggests something about $GOPATH and etc which shouldn't be the case here since I am trying to use go modules.
Help a fellow .NET developer join Go community by explaining him how exactly modules work cause I found this and this useless or at least I am missing the point, thanks in advance!
To follow up from my comment above:
From https://golang.org/doc/code.html:
Go programmers typically keep all their Go code in a single workspace.
A workspace contains many version control repositories (managed by Git, for example).
Each repository contains one or more packages.
Each package consists of one or more Go source files in a single directory.
The path to a package's directory determines its import path.
For your project, I'd do something like this:
$ tree
.
├── clientlib
│   └── lib.go
├── cmd
│   ├── client
│   │   └── main.go
│   └── server
│   └── main.go
├── go.mod
└── serverlib
└── lib.go
5 directories, 5 files
$ cat go.mod
module myproject.com
The module name is arbitrary (could be github.com/yourname/yourproject).
For the server side:
$ cat serverlib/lib.go
package serverlib
import "fmt"
func Hello() {
fmt.Println("Hello from serverlib.Hello")
}
$ cat cmd/server/main.go
package main
import (
"fmt"
"myproject.com/serverlib"
)
func main() {
fmt.Println("Running server")
serverlib.Hello()
}
And now we can build and run it:
$ go build -o server cmd/server/main.go
$ ./server
Running server
Hello from serverlib.Hello
The client side looks symmetrical.
Variations: you could name the .go files in cmd/... by their actual binary names - like server.go and client.go. The package in each is still main, but then go build creates an executable with the file's name (sans the .go) without needing to -o explicitly.

Resources