Embedding files in parent directories in Go

Original link: https://www.ixiqin.com/2022/10/02/in-the-embedded-in-the-parent-directory-of-the-file/

5e54199359bbafe0ef692365a9bcffb6.jpg

Since Go 1.16, Go has provided a mechanism to package binaries into Binary files:` //go:embed . Most of the examples I’ve seen, though, embed subfolders under the current folder. There is no example of embedding parent-level folders. So, I started researching.

Why would you need to embed files in the parent directory?

This is because different projects have different build rules. Some small projects may only have one main.go or several other go source files in the same directory, but for larger projects, reasonable project splitting can help improve the maintainability of the project.

Taking me as an example, my directory structure is as follows: the biz directory is my core logic and where I write code every day; conf is where various configurations are placed, such as various API Keys, and ral is the network access layer, such as I prefer to use gin as the underlying network access layer; script places various script files required for development; static places JS / CSS files required by the front end. When developing some content-oriented pages, I am used to using Server Side Render, so I also have a template directory under the biz directory. The main logic is placed in the handler.

 ├── biz│  ├── dal│  ├── handler│  ├── logic│  ├── service│  └── template├── conf├── ral│  └── gin├── script└── static └── public

In daily development, a very common operation is to process the basic logic in the handler, render the template in the template, and return it to the user. At this time, the file in the upper directory needs to be used in the handler.

Bad Attempt 1: Use .. to import

As a general configuration of the file system, I naturally know that the upper-level directory can be represented by .. , so I try to use the following syntax to import files

 //go:embed ../template/*

As a result, an error invalid pattern syntax was reported. It can be seen that there is a problem with my grammar.

By searching, I found this Github issue , only to learn that go embed prevents the usage of .. syntax due to avoiding cross-module access

Because embed.Files implements fs.FS, it cannot provide access to files with names beginning with .., so files in parent directories are also disallowed entirely, even when the parent directory named by .. does happen to be in the same module.

https://ift.tt/PlmCrJo

Bad Attempt 2: Use go:generate to perform the copy

In the above issue, I noticed that there is another way to achieve a similar effect. You can use go:generate to copy the file to the local when the go generate method is executed, so that the file can be copied to the local before the build binary file, which avoids the problem of cross-module and avoids putting the template file. Locally, the problem of polluting the code directory.

 //go:generate cp -r ../../assets ./local-asset-dir//go:embed local-asset-dirvar assetFs embed.FS

This method has no effect when running, but it may be effective for others (I guess it is because I rarely use go generate directly when developing, and I just use go run directly). However, this method also has a problem, because it is written in the code itself, and it is very likely that these codes will be deleted or modified by mistake for some reason, resulting in the abnormal operation of the entire system. And the descriptions scattered across the files can also complicate the repair.

the right way

At the end of reading this issue, I noticed the correct usage. In another issue , the developer tomasf mentioned that we should create an embed.go in the asset directory to complete the establishment of embedFs, and directly introduce this in other files file, complete the definition.

You can create a embed.go file in your assets directory and make the assets available as it’s own package to the rest of your program.

tomasf

As soon as this statement came out, it suddenly became clear! Give it a try, it really works. I created an embed.go file in the template directory and added the following code.

 package template

import "embed"

// go:embed *
var TemplateFs embed.FS

And use template.TemplateFs.ReadFile("index.tmpl") in another file to complete the reference of the template file. This neither violates golang’s cross-module nor makes the code unmaintainable, which is very good.

reference reading

  • https://ift.tt/PlmCrJo
  • https://ift.tt/AUZVcD2
  • https://ift.tt/Rz8LGtT
  • https://ift.tt/xBLwAbu
  • https://ift.tt/diyao1n

This article is reprinted from: https://www.ixiqin.com/2022/10/02/in-the-embedded-in-the-parent-directory-of-the-file/
This site is for inclusion only, and the copyright belongs to the original author.