diff options
Diffstat (limited to 'bitbake/lib/bb/fetch2/gomod.py')
-rw-r--r-- | bitbake/lib/bb/fetch2/gomod.py | 128 |
1 files changed, 128 insertions, 0 deletions
diff --git a/bitbake/lib/bb/fetch2/gomod.py b/bitbake/lib/bb/fetch2/gomod.py new file mode 100644 index 0000000000..fe025e367f --- /dev/null +++ b/bitbake/lib/bb/fetch2/gomod.py | |||
@@ -0,0 +1,128 @@ | |||
1 | """ | ||
2 | BitBake 'Fetch' implementation for Go modules | ||
3 | |||
4 | The gomod fetcher is used to download Go modules to the module cache from a | ||
5 | module proxy. | ||
6 | |||
7 | Example SRC_URI: | ||
8 | |||
9 | SRC_URI += "gomod://golang.org/x/net;version=v0.9.0;sha256sum=..." | ||
10 | |||
11 | Required SRC_URI parameters: | ||
12 | |||
13 | - version | ||
14 | The version of the module. | ||
15 | |||
16 | Optional SRC_URI parameters: | ||
17 | |||
18 | - mod | ||
19 | Fetch and unpack the go.mod file only instead of the complete module. | ||
20 | The go command may need to download go.mod files for many different modules | ||
21 | when computing the build list, and go.mod files are much smaller than | ||
22 | module zip files. | ||
23 | The default is "0", set mod=1 for the go.mod file only. | ||
24 | |||
25 | - sha256sum | ||
26 | The checksum of the module zip file, or the go.mod file in case of fetching | ||
27 | only the go.mod file. Alternatively, set the SRC_URI varible flag for | ||
28 | "module@version.sha256sum". | ||
29 | |||
30 | Related variables: | ||
31 | |||
32 | - GO_MOD_PROXY | ||
33 | The module proxy used by the fetcher. | ||
34 | |||
35 | - GO_MOD_CACHE_DIR | ||
36 | The directory where the module cache is located. | ||
37 | This must match the exported GOMODCACHE variable for the go command to find | ||
38 | the downloaded modules. | ||
39 | |||
40 | See the Go modules reference, https://go.dev/ref/mod, for more information | ||
41 | about the module cache, module proxies and version control systems. | ||
42 | """ | ||
43 | |||
44 | import os | ||
45 | import re | ||
46 | import shutil | ||
47 | import zipfile | ||
48 | |||
49 | import bb | ||
50 | from bb.fetch2 import FetchError | ||
51 | from bb.fetch2 import MissingParameterError | ||
52 | from bb.fetch2.wget import Wget | ||
53 | |||
54 | |||
55 | def escape(path): | ||
56 | """Escape capital letters using exclamation points.""" | ||
57 | return re.sub(r'([A-Z])', lambda m: '!' + m.group(1).lower(), path) | ||
58 | |||
59 | |||
60 | class GoMod(Wget): | ||
61 | """Class to fetch Go modules from a Go module proxy via wget""" | ||
62 | |||
63 | def supports(self, ud, d): | ||
64 | """Check to see if a given URL is for this fetcher.""" | ||
65 | return ud.type == 'gomod' | ||
66 | |||
67 | def urldata_init(self, ud, d): | ||
68 | """Set up to download the module from the module proxy. | ||
69 | |||
70 | Set up to download the module zip file to the module cache directory | ||
71 | and unpack the go.mod file (unless downloading only the go.mod file): | ||
72 | |||
73 | cache/download/<module>/@v/<version>.zip: The module zip file. | ||
74 | cache/download/<module>/@v/<version>.mod: The go.mod file. | ||
75 | """ | ||
76 | |||
77 | proxy = d.getVar('GO_MOD_PROXY') or 'proxy.golang.org' | ||
78 | moddir = d.getVar('GO_MOD_CACHE_DIR') or 'pkg/mod' | ||
79 | |||
80 | if 'version' not in ud.parm: | ||
81 | raise MissingParameterError('version', ud.url) | ||
82 | |||
83 | module = ud.host + ud.path | ||
84 | ud.parm['module'] = module | ||
85 | |||
86 | # Set URL and filename for wget download | ||
87 | path = escape(module + '/@v/' + ud.parm['version']) | ||
88 | if ud.parm.get('mod', '0') == '1': | ||
89 | path += '.mod' | ||
90 | else: | ||
91 | path += '.zip' | ||
92 | ud.parm['unpack'] = '0' | ||
93 | ud.url = bb.fetch2.encodeurl( | ||
94 | ('https', proxy, '/' + path, None, None, None)) | ||
95 | ud.parm['downloadfilename'] = path | ||
96 | |||
97 | # Set name parameter if sha256sum is set in recipe | ||
98 | name = f"{module}@{ud.parm['version']}" | ||
99 | if d.getVarFlag('SRC_URI', name + '.sha256sum'): | ||
100 | ud.parm['name'] = name | ||
101 | |||
102 | # Set subdir for unpack | ||
103 | ud.parm['subdir'] = os.path.join(moddir, 'cache/download', | ||
104 | os.path.dirname(path)) | ||
105 | |||
106 | super().urldata_init(ud, d) | ||
107 | |||
108 | def unpack(self, ud, rootdir, d): | ||
109 | """Unpack the module in the module cache.""" | ||
110 | |||
111 | # Unpack the module zip file or go.mod file | ||
112 | super().unpack(ud, rootdir, d) | ||
113 | |||
114 | if ud.localpath.endswith('.zip'): | ||
115 | # Unpack the go.mod file from the zip file | ||
116 | module = ud.parm['module'] | ||
117 | unpackdir = os.path.join(rootdir, ud.parm['subdir']) | ||
118 | name = os.path.basename(ud.localpath).rsplit('.', 1)[0] + '.mod' | ||
119 | bb.note(f"Unpacking {name} to {unpackdir}/") | ||
120 | with zipfile.ZipFile(ud.localpath) as zf: | ||
121 | with open(os.path.join(unpackdir, name), mode='wb') as mf: | ||
122 | try: | ||
123 | f = module + '@' + ud.parm['version'] + '/go.mod' | ||
124 | shutil.copyfileobj(zf.open(f), mf) | ||
125 | except KeyError: | ||
126 | # If the module does not have a go.mod file, synthesize | ||
127 | # one containing only a module statement. | ||
128 | mf.write(f'module {module}\n'.encode()) | ||