wic: moved content of direct.py to direct_plugin
This move simplifies directory structure and makes further refactoring easier. The code from direct.py was used only in direct_plugin, so it's safe to move it there. [YOCTO #10619] (From OE-Core rev: a8f5ebb26183faa9af6eb72f4dabfcf83aa1e8d4) Signed-off-by: Ed Bartosh <ed.bartosh@linux.intel.com> Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
This commit is contained in:
parent
dba8cf377c
commit
ee10c2f1bb
|
@ -1,402 +0,0 @@
|
|||
# ex:ts=4:sw=4:sts=4:et
|
||||
# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
|
||||
#
|
||||
# Copyright (c) 2013, Intel Corporation.
|
||||
# All rights reserved.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License version 2 as
|
||||
# published by the Free Software Foundation.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along
|
||||
# with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
#
|
||||
# DESCRIPTION
|
||||
# This implements the 'direct' image creator class for 'wic'
|
||||
#
|
||||
# AUTHORS
|
||||
# Tom Zanussi <tom.zanussi (at] linux.intel.com>
|
||||
#
|
||||
|
||||
import os
|
||||
import shutil
|
||||
import uuid
|
||||
import tempfile
|
||||
|
||||
from wic import msger
|
||||
from wic.utils.oe.misc import get_bitbake_var
|
||||
from wic.utils.partitionedfs import Image
|
||||
from wic.utils.errors import CreatorError, ImageError
|
||||
from wic.plugin import pluginmgr
|
||||
from wic.utils.oe.misc import exec_cmd, exec_native_cmd
|
||||
|
||||
disk_methods = {
|
||||
"do_install_disk":None,
|
||||
}
|
||||
|
||||
class DiskImage():
|
||||
"""
|
||||
A Disk backed by a file.
|
||||
"""
|
||||
def __init__(self, device, size):
|
||||
self.size = size
|
||||
self.device = device
|
||||
self.created = False
|
||||
|
||||
def exists(self):
|
||||
return os.path.exists(self.device)
|
||||
|
||||
def create(self):
|
||||
if self.created:
|
||||
return
|
||||
# create sparse disk image
|
||||
with open(self.device, 'w') as sparse:
|
||||
os.ftruncate(sparse.fileno(), self.size)
|
||||
|
||||
self.created = True
|
||||
|
||||
class DirectImageCreator:
|
||||
"""
|
||||
Installs a system into a file containing a partitioned disk image.
|
||||
|
||||
DirectImageCreator is an advanced ImageCreator subclass; an image
|
||||
file is formatted with a partition table, each partition created
|
||||
from a rootfs or other OpenEmbedded build artifact and dd'ed into
|
||||
the virtual disk. The disk image can subsequently be dd'ed onto
|
||||
media and used on actual hardware.
|
||||
"""
|
||||
|
||||
def __init__(self, image_name, ksobj, oe_builddir, image_output_dir,
|
||||
rootfs_dir, bootimg_dir, kernel_dir, native_sysroot,
|
||||
compressor, bmap=False):
|
||||
"""
|
||||
Initialize a DirectImageCreator instance.
|
||||
|
||||
This method takes the same arguments as ImageCreator.__init__()
|
||||
"""
|
||||
self.name = image_name
|
||||
self.outdir = image_output_dir
|
||||
self.workdir = tempfile.mktemp(prefix='wic')
|
||||
self.ks = ksobj
|
||||
|
||||
self.__image = None
|
||||
self.__disks = {}
|
||||
self.__disk_format = "direct"
|
||||
self._disk_names = []
|
||||
self.ptable_format = self.ks.bootloader.ptable
|
||||
|
||||
self.oe_builddir = oe_builddir
|
||||
self.rootfs_dir = rootfs_dir
|
||||
self.bootimg_dir = bootimg_dir
|
||||
self.kernel_dir = kernel_dir
|
||||
self.native_sysroot = native_sysroot
|
||||
self.compressor = compressor
|
||||
self.bmap = bmap
|
||||
|
||||
def _get_part_num(self, num, parts):
|
||||
"""calculate the real partition number, accounting for partitions not
|
||||
in the partition table and logical partitions
|
||||
"""
|
||||
realnum = 0
|
||||
for pnum, part in enumerate(parts, 1):
|
||||
if not part.no_table:
|
||||
realnum += 1
|
||||
if pnum == num:
|
||||
if part.no_table:
|
||||
return 0
|
||||
if self.ptable_format == 'msdos' and realnum > 3:
|
||||
# account for logical partition numbering, ex. sda5..
|
||||
return realnum + 1
|
||||
return realnum
|
||||
|
||||
def _write_fstab(self, image_rootfs):
|
||||
"""overriden to generate fstab (temporarily) in rootfs. This is called
|
||||
from _create, make sure it doesn't get called from
|
||||
BaseImage.create()
|
||||
"""
|
||||
if not image_rootfs:
|
||||
return
|
||||
|
||||
fstab_path = image_rootfs + "/etc/fstab"
|
||||
if not os.path.isfile(fstab_path):
|
||||
return
|
||||
|
||||
with open(fstab_path) as fstab:
|
||||
fstab_lines = fstab.readlines()
|
||||
|
||||
if self._update_fstab(fstab_lines, self._get_parts()):
|
||||
shutil.copyfile(fstab_path, fstab_path + ".orig")
|
||||
|
||||
with open(fstab_path, "w") as fstab:
|
||||
fstab.writelines(fstab_lines)
|
||||
|
||||
return fstab_path
|
||||
|
||||
def _update_fstab(self, fstab_lines, parts):
|
||||
"""Assume partition order same as in wks"""
|
||||
updated = False
|
||||
for num, part in enumerate(parts, 1):
|
||||
pnum = self._get_part_num(num, parts)
|
||||
if not pnum or not part.mountpoint \
|
||||
or part.mountpoint in ("/", "/boot"):
|
||||
continue
|
||||
|
||||
# mmc device partitions are named mmcblk0p1, mmcblk0p2..
|
||||
prefix = 'p' if part.disk.startswith('mmcblk') else ''
|
||||
device_name = "/dev/%s%s%d" % (part.disk, prefix, pnum)
|
||||
|
||||
opts = part.fsopts if part.fsopts else "defaults"
|
||||
line = "\t".join([device_name, part.mountpoint, part.fstype,
|
||||
opts, "0", "0"]) + "\n"
|
||||
|
||||
fstab_lines.append(line)
|
||||
updated = True
|
||||
|
||||
return updated
|
||||
|
||||
def set_bootimg_dir(self, bootimg_dir):
|
||||
"""
|
||||
Accessor for bootimg_dir, the actual location used for the source
|
||||
of the bootimg. Should be set by source plugins (only if they
|
||||
change the default bootimg source) so the correct info gets
|
||||
displayed for print_outimage_info().
|
||||
"""
|
||||
self.bootimg_dir = bootimg_dir
|
||||
|
||||
def _get_parts(self):
|
||||
if not self.ks:
|
||||
raise CreatorError("Failed to get partition info, "
|
||||
"please check your kickstart setting.")
|
||||
|
||||
# Set a default partition if no partition is given out
|
||||
if not self.ks.partitions:
|
||||
partstr = "part / --size 1900 --ondisk sda --fstype=ext3"
|
||||
args = partstr.split()
|
||||
part = self.ks.parse(args[1:])
|
||||
if part not in self.ks.partitions:
|
||||
self.ks.partitions.append(part)
|
||||
|
||||
# partitions list from kickstart file
|
||||
return self.ks.partitions
|
||||
|
||||
def _full_name(self, name, extention):
|
||||
""" Construct full file name for a file we generate. """
|
||||
return "%s-%s.%s" % (self.name, name, extention)
|
||||
|
||||
def _full_path(self, path, name, extention):
|
||||
""" Construct full file path to a file we generate. """
|
||||
return os.path.join(path, self._full_name(name, extention))
|
||||
|
||||
def get_default_source_plugin(self):
|
||||
"""
|
||||
The default source plugin i.e. the plugin that's consulted for
|
||||
overall image generation tasks outside of any particular
|
||||
partition. For convenience, we just hang it off the
|
||||
bootloader handler since it's the one non-partition object in
|
||||
any setup. By default the default plugin is set to the same
|
||||
plugin as the /boot partition; since we hang it off the
|
||||
bootloader object, the default can be explicitly set using the
|
||||
--source bootloader param.
|
||||
"""
|
||||
return self.ks.bootloader.source
|
||||
|
||||
#
|
||||
# Actual implemention
|
||||
#
|
||||
def create(self):
|
||||
"""
|
||||
For 'wic', we already have our build artifacts - we just create
|
||||
filesystems from the artifacts directly and combine them into
|
||||
a partitioned image.
|
||||
"""
|
||||
parts = self._get_parts()
|
||||
|
||||
self._image = Image(self.native_sysroot)
|
||||
|
||||
disk_ids = {}
|
||||
for num, part in enumerate(parts, 1):
|
||||
# as a convenience, set source to the boot partition source
|
||||
# instead of forcing it to be set via bootloader --source
|
||||
if not self.ks.bootloader.source and part.mountpoint == "/boot":
|
||||
self.ks.bootloader.source = part.source
|
||||
|
||||
# generate parition UUIDs
|
||||
if not part.uuid and part.use_uuid:
|
||||
if self.ptable_format == 'gpt':
|
||||
part.uuid = str(uuid.uuid4())
|
||||
else: # msdos partition table
|
||||
if part.disk not in disk_ids:
|
||||
disk_ids[part.disk] = int.from_bytes(os.urandom(4), 'little')
|
||||
disk_id = disk_ids[part.disk]
|
||||
part.uuid = '%0x-%02d' % (disk_id, self._get_part_num(num, parts))
|
||||
|
||||
fstab_path = self._write_fstab(self.rootfs_dir.get("ROOTFS_DIR"))
|
||||
|
||||
for part in parts:
|
||||
# get rootfs size from bitbake variable if it's not set in .ks file
|
||||
if not part.size:
|
||||
# and if rootfs name is specified for the partition
|
||||
image_name = self.rootfs_dir.get(part.rootfs_dir)
|
||||
if image_name and os.path.sep not in image_name:
|
||||
# Bitbake variable ROOTFS_SIZE is calculated in
|
||||
# Image._get_rootfs_size method from meta/lib/oe/image.py
|
||||
# using IMAGE_ROOTFS_SIZE, IMAGE_ROOTFS_ALIGNMENT,
|
||||
# IMAGE_OVERHEAD_FACTOR and IMAGE_ROOTFS_EXTRA_SPACE
|
||||
rsize_bb = get_bitbake_var('ROOTFS_SIZE', image_name)
|
||||
if rsize_bb:
|
||||
part.size = int(round(float(rsize_bb)))
|
||||
# need to create the filesystems in order to get their
|
||||
# sizes before we can add them and do the layout.
|
||||
# Image.create() actually calls __format_disks() to create
|
||||
# the disk images and carve out the partitions, then
|
||||
# self.assemble() calls Image.assemble() which calls
|
||||
# __write_partitition() for each partition to dd the fs
|
||||
# into the partitions.
|
||||
part.prepare(self, self.workdir, self.oe_builddir, self.rootfs_dir,
|
||||
self.bootimg_dir, self.kernel_dir, self.native_sysroot)
|
||||
|
||||
|
||||
self._image.add_partition(part.disk_size,
|
||||
part.disk,
|
||||
part.mountpoint,
|
||||
part.source_file,
|
||||
part.fstype,
|
||||
part.label,
|
||||
fsopts=part.fsopts,
|
||||
boot=part.active,
|
||||
align=part.align,
|
||||
no_table=part.no_table,
|
||||
part_type=part.part_type,
|
||||
uuid=part.uuid,
|
||||
system_id=part.system_id)
|
||||
|
||||
if fstab_path:
|
||||
shutil.move(fstab_path + ".orig", fstab_path)
|
||||
|
||||
self._image.layout_partitions(self.ptable_format)
|
||||
|
||||
for disk_name, disk in self._image.disks.items():
|
||||
full_path = self._full_path(self.workdir, disk_name, "direct")
|
||||
msger.debug("Adding disk %s as %s with size %s bytes" \
|
||||
% (disk_name, full_path, disk['min_size']))
|
||||
disk_obj = DiskImage(full_path, disk['min_size'])
|
||||
#self._disks[disk_name] = disk_obj
|
||||
self._image.add_disk(disk_name, disk_obj, disk_ids.get(disk_name))
|
||||
|
||||
self._image.create()
|
||||
|
||||
def assemble(self):
|
||||
"""
|
||||
Assemble partitions into disk image(s)
|
||||
"""
|
||||
for disk_name, disk in self._image.disks.items():
|
||||
full_path = self._full_path(self.workdir, disk_name, "direct")
|
||||
msger.debug("Assembling disk %s as %s with size %s bytes" \
|
||||
% (disk_name, full_path, disk['min_size']))
|
||||
self._image.assemble(full_path)
|
||||
|
||||
def finalize(self):
|
||||
"""
|
||||
Finalize the disk image.
|
||||
|
||||
For example, prepare the image to be bootable by e.g.
|
||||
creating and installing a bootloader configuration.
|
||||
"""
|
||||
source_plugin = self.get_default_source_plugin()
|
||||
if source_plugin:
|
||||
self._source_methods = pluginmgr.get_source_plugin_methods(source_plugin, disk_methods)
|
||||
for disk_name, disk in self._image.disks.items():
|
||||
self._source_methods["do_install_disk"](disk, disk_name, self,
|
||||
self.workdir,
|
||||
self.oe_builddir,
|
||||
self.bootimg_dir,
|
||||
self.kernel_dir,
|
||||
self.native_sysroot)
|
||||
|
||||
for disk_name, disk in self._image.disks.items():
|
||||
full_path = self._full_path(self.workdir, disk_name, "direct")
|
||||
# Generate .bmap
|
||||
if self.bmap:
|
||||
msger.debug("Generating bmap file for %s" % disk_name)
|
||||
exec_native_cmd("bmaptool create %s -o %s.bmap" % (full_path, full_path),
|
||||
self.native_sysroot)
|
||||
# Compress the image
|
||||
if self.compressor:
|
||||
msger.debug("Compressing disk %s with %s" % (disk_name, self.compressor))
|
||||
exec_cmd("%s %s" % (self.compressor, full_path))
|
||||
|
||||
def print_outimage_info(self):
|
||||
"""
|
||||
Print the image(s) and artifacts used, for the user.
|
||||
"""
|
||||
msg = "The new image(s) can be found here:\n"
|
||||
|
||||
parts = self._get_parts()
|
||||
|
||||
for disk_name in self._image.disks:
|
||||
extension = "direct" + {"gzip": ".gz",
|
||||
"bzip2": ".bz2",
|
||||
"xz": ".xz",
|
||||
"": ""}.get(self.compressor)
|
||||
full_path = self._full_path(self.outdir, disk_name, extension)
|
||||
msg += ' %s\n\n' % full_path
|
||||
|
||||
msg += 'The following build artifacts were used to create the image(s):\n'
|
||||
for part in parts:
|
||||
if part.rootfs_dir is None:
|
||||
continue
|
||||
if part.mountpoint == '/':
|
||||
suffix = ':'
|
||||
else:
|
||||
suffix = '["%s"]:' % (part.mountpoint or part.label)
|
||||
msg += ' ROOTFS_DIR%s%s\n' % (suffix.ljust(20), part.rootfs_dir)
|
||||
|
||||
msg += ' BOOTIMG_DIR: %s\n' % self.bootimg_dir
|
||||
msg += ' KERNEL_DIR: %s\n' % self.kernel_dir
|
||||
msg += ' NATIVE_SYSROOT: %s\n' % self.native_sysroot
|
||||
|
||||
msger.info(msg)
|
||||
|
||||
@property
|
||||
def rootdev(self):
|
||||
"""
|
||||
Get root device name to use as a 'root' parameter
|
||||
in kernel command line.
|
||||
|
||||
Assume partition order same as in wks
|
||||
"""
|
||||
parts = self._get_parts()
|
||||
for num, part in enumerate(parts, 1):
|
||||
if part.mountpoint == "/":
|
||||
if part.uuid:
|
||||
return "PARTUUID=%s" % part.uuid
|
||||
else:
|
||||
suffix = 'p' if part.disk.startswith('mmcblk') else ''
|
||||
pnum = self._get_part_num(num, parts)
|
||||
return "/dev/%s%s%-d" % (part.disk, suffix, pnum)
|
||||
|
||||
def cleanup(self):
|
||||
if self._image:
|
||||
try:
|
||||
self._image.cleanup()
|
||||
except ImageError as err:
|
||||
msger.warning("%s" % err)
|
||||
|
||||
# Move results to the output dir
|
||||
if not os.path.exists(self.outdir):
|
||||
os.makedirs(self.outdir)
|
||||
|
||||
for fname in os.listdir(self.workdir):
|
||||
path = os.path.join(self.workdir, fname)
|
||||
if os.path.isfile(path):
|
||||
shutil.move(path, os.path.join(self.outdir, fname))
|
||||
|
||||
# remove work directory
|
||||
shutil.rmtree(self.workdir, ignore_errors=True)
|
||||
|
|
@ -23,16 +23,23 @@
|
|||
# AUTHORS
|
||||
# Tom Zanussi <tom.zanussi (at] linux.intel.com>
|
||||
#
|
||||
import os
|
||||
import shutil
|
||||
import uuid
|
||||
import tempfile
|
||||
import time
|
||||
|
||||
from time import strftime
|
||||
|
||||
from os.path import basename, splitext
|
||||
from wic.utils import errors
|
||||
from wic.ksparser import KickStart, KickStartError
|
||||
from wic import msger
|
||||
|
||||
import wic.imager.direct as direct
|
||||
from wic import msger
|
||||
from wic.ksparser import KickStart, KickStartError
|
||||
from wic.plugin import pluginmgr
|
||||
from wic.pluginbase import ImagerPlugin
|
||||
from wic.utils import errors
|
||||
from wic.utils.errors import CreatorError, ImageError
|
||||
from wic.utils.oe.misc import get_bitbake_var, exec_cmd, exec_native_cmd
|
||||
from wic.utils.partitionedfs import Image
|
||||
|
||||
class DirectPlugin(ImagerPlugin):
|
||||
"""
|
||||
|
@ -87,16 +94,10 @@ class DirectPlugin(ImagerPlugin):
|
|||
strftime("%Y%m%d%H%M"))
|
||||
krootfs_dir = cls.__rootfs_dir_to_dict(rootfs_dir)
|
||||
|
||||
creator = direct.DirectImageCreator(image_name,
|
||||
ksobj,
|
||||
oe_builddir,
|
||||
image_output_dir,
|
||||
krootfs_dir,
|
||||
bootimg_dir,
|
||||
kernel_dir,
|
||||
native_sysroot,
|
||||
compressor,
|
||||
opts.bmap)
|
||||
creator = DirectImageCreator(image_name, ksobj, oe_builddir,
|
||||
image_output_dir, krootfs_dir,
|
||||
bootimg_dir, kernel_dir, native_sysroot,
|
||||
compressor, opts.bmap)
|
||||
try:
|
||||
creator.create()
|
||||
creator.assemble()
|
||||
|
@ -108,4 +109,367 @@ class DirectPlugin(ImagerPlugin):
|
|||
finally:
|
||||
creator.cleanup()
|
||||
|
||||
return 0
|
||||
disk_methods = {
|
||||
"do_install_disk":None,
|
||||
}
|
||||
|
||||
class DiskImage():
|
||||
"""
|
||||
A Disk backed by a file.
|
||||
"""
|
||||
def __init__(self, device, size):
|
||||
self.size = size
|
||||
self.device = device
|
||||
self.created = False
|
||||
|
||||
def exists(self):
|
||||
return os.path.exists(self.device)
|
||||
|
||||
def create(self):
|
||||
if self.created:
|
||||
return
|
||||
# create sparse disk image
|
||||
with open(self.device, 'w') as sparse:
|
||||
os.ftruncate(sparse.fileno(), self.size)
|
||||
|
||||
self.created = True
|
||||
|
||||
class DirectImageCreator:
|
||||
"""
|
||||
Installs a system into a file containing a partitioned disk image.
|
||||
|
||||
DirectImageCreator is an advanced ImageCreator subclass; an image
|
||||
file is formatted with a partition table, each partition created
|
||||
from a rootfs or other OpenEmbedded build artifact and dd'ed into
|
||||
the virtual disk. The disk image can subsequently be dd'ed onto
|
||||
media and used on actual hardware.
|
||||
"""
|
||||
|
||||
def __init__(self, image_name, ksobj, oe_builddir, image_output_dir,
|
||||
rootfs_dir, bootimg_dir, kernel_dir, native_sysroot,
|
||||
compressor, bmap=False):
|
||||
"""
|
||||
Initialize a DirectImageCreator instance.
|
||||
|
||||
This method takes the same arguments as ImageCreator.__init__()
|
||||
"""
|
||||
self.name = image_name
|
||||
self.outdir = image_output_dir
|
||||
self.workdir = tempfile.mktemp(prefix='wic')
|
||||
self.ks = ksobj
|
||||
|
||||
self.__image = None
|
||||
self.__disks = {}
|
||||
self.__disk_format = "direct"
|
||||
self._disk_names = []
|
||||
self.ptable_format = self.ks.bootloader.ptable
|
||||
|
||||
self.oe_builddir = oe_builddir
|
||||
self.rootfs_dir = rootfs_dir
|
||||
self.bootimg_dir = bootimg_dir
|
||||
self.kernel_dir = kernel_dir
|
||||
self.native_sysroot = native_sysroot
|
||||
self.compressor = compressor
|
||||
self.bmap = bmap
|
||||
|
||||
def _get_part_num(self, num, parts):
|
||||
"""calculate the real partition number, accounting for partitions not
|
||||
in the partition table and logical partitions
|
||||
"""
|
||||
realnum = 0
|
||||
for pnum, part in enumerate(parts, 1):
|
||||
if not part.no_table:
|
||||
realnum += 1
|
||||
if pnum == num:
|
||||
if part.no_table:
|
||||
return 0
|
||||
if self.ptable_format == 'msdos' and realnum > 3:
|
||||
# account for logical partition numbering, ex. sda5..
|
||||
return realnum + 1
|
||||
return realnum
|
||||
|
||||
def _write_fstab(self, image_rootfs):
|
||||
"""overriden to generate fstab (temporarily) in rootfs. This is called
|
||||
from _create, make sure it doesn't get called from
|
||||
BaseImage.create()
|
||||
"""
|
||||
if not image_rootfs:
|
||||
return
|
||||
|
||||
fstab_path = image_rootfs + "/etc/fstab"
|
||||
if not os.path.isfile(fstab_path):
|
||||
return
|
||||
|
||||
with open(fstab_path) as fstab:
|
||||
fstab_lines = fstab.readlines()
|
||||
|
||||
if self._update_fstab(fstab_lines, self._get_parts()):
|
||||
shutil.copyfile(fstab_path, fstab_path + ".orig")
|
||||
|
||||
with open(fstab_path, "w") as fstab:
|
||||
fstab.writelines(fstab_lines)
|
||||
|
||||
return fstab_path
|
||||
|
||||
def _update_fstab(self, fstab_lines, parts):
|
||||
"""Assume partition order same as in wks"""
|
||||
updated = False
|
||||
for num, part in enumerate(parts, 1):
|
||||
pnum = self._get_part_num(num, parts)
|
||||
if not pnum or not part.mountpoint \
|
||||
or part.mountpoint in ("/", "/boot"):
|
||||
continue
|
||||
|
||||
# mmc device partitions are named mmcblk0p1, mmcblk0p2..
|
||||
prefix = 'p' if part.disk.startswith('mmcblk') else ''
|
||||
device_name = "/dev/%s%s%d" % (part.disk, prefix, pnum)
|
||||
|
||||
opts = part.fsopts if part.fsopts else "defaults"
|
||||
line = "\t".join([device_name, part.mountpoint, part.fstype,
|
||||
opts, "0", "0"]) + "\n"
|
||||
|
||||
fstab_lines.append(line)
|
||||
updated = True
|
||||
|
||||
return updated
|
||||
|
||||
def set_bootimg_dir(self, bootimg_dir):
|
||||
"""
|
||||
Accessor for bootimg_dir, the actual location used for the source
|
||||
of the bootimg. Should be set by source plugins (only if they
|
||||
change the default bootimg source) so the correct info gets
|
||||
displayed for print_outimage_info().
|
||||
"""
|
||||
self.bootimg_dir = bootimg_dir
|
||||
|
||||
def _get_parts(self):
|
||||
if not self.ks:
|
||||
raise CreatorError("Failed to get partition info, "
|
||||
"please check your kickstart setting.")
|
||||
|
||||
# Set a default partition if no partition is given out
|
||||
if not self.ks.partitions:
|
||||
partstr = "part / --size 1900 --ondisk sda --fstype=ext3"
|
||||
args = partstr.split()
|
||||
part = self.ks.parse(args[1:])
|
||||
if part not in self.ks.partitions:
|
||||
self.ks.partitions.append(part)
|
||||
|
||||
# partitions list from kickstart file
|
||||
return self.ks.partitions
|
||||
|
||||
def _full_name(self, name, extention):
|
||||
""" Construct full file name for a file we generate. """
|
||||
return "%s-%s.%s" % (self.name, name, extention)
|
||||
|
||||
def _full_path(self, path, name, extention):
|
||||
""" Construct full file path to a file we generate. """
|
||||
return os.path.join(path, self._full_name(name, extention))
|
||||
|
||||
def get_default_source_plugin(self):
|
||||
"""
|
||||
The default source plugin i.e. the plugin that's consulted for
|
||||
overall image generation tasks outside of any particular
|
||||
partition. For convenience, we just hang it off the
|
||||
bootloader handler since it's the one non-partition object in
|
||||
any setup. By default the default plugin is set to the same
|
||||
plugin as the /boot partition; since we hang it off the
|
||||
bootloader object, the default can be explicitly set using the
|
||||
--source bootloader param.
|
||||
"""
|
||||
return self.ks.bootloader.source
|
||||
|
||||
#
|
||||
# Actual implemention
|
||||
#
|
||||
def create(self):
|
||||
"""
|
||||
For 'wic', we already have our build artifacts - we just create
|
||||
filesystems from the artifacts directly and combine them into
|
||||
a partitioned image.
|
||||
"""
|
||||
parts = self._get_parts()
|
||||
|
||||
self._image = Image(self.native_sysroot)
|
||||
|
||||
disk_ids = {}
|
||||
for num, part in enumerate(parts, 1):
|
||||
# as a convenience, set source to the boot partition source
|
||||
# instead of forcing it to be set via bootloader --source
|
||||
if not self.ks.bootloader.source and part.mountpoint == "/boot":
|
||||
self.ks.bootloader.source = part.source
|
||||
|
||||
# generate parition UUIDs
|
||||
if not part.uuid and part.use_uuid:
|
||||
if self.ptable_format == 'gpt':
|
||||
part.uuid = str(uuid.uuid4())
|
||||
else: # msdos partition table
|
||||
if part.disk not in disk_ids:
|
||||
disk_ids[part.disk] = int.from_bytes(os.urandom(4), 'little')
|
||||
disk_id = disk_ids[part.disk]
|
||||
part.uuid = '%0x-%02d' % (disk_id, self._get_part_num(num, parts))
|
||||
|
||||
fstab_path = self._write_fstab(self.rootfs_dir.get("ROOTFS_DIR"))
|
||||
|
||||
for part in parts:
|
||||
# get rootfs size from bitbake variable if it's not set in .ks file
|
||||
if not part.size:
|
||||
# and if rootfs name is specified for the partition
|
||||
image_name = self.rootfs_dir.get(part.rootfs_dir)
|
||||
if image_name and os.path.sep not in image_name:
|
||||
# Bitbake variable ROOTFS_SIZE is calculated in
|
||||
# Image._get_rootfs_size method from meta/lib/oe/image.py
|
||||
# using IMAGE_ROOTFS_SIZE, IMAGE_ROOTFS_ALIGNMENT,
|
||||
# IMAGE_OVERHEAD_FACTOR and IMAGE_ROOTFS_EXTRA_SPACE
|
||||
rsize_bb = get_bitbake_var('ROOTFS_SIZE', image_name)
|
||||
if rsize_bb:
|
||||
part.size = int(round(float(rsize_bb)))
|
||||
# need to create the filesystems in order to get their
|
||||
# sizes before we can add them and do the layout.
|
||||
# Image.create() actually calls __format_disks() to create
|
||||
# the disk images and carve out the partitions, then
|
||||
# self.assemble() calls Image.assemble() which calls
|
||||
# __write_partitition() for each partition to dd the fs
|
||||
# into the partitions.
|
||||
part.prepare(self, self.workdir, self.oe_builddir, self.rootfs_dir,
|
||||
self.bootimg_dir, self.kernel_dir, self.native_sysroot)
|
||||
|
||||
|
||||
self._image.add_partition(part.disk_size,
|
||||
part.disk,
|
||||
part.mountpoint,
|
||||
part.source_file,
|
||||
part.fstype,
|
||||
part.label,
|
||||
fsopts=part.fsopts,
|
||||
boot=part.active,
|
||||
align=part.align,
|
||||
no_table=part.no_table,
|
||||
part_type=part.part_type,
|
||||
uuid=part.uuid,
|
||||
system_id=part.system_id)
|
||||
|
||||
if fstab_path:
|
||||
shutil.move(fstab_path + ".orig", fstab_path)
|
||||
|
||||
self._image.layout_partitions(self.ptable_format)
|
||||
|
||||
for disk_name, disk in self._image.disks.items():
|
||||
full_path = self._full_path(self.workdir, disk_name, "direct")
|
||||
msger.debug("Adding disk %s as %s with size %s bytes" \
|
||||
% (disk_name, full_path, disk['min_size']))
|
||||
disk_obj = DiskImage(full_path, disk['min_size'])
|
||||
#self._disks[disk_name] = disk_obj
|
||||
self._image.add_disk(disk_name, disk_obj, disk_ids.get(disk_name))
|
||||
|
||||
self._image.create()
|
||||
|
||||
def assemble(self):
|
||||
"""
|
||||
Assemble partitions into disk image(s)
|
||||
"""
|
||||
for disk_name, disk in self._image.disks.items():
|
||||
full_path = self._full_path(self.workdir, disk_name, "direct")
|
||||
msger.debug("Assembling disk %s as %s with size %s bytes" \
|
||||
% (disk_name, full_path, disk['min_size']))
|
||||
self._image.assemble(full_path)
|
||||
|
||||
def finalize(self):
|
||||
"""
|
||||
Finalize the disk image.
|
||||
|
||||
For example, prepare the image to be bootable by e.g.
|
||||
creating and installing a bootloader configuration.
|
||||
"""
|
||||
source_plugin = self.get_default_source_plugin()
|
||||
if source_plugin:
|
||||
self._source_methods = pluginmgr.get_source_plugin_methods(source_plugin, disk_methods)
|
||||
for disk_name, disk in self._image.disks.items():
|
||||
self._source_methods["do_install_disk"](disk, disk_name, self,
|
||||
self.workdir,
|
||||
self.oe_builddir,
|
||||
self.bootimg_dir,
|
||||
self.kernel_dir,
|
||||
self.native_sysroot)
|
||||
|
||||
for disk_name, disk in self._image.disks.items():
|
||||
full_path = self._full_path(self.workdir, disk_name, "direct")
|
||||
# Generate .bmap
|
||||
if self.bmap:
|
||||
msger.debug("Generating bmap file for %s" % disk_name)
|
||||
exec_native_cmd("bmaptool create %s -o %s.bmap" % (full_path, full_path),
|
||||
self.native_sysroot)
|
||||
# Compress the image
|
||||
if self.compressor:
|
||||
msger.debug("Compressing disk %s with %s" % (disk_name, self.compressor))
|
||||
exec_cmd("%s %s" % (self.compressor, full_path))
|
||||
|
||||
def print_outimage_info(self):
|
||||
"""
|
||||
Print the image(s) and artifacts used, for the user.
|
||||
"""
|
||||
msg = "The new image(s) can be found here:\n"
|
||||
|
||||
parts = self._get_parts()
|
||||
|
||||
for disk_name in self._image.disks:
|
||||
extension = "direct" + {"gzip": ".gz",
|
||||
"bzip2": ".bz2",
|
||||
"xz": ".xz",
|
||||
"": ""}.get(self.compressor)
|
||||
full_path = self._full_path(self.outdir, disk_name, extension)
|
||||
msg += ' %s\n\n' % full_path
|
||||
|
||||
msg += 'The following build artifacts were used to create the image(s):\n'
|
||||
for part in parts:
|
||||
if part.rootfs_dir is None:
|
||||
continue
|
||||
if part.mountpoint == '/':
|
||||
suffix = ':'
|
||||
else:
|
||||
suffix = '["%s"]:' % (part.mountpoint or part.label)
|
||||
msg += ' ROOTFS_DIR%s%s\n' % (suffix.ljust(20), part.rootfs_dir)
|
||||
|
||||
msg += ' BOOTIMG_DIR: %s\n' % self.bootimg_dir
|
||||
msg += ' KERNEL_DIR: %s\n' % self.kernel_dir
|
||||
msg += ' NATIVE_SYSROOT: %s\n' % self.native_sysroot
|
||||
|
||||
msger.info(msg)
|
||||
|
||||
@property
|
||||
def rootdev(self):
|
||||
"""
|
||||
Get root device name to use as a 'root' parameter
|
||||
in kernel command line.
|
||||
|
||||
Assume partition order same as in wks
|
||||
"""
|
||||
parts = self._get_parts()
|
||||
for num, part in enumerate(parts, 1):
|
||||
if part.mountpoint == "/":
|
||||
if part.uuid:
|
||||
return "PARTUUID=%s" % part.uuid
|
||||
else:
|
||||
suffix = 'p' if part.disk.startswith('mmcblk') else ''
|
||||
pnum = self._get_part_num(num, parts)
|
||||
return "/dev/%s%s%-d" % (part.disk, suffix, pnum)
|
||||
|
||||
def cleanup(self):
|
||||
if self._image:
|
||||
try:
|
||||
self._image.cleanup()
|
||||
except ImageError as err:
|
||||
msger.warning("%s" % err)
|
||||
|
||||
# Move results to the output dir
|
||||
if not os.path.exists(self.outdir):
|
||||
os.makedirs(self.outdir)
|
||||
|
||||
for fname in os.listdir(self.workdir):
|
||||
path = os.path.join(self.workdir, fname)
|
||||
if os.path.isfile(path):
|
||||
shutil.move(path, os.path.join(self.outdir, fname))
|
||||
|
||||
# remove work directory
|
||||
shutil.rmtree(self.workdir, ignore_errors=True)
|
||||
|
||||
|
|
Loading…
Reference in New Issue