summaryrefslogtreecommitdiffstats
path: root/bitbake/lib/bb/fetch2/gomod.py
diff options
context:
space:
mode:
Diffstat (limited to 'bitbake/lib/bb/fetch2/gomod.py')
-rw-r--r--bitbake/lib/bb/fetch2/gomod.py140
1 files changed, 138 insertions, 2 deletions
diff --git a/bitbake/lib/bb/fetch2/gomod.py b/bitbake/lib/bb/fetch2/gomod.py
index fe025e367f..1b532d03ff 100644
--- a/bitbake/lib/bb/fetch2/gomod.py
+++ b/bitbake/lib/bb/fetch2/gomod.py
@@ -1,12 +1,13 @@
1""" 1"""
2BitBake 'Fetch' implementation for Go modules 2BitBake 'Fetch' implementation for Go modules
3 3
4The gomod fetcher is used to download Go modules to the module cache from a 4The gomod/gomodgit fetchers are used to download Go modules to the module cache
5module proxy. 5from a module proxy or directly from a version control repository.
6 6
7Example SRC_URI: 7Example SRC_URI:
8 8
9SRC_URI += "gomod://golang.org/x/net;version=v0.9.0;sha256sum=..." 9SRC_URI += "gomod://golang.org/x/net;version=v0.9.0;sha256sum=..."
10SRC_URI += "gomodgit://golang.org/x/net;version=v0.9.0;repo=go.googlesource.com/net;srcrev=..."
10 11
11Required SRC_URI parameters: 12Required SRC_URI parameters:
12 13
@@ -27,6 +28,23 @@ Optional SRC_URI parameters:
27 only the go.mod file. Alternatively, set the SRC_URI varible flag for 28 only the go.mod file. Alternatively, set the SRC_URI varible flag for
28 "module@version.sha256sum". 29 "module@version.sha256sum".
29 30
31- protocol
32 The method used when fetching directly from a version control repository.
33 The default is "https" for git.
34
35- repo
36 The URL when fetching directly from a version control repository. Required
37 when the URL is different from the module path.
38
39- srcrev
40 The revision identifier used when fetching directly from a version control
41 repository. Alternatively, set the SRCREV varible for "module@version".
42
43- subdir
44 The module subdirectory when fetching directly from a version control
45 repository. Required when the module is not located in the root of the
46 repository.
47
30Related variables: 48Related variables:
31 49
32- GO_MOD_PROXY 50- GO_MOD_PROXY
@@ -41,14 +59,19 @@ See the Go modules reference, https://go.dev/ref/mod, for more information
41about the module cache, module proxies and version control systems. 59about the module cache, module proxies and version control systems.
42""" 60"""
43 61
62import hashlib
44import os 63import os
45import re 64import re
46import shutil 65import shutil
66import subprocess
47import zipfile 67import zipfile
48 68
49import bb 69import bb
50from bb.fetch2 import FetchError 70from bb.fetch2 import FetchError
51from bb.fetch2 import MissingParameterError 71from bb.fetch2 import MissingParameterError
72from bb.fetch2 import runfetchcmd
73from bb.fetch2 import subprocess_setup
74from bb.fetch2.git import Git
52from bb.fetch2.wget import Wget 75from bb.fetch2.wget import Wget
53 76
54 77
@@ -126,3 +149,116 @@ class GoMod(Wget):
126 # If the module does not have a go.mod file, synthesize 149 # If the module does not have a go.mod file, synthesize
127 # one containing only a module statement. 150 # one containing only a module statement.
128 mf.write(f'module {module}\n'.encode()) 151 mf.write(f'module {module}\n'.encode())
152
153
154class GoModGit(Git):
155 """Class to fetch Go modules directly from a git repository"""
156
157 def supports(self, ud, d):
158 """Check to see if a given URL is for this fetcher."""
159 return ud.type == 'gomodgit'
160
161 def urldata_init(self, ud, d):
162 """Set up to download the module from the git repository.
163
164 Set up to download the git repository to the module cache directory and
165 unpack the module zip file and the go.mod file:
166
167 cache/vcs/<hash>: The bare git repository.
168 cache/download/<module>/@v/<version>.zip: The module zip file.
169 cache/download/<module>/@v/<version>.mod: The go.mod file.
170 """
171
172 moddir = d.getVar('GO_MOD_CACHE_DIR') or 'pkg/mod'
173
174 if 'version' not in ud.parm:
175 raise MissingParameterError('version', ud.url)
176
177 module = ud.host + ud.path
178 ud.parm['module'] = module
179
180 # Set host, path and srcrev for git download
181 if 'repo' in ud.parm:
182 repo = ud.parm['repo']
183 idx = repo.find('/')
184 if idx != -1:
185 ud.host = repo[:idx]
186 ud.path = repo[idx:]
187 else:
188 ud.host = repo
189 ud.path = ''
190 if 'protocol' not in ud.parm:
191 ud.parm['protocol'] = 'https'
192 name = f"{module}@{ud.parm['version']}"
193 ud.names = [name]
194 srcrev = d.getVar('SRCREV_' + name)
195 if srcrev:
196 if 'srcrev' not in ud.parm:
197 ud.parm['srcrev'] = srcrev
198 else:
199 if 'srcrev' in ud.parm:
200 d.setVar('SRCREV_' + name, ud.parm['srcrev'])
201 if 'branch' not in ud.parm:
202 ud.parm['nobranch'] = '1'
203
204 # Set subpath, subdir and bareclone for git unpack
205 if 'subdir' in ud.parm:
206 ud.parm['subpath'] = ud.parm['subdir']
207 key = f"git3:{ud.parm['protocol']}://{ud.host}{ud.path}".encode()
208 ud.parm['key'] = key
209 ud.parm['subdir'] = os.path.join(moddir, 'cache/vcs',
210 hashlib.sha256(key).hexdigest())
211 ud.parm['bareclone'] = '1'
212
213 super().urldata_init(ud, d)
214
215 def unpack(self, ud, rootdir, d):
216 """Unpack the module in the module cache."""
217
218 # Unpack the bare git repository
219 super().unpack(ud, rootdir, d)
220
221 moddir = d.getVar('GO_MOD_CACHE_DIR') or 'pkg/mod'
222
223 # Create the info file
224 module = ud.parm['module']
225 repodir = os.path.join(rootdir, ud.parm['subdir'])
226 with open(repodir + '.info', 'wb') as f:
227 f.write(ud.parm['key'])
228
229 # Unpack the go.mod file from the repository
230 unpackdir = os.path.join(rootdir, moddir, 'cache/download',
231 escape(module), '@v')
232 bb.utils.mkdirhier(unpackdir)
233 srcrev = ud.parm['srcrev']
234 version = ud.parm['version']
235 escaped_version = escape(version)
236 cmd = f"git ls-tree -r --name-only '{srcrev}'"
237 if 'subpath' in ud.parm:
238 cmd += f" '{ud.parm['subpath']}'"
239 files = runfetchcmd(cmd, d, workdir=repodir).split()
240 name = escaped_version + '.mod'
241 bb.note(f"Unpacking {name} to {unpackdir}/")
242 with open(os.path.join(unpackdir, name), mode='wb') as mf:
243 f = 'go.mod'
244 if 'subpath' in ud.parm:
245 f = os.path.join(ud.parm['subpath'], f)
246 if f in files:
247 cmd = ['git', 'cat-file', 'blob', srcrev + ':' + f]
248 subprocess.check_call(cmd, stdout=mf, cwd=repodir,
249 preexec_fn=subprocess_setup)
250 else:
251 # If the module does not have a go.mod file, synthesize one
252 # containing only a module statement.
253 mf.write(f'module {module}\n'.encode())
254
255 # Synthesize the module zip file from the repository
256 name = escaped_version + '.zip'
257 bb.note(f"Unpacking {name} to {unpackdir}/")
258 with zipfile.ZipFile(os.path.join(unpackdir, name), mode='w') as zf:
259 prefix = module + '@' + version + '/'
260 for f in files:
261 cmd = ['git', 'cat-file', 'blob', srcrev + ':' + f]
262 data = subprocess.check_output(cmd, cwd=repodir,
263 preexec_fn=subprocess_setup)
264 zf.writestr(prefix + f, data)