Merge pull request #55 from Torxed/43-overview
Added a configuration overview before formatting
This commit is contained in:
commit
f32f1e238a
|
|
@ -25,6 +25,16 @@ class BlockDevice():
|
|||
raise KeyError(f'{self} does not contain information: "{key}"')
|
||||
return self.info[key]
|
||||
|
||||
def json(self):
|
||||
"""
|
||||
json() has precedence over __dump__, so this is a way
|
||||
to give less/partial information for user readability.
|
||||
"""
|
||||
return {
|
||||
'path' : self.path,
|
||||
'size' : self.info['size'] if 'size' in self.info else '<unknown>'
|
||||
}
|
||||
|
||||
def __dump__(self):
|
||||
return {
|
||||
'path' : self.path,
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import os, json, hashlib, shlex, sys
|
||||
import time, pty
|
||||
from datetime import datetime, date
|
||||
from subprocess import Popen, STDOUT, PIPE, check_output
|
||||
from select import epoll, EPOLLIN, EPOLLHUP
|
||||
from .exceptions import *
|
||||
|
|
@ -30,6 +31,43 @@ def locate_binary(name):
|
|||
return os.path.join(root, file)
|
||||
break # Don't recurse
|
||||
|
||||
class JSON_Encoder:
|
||||
def _encode(obj):
|
||||
if isinstance(obj, dict):
|
||||
## We'll need to iterate not just the value that default() usually gets passed
|
||||
## But also iterate manually over each key: value pair in order to trap the keys.
|
||||
|
||||
for key, val in list(obj.items()):
|
||||
if isinstance(val, dict):
|
||||
val = json.loads(json.dumps(val, cls=JSON)) # This, is a EXTREMELY ugly hack..
|
||||
# But it's the only quick way I can think of to
|
||||
# trigger a encoding of sub-dictionaries.
|
||||
else:
|
||||
val = JSON_Encoder._encode(val)
|
||||
del(obj[key])
|
||||
obj[JSON_Encoder._encode(key)] = val
|
||||
return obj
|
||||
elif hasattr(obj, 'json'):
|
||||
return obj.json()
|
||||
elif hasattr(obj, '__dump__'):
|
||||
return obj.__dump__()
|
||||
elif isinstance(obj, (datetime, date)):
|
||||
return obj.isoformat()
|
||||
elif isinstance(obj, (list, set, tuple)):
|
||||
r = []
|
||||
for item in obj:
|
||||
r.append(json.loads(json.dumps(item, cls=JSON)))
|
||||
return r
|
||||
else:
|
||||
return obj
|
||||
|
||||
class JSON(json.JSONEncoder, json.JSONDecoder):
|
||||
def _encode(self, obj):
|
||||
return JSON_Encoder._encode(obj)
|
||||
|
||||
def encode(self, obj):
|
||||
return super(JSON, self).encode(self._encode(obj))
|
||||
|
||||
class sys_command():#Thread):
|
||||
"""
|
||||
Stolen from archinstall_gui
|
||||
|
|
|
|||
|
|
@ -61,6 +61,9 @@ class Profile():
|
|||
self._cache = None
|
||||
self.args = args
|
||||
|
||||
def __dump__(self, *args, **kwargs):
|
||||
return {'path' : self._path}
|
||||
|
||||
def __repr__(self, *args, **kwargs):
|
||||
return f'Profile({self._path} <"{self.path}">)'
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,20 @@
|
|||
import archinstall, getpass, time
|
||||
import archinstall
|
||||
import getpass, time, json, sys, signal
|
||||
|
||||
"""
|
||||
This signal-handler chain (and global variable)
|
||||
is used to trigger the "Are you sure you want to abort?" question.
|
||||
"""
|
||||
SIG_TRIGGER = False
|
||||
def kill_handler(sig, frame):
|
||||
print()
|
||||
exit(0)
|
||||
def sig_handler(sig, frame):
|
||||
global SIG_TRIGGER
|
||||
SIG_TRIGGER = True
|
||||
signal.signal(signal.SIGINT, kill_handler)
|
||||
original_sigint_handler = signal.getsignal(signal.SIGINT)
|
||||
signal.signal(signal.SIGINT, sig_handler)
|
||||
|
||||
def perform_installation(device, boot_partition, language, mirrors):
|
||||
"""
|
||||
|
|
@ -50,8 +66,13 @@ archinstall.sys_command(f'cryptsetup close /dev/mapper/luksloop', surpress_error
|
|||
keyboard_language = archinstall.select_language(archinstall.list_keyboard_languages())
|
||||
archinstall.set_keyboard_language(keyboard_language)
|
||||
|
||||
# Create a storage structure for all our information.
|
||||
# We'll print this right before the user gets informed about the formatting timer.
|
||||
archinstall.storage['_guided'] = {}
|
||||
|
||||
# Set which region to download packages from during the installation
|
||||
mirror_regions = archinstall.select_mirror_regions(archinstall.list_mirrors())
|
||||
archinstall.storage['_guided']['mirrors'] = mirror_regions
|
||||
|
||||
# Ask which harddrive/block-device we will install to
|
||||
harddrive = archinstall.select_disk(archinstall.all_disks())
|
||||
|
|
@ -61,10 +82,12 @@ while (disk_password := getpass.getpass(prompt='Enter disk encryption password (
|
|||
archinstall.log(' * Passwords did not match * ', bg='black', fg='red')
|
||||
continue
|
||||
break
|
||||
archinstall.storage['_guided']['harddrive'] = harddrive
|
||||
|
||||
# Ask for a hostname
|
||||
hostname = input('Desired hostname for the installation: ')
|
||||
if len(hostname) == 0: hostname = 'ArchInstall'
|
||||
archinstall.storage['_guided']['hostname'] = hostname
|
||||
|
||||
# Ask for a root password (optional, but triggers requirement for super-user if skipped)
|
||||
while (root_pw := getpass.getpass(prompt='Enter root password (leave blank to leave root disabled): ')):
|
||||
|
|
@ -87,6 +110,10 @@ while 1:
|
|||
archinstall.log(' * Since root is disabled, you need to create a least one (super) user!', bg='black', fg='red')
|
||||
continue
|
||||
break
|
||||
|
||||
if 'users' not in archinstall.storage['_guided']: archinstall.storage['_guided']['users'] = []
|
||||
archinstall.storage['_guided']['users'].append(new_user)
|
||||
|
||||
new_user_passwd = getpass.getpass(prompt=f'Password for user {new_user}: ')
|
||||
new_user_passwd_verify = getpass.getpass(prompt=f'Enter password again for verification: ')
|
||||
if new_user_passwd != new_user_passwd_verify:
|
||||
|
|
@ -99,12 +126,17 @@ while 1:
|
|||
# Ask for archinstall-specific profiles (such as desktop environments etc)
|
||||
while 1:
|
||||
profile = archinstall.select_profile(archinstall.list_profiles())
|
||||
if profile and type(profile) != str: # Got a imported profile
|
||||
if not profile[1]._prep_function():
|
||||
archinstall.log(' * Profile\'s preperation requirements was not fulfilled.', bg='black', fg='red')
|
||||
continue
|
||||
profile = profile[0]._path # Once the prep is done, replace the selected profile with the profile name ("path") given from select_profile()
|
||||
break
|
||||
if profile:
|
||||
archinstall.storage['_guided']['profile'] = profile
|
||||
|
||||
if type(profile) != str: # Got a imported profile
|
||||
archinstall.storage['_guided']['profile'] = profile[0] # The second return is a module, and not a handle/object.
|
||||
if not profile[1]._prep_function():
|
||||
archinstall.log(' * Profile\'s preperation requirements was not fulfilled.', bg='black', fg='red')
|
||||
continue
|
||||
|
||||
profile = profile[0]._path # Once the prep is done, replace the selected profile with the profile name ("path") given from select_profile()
|
||||
break
|
||||
else:
|
||||
break
|
||||
|
||||
|
|
@ -117,27 +149,42 @@ while 1:
|
|||
|
||||
try:
|
||||
if archinstall.validate_package_list(packages):
|
||||
archinstall.storage['_guided']['packages'] = packages
|
||||
break
|
||||
except archinstall.RequirementError as e:
|
||||
print(e)
|
||||
|
||||
# TODO: Print a summary here of all the options chosen.
|
||||
# Ideally, archinstall should keep track of this internally
|
||||
# and there should be something like print(archinstall.config).
|
||||
print()
|
||||
print('This is your chosen configuration:')
|
||||
print(json.dumps(archinstall.storage['_guided'], indent=4, sort_keys=True, cls=archinstall.JSON))
|
||||
print()
|
||||
|
||||
"""
|
||||
Issue a final warning before we continue with something un-revertable.
|
||||
We mention the drive one last time, and count from 5 to 0.
|
||||
"""
|
||||
print(f' ! Formatting {harddrive} in 5...')
|
||||
time.sleep(1)
|
||||
print(f' ! Formatting {harddrive} in 4...')
|
||||
time.sleep(1)
|
||||
print(f' ! Formatting {harddrive} in 3...')
|
||||
time.sleep(1)
|
||||
print(f' ! Formatting {harddrive} in 2...')
|
||||
time.sleep(1)
|
||||
print(f' ! Formatting {harddrive} in 1...')
|
||||
time.sleep(1)
|
||||
|
||||
print(f' ! Formatting {harddrive} in ', end='')
|
||||
|
||||
for i in range(5, 0, -1):
|
||||
print(f"{i}", end='')
|
||||
|
||||
for x in range(4):
|
||||
sys.stdout.flush()
|
||||
time.sleep(0.25)
|
||||
print(".", end='')
|
||||
|
||||
if SIG_TRIGGER:
|
||||
abort = input('\nDo you really want to abort (y/n)? ')
|
||||
if abort.strip() != 'n':
|
||||
exit(0)
|
||||
|
||||
if SIG_TRIGGER is False:
|
||||
sys.stdin.read()
|
||||
SIG_TRIGGER = False
|
||||
signal.signal(signal.SIGINT, sig_handler)
|
||||
print()
|
||||
signal.signal(signal.SIGINT, original_sigint_handler)
|
||||
|
||||
"""
|
||||
Setup the blockdevice, filesystem (and optionally encryption).
|
||||
|
|
|
|||
Loading…
Reference in New Issue