Golang import based on config variable - go

I'm currently in the process of still learning go but I recently got to a point where in one of my tests I wanted to create a quick backup application that will reference a config file and switch what "plugin" to use for the backup. So what I got to at this point is to create (as example, written from my head and syntax may be incorrect):
type BackupStorage interface{
Put (d []byte) (n int, err Error)
Get (l []byte) (d []byte, err Error)
}
At this point I would assume I should use reflection to switch on the type and return the specific backup function, although that does not seem right.
The second alternative I came to was to still use my BackupStorage interface and create "plugin" packages to dictate which import will be used, but how do I switch that then based on a config file variable. And I'd like to do this because some stuff on one machine may backup only to s3 where as others may backup to both s3 and google drive etc.
With the basic example above what I have in mind is this:
Implement 2 BackupStorage "plugins" (Google Drive / S3) with the flexibility to add more at any time, but have my code be generic enough to execute on whatever storage backend is selected in config files.
As I mentioned above I'm still learning and any explanations would be appreciated or examples on how to accomplish this. I don't mind the "your doing it wrong" as long as there is a proper explanation on why it's wrong and how to do it right.

You have the right idea to start, implement everything you need via an interface, and then you can plug in any concrete backup "plugin" that implements that interface.
Once you can run your backup via an interface, you can simply assign an instance of the backend you want based on whatever conditions you set.
var storage Backupper
type Backupper interface {
Backup()
}
type GDrive struct {
config string
}
func (g *GDrive) Backup() {
fmt.Println("Doing backup to Google Drive")
}
func main() {
storage = &GDrive{}
storage.Backup()
}
Or with multiple options: http://play.golang.org/p/RlmXjf55Yh

Related

Calling functions and variables in same package but different files with build tags

I'm setting up some integration testing, which I'm doing in a separate test package to my src code. This is done to prevent circular dependencies. Unit tests are not stored here, they are stored alongside the files they are testing.
My golang project hierarchy looks like:
cmd
public
...
testing/
main_test.go
database_test.go
in main_test.go, I plan to initialise the connections to external dependencies, such as my test database.
package tests
type Database struct {
...
}
var DB Database
func TestMain(m *testing.M){
SetUpDatabase()
exitCode := m.Run()
os.Exit(exitCode)
}
database_integration_test.go
func Test(t *testing.T) {
tests := []struct {
title string
run func(t *testing.T)
}{
{"should make query", testQuery},
}
for _, test := range tests {
t.Run(test.title, func(t *testing.T) {
test.run(t)
})
}
}
func testQuery(t *testing.T) {
var r result.Result
err := DB.database.DoQuery("").Decode(&r)
if err != nil {
t.Errorf(err.Error())
t.Fatal()
}
}
This setup works when I run it, however, I would like to add build tags to these files, or the type: // +build integration
However, as soon as I use the build tag, the database_integration_test.go file cannot see the initalised Database type. How can I stop this? Also as a side note, should I change the name of main_test.go. I only called it that due to main being the standrd entry point.
Firstly, Regarding this:
Also as a side note, should I change the name of main_test.go. I only
called it that due to main being the standard entry point.
I think it is confusing to name it as main_test.go as it might indicate that you are testing the main function in this file (according to golang convention)
Secondly, Regarding this:
However, as soon as I use the build tag, the
database_integration_test.go file cannot see the initialised Database
type. How can I stop this?
A Build Constraint or also known as Build Tag is used to include or exclude files in a package during a build process. With this, we can build different types of builds from the same source code.
So if you are not seeing the Database Type initialized then most probably the definition of the Database Type and the integration test are tagged with different build tags. Make sure they are present in the same build tags. Also, I think you can use more than one build tag to label a file. So you can try that as well.
For more details on the Build Tags check out the following article by Dave Cheney here
You could simply add a flag to your TestMain:
var isIntegration bool
func init() {
flag.StringVar(&isIntegration, "mytest.integration", "Set flag to set up DB for integration tests")
}
func TestMain(t *testing.M) {
SetUpDatabase(isIntegration)
//etc...
}
Then just simply have the SetUpDatabase call different, unexported, functions based on whether or not the argument is true or false. That'd be a quick way to get the behaviour, without having to much about with custom build constraints. Especially considering you're running tests, not building the application as-such.
As far as renaming main_test.go is concerned: I don't see why you'd need to change it. It does what it says on the tin. When someone else wants to see how the tests are structured/run, or what possible flags have been added, it's a lot easier to just check the directory and look for a main_test.go file (along with init.go, that'd be first file I'd look for). Any other name like setup_integration_test.go, integration_setup_test.go, integration_start_test.go, ... is just going to muddy the waters.

Should I call template.ParseFiles(...) on each http request or only once from the main function?

I am doing some web develoment using the go programming language using the package html/template. At some point of the code, I need to call the function template.ParseFiles(...) so I can create a template from those files ad then execute it using temp.Execute(w,data). I would like to know if it is better to create the template on each request or to do it once in the main and declare a global variable.
Right now I do it on each request on my handle functions, like most tutorials do. However, I don't know If I'm wasting resources by doing it on each request instead of having them as global variables.
This is how it looks on each request
func ViewStats(w http.ResponseWriter, r *http.Request) {
//Get stuff from db and put them in data
//...
//return data to user
tmp, err := template.ParseFiles("views/guest-layout.html",
"views/stats.html")
if err != nil {
fmt.Println(err)
} else {
tmp.Execute(w,data)
}
}
I would like to know if this is better:
var temp1 template.Template
func main() {
temp1, err = template.ParseFiles("file1","file2")
//...
}
As usual: It depends.
But first some nuance:
You should never do template parsing (or anything else interesting) in your main() function. Instead, your main() function should call methods (or a single method) that kicks off the chain of interesting things in your program.
Go doesn't have globals, so it's not actually an option to store your parsed templates in a global variable in the first place. The closest Go has to global variables is package variables. You could store your parsed templates in a package variable in the main package, but this is also bad form, as your main package (except for tiny, trivial programs), should just be an entry point, and otherwise nearly empty.
But now, on to the core of your question:
Should you parse templates per request, or per run?
And here it depends.
If you have templates that change frequently (i.e. during development, when you're constantly editing your HTML files), once per request can be best.
But this is far less efficient than just parsing once, so in production, you may wish to parse the templates once on startup only. Then you can store the templates in a package variable, or better, in a struct that is initialized at runtime. But I leave that to you.
But what may be best is actually a bit of a compromise between the two approaches. It may be best to load your templates at start-up, and re-load them occasionally, either automatically (say, every 5 minutes), or watch your filesystem, and reload them whenever the on-disk representation of the templates changes.
How to do this is left as an exercise for the reader.

Global variables and Go

I am currently trying to work on a small Go project, and I have a problem I am trying to solve.
I'm currently using github.com/jinzhu/gorm to handle database operations for the backend of a GraphQL server, and I wanted to be able to store the DB connection in a global variable accessible throughout the entire project (including sub-packages).
My first attempt was at creating a variable named db by doing the following in my main.go file:
var db *gorm.DB
var err error
then inside the init() function:
func init() {
db, err = gorm.Open("postgres", "credential stuff here")
db.AutoMigrate(&modelStructHere)
defer db.Close()
}
There isn't any crashing, but I would assume due to scoping, the db variable is only usable inside main.go, but I also need to be able to use this inside gql/gql.go, where my GraphQL resolver is currently located.
Perhaps I should move this chunk of code (DB init) to the actual resolver file, since there's really no use for DB operations outside of such a thing anyway, so maybe that's the problem?
Thanks in advance!
Alex's comment is spot on. Create a folder named "database" and inside put a file called "database.go" containing this:
package database
// the imports go here
var DB *gorm.DB
Now you can use it wherever you like with database.DB. You should not make the error variable global, handle it in the same function that initializes the DB. The init function can be in any place, usually you want it at the beginning of your program in the main function.

Use package file to write to Cloud Storage?

Golang provides the file package to access Cloud Storage.
The package's Create function requires the io.WriteCloser interface. However, I have not found a single sample or documentation showing how to actually save a file to Cloud Storage.
Can anybody help? Is there a higher level implementation of io.WriteCloser that would allow us to store files in Cloud Storage? Any sample code?
We've obviously tried to Google it ourselves but found nothing and now hope for the community to help.
It's perhaps true than the behavior is not well defined in the documentation.
If you check the code: https://code.google.com/p/appengine-go/source/browse/appengine/file/write.go#133
In each call to Write the data is sent to the cloud (line 139). So you don't need to save. (You should close the file when you're done, through.)
Anyway, I'm confused with your wording: "The package's Create function requires the io.WriteCloser interface." That's not true. The package's Create functions returns a io.WriteCloser, that is, a thingy you can write to and close.
yourFile, _, err := Create(ctx, "filename", nil)
// Check err != nil here.
defer func() {
err := yourFile.Close()
// Check err != nil here.
}()
yourFile.Write([]byte("This will be sent to the file immediately."))
fmt.Fprintln(yourFile, "This too.")
io.Copy(yourFile, someReader)
This is how interfaces work in Go. They just provide you with a set of methods you can call, hiding the actual implementation from you; and, when you just depend on a particular interface instead of a particular implementation, you can combine in multiple ways, as fmt.Fprintln and io.Copy do.

How to embed file for later parsing execution use

I am essentially trying to walk through a folder of html files. I want to embed them into the binary file and be able to parse them upon request for template execution purposes. (Please excuse me if im not wording this properly).
Any ideas, tips, tricks or better way of accomplishing this is much appreciated.
// Template Files
type TempFiles struct {
Files map[string]string
}
// Loop through view files and load them
func LoadTempFiles() {
t := new(TempFiles)
// Load template files
filepath.Walk("application/views", func(path string, info os.FileInfo, err error) error {
if !info.IsDir() {
content, _ := ioutil.ReadFile(path)
t.Files[path] = string(content)
}
return nil
})
}
func ViewTemp(w http.ResponseWriter, path string) {
t := new(TempFiles)
temp, err := template.New().Parse(t.Files[path])
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
} else {
temp.Execute(w, nil)
}
}
I do this with most of my Go web apps. I use go-bindata to auto-generate Go source code from all the files I want to embed and then compile them into the binary.
All this is done automatically during build.
One downside is that the current go build tools do not offer a way to hook into the build process, so I use a Makefile for this purpose. When the makefile is invoked, it runs go-bindata to generate the sources for all necessary files, then usually performs some additional code generation bits and bobs (notably, creating a Go source file which lists all the embedded files in a map.. A Table of Contents if you will). It then proceeds to compile the actual program.
This can become a little messy, but you only have to set it all up once.
Another downside, is that the use of a Makefile means the software is not compatible with the go get command. But since most of my web apps are not meant to be shared anyway, this has not been a problem so far.
When it comes to debugging/developing such an application, there is another issue that arises from embedding the static web content: I can't just edit an HTML or CSS file and refresh the browser to see its effects. I would have to stop the server, rebuild it and restart it with every edit. This is obviously not ideal, so I split the Makefile up into a debug and release mode. The release mode does what I described above. The debug mode, however, wil not actually embed the static files. It does generate source files for each of them, but instead of having them contain the actual file data, it contains a stub which simply loads the data from the filesystem.
As far as the server code is concerned, there is no difference in the generated code. All it does is call a function to fetch the contents of a given static file. It does not care whether that content is actually embedded in the binary, or if it's loaded from an external source. So the two build modes are freely interchangeable.
For example, the same generated function to fetch static file content in release and debug mode would look as follows:
Release mode:
func index_html() []byte {
return []byte {
....
}
}
Debug mode:
func index_html() []byte {
data, err := ioutil.ReadFile("index.html")
...
return data
}
The interface in both cases is identical. This allows for easy and care-free development and debugging.
Another tool to consider: Another recent good tool comes from esc: Embedding Static Assets in Go (GitHub repo)
a program that:
can take some directories and recursively embed all files in them in a way that was compatible with http.FileSystem
can optionally be disabled for use with the local file system for local development
will not change the output file on subsequent runs
has reasonable-sized diffs when files changed
is vendoring-friendly
Vendoring-friendly means that when I run godep or party, the static embed file will not change.
This means it must not have any third-party imports (since their import path will be rewritten during goimports, and thus different than what the tool itself produces), or a specifiable location for the needed third-party imports.
It generates nice, gzipped strings, one per file.
There is a simple flag to enable local development mode, which is smart enough to not strip directory prefixes off of filenames (an option in esc that is sometimes needed).
The output includes all needed code, and does not depend on any third-party libraries for compatibility with http.FileSystem.
I made a package that makes switching between debug and production easier. It also provides an http.FileSystem implementation, making it easy to server the files. And it has several ways of adding the files to the binary (generate go code, or append as zip).
https://github.com/GeertJohan/go.rice
Go now has builtin support for this:
package main
import (
"embed"
"os"
)
//go:embed *.html
var content embed.FS
func main() {
b, e := content.ReadFile("index.html")
if e != nil {
panic(e)
}
os.Stdout.Write(b)
}
https://golang.org/pkg/embed

Resources