* [PATCH 1/5] package_manager.py: support ipk incremental image generation
2014-02-18 9:42 [PATCH 0/5] package_manager.py/ootfs.py: support ipk incremental image generation Hongxu Jia
@ 2014-02-18 9:42 ` Hongxu Jia
2014-02-18 14:38 ` Laurentiu Palcu
2014-02-18 9:42 ` [PATCH 2/5] package_manager.py: tweak handle_bad_recommendations for " Hongxu Jia
` (3 subsequent siblings)
4 siblings, 1 reply; 12+ messages in thread
From: Hongxu Jia @ 2014-02-18 9:42 UTC (permalink / raw)
To: openembedded-core; +Cc: saul.wold
While incremental image generation enabled, 'load_old_install_solution'
is used to determine what we've got in the previous (existed) image and
'dump_install_solution' to determine what we need to install in the
current image.
The 'backup_packaging_data' is used to back up the current opkg database.
The 'recovery_packaging_data' is used to recover the opkg database which
backed up by the previous image creation.
Tweak 'remove' function in OpkgPM class, which the options for remove
with dependencies was incorrect.
[YOCTO #1894]
Signed-off-by: Hongxu Jia <hongxu.jia@windriver.com>
---
meta/lib/oe/package_manager.py | 106 +++++++++++++++++++++++++++++++++++++++--
1 file changed, 102 insertions(+), 4 deletions(-)
diff --git a/meta/lib/oe/package_manager.py b/meta/lib/oe/package_manager.py
index 6dc8fbd..4ea9677 100644
--- a/meta/lib/oe/package_manager.py
+++ b/meta/lib/oe/package_manager.py
@@ -934,12 +934,13 @@ class RpmPM(PackageManager):
class OpkgPM(PackageManager):
- def __init__(self, d, target_rootfs, config_file, archs):
+ def __init__(self, d, target_rootfs, config_file, archs, task_name='target'):
super(OpkgPM, self).__init__(d)
self.target_rootfs = target_rootfs
self.config_file = config_file
self.pkg_archs = archs
+ self.task_name = task_name
self.deploy_dir = self.d.getVar("DEPLOY_DIR_IPK", True)
self.deploy_lock_file = os.path.join(self.deploy_dir, "deploy.lock")
@@ -956,6 +957,13 @@ class OpkgPM(PackageManager):
bb.utils.mkdirhier(self.opkg_dir)
+ self.solution_manifest = self.d.expand('${T}/saved/%s_solution' %
+ self.task_name)
+ self.saved_opkg_dir = self.d.expand('${T}/saved/%s' % self.task_name)
+ if not os.path.exists(self.d.expand('${T}/saved')):
+ bb.utils.mkdirhier(self.d.expand('${T}/saved'))
+
+
if (self.d.getVar('BUILD_IMAGES_FROM_FEEDS', True) or "") != "1":
self._create_config()
else:
@@ -1075,7 +1083,9 @@ class OpkgPM(PackageManager):
try:
bb.note("Installing the following packages: %s" % ' '.join(pkgs))
- subprocess.check_output(cmd.split())
+ bb.note(cmd)
+ output = subprocess.check_output(cmd.split())
+ bb.note(output)
except subprocess.CalledProcessError as e:
(bb.fatal, bb.note)[attempt_only]("Unable to install packages. "
"Command '%s' returned %d:\n%s" %
@@ -1083,14 +1093,16 @@ class OpkgPM(PackageManager):
def remove(self, pkgs, with_dependencies=True):
if with_dependencies:
- cmd = "%s %s remove %s" % \
+ cmd = "%s %s --force-depends --force-remove --force-removal-of-dependent-packages remove %s" % \
(self.opkg_cmd, self.opkg_args, ' '.join(pkgs))
else:
cmd = "%s %s --force-depends remove %s" % \
(self.opkg_cmd, self.opkg_args, ' '.join(pkgs))
try:
- subprocess.check_output(cmd.split())
+ bb.note(cmd)
+ output = subprocess.check_output(cmd.split())
+ bb.note(output)
except subprocess.CalledProcessError as e:
bb.fatal("Unable to remove packages. Command '%s' "
"returned %d:\n%s" % (e.cmd, e.returncode, e.output))
@@ -1175,6 +1187,92 @@ class OpkgPM(PackageManager):
else:
status.write(line + "\n")
+ '''
+ If incremental install, we need to determine what we've got,
+ what we need to add, and what to remove...
+ The dump_install_solution will dump and save the new install
+ solution.
+ '''
+ def dump_install_solution(self, pkgs):
+ bb.note('creating new install solution for incremental install')
+ if len(pkgs) == 0:
+ return
+
+ install_pkgs = list()
+
+ # Create an temp dir as opkg root for simulating the installation
+ temp_rootfs = self.d.expand('${T}/opkg')
+ temp_opkg_dir = os.path.join(temp_rootfs, 'var/lib/opkg')
+ bb.utils.mkdirhier(temp_opkg_dir)
+
+ opkg_args = "-f %s -o %s " % (self.config_file, temp_rootfs)
+ opkg_args += self.d.getVar("OPKG_ARGS", True)
+
+ cmd = "%s %s update" % (self.opkg_cmd,
+ opkg_args)
+ try:
+ subprocess.check_output(cmd, shell=True)
+ except subprocess.CalledProcessError as e:
+ bb.note("Unable to dump install packages. Command '%s' "
+ "returned %d:\n%s" % (cmd, e.returncode, e.output))
+
+ # Simulate installation from zero
+ cmd = "%s %s --noaction install %s " % (self.opkg_cmd,
+ opkg_args,
+ ' '.join(pkgs))
+ cmd += "| awk '/^Installing/{print $2}' "
+ cmd += "| sort -u -o %s" % self.solution_manifest
+ try:
+ subprocess.check_output(cmd, shell=True)
+ with open(self.solution_manifest, 'r') as manifest:
+ for pkg in manifest.read().split('\n'):
+ install_pkgs.append(pkg)
+ except subprocess.CalledProcessError as e:
+ bb.note("Unable to dump install packages. Command '%s' "
+ "returned %d:\n%s" % (cmd, e.returncode, e.output))
+
+ bb.utils.remove(temp_rootfs, True)
+
+ return install_pkgs
+
+ '''
+ If incremental install, we need to determine what we've got,
+ what we need to add, and what to remove...
+ The load_old_install_solution will load the previous install
+ solution
+ '''
+ def load_old_install_solution(self):
+ bb.note('load old install solution for incremental install')
+ installed_pkgs = list()
+ if not os.path.exists(self.solution_manifest):
+ bb.note('old install solution not exist')
+ return installed_pkgs
+
+ with open(self.solution_manifest, 'r') as manifest:
+ for pkg in manifest.read().split('\n'):
+ installed_pkgs.append(pkg.strip())
+
+ return installed_pkgs
+
+ def backup_packaging_data(self):
+ # Save the opkglib for increment rpm image generation
+ if os.path.exists(self.saved_opkg_dir):
+ bb.utils.remove(self.saved_opkg_dir, True)
+ shutil.copytree(self.opkg_dir,
+ self.saved_opkg_dir,
+ symlinks=True)
+
+ def recovery_packaging_data(self):
+ # Move the opkglib back
+ if os.path.exists(self.saved_opkg_dir):
+ if os.path.exists(self.opkg_dir):
+ bb.utils.remove(self.opkg_dir, True)
+
+ bb.note('Recovery packaging data')
+ shutil.copytree(self.saved_opkg_dir,
+ self.opkg_dir,
+ symlinks=True)
+
class DpkgPM(PackageManager):
def __init__(self, d, target_rootfs, archs, base_archs, apt_conf_dir=None):
--
1.8.1.2
^ permalink raw reply related [flat|nested] 12+ messages in thread* Re: [PATCH 1/5] package_manager.py: support ipk incremental image generation
2014-02-18 9:42 ` [PATCH 1/5] package_manager.py: " Hongxu Jia
@ 2014-02-18 14:38 ` Laurentiu Palcu
2014-02-19 9:39 ` Hongxu Jia
0 siblings, 1 reply; 12+ messages in thread
From: Laurentiu Palcu @ 2014-02-18 14:38 UTC (permalink / raw)
To: Hongxu Jia; +Cc: saul.wold, openembedded-core
On Tue, Feb 18, 2014 at 05:42:24PM +0800, Hongxu Jia wrote:
> While incremental image generation enabled, 'load_old_install_solution'
> is used to determine what we've got in the previous (existed) image and
> 'dump_install_solution' to determine what we need to install in the
> current image.
>
> The 'backup_packaging_data' is used to back up the current opkg database.
>
> The 'recovery_packaging_data' is used to recover the opkg database which
> backed up by the previous image creation.
>
> Tweak 'remove' function in OpkgPM class, which the options for remove
> with dependencies was incorrect.
>
> [YOCTO #1894]
>
> Signed-off-by: Hongxu Jia <hongxu.jia@windriver.com>
> ---
> meta/lib/oe/package_manager.py | 106 +++++++++++++++++++++++++++++++++++++++--
> 1 file changed, 102 insertions(+), 4 deletions(-)
>
> diff --git a/meta/lib/oe/package_manager.py b/meta/lib/oe/package_manager.py
> index 6dc8fbd..4ea9677 100644
> --- a/meta/lib/oe/package_manager.py
> +++ b/meta/lib/oe/package_manager.py
> @@ -934,12 +934,13 @@ class RpmPM(PackageManager):
>
>
> class OpkgPM(PackageManager):
> - def __init__(self, d, target_rootfs, config_file, archs):
> + def __init__(self, d, target_rootfs, config_file, archs, task_name='target'):
> super(OpkgPM, self).__init__(d)
>
> self.target_rootfs = target_rootfs
> self.config_file = config_file
> self.pkg_archs = archs
> + self.task_name = task_name
>
> self.deploy_dir = self.d.getVar("DEPLOY_DIR_IPK", True)
> self.deploy_lock_file = os.path.join(self.deploy_dir, "deploy.lock")
> @@ -956,6 +957,13 @@ class OpkgPM(PackageManager):
>
> bb.utils.mkdirhier(self.opkg_dir)
>
> + self.solution_manifest = self.d.expand('${T}/saved/%s_solution' %
> + self.task_name)
> + self.saved_opkg_dir = self.d.expand('${T}/saved/%s' % self.task_name)
> + if not os.path.exists(self.d.expand('${T}/saved')):
> + bb.utils.mkdirhier(self.d.expand('${T}/saved'))
> +
> +
> if (self.d.getVar('BUILD_IMAGES_FROM_FEEDS', True) or "") != "1":
> self._create_config()
> else:
> @@ -1075,7 +1083,9 @@ class OpkgPM(PackageManager):
>
> try:
> bb.note("Installing the following packages: %s" % ' '.join(pkgs))
> - subprocess.check_output(cmd.split())
> + bb.note(cmd)
> + output = subprocess.check_output(cmd.split())
> + bb.note(output)
> except subprocess.CalledProcessError as e:
> (bb.fatal, bb.note)[attempt_only]("Unable to install packages. "
> "Command '%s' returned %d:\n%s" %
> @@ -1083,14 +1093,16 @@ class OpkgPM(PackageManager):
>
> def remove(self, pkgs, with_dependencies=True):
> if with_dependencies:
> - cmd = "%s %s remove %s" % \
> + cmd = "%s %s --force-depends --force-remove --force-removal-of-dependent-packages remove %s" % \
> (self.opkg_cmd, self.opkg_args, ' '.join(pkgs))
> else:
> cmd = "%s %s --force-depends remove %s" % \
> (self.opkg_cmd, self.opkg_args, ' '.join(pkgs))
>
> try:
> - subprocess.check_output(cmd.split())
> + bb.note(cmd)
> + output = subprocess.check_output(cmd.split())
> + bb.note(output)
> except subprocess.CalledProcessError as e:
> bb.fatal("Unable to remove packages. Command '%s' "
> "returned %d:\n%s" % (e.cmd, e.returncode, e.output))
> @@ -1175,6 +1187,92 @@ class OpkgPM(PackageManager):
> else:
> status.write(line + "\n")
>
> + '''
> + If incremental install, we need to determine what we've got,
> + what we need to add, and what to remove...
> + The dump_install_solution will dump and save the new install
> + solution.
> + '''
> + def dump_install_solution(self, pkgs):
Why not have this function in the Manifest class? We have an API in
place: Manifest.create_final() that should probably take care of
anything related to manifest(s) creation after all packages are installed.
> + bb.note('creating new install solution for incremental install')
> + if len(pkgs) == 0:
> + return
> +
> + install_pkgs = list()
> +
> + # Create an temp dir as opkg root for simulating the installation
> + temp_rootfs = self.d.expand('${T}/opkg')
> + temp_opkg_dir = os.path.join(temp_rootfs, 'var/lib/opkg')
> + bb.utils.mkdirhier(temp_opkg_dir)
> +
> + opkg_args = "-f %s -o %s " % (self.config_file, temp_rootfs)
> + opkg_args += self.d.getVar("OPKG_ARGS", True)
> +
> + cmd = "%s %s update" % (self.opkg_cmd,
> + opkg_args)
> + try:
> + subprocess.check_output(cmd, shell=True)
> + except subprocess.CalledProcessError as e:
> + bb.note("Unable to dump install packages. Command '%s' "
> + "returned %d:\n%s" % (cmd, e.returncode, e.output))
> +
> + # Simulate installation from zero
> + cmd = "%s %s --noaction install %s " % (self.opkg_cmd,
> + opkg_args,
> + ' '.join(pkgs))
> + cmd += "| awk '/^Installing/{print $2}' "
> + cmd += "| sort -u -o %s" % self.solution_manifest
Do we need to preserve this bash one-liner? Why not handle the command
output using Python?
> + try:
> + subprocess.check_output(cmd, shell=True)
> + with open(self.solution_manifest, 'r') as manifest:
> + for pkg in manifest.read().split('\n'):
> + install_pkgs.append(pkg)
> + except subprocess.CalledProcessError as e:
> + bb.note("Unable to dump install packages. Command '%s' "
> + "returned %d:\n%s" % (cmd, e.returncode, e.output))
> +
> + bb.utils.remove(temp_rootfs, True)
> +
> + return install_pkgs
> +
> + '''
> + If incremental install, we need to determine what we've got,
> + what we need to add, and what to remove...
> + The load_old_install_solution will load the previous install
> + solution
> + '''
> + def load_old_install_solution(self):
Same here: why not put it in the Manifest class? As we already have the
Manifest.parse_initial_manifest(), we can have something similar for the
final_manifest (or install_solution, etc) parsing.
> + bb.note('load old install solution for incremental install')
> + installed_pkgs = list()
> + if not os.path.exists(self.solution_manifest):
> + bb.note('old install solution not exist')
> + return installed_pkgs
> +
> + with open(self.solution_manifest, 'r') as manifest:
> + for pkg in manifest.read().split('\n'):
> + installed_pkgs.append(pkg.strip())
> +
> + return installed_pkgs
> +
> + def backup_packaging_data(self):
> + # Save the opkglib for increment rpm image generation
s/rpm/opkg/
> + if os.path.exists(self.saved_opkg_dir):
> + bb.utils.remove(self.saved_opkg_dir, True)
> + shutil.copytree(self.opkg_dir,
> + self.saved_opkg_dir,
> + symlinks=True)
> +
> + def recovery_packaging_data(self):
s/recovery/recover/ ?
> + # Move the opkglib back
> + if os.path.exists(self.saved_opkg_dir):
> + if os.path.exists(self.opkg_dir):
> + bb.utils.remove(self.opkg_dir, True)
> +
> + bb.note('Recovery packaging data')
> + shutil.copytree(self.saved_opkg_dir,
> + self.opkg_dir,
> + symlinks=True)
> +
>
> class DpkgPM(PackageManager):
> def __init__(self, d, target_rootfs, archs, base_archs, apt_conf_dir=None):
> --
> 1.8.1.2
>
^ permalink raw reply [flat|nested] 12+ messages in thread* Re: [PATCH 1/5] package_manager.py: support ipk incremental image generation
2014-02-18 14:38 ` Laurentiu Palcu
@ 2014-02-19 9:39 ` Hongxu Jia
0 siblings, 0 replies; 12+ messages in thread
From: Hongxu Jia @ 2014-02-19 9:39 UTC (permalink / raw)
To: Laurentiu Palcu; +Cc: saul.wold, openembedded-core
On 02/18/2014 10:38 PM, Laurentiu Palcu wrote:
> On Tue, Feb 18, 2014 at 05:42:24PM +0800, Hongxu Jia wrote:
>> While incremental image generation enabled, 'load_old_install_solution'
>> is used to determine what we've got in the previous (existed) image and
>> 'dump_install_solution' to determine what we need to install in the
>> current image.
>>
>> The 'backup_packaging_data' is used to back up the current opkg database.
>>
>> The 'recovery_packaging_data' is used to recover the opkg database which
>> backed up by the previous image creation.
>>
>> Tweak 'remove' function in OpkgPM class, which the options for remove
>> with dependencies was incorrect.
>>
>> [YOCTO #1894]
>>
>> Signed-off-by: Hongxu Jia <hongxu.jia@windriver.com>
>> ---
>> meta/lib/oe/package_manager.py | 106 +++++++++++++++++++++++++++++++++++++++--
>> 1 file changed, 102 insertions(+), 4 deletions(-)
>>
>> diff --git a/meta/lib/oe/package_manager.py b/meta/lib/oe/package_manager.py
>> index 6dc8fbd..4ea9677 100644
>> --- a/meta/lib/oe/package_manager.py
>> +++ b/meta/lib/oe/package_manager.py
>> @@ -934,12 +934,13 @@ class RpmPM(PackageManager):
>>
>>
>> class OpkgPM(PackageManager):
>> - def __init__(self, d, target_rootfs, config_file, archs):
>> + def __init__(self, d, target_rootfs, config_file, archs, task_name='target'):
>> super(OpkgPM, self).__init__(d)
>>
>> self.target_rootfs = target_rootfs
>> self.config_file = config_file
>> self.pkg_archs = archs
>> + self.task_name = task_name
>>
>> self.deploy_dir = self.d.getVar("DEPLOY_DIR_IPK", True)
>> self.deploy_lock_file = os.path.join(self.deploy_dir, "deploy.lock")
>> @@ -956,6 +957,13 @@ class OpkgPM(PackageManager):
>>
>> bb.utils.mkdirhier(self.opkg_dir)
>>
>> + self.solution_manifest = self.d.expand('${T}/saved/%s_solution' %
>> + self.task_name)
>> + self.saved_opkg_dir = self.d.expand('${T}/saved/%s' % self.task_name)
>> + if not os.path.exists(self.d.expand('${T}/saved')):
>> + bb.utils.mkdirhier(self.d.expand('${T}/saved'))
>> +
>> +
>> if (self.d.getVar('BUILD_IMAGES_FROM_FEEDS', True) or "") != "1":
>> self._create_config()
>> else:
>> @@ -1075,7 +1083,9 @@ class OpkgPM(PackageManager):
>>
>> try:
>> bb.note("Installing the following packages: %s" % ' '.join(pkgs))
>> - subprocess.check_output(cmd.split())
>> + bb.note(cmd)
>> + output = subprocess.check_output(cmd.split())
>> + bb.note(output)
>> except subprocess.CalledProcessError as e:
>> (bb.fatal, bb.note)[attempt_only]("Unable to install packages. "
>> "Command '%s' returned %d:\n%s" %
>> @@ -1083,14 +1093,16 @@ class OpkgPM(PackageManager):
>>
>> def remove(self, pkgs, with_dependencies=True):
>> if with_dependencies:
>> - cmd = "%s %s remove %s" % \
>> + cmd = "%s %s --force-depends --force-remove --force-removal-of-dependent-packages remove %s" % \
>> (self.opkg_cmd, self.opkg_args, ' '.join(pkgs))
>> else:
>> cmd = "%s %s --force-depends remove %s" % \
>> (self.opkg_cmd, self.opkg_args, ' '.join(pkgs))
>>
>> try:
>> - subprocess.check_output(cmd.split())
>> + bb.note(cmd)
>> + output = subprocess.check_output(cmd.split())
>> + bb.note(output)
>> except subprocess.CalledProcessError as e:
>> bb.fatal("Unable to remove packages. Command '%s' "
>> "returned %d:\n%s" % (e.cmd, e.returncode, e.output))
>> @@ -1175,6 +1187,92 @@ class OpkgPM(PackageManager):
>> else:
>> status.write(line + "\n")
>>
>> + '''
>> + If incremental install, we need to determine what we've got,
>> + what we need to add, and what to remove...
>> + The dump_install_solution will dump and save the new install
>> + solution.
>> + '''
>> + def dump_install_solution(self, pkgs):
> Why not have this function in the Manifest class? We have an API in
> place: Manifest.create_final() that should probably take care of
> anything related to manifest(s) creation after all packages are installed.
Got it,
The dump_install_solution creates a manifest with the
packages that *will be* installed into the image, it is a
dummy installation.
I will move 'dump_install_solution' to Manifest class as
create_full.
>> + bb.note('creating new install solution for incremental install')
>> + if len(pkgs) == 0:
>> + return
>> +
>> + install_pkgs = list()
>> +
>> + # Create an temp dir as opkg root for simulating the installation
>> + temp_rootfs = self.d.expand('${T}/opkg')
>> + temp_opkg_dir = os.path.join(temp_rootfs, 'var/lib/opkg')
>> + bb.utils.mkdirhier(temp_opkg_dir)
>> +
>> + opkg_args = "-f %s -o %s " % (self.config_file, temp_rootfs)
>> + opkg_args += self.d.getVar("OPKG_ARGS", True)
>> +
>> + cmd = "%s %s update" % (self.opkg_cmd,
>> + opkg_args)
>> + try:
>> + subprocess.check_output(cmd, shell=True)
>> + except subprocess.CalledProcessError as e:
>> + bb.note("Unable to dump install packages. Command '%s' "
>> + "returned %d:\n%s" % (cmd, e.returncode, e.output))
>> +
>> + # Simulate installation from zero
>> + cmd = "%s %s --noaction install %s " % (self.opkg_cmd,
>> + opkg_args,
>> + ' '.join(pkgs))
>> + cmd += "| awk '/^Installing/{print $2}' "
>> + cmd += "| sort -u -o %s" % self.solution_manifest
> Do we need to preserve this bash one-liner? Why not handle the command
> output using Python?
Agree, I will handle this in Python.
>> + try:
>> + subprocess.check_output(cmd, shell=True)
>> + with open(self.solution_manifest, 'r') as manifest:
>> + for pkg in manifest.read().split('\n'):
>> + install_pkgs.append(pkg)
>> + except subprocess.CalledProcessError as e:
>> + bb.note("Unable to dump install packages. Command '%s' "
>> + "returned %d:\n%s" % (cmd, e.returncode, e.output))
>> +
>> + bb.utils.remove(temp_rootfs, True)
>> +
>> + return install_pkgs
>> +
>> + '''
>> + If incremental install, we need to determine what we've got,
>> + what we need to add, and what to remove...
>> + The load_old_install_solution will load the previous install
>> + solution
>> + '''
>> + def load_old_install_solution(self):
> Same here: why not put it in the Manifest class? As we already have the
> Manifest.parse_initial_manifest(), we can have something similar for the
> final_manifest (or install_solution, etc) parsing.
Agree, Manifest.parse_full_manifest() will be added
>> + bb.note('load old install solution for incremental install')
>> + installed_pkgs = list()
>> + if not os.path.exists(self.solution_manifest):
>> + bb.note('old install solution not exist')
>> + return installed_pkgs
>> +
>> + with open(self.solution_manifest, 'r') as manifest:
>> + for pkg in manifest.read().split('\n'):
>> + installed_pkgs.append(pkg.strip())
>> +
>> + return installed_pkgs
>> +
>> + def backup_packaging_data(self):
>> + # Save the opkglib for increment rpm image generation
> s/rpm/opkg/
Sorry for the typo
>> + if os.path.exists(self.saved_opkg_dir):
>> + bb.utils.remove(self.saved_opkg_dir, True)
>> + shutil.copytree(self.opkg_dir,
>> + self.saved_opkg_dir,
>> + symlinks=True)
>> +
>> + def recovery_packaging_data(self):
> s/recovery/recover/ ?
Sorry for the typo
V2 incoming
//Hongxu
>> + # Move the opkglib back
>> + if os.path.exists(self.saved_opkg_dir):
>> + if os.path.exists(self.opkg_dir):
>> + bb.utils.remove(self.opkg_dir, True)
>> +
>> + bb.note('Recovery packaging data')
>> + shutil.copytree(self.saved_opkg_dir,
>> + self.opkg_dir,
>> + symlinks=True)
>> +
>>
>> class DpkgPM(PackageManager):
>> def __init__(self, d, target_rootfs, archs, base_archs, apt_conf_dir=None):
>> --
>> 1.8.1.2
>>
^ permalink raw reply [flat|nested] 12+ messages in thread
* [PATCH 2/5] package_manager.py: tweak handle_bad_recommendations for ipk incremental image generation
2014-02-18 9:42 [PATCH 0/5] package_manager.py/ootfs.py: support ipk incremental image generation Hongxu Jia
2014-02-18 9:42 ` [PATCH 1/5] package_manager.py: " Hongxu Jia
@ 2014-02-18 9:42 ` Hongxu Jia
2014-02-18 9:42 ` [PATCH 3/5] rootfs.py: support " Hongxu Jia
` (2 subsequent siblings)
4 siblings, 0 replies; 12+ messages in thread
From: Hongxu Jia @ 2014-02-18 9:42 UTC (permalink / raw)
To: openembedded-core; +Cc: saul.wold
Let opkg_dir be configurable in handle_bad_recommendations,
so it could work on other root fs.
Invoke handle_bad_recommendations in dump_install_solution
which simulates package install on other root fs.
[YOCTO #1894]
Signed-off-by: Hongxu Jia <hongxu.jia@windriver.com>
---
meta/lib/oe/package_manager.py | 18 +++++++++++++-----
1 file changed, 13 insertions(+), 5 deletions(-)
diff --git a/meta/lib/oe/package_manager.py b/meta/lib/oe/package_manager.py
index 4ea9677..3cfd4af 100644
--- a/meta/lib/oe/package_manager.py
+++ b/meta/lib/oe/package_manager.py
@@ -1157,12 +1157,19 @@ class OpkgPM(PackageManager):
return output
- def handle_bad_recommendations(self):
- bad_recommendations = self.d.getVar("BAD_RECOMMENDATIONS", True)
- if bad_recommendations is None:
+ def handle_bad_recommendations(self, opkg_dir=""):
+ bad_recommendations = self.d.getVar("BAD_RECOMMENDATIONS", True) or ""
+ if bad_recommendations.strip() == "":
return
- status_file = os.path.join(self.opkg_dir, "status")
+ if opkg_dir == "":
+ opkg_dir = self.opkg_dir
+ status_file = os.path.join(opkg_dir, "status")
+
+ # If status file existed, it means the bad recommendations has already
+ # been handled
+ if os.path.exists(status_file):
+ return
cmd = "%s %s info " % (self.opkg_cmd, self.opkg_args)
@@ -1177,7 +1184,7 @@ class OpkgPM(PackageManager):
"returned %d:\n%s" % (pkg_info, e.returncode, e.output))
if output == "":
- bb.note("Requested ignored recommendation $i is "
+ bb.note("Requested ignored recommendation %s is "
"not a package" % pkg)
continue
@@ -1204,6 +1211,7 @@ class OpkgPM(PackageManager):
temp_rootfs = self.d.expand('${T}/opkg')
temp_opkg_dir = os.path.join(temp_rootfs, 'var/lib/opkg')
bb.utils.mkdirhier(temp_opkg_dir)
+ self.handle_bad_recommendations(temp_opkg_dir)
opkg_args = "-f %s -o %s " % (self.config_file, temp_rootfs)
opkg_args += self.d.getVar("OPKG_ARGS", True)
--
1.8.1.2
^ permalink raw reply related [flat|nested] 12+ messages in thread* [PATCH 3/5] rootfs.py: support ipk incremental image generation
2014-02-18 9:42 [PATCH 0/5] package_manager.py/ootfs.py: support ipk incremental image generation Hongxu Jia
2014-02-18 9:42 ` [PATCH 1/5] package_manager.py: " Hongxu Jia
2014-02-18 9:42 ` [PATCH 2/5] package_manager.py: tweak handle_bad_recommendations for " Hongxu Jia
@ 2014-02-18 9:42 ` Hongxu Jia
2014-02-18 9:42 ` [PATCH 4/5] rootfs.py: fix BAD_RECOMMENDATIONS for " Hongxu Jia
2014-02-18 9:42 ` [PATCH 5/5] rootfs.py: tweak _multilib_sanity_test " Hongxu Jia
4 siblings, 0 replies; 12+ messages in thread
From: Hongxu Jia @ 2014-02-18 9:42 UTC (permalink / raw)
To: openembedded-core; +Cc: saul.wold
While incremental image generation enabled, if previous image existed,
it restores the opkg database. Based on the previous image, it gets what
need to remove for the current and remove them.
The newly added and upgraded packages will be done since opkg install
invoked.
[YOCTO #1894]
Signed-off-by: Hongxu Jia <hongxu.jia@windriver.com>
---
meta/lib/oe/rootfs.py | 50 +++++++++++++++++++++++++++++++++++++++++++++++---
1 file changed, 47 insertions(+), 3 deletions(-)
diff --git a/meta/lib/oe/rootfs.py b/meta/lib/oe/rootfs.py
index d149ca3..5561bb9 100644
--- a/meta/lib/oe/rootfs.py
+++ b/meta/lib/oe/rootfs.py
@@ -438,13 +438,25 @@ class OpkgRootfs(Rootfs):
def __init__(self, d, manifest_dir):
super(OpkgRootfs, self).__init__(d)
- bb.utils.remove(self.image_rootfs, True)
- bb.utils.remove(self.d.getVar('MULTILIB_TEMP_ROOTFS', True), True)
self.manifest = OpkgManifest(d, manifest_dir)
self.opkg_conf = self.d.getVar("IPKGCONF_TARGET", True)
self.pkg_archs = self.d.getVar("ALL_MULTILIB_PACKAGE_ARCHS", True)
- self.pm = OpkgPM(d, self.image_rootfs, self.opkg_conf, self.pkg_archs)
+ self.inc_opkg_image_gen = self.d.getVar('INC_IPK_IMAGE_GEN', True)
+ if self.inc_opkg_image_gen != "1":
+ bb.utils.remove(self.image_rootfs, True)
+ self.pm = OpkgPM(d,
+ self.image_rootfs,
+ self.opkg_conf,
+ self.pkg_archs)
+ else:
+ self.pm = OpkgPM(d,
+ self.image_rootfs,
+ self.opkg_conf,
+ self.pkg_archs)
+ self.pm.recovery_packaging_data()
+
+ bb.utils.remove(self.d.getVar('MULTILIB_TEMP_ROOTFS', True), True)
"""
This function was reused from the old implementation.
@@ -508,6 +520,32 @@ class OpkgRootfs(Rootfs):
self._multilib_sanity_test(dirs)
+ '''
+ While ipk incremental image generation is enabled, it will remove the
+ unneeded pkgs by comparing the new install solution manifest and the
+ old installed manifest.
+ '''
+ def _create_incremental(self, pkgs_initial_install):
+ if self.inc_opkg_image_gen == "1":
+
+ pkgs_to_install = list()
+ for pkg_type in pkgs_initial_install:
+ pkgs_to_install += pkgs_initial_install[pkg_type]
+
+ installed_manifest = self.pm.load_old_install_solution()
+ solution_manifest = self.pm.dump_install_solution(pkgs_to_install)
+
+ pkg_to_remove = list()
+ for pkg in installed_manifest:
+ if pkg not in solution_manifest:
+ pkg_to_remove.append(pkg)
+
+ self.pm.update()
+
+ if pkg_to_remove != []:
+ bb.note('incremental removed: %s' % ' '.join(pkg_to_remove))
+ self.pm.remove(pkg_to_remove)
+
def _create(self):
pkgs_to_install = self.manifest.parse_initial_manifest()
opkg_pre_process_cmds = self.d.getVar('OPKG_PREPROCESS_COMMANDS', True)
@@ -518,6 +556,9 @@ class OpkgRootfs(Rootfs):
if (self.d.getVar('BUILD_IMAGES_FROM_FEEDS', True) or "") != "1":
self.pm.write_index()
+ if self.inc_opkg_image_gen == "1":
+ self._create_incremental(pkgs_to_install)
+
execute_pre_post_process(self.d, opkg_pre_process_cmds)
self.pm.update()
@@ -540,6 +581,9 @@ class OpkgRootfs(Rootfs):
execute_pre_post_process(self.d, opkg_post_process_cmds)
execute_pre_post_process(self.d, rootfs_post_install_cmds)
+ if self.inc_opkg_image_gen == "1":
+ self.pm.backup_packaging_data()
+
def _get_delayed_postinsts(self):
pkg_list = []
status_file = os.path.join(self.image_rootfs,
--
1.8.1.2
^ permalink raw reply related [flat|nested] 12+ messages in thread* [PATCH 4/5] rootfs.py: fix BAD_RECOMMENDATIONS for ipk incremental image generation
2014-02-18 9:42 [PATCH 0/5] package_manager.py/ootfs.py: support ipk incremental image generation Hongxu Jia
` (2 preceding siblings ...)
2014-02-18 9:42 ` [PATCH 3/5] rootfs.py: support " Hongxu Jia
@ 2014-02-18 9:42 ` Hongxu Jia
2014-02-18 15:03 ` Laurentiu Palcu
2014-02-18 9:42 ` [PATCH 5/5] rootfs.py: tweak _multilib_sanity_test " Hongxu Jia
4 siblings, 1 reply; 12+ messages in thread
From: Hongxu Jia @ 2014-02-18 9:42 UTC (permalink / raw)
To: openembedded-core; +Cc: saul.wold
While incremental image generation enabled and the previous image existed,
if BAD_RECOMMENDATIONS is changed, the operation on the existed image is
complicated, so remove the existed image in this situation.
The same with PACKAGE_EXCLUDE and NO_RECOMMENDATIONS.
[YOCTO #1894]
Signed-off-by: Hongxu Jia <hongxu.jia@windriver.com>
---
meta/lib/oe/rootfs.py | 30 +++++++++++++++++++++++++++++-
1 file changed, 29 insertions(+), 1 deletion(-)
diff --git a/meta/lib/oe/rootfs.py b/meta/lib/oe/rootfs.py
index 5561bb9..3d7adf9 100644
--- a/meta/lib/oe/rootfs.py
+++ b/meta/lib/oe/rootfs.py
@@ -443,7 +443,7 @@ class OpkgRootfs(Rootfs):
self.pkg_archs = self.d.getVar("ALL_MULTILIB_PACKAGE_ARCHS", True)
self.inc_opkg_image_gen = self.d.getVar('INC_IPK_IMAGE_GEN', True)
- if self.inc_opkg_image_gen != "1":
+ if self._remove_existed_image():
bb.utils.remove(self.image_rootfs, True)
self.pm = OpkgPM(d,
self.image_rootfs,
@@ -546,6 +546,34 @@ class OpkgRootfs(Rootfs):
bb.note('incremental removed: %s' % ' '.join(pkg_to_remove))
self.pm.remove(pkg_to_remove)
+ '''
+ Compare with previous (existed) image creation, if some conditions
+ triggered, the previous (existed) image should be removed.
+ The conditions included any of 'PACKAGE_EXCLUDE, NO_RECOMMENDATIONS
+ and BAD_RECOMMENDATIONS' has been changed.
+ '''
+ def _remove_existed_image(self):
+ # Incremental image creation is not enable
+ if self.inc_opkg_image_gen != "1":
+ return True
+
+ vars_list_dir = self.d.expand('${T}/vars_list')
+
+ old_vars_list = ""
+ if os.path.exists(vars_list_dir):
+ old_vars_list = open(vars_list_dir, 'r+').read()
+
+ new_vars_list = '%s:%s:%s\n' % \
+ ((self.d.getVar('BAD_RECOMMENDATIONS', True) or '').strip(),
+ (self.d.getVar('NO_RECOMMENDATIONS', True) or '').strip(),
+ (self.d.getVar('PACKAGE_EXCLUDE', True) or '').strip())
+ open(vars_list_dir, 'w+').write(new_vars_list)
+
+ if old_vars_list != new_vars_list:
+ return True
+
+ return False
+
def _create(self):
pkgs_to_install = self.manifest.parse_initial_manifest()
opkg_pre_process_cmds = self.d.getVar('OPKG_PREPROCESS_COMMANDS', True)
--
1.8.1.2
^ permalink raw reply related [flat|nested] 12+ messages in thread* Re: [PATCH 4/5] rootfs.py: fix BAD_RECOMMENDATIONS for ipk incremental image generation
2014-02-18 9:42 ` [PATCH 4/5] rootfs.py: fix BAD_RECOMMENDATIONS for " Hongxu Jia
@ 2014-02-18 15:03 ` Laurentiu Palcu
2014-02-19 9:44 ` Hongxu Jia
0 siblings, 1 reply; 12+ messages in thread
From: Laurentiu Palcu @ 2014-02-18 15:03 UTC (permalink / raw)
To: Hongxu Jia; +Cc: saul.wold, openembedded-core
On Tue, Feb 18, 2014 at 05:42:27PM +0800, Hongxu Jia wrote:
> While incremental image generation enabled and the previous image existed,
> if BAD_RECOMMENDATIONS is changed, the operation on the existed image is
> complicated, so remove the existed image in this situation.
>
> The same with PACKAGE_EXCLUDE and NO_RECOMMENDATIONS.
>
> [YOCTO #1894]
> Signed-off-by: Hongxu Jia <hongxu.jia@windriver.com>
> ---
> meta/lib/oe/rootfs.py | 30 +++++++++++++++++++++++++++++-
> 1 file changed, 29 insertions(+), 1 deletion(-)
>
> diff --git a/meta/lib/oe/rootfs.py b/meta/lib/oe/rootfs.py
> index 5561bb9..3d7adf9 100644
> --- a/meta/lib/oe/rootfs.py
> +++ b/meta/lib/oe/rootfs.py
> @@ -443,7 +443,7 @@ class OpkgRootfs(Rootfs):
> self.pkg_archs = self.d.getVar("ALL_MULTILIB_PACKAGE_ARCHS", True)
>
> self.inc_opkg_image_gen = self.d.getVar('INC_IPK_IMAGE_GEN', True)
> - if self.inc_opkg_image_gen != "1":
> + if self._remove_existed_image():
> bb.utils.remove(self.image_rootfs, True)
> self.pm = OpkgPM(d,
> self.image_rootfs,
> @@ -546,6 +546,34 @@ class OpkgRootfs(Rootfs):
> bb.note('incremental removed: %s' % ' '.join(pkg_to_remove))
> self.pm.remove(pkg_to_remove)
>
> + '''
> + Compare with previous (existed) image creation, if some conditions
> + triggered, the previous (existed) image should be removed.
> + The conditions included any of 'PACKAGE_EXCLUDE, NO_RECOMMENDATIONS
> + and BAD_RECOMMENDATIONS' has been changed.
> + '''
> + def _remove_existed_image(self):
s/existed/existing/
Also in the comment above.
> + # Incremental image creation is not enable
> + if self.inc_opkg_image_gen != "1":
> + return True
> +
> + vars_list_dir = self.d.expand('${T}/vars_list')
s/vars_list_dir/vars_list_file/ in the line above and the code below.
Leaving this variable with a 'dir' suffix while we're opening a file for
reading/writing, is a little misleading.
> +
> + old_vars_list = ""
> + if os.path.exists(vars_list_dir):
> + old_vars_list = open(vars_list_dir, 'r+').read()
> +
> + new_vars_list = '%s:%s:%s\n' % \
> + ((self.d.getVar('BAD_RECOMMENDATIONS', True) or '').strip(),
> + (self.d.getVar('NO_RECOMMENDATIONS', True) or '').strip(),
> + (self.d.getVar('PACKAGE_EXCLUDE', True) or '').strip())
> + open(vars_list_dir, 'w+').write(new_vars_list)
> +
> + if old_vars_list != new_vars_list:
> + return True
> +
> + return False
> +
> def _create(self):
> pkgs_to_install = self.manifest.parse_initial_manifest()
> opkg_pre_process_cmds = self.d.getVar('OPKG_PREPROCESS_COMMANDS', True)
> --
> 1.8.1.2
>
^ permalink raw reply [flat|nested] 12+ messages in thread* Re: [PATCH 4/5] rootfs.py: fix BAD_RECOMMENDATIONS for ipk incremental image generation
2014-02-18 15:03 ` Laurentiu Palcu
@ 2014-02-19 9:44 ` Hongxu Jia
0 siblings, 0 replies; 12+ messages in thread
From: Hongxu Jia @ 2014-02-19 9:44 UTC (permalink / raw)
To: Laurentiu Palcu; +Cc: saul.wold, openembedded-core
On 02/18/2014 11:03 PM, Laurentiu Palcu wrote:
> On Tue, Feb 18, 2014 at 05:42:27PM +0800, Hongxu Jia wrote:
>> While incremental image generation enabled and the previous image existed,
>> if BAD_RECOMMENDATIONS is changed, the operation on the existed image is
>> complicated, so remove the existed image in this situation.
>>
>> The same with PACKAGE_EXCLUDE and NO_RECOMMENDATIONS.
>>
>> [YOCTO #1894]
>> Signed-off-by: Hongxu Jia <hongxu.jia@windriver.com>
>> ---
>> meta/lib/oe/rootfs.py | 30 +++++++++++++++++++++++++++++-
>> 1 file changed, 29 insertions(+), 1 deletion(-)
>>
>> diff --git a/meta/lib/oe/rootfs.py b/meta/lib/oe/rootfs.py
>> index 5561bb9..3d7adf9 100644
>> --- a/meta/lib/oe/rootfs.py
>> +++ b/meta/lib/oe/rootfs.py
>> @@ -443,7 +443,7 @@ class OpkgRootfs(Rootfs):
>> self.pkg_archs = self.d.getVar("ALL_MULTILIB_PACKAGE_ARCHS", True)
>>
>> self.inc_opkg_image_gen = self.d.getVar('INC_IPK_IMAGE_GEN', True)
>> - if self.inc_opkg_image_gen != "1":
>> + if self._remove_existed_image():
>> bb.utils.remove(self.image_rootfs, True)
>> self.pm = OpkgPM(d,
>> self.image_rootfs,
>> @@ -546,6 +546,34 @@ class OpkgRootfs(Rootfs):
>> bb.note('incremental removed: %s' % ' '.join(pkg_to_remove))
>> self.pm.remove(pkg_to_remove)
>>
>> + '''
>> + Compare with previous (existed) image creation, if some conditions
>> + triggered, the previous (existed) image should be removed.
>> + The conditions included any of 'PACKAGE_EXCLUDE, NO_RECOMMENDATIONS
>> + and BAD_RECOMMENDATIONS' has been changed.
>> + '''
>> + def _remove_existed_image(self):
> s/existed/existing/
>
> Also in the comment above.
Sorry for the typo
>
>> + # Incremental image creation is not enable
>> + if self.inc_opkg_image_gen != "1":
>> + return True
>> +
>> + vars_list_dir = self.d.expand('${T}/vars_list')
> s/vars_list_dir/vars_list_file/ in the line above and the code below.
> Leaving this variable with a 'dir' suffix while we're opening a file for
> reading/writing, is a little misleading.
Sorry for the misleading
V2 incoming
//Hongxu
>> +
>> + old_vars_list = ""
>> + if os.path.exists(vars_list_dir):
>> + old_vars_list = open(vars_list_dir, 'r+').read()
>> +
>> + new_vars_list = '%s:%s:%s\n' % \
>> + ((self.d.getVar('BAD_RECOMMENDATIONS', True) or '').strip(),
>> + (self.d.getVar('NO_RECOMMENDATIONS', True) or '').strip(),
>> + (self.d.getVar('PACKAGE_EXCLUDE', True) or '').strip())
>> + open(vars_list_dir, 'w+').write(new_vars_list)
>> +
>> + if old_vars_list != new_vars_list:
>> + return True
>> +
>> + return False
>> +
>> def _create(self):
>> pkgs_to_install = self.manifest.parse_initial_manifest()
>> opkg_pre_process_cmds = self.d.getVar('OPKG_PREPROCESS_COMMANDS', True)
>> --
>> 1.8.1.2
>>
^ permalink raw reply [flat|nested] 12+ messages in thread
* [PATCH 5/5] rootfs.py: tweak _multilib_sanity_test for ipk incremental image generation
2014-02-18 9:42 [PATCH 0/5] package_manager.py/ootfs.py: support ipk incremental image generation Hongxu Jia
` (3 preceding siblings ...)
2014-02-18 9:42 ` [PATCH 4/5] rootfs.py: fix BAD_RECOMMENDATIONS for " Hongxu Jia
@ 2014-02-18 9:42 ` Hongxu Jia
2014-02-18 15:36 ` Laurentiu Palcu
4 siblings, 1 reply; 12+ messages in thread
From: Hongxu Jia @ 2014-02-18 9:42 UTC (permalink / raw)
To: openembedded-core; +Cc: saul.wold
The _multilib_sanity_test installs multilib packages in a temporary
root fs, and compare with the current image to figure out duplicated
file that comes from different packages.
While incremental image generation enabled and the previous image
existed, there was a Multilib check error:
...
ERROR: Multilib check error: duplicate files tmp/work/qemux86_64-poky-
linux/core-image-minimal/1.0-r0/multilib/lib32/lib/libc.so.6 tmp/work/
qemux86_64-poky-linux/core-image-minimal/1.0-r0/rootfs/lib/libc.so.6
is not the same
...
The reason is the file in current image has been prelinked in previous
image generation and the file in a temporary root fs is not prelinked,
even though the files come from the same package, the Multilib check
considers they are different.
[YOCTO #1894]
Signed-off-by: Hongxu Jia <hongxu.jia@windriver.com>
---
meta/lib/oe/rootfs.py | 56 +++++++++++++++++++++++++++++++++++++++++++++++----
1 file changed, 52 insertions(+), 4 deletions(-)
diff --git a/meta/lib/oe/rootfs.py b/meta/lib/oe/rootfs.py
index 3d7adf9..5054d1e 100644
--- a/meta/lib/oe/rootfs.py
+++ b/meta/lib/oe/rootfs.py
@@ -3,6 +3,8 @@ from oe.utils import execute_pre_post_process
from oe.utils import contains as base_contains
from oe.package_manager import *
from oe.manifest import *
+import oe.path
+import filecmp
import shutil
import os
import subprocess
@@ -458,13 +460,61 @@ class OpkgRootfs(Rootfs):
bb.utils.remove(self.d.getVar('MULTILIB_TEMP_ROOTFS', True), True)
+ def _prelink_file(self, root_dir, filename):
+ bb.note('prelink %s in %s' % (filename, root_dir))
+ prelink_cfg = oe.path.join(root_dir,
+ self.d.expand('${sysconfdir}/prelink.conf'))
+ if not os.path.exists(prelink_cfg):
+ shutil.copy(self.d.expand('${STAGING_DIR_NATIVE}${sysconfdir_native}/prelink.conf'),
+ prelink_cfg)
+
+ cmd_prelink = self.d.expand('${STAGING_DIR_NATIVE}${sbindir_native}/prelink')
+ self._exec_shell_cmd([cmd_prelink,
+ '--root',
+ root_dir,
+ '-amR',
+ '-N',
+ '-c',
+ self.d.expand('${sysconfdir}/prelink.conf')])
+
+ '''
+ Compare two files with the same key twice to see if they came
+ from the same package. If they are not same, they are duplicated
+ and come from different packages.
+ 1st: Comapre them directly;
+ 2nd: While incremental image creation is enabled, one of the
+ files could be probaly prelinked in the previous image
+ creation and the file has been changed, so we need to
+ prelink the other one and compare them.
+ '''
+ def _file_duplicate(self, key, f1, f2):
+
+ if not os.path.exists(f1) or not os.path.exists(f2):
+ return False
+
+ # f1 is the same with f2, both of them were not prelinked
+ if filecmp.cmp(f1, f2):
+ return False
+
+ if self.image_rootfs not in f1:
+ self._prelink_file(f1.replace(key, ''), f1)
+
+ if self.image_rootfs not in f2:
+ self._prelink_file(f2.replace(key, ''), f2)
+
+ # f1 is the same with f2, both of them were prelinked
+ if filecmp.cmp(f1, f2):
+ return False
+
+ # Duplicated
+ return True
+
"""
This function was reused from the old implementation.
See commit: "image.bbclass: Added variables for multilib support." by
Lianhao Lu.
"""
def _multilib_sanity_test(self, dirs):
- import filecmp
allow_replace = self.d.getVar("MULTILIBRE_ALLOW_REP", True)
if allow_replace is None:
@@ -486,9 +536,7 @@ class OpkgRootfs(Rootfs):
if allow_rep.match(key):
valid = True
else:
- if os.path.exists(files[key]) and \
- os.path.exists(item) and \
- not filecmp.cmp(files[key], item):
+ if self._file_duplicate(key, files[key], item):
valid = False
bb.fatal("%s duplicate files %s %s is not the same\n" %
(error_prompt, item, files[key]))
--
1.8.1.2
^ permalink raw reply related [flat|nested] 12+ messages in thread* Re: [PATCH 5/5] rootfs.py: tweak _multilib_sanity_test for ipk incremental image generation
2014-02-18 9:42 ` [PATCH 5/5] rootfs.py: tweak _multilib_sanity_test " Hongxu Jia
@ 2014-02-18 15:36 ` Laurentiu Palcu
2014-02-19 9:51 ` Hongxu Jia
0 siblings, 1 reply; 12+ messages in thread
From: Laurentiu Palcu @ 2014-02-18 15:36 UTC (permalink / raw)
To: Hongxu Jia; +Cc: saul.wold, openembedded-core
On Tue, Feb 18, 2014 at 05:42:28PM +0800, Hongxu Jia wrote:
> The _multilib_sanity_test installs multilib packages in a temporary
> root fs, and compare with the current image to figure out duplicated
> file that comes from different packages.
>
> While incremental image generation enabled and the previous image
> existed, there was a Multilib check error:
> ...
> ERROR: Multilib check error: duplicate files tmp/work/qemux86_64-poky-
> linux/core-image-minimal/1.0-r0/multilib/lib32/lib/libc.so.6 tmp/work/
> qemux86_64-poky-linux/core-image-minimal/1.0-r0/rootfs/lib/libc.so.6
> is not the same
> ...
>
> The reason is the file in current image has been prelinked in previous
> image generation and the file in a temporary root fs is not prelinked,
> even though the files come from the same package, the Multilib check
> considers they are different.
>
> [YOCTO #1894]
> Signed-off-by: Hongxu Jia <hongxu.jia@windriver.com>
> ---
> meta/lib/oe/rootfs.py | 56 +++++++++++++++++++++++++++++++++++++++++++++++----
> 1 file changed, 52 insertions(+), 4 deletions(-)
>
> diff --git a/meta/lib/oe/rootfs.py b/meta/lib/oe/rootfs.py
> index 3d7adf9..5054d1e 100644
> --- a/meta/lib/oe/rootfs.py
> +++ b/meta/lib/oe/rootfs.py
> @@ -3,6 +3,8 @@ from oe.utils import execute_pre_post_process
> from oe.utils import contains as base_contains
> from oe.package_manager import *
> from oe.manifest import *
> +import oe.path
> +import filecmp
> import shutil
> import os
> import subprocess
> @@ -458,13 +460,61 @@ class OpkgRootfs(Rootfs):
>
> bb.utils.remove(self.d.getVar('MULTILIB_TEMP_ROOTFS', True), True)
>
> + def _prelink_file(self, root_dir, filename):
> + bb.note('prelink %s in %s' % (filename, root_dir))
> + prelink_cfg = oe.path.join(root_dir,
> + self.d.expand('${sysconfdir}/prelink.conf'))
> + if not os.path.exists(prelink_cfg):
> + shutil.copy(self.d.expand('${STAGING_DIR_NATIVE}${sysconfdir_native}/prelink.conf'),
> + prelink_cfg)
> +
> + cmd_prelink = self.d.expand('${STAGING_DIR_NATIVE}${sbindir_native}/prelink')
> + self._exec_shell_cmd([cmd_prelink,
> + '--root',
> + root_dir,
> + '-amR',
> + '-N',
> + '-c',
> + self.d.expand('${sysconfdir}/prelink.conf')])
> +
> + '''
> + Compare two files with the same key twice to see if they came
> + from the same package. If they are not same, they are duplicated
> + and come from different packages.
I'm kind of confused by this comment. Doesn't same = duplicate? There
might be a small confusion of terms here because the function's behavior
is not as the name implies.
> + 1st: Comapre them directly;
> + 2nd: While incremental image creation is enabled, one of the
> + files could be probaly prelinked in the previous image
> + creation and the file has been changed, so we need to
> + prelink the other one and compare them.
> + '''
> + def _file_duplicate(self, key, f1, f2):
Shouldn't be better to rename this function to something else in order
to avoid confusion? Let's say: _files_are_equal() ?
> +
> + if not os.path.exists(f1) or not os.path.exists(f2):
> + return False
> +
> + # f1 is the same with f2, both of them were not prelinked
> + if filecmp.cmp(f1, f2):
> + return False
filecmp.cmp() returns True if files are equal. Hence the confusion:
_file_duplicate() returns False here, if files are equal... I think the logic
is a little bit the other way around! :)
> +
> + if self.image_rootfs not in f1:
> + self._prelink_file(f1.replace(key, ''), f1)
> +
> + if self.image_rootfs not in f2:
> + self._prelink_file(f2.replace(key, ''), f2)
> +
> + # f1 is the same with f2, both of them were prelinked
> + if filecmp.cmp(f1, f2):
> + return False
> +
> + # Duplicated
> + return True
here the return value matches the comment and the function name! :)
> +
> """
> This function was reused from the old implementation.
> See commit: "image.bbclass: Added variables for multilib support." by
> Lianhao Lu.
> """
> def _multilib_sanity_test(self, dirs):
> - import filecmp
>
> allow_replace = self.d.getVar("MULTILIBRE_ALLOW_REP", True)
> if allow_replace is None:
> @@ -486,9 +536,7 @@ class OpkgRootfs(Rootfs):
> if allow_rep.match(key):
> valid = True
> else:
> - if os.path.exists(files[key]) and \
> - os.path.exists(item) and \
> - not filecmp.cmp(files[key], item):
> + if self._file_duplicate(key, files[key], item):
> valid = False
> bb.fatal("%s duplicate files %s %s is not the same\n" %
> (error_prompt, item, files[key]))
> --
> 1.8.1.2
>
^ permalink raw reply [flat|nested] 12+ messages in thread* Re: [PATCH 5/5] rootfs.py: tweak _multilib_sanity_test for ipk incremental image generation
2014-02-18 15:36 ` Laurentiu Palcu
@ 2014-02-19 9:51 ` Hongxu Jia
0 siblings, 0 replies; 12+ messages in thread
From: Hongxu Jia @ 2014-02-19 9:51 UTC (permalink / raw)
To: Laurentiu Palcu; +Cc: saul.wold, openembedded-core
I will rename _file_duplicate with _file_equal, and do
the necessary ajustment to avoid confusions.
Thank you for pointing out
V2 incoming
//Hongxu
On 02/18/2014 11:36 PM, Laurentiu Palcu wrote:
> On Tue, Feb 18, 2014 at 05:42:28PM +0800, Hongxu Jia wrote:
>> The _multilib_sanity_test installs multilib packages in a temporary
>> root fs, and compare with the current image to figure out duplicated
>> file that comes from different packages.
>>
>> While incremental image generation enabled and the previous image
>> existed, there was a Multilib check error:
>> ...
>> ERROR: Multilib check error: duplicate files tmp/work/qemux86_64-poky-
>> linux/core-image-minimal/1.0-r0/multilib/lib32/lib/libc.so.6 tmp/work/
>> qemux86_64-poky-linux/core-image-minimal/1.0-r0/rootfs/lib/libc.so.6
>> is not the same
>> ...
>>
>> The reason is the file in current image has been prelinked in previous
>> image generation and the file in a temporary root fs is not prelinked,
>> even though the files come from the same package, the Multilib check
>> considers they are different.
>>
>> [YOCTO #1894]
>> Signed-off-by: Hongxu Jia <hongxu.jia@windriver.com>
>> ---
>> meta/lib/oe/rootfs.py | 56 +++++++++++++++++++++++++++++++++++++++++++++++----
>> 1 file changed, 52 insertions(+), 4 deletions(-)
>>
>> diff --git a/meta/lib/oe/rootfs.py b/meta/lib/oe/rootfs.py
>> index 3d7adf9..5054d1e 100644
>> --- a/meta/lib/oe/rootfs.py
>> +++ b/meta/lib/oe/rootfs.py
>> @@ -3,6 +3,8 @@ from oe.utils import execute_pre_post_process
>> from oe.utils import contains as base_contains
>> from oe.package_manager import *
>> from oe.manifest import *
>> +import oe.path
>> +import filecmp
>> import shutil
>> import os
>> import subprocess
>> @@ -458,13 +460,61 @@ class OpkgRootfs(Rootfs):
>>
>> bb.utils.remove(self.d.getVar('MULTILIB_TEMP_ROOTFS', True), True)
>>
>> + def _prelink_file(self, root_dir, filename):
>> + bb.note('prelink %s in %s' % (filename, root_dir))
>> + prelink_cfg = oe.path.join(root_dir,
>> + self.d.expand('${sysconfdir}/prelink.conf'))
>> + if not os.path.exists(prelink_cfg):
>> + shutil.copy(self.d.expand('${STAGING_DIR_NATIVE}${sysconfdir_native}/prelink.conf'),
>> + prelink_cfg)
>> +
>> + cmd_prelink = self.d.expand('${STAGING_DIR_NATIVE}${sbindir_native}/prelink')
>> + self._exec_shell_cmd([cmd_prelink,
>> + '--root',
>> + root_dir,
>> + '-amR',
>> + '-N',
>> + '-c',
>> + self.d.expand('${sysconfdir}/prelink.conf')])
>> +
>> + '''
>> + Compare two files with the same key twice to see if they came
>> + from the same package. If they are not same, they are duplicated
>> + and come from different packages.
> I'm kind of confused by this comment. Doesn't same = duplicate? There
> might be a small confusion of terms here because the function's behavior
> is not as the name implies.
>
>> + 1st: Comapre them directly;
>> + 2nd: While incremental image creation is enabled, one of the
>> + files could be probaly prelinked in the previous image
>> + creation and the file has been changed, so we need to
>> + prelink the other one and compare them.
>> + '''
>> + def _file_duplicate(self, key, f1, f2):
> Shouldn't be better to rename this function to something else in order
> to avoid confusion? Let's say: _files_are_equal() ?
>
>> +
>> + if not os.path.exists(f1) or not os.path.exists(f2):
>> + return False
>> +
>> + # f1 is the same with f2, both of them were not prelinked
>> + if filecmp.cmp(f1, f2):
>> + return False
> filecmp.cmp() returns True if files are equal. Hence the confusion:
> _file_duplicate() returns False here, if files are equal... I think the logic
> is a little bit the other way around! :)
>
>> +
>> + if self.image_rootfs not in f1:
>> + self._prelink_file(f1.replace(key, ''), f1)
>> +
>> + if self.image_rootfs not in f2:
>> + self._prelink_file(f2.replace(key, ''), f2)
>> +
>> + # f1 is the same with f2, both of them were prelinked
>> + if filecmp.cmp(f1, f2):
>> + return False
>> +
>> + # Duplicated
>> + return True
> here the return value matches the comment and the function name! :)
>> +
>> """
>> This function was reused from the old implementation.
>> See commit: "image.bbclass: Added variables for multilib support." by
>> Lianhao Lu.
>> """
>> def _multilib_sanity_test(self, dirs):
>> - import filecmp
>>
>> allow_replace = self.d.getVar("MULTILIBRE_ALLOW_REP", True)
>> if allow_replace is None:
>> @@ -486,9 +536,7 @@ class OpkgRootfs(Rootfs):
>> if allow_rep.match(key):
>> valid = True
>> else:
>> - if os.path.exists(files[key]) and \
>> - os.path.exists(item) and \
>> - not filecmp.cmp(files[key], item):
>> + if self._file_duplicate(key, files[key], item):
>> valid = False
>> bb.fatal("%s duplicate files %s %s is not the same\n" %
>> (error_prompt, item, files[key]))
>> --
>> 1.8.1.2
>>
^ permalink raw reply [flat|nested] 12+ messages in thread