为了账号安全,请及时绑定邮箱和手机立即绑定

迁移到 Go 模块,同时继续使用分发包

迁移到 Go 模块,同时继续使用分发包

Go
蛊毒传说 2022-08-24 18:55:45
我有一个基于GOPATH的项目,我目前在Fedora上构建如下:sudo dnf install golang-etcd-bbolt-devel golang-x-sys-devel golang-x-text-devel GOPATH=$HOME/go:/usr/share/gocode go build我的项目(gonzofilter)实现了一个命令行实用程序,因此源文件位于主包中(即它们具有声明)。package main在 Fedora 34 及更高版本中,Go 似乎删除了对构建 GOPATH 样式项目的支持,人们真的必须使用 Go 模块:go build go: cannot find main module; see 'go help modules'那篇Go博客文章涵盖了我的情况(->“没有依赖管理器”),但它没有明确提到如何处理主包项目或分发提供的依赖关系。那么,如何迁移这样的项目呢?我如何告诉Go/在?go mod tidy/usr/share/gocode编辑:确切地说:Fedora 34 附带了 Go 1.16,它“刚刚”将默认值从 更改为 .因此,仍然可以通过设置来恢复旧行为。GO111MODULEautoonGO111MODULE=auto但是,Golang开发人员已经宣布他们希望放弃对Gopath样式项目的Gopath 1.17的支持:我们计划在 Go 1.17 中放弃对 GOPATH 模式的支持。换句话说,Go 1.17 将忽略 GO111MODULE。如果您的项目未在模块感知模式下生成,那么现在是时候迁移了。
查看完整描述

4 回答

?
天涯尽头无女友

TA贡献1831条经验 获得超9个赞

理想情况下,发行版应将已安装的依赖项打包在与 GOPROXY 协议兼容的布局中。然后,您将能够进行适当的设置并运行以使用已安装的依赖项。GOPROXYgo mod tidy

但是,据我所知,在这一点上,没有发行版实际上提供了一棵树。您可能需要一个解决方法。GOPROXY


下一个最好的选择是使用指令自己连接替换件。 已经知道更喜欢指令中的版本而不是其他版本,所以做这样的事情就足够了:replacego mod tidyreplace

go mod init github.com/gsauthof/gonzofilter

go mod edit -replace go.etcd.io/bbolt=/usr/share/gocode/src/go.etcd.io/bbolt
go mod edit -replace golang.org/x/sys=/usr/share/gocode/src/golang.org/x/sys
go mod edit -replace golang.org/x/text=/usr/share/gocode/src/golang.org/x/text

go mod tidy

但是,请注意,该指令要求目标包含显式文件,因此,仅当依赖项已具有显式文件或发行版打包程序已将它们添加为修补程序以支持此用例时,此操作才有效。replacego.modgo.mod


请注意,有了这些指令,您的构建将不会随着时间的推移而重现可重复:如果您更改依赖项的发行版安装版本,那么的含义将静默地更改为使用这些不同的(并且可能不兼容!)版本。replacego build

因此,我建议您不要这样做,而是使用和/或从上游或公共模块代理(例如)获取所需的特定模块版本。go getgo mod tidyproxy.golang.org

如果您担心上游篡改,请注意,默认情况下,Go项目的官方二进制命令分发 - 以及从原始源代码构建的命令 - 会自动根据 https://sum.golang.org 的可审计公共数据库验证已下载模块的校验和;但是,默认情况下,该命令的 Fedora 发行版禁止使用校验和数据库gogogo


查看完整回答
反对 回复 2022-08-24
?
慕姐4208626

TA贡献1852条经验 获得超7个赞

您可以在生成的 mod 文件中使用 replace 关键字显式定义,以引用本地模块。

replace packagename => /usr/share/gcode


查看完整回答
反对 回复 2022-08-24
?
慕沐林林

TA贡献2016条经验 获得超9个赞

将这样的 GOPATH 项目迁移到感知 Go 模块的一种方法是:


首先,使用直接依赖项手动创建 :go.mod


module github.com/gsauthof/gonzofilter


go 1.15


require (

    go.etcd.io/bbolt  v1.3.5

    golang.org/x/sys  v0.0.0-20210423185535-09eb48e85fd7

    golang.org/x/text v0.3.5

)

我从我的系统上当前的内容中获得了最低版本:


$ rpm -q golang-etcd-bbolt-devel golang-x-sys-devel golang-x-text-devel golang-bin

golang-etcd-bbolt-devel-1.3.5-2.fc33.noarch

golang-x-sys-devel-0-0.39.20210123git9b0068b.fc33.noarch

golang-x-text-devel-0.3.5-1.fc33.noarch

golang-bin-1.15.8-1.fc33.x86_64

现在的问题是,人们不能简单地告诉模块感知的Go工具在它们所在的文件系统路径下查找这些模块。/usr/share/gocode/src


有一个指令可以添加到我们的文件中,以设置单个依赖项的查找路径,例如:replacego.mod


replace (

    go.etcd.io/bbolt  => /usr/share/gocode/src/go.etcd.io/bbolt

    golang.org/x/sys  => /usr/share/gocode/src/golang.org/x/sys

    golang.org/x/text => /usr/share/gocode/src/golang.org/x/text

)

但是,静止不使用 来自 的间接依赖项,例如,包提供的依赖项依赖于。在此示例中,确实找到了,但该文件不包含任何指令。go build/usr/share/gocodegolang-x-text-develgo build/usr/share/gocode/src/golang.org/x/text/go.modreplace


因此,这将失败:


$ GOPROXY=off go build -mod=readonly

go: golang.org/x/text@v0.3.6 requires

    golang.org/x/tools@v0.0.0-20180917221912-90fa682c2a6e: module lookup disabled

       by GOPROXY=off

为了解决这个问题,我们必须为所有间接依赖项添加替换指令行。


当然,手动执行此操作既繁琐又容易出错。


因此,我们可以使用一个小的shell单行线来自动化:


我们从这个文件开始:go.mod


module github.com/gsauthof/gonzofilter


go 1.15


require (

    go.etcd.io/bbolt v1.3.5

    golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7

    golang.org/x/text v0.3.6

)


replace (

//replace-this

)

然后,以下固定点迭代添加依赖项,直到构建成功:


while true; do

    GOPROXY=off go build -mod readonly 2> t

    if [ $? -eq 1 ] && grep 'module lookup disabled' t >/dev/null; then

        x=$(grep disabled t |  tr ' \t' '\n'   | grep '@' | cut -d'@' -f1 )

        echo "Adding $x"

        sed -i "s@^\(//replace-this\)@\t$x => /usr/share/gocode/src/$x\n\1@" go.mod

        continue

    fi

    break

done

这导致此示例项目的以下 require 指令:


replace (

    go.etcd.io/bbolt => /usr/share/gocode/src/go.etcd.io/bbolt

    golang.org/x/sys => /usr/share/gocode/src/golang.org/x/sys

    golang.org/x/text => /usr/share/gocode/src/golang.org/x/text

    golang.org/x/tools => /usr/share/gocode/src/golang.org/x/tools

    github.com/yuin/goldmark => /usr/share/gocode/src/github.com/yuin/goldmark

    golang.org/x/mod => /usr/share/gocode/src/golang.org/x/mod

    golang.org/x/net => /usr/share/gocode/src/golang.org/x/net

    golang.org/x/sync => /usr/share/gocode/src/golang.org/x/sync

    golang.org/x/xerrors => /usr/share/gocode/src/golang.org/x/xerrors

    golang.org/x/crypto => /usr/share/gocode/src/golang.org/x/crypto

    golang.org/x/term => /usr/share/gocode/src/golang.org/x/term

//replace-this

)


查看完整回答
反对 回复 2022-08-24
?
qq_笑_17

TA贡献1818条经验 获得超7个赞

将 Go 指向系统范围的可用依赖项的另一种方法是利用 Go 的模块供应商支持:这意味着通过符号化地链接模块文件路径,创建最小值并使用 进行编译。vendor/modules.txt-mod vendor


因此,使用Go构建不会尝试下载任何所需的模块,而是在目录中查找它们。-mod vendorvendor/


人们可能试图创建一个指向的符号链接(所有分发包都安装在那里),但这不起作用,因为还需要另一个模块描述文件,即.vendor//usr/share/gocode/srcgolang-...-devel-mod vendorvendor/modules.txt


因此,除了一些更具体的符号链接之外,我们在使用供应商功能时还必须创建一个适当的符号链接:modules.txt


首先,创建所有子级别符号链接:


awk -vvd=wendor 'BEGIN {

    PROCINFO["sorted_in"]="@ind_str_asc";

    system("mkdir -p "vd)

}

func push_mod(pkg) {

    if (!seen[pkg]) {

        ARGV[ARGC++]="/usr/share/gocode/src/"pkg"/go.mod";

        seen[pkg]=1;

    }

    sub("/.+$", "", pkg);

    xs[pkg]=1;

}

/^require[^(]+$/ {

    push_mod($2);

    next

}

/^require/ {

    inb=1;

    next

}

/^\)/ {

    inb=0;

    next

}

inb { 

    push_mod($1);

}

END {

    for (i in xs) {

        print i;

        system("ln -sfn /usr/share/gocode/src/"i" "vd"/"i)

    }

}' go.mod

然后,要创建:vendor/modules.txt


awk -vvd=wendor 'BEGIN {

    fn=vd"/modules.txt"

}

/^require/ {

    inb=1;

    next

}

/^\)/ {

    inb=0;

    next

}

inb {

    printf("# %s %s\n## explicit\n%s\n", $1, $2, $1) > fn 

}' go.mod

在这些命令之后,对于我们的示例项目,供应商目录如下所示:


$ ls -l vendor

total 16

lrwxrwxrwx. 1 juser juser  32 2021-04-25 11:12 github.com -> /usr/share/gocode/src/github.com

lrwxrwxrwx. 1 juser juser  32 2021-04-25 11:12 go.etcd.io -> /usr/share/gocode/src/go.etcd.io

lrwxrwxrwx. 1 juser juser  32 2021-04-25 11:12 golang.org -> /usr/share/gocode/src/golang.org

-rw-r--r--. 1 juser juser 195 2021-04-25 11:13 modules.txt

$ cat vendor/modules.txt

# go.etcd.io/bbolt v1.3.5

## explicit

go.etcd.io/bbolt

# golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7

## explicit

golang.org/x/sys

# golang.org/x/text v0.3.5

## explicit

golang.org/x/text

而 是相当小的,即它不包含任何替换指令:go.mod


module github.com/gsauthof/gonzofilter


go 1.15


require (

    go.etcd.io/bbolt  v1.3.5

    golang.org/x/sys  v0.0.0-20210423185535-09eb48e85fd7

    golang.org/x/text v0.3.5

)

这足以让


GOPROXY=off go build -mod vendor

成功。


请注意,间接依赖项(如)未在 中列出,但是,它们仍然可以通过,因为我们在创建指向顶级目录的符号链接时,以传递方式遍历了从所需模块开始的所有文件。golang.org/x/toolsmodules.txtvendor/go.mod


此方案的离散魅力在于不必弄乱文件中的指令。这意味着可以保持相当通用,基本上只需要将开关添加到构建命令中即可。replacego.modgo.mod-mod vendor


查看完整回答
反对 回复 2022-08-24
  • 4 回答
  • 0 关注
  • 159 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信