File: builder.py

package info (click to toggle)
freedom-maker 0.35
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 408 kB
  • sloc: python: 2,200; xml: 357; makefile: 10
file content (137 lines) | stat: -rw-r--r-- 4,488 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
# SPDX-License-Identifier: GPL-3.0-or-later
"""
Base worker class to run various commands that build the image.
"""

import logging
import os

from . import internal, library

BASE_PACKAGES = []

logger = logging.getLogger(__name__)  # pylint: disable=invalid-name


class ImageBuilder:  # pylint: disable=too-many-instance-attributes
    """Base for all image builders."""
    architecture: str | None = None
    machine: str = 'all'
    include_non_free_firmware: bool = False
    include_contrib: bool = False

    builder_backend: str = 'internal'
    partition_table_type: str = 'msdos'
    root_filesystem_type: str = 'btrfs'
    boot_filesystem_type: str | None = None
    boot_size: str | None = None
    efi_filesystem_type: str | None = None
    efi_size: str | None = None
    firmware_filesystem_type: str | None = None
    firmware_size: str | None = None
    kernel_flavor: str = 'default'
    debootstrap_variant: str | None = None

    @classmethod
    def get_target_name(cls):
        """Return the command line name of target for this builder."""
        return None

    @classmethod
    def get_builder_class(cls, target):
        """Return an builder class given target name."""
        from . import builders  # noqa: F401, pylint: disable=unused-variable

        for subclass in cls.get_subclasses():
            if subclass.get_target_name() == target:
                return subclass

        raise ValueError('No such target')

    @classmethod
    def get_subclasses(cls):
        """Iterate through the subclasses of this class."""
        for subclass in cls.__subclasses__():
            yield subclass
            yield from subclass.get_subclasses()

    def __init__(self, arguments):
        """Initialize object."""
        self.arguments = arguments
        self.packages = BASE_PACKAGES
        self.ram_directory = None

        self.builder_backends = {}
        self.builder_backends['internal'] = internal.InternalBuilderBackend(
            self)

        self.image_file = os.path.join(self.arguments.build_dir,
                                       self._get_image_base_name() + '.img')

    @property
    def image_size(self):
        """Return the size of the image to create based on CLI arguments."""
        return self.arguments.image_size

    @property
    def release_components(self):
        """Return the Debian release components to use for the build."""
        components = ['main']
        if self.include_non_free_firmware:
            components.append('non-free-firmware')

        if self.include_contrib:
            components.append('contrib')

        if self.arguments.release_component:
            for component in self.arguments.release_component:
                if component not in components:
                    components.append(component)

        return components

    def build(self):
        """Run the image building process."""
        archive_file = self.image_file + '.xz'
        self.make_image()
        self.compress(archive_file, self.image_file)

        self.sign(archive_file)

    def _get_builder_backend(self):
        """Returns the builder backend."""
        builder = self.builder_backend
        return self.builder_backends[builder]

    def make_image(self):
        """Call a builder backend to create basic image."""
        self._get_builder_backend().make_image()

    def _get_image_base_name(self):
        """Return the base file name of the final image."""
        build_stamp = self.arguments.build_stamp
        build_stamp = build_stamp + '_' if build_stamp else ''
        return 'freedombox-{distribution}_{build_stamp}{machine}' \
            '-{architecture}'.format(
                distribution=self.arguments.distribution,
                build_stamp=build_stamp, machine=self.machine,
                architecture=self.architecture)

    def compress(self, archive_file, image_file):
        """Compress the generated image."""
        if not self.arguments.skip_compression:
            library.compress(archive_file, image_file)
        else:
            logger.info('Skipping image compression')

    def sign(self, archive):
        """Sign the final output image."""
        if not self.arguments.sign:
            return

        library.sign(archive)

    @staticmethod
    def _replace_extension(file_name, new_extension):
        """Replace a file's extension with a new extention."""
        return file_name.rsplit('.', maxsplit=1)[0] + new_extension