英文:
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 get
,go.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 (
"go.example.com/module1"
"go.example.com/module2"
)
currently possible but not desired:
import (
"go.example.com/go/module1"
"go.example.com/go/module2"
)
According to the docs the format for the <meta>
element at go.example.com
should be of the form:
<meta name="go-import" content="import-prefix vcs repo-root">
So in this case I would have:
<meta name="go-import" content="go.example.com git github.com/example/repo">
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模块代理
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/<module>
.
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:
<meta name="go-import" content="go.example.com git github.com/example/repo-go">
(where the original repo was github.com/example/repo
).
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论