惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

W
WeLiveSecurity
Jina AI
Jina AI
博客园 - 司徒正美
雷峰网
雷峰网
宝玉的分享
宝玉的分享
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
博客园_首页
WordPress大学
WordPress大学
Google DeepMind News
Google DeepMind News
GbyAI
GbyAI
MyScale Blog
MyScale Blog
Apple Machine Learning Research
Apple Machine Learning Research
美团技术团队
I
InfoQ
博客园 - Franky
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
博客园 - 叶小钗
阮一峰的网络日志
阮一峰的网络日志
Cyberwarzone
Cyberwarzone
C
CXSECURITY Database RSS Feed - CXSecurity.com
S
Schneier on Security
P
Privacy & Cybersecurity Law Blog
T
Threatpost
Cloudbric
Cloudbric
D
Docker
M
MIT News - Artificial intelligence
Recent Commits to openclaw:main
Recent Commits to openclaw:main
Vercel News
Vercel News
Martin Fowler
Martin Fowler
J
Java Code Geeks
AWS News Blog
AWS News Blog
The Cloudflare Blog
酷 壳 – CoolShell
酷 壳 – CoolShell
L
Lohrmann on Cybersecurity
Hacker News: Ask HN
Hacker News: Ask HN
Last Week in AI
Last Week in AI
S
Security @ Cisco Blogs
Help Net Security
Help Net Security
C
Cisco Blogs
V
V2EX
博客园 - 【当耐特】
I
Intezer
爱范儿
爱范儿
F
Fortinet All Blogs
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
P
Privacy International News Feed
IT之家
IT之家
L
LINUX DO - 最新话题
B
Blog RSS Feed
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO

Razeen`s Blog

Let's Encrypt 推出 Gen Y 根证书架构:揭示 Web PKI 的五大未来趋势 通过 Wi-Fi 自动备份你的 iPhone 到 Nas 管理培训感悟:从技术视角看管理之路 UPS 一拖多:保护你的 NAS 和 Linux 服务器 从影音中心到 AI 助手:我的50款 Homelab 服务清单 从SSL证书有效期将缩短到47天聊开去 部署一个自己的 Running Page 谈谈特斯拉 Model Y 用车一年的感受和费用分析 弃用 Disqus 评论,使用自建 Waline 使用 Prometheus 和 Grafana 搭建你的证书监控面板 服务器迁移记:一次磁盘换板引发的Linux分区与挂载的学习 改善信息来源, 利用 RSS 高效获取资讯 (RSShub + Reeder5 + WeWe RSS) 多种 Docker 镜像拉取解决方案与实践 App分享 | AppCleaner - Mac上的卸载神器 Azure OpenAI API 申请和使用 如何开通 OneKey 虚拟信用卡,并充值消费 如何拥有一个可长期在国内使用的国外手机号码 分享开通 ChatGPT Plus 过程 如何开通 Depay 虚拟信用卡,并充值消费 如何开通欧易Web3钱包, 交易入账 如何5分钟内1块钱注册 ChatGPT 如何注册美区的 Apple ID (2023年/无需科学上网) NAS折腾记(11): NASTool3.0体验和降级 NAS折腾记(10): Docker版本的NASTool配置 NAS折腾记(9): NASTool与微信交互,微信发送消息远程下载电影【多图】 NAS折腾记(8):群晖安装 NASTool 实现影音半自动化【多图】 内网穿透(2):Tailscale 组网实现内网穿透,操作简单,无成本 内网穿透(1):总结了11中内网穿透的方式,总有一种适合你 NAS折腾记(7):从零开始设置(黑)群晖系统 NAS折腾记(6):黑群晖系统安装好后怎么洗白? NAS折腾记(5):群晖硬盘休眠设置与分析 NAS折腾记(4): 20分钟手把手带你完美安装 DS918+ 黑群晖7.1.1 NAS折腾记(3):NAS 装机 NAS折腾记(2):B360-ITX 双M.2 双2.5G网口 6 SATA主版 开箱 NAS折腾记(1):328元的4盘位Nas机箱开箱 Openwrt + Clash 全局科学上网 Newifi3 刷入 OpenWrt 固件 v21.02 利用 Markdown 画一些流程图、时序图、甘特图等 Homelab(8): 搭建自用 Gitlab 与 Docker 仓库 Nginx Tcp 转发保留客户端真实 IP (PROXY Protocol) Homelab (7):IPSec VPN(基于证书认证)客户端设置 Homelab (6): 基于自签发证书的 IPSec VPN 搭建 Homelab (5): DDNS 动态域名解析 Homelab (4): Linux 服务器基础环境准备 Homelab (3): 整体网络与基础硬件介绍 Github Actions 初体验之自动化部署 Hexo 博客 记一次 Nginx DNS 缓存导致转发问题 Homelab (2): 电信悦me网关修改桥接模式,路由器拨号 Homelab (1):5分钟上手黑群晖 NAS 终极 Bash 脚本指南 Typora 自动上传图片到七牛云 Ubuntu 20.04 LTS 有线网卡驱动安装 折腾 Ubuntu 20.04 LTS 开发环境 Go学习笔记(九) 计时器的生命周期[译] 利用 git hook 规范你的代码与 commit message 规范 git commit message 与自动化版本控制 超详细 vim 配置 (with MacVim) Golang 中的 RESTful API 最佳实践 折腾服务器(开篇) 我的第一台个人服务器 Newifi3 实现低成本家庭级科学上网 Go学习笔记(八) | 使用 os/exec 执行命令 如何用 Go 调用 Windows API Mac OS 自动根据 WI-FI 名字改变网络位置 关于 Docker 清理 MIME Types 速查表 Go学习笔记(七) | 理解OAuth 2.0并实现一个客户端 我又又又把博客迁移了 Go学习笔记(六) | 使用swaggo自动生成Restful API文档 Go学习笔记(五) | 使用代码片段(snippets)提高编码效率 书单 - 2018 IPFS 初体验,利用 IPFS 托管你的静态网站 记一次 PostgreSQL LIKE 索引优化,联合字段 LIKE 查询优化。 Disqus 添加有趣的 Reactions 的功能 TLS 1.3 详解 (RFC 8446解读) gRPC在Go中的使用(三)gRPC实现TLS加密通信与流模式 gRPC在Go中的使用(二)gRPC实现简单通讯 gRPC在Go中的使用(一)Protocol Buffers语法与相关使用 CentOS 安装 tshark 抓包工具 Go学习笔记(四) | win上使用VSCode搭建Go开发环境 日常 Postgres 数据库点滴记录 简单了解 PKCS 规范 美食篇 | DIY戚风蛋糕(烤箱做蛋糕) Go学习笔记(三) | 怎么写Go基准测试(性能测试) TLS1.3正式更新,为Nginx添加TLS1.3的支持 一次诡异的数据库删除 GitHub Pages自定义域名开启HTTPS 证书透明度是什么?它是怎么工作的? Go学习笔记(二) | 我对 recover 的一点误解 搭建证书透明度(certificate-transparency)日志服务之从入门到放弃 修复远程登陆 Centos 时,出现 UTF-8 Warning HTTPS篇之SSL握手过程详解 Go学习笔记(一) | postgres与golang点点滴滴 AWS 命令行界面(aws-cli)从安装到快速上手 数字证书分类及怎么区分各类数字证书 常用 linux 命令小结(一)文件目录操作 云服务器搭建 hexo 博客,git hooks自动更新 SSH 免密登陆, SSH Config 配置 Golang CGO Mac 交叉编译 Windows 使用 goose 让数据库迁移更加轻松 开始使用Ghost
Go学习笔记(十)老项目迁移 go module 大型灾难记录
2021-07-20 · via Razeen`s Blog

最近在改造一个比较早期的一个项目,其中就涉及到用将原来 Vendor 管理依赖换成 Go Modules 来管理。 然而过程真是一波三折,在这里总结一下此次 Go Modules 改造中遇到的问题,以及解决方法。

背景

  • go version:

    $ go version
    go version go1.16.5 darwin/amd64
    
  • 简化的 demo 如下, 很 “简单” 我们只要把 hello world 输出即可。

    package main
    
    import (
    	"github.com/coreos/etcd/pkg/transport"
    	"github.com/google/certificate-transparency-go/tls"
    	"github.com/qiniu/api.v7/auth/qbox"
    	"go.etcd.io/etcd/clientv3"
    	"google.golang.org/grpc"
    	"qiniupkg.com/x/log.v7"
    )
    
    func main() {
    
    	_ = transport.TLSInfo{}
    
    	_ = clientv3.WatchResponse{}
    
    	_, _ = clientv3.New(clientv3.Config{})
    
    	_ = qbox.NewMac("", "")
    
    	_ = tls.DigitallySigned{}
    
    	_ = grpc.ClientConn{}
    
    	log.Info("hello world")
    }
    

实战

直接初始化,并 tidy 一下。

$ go mod init demo-go/gomod
go: creating new go.mod: module demo-go/gomod
go: to add module requirements and sums:
        go mod tidy
   
$ go mod tidy
go: finding module for ...
demo-go/gomod imports
        qiniupkg.com/x/log.v7: module qiniupkg.com/x@latest found (v1.11.5), but does not contain package qiniupkg.com/x/log.v7
demo-go/gomod imports
        github.com/qiniu/api.v7/auth/qbox imports
        github.com/qiniu/x/bytes.v7/seekable: module github.com/qiniu/x@latest found (v1.11.5), but does not contain package github.com/qiniu/x/bytes.v7/seekable
demo-go/gomod imports
        go.etcd.io/etcd/clientv3 imports
        github.com/coreos/etcd/Godeps/_workspace/src/golang.org/x/net/context: package github.com/coreos/etcd/Godeps/_workspace/src/golang.org/x/net/context provided by github.com/coreos/etcd at latest version v2.3.8+incompatible but not at required version v3.3.10+incompatible
demo-go/gomod imports
        go.etcd.io/etcd/clientv3 imports
        github.com/coreos/etcd/Godeps/_workspace/src/google.golang.org/grpc: package github.com/coreos/etcd/Godeps/_workspace/src/google.golang.org/grpc provided by github.com/coreos/etcd at latest version v2.3.8+incompatible but not at required version v3.3.10+incompatible
demo-go/gomod imports
        go.etcd.io/etcd/clientv3 imports
        github.com/coreos/etcd/Godeps/_workspace/src/google.golang.org/grpc/credentials: package github.com/coreos/etcd/Godeps/_workspace/src/google.golang.org/grpc/credentials provided by github.com/coreos/etcd at latest version v2.3.8+incompatible but not at required version v3.3.10+incompatible
demo-go/gomod imports
        go.etcd.io/etcd/clientv3 imports
        github.com/coreos/etcd/storage/storagepb: package github.com/coreos/etcd/storage/storagepb provided by github.com/coreos/etcd at latest version v2.3.8+incompatible but not at required version v3.3.10+incompatible

好家伙,报错了。我们先看到前两行

  1. qiniupkg.com/x@latest 中没有 qiniupkg.com/x/log.v7
  2. github.com/qiniu/x@latest 中没有 github.com/qiniu/x/bytes.v7/seekable

这看起来应该是一个问题, qiniupkg.com/xgithub.com/qiniu/x 应该是同一个包,不同镜像。于是我到 Github 看一下 @lastet 版本的代码,确实没有bytes.v7 包了。人肉查找,最后在 v1.7.8 版本,我们找到了 bytes.v7 包。

于是,我们可以指定一下版本。

go mod edit -replace qiniupkg.com/x=qiniupkg.com/x@v1.7.8
go mod edit -replace github.com/qiniu/x=github.com/qiniu/x@v1.7.8

继续往下看,接下来的几个问题是一类的,都是etcd导致的。

意思是 go.etcd.io/etcd/clientv3 导入了 github.com/coreos/etcd/Godeps/_workspace/src/golang.org/x/net/context, 同时 github.com/coreos/etcd@v2.3.8 中 提供了 github.com/coreos/etcd/Godeps/_workspace/src/golang.org/x/net/context 。 但是,我们这里需要 github.com/coreos/etcd@v3.3.10, 而该版本并不提供 github.com/coreos/etcd/Godeps/_workspace/src/golang.org/x/net/context

我们直接更新 etcd 到的 v3.3.10 试试。

go mod edit -replace go.etcd.io/etcd=go.etcd.io/etcd@v3.3.20+incompatible

我们再 go mod tidy 下。

$ go mod tidy
go: demo-go/gomod imports
        go.etcd.io/etcd/clientv3 tested by
        go.etcd.io/etcd/clientv3.test imports
        github.com/coreos/etcd/auth imports
        github.com/coreos/etcd/mvcc/backend imports
        github.com/coreos/bbolt: github.com/coreos/bbolt@v1.3.6: parsing go.mod:
        module declares its path as: go.etcd.io/bbolt
                but was required as: github.com/coreos/bbolt

这个错误和鸟窝这篇 Etcd使用go module的灾难一致,go.etcd.io/bboltgithub.com/coreos/bbolt 包名不一致,我们替换一下。

go mod edit -replace github.com/coreos/bbolt@v1.3.6=go.etcd.io/bbolt@v1.3.6

继续,go mod tidy 一下。

$ go mod tidy
...
demo-go/gomod imports
        go.etcd.io/etcd/clientv3 imports
        github.com/coreos/etcd/clientv3/balancer: module github.com/coreos/etcd@latest found (v2.3.8+incompatible), but does not contain package github.com/coreos/etcd/clientv3/balancer
demo-go/gomod imports
        go.etcd.io/etcd/clientv3 imports
        github.com/coreos/etcd/clientv3/balancer/picker: module github.com/coreos/etcd@latest found (v2.3.8+incompatible), but does not contain package github.com/coreos/etcd/clientv3/balancer/picker
demo-go/gomod imports
        go.etcd.io/etcd/clientv3 imports
        github.com/coreos/etcd/clientv3/balancer/resolver/endpoint: module github.com/coreos/etcd@latest found (v2.3.8+incompatible), but does not contain package github.com/coreos/etcd/clientv3/balancer/resolver/endpoint
demo-go/gomod imports
        go.etcd.io/etcd/clientv3 imports
        github.com/coreos/etcd/clientv3/credentials: module github.com/coreos/etcd@latest found (v2.3.8+incompatible), but does not contain package github.com/coreos/etcd/clientv3/credentials
demo-go/gomod imports
        go.etcd.io/etcd/clientv3 tested by
        go.etcd.io/etcd/clientv3.test imports
        github.com/coreos/etcd/integration imports
        github.com/coreos/etcd/proxy/grpcproxy imports
        google.golang.org/grpc/naming: module google.golang.org/grpc@latest found (v1.39.0), but does not contain package google.golang.org/grpc/naming

好家伙,又是etcd。 仔细一看,我们导入了github.com/coreos/etcdgo.etcd.io/etcd 两个版本etcd, 我们前面只替换了一个。现在我们把另外一个也替换了。

go mod edit -replace github.com/coreos/etcd=github.com/coreos/etcd@v3.3.20+incompatible

go mod tidy下,这个错误没有了,但还有个grpc的错误,继续找原因。原来是 google.golang.org/grpc v1.39.0 版本没有 google.golang.org/grpc/naming 包。 上 Github 仓库, 找了一下历史版本,v1.29.1上是有这个包的,我们继续替换。

go mod edit -replace google.golang.org/grpc=google.golang.org/grpc@v1.29.1

这下,终于,go mod tidy通过了,可以开心的输出hello world 了。

然而,

$ go run main.go
# github.com/coreos/etcd/clientv3/balancer/resolver/endpoint
../../../go/pkg/mod/github.com/coreos/etcd@v3.3.20+incompatible/clientv3/balancer/resolver/endpoint/endpoint.go:114:78: undefined: resolver.BuildOption
../../../go/pkg/mod/github.com/coreos/etcd@v3.3.20+incompatible/clientv3/balancer/resolver/endpoint/endpoint.go:182:31: undefined: resolver.ResolveNowOption
# github.com/coreos/etcd/clientv3/balancer/picker
../../../go/pkg/mod/github.com/coreos/etcd@v3.3.20+incompatible/clientv3/balancer/picker/err.go:37:44: undefined: balancer.PickOptions
../../../go/pkg/mod/github.com/coreos/etcd@v3.3.20+incompatible/clientv3/balancer/picker/roundrobin_balanced.go:55:54: undefined: balancer.PickOptions

意不意外,惊不惊喜!!

原来etcd包依赖了grpcresolver包,但我导入的v1.29.1版本的grpc是没有这个包的。到 grpc仓库 挨个版本看了一下,确实只有v1.26.0版本才声明了type BuildOption 。于是,我们再次使用替换大法。

go mod edit -replace google.golang.org/grpc=google.golang.org/grpc@v1.26.0

再次tidy, 运行! 终于,看到了久违的hello world!

$ go run main.go
2021/07/20 12:27:09.642431 [INFO] /Users/razeen/wspace/github/demo-go/gomod/main.go:26: hello world

总结

项目规范

现在我们回过头看下这个 demo 项目,其实很有问题。

	"github.com/coreos/etcd/pkg/transport"
	"github.com/google/certificate-transparency-go/tls"
	"github.com/qiniu/api.v7/auth/qbox"
	"go.etcd.io/etcd/clientv3"
	"google.golang.org/grpc"
	"qiniupkg.com/x/log.v7"

etcdqiniupkg的包完全可以统一,只导入一种!而且,后来我们发现log.v7这包也是意外导入的….

这也是在改造我们一些老的项目时遇到的问题,以前用vendor go get 没有注意到这些问题,这是需要提前规范的。

看懂 go.mod

我们来简单看一下,经历各种坎坷后,得出的go.mod 文件。

module demo-go/gomod

go 1.16

replace qiniupkg.com/x => qiniupkg.com/x v1.7.8

replace github.com/qiniu/x => github.com/qiniu/x v1.7.8

replace go.etcd.io/etcd => go.etcd.io/etcd v3.3.20+incompatible

replace github.com/coreos/bbolt v1.3.6 => go.etcd.io/bbolt v1.3.6

replace github.com/coreos/etcd => github.com/coreos/etcd v3.3.20+incompatible

replace google.golang.org/grpc => google.golang.org/grpc v1.26.0

require (
	github.com/coreos/bbolt v1.3.6 // indirect
	github.com/coreos/etcd v3.3.10+incompatible
	github.com/dgrijalva/jwt-go v3.2.0+incompatible // indirect
	github.com/google/certificate-transparency-go v1.1.1
	github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 // indirect
	github.com/qiniu/api.v7 v7.2.5+incompatible
	github.com/qiniu/x v0.0.0-00010101000000-000000000000 // indirect
	github.com/soheilhy/cmux v0.1.5 // indirect
	github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 // indirect
	go.etcd.io/etcd v0.0.0-20200513171258-e048e166ab9c
	google.golang.org/grpc v1.29.1
	qiniupkg.com/x v0.0.0-00010101000000-000000000000
	sigs.k8s.io/yaml v1.2.0 // indirect
)

我们先看一个常见的这几个指令

  • module 定义主模块的路径;
  • go 编写该mod文件时的go版本;
  • require 声明给定模块依赖项的最低要求版本;
  • replace 手动指定的依赖模块 (可以替换全部的版本、指定的版本、本地的版本等等 );

还有就是 v3.3.20+incompatible 后面的 +incompatible , 这是指兼容的版本,指依赖库的版本是v2 或以上,但go.mod和 依赖库路径 没有按照官方指定的方式命名,会加上这个。

v0.0.0-00010101000000-000000000000 这是一个伪版本,在和 不兼容 module 或 标记的版本不可用的时候,回打上这个伪版本。

// indirect 这指明这些不是我们直接引用的依赖。

除此之外,以下指令也可了解一下。

# 查看当前模块以及所有的依赖模块
go list -m all

# 查看某个模块的以及打标签的版本
go list -m -versions go.etcd.io/etcd

# 升级特定的包
go get xx@version 升级特定的包

# 了解为什么需要模块
go mod why -m all  

# 为什么需要指定(google.golang.org/grpc)的模块
go mod why -m google.golang.org/grpc

更多可以细读官方文档,感谢阅读。

参考