aboutsummaryrefslogtreecommitdiff
path: root/linaro_image_tools/media_create/boards.py
diff options
context:
space:
mode:
authorMilo Casagrande <milo@ubuntu.com>2012-12-05 14:01:06 +0100
committerMilo Casagrande <milo@ubuntu.com>2012-12-05 14:01:06 +0100
commite6908f12a8ae63e50faa15ec874c1276ed105ea8 (patch)
tree0545538b3e1c30151b92619898d3ee0a723e360e /linaro_image_tools/media_create/boards.py
parent279fda8e1167c5ec5aa1b80069d70c508a1c0997 (diff)
Refactored HardwarepackHandler class, moved under the hwpack package, fixed tests.
Diffstat (limited to 'linaro_image_tools/media_create/boards.py')
-rw-r--r--linaro_image_tools/media_create/boards.py266
1 files changed, 2 insertions, 264 deletions
diff --git a/linaro_image_tools/media_create/boards.py b/linaro_image_tools/media_create/boards.py
index ff939e0..fb4637d 100644
--- a/linaro_image_tools/media_create/boards.py
+++ b/linaro_image_tools/media_create/boards.py
@@ -31,13 +31,8 @@ import re
import tempfile
import struct
from binascii import crc32
-import tarfile
-import ConfigParser
-import shutil
import string
import logging
-from linaro_image_tools.hwpack.config import Config
-from linaro_image_tools.hwpack.builder import PackageUnpacker
from parted import Device
@@ -45,7 +40,8 @@ from linaro_image_tools import cmd_runner
from linaro_image_tools.media_create.partitions import (
partition_mounted, SECTOR_SIZE, register_loopback)
-from StringIO import StringIO
+
+from linaro_image_tools.hwpack.handler import HardwarepackHandler
logger = logging.getLogger(__name__)
@@ -115,264 +111,6 @@ class classproperty(object):
return self.getter(cls)
-class HardwarepackHandler(object):
- FORMAT_1 = '1.0'
- FORMAT_2 = '2.0'
- FORMAT_3 = '3.0'
- FORMAT_MIXED = '1.0and2.0'
- metadata_filename = 'metadata'
- format_filename = 'FORMAT'
- main_section = 'main'
- hwpack_tarfiles = []
- tempdir = None
-
- def __init__(self, hwpacks, bootloader=None, board=None):
- self.hwpacks = hwpacks
- self.hwpack_tarfiles = []
- self.bootloader = bootloader
- self.board = board
- self.tempdirs = {}
- # Used to store the config created from the metadata.
- self.config = None
-
- class FakeSecHead(object):
- """ Add a fake section header to the metadata file.
-
- This is done so we can use ConfigParser to parse the file.
- """
- def __init__(self, fp):
- self.fp = fp
- self.sechead = '[%s]\n' % HardwarepackHandler.main_section
-
- def readline(self):
- if self.sechead:
- try:
- return self.sechead
- finally:
- self.sechead = None
- else:
- return self.fp.readline()
-
- def __enter__(self):
- self.tempdir = tempfile.mkdtemp()
- for hwpack in self.hwpacks:
- hwpack_tarfile = tarfile.open(hwpack, mode='r:gz')
- self.hwpack_tarfiles.append(hwpack_tarfile)
- return self
-
- def __exit__(self, type, value, traceback):
- for hwpack_tarfile in self.hwpack_tarfiles:
- if hwpack_tarfile is not None:
- hwpack_tarfile.close()
- self.hwpack_tarfiles = []
- if self.tempdir is not None and os.path.exists(self.tempdir):
- shutil.rmtree(self.tempdir)
-
- for name in self.tempdirs:
- tempdir = self.tempdirs[name]
- if tempdir is not None and os.path.exists(tempdir):
- shutil.rmtree(tempdir)
-
- def _get_config_from_metadata(self, metadata):
- """
- Retrieves a Config object associated with the metadata.
-
- :param metadata: The metadata to parse.
- :return: A Config instance.
- """
- if not self.config:
- lines = metadata.readlines()
- if re.search("=", lines[0]) and not re.search(":", lines[0]):
- # Probably V2 hardware pack without [hwpack] on the first line
- lines = ["[hwpack]\n"] + lines
- self.config = Config(StringIO("".join(lines)))
- self.config.set_board(self.board)
- self.config.set_bootloader(self.bootloader)
- return self.config
-
- def get_field(self, field, return_keys=False):
- data = None
- hwpack_with_data = None
- keys = None
- for hwpack_tarfile in self.hwpack_tarfiles:
- metadata = hwpack_tarfile.extractfile(self.metadata_filename)
- parser = self._get_config_from_metadata(metadata)
- try:
- new_data = parser.get_option(field)
- if new_data is not None:
- assert data is None, "The metadata field '%s' is set to " \
- "'%s' and new value '%s' is found" % (field, data,
- new_data)
- data = new_data
- hwpack_with_data = hwpack_tarfile
- if return_keys:
- keys = parser.get_last_used_keys()
- except ConfigParser.NoOptionError:
- continue
-
- if return_keys:
- return data, hwpack_with_data, keys
- return data, hwpack_with_data
-
- def get_format(self):
- format = None
- supported_formats = [self.FORMAT_1, self.FORMAT_2, self.FORMAT_3]
- for hwpack_tarfile in self.hwpack_tarfiles:
- format_file = hwpack_tarfile.extractfile(self.format_filename)
- format_string = format_file.read().strip()
- if not format_string in supported_formats:
- raise AssertionError(
- "Format version '%s' is not supported." % format_string)
- if format is None:
- format = format_string
- elif format != format_string:
- return self.FORMAT_MIXED
- return format
-
- def get_file(self, file_alias):
- """Get file(s) from a hwpack.
- :param file_alias: Property name (not field name) which contains
- file reference(s)
- :return: path to a file or list of paths to files
- """
- file_names, hwpack_tarfile, keys = self.get_field(file_alias,
- return_keys=True)
- if not file_names:
- return file_names
- single = False
- if not isinstance(file_names, list):
- single = True
- file_names = [file_names]
- out_files = []
-
- # Depending on if board and/or bootloader were used to look up the
- # file we are getting, we need to prepend those names to the path
- # to get the correct extracted file from the hardware pack.
- config_names = [("board", "boards"), ("bootloader", "bootloaders")]
- base_path = ""
- if keys:
- # If keys is non-empty, we have a V3 config option that was
- # modified by the bootloader and/or boot option...
- for name, key in config_names:
- if self.get_field(name):
- value = self.get_field(name)[0]
- if keys[0] == key:
- base_path = os.path.join(base_path, value)
- keys = keys[1:]
-
- for f in file_names:
- # Check that the base path is needed. If the file doesn't exist,
- # try without it (this provides fallback to V2 style directory
- # layouts with a V3 config).
- path_inc_board_and_bootloader = os.path.join(base_path, f)
- if path_inc_board_and_bootloader in hwpack_tarfile.getnames():
- f = path_inc_board_and_bootloader
- hwpack_tarfile.extract(f, self.tempdir)
- f = os.path.join(self.tempdir, f)
- out_files.append(f)
- if single:
- return out_files[0]
- return out_files
-
- def list_packages(self):
- """Return list of (package names, TarFile object containing them)"""
- packages = []
- for tf in self.hwpack_tarfiles:
- for name in tf.getnames():
- if name.startswith("pkgs/") and name.endswith(".deb"):
- packages.append((tf, name))
- return packages
-
- def find_package_for(self, name, version=None, revision=None,
- architecture=None):
- """Find a package that matches the name, version, rev and arch given.
-
- Packages are named according to the debian specification:
- http://www.debian.org/doc/manuals/debian-faq/ch-pkg_basics.en.html
- <name>_<Version>-<DebianRevisionNumber>_<DebianArchitecture>.deb
- DebianRevisionNumber seems to be optional.
- Use this spec to return a package matching the requirements given.
- """
- for tar_file, package in self.list_packages():
- file_name = os.path.basename(package)
- dpkg_chunks = re.search("^(.+)_(.+)_(.+)\.deb$",
- file_name)
- assert dpkg_chunks, "Could not split package file name into"\
- "<name>_<Version>_<DebianArchitecture>.deb"
-
- pkg_name = dpkg_chunks.group(1)
- pkg_version = dpkg_chunks.group(2)
- pkg_architecture = dpkg_chunks.group(3)
-
- ver_chunks = re.search("^(.+)-(.+)$", pkg_version)
- if ver_chunks:
- pkg_version = ver_chunks.group(1)
- pkg_revision = ver_chunks.group(2)
- else:
- pkg_revision = None
-
- if name != pkg_name:
- continue
- if version != None and str(version) != pkg_version:
- continue
- if revision != None and str(revision) != pkg_revision:
- continue
- if (architecture != None and
- str(architecture) != pkg_architecture):
- continue
-
- # Got a matching package - return its path inside the tarball
- return tar_file, package
-
- # Failed to find a matching package - return None
- return None
-
- def get_file_from_package(self, file_path, package_name,
- package_version=None, package_revision=None,
- package_architecture=None):
- """Extract named file from package specified by name, ver, rev, arch.
-
- File is extracted from the package matching the given specification
- to a temporary directory. The absolute path to the extracted file is
- returned.
- """
-
- package_info = self.find_package_for(package_name,
- package_version,
- package_revision,
- package_architecture)
- if package_info is None:
- return None
- tar_file, package = package_info
-
- # Avoid unpacking hardware pack more than once by assigning each one
- # its own tempdir to unpack into.
- # TODO: update logic that uses self.tempdir so we can get rid of this
- # by sharing nicely.
- if not package in self.tempdirs:
- self.tempdirs[package] = tempfile.mkdtemp()
- tempdir = self.tempdirs[package]
-
- # We extract everything in the hardware pack so we don't have to worry
- # about chasing links (extract a link, find where it points to, extract
- # that...). This is slower, but more reliable.
- tar_file.extractall(tempdir)
- package_path = os.path.join(tempdir, package)
-
- with PackageUnpacker() as self.package_unpacker:
- extracted_file = self.package_unpacker.get_file(package_path,
- file_path)
- after_tmp = re.sub(self.package_unpacker.tempdir, "",
- extracted_file).lstrip("/\\")
- extract_dir = os.path.join(tempdir, "extracted",
- os.path.dirname(after_tmp))
- os.makedirs(extract_dir)
- shutil.move(extracted_file, extract_dir)
- extracted_file = os.path.join(extract_dir,
- os.path.basename(extracted_file))
- return extracted_file
-
-
class BoardConfig(object):
board = None
"""The configuration used when building an image for a board."""