diff options
Diffstat (limited to 'bitbake/lib/bb/fetch2/gomod.py')
-rw-r--r-- | bitbake/lib/bb/fetch2/gomod.py | 140 |
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 | """ |
2 | BitBake 'Fetch' implementation for Go modules | 2 | BitBake 'Fetch' implementation for Go modules |
3 | 3 | ||
4 | The gomod fetcher is used to download Go modules to the module cache from a | 4 | The gomod/gomodgit fetchers are used to download Go modules to the module cache |
5 | module proxy. | 5 | from a module proxy or directly from a version control repository. |
6 | 6 | ||
7 | Example SRC_URI: | 7 | Example SRC_URI: |
8 | 8 | ||
9 | SRC_URI += "gomod://golang.org/x/net;version=v0.9.0;sha256sum=..." | 9 | SRC_URI += "gomod://golang.org/x/net;version=v0.9.0;sha256sum=..." |
10 | SRC_URI += "gomodgit://golang.org/x/net;version=v0.9.0;repo=go.googlesource.com/net;srcrev=..." | ||
10 | 11 | ||
11 | Required SRC_URI parameters: | 12 | Required 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 | |||
30 | Related variables: | 48 | Related 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 | |||
41 | about the module cache, module proxies and version control systems. | 59 | about the module cache, module proxies and version control systems. |
42 | """ | 60 | """ |
43 | 61 | ||
62 | import hashlib | ||
44 | import os | 63 | import os |
45 | import re | 64 | import re |
46 | import shutil | 65 | import shutil |
66 | import subprocess | ||
47 | import zipfile | 67 | import zipfile |
48 | 68 | ||
49 | import bb | 69 | import bb |
50 | from bb.fetch2 import FetchError | 70 | from bb.fetch2 import FetchError |
51 | from bb.fetch2 import MissingParameterError | 71 | from bb.fetch2 import MissingParameterError |
72 | from bb.fetch2 import runfetchcmd | ||
73 | from bb.fetch2 import subprocess_setup | ||
74 | from bb.fetch2.git import Git | ||
52 | from bb.fetch2.wget import Wget | 75 | from 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 | |||
154 | class 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) | ||