My project is currently structured such that the HTML templates are in the root of the project within a templates/ directory.
My HTTP request handlers are several levels down the file system tree.
go.mod
templates/webpp/*.html
templates/admin-dashboard/*html
cmd/webapp/main.go
cmd/admin-dashboard/main.go
app/webapp/handlers/handler.go
Ideally, I would like to be able to use go:embed in the following way:
//go:embed ../../templates
or
///go:embed $PROJECT_ROOT/templates
But unfortunately neither of these methodologies exist. The go doc embed says:
The patterns are interpreted relative to the package
directory containing the source file. The path separator is a forward slash,
even on Windows systems. Patterns may not contain ‘.’ or ‘..’ or empty path
elements, nor may they begin or end with a slash.
I could relocate the templates (something I'd rather not do since in some modes my webapp expects to see them relative to the running binary). e.g.
webapp <-- binary uses templates at runtime
templates/*.html <-- editable HTML files
So I could have my build script copy them in place just before compilation, but this seem unnecessarily convoluted; if I bypasses the build script or forget or mess up the build sequence, I could end up with a v2 binary with v1 "old templates" embedded.
Or, I could make the templates/ directory into a package and export an embed.FS and then inject it as a dependency to my application, but now my code is re-structured just to accomodate the embedding process.
Is there any likelyhood that go:embed will allow some type of embedding relative to the project root in future, or would this raise security issues?
go:embed is a great feature, but it feels like I'm beholden to it- either forced to copy, relocate, split up my sets of templates into separate directories or adjust my application to use dependency injection.
What's the best practice?
Related
I have several projects which I document with Sphinx. The contents of index.rst are identical in each of them (I use some substitutions for project name and include another rst file with the list of modules). So I thought I could remove this file from most projects and only keep it in one shared project to which the others can find an absolute path during build.
However, the master_doc config does not let me enter an absolute path, and it even rejects relative paths that go "out of scope of the single project". I even tried adding the shared folder in sys.path, but it still did not help.
I've seen many questions asking the opposite, i.e. using multiple index.rst files in a single project. But that's not my case.
Do you have any ideas on how to get this working?
I am writing a Go command-line tool that generates some files based on templates.
The templates are located in the Git repository alongside the code for the command-line tool itself.
I wanted to allow the following:
The binary, wherever it is called from, should always find the templates directory.
The templates directory can be overriden by the user if need be.
Since this is a Go application, I went with something like:
templateRoot := filepath.Join(
os.Getenv("GOPATH"),
"src/github.com/myuser/myproject/templates",
)
But being rather new to Go, I wonder if this approach is reliable enough: is it guaranteed that my application template will always be accessible at that path ?
What if someone vendorize my application into their own project ? Does that even make sense for a command-line tool ?
Because of 2., I obviously can't/won't use go-bindata because I want to allow for the templates to be overriden if need be.
In summary: what is a good strategy to reliably refer to non-go, static files in a Go command-line tool ?
GOPATH is used for building the application. While you could look for GOPATH and check relative locations to each GOPATH entry at runtime, you can't be sure it will exist (unless of course you make it a prerequisite for running your application).
go get itself is a convenience for developers to fetch and build a go package. It relies on having a GOPATH (though there's a default now in go1.8), and GOBIN in your PATH. Many programs require extra steps not covered by the simple go tool, and have scripts or Makefiles to do the build. If you're targeting users that aren't developers, you need to provide a way to install into standard system paths anyway.
Do what any regular program would do, and use some well-known path to locate the template files. You can certainly add some logic in your program to check for a hierarchy of locations: relative to $GOPATH, relative to the binary, working directory, $HOME, etc; just provide a list of locations to the user that your program will look for templates.
My organization uses Rails to develop its app but I'm attempting to re-write one of our back-end processes in Golang because it's much quicker.
I've structure my application with our company a namespace for my app (example.co), and a subfolder for each of the packages within my app.
Each library that I've included (e.g. sqlx, etc...) also has it's own folder.
src/
github.com/
jmoiron/
(sqlx package files)
example.co
my_app/
(my app package files)
model/
(model package files...)
However looking at other packages like sqlx, it appears they scrap this directory structure entirely and put all their files in the root directory
Is this because I'm writing an application and sqlx is a package that's meant to be included in other applications? Or is it just a difference in preference since there's no real accepted "standard"
I did this too on my first project. I have since learned:
the $GOPATH/bin/ pkg/ src/ layout is constructed by go get and similar commands
you can organize your .go files as a single flat project dir or with subfolders (caveat: all .go files in the same folder must have the same package name)
put other people's code in a /vendor directory inside your project root, if it is code your app needs to work (google this, it's the worst part of go imo)
put your own project under your gopath, symlink to it if you want it more accessible
So I would imagine your code could look something like:
/Users/user2490003/MyGoPath/
▾ src/github.com/user2490003/myproject/
▾ model/
user.go
▾ myapp/
myapp.go
▾ vendor/github.com/jmoiron/sqlx/
sqlx.go
main.go
Import the full package references, like this:
// main.go
package main
import (
github.com/jmoiron/sqlx
github.com/user2490003/myproject/myapp
github.com/user2490003/myproject/model
)
I would recommend to start with a layout that seems logical and works at the present moment and then refactor/restructure as needed when your applications grows and evolves.
Using your company namespace is reasonable - I would consider creating a directory for your app underneath it (such as company.co/my_app) and inside of it, subdirectories for library packages (for example, company.co/my_app/db etc.) as well as the cmd one that would contain directories for the actual executables (package main programs) that you want to produce: cmd/exe1, cmd/exe2 etc. This will allow you to have multiple executables as well as multiple library "subpackages" inside of the my_app which can be included independently with the corresponding import path.
Each library that I've included (e.g. sqlx, etc...) also has it's own folder.
If you are ok with using the latest version of dependencies from Github, you don't have to include the dependencies' code into your repositories but instead install them with go get into the build area. If you want to build from a local copy - and for corporate usage, it may be preferable for stability and audit track - you should put them in a vendor subdirectory, for example company.co/my_app/vendor/github.com/jmoiron/sqlx. This way you have control on when you upgrade to a newer version of the dependencies and assurance that the upstream changes will not break your build or otherwise affect your programs without your knowledge and until you have a chance to do thorough testing.
I'm playing with golang and made a tool for password generation. Initially it was intended to be used as a command line tool. I later separated the generation logic into a separate package (still same github repository) and left the main function in the root of the project. Now I also want to add a simple web frontend (nothing fancy), but I don't know how to structure the packages.
Am I supposed to put both the command line entry point as well as the web UI into their own packages in the same project (which leaves the root empty). Or maybe I should move the actual generation library to the root and the UIs in separate packages. I guess the other option is to have the UIs in separate projects on github, but they are only going to be used for this library, so it does not seem like a good idea.
I remember seeing in some projects packages named cmd for example, but never have I encountered one, with multiple front ends. Is there a go(-gettable-)way for doing this?
I agree that there's not much point in making separate projects/repositories if they're only going to be used for this library. I would just have a cmd directory with a subdirectory for each executable you're building.
Something like this:
github.com/user/project
generation
cmd
cmdline
main.go
web
main.go
The main.go files can use the functionality that you've broken out into your "generation" package.
The name of the executables produced by go build will be the name of the parent directory, so cmdline and web in this example (you would want to choose better names).
Note: you don't actually have a package cmdline or web. The files in those directories would all be in [their own separate] package main.
My application uses json configuration files and other resources. Where should I place them in my project hierarchy?
I could not find the answer in http://golang.org/doc/code.html (How to Write Go Code)
Upd:
The question is not about automatic distribution of resources with application but much simpler: Where should I keep my resources in project hierarchy? Is there some standard place anyone expects them to be?
There is no single correct answer, nor are there any strong conventions assumed or enforced by any Go tooling at this time.
Typically I start by assuming that the files I need are located in the same directory from where the program will be run. For instance, suppose I need conf.json for myprog.go; then both of those files live together in the same directory and it works to just run something like
go build -o myprog && ./myprog
When I deploy the code, the myprog binary and conf.json live together on the server. The run/supervisor script needs to cd to that directory and then run the program.
This also works when you have a lot of resources; for instance, if you have a webserver with JS, CSS, and images, you just assume they're relative to cwd in the code and deploy the resource directories along with the server binary.
Another alternative to assuming a cwd is to have a -conf flag which the user can use to specify a configuration file. I typically use this for distributing command-line tools and open-source server applications that require a single configuration file. You could even use an -assets flag or something to point to a whole tree of resource files, if you wanted.
Finally, one more approach is to not have any resource files. go-bindata is a useful tool that I've used for this purpose -- it just encodes some data as bytes into a Go source file. That way it's all baked into your binary. I think this method is most useful when the resource data will rarely or never change, and is pretty small. (Otherwise you're going to be shipping around huge binaries.) One (kind of silly) example of when I've used go-bindata in the past was for baking a favicon into a really simple server which didn't otherwise require any extra files besides the server binary.
For static resource it might be the most convenient solution to include them in the binary similar to resources in Java. Newer Go version, at least 1.18 are providing the //go:embed directive to include content:
import (
_ "embed"
)
//go:embed myfile.txt
var myfile string
You can now use myfile in your code. E.g. IntelliJ provides also support for this.
There are also other options to include the content, e.g. as binary or dynamically, see the link.