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.py128
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"""
2BitBake 'Fetch' implementation for Go modules
3
4The gomod fetcher is used to download Go modules to the module cache from a
5module proxy.
6
7Example SRC_URI:
8
9SRC_URI += "gomod://golang.org/x/net;version=v0.9.0;sha256sum=..."
10
11Required SRC_URI parameters:
12
13- version
14 The version of the module.
15
16Optional 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
30Related 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
40See the Go modules reference, https://go.dev/ref/mod, for more information
41about the module cache, module proxies and version control systems.
42"""
43
44import os
45import re
46import shutil
47import zipfile
48
49import bb
50from bb.fetch2 import FetchError
51from bb.fetch2 import MissingParameterError
52from bb.fetch2.wget import Wget
53
54
55def 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
60class 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())