Command line application install using GoLang - go

I'm not sure how this would work but I'm basically trying to write a command line app that I can run commands and subcommands from. I'm using this popular third party library for parsing command line parameters:
https://github.com/urfave/cli
My problem is I have a project folder where my .go files will live:
MyProject
so even if in the code in my main.go file, using their example, I have:
package main
import (
"fmt"
"os"
"github.com/urfave/cli"
)
func main() {
app := cli.NewApp()
app.Name = "greet"
app.Usage = "fight the loneliness!"
app.Action = func(c *cli.Context) error {
fmt.Println("Hello friend!")
return nil
}
app.Run(os.Args)
}
when I run go install,
in my $GOPATH/bin directory, I actually get MyProject built. And then when I run MyProject from the terminal, I get
USAGE:
myproject [global options] command [command options] [arguments...]
But in reality, I don't need the myproject command first. Is there a way this is normally done with command line apps or third party packages to create command line apps so that I can run greet from the command line instead of myproject as the first command?

Check the documentation for the go build command
go build [-o output] [-i] [build flags] [packages]
When compiling a single main package, build writes the resulting
executable to an output file named after the first source file ('go
build ed.go rx.go' writes 'ed' or 'ed.exe') or the source code
directory ('go build unix/sam' writes 'sam' or 'sam.exe'). The '.exe'
suffix is added when writing a Windows executable.
When compiling multiple packages or a single non-main package, build
compiles the packages but discards the resulting object, serving only
as a check that the packages can be built.
The -o flag, only allowed when compiling a single package, forces
build to write the resulting executable or object to the named output
file, instead of the default behavior described in the last two
paragraphs.
Try building it like this go build -o greet and do not forget to add the resulting executable to your $PATH if you want it to be accessible from everywhere.
Alternatively, you can just 1) create an alias; or 2) symlink to the actual executable:
alias greet='myproject'
ln -s $GOPATH/bin/myproject greet (the link will be created in the current dir)

Related

command-line-arguments : handling "undefined" error message

Following is how the source files are organized
✘-1 ~/Go/src/github.com/krmahadevan/packages
18:24 $ tree .
.
├── sample_main.go
└── sample_one.go
0 directories, 2 files
Here's how the source code looks like:
sample_one.go
package main
var data map[string]string
func init() {
data = make(map[string]string, 0)
}
sample_main.go
package main
import "fmt"
func main() {
data["foo"] = "bar"
fmt.Println(data)
}
Now when I attempt at running sample_main.go I get errors stating that data is undefined.
18:24 $ go run sample_main.go
# command-line-arguments
./sample_main.go:6:2: undefined: data
./sample_main.go:7:14: undefined: data
✘-2 ~/Go/src/github.com/krmahadevan/packages
But when I build the code into a binary and then execute it, it runs fine.
✔ ~/Go/src/github.com/krmahadevan/packages
18:27 $ go build
✔ ~/Go/src/github.com/krmahadevan/packages
18:28 $ ./packages
map[foo:bar]
✔ ~/Go/src/github.com/krmahadevan/packages
I would like to understand why is this behavior ?
Environment:
18:31 $ go version
go version go1.11.4 darwin/amd64
The closest I found was this post : Golang : command-line-arguments undefined: variable
But this post talks about scoped variables that are defined in main.
But my problem statement involves variables defined in another go file and accessed in the main method.
To understand why, read the go command documentation:
Command go
Compile and run Go program
Usage:
go run [build flags] [-exec xprog] package [arguments...]
Run compiles and runs the named main Go package. Typically the package
is specified as a list of .go source files, but it may also be an
import path, file system path, or pattern matching a single known
package, as in 'go run .' or 'go run my/cmd'.
Compile packages and dependencies
Usage:
go build [-o output] [-i] [build flags] [packages]
Build compiles the packages named by the import paths, along with
their dependencies, but it does not install the results.
If the arguments to build are a list of .go files, build treats them
as a list of source files specifying a single package.
For more about specifying packages, see 'go help packages'. For more
about where packages and binaries are installed, run 'go help gopath'.
go run: Typically the package is specified as a list of .go source files.
For your go run example, list the files:
go run sample_main.go sample_one.go
To fix it, just run the following command:
Windows: go run * or go build *
Unix: go run . or go build .
You are going to run it inside the folder of the files you want to use.

What is the use of pkg directory in Go?

If we have bin directory already where executables go then what is the need of pkg directory? Please explain.
The pkg directory contains Go package objects compiled from src directory Go source code packages, which are then used, at link time, to create the complete Go executable binary in the bin directory.
We can compile a package once, but link that object into many executables. For example, the fmt package appears in almost every Go program. It's compiled once but linked many times, a big saving.
~/go/pkg
From How to Write Go Code, we know ~/go/pkg can store third party library. For example:
Create two file main.go and go.mod:
//main.go
package main
import (
"fmt"
"github.com/google/go-cmp/cmp"
)
func main() {
fmt.Println(cmp.Diff("Hello World", "Hello Go"))
}
//go.mod
module example.com/user/hello
go 1.13
Install a third party library
$ ls ~/go/pkg/mod/github.com/google/
...
$ go install example.com/user/hello
go: finding github.com/google/go-cmp v0.5.2
go: downloading github.com/google/go-cmp v0.5.2
go: extracting github.com/google/go-cmp v0.5.2
$ ls ~/go/pkg/mod/github.com/google/
... go-cmp#v0.5.2
$ ls ~/go/pkg/mod/github.com/google/go-cmp#v0.5.2
And then, you will see a lot of go files, not compile files.
$ ls ~/go/pkg/mod/github.com/google/go-cmp#v0.5.2/cmp/
... example_test.go options.go ...
pkg in user project
This pkg is a directory/package of user project. You can see it as Library and it's OK to use by external applications. For more things, you can check here.
You put your source code in src directory while pkg is the directory that holds compilation output of your actual source code. If you use multiple libraries/packages you will have different output with extension .a for each one, A linker should be responsible for linking and combining all of them together to produce one final executable in bin directory.
As pkg and bin are more specific to the machine or operating system into which you build your actual source code so it is not recommended to share both of them, your repo should have only your actual code.
A side note, if you plan to use docker containers, pkg dir should be ignored as we may build the source code in windows for example while you import/mount your code into linux container; at this time pkg will have compiled files that are only valid for windows

Go: How does go run file.go work

The commands go build and go install compile the files into binaries. Does go run compile or interpret the file? I couldn't find explanations online and may have missed it. Appreciate pointers. Thanks!
It's more or less the equivalent of running go build X.go -o /tmp/random-tmp-folder/exe && /tmp/random-tmp-folder/exe
The go run command compiles and runs a main package comprised of the .go files specified on the command line. The command is compiled to a temporary folder.
The go build and go install examine the files in the directory to determine which .go files are included in the main package.
Command go run performs project's building under the hood (so yes it builds project)
and with flag --work (go run --work main.go) you can see the location of temporary build files.
Also in official documentation (go1.11) you can find:
go run - compiles and runs the named main Go package.
go build - compiles the packages named by the import paths,
along with their dependencies, but it does not install the results.
go install - compiles and installs the packages named by the import paths.
Unlike in java, where the bytcode is created and interpreted at the execution time, go creates an executable file that is dependent on the machine being used,like in c, c++.

How can I "go run" a project with multiple files in the main package?

I have a single file in the main package called main.go. Because the code isn't reusable I want to separate part of the code in a different file but in the same package.
How do I split the contents of main.go into multiple files without creating a separate package?
I want a directory structure like this:
ls foo
# output:
main.go
bar.go
File: bar.go
package main
import "fmt"
func Bar() {
fmt.Println("Bar")
}
File: main.go
package main
func main() {
Bar()
}
When I run go run main.go, it gives me:
# command-line-arguments
./main.go:4:2: undefined: Bar
Update 26th July 2019 (for go >=1.11)
go run .
Will work on windows as well.
Original answer (for non windows environments)
The code actually works. The problem was that instead of running go run main.go I should run:
go run *.go
Update August 2018, with Go 1.11, a section "Run" states:
The go run command now allows a single import path, a directory name or a pattern matching a single package.
This allows go run pkg or go run dir, most importantly go run .
Original answer Jan. 2015
As mentioned in "How to compile Go program consisting of multiple files?", go run expects a list of files, since it "compiles and runs the main package comprising the named Go source files".
So you certainly can split your main package in several files with go run.
That differs from go build/go install which expect package names (and not go filenames).
A simple go build would produce an executable named after the parent folder.
Note that, as illustrated by this thread, a go run *.go wouldn't work in a Windows CMD session, since the shell doesn't do wildcard expansion.
In my opinion, the best answer to this question is hidden in the comments to the top answer.
Just run this:
go run .
This will run all the files in main package, but will not give an error message like
go run: cannot run *_test.go files (main_test.go)
Kudos to #BarthesSimpson
As mentioned, you can say go run *.go but for Windows you can just list the script files (since *.go won't work) - go run main.go other.go third.go
The first method to do so will be to run
go run *.go
The another method is to generate an exe file
go build
Then run that .exe file
./filename.exe
Multiple options
go run .
go run *.go
make run using Makefile where, add any of the above command as build target.
for testing
go test ./...
make test using Makefile with go test ./... as build target
For Windows install Cygwin and use it instead of command prompt. "go run *.go" will work then.
If you are trying to run multiple files on localhost using gorilla mux in go as per latest version(1.11). Try using any of the following 2 commands.
go install && FolderName -port 8081 .
go build && ./FolderName -port 8081.
Make sure that you are in the source folder ie go/src/FolderName before executing the command in the Terminal.

What causes 'go build' to fail with 'unexpected NUL in input'?

I have a Linux VM where I am trying to compile a simple Go package. The package was retrieved into my user directory with git:
$ git clone [...]/test.go
Cloning into 'test.go'...
done.
$ cd test.go/
$ ls
main.go
I set up the GOPATH and build:
$ export GOPATH=$PWD; echo $GOPATH
/home/vagrant/test.go
$ go build
$ ls
main.go test.go*
So far so good. But now when I try to build again, it fails:
$ go build
can't load package: package .: read /home/vagrant/test.go/test.go: unexpected NUL in input
Deleting the test.go file before building will allow it to build. But this is inconvenient because tools like github.com/codegangsta/gin which try to rebuild the package will fail.
The repository was named [...]/test.go, and the default container directory for git clone is the repo name, so the containing directory is named test.go\.
From go help build:
If the package is main and file names are provided, the file name
derives from the first file name mentioned, such as f1 for 'go build
f1.go f2.go'; with no files provided ('go build'), the output file
name is the base name of the containing directory.
In this case the output is a file called test.go. The problem is:
In the directory containing the package, .go, .c, .h, and .s files are considered part of the package
During a go build if the output from a previous build, test.go, exists, it will be treated as a source file, triggering the 'unexpected NUL in input' message.
The problem can be resolved by renaming the directory to avoid the build output having a name that will be considered part of the package.

Resources