如何在 monorepo 中将 Go vanity import URL 设置为存储库的子目录?

huangapple go评论87阅读模式
英文:

How to set Go vanity import URL to repository subdirectory in a monorepo?

问题

我正在使用一个按语言组织的 monorepo,所以所有的 Go 模块都位于存储库根目录下的 go 目录中。我想设置一个自定义导入 URL,指向 go 目录而不是存储库根目录,这样导入路径就不需要包含 go/

当前的文件结构如下:

/
  go/
    module1/
    module2/

期望的导入格式如下:

import (
    "go.example.com/module1"
    "go.example.com/module2"
)

当前可能的导入格式,但不希望这样:

import (
    "go.example.com/go/module1"
    "go.example.com/go/module2"
)

根据文档go.example.com 上的 <meta> 元素的格式应为:

<meta name="go-import" content="import-prefix vcs repo-root">

所以在这种情况下,我会有:

<meta name="go-import" content="go.example.com git github.com/example/repo">

这将把 import-prefix 后面的路径转换为相对于存储库根目录的路径,这样 go.example.com/this/path 就会在存储库中查找 this/path 目录。我希望路径相对于存储库中的 go 目录而不是存储库根目录。

有没有办法告诉 go getgo.example.com 后面的路径应该相对于 github.com/example/repo/go 而不仅仅是 github.com/example/repo

英文:

I'm working with a monorepo that is organized by language at the top level, so all Go modules are located in the go directory in the repository root. I want to set up a vanity import URL that points to the go directory rather than the repository root so that the go/ does not need to be included in the import path.

Current file structure:

/
  go/
    module1/
    module2/

Desired import format:

import (
    &quot;go.example.com/module1&quot;
    &quot;go.example.com/module2&quot;
)

currently possible but not desired:

import (
    &quot;go.example.com/go/module1&quot;
    &quot;go.example.com/go/module2&quot;
)

According to the docs the format for the &lt;meta&gt; element at go.example.com should be of the form:

&lt;meta name=&quot;go-import&quot; content=&quot;import-prefix vcs repo-root&quot;&gt;

So in this case I would have:

&lt;meta name=&quot;go-import&quot; content=&quot;go.example.com git github.com/example/repo&quot;&gt;

This translates the path following the import-prefix to a path relative to the root directory of the repository, so that go.example.com/this/path looks for the this/path directory in the repo. I would like instead for the path to be relative to the go directory in the repo instead of the repo root.

Is there any way to inform go get that the paths following go.example.com should be relative to github.com/example/repo/go rather than just github.com/example/repo?

答案1

得分: 1

不直接,但有一些解决方法。

golang/go的这个问题中可以看到:

[...] 目前没有办法让HTTPS服务器指示模块偏移前缀src/go,因为这不是Go包路径的一部分。这种布局在go命令的内置git支持中是行不通的。

使用go命令的内置git支持,导入规范以仓库的URL开头,后跟所需包的路径。因此,路径必须相对于仓库根目录。使用虚拟导入路径,如果需要,可以使路径更长,但不能更短(例如example.com/pkg)。

因此,以下是没有解决方法的最短导入路径:go.example.com/go/<module>


解决方法

对于真正专注的人。

这些方法需要一些设置和额外的处理,可能仅为了导入路径的美观而不值得。

我已经找到了两种方法(以及一种可能无法与大量模块一起使用的半解决方法)。第一种是设置模块代理。第二种是创建另一个从go目录复制的存储库,并从那里导入。

go.mod中使用replace

这个方法非常简单,你可以将基本导入路径设置为任何你喜欢的内容,然后在go.mod文件中使用replace进行替换。

缺点是在处理许多相互依赖的模块时会变得复杂(如下一节中链接的文章中所讨论的)。而且感觉不太特别,负担在导入项目上进行设置,而不是被导入的项目。

Go模块代理

这篇文章(gist)很好地解释了这种方法。

go get使用GOPROXY环境变量来决定在哪里查找和解析包。基本思路是设置一个代理服务器,知道如何转换公共模块名称并从实际存储库获取相关代码,然后将该服务器的URL放入GOPROXY变量中。

对于私有模块/存储库,这种方法需要额外的注意,因为你还需要处理身份验证。

复制Git存储库

最后一种方法是将go目录的内容复制到另一个存储库中,可以使用GitHub Actions或类似工具自动化此过程。

为了保留版本标签(如果使用)和分支(尽管不包括提交哈希),你可以使用git filter-repo重写历史,使go目录实际上成为包的根目录(并且一直如此):git filter-repo --subdirectory-filter go/

然后,只需将虚拟的go-import标签设置为:

<meta name="go-import" content="go.example.com git github.com/example/repo-go">

(其中原始存储库是github.com/example/repo)。

英文:

Not directly, but there are workarounds.

From this issue in golang/go:

> [...] there is currently no way for the HTTPS server to indicate that the module is offset by the prefix src/go, since that is not a part of the Go package path. This layout is just not going to work with the go command's built-in git support.

With the go command's built-in git support, import specs start with the URL of the repository and are followed by a path to the desired package. Therefore paths must be relative to the repository root. With a vanity import path you can make the path longer if desired, but not shorter (e.g. example.com/pkg).

So the following is the shortest possible import path without a workaround: go.example.com/go/&lt;module&gt;.


Workarounds

For the truly dedicated.

These involve a bit of setup and extra handling and might not be worth it just for the aesthetics of the import path.

There are two approaches I've worked out (and one semi-solution that probably won't work with a large number of modules). The first is setting up a module proxy. The second is creating another repo that copies from the go directory and importing from there.

Use replace in go.mod

This one is pretty simple, you can make the base import path anything you like and just replace it in the go.mod file.

Downside is this gets complicated to manage with many interdependent modules (as discussed in the linked article in the next section). Also feels less special and the burden is on the importing project to set up rather than the imported project.

Go Module Proxy

This article(gist) does a nice job explaining the approach.

go get uses the GOPROXY environment variable to decide where to look to find and resolve packages. The basic idea is to set up a proxy server that knows how to translate the public module name and get the relevant code from the actual repo, then put the URL of that server in the GOPROXY variable.

Extra care is needed with this approach for private modules/repositories as you'll have to handle authentication as well.

Copy Git Repository

The final approach is to copy the contents of the go directory to another repo, which can be automated with GitHub Actions or similar.

To preserve version tags (if used) and branches (although not commit hashes), you can use git filter-repo to rewrite history so that the go directory is actually the package root (and always has been): git filter-repo --subdirectory-filter go/.

Then just set the vanity go-import tag to:

&lt;meta name=&quot;go-import&quot; content=&quot;go.example.com git github.com/example/repo-go&quot;&gt;

(where the original repo was github.com/example/repo).

huangapple
  • 本文由 发表于 2022年5月24日 10:14:05
  • 转载请务必保留本文链接:https://go.coder-hub.com/72356519.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定