前言
- 在开发信息收集工具过程中,两个不同的程序用到了大部分相同的代码,而且共用了部分命令行参数解析代码,当这两个程序编译时如果不分开就会将另一个程序的命令行参数也一起编译进来了,所以需要再不同程序中引用不同的文件进行编译。
如何使用Tags
- 先例如两个程序都共用了同一份命令行参数解析的代码,功能都是设置Redis连接参数的
package pconfig
import (
"crypto/sha1"
"encoding/hex"
)
type node_config struct {
NodeFlag string //上线标识,UUID前8位
ACL string //ACL
Addr string //连接帐号密码
UserName string //用户名
PassWord string //密码
DB int //Redis仓库
Sha1 string //签名
}
var (
PENodeConfig node_config
)
func (n *node_config) Verify() bool {
s := sha1.New()
s.Write([]byte(n.ACL + n.NodeFlag + n.UserName + n.PassWord))
ss := hex.EncodeToString(s.Sum(nil))
return ss == n.Sha1
}
package pconfig
import (
"os"
"path"
"peien-engine/logger"
"github.com/spf13/pflag"
"github.com/spf13/viper"
)
func init() {
PENodeConfig = node_config{}
pflag.String("node_flag", "0c3f6d78", "上线标识")
pflag.String("acl", "acl_key", "Redis ACL键")
pflag.Int("redis_db", 5, "Redis 仓库")
pflag.String("redis_host", "127.0.0.1:6379", "Redis 服务器地址")
pflag.String("redis_username", "kali-team", "Redis 用户名")
pflag.String("redis_password", "password", "Redis 密码")
pflag.String("sha1", "344f3467e824e7c5f54875ad53f7051eea925939", "Redis 数字签名")
pflag.Parse()
viper.AutomaticEnv()
viper.BindPFlags(pflag.CommandLine)
PENodeConfig.NodeFlag = viper.GetString("node_flag")
PENodeConfig.ACL = viper.GetString("acl")
PENodeConfig.Addr = viper.GetString("redis_host")
PENodeConfig.UserName = viper.GetString("redis_username")
PENodeConfig.PassWord = viper.GetString("redis_password")
PENodeConfig.DB = viper.GetInt("redis_db")
PENodeConfig.Sha1 = viper.GetString("sha1")
if !PENodeConfig.Verify() {
logger.Error("Redis签名错误")
os.Exit(1)
}
}
- 第一个程序有一个超时参数,第二个程序没有这个参数,但是第二个程序有一个Token参数。
//go:build node
// +build node
package pconfig
import (
"os"
"path"
"github.com/spf13/pflag"
"github.com/spf13/viper"
)
var (
PEScanConfig = scan_config{
Timeout: *pflag.Int("timeout", 15, "Nuclei验证超时参数,默认:15秒")}
)
func init() {
viper.AutomaticEnv()
viper.BindPFlags(pflag.CommandLine)
PEScanConfig.Timeout = viper.GetInt("timeout")
}
//go:build engine
// +build engine
package pconfig
import (
"github.com/spf13/pflag"
"github.com/spf13/viper"
)
var (
PEApiToken = token{
ApiToken: *pflag.String("api_token", "token", "接口Token")}
)
func init() {
viper.AutomaticEnv()
viper.BindPFlags(pflag.CommandLine)
PESumap.SumapApiToken = viper.GetString("api_token")
}
编译
- 再编译时加上
-tags
参数分别加上你设置的标签名称,例如:
go build -tags engine -ldflags "-s -w -extldflags '-static'" -o engine cmd/engine/receiver/main.go
go build -tags node -ldflags "-s -w -extldflags '-static'" -o node cmd/node/receiver/main.go
效果
➜ peien-engine git:(master) ✗ ./engine -h
Usage of ./engine:
--acl string Redis ACL键 (default "acl_key")
--node_flag string 上线标识 (default "0c3f6d78")
--redis_db int Redis 仓库 (default 5)
--redis_host string Redis 服务器地址 (default "127.0.0.1:6379")
--redis_password string Redis 密码 (default "password")
--redis_username string Redis 用户名 (default "kali-team")
--sha1 string Redis 数字签名 (default "344f3467e824e7c5f54875ad53f7051eea925939")
--api_token string 接口Token (default "token")
pflag: help requested
➜ peien-engine git:(master) ✗ ./node -h
Usage of ./node:
--acl string Redis ACL键 (default "acl_key")
--node_flag string 上线标识 (default "0c3f6d78")
--redis_db int Redis 仓库 (default 5)
--redis_host string Redis 服务器地址 (default "127.0.0.1:6379")
--redis_password string Redis 密码 (default "password")
--redis_username string Redis 用户名 (default "kali-team")
--timeout int Nuclei验证超时参数,默认:15秒 (default 15)
--sha1 string Redis 数字签名 (default "344f3467e824e7c5f54875ad53f7051eea925939")
pflag: help requested
VsCode的gopls提示
- 加了tags标签后会出现无法引用解析到这个文件,开发时会变得更麻烦,所以要加上配置,创建文件:.vscode/settings.json,添加你设置的两个标签,重新加载VsCode插件。
{
"gopls": {
"build.buildFlags": [
"-tags=engine,node",
],
},
}
总结
- go的tags类似rust中的
features
和cfg
的宏定义,但是相比之下还是比不上rust的灵活和方便,而且在使用过程中要每个文件前面都加上注释,没办法对函数级,更小单元的控制,只能把全部函数或者变量都放在同一个文件上,总体功能够用。