is there a way that go generate will skip unchanged files/ pkg - go

Is there an easy way to run go generate ./...
and in case that all the file in the pkg that call the generate didn't change- that go generate skip generating again this file?
(the reason is time consumption on generate)
For example:
-a (directory)
example1.go //contain //go:generate -output generated_example1.go
example2.go //contain //go:generate -output generated_example2.go
...
lets say i have 7 files to generate,
and I had changed only file 'example1.go'
so when i run go generate ./... I would like that it will not try to generate all the 7 files but only example1 because only this source has changed
(calling the go generate from inner directory will not solve the issue because there are couple of files to generate from same directory.)

This is not supported. The tool (command) you run with go generate may support this. See related: How to run go generate only for changed templates?
Some reasoning: go generate may be used to run arbitrary tool, not just source generation / manipulation tools, and running again may not have the same output / side effect. Also, running the tools may fail, and go generate does not keep a database of successful / failed runs, in which case it would not know which commands to run again even if source files didn't change.
All-in-all, your tool should check the existence of the desired output files (and their versions) to decide if (re-)generation is needed. This is easier than one might think though: since generation runs after the source file change, it's enough to compare the last modified timestamps. If the source (containing //go:generate) has a newer timestamp, generation should run. Otherwise it can be skipped. Note that go generate sets the $GOFILE env var to the base name of the file that triggered the command, so it's easy to check this.

Related

Set workdir/pwd of go build

Is it possible to set the workdir to a different path?
For example, I want to run go build from the root path, but my source code is under a different directory, and I do not want to cd to it.
npm, for example, has the --prefix, which serves for this purpose.
Yes, its possible.
go build -o [output file path/name] [source code file path/name]
For example, if your source code file is located in projectdir/code/src/ and want to build and save output to projectdir/code/out, do following:
$ go build -o projectdir/code/out/main projectdir/code/src/main.go
As per go build documentation:
If the named output is an existing directory or ends with a slash or
backslash, then any resulting executables will be written to that
directory.
So our above build command can be rewritten like this:
go build -o projectdir/code/out/ projectdir/code/src/main.go
and it will generate executable named main in projectdir/code/out/ directory.
For more details, run go help build
No, this is not possible with 1.19. Just cd into it.
Go 1.20 (yet unreleased) brings the -C flag which might be what you want.

Make goimports NOT scan files within vendor

I want to setup a CI system that it fails when code is not properly formatted according to goimports.
How I list my dirs:
go list -f {{.Dir}} ./...
/Users/felix/gocode/src/github.com/XXXX/YYY
/Users/felix/gocode/src/github.com/XXXX/YYY/cmd/foo
/Users/felix/gocode/src/github.com/XXXX/YYY/cmd/dev
/Users/felix/gocode/src/github.com/XXXX/YYY/pkg/monitoring/top
How I run goimports in the end:
goimports -l $(go list -f {{.Dir}} ./...)
/Users/felix/gocode/src/github.com/XXX/YYY/config.go
/Users/felix/gocode/src/github.com/XXX/YYY/raid_test.go
/Users/felix/gocode/src/github.com/XXX/YYY/vendor/github.com/shirou/gopsutil/disk/disk_freebsd.go
/Users/felix/gocode/src/github.com/XXX/YYY/vendor/github.com/shirou/gopsutil/disk/disk_linux.go
/Users/felix/gocode/src/github.com/XXX/YYY/vendor/golang.org/x/crypto/ssh/terminal/util_solaris.go
As you can see it also lists files within vendor. The execution also takes quite some time so I guess it's really checking all the files.
I really just care about the files outside vendor.
I think you use <1.9 Go version. Since 1.9 ./... shouldn't match vendor directory. See https://golang.org/doc/go1.9#vendor-dotdotdot.

How to check if a go app is buildable?

I write some code then build the app to an output file, but sometimes I just want to check if the app is buildable, i.e. has no errors and produces a compiled output, but without actually writing the output file.
I tried this variant and it seemed to work:
go build -o /dev/null myapp
But I suspect there must be a more "official" Go way to check if it can build.
Please advise!
To check if a package or app is buildable, go build is the "official" way.
What you did is the easiest way. In my opinion, you should stick to it. Alternatively you may do:
go build -o delme && rm delme
But it's somewhat slower as it has to write the result which is then deleted, but this solution is platform independent (as /dev/null does not exist on windows).
When building a command (main package), by definition go build will create and leave the result in the current working directory. If you build a "normal" package (non-main), the results will be discarded. See details here: What does go build build?
So if it bothers you that you have to use the -o /dev/null param or manually delete the result, you may "transform" your main package to a non-main, let's call it main2. And add a new main package which should do nothing else but import and call main2.Main(). Building the main2 package will not leave any files behind.
E.g. myapp/main.go:
package main
import "myapp/main2"
func main() { main2.Main() }
myapp/main2/main2.go:
// Every content you originally had in main.go
package main2
func Main() {
// ...
}
How to check if a go app is buildable?
As I understand your question, you wanted to see if the file you're editing has no error.
then you can use vim-go plugin for vim.
And then setup your .vimrc for creating the shortcut :
"shortcut for vim-go
au FileType go nmap <leader>r <Plug>(go-run)
au FileType go nmap <leader>b <Plug>(go-build)
au FileType go nmap <leader>t <Plug>(go-test)
au FileType go nmap <leader>c <Plug>(go-coverage)
I use this as my daily work life when I want to see my file has no error I just type \+b. and then it will output the error without typing go build in the terminal.
hope it helps.
One way would be gofmt -e my_file.go on all files, but:
that would not scale well
This doesn't actually report all errors that go build might.
Meaning: go build -o /dev/null might still be the more thorough approach.
For just validating syntax and structure: see gotype
I use VSCode and I've found it to be the better than Sublime when it comes to Go with this extension.
When I save the document, it formats it well. It shows the the errors as I write code with the help of golint making development very manageable.
You can also use golint separately just like gofmt.
You can also try go vet. There are debates going on around what to use when but I'd just advise to use both if you can.

what is the difference between 'make after make clean' and just 'make'?

there are C files in a directory and I have a makefile.
I usually use makefile to compile.
I have been wandering the role of the 'make clean'
'make clean' is just to remove files.
Though I didn't use 'make clean', t
he error and warning was shown up when there were something wrong.
I cannot realize why I need to use 'make clean' whenever I change the source file.
make is a utility is to determine automatically which pieces of a large program need to be recompiled, and issue the commands to recompile them.
To prepare to use make, you must write a file called the makefile that describes the relationships among files in your program, and the states the commands for updating each file.
Once a suitable makefile exists, each time you change some source files, this simple shell command:
make
suffices to perform all necessary recompilations. The make program uses the makefile data base and the last-modification times of the files to decide which of the files need to be updated.
We generally use make clean as a generic way to tell clean up the code.ie; remove all the compiled object files from the source code. You can name it as anything you like.
It's convention only. The convention is that clean will return you to a state where all you have is the "source" files. In other words, it gets rid of everything that can be built from something else (objects, executables, listings and so on).
So make clean ; make is expected to build everything from scratch. And, in fact, you'll often find a rule like:
rebuild: clean all
which will do both steps for you.
You should never have to do a clean unless you're wanting to (for example) copy just the source files somewhere. If you have to do so after editing a file, then your Makefile is not set up correctly.
And, if you make and get an error, you should get exactly the same error if you subsequently make without fixing said error.

Avoid typing out all go files in the main package when "Go run"-ng

When you have multiple .go files in a main package, i need to list them all out when doing a go run.
So when i have main.go, a.go, b.go and they all belong to the main package, i need to type go run main.go a.go b.go in order to use functions and structs inside the other 2 go files. The go build command however, is smart enough to link all files together automatically.
Have i misunderstood something about Go, or is this normal (listing out all the files in the main package when doing a go run)?
The short answer is: you need to list them all out. You can do this with shell tricks, if you're desperate. I usually just write a shell script to go build and then run the resulting executable, after it gets too annoying.
# this works unless you have _test.go files
go run *.go
# if you really want to... enable extended glob
shopt -s extglob
# so you can do something like this (matches all .go except *_test.go files)
go run !(*_test).go
Check out this thread: https://groups.google.com/forum/#!topic/golang-nuts/EOi0VAQNA4c
If your source is in $GOPATH/src
as in
$GOPATH/src/somedir/main.go
$GOPATH/src/somedir/a.go
$GOPATH/src/somedir/b.go
doing "go install somedir" will compile and install the somedir binary in to $GOPATH/bin
no need to list out the files individually
"go install" finds all the files on it's own.
My common work cycle with go is (from my bash prompt):
$ clear; go install myproj && $GOPATH/bin/myproj
which, clears the screen, builds and installs "myproj" and then runs it
so, after I change code, I just hit Ctrl-C, Up arrow, and enter.
Entire cycle time is ~1 second (for small to start stuff)

Resources