想法和概念
我一开始就考虑到了以下特点。
- 轻量级CLI
- 简单的认证
- 上传至S3
- 可配置不同文件集的缓存头信息
- 可配置的源文件夹,可选择忽略某些文件
- Cloudfront无效
- 可配置的无效URL
- 干运行选项
- 在开始上传/失效前测试配置(这可能会产生成本)。
Go在创建轻量级CLI方面非常出色,即使没有任何额外的库或框架。flag 包和方便的I/O通常对这样的小项目是足够的。
对于配置来说,一个简单的config.yml 文件就足够了,用正则表达式来过滤文件,用文件集来过滤头文件。
认证将通过配置文件或环境变量来处理,这很简单,并将安全处理工具的责任放在用户身上。
到目前为止,还不错。
实施
看看这个功能集,我决定采用以下结构。
- main.go
- 包失效
- invalidate.go
- 软件包上传
- upload.go
这样每个人都可以在需要时自行使用隔离的invalidate 和upload 包。
main.go
这里真的没有发生什么。我使用flag 包来解析命令行标志,并将config.yml 文件读入以下数据结构。
type Config struct {
Auth struct {
Accesskey string
Key string
}
S3 upload.Config
Cloudfront invalidate.Config
}
其中S3 和Cloudfront 代表我的两个worker 包的配置对象。
在解析了配置文件后,main.go 只需用给定的命令行选项和各自的配置调用另外两个包。它还会传入一个logger ,所以这些包不必写到Stdout。这样做的另一个好处是,可以通过传入ioutil.Discard 写入器来实现silent 标志,它可以扔掉所有写给它的信息。
如果有错误发生,它只是被记录下来,然后程序退出。
upload/upload.go
这是它变得更有趣的地方。upload 包有两个公共函数。
ParseFiles- 根据配置创建并返回一个从文件路径到头文件的地图
Do- 上传在创建的地图中指定的文件。
ParseFiles
- 上传在创建的地图中指定的文件。
upload 包的配置对象看起来像这样。
type Header map[string]string
type Files map[string][]Header
type Config struct {
Bucket struct {
Name string
Accesskey string
Key string
}
Parallel int
Source string
Ignore string
Metadata []struct {
Regex string
Headers []Header
}
}
ParseFiles 读取 文件夹,忽略所有与 匹配的文件,如果文件与 匹配,则添加 中给出的 。 出来的是一个 对象,它是一个从文件路径到文件配置的 的映射。Source Ignore Regex Metadata Headers Files Headers
第二个函数,Do 拿到Files 对象,同时(由Parallel 选项指定)为每个条目调用uploadFile ,为每个文件设置适当的头文件。
在uploadFile ,Multipart 文件被创建并发送到AWS S3PUT 端点。最初,我想用io.Pipe ,以便以最小的内存占用有效地串联文件,但AWS的分块上传API与Go标准库的默认实现不兼容。
虽然解决这个问题肯定很有趣,但这似乎是不成熟的优化(特别是考虑到一个静态博客的文件大小在千字节以下)。
请求认证是通过伟大的github.com/smartystree…包完成的,这使得它变得如此简单。
req, err := http.NewRequest(...)
awsauth.Sign(req, awsauth.Credentials{
AccessKeyID: config.Bucket.Accesskey,
SecretAccessKey: config.Bucket.Key,
})
当然,在这个I/O繁重的过程中,可能会发生大量的错误,这些错误都会得到相应的处理。如果出现dry-run ,本来已经上传的文件就会被打印在屏幕上。
invalidate/invalidate.go
invalidate 包只有一个公共函数。
Do- 创建XML有效载荷并将其发送至AWS Cloudfront API
invalidate 的配置对象看起来像这样。
type Config struct {
Distribution struct {
Id string
Accesskey string
Key string
}
Invalidation []string
}
无效化比上传部分要简单一些。首先,XML有效载荷是使用惊人的github.com/beevik/etre…包创建的,然后被发送到Cloudfront API的invalidation 端点。
请求认证的工作方式与upload 包中相同。在dry-run ,会被无效的URL被打印到屏幕上。
结论
在我看来,自己解决像这样的小型自动化问题总是一种有趣的学习经验。我也更喜欢精简的、单一用途的工具,而不是臃肿的软件,只要你把它配置好,它就能做所有的事情(这有时会和自己写一个新工具一样长......)。
解决这个简单的问题也是提高我的围棋技能的一个好方法,有一些有趣的挑战,如同时上传文件,建立一个易于使用的CLI,以及与一个奇怪的基于XML的API一起工作。
这篇文章中描述的工具正是我现在需要的。它使我能够通过一个简单的命令来更新我的博客。
如果有需要的话,我可能会在将来为它添加一些更多的功能,但现在我对它很满意。如果有其他人觉得它有用--那就更好了! :):)