summaryrefslogtreecommitdiffstats
path: root/meta/lib/oe/package_manager/ipk
diff options
context:
space:
mode:
Diffstat (limited to 'meta/lib/oe/package_manager/ipk')
-rw-r--r--meta/lib/oe/package_manager/ipk/__init__.py438
-rw-r--r--meta/lib/oe/package_manager/ipk/manifest.py76
-rw-r--r--meta/lib/oe/package_manager/ipk/rootfs.py352
-rw-r--r--meta/lib/oe/package_manager/ipk/sdk.py113
4 files changed, 0 insertions, 979 deletions
diff --git a/meta/lib/oe/package_manager/ipk/__init__.py b/meta/lib/oe/package_manager/ipk/__init__.py
deleted file mode 100644
index 4794f31f88..0000000000
--- a/meta/lib/oe/package_manager/ipk/__init__.py
+++ /dev/null
@@ -1,438 +0,0 @@
1#
2# Copyright OpenEmbedded Contributors
3#
4# SPDX-License-Identifier: GPL-2.0-only
5#
6
7import re
8import shutil
9import subprocess
10from oe.package_manager import *
11from oe.package_manager.common_deb_ipk import OpkgDpkgPM
12
13class OpkgIndexer(Indexer):
14 def write_index(self):
15 arch_vars = ["ALL_MULTILIB_PACKAGE_ARCHS",
16 "SDK_PACKAGE_ARCHS",
17 ]
18
19 opkg_index_cmd = bb.utils.which(os.getenv('PATH'), "opkg-make-index")
20 opkg_index_cmd_extra_params = self.d.getVar('OPKG_MAKE_INDEX_EXTRA_PARAMS') or ""
21 if self.d.getVar('PACKAGE_FEED_SIGN') == '1':
22 signer = get_signer(self.d, self.d.getVar('PACKAGE_FEED_GPG_BACKEND'))
23 else:
24 signer = None
25
26 if not os.path.exists(os.path.join(self.deploy_dir, "Packages")):
27 open(os.path.join(self.deploy_dir, "Packages"), "w").close()
28
29 index_cmds = set()
30 index_sign_files = set()
31 for arch_var in arch_vars:
32 archs = self.d.getVar(arch_var)
33 if archs is None:
34 continue
35
36 for arch in archs.split():
37 pkgs_dir = os.path.join(self.deploy_dir, arch)
38 pkgs_file = os.path.join(pkgs_dir, "Packages")
39
40 if not os.path.isdir(pkgs_dir):
41 continue
42
43 if not os.path.exists(pkgs_file):
44 open(pkgs_file, "w").close()
45
46 index_cmds.add('%s --checksum md5 --checksum sha256 -r %s -p %s -m %s %s' %
47 (opkg_index_cmd, pkgs_file, pkgs_file, pkgs_dir, opkg_index_cmd_extra_params))
48
49 index_sign_files.add(pkgs_file)
50
51 if len(index_cmds) == 0:
52 bb.note("There are no packages in %s!" % self.deploy_dir)
53 return
54
55 oe.utils.multiprocess_launch(create_index, index_cmds, self.d)
56
57 if signer:
58 feed_sig_type = self.d.getVar('PACKAGE_FEED_GPG_SIGNATURE_TYPE')
59 is_ascii_sig = (feed_sig_type.upper() != "BIN")
60 for f in index_sign_files:
61 signer.detach_sign(f,
62 self.d.getVar('PACKAGE_FEED_GPG_NAME'),
63 self.d.getVar('PACKAGE_FEED_GPG_PASSPHRASE_FILE'),
64 armor=is_ascii_sig)
65
66class PMPkgsList(PkgsList):
67 def __init__(self, d, rootfs_dir):
68 super(PMPkgsList, self).__init__(d, rootfs_dir)
69 config_file = d.getVar("IPKGCONF_TARGET")
70
71 self.opkg_cmd = bb.utils.which(os.getenv('PATH'), "opkg")
72 self.opkg_args = "-f %s -o %s " % (config_file, rootfs_dir)
73 self.opkg_args += self.d.getVar("OPKG_ARGS")
74
75 def list_pkgs(self, format=None):
76 cmd = "%s %s status" % (self.opkg_cmd, self.opkg_args)
77
78 # opkg returns success even when it printed some
79 # "Collected errors:" report to stderr. Mixing stderr into
80 # stdout then leads to random failures later on when
81 # parsing the output. To avoid this we need to collect both
82 # output streams separately and check for empty stderr.
83 p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
84 cmd_output, cmd_stderr = p.communicate()
85 cmd_output = cmd_output.decode("utf-8")
86 cmd_stderr = cmd_stderr.decode("utf-8")
87 if p.returncode or cmd_stderr:
88 bb.fatal("Cannot get the installed packages list. Command '%s' "
89 "returned %d and stderr:\n%s" % (cmd, p.returncode, cmd_stderr))
90
91 return opkg_query(cmd_output)
92
93
94class OpkgPM(OpkgDpkgPM):
95 def __init__(self, d, target_rootfs, config_file, archs, task_name='target', ipk_repo_workdir="oe-rootfs-repo", filterbydependencies=True, prepare_index=True):
96 super(OpkgPM, self).__init__(d, target_rootfs)
97
98 self.config_file = config_file
99 self.pkg_archs = archs
100 self.task_name = task_name
101
102 self.deploy_dir = oe.path.join(self.d.getVar('WORKDIR'), ipk_repo_workdir)
103 self.deploy_lock_file = os.path.join(self.deploy_dir, "deploy.lock")
104 self.opkg_cmd = bb.utils.which(os.getenv('PATH'), "opkg")
105 self.opkg_args = "--volatile-cache -f %s -t %s -o %s " % (self.config_file, self.d.expand('${T}/ipktemp/') ,target_rootfs)
106 self.opkg_args += self.d.getVar("OPKG_ARGS")
107
108 if prepare_index:
109 create_packages_dir(self.d, self.deploy_dir, d.getVar("DEPLOY_DIR_IPK"), "package_write_ipk", filterbydependencies)
110
111 self.opkg_dir = oe.path.join(target_rootfs, self.d.getVar('OPKGLIBDIR'), "opkg")
112 bb.utils.mkdirhier(self.opkg_dir)
113
114 self.saved_opkg_dir = self.d.expand('${T}/saved/%s' % self.task_name)
115 if not os.path.exists(self.d.expand('${T}/saved')):
116 bb.utils.mkdirhier(self.d.expand('${T}/saved'))
117
118 self.from_feeds = (self.d.getVar('BUILD_IMAGES_FROM_FEEDS') or "") == "1"
119 if self.from_feeds:
120 self._create_custom_config()
121 else:
122 self._create_config()
123
124 self.indexer = OpkgIndexer(self.d, self.deploy_dir)
125
126 def mark_packages(self, status_tag, packages=None):
127 """
128 This function will change a package's status in /var/lib/opkg/status file.
129 If 'packages' is None then the new_status will be applied to all
130 packages
131 """
132 status_file = os.path.join(self.opkg_dir, "status")
133
134 with open(status_file, "r") as sf:
135 with open(status_file + ".tmp", "w+") as tmp_sf:
136 if packages is None:
137 tmp_sf.write(re.sub(r"Package: (.*?)\n((?:[^\n]+\n)*?)Status: (.*)(?:unpacked|installed)",
138 r"Package: \1\n\2Status: \3%s" % status_tag,
139 sf.read()))
140 else:
141 if type(packages).__name__ != "list":
142 raise TypeError("'packages' should be a list object")
143
144 status = sf.read()
145 for pkg in packages:
146 status = re.sub(r"Package: %s\n((?:[^\n]+\n)*?)Status: (.*)(?:unpacked|installed)" % pkg,
147 r"Package: %s\n\1Status: \2%s" % (pkg, status_tag),
148 status)
149
150 tmp_sf.write(status)
151
152 bb.utils.rename(status_file + ".tmp", status_file)
153
154 def _create_custom_config(self):
155 bb.note("Building from feeds activated!")
156
157 with open(self.config_file, "w+") as config_file:
158 priority = 1
159 for arch in self.pkg_archs.split():
160 config_file.write("arch %s %d\n" % (arch, priority))
161 priority += 5
162
163 for line in (self.d.getVar('IPK_FEED_URIS') or "").split():
164 feed_match = re.match(r"^[ \t]*(.*)##([^ \t]*)[ \t]*$", line)
165
166 if feed_match is not None:
167 feed_name = feed_match.group(1)
168 feed_uri = feed_match.group(2)
169
170 bb.note("Add %s feed with URL %s" % (feed_name, feed_uri))
171
172 config_file.write("src/gz %s %s\n" % (feed_name, feed_uri))
173
174 """
175 Allow to use package deploy directory contents as quick devel-testing
176 feed. This creates individual feed configs for each arch subdir of those
177 specified as compatible for the current machine.
178 NOTE: Development-helper feature, NOT a full-fledged feed.
179 """
180 if (self.d.getVar('FEED_DEPLOYDIR_BASE_URI') or "") != "":
181 for arch in self.pkg_archs.split():
182 cfg_file_name = oe.path.join(self.target_rootfs,
183 self.d.getVar("sysconfdir"),
184 "opkg",
185 "local-%s-feed.conf" % arch)
186
187 with open(cfg_file_name, "w+") as cfg_file:
188 cfg_file.write("src/gz local-%s %s/%s" %
189 (arch,
190 self.d.getVar('FEED_DEPLOYDIR_BASE_URI'),
191 arch))
192
193 if self.d.getVar('OPKGLIBDIR') != '/var/lib':
194 # There is no command line option for this anymore, we need to add
195 # info_dir and status_file to config file, if OPKGLIBDIR doesn't have
196 # the default value of "/var/lib" as defined in opkg:
197 # libopkg/opkg_conf.h:#define OPKG_CONF_DEFAULT_LISTS_DIR VARDIR "/lib/opkg/lists"
198 # libopkg/opkg_conf.h:#define OPKG_CONF_DEFAULT_INFO_DIR VARDIR "/lib/opkg/info"
199 # libopkg/opkg_conf.h:#define OPKG_CONF_DEFAULT_STATUS_FILE VARDIR "/lib/opkg/status"
200 cfg_file.write("option info_dir %s\n" % os.path.join(self.d.getVar('OPKGLIBDIR'), 'opkg', 'info'))
201 cfg_file.write("option lists_dir %s\n" % os.path.join(self.d.getVar('OPKGLIBDIR'), 'opkg', 'lists'))
202 cfg_file.write("option status_file %s\n" % os.path.join(self.d.getVar('OPKGLIBDIR'), 'opkg', 'status'))
203
204
205 def _create_config(self):
206 with open(self.config_file, "w+") as config_file:
207 priority = 1
208 for arch in self.pkg_archs.split():
209 config_file.write("arch %s %d\n" % (arch, priority))
210 priority += 5
211
212 config_file.write("src oe file:%s\n" % self.deploy_dir)
213
214 for arch in self.pkg_archs.split():
215 pkgs_dir = os.path.join(self.deploy_dir, arch)
216 if os.path.isdir(pkgs_dir):
217 config_file.write("src oe-%s file:%s\n" %
218 (arch, pkgs_dir))
219
220 if self.d.getVar('OPKGLIBDIR') != '/var/lib':
221 # There is no command line option for this anymore, we need to add
222 # info_dir and status_file to config file, if OPKGLIBDIR doesn't have
223 # the default value of "/var/lib" as defined in opkg:
224 # libopkg/opkg_conf.h:#define OPKG_CONF_DEFAULT_LISTS_DIR VARDIR "/lib/opkg/lists"
225 # libopkg/opkg_conf.h:#define OPKG_CONF_DEFAULT_INFO_DIR VARDIR "/lib/opkg/info"
226 # libopkg/opkg_conf.h:#define OPKG_CONF_DEFAULT_STATUS_FILE VARDIR "/lib/opkg/status"
227 config_file.write("option info_dir %s\n" % os.path.join(self.d.getVar('OPKGLIBDIR'), 'opkg', 'info'))
228 config_file.write("option lists_dir %s\n" % os.path.join(self.d.getVar('OPKGLIBDIR'), 'opkg', 'lists'))
229 config_file.write("option status_file %s\n" % os.path.join(self.d.getVar('OPKGLIBDIR'), 'opkg', 'status'))
230
231 def insert_feeds_uris(self, feed_uris, feed_base_paths, feed_archs):
232 if feed_uris == "":
233 return
234
235 rootfs_config = os.path.join('%s/etc/opkg/base-feeds.conf'
236 % self.target_rootfs)
237
238 os.makedirs('%s/etc/opkg' % self.target_rootfs, exist_ok=True)
239
240 feed_uris = self.construct_uris(feed_uris.split(), feed_base_paths.split())
241 archs = self.pkg_archs.split() if feed_archs is None else feed_archs.split()
242
243 with open(rootfs_config, "w+") as config_file:
244 uri_iterator = 0
245 for uri in feed_uris:
246 if archs:
247 for arch in archs:
248 if (feed_archs is None) and (not os.path.exists(oe.path.join(self.deploy_dir, arch))):
249 continue
250 bb.note('Adding opkg feed url-%s-%d (%s)' %
251 (arch, uri_iterator, uri))
252 config_file.write("src/gz uri-%s-%d %s/%s\n" %
253 (arch, uri_iterator, uri, arch))
254 else:
255 bb.note('Adding opkg feed url-%d (%s)' %
256 (uri_iterator, uri))
257 config_file.write("src/gz uri-%d %s\n" %
258 (uri_iterator, uri))
259
260 uri_iterator += 1
261
262 def update(self):
263 self.deploy_dir_lock()
264
265 cmd = "%s %s update" % (self.opkg_cmd, self.opkg_args)
266
267 try:
268 subprocess.check_output(cmd.split(), stderr=subprocess.STDOUT)
269 except subprocess.CalledProcessError as e:
270 self.deploy_dir_unlock()
271 bb.fatal("Unable to update the package index files. Command '%s' "
272 "returned %d:\n%s" % (cmd, e.returncode, e.output.decode("utf-8")))
273
274 self.deploy_dir_unlock()
275
276 def install(self, pkgs, attempt_only=False, hard_depends_only=False):
277 if not pkgs:
278 return
279
280 cmd = "%s %s" % (self.opkg_cmd, self.opkg_args)
281 for exclude in (self.d.getVar("PACKAGE_EXCLUDE") or "").split():
282 cmd += " --add-exclude %s" % exclude
283 for bad_recommendation in (self.d.getVar("BAD_RECOMMENDATIONS") or "").split():
284 cmd += " --add-ignore-recommends %s" % bad_recommendation
285 if hard_depends_only:
286 cmd += " --no-install-recommends"
287 cmd += " install "
288 cmd += " ".join(pkgs)
289
290 os.environ['D'] = self.target_rootfs
291 os.environ['OFFLINE_ROOT'] = self.target_rootfs
292 os.environ['IPKG_OFFLINE_ROOT'] = self.target_rootfs
293 os.environ['OPKG_OFFLINE_ROOT'] = self.target_rootfs
294 os.environ['INTERCEPT_DIR'] = self.intercepts_dir
295 os.environ['NATIVE_ROOT'] = self.d.getVar('STAGING_DIR_NATIVE')
296
297 try:
298 bb.note("Installing the following packages: %s" % ' '.join(pkgs))
299 bb.note(cmd)
300 output = subprocess.check_output(cmd.split(), stderr=subprocess.STDOUT).decode("utf-8")
301 bb.note(output)
302 failed_pkgs = []
303 for line in output.split('\n'):
304 if line.endswith("configuration required on target."):
305 bb.warn(line)
306 failed_pkgs.append(line.split(".")[0])
307 if failed_pkgs:
308 failed_postinsts_abort(failed_pkgs, self.d.expand("${T}/log.do_${BB_CURRENTTASK}"))
309 except subprocess.CalledProcessError as e:
310 e_output = e.output.decode("utf-8")
311 extra_info = ""
312 unmatched_pkgs = []
313 for e_line in e_output.split('\n'):
314 if "error: opkg_solver_install: No candidates to install" in e_line:
315 unmatched_pkg = re.search(r"error: opkg_solver_install: No candidates to install ([a-z0-9+\-\._]+)", e_line).group(1)
316 unmatched_pkgs.append(unmatched_pkg)
317 elif "error: opkg_prepare_url_for_install: Couldn't find anything to satisfy" in e_line:
318 unmatched_pkg = re.search(r"error: opkg_prepare_url_for_install: Couldn't find anything to satisfy '([a-z0-9+\-\._]+)'", e_line).group(1)
319 unmatched_pkgs.append(unmatched_pkg)
320 for pkg in unmatched_pkgs:
321 extra_info += self.get_missing_pkg_reason(pkg)
322 (bb.fatal, bb.warn)[attempt_only]("Unable to install packages. "
323 "Command '%s' returned %d:\n%s%s" %
324 (cmd, e.returncode, e_output, extra_info))
325
326 def remove(self, pkgs, with_dependencies=True):
327 if not pkgs:
328 return
329
330 if with_dependencies:
331 cmd = "%s %s --force-remove --force-removal-of-dependent-packages remove %s" % \
332 (self.opkg_cmd, self.opkg_args, ' '.join(pkgs))
333 else:
334 cmd = "%s %s --force-depends remove %s" % \
335 (self.opkg_cmd, self.opkg_args, ' '.join(pkgs))
336
337 try:
338 bb.note(cmd)
339 output = subprocess.check_output(cmd.split(), stderr=subprocess.STDOUT).decode("utf-8")
340 bb.note(output)
341 except subprocess.CalledProcessError as e:
342 bb.fatal("Unable to remove packages. Command '%s' "
343 "returned %d:\n%s" % (e.cmd, e.returncode, e.output.decode("utf-8")))
344
345 def write_index(self):
346 self.deploy_dir_lock()
347
348 result = self.indexer.write_index()
349
350 self.deploy_dir_unlock()
351
352 if result is not None:
353 bb.fatal(result)
354
355 def remove_packaging_data(self):
356 cachedir = oe.path.join(self.target_rootfs, self.d.getVar("localstatedir"), "cache", "opkg")
357 bb.utils.remove(self.opkg_dir, True)
358 bb.utils.remove(cachedir, True)
359
360 def remove_lists(self):
361 if not self.from_feeds:
362 bb.utils.remove(os.path.join(self.opkg_dir, "lists"), True)
363
364 def list_installed(self):
365 return PMPkgsList(self.d, self.target_rootfs).list_pkgs()
366
367 def dummy_install(self, pkgs):
368 """
369 The following function dummy installs pkgs and returns the log of output.
370 """
371 if len(pkgs) == 0:
372 return
373
374 # Create an temp dir as opkg root for dummy installation
375 temp_rootfs = self.d.expand('${T}/opkg')
376 opkg_lib_dir = self.d.getVar('OPKGLIBDIR')
377 if opkg_lib_dir[0] == "/":
378 opkg_lib_dir = opkg_lib_dir[1:]
379 temp_opkg_dir = os.path.join(temp_rootfs, opkg_lib_dir, 'opkg')
380 bb.utils.mkdirhier(temp_opkg_dir)
381
382 opkg_args = "-f %s -o %s " % (self.config_file, temp_rootfs)
383 opkg_args += self.d.getVar("OPKG_ARGS")
384
385 cmd = "%s %s update" % (self.opkg_cmd, opkg_args)
386 try:
387 subprocess.check_output(cmd, stderr=subprocess.STDOUT, shell=True)
388 except subprocess.CalledProcessError as e:
389 bb.fatal("Unable to update. Command '%s' "
390 "returned %d:\n%s" % (cmd, e.returncode, e.output.decode("utf-8")))
391
392 # Dummy installation
393 cmd = "%s %s --noaction install %s " % (self.opkg_cmd,
394 opkg_args,
395 ' '.join(pkgs))
396 proc = subprocess.run(cmd, capture_output=True, encoding="utf-8", shell=True)
397 if proc.returncode:
398 bb.fatal("Unable to dummy install packages. Command '%s' "
399 "returned %d:\n%s" % (cmd, proc.returncode, proc.stderr))
400 elif proc.stderr:
401 bb.note("Command '%s' returned stderr: %s" % (cmd, proc.stderr))
402
403 bb.utils.remove(temp_rootfs, True)
404
405 return proc.stdout
406
407 def backup_packaging_data(self):
408 # Save the opkglib for increment ipk image generation
409 if os.path.exists(self.saved_opkg_dir):
410 bb.utils.remove(self.saved_opkg_dir, True)
411 shutil.copytree(self.opkg_dir,
412 self.saved_opkg_dir,
413 symlinks=True)
414
415 def recover_packaging_data(self):
416 # Move the opkglib back
417 if os.path.exists(self.saved_opkg_dir):
418 if os.path.exists(self.opkg_dir):
419 bb.utils.remove(self.opkg_dir, True)
420
421 bb.note('Recover packaging data')
422 shutil.copytree(self.saved_opkg_dir,
423 self.opkg_dir,
424 symlinks=True)
425
426 def package_info(self, pkg):
427 """
428 Returns a dictionary with the package info.
429 """
430 cmd = "%s %s info %s" % (self.opkg_cmd, self.opkg_args, pkg)
431 pkg_info = self._common_package_info(cmd)
432
433 pkg_arch = pkg_info[pkg]["arch"]
434 pkg_filename = pkg_info[pkg]["filename"]
435 pkg_info[pkg]["filepath"] = \
436 os.path.join(self.deploy_dir, pkg_arch, pkg_filename)
437
438 return pkg_info
diff --git a/meta/lib/oe/package_manager/ipk/manifest.py b/meta/lib/oe/package_manager/ipk/manifest.py
deleted file mode 100644
index 3549d7428d..0000000000
--- a/meta/lib/oe/package_manager/ipk/manifest.py
+++ /dev/null
@@ -1,76 +0,0 @@
1#
2# Copyright OpenEmbedded Contributors
3#
4# SPDX-License-Identifier: GPL-2.0-only
5#
6
7from oe.manifest import Manifest
8import re
9
10class PkgManifest(Manifest):
11 """
12 Returns a dictionary object with mip and mlp packages.
13 """
14 def _split_multilib(self, pkg_list):
15 pkgs = dict()
16
17 for pkg in pkg_list.split():
18 pkg_type = self.PKG_TYPE_MUST_INSTALL
19
20 ml_variants = self.d.getVar('MULTILIB_VARIANTS').split()
21
22 for ml_variant in ml_variants:
23 if pkg.startswith(ml_variant + '-'):
24 pkg_type = self.PKG_TYPE_MULTILIB
25
26 if not pkg_type in pkgs:
27 pkgs[pkg_type] = pkg
28 else:
29 pkgs[pkg_type] += " " + pkg
30
31 return pkgs
32
33 def create_initial(self):
34 pkgs = dict()
35
36 with open(self.initial_manifest, "w+") as manifest:
37 manifest.write(self.initial_manifest_file_header)
38
39 for var in self.var_maps[self.manifest_type]:
40 if var in self.vars_to_split:
41 split_pkgs = self._split_multilib(self.d.getVar(var))
42 if split_pkgs is not None:
43 pkgs = dict(list(pkgs.items()) + list(split_pkgs.items()))
44 else:
45 pkg_list = self.d.getVar(var)
46 if pkg_list is not None:
47 pkgs[self.var_maps[self.manifest_type][var]] = self.d.getVar(var)
48
49 for pkg_type in sorted(pkgs):
50 for pkg in sorted(pkgs[pkg_type].split()):
51 manifest.write("%s,%s\n" % (pkg_type, pkg))
52
53 def create_final(self):
54 pass
55
56 def create_full(self, pm):
57 if not os.path.exists(self.initial_manifest):
58 self.create_initial()
59
60 initial_manifest = self.parse_initial_manifest()
61 pkgs_to_install = list()
62 for pkg_type in initial_manifest:
63 pkgs_to_install += initial_manifest[pkg_type]
64 if len(pkgs_to_install) == 0:
65 return
66
67 output = pm.dummy_install(pkgs_to_install)
68
69 with open(self.full_manifest, 'w+') as manifest:
70 pkg_re = re.compile('^Installing ([^ ]+) [^ ].*')
71 for line in set(output.split('\n')):
72 m = pkg_re.match(line)
73 if m:
74 manifest.write(m.group(1) + '\n')
75
76 return
diff --git a/meta/lib/oe/package_manager/ipk/rootfs.py b/meta/lib/oe/package_manager/ipk/rootfs.py
deleted file mode 100644
index ba93eb62ea..0000000000
--- a/meta/lib/oe/package_manager/ipk/rootfs.py
+++ /dev/null
@@ -1,352 +0,0 @@
1#
2# Copyright OpenEmbedded Contributors
3#
4# SPDX-License-Identifier: GPL-2.0-only
5#
6
7import re
8import filecmp
9import shutil
10from oe.rootfs import Rootfs
11from oe.manifest import Manifest
12from oe.utils import execute_pre_post_process
13from oe.package_manager.ipk.manifest import PkgManifest
14from oe.package_manager.ipk import OpkgPM
15
16class DpkgOpkgRootfs(Rootfs):
17 def __init__(self, d, progress_reporter=None, logcatcher=None):
18 super(DpkgOpkgRootfs, self).__init__(d, progress_reporter, logcatcher)
19
20 def _get_pkgs_postinsts(self, status_file):
21 def _get_pkg_depends_list(pkg_depends):
22 pkg_depends_list = []
23 # filter version requirements like libc (>= 1.1)
24 for dep in pkg_depends.split(', '):
25 m_dep = re.match(r"^(.*) \(.*\)$", dep)
26 if m_dep:
27 dep = m_dep.group(1)
28 pkg_depends_list.append(dep)
29
30 return pkg_depends_list
31
32 pkgs = {}
33 pkg_name = ""
34 pkg_status_match = False
35 pkg_depends = ""
36
37 with open(status_file) as status:
38 data = status.read()
39 status.close()
40 for line in data.split('\n'):
41 m_pkg = re.match(r"^Package: (.*)", line)
42 m_status = re.match(r"^Status:.*unpacked", line)
43 m_depends = re.match(r"^Depends: (.*)", line)
44
45 #Only one of m_pkg, m_status or m_depends is not None at time
46 #If m_pkg is not None, we started a new package
47 if m_pkg is not None:
48 #Get Package name
49 pkg_name = m_pkg.group(1)
50 #Make sure we reset other variables
51 pkg_status_match = False
52 pkg_depends = ""
53 elif m_status is not None:
54 #New status matched
55 pkg_status_match = True
56 elif m_depends is not None:
57 #New depends macthed
58 pkg_depends = m_depends.group(1)
59 else:
60 pass
61
62 #Now check if we can process package depends and postinst
63 if "" != pkg_name and pkg_status_match:
64 pkgs[pkg_name] = _get_pkg_depends_list(pkg_depends)
65 else:
66 #Not enough information
67 pass
68
69 # remove package dependencies not in postinsts
70 pkg_names = list(pkgs.keys())
71 for pkg_name in pkg_names:
72 deps = pkgs[pkg_name][:]
73
74 for d in deps:
75 if d not in pkg_names:
76 pkgs[pkg_name].remove(d)
77
78 return pkgs
79
80 def _get_delayed_postinsts_common(self, status_file):
81 def _dep_resolve(graph, node, resolved, seen):
82 seen.append(node)
83
84 for edge in graph[node]:
85 if edge not in resolved:
86 if edge in seen:
87 raise RuntimeError("Packages %s and %s have " \
88 "a circular dependency in postinsts scripts." \
89 % (node, edge))
90 _dep_resolve(graph, edge, resolved, seen)
91
92 resolved.append(node)
93
94 pkg_list = []
95
96 pkgs = None
97 if not self.d.getVar('PACKAGE_INSTALL').strip():
98 bb.note("Building empty image")
99 else:
100 pkgs = self._get_pkgs_postinsts(status_file)
101 if pkgs:
102 root = "__packagegroup_postinst__"
103 pkgs[root] = list(pkgs.keys())
104 _dep_resolve(pkgs, root, pkg_list, [])
105 pkg_list.remove(root)
106
107 if len(pkg_list) == 0:
108 return None
109
110 return pkg_list
111
112 def _save_postinsts_common(self, dst_postinst_dir, src_postinst_dir):
113 if bb.utils.contains("IMAGE_FEATURES", "package-management",
114 True, False, self.d):
115 return
116 num = 0
117 for p in self._get_delayed_postinsts():
118 bb.utils.mkdirhier(dst_postinst_dir)
119
120 if os.path.exists(os.path.join(src_postinst_dir, p + ".postinst")):
121 shutil.copy(os.path.join(src_postinst_dir, p + ".postinst"),
122 os.path.join(dst_postinst_dir, "%03d-%s" % (num, p)))
123
124 num += 1
125
126class PkgRootfs(DpkgOpkgRootfs):
127 def __init__(self, d, manifest_dir, progress_reporter=None, logcatcher=None):
128 super(PkgRootfs, self).__init__(d, progress_reporter, logcatcher)
129 self.log_check_regex = '(exit 1|Collected errors)'
130
131 self.manifest = PkgManifest(d, manifest_dir)
132 self.opkg_conf = self.d.getVar("IPKGCONF_TARGET")
133 self.pkg_archs = self.d.getVar("ALL_MULTILIB_PACKAGE_ARCHS")
134
135 self.inc_opkg_image_gen = self.d.getVar('INC_IPK_IMAGE_GEN') or ""
136 if self._remove_old_rootfs():
137 bb.utils.remove(self.image_rootfs, True)
138 self.pm = OpkgPM(d,
139 self.image_rootfs,
140 self.opkg_conf,
141 self.pkg_archs)
142 else:
143 self.pm = OpkgPM(d,
144 self.image_rootfs,
145 self.opkg_conf,
146 self.pkg_archs)
147 self.pm.recover_packaging_data()
148
149 bb.utils.remove(self.d.getVar('MULTILIB_TEMP_ROOTFS'), True)
150 '''
151 Compare two files with the same key twice to see if they are equal.
152 If they are not equal, it means they are duplicated and come from
153 different packages.
154 '''
155 def _file_equal(self, key, f1, f2):
156 if filecmp.cmp(f1, f2):
157 return True
158 # Not equal
159 return False
160
161 """
162 This function was reused from the old implementation.
163 See commit: "image.bbclass: Added variables for multilib support." by
164 Lianhao Lu.
165 """
166 def _multilib_sanity_test(self, dirs):
167
168 allow_replace = "|".join((self.d.getVar("MULTILIBRE_ALLOW_REP") or "").split())
169 if allow_replace is None:
170 allow_replace = ""
171
172 allow_rep = re.compile(re.sub(r"\|$", r"", allow_replace))
173 error_prompt = "Multilib check error:"
174
175 files = {}
176 for dir in dirs:
177 for root, subfolders, subfiles in os.walk(dir):
178 for file in subfiles:
179 item = os.path.join(root, file)
180 key = str(os.path.join("/", os.path.relpath(item, dir)))
181
182 valid = True
183 if key in files:
184 #check whether the file is allow to replace
185 if allow_rep.match(key):
186 valid = True
187 else:
188 if os.path.exists(files[key]) and \
189 os.path.exists(item) and \
190 not self._file_equal(key, files[key], item):
191 valid = False
192 bb.fatal("%s duplicate files %s %s is not the same\n" %
193 (error_prompt, item, files[key]))
194
195 #pass the check, add to list
196 if valid:
197 files[key] = item
198
199 def _multilib_test_install(self, pkgs):
200 ml_temp = self.d.getVar("MULTILIB_TEMP_ROOTFS")
201 bb.utils.mkdirhier(ml_temp)
202
203 dirs = [self.image_rootfs]
204
205 for variant in self.d.getVar("MULTILIB_VARIANTS").split():
206 ml_target_rootfs = os.path.join(ml_temp, variant)
207
208 bb.utils.remove(ml_target_rootfs, True)
209
210 ml_opkg_conf = os.path.join(ml_temp,
211 variant + "-" + os.path.basename(self.opkg_conf))
212
213 ml_pm = OpkgPM(self.d, ml_target_rootfs, ml_opkg_conf, self.pkg_archs, prepare_index=False)
214
215 ml_pm.update()
216 ml_pm.install(pkgs)
217
218 dirs.append(ml_target_rootfs)
219
220 self._multilib_sanity_test(dirs)
221
222 '''
223 While ipk incremental image generation is enabled, it will remove the
224 unneeded pkgs by comparing the old full manifest in previous existing
225 image and the new full manifest in the current image.
226 '''
227 def _remove_extra_packages(self, pkgs_initial_install):
228 if self.inc_opkg_image_gen == "1":
229 # Parse full manifest in previous existing image creation session
230 old_full_manifest = self.manifest.parse_full_manifest()
231
232 # Create full manifest for the current image session, the old one
233 # will be replaced by the new one.
234 self.manifest.create_full(self.pm)
235
236 # Parse full manifest in current image creation session
237 new_full_manifest = self.manifest.parse_full_manifest()
238
239 pkg_to_remove = list()
240 for pkg in old_full_manifest:
241 if pkg not in new_full_manifest:
242 pkg_to_remove.append(pkg)
243
244 if pkg_to_remove != []:
245 bb.note('decremental removed: %s' % ' '.join(pkg_to_remove))
246 self.pm.remove(pkg_to_remove)
247
248 '''
249 Compare with previous existing image creation, if some conditions
250 triggered, the previous old image should be removed.
251 The conditions include any of 'PACKAGE_EXCLUDE, NO_RECOMMENDATIONS
252 and BAD_RECOMMENDATIONS' has been changed.
253 '''
254 def _remove_old_rootfs(self):
255 if self.inc_opkg_image_gen != "1":
256 return True
257
258 vars_list_file = self.d.expand('${T}/vars_list')
259
260 old_vars_list = ""
261 if os.path.exists(vars_list_file):
262 old_vars_list = open(vars_list_file, 'r+').read()
263
264 new_vars_list = '%s:%s:%s\n' % \
265 ((self.d.getVar('BAD_RECOMMENDATIONS') or '').strip(),
266 (self.d.getVar('NO_RECOMMENDATIONS') or '').strip(),
267 (self.d.getVar('PACKAGE_EXCLUDE') or '').strip())
268 open(vars_list_file, 'w+').write(new_vars_list)
269
270 if old_vars_list != new_vars_list:
271 return True
272
273 return False
274
275 def _create(self):
276 pkgs_to_install = self.manifest.parse_initial_manifest()
277 opkg_pre_process_cmds = self.d.getVar('OPKG_PREPROCESS_COMMANDS')
278 opkg_post_process_cmds = self.d.getVar('OPKG_POSTPROCESS_COMMANDS')
279
280 # update PM index files
281 self.pm.write_index()
282
283 execute_pre_post_process(self.d, opkg_pre_process_cmds)
284
285 if self.progress_reporter:
286 self.progress_reporter.next_stage()
287 # Steps are a bit different in order, skip next
288 self.progress_reporter.next_stage()
289
290 self.pm.update()
291
292 if self.progress_reporter:
293 self.progress_reporter.next_stage()
294
295 if self.inc_opkg_image_gen == "1":
296 self._remove_extra_packages(pkgs_to_install)
297
298 if self.progress_reporter:
299 self.progress_reporter.next_stage()
300
301 for pkg_type in self.install_order:
302 if pkg_type in pkgs_to_install:
303 # For multilib, we perform a sanity test before final install
304 # If sanity test fails, it will automatically do a bb.fatal()
305 # and the installation will stop
306 if pkg_type == Manifest.PKG_TYPE_MULTILIB:
307 self._multilib_test_install(pkgs_to_install[pkg_type])
308
309 self.pm.install(pkgs_to_install[pkg_type],
310 [False, True][pkg_type == Manifest.PKG_TYPE_ATTEMPT_ONLY])
311
312 if self.progress_reporter:
313 self.progress_reporter.next_stage()
314
315 self.pm.install_complementary()
316
317 if self.progress_reporter:
318 self.progress_reporter.next_stage()
319
320 opkg_lib_dir = self.d.getVar('OPKGLIBDIR')
321 opkg_dir = os.path.join(opkg_lib_dir, 'opkg')
322 self._setup_dbg_rootfs([opkg_dir])
323
324 execute_pre_post_process(self.d, opkg_post_process_cmds)
325
326 if self.inc_opkg_image_gen == "1":
327 self.pm.backup_packaging_data()
328
329 if self.progress_reporter:
330 self.progress_reporter.next_stage()
331
332 @staticmethod
333 def _depends_list():
334 return ['IPKGCONF_SDK', 'IPK_FEED_URIS', 'DEPLOY_DIR_IPK', 'IPKGCONF_TARGET', 'INC_IPK_IMAGE_GEN', 'OPKG_ARGS', 'OPKGLIBDIR', 'OPKG_PREPROCESS_COMMANDS', 'OPKG_POSTPROCESS_COMMANDS', 'OPKGLIBDIR']
335
336 def _get_delayed_postinsts(self):
337 status_file = os.path.join(self.image_rootfs,
338 self.d.getVar('OPKGLIBDIR').strip('/'),
339 "opkg", "status")
340 return self._get_delayed_postinsts_common(status_file)
341
342 def _save_postinsts(self):
343 dst_postinst_dir = self.d.expand("${IMAGE_ROOTFS}${sysconfdir}/ipk-postinsts")
344 src_postinst_dir = self.d.expand("${IMAGE_ROOTFS}${OPKGLIBDIR}/opkg/info")
345 return self._save_postinsts_common(dst_postinst_dir, src_postinst_dir)
346
347 def _log_check(self):
348 self._log_check_warn()
349 self._log_check_error()
350
351 def _cleanup(self):
352 self.pm.remove_lists()
diff --git a/meta/lib/oe/package_manager/ipk/sdk.py b/meta/lib/oe/package_manager/ipk/sdk.py
deleted file mode 100644
index 3acd55f548..0000000000
--- a/meta/lib/oe/package_manager/ipk/sdk.py
+++ /dev/null
@@ -1,113 +0,0 @@
1#
2# Copyright OpenEmbedded Contributors
3#
4# SPDX-License-Identifier: GPL-2.0-only
5#
6
7import glob
8import shutil
9from oe.utils import execute_pre_post_process
10from oe.sdk import Sdk
11from oe.package_manager.ipk.manifest import PkgManifest
12from oe.manifest import Manifest
13from oe.package_manager.ipk import OpkgPM
14
15class PkgSdk(Sdk):
16 def __init__(self, d, manifest_dir=None):
17 super(PkgSdk, self).__init__(d, manifest_dir)
18
19 # In sdk_list_installed_packages the call to opkg is hardcoded to
20 # always use IPKGCONF_TARGET and there's no exposed API to change this
21 # so simply override IPKGCONF_TARGET to use this separated config file.
22 ipkgconf_sdk_target = d.getVar("IPKGCONF_SDK_TARGET")
23 d.setVar("IPKGCONF_TARGET", ipkgconf_sdk_target)
24
25 self.target_conf = self.d.getVar("IPKGCONF_TARGET")
26 self.host_conf = self.d.getVar("IPKGCONF_SDK")
27
28 self.target_manifest = PkgManifest(d, self.manifest_dir,
29 Manifest.MANIFEST_TYPE_SDK_TARGET)
30 self.host_manifest = PkgManifest(d, self.manifest_dir,
31 Manifest.MANIFEST_TYPE_SDK_HOST)
32
33 ipk_repo_workdir = "oe-sdk-repo"
34 if "sdk_ext" in d.getVar("BB_RUNTASK"):
35 ipk_repo_workdir = "oe-sdk-ext-repo"
36
37 self.target_pm = OpkgPM(d, self.sdk_target_sysroot, self.target_conf,
38 self.d.getVar("ALL_MULTILIB_PACKAGE_ARCHS"),
39 ipk_repo_workdir=ipk_repo_workdir)
40
41 self.host_pm = OpkgPM(d, self.sdk_host_sysroot, self.host_conf,
42 self.d.getVar("SDK_PACKAGE_ARCHS"),
43 ipk_repo_workdir=ipk_repo_workdir)
44
45 def _populate_sysroot(self, pm, manifest):
46 pkgs_to_install = manifest.parse_initial_manifest()
47
48 if (self.d.getVar('BUILD_IMAGES_FROM_FEEDS') or "") != "1":
49 pm.write_index()
50
51 pm.update()
52
53 for pkg_type in self.install_order:
54 if pkg_type in pkgs_to_install:
55 pm.install(pkgs_to_install[pkg_type],
56 [False, True][pkg_type == Manifest.PKG_TYPE_ATTEMPT_ONLY])
57
58 def _populate(self):
59 execute_pre_post_process(self.d, self.d.getVar("POPULATE_SDK_PRE_TARGET_COMMAND"))
60
61 bb.note("Installing TARGET packages")
62 self._populate_sysroot(self.target_pm, self.target_manifest)
63
64 self.target_pm.install_complementary(self.d.getVar('SDKIMAGE_INSTALL_COMPLEMENTARY'))
65
66 env_bkp = os.environ.copy()
67 os.environ['PATH'] = self.d.expand("${COREBASE}/scripts/nativesdk-intercept") + \
68 os.pathsep + os.environ["PATH"]
69
70 self.target_pm.run_intercepts(populate_sdk='target')
71 os.environ.update(env_bkp)
72
73 execute_pre_post_process(self.d, self.d.getVar("POPULATE_SDK_POST_TARGET_COMMAND"))
74
75 if not bb.utils.contains("SDKIMAGE_FEATURES", "package-management", True, False, self.d):
76 self.target_pm.remove_packaging_data()
77 else:
78 self.target_pm.remove_lists()
79
80 bb.note("Installing NATIVESDK packages")
81 self._populate_sysroot(self.host_pm, self.host_manifest)
82 self.install_locales(self.host_pm)
83
84 self.host_pm.run_intercepts(populate_sdk='host')
85
86 execute_pre_post_process(self.d, self.d.getVar("POPULATE_SDK_POST_HOST_COMMAND"))
87
88 if not bb.utils.contains("SDKIMAGE_FEATURES", "package-management", True, False, self.d):
89 self.host_pm.remove_packaging_data()
90 else:
91 self.host_pm.remove_lists()
92
93 target_sysconfdir = os.path.join(self.sdk_target_sysroot, self.sysconfdir)
94 host_sysconfdir = os.path.join(self.sdk_host_sysroot, self.sysconfdir)
95
96 self.mkdirhier(target_sysconfdir)
97 shutil.copy(self.target_conf, target_sysconfdir)
98 os.chmod(os.path.join(target_sysconfdir,
99 os.path.basename(self.target_conf)), 0o644)
100
101 self.mkdirhier(host_sysconfdir)
102 shutil.copy(self.host_conf, host_sysconfdir)
103 os.chmod(os.path.join(host_sysconfdir,
104 os.path.basename(self.host_conf)), 0o644)
105
106 native_opkg_state_dir = os.path.join(self.sdk_output, self.sdk_native_path,
107 self.d.getVar('localstatedir_nativesdk').strip('/'),
108 "lib", "opkg")
109 self.mkdirhier(native_opkg_state_dir)
110 for f in glob.glob(os.path.join(self.sdk_output, "var", "lib", "opkg", "*")):
111 self.movefile(f, native_opkg_state_dir)
112
113 self.remove(os.path.join(self.sdk_output, "var"), True)