gobuffalo/packr
GitHub: gobuffalo/packr
Packr 是一个将静态文件嵌入 Go 二进制文件的工具,让开发者无需额外携带资源文件即可分发单一可执行程序。
Stars: 3391 | Forks: 194
**注意:请考虑将您的项目迁移至
[embed](https://pkg.go.dev/embed),这是 Go 原生的文件嵌入功能,
或者 github.com/markbates/pkger。它具有惯用的 API、极少的依赖、更强大的测试套件(直接针对标准库的对应组件进行测试)、透明的工具等等。**
https://blog.gobuffalo.io/introducing-pkger-static-file-embedding-in-go-1ce76dc79c65
# Packr (v2)
[](https://godoc.org/github.com/gobuffalo/packr/v2)
[](https://github.com/gobuffalo/packr/actions)
Packr 是一个将静态资源打包进 Go 二进制文件的简单解决方案。最重要的是,它在开发过程中对开发者非常友好。
目前,支持的 go 版本包括:
* 1.16.x
* 1.17.x
尽管它可能(也可能不会)在旧版本上良好运行。
## 介绍视频
要了解 Packr 的内容和初衷,请观看此简短视频:[https://vimeo.com/219863271](https://vimeo.com/219863271)。
## 库安装
### Go 1.16 及以上版本
```
$ go install github.com/gobuffalo/packr/v2@v2.8.3
```
或
```
$ go install github.com/gobuffalo/packr/v2@latest
```
### Go 1.15 及以下版本
```
$ go get -u github.com/gobuffalo/packr/...
```
## 二进制文件安装
### Go 1.16 及以上版本
```
$ go install github.com/gobuffalo/packr/v2/packr2@v2.8.3
```
或
```
$ go install github.com/gobuffalo/packr/v2/packr2@latest
```
### Go 1.15 及以下版本
```
$ go get -u github.com/gobuffalo/packr/packr2
```
## 新文件格式常见问题解答
在 `v2.0.0` 版本中,文件格式发生了变化,并且与 `packr-v1.x` 库不向后兼容。
#### `packr-v1.x` 可以读取新格式吗?
不,它不可以。由于新文件格式的工作方式,将其移植到 `packr-v1.x` 会比较困难。不过,欢迎提交 PR。 :)
#### `packr-v2.x` 可以读取 `packr-v1.x` 文件吗?
是的,它可以,但这种能力最终会被淘汰。因此,我们建议您迁移到新格式。
#### `packr-v2.x` 可以生成 `packr-v1.x` 文件吗?
是的,它可以,但这种能力最终会被淘汰。因此,我们建议您迁移到新格式。
`--legacy` 命令适用于所有生成 `-packr.go` 文件的命令。
```
$ packr2 --legacy
```
## 用法
### 在代码中
使用 Packr 的第一步是创建一个新的 box。一个 box 代表磁盘上的一个文件夹。一旦你有了一个 box,你就可以获取文件的 `string` 或 `[]byte` 表示形式。
```
// set up a new box by giving it a name and an optional (relative) path to a folder on disk:
box := packr.New("My Box", "./templates")
// Get the string representation of a file, or an error if it doesn't exist:
html, err := box.FindString("index.html")
// Get the []byte representation of a file, or an error if it doesn't exist:
html, err := box.Find("index.html")
```
### 什么是 Box?
Box 代表磁盘上的一个文件夹及其任何子文件夹,您希望在二进制文件中访问它们。使用 `packr2` CLI 编译二进制文件时,该文件夹的内容将被转换为可以编译到“标准” go 二进制文件中的 Go 文件。在编译后的二进制文件内部,这些文件将从内存中读取。在本地工作时,文件将直接从磁盘读取。这是一个无缝切换,不需要您进行任何特殊处理。
#### 示例
```
├── main.go
└── templates
├── admin
│ └── index.html
└── index.html
```
以下程序将读取 `./templates/admin/index.html` 文件并将其打印出来。
```
package main
import (
"fmt"
"github.com/gobuffalo/packr/v2"
)
func main() {
box := packr.New("myBox", "./templates")
s, err := box.FindString("admin/index.html")
if err != nil {
log.Fatal(err)
}
fmt.Println(s)
}
```
### 让开发变得简单
为了将静态文件放入 Go 二进制文件中,这些文件必须首先转换为 Go 代码。为此,Packr 提供了一些工具来帮助构建二进制文件。见下文。
然而,在开发过程中,必须不断运行工具来编译这些文件是非常痛苦的。
Packr 在查找文件时使用以下解析规则:
1. 在内存中(Go 二进制文件内部)查找文件
2. 在磁盘上(开发期间)查找文件
因为 Packr 知道如何回退到文件系统,所以开发者无需担心不断地将静态文件编译到二进制文件中。他们可以不受阻碍地进行工作。
Packr 进一步推进了文件解析。当声明一个新的 box 时,您使用一个相对路径,例如 `./templates`。当 Packr 收到此调用时,它会计算出该目录的绝对路径。通过这样做,这意味着可以保证 Packr 能够正确找到您的文件,即使您不是在创建 box 的目录中运行它。这有助于解决测试问题,在测试中 Go 会更改每个 package 的 `pwd`,使得相对路径难以处理。使用 Packr 时这不是问题。
## 结合 HTTP 使用
box 实现了 [`http.FileSystem`](https://golang.org/pkg/net/http/#FileSystem) 接口,这意味着它可以用来提供静态文件。
```
package main
import (
"net/http"
"github.com/gobuffalo/packr/v2"
)
func main() {
box := packr.New("someBoxName", "./templates")
http.Handle("/", http.FileServer(box))
http.ListenAndServe(":3000", nil)
}
```
## 构建二进制文件
在构建 Go 二进制文件之前,请先运行 `packr2` 命令。它将查找代码中的所有 box,然后生成 `.go` 文件,将静态文件打包成可以捆绑到 Go 二进制文件中的字节。
```
$ packr2
```
然后像平常一样运行您的 `go build command`。
*注意*:不建议将这些生成的 `-packr.go` 文件提交到版本库中。它们可能会很大,如果不小心的话很容易过时。建议您在运行 `packr2` 工具后始终运行 `packr2 clean`。
#### 清理
完成后,建议您运行 `packr2 clean` 命令。这将删除 Packr 为您创建的所有生成文件。
```
$ packr2 clean
```
为什么你要这样做?Packr 首先会查看存储在这些生成文件中的信息,如果信息不存在,它就会查看磁盘。这使得在开发中更容易使用。
## 调试
`packr2` 命令会将所有参数传递给底层的 `go` 命令,这包括用于打印 `go build` 信息的 `-v` 标志。Packr 会寻找 `-v` 标志,并开启其自身的详细日志记录。这对于尝试了解 `packr` 命令在运行时正在做什么非常有用。
## 常见问题解答
### Go Templates 的编译错误
问:我有一个包含 Go 模板文件的程序,这些文件名为 `foo.go`,如下所示:
```
// Copyright {{.Year}} {{.Author}}. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package {{.Project}}
```
当我运行 `packr2` 时,出现如下错误:
```
expected 'IDENT', found '{'
```
答:Packr 的工作原理是在您的 `.go` 文件中搜索 [`github.com/gobuffalo/packr/v2#New`](https://godoc.org/github.com/gobuffalo/packr/v2#New) 或 [`github.com/gobuffalo/packr/v2#NewBox`](https://godoc.org/github.com/gobuffalo/packr/v2#NewBox) 调用。因为这些文件不是“正确”的 Go 文件,所以 Packr 无法解析它们以找到 box 声明。要解决此问题,您需要告诉 Packr 在搜索 box 时忽略这些文件。此问题的一些解决方案是:
* 将文件重命名为其他名称。`.tmpl` 扩展名是命名此类文件的习惯用法。
* 将包含这些文件的文件夹重命名为以 `_` 开头,例如 `_templates`。Packr 和 Go 一样,在搜索 box 时会忽略以 `_` 字符开头的文件夹。
### 动态 Box 路径
问:我需要使用变量来设置 box 的路径,但是 `packr.New("foo", myVar)` 无法正常工作。
答:Packr 在使用 [`github.com/gobuffalo/packr/v2#New`](https://godoc.org/github.com/gobuffalo/packr/v2#New) 时会尝试“自动”设置其解析目录,但是,对于动态路径,您需要手动设置它:
```
box := packr.New("foo", "|")
box.ResolutionDir = myVar
```
### 我不想打包文件,但仍想使用 Packr 接口。
问:我想编写使用 Packr 工具的代码,但实际上并不将文件打包到我的二进制文件中。我该怎么做?
答:使用 [`github.com/gobuffalo/packr/v2#Folder`](https://godoc.org/github.com/gobuffalo/packr/v2#Folder) 会返回一个可以像平常一样使用的 `*packr.Box`,但在编译时会被 Packr 工具排除。
### Packr 未找到任何 Box
问:我运行了 `packr2 -v` 但它没有找到我的 box:
```
DEBU[2019-03-18T18:48:52+01:00] *parser.Parser#NewFromRoots found prospects=0
DEBU[2019-03-18T18:48:52+01:00] found 0 boxes
```
答:Packr 的工作原理是解析 `.go` 文件以查找 [`github.com/gobuffalo/packr/v2#Box`](https://godoc.org/github.com/gobuffalo/packr/v2#Box) 和 [`github.com/gobuffalo/packr/v2#NewBox`](https://godoc.org/github.com/gobuffalo/packr/v2#NewBox) 声明。如果运行 `packr2` 的文件夹中没有任何 `.go` 文件,它就无法找到这些声明。要解决此问题,请在包含您 `.go` 文件的目录中运行 `packr2` 命令。
### Box 接口
问:我希望能通过传入模拟的 box 来轻松测试我的应用程序。我该怎么做?
答:Packr 的 box 和文件符合 [`github.com/gobuffalo/packd`](https://godoc.org/github.com/gobuffalo/packd) 中定义的接口。更改您的应用程序以使用这些接口,而不是具体的 Packr 类型。
```
// using concrete type
func myFunc(box *packr.Box) {}
// using interfaces
func myFunc(box packd.Box) {}
```
标签:EVTX分析, Go, Ruby工具, SOC Prime, 工具库, 开发工具, 文档结构分析, 日志审计, 编译嵌入, 静态资源打包