summaryrefslogtreecommitdiffstats
path: root/scripts/lib
diff options
context:
space:
mode:
authorRoss Burton <ross.burton@arm.com>2025-06-27 14:48:48 +0100
committerRichard Purdie <richard.purdie@linuxfoundation.org>2025-07-01 08:49:37 +0100
commit43434a79c0ac8b0e7a7a5da8730b03af0dc17fd5 (patch)
tree53416e7e4eccf7be3782e9c7bb6fd392d1c4b4e9 /scripts/lib
parent9291f67f1e01fe58dab7c28cbc2bd443da7950dc (diff)
downloadpoky-43434a79c0ac8b0e7a7a5da8730b03af0dc17fd5.tar.gz
recipetool/create_go: proxy module fetching to go-mod-update-modules
Now that the go-mod-update-modules class exists, this Go handler can create a stub recipe and then proxy the module handling to the class. (From OE-Core rev: 0aa406d0582d32399c48dfa78f24adc75696112c) Signed-off-by: Ross Burton <ross.burton@arm.com> Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
Diffstat (limited to 'scripts/lib')
-rw-r--r--scripts/lib/recipetool/create_go.py152
1 files changed, 36 insertions, 116 deletions
diff --git a/scripts/lib/recipetool/create_go.py b/scripts/lib/recipetool/create_go.py
index 3e9fc85784..4b1fa39d13 100644
--- a/scripts/lib/recipetool/create_go.py
+++ b/scripts/lib/recipetool/create_go.py
@@ -11,17 +11,15 @@
11 11
12 12
13from recipetool.create import RecipeHandler, handle_license_vars 13from recipetool.create import RecipeHandler, handle_license_vars
14from recipetool.create import find_licenses
15 14
16import bb.utils 15import bb.utils
17import json 16import json
18import logging 17import logging
19import os 18import os
20import re 19import re
20import subprocess
21import sys 21import sys
22import tempfile 22import tempfile
23import urllib.parse
24import urllib.request
25 23
26 24
27logger = logging.getLogger('recipetool') 25logger = logging.getLogger('recipetool')
@@ -66,97 +64,6 @@ class GoRecipeHandler(RecipeHandler):
66 64
67 return bindir 65 return bindir
68 66
69 @staticmethod
70 def __unescape_path(path):
71 """Unescape capital letters using exclamation points."""
72 return re.sub(r'!([a-z])', lambda m: m.group(1).upper(), path)
73
74 @staticmethod
75 def __fold_uri(uri):
76 """Fold URI for sorting shorter module paths before longer."""
77 return uri.replace(';', ' ').replace('/', '!')
78
79 @staticmethod
80 def __go_run_cmd(cmd, cwd, d):
81 env = dict(os.environ, PATH=d.getVar('PATH'), GOMODCACHE=d.getVar('GOMODCACHE'))
82 return bb.process.run(cmd, env=env, shell=True, cwd=cwd)
83
84 def __go_mod(self, go_mod, srctree, localfilesdir, extravalues, d):
85 moddir = d.getVar('GOMODCACHE')
86
87 # List main packages and their dependencies with the go list command.
88 stdout, _ = self.__go_run_cmd(f"go list -json=Dir,Module -deps {go_mod['Module']['Path']}/...", srctree, d)
89 pkgs = json.loads('[' + stdout.replace('}\n{', '},\n{') + ']')
90
91 # Collect licenses for the dependencies.
92 licenses = set()
93 lic_files_chksum = []
94 lic_files = {}
95 for pkg in pkgs:
96 # TODO: If the package is in a subdirectory with its own license
97 # files then report those istead of the license files found in the
98 # module root directory.
99 mod = pkg.get('Module', None)
100 if not mod or mod.get('Main', False):
101 continue
102 path = os.path.relpath(mod['Dir'], moddir)
103 for lic in find_licenses(mod['Dir'], d):
104 lic_files[os.path.join(path, lic[1])] = (lic[0], lic[2])
105
106 for lic_file in lic_files:
107 licenses.add(lic_files[lic_file][0])
108 lic_files_chksum.append(
109 f'file://pkg/mod/{lic_file};md5={lic_files[lic_file][1]}')
110
111 # Collect the module cache files downloaded by the go list command as
112 # the go list command knows best what the go list command needs and it
113 # needs more files in the module cache than the go install command as
114 # it doesn't do the dependency pruning mentioned in the Go module
115 # reference, https://go.dev/ref/mod, for go 1.17 or higher.
116 src_uris = []
117 downloaddir = os.path.join(moddir, 'cache', 'download')
118 for dirpath, _, filenames in os.walk(downloaddir):
119 path, base = os.path.split(os.path.relpath(dirpath, downloaddir))
120 if base != '@v':
121 continue
122 path = self.__unescape_path(path)
123 zipver = None
124 for name in filenames:
125 ver, ext = os.path.splitext(name)
126 if ext == '.zip':
127 chksum = bb.utils.sha256_file(os.path.join(dirpath, name))
128 src_uris.append(f'gomod://{path};version={ver};sha256sum={chksum}')
129 zipver = ver
130 break
131 for name in filenames:
132 ver, ext = os.path.splitext(name)
133 if ext == '.mod' and ver != zipver:
134 chksum = bb.utils.sha256_file(os.path.join(dirpath, name))
135 src_uris.append(f'gomod://{path};version={ver};mod=1;sha256sum={chksum}')
136
137 self.__go_run_cmd("go clean -modcache", srctree, d)
138
139 licenses_basename = "{pn}-licenses.inc"
140 licenses_filename = os.path.join(localfilesdir, licenses_basename)
141 with open(licenses_filename, "w") as f:
142 f.write(f'GO_MOD_LICENSES = "{" & ".join(sorted(licenses))}"\n\n')
143 f.write('LIC_FILES_CHKSUM += "\\\n')
144 for lic in sorted(lic_files_chksum, key=self.__fold_uri):
145 f.write(' ' + lic + ' \\\n')
146 f.write('"\n')
147
148 extravalues['extrafiles'][f"../{licenses_basename}"] = licenses_filename
149
150 go_mods_basename = "{pn}-go-mods.inc"
151 go_mods_filename = os.path.join(localfilesdir, go_mods_basename)
152 with open(go_mods_filename, "w") as f:
153 f.write('SRC_URI += "\\\n')
154 for uri in sorted(src_uris, key=self.__fold_uri):
155 f.write(' ' + uri + ' \\\n')
156 f.write('"\n')
157
158 extravalues['extrafiles'][f"../{go_mods_basename}"] = go_mods_filename
159
160 def process(self, srctree, classes, lines_before, 67 def process(self, srctree, classes, lines_before,
161 lines_after, handled, extravalues): 68 lines_after, handled, extravalues):
162 69
@@ -167,37 +74,52 @@ class GoRecipeHandler(RecipeHandler):
167 if not files: 74 if not files:
168 return False 75 return False
169 76
170 d = bb.data.createCopy(tinfoil.config_data)
171 go_bindir = self.__ensure_go() 77 go_bindir = self.__ensure_go()
172 if not go_bindir: 78 if not go_bindir:
173 sys.exit(14) 79 sys.exit(14)
174 80
175 d.prependVar('PATH', '%s:' % go_bindir)
176 handled.append('buildsystem') 81 handled.append('buildsystem')
177 classes.append("go-mod") 82 classes.append("go-mod")
178 83
179 tmp_mod_dir = tempfile.mkdtemp(prefix='go-mod-') 84 # Use go-mod-update-modules to set the full SRC_URI and LICENSE
180 d.setVar('GOMODCACHE', tmp_mod_dir) 85 classes.append("go-mod-update-modules")
86 extravalues["run_tasks"] = "update_modules"
87
88 with tempfile.TemporaryDirectory(prefix="go-mod-") as tmp_mod_dir:
89 env = dict(os.environ)
90 env["PATH"] += f":{go_bindir}"
91 env['GOMODCACHE'] = tmp_mod_dir
181 92
182 stdout, _ = self.__go_run_cmd("go mod edit -json", srctree, d) 93 stdout = subprocess.check_output(["go", "mod", "edit", "-json"], cwd=srctree, env=env, text=True)
183 go_mod = json.loads(stdout) 94 go_mod = json.loads(stdout)
184 go_import = re.sub(r'/v([0-9]+)$', '', go_mod['Module']['Path']) 95 go_import = re.sub(r'/v([0-9]+)$', '', go_mod['Module']['Path'])
185 96
186 localfilesdir = tempfile.mkdtemp(prefix='recipetool-go-') 97 localfilesdir = tempfile.mkdtemp(prefix='recipetool-go-')
187 extravalues.setdefault('extrafiles', {}) 98 extravalues.setdefault('extrafiles', {})
188 99
189 # Write the ${BPN}-licenses.inc and ${BPN}-go-mods.inc files 100 # Write the stub ${BPN}-licenses.inc and ${BPN}-go-mods.inc files
190 self.__go_mod(go_mod, srctree, localfilesdir, extravalues, d) 101 basename = "{pn}-licenses.inc"
102 filename = os.path.join(localfilesdir, basename)
103 with open(filename, "w") as f:
104 f.write("# FROM RECIPETOOL\n")
105 extravalues['extrafiles'][f"../{basename}"] = filename
191 106
192 # Do generic license handling 107 basename = "{pn}-go-mods.inc"
193 handle_license_vars(srctree, lines_before, handled, extravalues, d) 108 filename = os.path.join(localfilesdir, basename)
194 self.__rewrite_lic_vars(lines_before) 109 with open(filename, "w") as f:
110 f.write("# FROM RECIPETOOL\n")
111 extravalues['extrafiles'][f"../{basename}"] = filename
195 112
196 self.__rewrite_src_uri(lines_before) 113 # Do generic license handling
114 d = bb.data.createCopy(tinfoil.config_data)
115 handle_license_vars(srctree, lines_before, handled, extravalues, d)
116 self.__rewrite_lic_vars(lines_before)
197 117
198 lines_before.append('require ${BPN}-licenses.inc') 118 self.__rewrite_src_uri(lines_before)
199 lines_before.append('require ${BPN}-go-mods.inc') 119
200 lines_before.append(f'GO_IMPORT = "{go_import}"') 120 lines_before.append('require ${BPN}-licenses.inc')
121 lines_before.append('require ${BPN}-go-mods.inc')
122 lines_before.append(f'GO_IMPORT = "{go_import}"')
201 123
202 def __update_lines_before(self, updated, newlines, lines_before): 124 def __update_lines_before(self, updated, newlines, lines_before):
203 if updated: 125 if updated:
@@ -210,10 +132,8 @@ class GoRecipeHandler(RecipeHandler):
210 return updated 132 return updated
211 133
212 def __rewrite_lic_vars(self, lines_before): 134 def __rewrite_lic_vars(self, lines_before):
213
214 def varfunc(varname, origvalue, op, newlines): 135 def varfunc(varname, origvalue, op, newlines):
215 if varname == 'LICENSE': 136 import urllib.parse
216 return ' & '.join((origvalue, '${GO_MOD_LICENSES}')), None, -1, True
217 if varname == 'LIC_FILES_CHKSUM': 137 if varname == 'LIC_FILES_CHKSUM':
218 new_licenses = [] 138 new_licenses = []
219 licenses = origvalue.split('\\') 139 licenses = origvalue.split('\\')
@@ -235,7 +155,7 @@ class GoRecipeHandler(RecipeHandler):
235 return origvalue, None, 0, True 155 return origvalue, None, 0, True
236 156
237 updated, newlines = bb.utils.edit_metadata( 157 updated, newlines = bb.utils.edit_metadata(
238 lines_before, ['LICENSE', 'LIC_FILES_CHKSUM'], varfunc) 158 lines_before, ['LIC_FILES_CHKSUM'], varfunc)
239 return self.__update_lines_before(updated, newlines, lines_before) 159 return self.__update_lines_before(updated, newlines, lines_before)
240 160
241 def __rewrite_src_uri(self, lines_before): 161 def __rewrite_src_uri(self, lines_before):