How to import a method from an external package in Golang? - go

Sorry if this question is a bit basic however I have not been able to find any documentation on it.
I am trying to import the following method from example.com/User/project/controllers package
func (env *Env) Index(ctx *fasthttp.RequestCtx, ps fasthttprouter.Params){
fmt.Fprintf(ctx, "Hi there! RequestURI is %q", ctx.RequestURI())
}
Into the following file to be used in a router as follows
db, err := db.Conn()
if err != nil {
log.Panic(err)
}
env := &Env{db}
...
router.GET("/", env.controllers.Index)///this import is not valid
I have tried to use controllers.env.Index env.controllers.Index I have also tried importing with a . before the import .etc
How would one in this instance import a method from another package whereby a struct (ENV) can be passed to it? To clarify the problem here is using method on top of the package ontop of the helper e.g. method.package.helper how would I resolve the above code so that I can pass a method to a helper from an external package
Thanks

Just to clarify, you would like to pass in your db struct to your Env struct correct?
This may help if I am understanding correctly.
Since a struct is really just a collection of fields, it's dependent on the makeup of the Env struct.
What is the error that you are receiving?

Related

Get Name of Current Module in Go

I am attempting to create named loggers automatically for HTTP handlers that I'm writing, where I am passed a function (pointer).
I'm using the code mentioned in this question to get the name of a function:
package utils
import (
"reflect"
"runtime"
)
func GetFunctionName(fn interface{}) string {
value := reflect.ValueOf(fn)
ptr := value.Pointer()
ffp := runtime.FuncForPC(ptr)
return ffp.Name()
}
I'm using this in my main function to try it out like so:
package main
import (
"github.com/naftulikay/golang-webapp/experiments/functionname/long"
"github.com/naftulikay/golang-webapp/experiments/functionname/long/nested/path"
"github.com/naftulikay/golang-webapp/experiments/functionname/utils"
"log"
)
type Empty struct{}
func main() {
a := long.HandlerA
b := path.HandlerB
c := path.HandlerC
log.Printf("long.HandlerA: %s", utils.GetFunctionName(a))
log.Printf("long.nested.path.HandlerB: %s", utils.GetFunctionName(b))
log.Printf("long.nested.path.HandlerC: %s", utils.GetFunctionName(c))
}
I see output like this:
github.com/naftulikay/golang-webapp/experiments/functionname/long.HandlerA
This is okay but I'd like an output such as long.HandlerA, long.nested.path.HandlerB, etc.
If I could get the Go module name (github.com/naftulikay/golang-webapp/experiments/functionname), I can then use strings.Replace to remove the module name to arrive at long/nested/path.HandlerB, then strings.Replace to replace / with . to finally get to my desired value, which is long.nested.path.HandlerB.
The first question is: can I do better than runtime.FuncForPC(reflect.ValueOf(fn).Pointer()) for getting the qualified path to a function?
If the answer is no, is there a way to get the current Go module name using runtime or reflect so that I can transform the output of runtime.FuncForPC into what I need?
Once again, I'm getting values like:
github.com/naftulikay/golang-webapp/experiments/functionname/long.HandlerA
github.com/naftulikay/golang-webapp/experiments/functionname/long/nested/path.HandlerB
github.com/naftulikay/golang-webapp/experiments/functionname/long/nested/path.HandlerC
And I'd like to get values like:
long.HandlerA
long.nested.path.HandlerB
long.nested.path.HandlerC
EDIT: It appears that Go does not have a runtime representation of modules, and that's okay, if I can do it at compile time that would be fine too. I've seen the codegen documentation and I'm having a hard time figuring out how to write my own custom codegen that can be used from go generate.
The module info is included in the executable binary, and can be acquired using the debug.ReadBuildInfo() function (the only requirement is that the executable must be built using module support, but this is the default in the current version, and likely the only in future versions).
BuildInfo.Path is the current module's path.
Let's say you have the following go.mod file:
module example.com/foo
Example reading the build info:
bi, ok := debug.ReadBuildInfo()
if !ok {
log.Printf("Failed to read build info")
return
}
fmt.Println(bi.Main.Path)
// or
fmt.Println(bi.Path)
This will output (try it on the Go Playground):
example.com/foo
example.com/foo
See related: Golang - How to display modules version from inside of code
If your goal is to just have the name of the module available in your program, and if you are okay with setting this value at link time, then you may use the -ldflags build option.
You can get the name of the module with go list -m from within the module directory.
You can place everything in a Makefile or in a shell script:
MOD_NAME=$(go list -m)
go build -ldflags="-X 'main.MODNAME=$MOD_NAME'" -o main ./...
With main.go looking like:
package main
import "fmt"
var MODNAME string
func main() {
fmt.Println(MODNAME) // example.com
}
With the mentioned "golang.org/x/mod/modfile" package, an example might look like:
package main
import (
"fmt"
"golang.org/x/mod/modfile"
_ "embed"
)
//go:embed go.mod
var gomod []byte
func main() {
f, err := modfile.Parse("go.mod", gomod, nil)
if err != nil {
panic(err)
}
fmt.Println(f.Module.Mod.Path) // example.com
}
However embedding the entire go.mod file in your use case seems overkill. Of course you could also open the file at runtime, but that means you have to deploy go.mod along with your executable. Setting the module name with -ldflags is more straightforward IMO.

Gin or Gorm complain about a unique column index being a syntax error, somewhat inconsistently

I took the example from Gorm's docs of how to create a unique index, which seems to be be simply adding a ,unique to the column tag when declaring a model. But when I tried to run it, it would always output the following message in the console:
(/Users/[...]/main.go:16)
[2021-06-26 13:59:20] near "unique": syntax error
While it seemed bizarre that an example directly from their docs would fail, I tried running that code in isolation, and it indeed worked fine on its own. Then, adding on more and more code from my app, it seemed to start outputting that message once Gin-Gonic was introduced and gin.Default() was called. I don't know if this is only because Go won't output the error by default, or there is some sort of a clash going on. But either way, I have also never had Gorm actually create the unique index; syntax error or not.
The minimum reproducible code is as follows, though it behaves rather inconsistently, running without any error about 1 out of 5 times:
package main
import (
"github.com/jinzhu/gorm"
_ "github.com/jinzhu/gorm/dialects/sqlite"
"github.com/gin-gonic/gin"
)
type User struct {
gorm.Model
Name string `gorm:"size:40;index:idx_name,unique"`
}
func main() {
db, _ := gorm.Open("sqlite3", "test.db")
db.AutoMigrate(&User{})
r := gin.Default()
r.Run(":8082")
}
How would I go about fixing this; Both getting rid of the inconsistent error, and having the unique index actually being created?
If relevant, I'm running this on a Mac.
You took an example from the gorm.io but you didn't use the right packages imports.
See here the installation here: https://gorm.io/docs/#Install
You are using imports from v1 (http://v1.gorm.io/docs/) and coding with examples from the latest version. (http://gorm.io/docs/)
Look the import and the database drive initialization in the code below:
package main
import (
"github.com/gin-gonic/gin"
"gorm.io/driver/sqlite"
"gorm.io/gorm"
)
type User struct {
gorm.Model
Name string `gorm:"size:40;index:idx_name,unique"`
}
func main() {
db, _ := gorm.Open(sqlite.Open("gorm.db"), &gorm.Config{})
db.AutoMigrate(&User{})
r := gin.Default()
r.Run("localhost:8082")
}

Unit tests for kubernetes controller

I'm trying to write a controller and I'm having a few issues writing tests.
I've used some code from the k8s HPA in my controller and I'm seeing something weird when using the testrestmapper.
basically when running this test with a breakpoint here I see the mappings are returned.
When I do the same the mappings are not returned.
What magic is happening here?
The following test fails
package main
import (
"github.com/stretchr/testify/assert"
"k8s.io/apimachinery/pkg/api/meta/testrestmapper"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/kubernetes/pkg/api/legacyscheme"
"testing"
)
func TestT(t *testing.T) {
mapper := testrestmapper.TestOnlyStaticRESTMapper(legacyscheme.Scheme)
gk := schema.FromAPIVersionAndKind("apps/v1", "Deployment").GroupKind()
mapping, err := mapper.RESTMapping(gk)
assert.NoError(t, err)
assert.NotNil(t, mapping)
}
I think this is because you are missing an import of _ "k8s.io/kubernetes/pkg/apis/apps/install".
Without importing this path, there are no API groups or versions registered with the schema you are using to obtain the REST mapping.
By importing the path, the API group will be registered, allowing the call to schema.FromAPIVersionAndKind("apps/v1", "Deployment").GroupKind() to return a valid GroupKind.

Getting a use of package without selector error

I'm using this config library called Viper
In my main I have this:
viper.SetConfigName("development")
viper.AddConfigPath("config/settings/")
err := viper.ReadInConfig()
if err != nil {
fmt.Println("viper config read error %v", err)
}
I then have a struct that takes a viper as parameter:
type MyConfig struct {
v *viper.Viper
}
In my main I have a function that returns this MyConfig like:
func NewMyConfig(v *viper.Viper) *MyConfig {
return &MyConfig{v: v}
}
I am getting this error:
./main.go:55: use of package viper without selector
Not sure what I should be doing?
When you import a package like
import "github.com/spf13/viper"
the package name (which is viper in this case) will be available to you as a new identifier. You may use this identifier to construct qualified identifiers to refer to exported identifiers of the package (identifiers that start wtih an uppercase letter).
The package name itself cannot be used by itself. The line that gives you error:
myConfig = NewMyConfig(&viper)
You used package name viper without specifying what exported identifier you want to refer to from the package.
You want to use your NewMyConfig() function to obtain a pointer to a new value of your MyConfig struct. Your NewMyConfig() function expects a value of *viper.Viper. Since the viper.Viper struct contains unexported fields, you can just create it like &viper.Viper{}, but the viper package exports a function viper.New() which can be used to obtain a pointer to a new, initialized viper.Viper value. You may use it like:
vp := viper.New()
myConfig = NewMyConfig(vp)
Note that the viper package declares an internal, global, unexported viper.Viper "instance". There are many exported functions that match methods of the viper.Viper type. These "matching" functions work on the global, unexported viper.Viper instance. So you may choose to use all the exported global functions of the viper package, or create your own Viper instance and then keep using its methods afterwards.

Passing around structs

I am new to go and coming from a Ruby background. I am trying to understand code structuring in a world without classes and am probably making the mistake wanting to do it "the Ruby way" in Go.
I am trying to refactor my code to make it more modular / readable so I moved the loading of the configuration file to its own package. Good idea?
package configuration
import "github.com/BurntSushi/toml"
type Config struct {
Temperatures []struct {
Degrees int
Units string
}
}
func Load() Config {
var cnf Config
_, err := toml.DecodeFile("config", &cnf)
if err != nil {
panic(err)
}
return cnf
}
Now, in my main package:
package main
import "./configuration"
var conf Configuration = configuration.Load()
Gives undefined: Config. I understand why. I could copy the struct definition in the main package but that's not very DRY.
It's my understanding passing around structs like this is a bad practice as it makes your code harder to understand (now everyone needs to know about my Config struct).
Is hiding logic in a package like I am trying to do here a good idea in Go? If so, what's the "Go" way to pass this Config struct around?
In your main package you should specify
var conf configuration.Config = configuration.Load()
configuration refers to your imported package and Config is the exported struct (uppercase name) from that package. But you can also omit this, as the type can be inferred
var conf = configuration.Load()
As a side note: please don't use relative imports
in Go imports you always declare the full path of you package, dont use relative paths in imports, best example is that toml import import "github.com/BurntSushi/toml" that exist in:
GOPATH/src/github.com/BurntSushi/toml
GOPATH/pkg/_/github.com/BurntSushi/toml
Then build you package and main.go
package main
import "mypackage/configuration"
func main() {
// configuration contain all funcs & structs
var conf configuration.Config = configuration.Load()
}
Go it is not ruby.
Ref Packages: https://golang.org/doc/code.html
why don't you just import the configuration package and then do Go's variable declaration/instatiation shortcut? Maybe I'm missing something.
package main
import "mypackage/configuration"
func main() {
conf := configuration.Load()
}

Resources