]>
git.ipfire.org Git - people/ms/bricklayer.git/blob - src/python/__init__.py
2dcceb201b6d3bd81d75cf1f0a5322222fa80e75
1 ###############################################################################
3 # Bricklayer - An Installer for IPFire #
4 # Copyright (C) 2021 IPFire Development Team #
6 # This program is free software; you can redistribute it and/or #
7 # modify it under the terms of the GNU General Public License #
8 # as published by the Free Software Foundation; either version 2 #
9 # of the License, or (at your option) any later version. #
11 # This program is distributed in the hope that it will be useful, #
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of #
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
14 # GNU General Public License for more details. #
16 # You should have received a copy of the GNU General Public License #
17 # along with this program. If not, see <http://www.gnu.org/licenses/>. #
19 ###############################################################################
29 from . import bootloaders
33 from . import packages
35 from . import timezones
42 log
= logging
.getLogger("bricklayer")
44 class Bricklayer(object):
46 Bricklayer's base class
48 def __init__(self
, arch
, pakfire_conf
=None, first_install
=False, debug
=False,
49 unattended
=False, disks
=[]):
51 self
.pakfire_conf
= pakfire_conf
52 self
.first_install
= first_install
54 self
.unattended
= unattended
56 # Enable debug logging
58 log
.setLevel(logging
.DEBUG
)
62 "language" : i18n
.default_language
,
65 # Install the Base group
69 # Set the default swap size to 1 GiB
70 "swap-size": 1024 ** 3,
77 self
.os
= self
._read
_os
_release
()
79 # Select a bootloaders
80 self
.bootloaders
= self
._select
_bootloaders
()
83 self
.disks
= disk
.Disks(self
)
85 self
.disks
.add_disk(path
)
87 # Initialise the text user interface
88 self
.tui
= tui
.Tui(self
)
90 # Create root directory
91 self
.root
= tempfile
.mkdtemp(prefix
="bricklayer-", suffix
="-root")
93 # Log when we are ready
94 log
.info("Bricklayer initialized")
96 # An ordered list of all available steps
98 step
.UnattendedWarning
,
100 timezones
.SelectTimezone
,
102 disk
.CalculatePartitionLayout
,
106 disk
.CreatePartitionLayout
,
107 disk
.CreateFilesystems
,
108 disk
.MountFilesystems
,
109 packages
.InstallPackages
,
110 bootloaders
.InstallBootloader
,
113 step
.ToggleFirstInstallStatus
,
114 disk
.UmountFilesystems
,
115 step
.Congratulations
,
121 # Walk through all steps
122 for step
in self
.steps
:
126 # End installer if aborted
127 except InstallAbortedError
:
130 # The user requested to cancel the installation process
131 except UserCanceledError
:
133 _("Cancel Installation?"),
134 _("Are you sure that you want to cancel the installation process?"),
138 # Catch any failed commands
139 except subprocess
.CalledProcessError
as e
:
141 "command" : " ".join(e
.cmd
),
142 "output" : e
.output
.decode(),
143 "returncode" : e
.returncode
,
147 log
.error("Command \"%(command)s\" failed with error code "
148 "%(returncode)s:\n%(output)s" % args
)
150 # Format the error message
151 error
= _("Command \"%(command)s\" failed with error code "
152 "%(returncode)s:\n\n%(output)s" % args
)
155 self
.tui
.error(_("An Unexpected Error Occured"), error
,
156 buttons
=[_("Exit")], width
=78)
161 # Catch all other exceptions and show an error
163 type, value
, tb
= sys
.exc_info()
166 log
.error("An unexpected error occured:", exc_info
=True)
168 # Format the exception
169 error
= _("The installation cannot be continued due to an error:"
170 "\n\n%s") % "".join(traceback
.format_exception(type, value
, tb
))
172 # Show an error message
173 self
.tui
.error(_("An Unexpected Error Occured"),
174 "".join(error
), buttons
=[_("Exit")], width
=78)
179 # Cleanup when we leave
181 self
.disks
.tear_down()
183 def _run_step(self
, stepcls
):
187 # Initialize the step
188 step
= stepcls(self
, tui
=self
.tui
)
190 # Skip this step if it isn't enabled in first install mode
191 if self
.first_install
and not step
.first_install
:
194 # Skip this step if it isn't enabled
201 def _read_os_release(self
):
205 with
open("/etc/os-release") as f
:
206 return util
.config_read(f
)
208 def command(self
, command
, error_ok
=False, interactive
=False):
210 Runs a command in a shell environment
212 log
.debug("Running command: %s" % " ".join(command
))
218 "stdout" : subprocess
.PIPE
,
219 "stderr" : subprocess
.STDOUT
,
222 # Execute the command
223 p
= subprocess
.run(command
, **args
)
225 # Check the return code (raises CalledProcessError on non-zero)
229 # There is no output in interactive mode
234 output
= p
.stdout
.decode()
242 def setup_pakfire(self
, **kwargs
):
244 Calls Pakfire and has it load its configuration
247 "confirm_callback" : self
.tui
._confirm
,
250 return pakfire
.Pakfire(self
.root
, arch
=self
.arch
,
251 conf
=self
.pakfire_conf
, **kwargs
)
253 def _select_bootloaders(self
):
255 Select all bootloaders for this installation process
258 bootloaders
.Grub(self
),
259 bootloaders
.GrubEFI(self
),
262 # Return all supported bootloaders
263 return [bl
for bl
in _bootloaders
if bl
.supported
]