Write Your OS¶
Basic Concepts¶
Once you followed the Setup And Installation to prepare your environment, then you’re ready to write your fist OS.
First of all, lets start from a basic building block:
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:
Create a target,
gnome_desktop_packages, which define 3 upstream packages to install:dconf-editor,task-gnome-desktopandtask-english. The upstream means packages to install are from the Debian official package repository.Passing the target as parameter to the
build_imageto start build process. Once you run the code withpython main.py(assume your filename ismain.py):
A directory called
buildwill 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 thebuilddirectory.
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:
UpstreamPackages- Packages to install from Debian official package repository. Thepackage_set_codedecides package filename under theconfig/package-lists.UpstreamPackages( packages=[ "dconf-editor", "task-gnome-desktop", "task-english", ], package_set_code="desktop", )
CustomDeb- Custom.debfile to install. Theget_debshould be a callback function to get file path, which makes file creation dynamic(e.g., download from internet).CustomDeb( get_deb=lambda: Path("path/to/deb.deb"), )
HookScript- Hooks scripts to run after upstream/customdeb packages installed. Thehook_namedecides hook scripts filename under theconfig/hooks/*.HookScript( get_script_file=lambda: Path("path/to/script.sh"), hook_name="somehook.sh" )
StaticFile- Files to include in the binary stage. Thetarget_filepathdefines file path in built system, which will also be created with the same file path underconfig/includes.*/(e.g./opt/some/file.txt),StaticFile( get_source_file=lambda: Path("path/to/file") target_filepath=Path("/opt/some/file.txt") )
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. Thepreference_typedenotes the preference should take effects at runtime (for built system, underconfig/apt/preferences) or build time (for build process, underconfig/includes.chroot/etc/apt/preferences).AptPreference( package="libroffice", pin="version *", pin_priority=-1, preference_type=AptPreferenceType.RUN_TIME )
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. Thetarget_filepathdenotes file path under the build directory to write files.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 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 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, build_image to turn targets into actual config files and start build process. Accepted parameters are:
targets – Targets to process. Elements can be
TargetorList[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.
trixieby default.image_name – Name of image.
myosby 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.
render_template_to_file- Render a jinja2 template as file.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 )
render_template_to_string <lbhelper.render_template_to_string()- Render a jinja2 template as string.render_template_to_string( template_path=lambda: Path("path/to/template"), arg1="arg1", arg2="arg2", )
escape_string_for_shell_script- Escape “\” and “$”. Useful when writing strings to files via shell scripts. For instance, when writing strings via:cat > file<<EOL $SOME_STRING EOL
The
\and$of$SOME_STRINGneed to be escaped. Otherwise, they’ll be treated as special characters from source script and cause unexpected results.download_file- Download given URL as file under/tmpwith random filename.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 lbhelper package.