Write Your OS =================== Basic Concepts -------------- Once you followed the :doc:`setup` to prepare your environment, then you're ready to write your fist OS. First of all, lets start from a basic building block: .. code-block:: python from lbhelper import build_image from lbhelper import UpstreamPackages gnome_desktop_packages = UpstreamPackages( packages=[ "dconf-editor", "task-gnome-desktop", "task-english", ], package_set_code="desktop", ) targets = [ gnome_desktop_packages ] if __name__ == '__main__': build_image(targets=targets, iso_build_dir=Path("build"), image_name="firstos") Here are things the sample code does: 1. Create a target, ``gnome_desktop_packages``, which define 3 upstream packages to install: ``dconf-editor``, ``task-gnome-desktop`` and ``task-english``. The *upstream* means packages to install are from the Debian official package repository. 2. Passing the target as parameter to the ``build_image`` to start build process. Once you run the code with :code:`python main.py` (assume your filename is ``main.py``): - A directory called ``build`` will be created. - The `auto` scripts and `config` will also be generated. - Build process will start(depends on your network and machine, it'll take 20-90 minutes to build) and logs will show on your terminal. - When build process finish, you can find an ISO image, ``firstos-amd64.hybrid.iso``, in the ``build`` directory. Now you can boot your first OS via hypervisors like Qemu or VirtualBox with this image. Utilities From lbhelper ----------------------- In addition to ``UpstreamPackages``, ``lbhelper`` also provides variety of utilities to configure image. Targets ^^^^^^^ The ``lbhelper`` provides the following targets: - :class:`UpstreamPackages ` - Packages to install from `Debian official package repository `__. The ``package_set_code`` decides package filename under the ``config/package-lists``. .. code-block:: python UpstreamPackages( packages=[ "dconf-editor", "task-gnome-desktop", "task-english", ], package_set_code="desktop", ) - :class:`CustomDeb ` - Custom ``.deb`` file to install. The ``get_deb`` should be a callback function to get file path, which makes file creation dynamic(e.g., download from internet). .. code-block:: python CustomDeb( get_deb=lambda: Path("path/to/deb.deb"), ) - :class:`HookScript ` - Hooks scripts to run after upstream/customdeb packages installed. The ``hook_name`` decides hook scripts filename under the ``config/hooks/*``. .. code-block:: python HookScript( get_script_file=lambda: Path("path/to/script.sh"), hook_name="somehook.sh" ) - :class:`StaticFile ` - Files to include in the binary stage. The ``target_filepath`` defines file path in built system, which will also be created with the same file path under ``config/includes.*/`` (e.g. ``/opt/some/file.txt`` ), .. code-block:: python StaticFile( get_source_file=lambda: Path("path/to/file") target_filepath=Path("/opt/some/file.txt") ) - :class:`AptPreference ` - Set package preferences for upstream packages. See https://live-team.pages.debian.net/live-manual/html/live-manual/customizing-package-installation.en.html#514 and https://linux.die.net/man/5/apt_preferences for more details. The ``preference_type`` denotes the preference should take effects at runtime (for built system, under ``config/apt/preferences``) or build time (for build process, under ``config/includes.chroot/etc/apt/preferences``). .. code-block:: python AptPreference( package="libroffice", pin="version *", pin_priority=-1, preference_type=AptPreferenceType.RUN_TIME ) - :class:`DirectConfig ` - If you have special requires which targets above cannot satisfy(i.e., customize bootloader), you can create config file under the build directly with this target. Use this target carefully as it might break/override other targets unintentionally. The ``target_filepath`` denotes file path under the build directory to write files. .. code-block:: python DirectConfig( target_filepath="config/path/to/direct/config", # file will be written to "${build_dir}/config/path/to/direct/config" get_source_file=lambda :source_file ) Note: Build stage follows orders described in :ref:`source/index:Build Process`. Carefully managing dependencies to avoid the situation like hook scripts rely files from binary stage. Also, though the orders of config depends on the order of targets passed to :func:`build_image `, please consider making targets idempotent to reduce complexity and avoid unintentional side effects. Build Image ^^^^^^^^^^^ The ``lbhelper`` provides an all-in-one function, :func:`build_image ` to turn targets into actual config files and start build process. Accepted parameters are: - targets – Targets to process. Elements can be ``Target`` or ``List[Target]``. - iso_build_dir – Image build directory path. - fresh_build – If ``True``, remove build directory before performing any operations for fresh build. - distribution – Base Debian distribution for image. ``trixie`` by default. - image_name – Name of image. ``myos`` by default. - skip_build – If ``True``, `lb build` won’t run. You can use this option to validate configs manually. Helper Functions ^^^^^^^^^^^^^^^^ The ``lbhelper`` also provides useful helper function to create scripts and files. - :func:`render_template_to_file ` - Render a `jinja2 `__ template as file. .. code-block:: python render_template_to_file( template_path=lambda: Path("path/to/template"), target_path=Path("some/path"), # if not given, then rendered file will be written to /tmp with random name. arg1="arg1", # args for template arg2="arg2", # args for template ) - :func:`render_template_to_string ` - Escape "\\" and "$". Useful when writing strings to files via shell scripts. For instance, when writing strings via: .. code-block:: shell cat > file<` - Download given URL as file under ``/tmp`` with random filename. .. code-block:: python discord_download_url = "https://discord.com/api/download?platform=linux" discord_deb = CustomDeb( get_deb=lambda : download_file(discord_download_url), ) Further Reading --------------- For more comprehensive example using utilities above, check `myos `__. For more detailed API documents, check :doc:`lbhelper`.