因为最近织梦开启了版权收费,所以之前用织梦开发的网站都需要换一下,正好之前自己写了一套tp5开发的cms,本着为客户负责的态度,我们公司开始给之前的老客户免费更换后台,今天写这篇文章是为了记录下,tp
顺晟科技
2021-08-28 09:41:05
344
昨天在GopherChina 2021会议上分享了《深入Go Module》,因为干货太多,所以我将详细介绍接下来的几篇文章。
现在不是所有新的编程语言都提供库版本工具吗?Java、Python、nonjs、rust都有自己的库管理方法和库注册中心,而不管其名称如何。Go刚上市的时候没有库管理方式,采用GOPATH方式,所有项目都要在GOPATH之下。从其他语言(如Java)转过来的学生不止一次被问到:“为什么我不能编译在我文件夹下建造的项目?”,因为他的文件夹没有建在GOPATH下面,所以当他想在GOPATH下面建立一个项目时,package path又不知道该怎么写。(威廉莎士比亚,《北方执行》(Northern Exposure))。
所以GO使用的GOPATH方式对初学者来说确实是一件非常困惑的事情。随着Go生态系统的迅速增长,还出现了另一个经典的库管理问题。在我们项目的从属库中经常出现API broken的情况。从属库相关接口已更改,项目在更新从属库后编译。但是,必须修改代码以适应从属库的最新版本。更困难的是,如果多个从属库分别依赖第三个从属库的第三个版本,则会发生版本冲突。
几乎所有依赖库冲突的编程语言都存在这些问题,操作系统也存在DLL地狱问题,因此各种编程语言都尝试使用自己的方法来解决依赖库版本的问题。
如上所述,Go最初没有正式的库版本,由谷歌、glide、dep等第三方工具组成,2012年各种工具分别出现,海淘公司、浮沉公司,最后使用了一些常用工具,dep公司于2017年出现。
但是蜜月期没过多久,2018年Russ Cox经过深思熟虑和早期实验后,决定go库版本的方式需要从头开始,将go的各种工具(go get、go list等
但是无论如何,Go官方库管理方式是在2018年go 1.11中实验性引入的,可以通过设置环境变量GO11module=on来废弃,期待go 1.12正式退出,环境变量GO11module=on可以去除。但是意外地,go module上市后出现了很多问题。目前,所有go版本都有go module修改,因此该功能尚未最终完成。这就是我吐露它的地方。快三年了。feature开发了那么久,还有未来的go 1.17、GO1.17。
Go官方库管理方式称为go module。以前,库被配置为package,package将单个功能实现为由package或多个package组成的单个文件或多个文件。Go module是具有定义module path和从属库版本的go.mod文件的集成版本和已发布的package的集合。package作为子文件夹存在于module中,package path是modulepath'/'
一般来说,我们的项目都是单个module格式,项目主文件夹下是go.mod,子文件夹定义的package或主文件夹也是package。但是,项目可以包含多个模块。但是,这种方法并不常用。
Go.mod
Go module中最重要的是go.mod文件的定义,用于显示module及其从属库和从属库的版本。位于module的主文件夹下,通常命名为go.mod。
Go.mod的内容类似于以下格式3360
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
modulegithub.com/panicthis/modfile
Go 1.16
Require(
github.com/cenk/backoff v 2 . 2 . 1 incompatible
github.com/core OS/bbolt v 1 . 3 . 3
github.com/edwingeng/double jump v 0 . 0 . 0-20200330080233-E4 ea8 BD 1c Bed
github.com/stretchr/objx v 0 . 3 . 0//indirect
github.com/stretchr/testify v 1 . 7 . 0
go . etcd . io/b bolt v 1 . 3 . 6/indirect
go . etcd . io/etcd/client/v 2v 2 . 305 . 0-RC . 1
go . etcd . io/etcd/client/v 3v 3 . 5 . 0-RC . 1
golang . org/x/net v 0 . 0 . 0-20210610132358-84b 48 f 89b 13 b//indirect
golang . org/x/sys v 0 . 0 . 0-20210611083646-a4fc 73990273//indirect
)。
Exclude(
go . etcd . io/etcd/client/v 2v 2 . 305 . 0-RC . 0
go . etcd . io/etcd/client/v 3v 3 . 5 . 0-RC . 0
)。
Retract(
V1.0.0 //已废弃版本,使用v1.1.0
)。
虽然是简单的文件,但是里面的干坤不少,我依次介绍一下。(大卫亚设,北上广深)。
意义版本2.0.0
Go module遵循语义版本规范2.0.0。有意义的版本规范2.0.0指定版本号的格式、每个字段的含义、版本号比较规则等。
如果您想要项目的发行版,可以将tag设置为上述格式(例如v1.3.0、v2.0.0-rc.1等)。在Metadata中,Go版本比较中不参与运算,只是辅助信息。
Module path
Go.mod的行是module path,通常定义为仓库module name。所以当我们得到模块时,我们可以去那个仓库查询,或者让go proxy去仓库查询。(阿尔伯特爱因斯坦,北方执行)。
1
modulegithub.com/panicthis/modfile
如果你的版本已经大于或等于2.0.0,根据Go的规范,你需要加上major的后缀。module path应通过以下方式更改为:
1
modulegithub.com/panicthis/modfile/v2
1
modulegithub.com/panicthis/modfile/v3
此外,在引用代码时,必须添加v2、v3、VX后缀,以便与其他major版本区分开来。
这是一个非常奇怪的约定,优点是在一个项目中可以使用依赖库的不同major版本。这个版本可以共存。(大卫亚设,北上广深)。
Go directive
第二行是go directive。格式为go 1.xx,这不是当前使用的go版本,而是指定代码所需的Go的更低版本。
1
Go 1.16
Go的标准库也发生了变化,因此还添加了一些新的API,如果代码使用这些新的API,则可能需要指定依赖的go版本。(威廉莎士比亚,《北方执行》(Northern Exposure),标准)。
这一行不是必须的,你不用写。
Require
Require部分列出了项目所需的每个从属库及其版本。除了常规v1.3.0等版本外,还有奇怪的版本和注释。那么它们是什么意思呢?
不需要介绍正式版本号。大家都知道:
1
github.com/core OS/bbolt v 1 . 3 . 3
相似版本号
1
github.com/edwingeng/double jump v 0 . 0 . 0-20200330080233-E4 ea8 BD 1c Bed
上述库中的版本号是相似版本号v 0 . 0 . 0-20200330080233-E4 EA8 BD 1C Bed。这是go module生成的类似语义版本2.0.0。实际上,该库尚未发布此版本。
正式上,此从属库没有发行版本,go module需要指定此库的特定版本,因此创建的类似版本号。
Go module的目的是在go.mod上显示这个项目的所有依赖关系和他们决定的版本。
其中,20200330080233是此次提交时间,格式为yyyMMddhhmmss,e4ea8bd1cbed是此版本的commit id。此字段允许您查看此库的特定版本。
前面的v0.0.0可以有多种生成方法。主要取决于commit的base version:
如果没有VX.0.0-yyyymmdd hhmmss-abcdef abcdef 3360原生版本,则格式为VX . 0 . 0
VX。y . Z-pre . 0 . yyyymmdd hhmmss-abcdef ABC def:如果base版本是预发行版本(如vx.y.z-pre),请使用vx
如果VX . y .(Z1)-0 . yyyymmdd hhmmss-abcdef abcdef :基础版本正式上市,请在修补程序编号后加上1。例如,Vx.y. (Z1)-0
Indirect注释
1
2
3
go . etcd . io/b bolt v 1 . 3 . 6/indirect
golang . org/x/net v 0 . 0 . 0-20210610132358-84b 48 f 89b 13 b//indirect
golang . org/x/sys v 0 . 0 . 0-20210611083646-a4fc 73990273//indirect
一些库后面附有indirect后缀,这又是什么意思?
用一句话概括,间接使用了这个库,但如果没有被列入任何go.mod,那么这句话当然不太准确。更准确的说法是,以下内容之一将在此库中附加inderict后缀:
如果当前项目依赖A,但A的go.mod中缺少B,则在当前项目的go.mod中添加B,并添加indirect注释
当前项目依赖A,但如果A没有go.mod,则在当前项目的go.mod中添加B,并添加indirect注释
目前项目依赖A,A依赖B,A降级时降级的A不再依赖B。此时,B将显示indirect注释。
Incompatible
某些库后面带有incompatible后缀,但如果查看这些项目,则只会发布v2.2.1的tag,而不会发布incompatible后缀。
1
github.com/cenk/backoff v 2 . 2 . 1 incompatible
这些库使用go.mod管理,但不幸的是,这些库的major版本已经大于或等于2,但module path没有添加后缀,如v2、v3。
所以gho module把它们标记为incompatible。可以引用,但实际上不符合规格。
Exclude
如果要跳过项目中从属库的特定版本,可以使用此部分。
1
2
3
4
Exclude(
go . etcd . io/etcd/client/v 2v 2 . 305 . 0-RC . 0
go . etcd . io/etcd/client/v 3v 3 . 5 . 0-RC . 0
)。
这样,Go在选择版本时将积极跳过这些版本。例如,go get -u.或者,使用go get github.com/xxx/xxx@latest等命令时,执行version query的行为
Replace
另外,replace是解决对错误从属库的引用或调试从属库的常用方法。
1
2
3
replace github.com/coreos/b bolt=go . etcd . io/b bolt v 1 . 3 . 3
replace github.com/panicthis/a v 1 . 1 . 0=github.com/panicthis/r v 1 . 8 . 0
replace github.com/coreos/b bolt=./R
例如,etcd v3.3.x版本错误地将github.com/coreos/bbolt用作bbolt的module path,该库在自己的go.mod中声明的module path是go.etcd。
即使你认为某些依赖库有问题,你也可以自己去当地修改fork,调试,换一个经济高效的文件夹。(模板)。
Replace可以将一个库的所有版本替换为另一个库的特定版本,也可以将一个库的特定版本替换为另一个库的特定版本。
Retract
Retract以go 1.16中新增的内容,借用学术杂志投稿撤回一词,宣布撤回库版本。
如果不小心发布版本或以后发现版本不成熟,可以提示您不要推或使用宣布旧版本已撤销的新版本。
撤回的版本tag仍然存在,go proxy也存在这个版本,所以你强制的话还是可以使用的。否则这些版本将被省略。(阿尔伯特爱因斯坦,北上广深)。
与Exclude的区别在于,retract由该库的owner定义,而exclude由库用户在自己的go.mod中定义。
12
2021-11
28
2021-08
28
2021-08
16
2021-06
16
2021-06
16
2021-06