Refactor GDM module to correspond SOLID principles

- I don't know how I will support this hell ahh code;
- Added some methods to gnome_shell_theme_builder.py;
- Added "color" property "install" method from theme_base.py.
This commit is contained in:
Vladyslav Hroshev
2025-04-12 23:30:34 +03:00
parent 48d10df4b1
commit ca4e4d4cbe
17 changed files with 674 additions and 202 deletions

View File

@@ -28,7 +28,7 @@ class AlternativesUpdater:
@staticmethod
@ubuntu_specific
def install_and_set(link: str, name: str, path: PathString, priority: int = 0):
def install_and_set(link: PathString, name: str, path: PathString, priority: int = 0):
AlternativesUpdater.install(link, name, path, priority)
AlternativesUpdater.set(name, path)

View File

View File

@@ -0,0 +1,88 @@
from scripts.types.theme_base import ThemeBase
from scripts.utils.global_theme.gdm_installer import GDMThemeInstaller
from scripts.utils.global_theme.gdm_preparer import GDMThemePreparer
from scripts.utils.global_theme.gdm_remover import GDMThemeRemover
from scripts.utils.global_theme.gdm_theme_prepare import GDMThemePrepare
class GDMTheme(ThemeBase):
"""
GDM theming module.
This module provides functionality to prepare, install, and remove GNOME Display Manager themes.
It follows a workflow of:
1. Preparing themes from existing GDM resources
2. Installing themes with custom colors/styles
3. Providing ability to restore original GDM themes
The main entry point is the GDMTheme class, which orchestrates the entire theme management process.
"""
def __init__(self, preparer: GDMThemePreparer, installer: GDMThemeInstaller, remover: GDMThemeRemover):
"""
:param preparer: GDMThemePreparer instance for preparing themes
:param installer: GDMThemeInstaller instance for installing themes
:param remover: GDMThemeRemover instance for removing themes
"""
self.preparer = preparer
self.installer = installer
self.remover = remover
self.themes: list[GDMThemePrepare] = []
def prepare(self):
"""
Prepare the theme for installation.
This method:
1. Checks if a theme is already installed and uses backup if needed
2. Extracts relevant theme files
3. Processes them into ready-to-compile GDMThemePrepare objects
The processed themes are stored in the themes attribute for later use.
"""
if self._is_installed():
self.preparer.use_backup_as_source()
self.themes = self.preparer.prepare()
def _is_installed(self) -> bool:
"""
Check if a GDM theme is currently installed.
This looks for specific markers in the system gresource files
that indicate our theme has been installed.
:return: True if a custom theme is installed, False otherwise
"""
return self.installer.is_installed()
def install(self, hue: int, name: str, sat: float | None = None):
"""
Install the prepared theme with specified color adjustments.
This method:
1. Compiles theme files with the specified hue and saturation
2. Creates a backup of the original GDM theme if one doesn't exist
3. Installs the compiled theme to the system
:param hue: The hue adjustment (0-360) to apply to the theme
:param name: The name of the theme to be installed. In GDM will only be shown in logger
:param sat: Optional saturation adjustment (0-100) to apply
"""
self.installer.compile(self.themes, hue, name, sat)
if not self._is_installed():
self.installer.backup()
self.installer.install()
def remove(self):
"""
Remove the installed theme and restore the original GDM theme.
If no theme is installed, displays a warning message to the user.
This will restore from backup and update GDM alternatives if needed.
"""
if self._is_installed():
self.remover.remove()
else:
self.remover.warn_not_installed()

View File

@@ -0,0 +1,168 @@
import os.path
from typing import Optional
from scripts import config
from scripts.install.colors_definer import ColorsDefiner
from scripts.types.installation_color import InstallationMode
from scripts.utils.alternatives_updater import AlternativesUpdater, PathString
from scripts.utils.command_runner.subprocess_command_runner import SubprocessCommandRunner
from scripts.utils.global_theme.gdm import GDMTheme
from scripts.utils.global_theme.gdm_installer import GDMThemeInstaller
from scripts.utils.global_theme.gdm_preparer import GDMThemePreparer
from scripts.utils.global_theme.gdm_remover import GDMThemeRemover
from scripts.utils.global_theme.ubuntu_alternatives_updater import UbuntuGDMAlternativesUpdater
from scripts.utils.gresource.gresource import Gresource
from scripts.utils.logger.console import Console
from scripts.utils.logger.logger import LoggerFactory
from scripts.utils.theme.gnome_shell_theme_builder import GnomeShellThemeBuilder
class GdmBuilder:
"""
Builder class for creating GDMTheme instances with configurable components.
This class follows the Builder pattern to create a GDMTheme with all necessary
dependencies. Dependencies can be injected via the with_* methods or will be
automatically resolved during build() if not provided.
Example usage:
builder = GdmBuilder(colors_provider)
theme = builder.with_mode("dark").with_filled(True).build()
"""
def __init__(self, colors_provider: ColorsDefiner):
"""
:param colors_provider: A provider for color definitions.
"""
self.colors_provider: ColorsDefiner = colors_provider
self._temp_folder: PathString = os.path.join(config.temp_folder, config.gdm_folder)
self._mode: Optional[InstallationMode] = None
self._is_filled: bool = False
self._logger_factory: Optional[LoggerFactory] = None
self._gresource: Optional[Gresource] = None
self._ubuntu_gdm_alternatives_updater: Optional[UbuntuGDMAlternativesUpdater] = None
self._preparer: Optional[GDMThemePreparer] = None
self._installer: Optional[GDMThemeInstaller] = None
self._remover: Optional[GDMThemeRemover] = None
def with_mode(self, mode: InstallationMode | None) -> 'GdmBuilder':
"""Set the mode for the theme."""
self._mode = mode
return self
def with_filled(self, is_filled=True) -> 'GdmBuilder':
"""Set the filled state for the theme."""
self._is_filled = is_filled
return self
def with_logger_factory(self, logger_factory: LoggerFactory) -> 'GdmBuilder':
"""Inject a logger factory for logging purposes."""
self._logger_factory = logger_factory
return self
def with_gresource(self, gresource: Gresource) -> 'GdmBuilder':
"""Inject a gresource instance for managing gresource files."""
self._gresource = gresource
return self
def with_ubuntu_gdm_alternatives_updater(self, alternatives_updater: UbuntuGDMAlternativesUpdater) -> 'GdmBuilder':
"""Inject an alternatives updater for managing GDM alternatives."""
self._ubuntu_gdm_alternatives_updater = alternatives_updater
return self
def with_preparer(self, preparer: GDMThemePreparer) -> 'GdmBuilder':
"""Inject a preparer for preparing the theme."""
self._preparer = preparer
return self
def with_installer(self, installer: GDMThemeInstaller) -> 'GdmBuilder':
"""Inject an installer for installing the theme."""
self._installer = installer
return self
def with_remover(self, remover: GDMThemeRemover) -> 'GdmBuilder':
"""Inject a remover for removing the theme."""
self._remover = remover
return self
def build(self) -> GDMTheme:
"""
Build the GDMTheme object with the configured components.
Automatically resolves any dependencies that haven't been explicitly
provided through with_* methods. The order of resolution ensures
that dependencies are created before they're needed.
:return: A fully configured GDMTheme instance ready for use
"""
self._resolve_logger_factory()
self._resolve_gresource()
self._resolve_ubuntu_gdm_alternatives_updater()
self._resolve_preparer()
self._resolve_installer()
self._resolve_remover()
return GDMTheme(self._preparer, self._installer, self._remover)
def _resolve_logger_factory(self):
"""Instantiate a default Console logger if not explicitly provided."""
if self._logger_factory: return
self._logger_factory = Console()
def _resolve_gresource(self):
"""
Create a Gresource handler if not explicitly provided.
Uses configuration values for file paths and destinations.
"""
if self._gresource: return
gresource_file = config.gnome_shell_gresource
temp_folder = os.path.join(self._temp_folder, config.extracted_gdm_folder)
destination = config.global_gnome_shell_theme
runner = SubprocessCommandRunner()
self._gresource = Gresource(
gresource_file=gresource_file,
temp_folder=temp_folder,
destination=destination,
logger_factory=self._logger_factory,
runner=runner
)
def _resolve_ubuntu_gdm_alternatives_updater(self):
"""Create an UbuntuGDMAlternativesUpdater if not explicitly provided."""
if self._ubuntu_gdm_alternatives_updater: return
alternatives_updater = AlternativesUpdater()
self._ubuntu_gdm_alternatives_updater = UbuntuGDMAlternativesUpdater(alternatives_updater)
def _resolve_preparer(self):
"""Create a GDMThemePreparer if not explicitly provided."""
if self._preparer: return
theme_builder = GnomeShellThemeBuilder(self.colors_provider)
self._preparer = GDMThemePreparer(
temp_folder=self._temp_folder,
default_mode=self._mode,
is_filled=self._is_filled,
gresource=self._gresource,
theme_builder=theme_builder,
logger_factory=self._logger_factory
)
def _resolve_installer(self):
"""Create a GDMThemeInstaller if not explicitly provided."""
if self._installer: return
self._installer = GDMThemeInstaller(
gresource=self._gresource,
alternatives_updater=self._ubuntu_gdm_alternatives_updater,
)
def _resolve_remover(self):
"""Create a GDMThemeRemover if not explicitly provided."""
if self._remover: return
self._remover = GDMThemeRemover(
gresource=self._gresource,
alternatives_updater=self._ubuntu_gdm_alternatives_updater,
logger_factory=self._logger_factory
)

View File

@@ -0,0 +1,66 @@
from scripts.utils.global_theme.gdm_theme_prepare import GDMThemePrepare
from scripts.utils.global_theme.ubuntu_alternatives_updater import UbuntuGDMAlternativesUpdater
from scripts.utils.gresource.gresource import Gresource
class GDMThemeInstaller:
"""
Handles the installation of GDM themes system-wide.
This class manages:
- Compiling prepared theme resources into a gresource file
- Creating backups of original system files
- Installing compiled themes via the alternatives system
- Detecting if a theme is already installed
"""
def __init__(self, gresource: Gresource, alternatives_updater: UbuntuGDMAlternativesUpdater):
"""
:param gresource: Handler for gresource operations
:param alternatives_updater: Handler for update-alternatives operations
"""
self.gresource = gresource
self.alternatives_updater = alternatives_updater
self._is_installed_trigger = "\n/* Marble theme */\n"
def is_installed(self) -> bool:
"""
Check if the theme is installed
by looking for the trigger in the gresource file.
"""
return self.gresource.has_trigger(self._is_installed_trigger)
def compile(self, themes: list[GDMThemePrepare], hue: int, color: str, sat: int = None):
"""
Prepares themes for gresource and compiles them.
:param themes: themes to be compiled
:param hue: hue value for the theme
:param color: the color name. in GDM will only be shown in logger
:param sat: saturation value for the theme
"""
self._generate_themes(themes, hue, color, sat)
self.gresource.compile()
def _generate_themes(self, themes: list[GDMThemePrepare], hue: int, color: str, sat: int = None):
"""Generate theme files for further compiling by gresource"""
for theme_prepare in themes:
if theme_prepare.label is not None:
theme_prepare.label_theme()
theme_prepare.remove_keywords("!important")
theme_prepare.remove_properties("background-color", "color", "box-shadow", "border-radius")
theme_prepare.prepend_source_styles(self._is_installed_trigger)
theme_prepare.install(hue, color, sat, destination=self.gresource.temp_folder)
def backup(self):
"""Backup the current gresource file."""
self.gresource.backup()
def install(self):
"""
Install the theme globally by moving the compiled gresource file to the destination.
Also updates the alternatives for the gdm theme.
"""
self.gresource.move()
self.alternatives_updater.install_and_set()

View File

@@ -0,0 +1,88 @@
import os
from scripts.utils.global_theme.gdm_theme_prepare import GDMThemePrepare
from scripts.utils.gresource.gresource import Gresource
from scripts.utils.logger.logger import LoggerFactory
from scripts.utils.theme.gnome_shell_theme_builder import GnomeShellThemeBuilder
class GDMThemePreparer:
"""
GDM theme preparation module.
This module contains classes responsible for extracting and processing
GDM theme resources for later compilation and installation.
The main class, GDMThemePreparer, orchestrates the extraction process
and creates GDMThemePrepare objects representing processable themes.
"""
def __init__(self, temp_folder: str, default_mode: str | None, is_filled: bool,
gresource: Gresource,
theme_builder: GnomeShellThemeBuilder,
logger_factory: LoggerFactory):
"""
:param temp_folder: Temporary folder for extracted theme files
:param default_mode: Default theme mode to use if not specified in CSS filename
:param is_filled: Whether to generate filled (True) or outlined (False) styles
:param gresource: Gresource instance for managing gresource files
:param theme_builder: Theme builder instance for creating themes
"""
self.temp_folder = temp_folder
self.gresource_temp_folder = gresource.temp_folder
self.default_mode = default_mode
self.is_filled = is_filled
self.gresource = gresource
self.theme_builder = theme_builder
self.logger_factory = logger_factory
def use_backup_as_source(self):
"""Use backup gresource file for extraction"""
self.gresource.use_backup_gresource()
self.logger_factory.create_logger().info("Using backup gresource file for extraction...")
def prepare(self) -> list[GDMThemePrepare]:
"""
Extract and prepare GDM themes for processing.
:return: List of prepared theme objects ready for compilation
"""
self.gresource.extract()
return self._find_themes()
def _find_themes(self) -> list[GDMThemePrepare]:
extracted_files = os.listdir(self.gresource_temp_folder)
allowed_css = {"gnome-shell-dark.css", "gnome-shell-light.css", "gnome-shell.css"}
themes = [
self._create_theme(file_name)
for file_name in extracted_files
if file_name in allowed_css
]
return themes
def _create_theme(self, file_name: str) -> GDMThemePrepare:
"""Helper to create and prepare a theme"""
mode = file_name.split("-")[-1].replace(".css", "")
mode = mode if mode in {"dark", "light"} else self.default_mode
self._setup_theme_builder(file_name, mode)
theme = self.theme_builder.build()
theme.prepare()
theme_file = os.path.join(self.gresource_temp_folder, file_name)
return GDMThemePrepare(theme=theme, theme_file=theme_file, label=mode)
def _setup_theme_builder(self, file_name: str, mode: str):
self.theme_builder.with_temp_folder(self.temp_folder)
theme_name = file_name.replace(".css", "")
(self.theme_builder
.with_temp_folder(self.temp_folder)
.with_theme_name(theme_name)
.with_mode(mode)
.filled(self.is_filled)
.with_logger_factory(self.logger_factory)
.with_reset_dependencies())

View File

@@ -0,0 +1,65 @@
from scripts.utils.global_theme.ubuntu_alternatives_updater import UbuntuGDMAlternativesUpdater
from scripts.utils.gresource import GresourceBackupNotFoundError
from scripts.utils.gresource.gresource import Gresource
from scripts.utils.logger.console import Console, Color, Format
from scripts.utils.logger.logger import LoggerFactory
class GDMThemeRemover:
"""
Responsible for safely removing installed GDM themes.
This class handles:
- Restoring original gresource files from backups
- Removing theme alternatives from the system
- Providing feedback about removal status
"""
def __init__(self,
gresource: Gresource,
alternatives_updater: UbuntuGDMAlternativesUpdater,
logger_factory: LoggerFactory):
"""
:param gresource: Handler for gresource operations
:param alternatives_updater: Handler for update-alternatives operations
:param logger_factory: Factory for creating loggers
"""
self.gresource = gresource
self.alternatives_updater = alternatives_updater
self.remover_logger = GDMRemoverLogger(logger_factory)
def remove(self):
"""Restores the gresource backup and removes the alternatives."""
self.remover_logger.start_removing()
try:
self.gresource.restore()
self.alternatives_updater.remove()
self.remover_logger.success_removing()
except GresourceBackupNotFoundError:
self.remover_logger.error_removing()
def warn_not_installed(self):
self.remover_logger.not_installed_warning()
class GDMRemoverLogger:
def __init__(self, logger_factory: LoggerFactory):
self.logger_factory = logger_factory
self.removing_line = None
def start_removing(self):
self.removing_line = self.logger_factory.create_logger()
self.removing_line.update("Theme is installed. Removing...")
def success_removing(self):
self.removing_line.success("Global theme removed successfully. Restart GDM to apply changes.")
def error_removing(self):
formatted_shell = Console.format("gnome-shell", color=Color.BLUE, format_type=Format.BOLD)
self.removing_line.error(f"Backup file not found. Try reinstalling {formatted_shell} package.")
def not_installed_warning(self):
self.logger_factory.create_logger().error(
"Theme is not installed. Nothing to remove.")
self.logger_factory.create_logger().warn(
"If theme is still installed globally, try reinstalling gnome-shell package.")

View File

@@ -0,0 +1,66 @@
from scripts.utils import remove_keywords, remove_properties
from scripts.utils.files_labeler import FilesLabeler
from scripts.utils.theme.theme import Theme
class GDMThemePrepare:
"""
Prepares theme files for installation into the GDM system.
This class handles:
- Theme file labeling for dark/light variants
- CSS property and keyword removal for customization
- Theme installation with color adjustments
"""
def __init__(self, theme: Theme, theme_file: str, label: str = None):
"""
:param theme: The theme object to prepare
:param theme_file: Path to the original decompiled CSS file
:param label: Optional label for the theme (e.g. "dark", "light")
"""
self.theme = theme
self.theme_file = theme_file
self.label = label
def label_theme(self):
"""
Label the theme files if the label is set.
Also updates references in the theme files.
:raises ValueError: if the label is not set
"""
if self.label is None:
raise ValueError("Label is not set for the theme.")
files_labeler = FilesLabeler(self.theme.temp_folder, self.theme.main_styles)
files_labeler.append_label(self.label)
def remove_keywords(self, *args: str):
"""Remove specific keywords from the theme file"""
remove_keywords(self.theme_file, *args)
def remove_properties(self, *args: str):
"""Remove specific properties from the theme file"""
remove_properties(self.theme_file, *args)
def prepend_source_styles(self, trigger: str):
"""
Add source styles and installation trigger to the theme file.
This adds original theme styles and a marker that identifies
the theme as installed by this application.
:param trigger: String marker used to identify installed themes
"""
with open(self.theme_file, 'r') as gnome_theme:
gnome_styles = gnome_theme.read() + trigger
self.theme.add_to_start(gnome_styles)
def install(self, hue: int, color: str, sat: int | None, destination: str):
"""
Install the theme to the specified destination
:param hue: Hue value for the theme
:param color: Color name for the theme
:param sat: Saturation value for the theme
:param destination: Destination folder for the theme
"""
self.theme.install(hue, color, sat, destination=destination)

View File

@@ -0,0 +1,65 @@
import os.path
from scripts import config
from scripts.utils.alternatives_updater import AlternativesUpdater
class UbuntuGDMAlternativesUpdater:
"""
Manages update-alternatives for Ubuntu GDM themes.
This class handles:
- Creating alternatives for GDM theme files
- Setting installed theme as the active alternative
- Removing theme alternatives during uninstallation
"""
def __init__(self, alternatives_updater: AlternativesUpdater):
"""
:param alternatives_updater: Handler for update-alternatives operations
"""
self.ubuntu_gresource_link = config.ubuntu_gresource_link
self.destination_dir = config.global_gnome_shell_theme
self.destination_file = config.gnome_shell_gresource
self.alternatives_updater = alternatives_updater
self._update_gresource_paths()
def _update_gresource_paths(self):
self.ubuntu_gresource_path = os.path.join(self.destination_dir, self.ubuntu_gresource_link)
self.gnome_gresource_path = os.path.join(self.destination_dir, self.destination_file)
def with_custom_destination(self, destination_dir: str, destination_file: str):
"""Set custom destination directory and file for the theme."""
self.destination_dir = destination_dir
self.destination_file = destination_file
self._update_gresource_paths()
return self
def install_and_set(self, priority: int = 0):
"""
Add theme as an alternative and set it as active.
This creates a system alternative for the GDM theme and
makes it the active selection with the specified priority.
:param priority: Priority level for the alternative (higher wins in conflicts)
"""
self.alternatives_updater.install_and_set(
link=self.ubuntu_gresource_path,
name=self.ubuntu_gresource_link,
path=self.gnome_gresource_path,
priority=priority
)
def remove(self):
"""
Remove the theme alternative from the system.
This removes the previously installed alternative, allowing
the system to fall back to the default GDM theme.
"""
self.alternatives_updater.remove(
name=self.ubuntu_gresource_link,
path=self.gnome_gresource_path
)

View File

@@ -1,5 +1,6 @@
import os
from scripts.utils.alternatives_updater import PathString
from scripts.utils.command_runner.command_runner import CommandRunner
from scripts.utils.gresource.gresource_backuper import GresourceBackuperManager
from scripts.utils.gresource.gresource_compiler import GresourceCompiler
@@ -12,7 +13,7 @@ class Gresource:
"""Orchestrator for gresource files."""
def __init__(
self, gresource_file: str, temp_folder: str, destination: str,
self, gresource_file: str, temp_folder: PathString, destination: PathString,
logger_factory: LoggerFactory, runner: CommandRunner
):
"""
@@ -34,6 +35,15 @@ class Gresource:
self._backuper = GresourceBackuperManager(self._destination_gresource,
logger_factory=self.logger_factory)
def has_trigger(self, trigger: str) -> bool:
"""
Check if the trigger is present in the gresource file.
Used to detect if the theme is already installed.
:param trigger: The trigger to check for.
:return: True if the trigger is found, False otherwise.
"""
return self._backuper.has_trigger(trigger)
def use_backup_gresource(self):
self._active_source_gresource = self._backuper.get_backup()
return self._active_source_gresource

View File

@@ -11,6 +11,9 @@ class GresourceBackuperManager:
self._backup_file = f"{destination_file}.backup"
self._backuper = GresourceBackuper(destination_file, self._backup_file, logger_factory)
def has_trigger(self, trigger: str) -> bool:
return self._backuper.has_trigger(trigger)
def backup(self):
self._backuper.backup()
@@ -27,6 +30,10 @@ class GresourceBackuper:
self.backup_file = backup_file
self.logger_factory = logger_factory
def has_trigger(self, trigger: str) -> bool:
with open(self.destination_file, "rb") as f:
return trigger.encode() in f.read()
def get_backup(self) -> str:
if not os.path.exists(self.backup_file):
raise GresourceBackupNotFoundError(self.backup_file)

View File

@@ -4,6 +4,7 @@ from scripts import config
from scripts.install.colors_definer import ColorsDefiner
from scripts.utils.color_converter.color_converter_impl import ColorConverterImpl
from scripts.utils.logger.console import Console
from scripts.utils.logger.logger import LoggerFactory
from scripts.utils.style_manager import StyleManager
from scripts.utils.theme.theme import Theme
from scripts.utils.theme.theme_color_applier import ThemeColorApplier
@@ -38,6 +39,7 @@ class GnomeShellThemeBuilder:
self.temp_folder = os.path.join(self._base_temp_folder, self.theme_name)
self.main_styles = os.path.join(self.temp_folder, f"{self.theme_name}.css")
self.logger_factory: LoggerFactory | None = None
self.preparation: ThemePreparation | None = None
self.installer: ThemeInstaller | None = None
@@ -66,6 +68,28 @@ class GnomeShellThemeBuilder:
self.is_filled = filled
return self
def with_logger_factory(self, logger_factory: LoggerFactory | None):
"""Inject a logger factory for logging purposes."""
self.logger_factory = logger_factory
return self
def with_preparation(self, preparation: ThemePreparation | None):
"""Inject a preparation instance for preparing the theme."""
self.preparation = preparation
return self
def with_installer(self, installer: ThemeInstaller | None):
"""Inject an installer for installing the theme."""
self.installer = installer
return self
def with_reset_dependencies(self):
"""Reset the dependencies for the theme preparation and installation."""
self.preparation = None
self.installer = None
return self
def build(self) -> "Theme":
"""
Constructs and returns a Theme instance using the configured properties.
@@ -81,7 +105,7 @@ class GnomeShellThemeBuilder:
return Theme(self.preparation, self.installer, self.mode, self.is_filled)
def _resolve_preparation(self):
if self.preparation is not None: return
if self.preparation: return
file_manager = ThemeTempManager(self.temp_folder)
style_manager = StyleManager(self.main_styles)
@@ -89,13 +113,14 @@ class GnomeShellThemeBuilder:
file_manager=file_manager, style_manager=style_manager)
def _resolve_installer(self):
if self.installer is not None: return
if self.installer: return
color_converter = ColorConverterImpl()
color_replacement_generator = ColorReplacementGenerator(
colors_provider=self.colors_provider, color_converter=color_converter)
colors_provider=self.colors_provider,
color_converter=color_converter)
color_applier = ThemeColorApplier(color_replacement_generator=color_replacement_generator)
logger_factory = Console()
logger_factory = self.logger_factory or Console()
path_provider = ThemePathProvider()
self.installer = ThemeInstaller(self.theme_name, self.temp_folder, self.destination_folder,
logger_factory=logger_factory,