diff --git a/build-tests/x86/tumbleweed/test-image-live/appliance.kiwi b/build-tests/x86/tumbleweed/test-image-live/appliance.kiwi
index f713e7c57d4..c41a35f068d 100644
--- a/build-tests/x86/tumbleweed/test-image-live/appliance.kiwi
+++ b/build-tests/x86/tumbleweed/test-image-live/appliance.kiwi
@@ -14,6 +14,7 @@
+
1.42.3
@@ -31,6 +32,11 @@
+
+
+
+
+
@@ -50,7 +56,7 @@
-
+
@@ -58,6 +64,7 @@
+
diff --git a/build-tests/x86/tumbleweed/test-image-live/config.sh b/build-tests/x86/tumbleweed/test-image-live/config.sh
index 1bd6f33a453..607183c193e 100644
--- a/build-tests/x86/tumbleweed/test-image-live/config.sh
+++ b/build-tests/x86/tumbleweed/test-image-live/config.sh
@@ -1,39 +1,26 @@
#!/bin/bash
-#================
-# FILE : config.sh
-#----------------
-# PROJECT : OpenSuSE KIWI Image System
-# COPYRIGHT : (c) 2006 SUSE LINUX Products GmbH. All rights reserved
-# :
-# AUTHOR : Marcus Schaefer
-# :
-# BELONGS TO : Operating System images
-# :
-# DESCRIPTION : configuration script for SUSE based
-# : operating systems
-#----------------
-#======================================
-# Functions...
-#--------------------------------------
-test -f /.kconfig && . /.kconfig
-test -f /.profile && . /.profile
+
+set -ex
+
+declare kiwi_profiles=${kiwi_profiles}
+declare kiwi_iname=${kiwi_iname}
#======================================
# Greeting...
#--------------------------------------
echo "Configure image: [$kiwi_iname]..."
-#======================================
-# Setup baseproduct link
-#--------------------------------------
-suseSetupProduct
-
#======================================
# Activate services
#--------------------------------------
-suseInsertService sshd
+systemctl enable sshd
#======================================
-# Setup default target, multi-user
+# Include erofs module
#--------------------------------------
-baseSetRunlevel 3
+for profile in ${kiwi_profiles//,/ }; do
+ if [ "${profile}" = "EroFS" ]; then
+ # remove from blacklist
+ rm -f /usr/lib/modprobe.d/60-blacklist_fs-erofs.conf
+ fi
+done
diff --git a/kiwi/builder/filesystem.py b/kiwi/builder/filesystem.py
index 1bc53a67479..34b6b42d0f4 100644
--- a/kiwi/builder/filesystem.py
+++ b/kiwi/builder/filesystem.py
@@ -89,7 +89,7 @@ def __init__(
self.blocksize = xml_state.build_type.get_target_blocksize()
self.filesystem_setup = FileSystemSetup(xml_state, root_dir)
self.filesystems_no_device_node = [
- 'squashfs'
+ 'squashfs', 'erofs'
]
self.luks = xml_state.get_luks_credentials()
self.result = Result(xml_state)
diff --git a/kiwi/builder/live.py b/kiwi/builder/live.py
index 9be04d0a14d..f87a0d59bef 100644
--- a/kiwi/builder/live.py
+++ b/kiwi/builder/live.py
@@ -246,7 +246,7 @@ def create(self) -> Result:
filesystem_setup = FileSystemSetup(
self.xml_state, self.root_dir
)
- if root_filesystem != 'squashfs':
+ if root_filesystem not in ['squashfs', 'erofs']:
# Create a filesystem image of the specified type
# and put it into a SquashFS container
root_image = Temporary().new_file()
@@ -302,13 +302,13 @@ def create(self) -> Result:
else:
# Put the root filesystem into SquashFS directly
with FileSystem.new(
- name='squashfs',
+ name=root_filesystem,
device_provider=DeviceProvider(),
root_dir=self.root_dir + os.sep,
custom_args={
'compression':
self.xml_state.build_type.get_squashfscompression()
- }
+ } if root_filesystem == 'squashfs' else {'compression': ''}
) as live_container_image:
container_image = Temporary().new_file()
live_container_image.create_on_file(
@@ -316,6 +316,12 @@ def create(self) -> Result:
)
Path.create(self.media_dir.name + '/LiveOS')
os.chmod(container_image.name, 0o644)
+ # Note: we keep the filename of the read-only image as it is
+ # even if another read-only filesystem not matching this
+ # filename is used. This is because the following filename
+ # is also used in the initrd code for the kiwi-live and
+ # dmsquash dracut modules. The name can be overwritten
+ # with the rd.live.squashimg boot option though.
shutil.copy(
container_image.name,
self.media_dir.name + '/LiveOS/squashfs.img'
diff --git a/kiwi/defaults.py b/kiwi/defaults.py
index 0deb1707c5f..7539f5c91a9 100644
--- a/kiwi/defaults.py
+++ b/kiwi/defaults.py
@@ -1523,7 +1523,7 @@ def get_filesystem_image_types():
"""
return [
'ext2', 'ext3', 'ext4', 'btrfs', 'squashfs',
- 'xfs', 'fat16', 'fat32'
+ 'xfs', 'fat16', 'fat32', 'erofs'
]
@staticmethod
diff --git a/kiwi/filesystem/__init__.py b/kiwi/filesystem/__init__.py
index 067048cc32f..3adfbc3d977 100644
--- a/kiwi/filesystem/__init__.py
+++ b/kiwi/filesystem/__init__.py
@@ -54,7 +54,8 @@ def new(
'fat16': 'Fat16',
'fat32': 'Fat32',
'squashfs': 'SquashFs',
- 'swap': 'Swap'
+ 'swap': 'Swap',
+ 'erofs': 'EroFs'
}
try:
filesystem = importlib.import_module(
diff --git a/kiwi/filesystem/erofs.py b/kiwi/filesystem/erofs.py
new file mode 100644
index 00000000000..c421680163a
--- /dev/null
+++ b/kiwi/filesystem/erofs.py
@@ -0,0 +1,57 @@
+# Copyright (c) 2024 SUSE Software Solutions Germany GmbH. All rights reserved.
+#
+# This file is part of kiwi.
+#
+# kiwi is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# kiwi 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 kiwi. If not, see
+#
+from typing import List
+
+# project
+from kiwi.filesystem.base import FileSystemBase
+from kiwi.command import Command
+
+
+class FileSystemEroFs(FileSystemBase):
+ """
+ **Implements creation of erofs filesystem**
+ """
+ def create_on_file(
+ self, filename, label: str = None, exclude: List[str] = None
+ ):
+ """
+ Create erofs filesystem from data tree
+
+ :param string filename: result file path name
+ :param string label: volume label
+ :param list exclude: list of exclude dirs/files
+ """
+ self.filename = filename
+ exclude_options = []
+ # compression = self.custom_args.get('compression')
+
+ if exclude:
+ for item in exclude:
+ exclude_options.append(f'--exclude-regex={item}')
+
+ if label:
+ self.custom_args['create_options'].append('-L')
+ self.custom_args['create_options'].append(label)
+
+ Command.run(
+ [
+ 'mkfs.erofs'
+ ] + self.custom_args['create_options'] + exclude_options + [
+ self.filename, self.root_dir
+ ]
+ )
diff --git a/kiwi/schema/kiwi.rnc b/kiwi/schema/kiwi.rnc
index cb39f22eaf8..37f7e274123 100644
--- a/kiwi/schema/kiwi.rnc
+++ b/kiwi/schema/kiwi.rnc
@@ -1671,7 +1671,7 @@ div {
k.type.filesystem.attribute =
## Specifies the root filesystem type
attribute filesystem {
- "btrfs" | "ext2" | "ext3" | "ext4" | "squashfs" | "xfs"
+ "btrfs" | "ext2" | "ext3" | "ext4" | "squashfs" | "erofs" | "xfs"
}
>> sch:pattern [ id = "filesystem" is-a = "image_type"
sch:param [ name = "attr" value = "filesystem" ]
@@ -1958,7 +1958,7 @@ div {
## Specifies the image type
attribute image {
"btrfs" | "cpio" | "docker" | "ext2" | "ext3" |
- "ext4" | "iso" | "oem" | "pxe" | "kis" | "squashfs" | "tbz" |
+ "ext4" | "iso" | "oem" | "pxe" | "kis" | "squashfs" | "erofs" | "tbz" |
"xfs" | "oci" | "appx" | "enclave"
}
>> sch:pattern [
diff --git a/kiwi/schema/kiwi.rng b/kiwi/schema/kiwi.rng
index 9988bac5f4c..439693e45a0 100644
--- a/kiwi/schema/kiwi.rng
+++ b/kiwi/schema/kiwi.rng
@@ -2435,6 +2435,7 @@ structure
ext3
ext4
squashfs
+ erofs
xfs
@@ -2822,6 +2823,7 @@ initrd architecture.
pxe
kis
squashfs
+ erofs
tbz
xfs
oci
diff --git a/package/python-kiwi-spec-template b/package/python-kiwi-spec-template
index 40f0425c728..0cd8fb26392 100644
--- a/package/python-kiwi-spec-template
+++ b/package/python-kiwi-spec-template
@@ -291,10 +291,14 @@ Provides: kiwi-filesystem:ext3
Provides: kiwi-filesystem:ext4
Provides: kiwi-filesystem:squashfs
Provides: kiwi-filesystem:xfs
+Provides: kiwi-filesystem:erofs
%endif
Requires: dosfstools
Requires: e2fsprogs
Requires: xfsprogs
+%if ! (0%{?suse_version} && 0%{?suse_version} < 1600)
+Requires: erofs-utils
+%endif
%if 0%{?suse_version}
Requires: btrfsprogs
%else
diff --git a/test/unit/filesystem/erofs_test.py b/test/unit/filesystem/erofs_test.py
new file mode 100644
index 00000000000..ea3db9a2efd
--- /dev/null
+++ b/test/unit/filesystem/erofs_test.py
@@ -0,0 +1,36 @@
+from unittest.mock import patch
+
+import unittest.mock as mock
+
+from kiwi.defaults import Defaults
+from kiwi.filesystem.erofs import FileSystemEroFs
+
+
+class TestFileSystemEroFs:
+ @patch('os.path.exists')
+ def setup(self, mock_exists):
+ mock_exists.return_value = True
+ self.erofs = FileSystemEroFs(mock.Mock(), 'root_dir')
+
+ @patch('os.path.exists')
+ def setup_method(self, cls, mock_exists):
+ self.setup()
+
+ @patch('kiwi.filesystem.erofs.Command.run')
+ def test_create_on_file(self, mock_command):
+ Defaults.set_platform_name('x86_64')
+ self.erofs.create_on_file('myimage', 'label')
+ mock_command.assert_called_once_with(
+ ['mkfs.erofs', '-L', 'label', 'myimage', 'root_dir']
+ )
+
+ @patch('kiwi.filesystem.erofs.Command.run')
+ def test_create_on_file_exclude_data(self, mock_command):
+ Defaults.set_platform_name('x86_64')
+ self.erofs.create_on_file('myimage', 'label', ['foo'])
+ mock_command.assert_called_once_with(
+ [
+ 'mkfs.erofs', '-L', 'label',
+ '--exclude-regex=foo', 'myimage', 'root_dir'
+ ]
+ )