Merge branch 'project-overhaul' into dev
* Linux side is done
|
|
@ -1,63 +0,0 @@
|
|||
# Wizard Kit: Activate Windows using various methods
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
# Init
|
||||
sys.path.append(os.path.dirname(os.path.realpath(__file__)))
|
||||
from functions.activation import *
|
||||
init_global_vars()
|
||||
os.system('title {}: Windows Activation Tool'.format(KIT_NAME_FULL))
|
||||
|
||||
if __name__ == '__main__':
|
||||
try:
|
||||
stay_awake()
|
||||
clear_screen()
|
||||
print_info('{}: Windows Activation Tool\n'.format(KIT_NAME_FULL))
|
||||
# Bail early if already activated
|
||||
if windows_is_activated():
|
||||
print_info('This system is already activated')
|
||||
sleep(5)
|
||||
exit_script()
|
||||
other_results = {
|
||||
'Error': {
|
||||
'BIOSKeyNotFoundError': 'BIOS key not found.',
|
||||
}}
|
||||
|
||||
# Determine activation method
|
||||
activation_methods = [
|
||||
{'Name': 'Activate with BIOS key', 'Function': activate_with_bios},
|
||||
]
|
||||
if global_vars['OS']['Version'] not in ('8', '8.1', '10'):
|
||||
activation_methods[0]['Disabled'] = True
|
||||
actions = [
|
||||
{'Name': 'Quit', 'Letter': 'Q'},
|
||||
]
|
||||
|
||||
while True:
|
||||
selection = menu_select(
|
||||
'{}: Windows Activation Menu'.format(KIT_NAME_FULL),
|
||||
main_entries=activation_methods, action_entries=actions)
|
||||
|
||||
if (selection.isnumeric()):
|
||||
result = try_and_print(
|
||||
message = activation_methods[int(selection)-1]['Name'],
|
||||
function = activation_methods[int(selection)-1]['Function'],
|
||||
other_results=other_results)
|
||||
if result['CS']:
|
||||
break
|
||||
else:
|
||||
sleep(2)
|
||||
elif selection == 'Q':
|
||||
exit_script()
|
||||
|
||||
# Done
|
||||
print_success('\nDone.')
|
||||
pause("Press Enter to exit...")
|
||||
exit_script()
|
||||
except SystemExit as sys_exit:
|
||||
exit_script(sys_exit.code)
|
||||
except:
|
||||
major_exception()
|
||||
|
||||
# vim: sts=2 sw=2 ts=2
|
||||
|
|
@ -1,149 +0,0 @@
|
|||
#!/bin/env python3
|
||||
#
|
||||
# pylint: disable=no-name-in-module,wildcard-import,wrong-import-position
|
||||
# vim: sts=2 sw=2 ts=2
|
||||
"""Wizard Kit: UFD build tool"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
# Init
|
||||
sys.path.append(os.path.dirname(os.path.realpath(__file__)))
|
||||
from docopt import docopt
|
||||
from functions.common import *
|
||||
from functions.ufd import *
|
||||
from settings.ufd import *
|
||||
init_global_vars(silent=True)
|
||||
|
||||
# Main section
|
||||
if __name__ == '__main__':
|
||||
# pylint: disable=invalid-name
|
||||
# Set log
|
||||
try:
|
||||
global_vars['LogDir'] = '{}/Logs'.format(
|
||||
get_user_home(get_user_name()))
|
||||
set_log_file('Build UFD ({Date-Time}).log'.format(**global_vars))
|
||||
except: # pylint: disable=bare-except
|
||||
major_exception()
|
||||
|
||||
# Header
|
||||
print_success(KIT_NAME_FULL)
|
||||
print_standard('UFD Build Tool')
|
||||
print_standard(' ')
|
||||
|
||||
# Check if running as root
|
||||
if not running_as_root():
|
||||
print_error('ERROR: This script is meant to be run as root.')
|
||||
abort(False)
|
||||
|
||||
# Docopt
|
||||
try:
|
||||
args = docopt(DOCSTRING)
|
||||
except SystemExit as sys_exit:
|
||||
# Catch docopt exits
|
||||
exit_script(sys_exit.code)
|
||||
except: # pylint: disable=bare-except
|
||||
major_exception()
|
||||
|
||||
try:
|
||||
# Verify selections
|
||||
ufd_dev = verify_ufd(args['--ufd-device'])
|
||||
sources = verify_sources(args, UFD_SOURCES)
|
||||
show_selections(args, sources, ufd_dev, UFD_SOURCES)
|
||||
if not args['--force']:
|
||||
confirm_selections(args)
|
||||
|
||||
# Prep UFD
|
||||
if not args['--update']:
|
||||
print_info('Prep UFD')
|
||||
prep_device(ufd_dev, UFD_LABEL, use_mbr=args['--use-mbr'])
|
||||
|
||||
# Mount UFD
|
||||
try_and_print(
|
||||
indent=2,
|
||||
message='Mounting UFD...',
|
||||
function=mount,
|
||||
mount_source=find_first_partition(ufd_dev),
|
||||
mount_point='/mnt/UFD',
|
||||
read_write=True,
|
||||
)
|
||||
|
||||
# Remove Arch folder
|
||||
if args['--update']:
|
||||
try_and_print(
|
||||
indent=2,
|
||||
message='Removing Linux...',
|
||||
function=remove_arch,
|
||||
)
|
||||
|
||||
# Copy sources
|
||||
print_standard(' ')
|
||||
print_info('Copy Sources')
|
||||
for s_label, s_path in sources.items():
|
||||
try_and_print(
|
||||
indent=2,
|
||||
message='Copying {}...'.format(s_label),
|
||||
function=copy_source,
|
||||
source=s_path,
|
||||
items=ITEMS[s_label],
|
||||
overwrite=True,
|
||||
)
|
||||
|
||||
# Update boot entries
|
||||
print_standard(' ')
|
||||
print_info('Boot Setup')
|
||||
try_and_print(
|
||||
indent=2,
|
||||
message='Updating boot entries...',
|
||||
function=update_boot_entries,
|
||||
boot_entries=BOOT_ENTRIES,
|
||||
boot_files=BOOT_FILES,
|
||||
iso_label=ISO_LABEL,
|
||||
ufd_label=UFD_LABEL,
|
||||
)
|
||||
|
||||
# Install syslinux (to partition)
|
||||
try_and_print(
|
||||
indent=2,
|
||||
message='Syslinux (partition)...',
|
||||
function=install_syslinux_to_partition,
|
||||
partition=find_first_partition(ufd_dev),
|
||||
)
|
||||
|
||||
# Unmount UFD
|
||||
try_and_print(
|
||||
indent=2,
|
||||
message='Unmounting UFD...',
|
||||
function=unmount,
|
||||
mount_point='/mnt/UFD',
|
||||
)
|
||||
|
||||
# Install syslinux (to device)
|
||||
try_and_print(
|
||||
indent=2,
|
||||
message='Syslinux (device)...',
|
||||
function=install_syslinux_to_dev,
|
||||
ufd_dev=ufd_dev,
|
||||
use_mbr=args['--use-mbr'],
|
||||
)
|
||||
|
||||
# Hide items
|
||||
print_standard(' ')
|
||||
print_info('Final Touches')
|
||||
try_and_print(
|
||||
indent=2,
|
||||
message='Hiding items...',
|
||||
function=hide_items,
|
||||
ufd_dev=ufd_dev,
|
||||
items=ITEMS_HIDDEN,
|
||||
)
|
||||
|
||||
# Done
|
||||
if not args['--force']:
|
||||
print_standard('\nDone.')
|
||||
pause('Press Enter to exit...')
|
||||
exit_script()
|
||||
except SystemExit as sys_exit:
|
||||
exit_script(sys_exit.code)
|
||||
except: # pylint: disable=bare-except
|
||||
major_exception()
|
||||
|
|
@ -1,43 +0,0 @@
|
|||
# Wizard Kit: Backup CBS Logs and prep CBS temp data for deletion
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
# Init
|
||||
sys.path.append(os.path.dirname(os.path.realpath(__file__)))
|
||||
from functions.cleanup import *
|
||||
from functions.data import *
|
||||
init_global_vars()
|
||||
os.system('title {}: CBS Cleanup'.format(KIT_NAME_FULL))
|
||||
set_log_file('CBS Cleanup.log')
|
||||
|
||||
if __name__ == '__main__':
|
||||
try:
|
||||
# Prep
|
||||
stay_awake()
|
||||
clear_screen()
|
||||
folder_path = r'{}\Backups'.format(KIT_NAME_SHORT)
|
||||
dest = select_destination(folder_path=folder_path,
|
||||
prompt='Which disk are we using for temp data and backup?')
|
||||
|
||||
# Show details
|
||||
print_info('{}: CBS Cleanup Tool\n'.format(KIT_NAME_FULL))
|
||||
show_data('Backup / Temp path:', dest)
|
||||
print_standard('\n')
|
||||
if (not ask('Proceed with CBS cleanup?')):
|
||||
abort()
|
||||
|
||||
# Run Cleanup
|
||||
try_and_print(message='Running cleanup...', function=cleanup_cbs,
|
||||
cs='Done', dest_folder=dest)
|
||||
|
||||
# Done
|
||||
print_standard('\nDone.')
|
||||
pause("Press Enter to exit...")
|
||||
exit_script()
|
||||
except SystemExit as sys_exit:
|
||||
exit_script(sys_exit.code)
|
||||
except:
|
||||
major_exception()
|
||||
|
||||
# vim: sts=2 sw=2 ts=2
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
#!/bin/bash
|
||||
#
|
||||
## Wizard Kit: ddrescue TUI Launcher
|
||||
|
||||
source launch-in-tmux
|
||||
|
||||
SESSION_NAME="ddrescue-tui"
|
||||
WINDOW_NAME="ddrescue TUI"
|
||||
TMUX_CMD="ddrescue-tui-menu"
|
||||
|
||||
launch_in_tmux "$@"
|
||||
|
|
@ -1,64 +0,0 @@
|
|||
#!/bin/python3
|
||||
#
|
||||
## Wizard Kit: TUI for ddrescue cloning and imaging
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
# Init
|
||||
sys.path.append(os.path.dirname(os.path.realpath(__file__)))
|
||||
from functions.ddrescue import *
|
||||
from functions.hw_diags import *
|
||||
init_global_vars()
|
||||
|
||||
if __name__ == '__main__':
|
||||
try:
|
||||
# Prep
|
||||
clear_screen()
|
||||
args = list(sys.argv)
|
||||
run_mode = ''
|
||||
source_path = None
|
||||
dest_path = None
|
||||
|
||||
# Parse args
|
||||
try:
|
||||
script_name = os.path.basename(args.pop(0))
|
||||
run_mode = str(args.pop(0)).lower()
|
||||
source_path = args.pop(0)
|
||||
dest_path = args.pop(0)
|
||||
except IndexError:
|
||||
# We'll set the missing paths later
|
||||
pass
|
||||
|
||||
# Show usage
|
||||
if re.search(r'-+(h|help)', str(sys.argv), re.IGNORECASE):
|
||||
show_usage(script_name)
|
||||
exit_script()
|
||||
|
||||
# Start cloning/imaging
|
||||
if run_mode in ('clone', 'image'):
|
||||
menu_ddrescue(source_path, dest_path, run_mode)
|
||||
else:
|
||||
if not re.search(r'^-*(h|help\?)', run_mode, re.IGNORECASE):
|
||||
print_error('Invalid mode.')
|
||||
|
||||
# Done
|
||||
print_standard('\nDone.')
|
||||
pause("Press Enter to exit...")
|
||||
tmux_switch_client()
|
||||
exit_script()
|
||||
except GenericAbort:
|
||||
abort()
|
||||
except GenericError as ge:
|
||||
msg = 'Generic Error'
|
||||
if str(ge):
|
||||
msg = str(ge)
|
||||
print_error(msg)
|
||||
abort()
|
||||
except SystemExit as sys_exit:
|
||||
tmux_switch_client()
|
||||
exit_script(sys_exit.code)
|
||||
except:
|
||||
major_exception()
|
||||
|
||||
# vim: sts=2 sw=2 ts=2
|
||||
|
|
@ -1,954 +0,0 @@
|
|||
# Wizard Kit: Functions - Common
|
||||
|
||||
import os
|
||||
import psutil
|
||||
import re
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
import time
|
||||
import traceback
|
||||
try:
|
||||
import winreg
|
||||
except ModuleNotFoundError:
|
||||
if psutil.WINDOWS:
|
||||
raise
|
||||
|
||||
from settings.main import *
|
||||
from settings.tools import *
|
||||
from settings.windows_builds import *
|
||||
from subprocess import CalledProcessError
|
||||
|
||||
|
||||
# Global variables
|
||||
global_vars = {}
|
||||
|
||||
|
||||
# STATIC VARIABLES
|
||||
COLORS = {
|
||||
'CLEAR': '\033[0m',
|
||||
'RED': '\033[31m',
|
||||
'ORANGE': '\033[31;1m',
|
||||
'GREEN': '\033[32m',
|
||||
'YELLOW': '\033[33m',
|
||||
'BLUE': '\033[34m',
|
||||
'PURPLE': '\033[35m',
|
||||
'CYAN': '\033[36m',
|
||||
}
|
||||
try:
|
||||
HKU = winreg.HKEY_USERS
|
||||
HKCR = winreg.HKEY_CLASSES_ROOT
|
||||
HKCU = winreg.HKEY_CURRENT_USER
|
||||
HKLM = winreg.HKEY_LOCAL_MACHINE
|
||||
except NameError:
|
||||
if psutil.WINDOWS:
|
||||
raise
|
||||
|
||||
|
||||
# Error Classes
|
||||
class BIOSKeyNotFoundError(Exception):
|
||||
pass
|
||||
|
||||
class BinNotFoundError(Exception):
|
||||
pass
|
||||
|
||||
class GenericAbort(Exception):
|
||||
pass
|
||||
|
||||
class GenericError(Exception):
|
||||
pass
|
||||
|
||||
class GenericRepair(Exception):
|
||||
pass
|
||||
|
||||
class MultipleInstallationsError(Exception):
|
||||
pass
|
||||
|
||||
class NoProfilesError(Exception):
|
||||
pass
|
||||
|
||||
class Not4KAlignedError(Exception):
|
||||
pass
|
||||
|
||||
class NotInstalledError(Exception):
|
||||
pass
|
||||
|
||||
class OSInstalledLegacyError(Exception):
|
||||
pass
|
||||
|
||||
class PathNotFoundError(Exception):
|
||||
pass
|
||||
|
||||
class UnsupportedOSError(Exception):
|
||||
pass
|
||||
|
||||
class SecureBootDisabledError(Exception):
|
||||
pass
|
||||
|
||||
class SecureBootNotAvailError(Exception):
|
||||
pass
|
||||
|
||||
class SecureBootUnknownError(Exception):
|
||||
pass
|
||||
|
||||
class WindowsOutdatedError(Exception):
|
||||
pass
|
||||
|
||||
class WindowsUnsupportedError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
# General functions
|
||||
def abort(show_prompt=True):
|
||||
"""Abort script."""
|
||||
print_warning('Aborted.')
|
||||
if show_prompt:
|
||||
sleep(1)
|
||||
pause(prompt='Press Enter to exit... ')
|
||||
exit_script(1)
|
||||
|
||||
|
||||
def ask(prompt='Kotaero!'):
|
||||
"""Prompt the user with a Y/N question, returns bool."""
|
||||
answer = None
|
||||
prompt = '{} [Y/N]: '.format(prompt)
|
||||
while answer is None:
|
||||
tmp = input(prompt)
|
||||
if re.search(r'^y(es|)$', tmp, re.IGNORECASE):
|
||||
answer = True
|
||||
elif re.search(r'^n(o|ope|)$', tmp, re.IGNORECASE):
|
||||
answer = False
|
||||
message = '{prompt}{answer_text}'.format(
|
||||
prompt = prompt,
|
||||
answer_text = 'Yes' if answer else 'No')
|
||||
print_log(message=message)
|
||||
return answer
|
||||
|
||||
|
||||
def beep(repeat=1):
|
||||
"""Play system bell with optional repeat."""
|
||||
for i in range(repeat):
|
||||
# Print bell char
|
||||
print('\a')
|
||||
sleep(0.5)
|
||||
|
||||
|
||||
def choice(choices, prompt='Kotaero!'):
|
||||
"""Prompt the user with a choice question, returns str."""
|
||||
answer = None
|
||||
choices = [str(c) for c in choices]
|
||||
choices_short = {c[:1].upper(): c for c in choices}
|
||||
prompt = '{} [{}]: '.format(prompt, '/'.join(choices))
|
||||
regex = '^({}|{})$'.format(
|
||||
'|'.join([c[:1] for c in choices]),
|
||||
'|'.join(choices))
|
||||
|
||||
# Get user's choice
|
||||
while answer is None:
|
||||
tmp = input(prompt)
|
||||
if re.search(regex, tmp, re.IGNORECASE):
|
||||
answer = tmp
|
||||
|
||||
# Log result
|
||||
message = '{prompt}{answer_text}'.format(
|
||||
prompt = prompt,
|
||||
answer_text = 'Yes' if answer else 'No')
|
||||
print_log(message=message)
|
||||
|
||||
# Fix answer formatting to match provided values
|
||||
answer = choices_short[answer[:1].upper()]
|
||||
|
||||
# Done
|
||||
return answer
|
||||
|
||||
|
||||
def clear_screen():
|
||||
"""Simple wrapper for cls/clear."""
|
||||
if psutil.WINDOWS:
|
||||
os.system('cls')
|
||||
else:
|
||||
os.system('clear')
|
||||
|
||||
|
||||
def convert_to_bytes(size):
|
||||
"""Convert human-readable size str to bytes and return an int."""
|
||||
size = str(size)
|
||||
tmp = re.search(r'(\d+\.?\d*)\s+([PTGMKB])B?', size.upper())
|
||||
if tmp:
|
||||
size = float(tmp.group(1))
|
||||
units = tmp.group(2)
|
||||
if units == 'P':
|
||||
size *= 1024 ** 5
|
||||
if units == 'T':
|
||||
size *= 1024 ** 4
|
||||
elif units == 'G':
|
||||
size *= 1024 ** 3
|
||||
elif units == 'M':
|
||||
size *= 1024 ** 2
|
||||
elif units == 'K':
|
||||
size *= 1024 ** 1
|
||||
elif units == 'B':
|
||||
size *= 1024 ** 0
|
||||
size = int(size)
|
||||
else:
|
||||
return -1
|
||||
|
||||
return size
|
||||
|
||||
|
||||
def exit_script(return_value=0):
|
||||
"""Exits the script after some cleanup and opens the log (if set)."""
|
||||
# Remove dirs (if empty)
|
||||
for dir in ['BackupDir', 'LogDir', 'TmpDir']:
|
||||
try:
|
||||
os.rmdir(global_vars[dir])
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
# Open Log (if it exists)
|
||||
log = global_vars.get('LogFile', '')
|
||||
if log and os.path.exists(log) and psutil.WINDOWS and ENABLED_OPEN_LOGS:
|
||||
try:
|
||||
extract_item('NotepadPlusPlus', silent=True)
|
||||
popen_program(
|
||||
[global_vars['Tools']['NotepadPlusPlus'],
|
||||
global_vars['LogFile']])
|
||||
except Exception:
|
||||
print_error('ERROR: Failed to extract Notepad++ and open log.')
|
||||
pause('Press Enter to exit...')
|
||||
|
||||
# Kill Caffeine if still running
|
||||
kill_process('caffeine.exe')
|
||||
|
||||
# Exit
|
||||
sys.exit(return_value)
|
||||
|
||||
|
||||
def extract_item(item, filter='', silent=False):
|
||||
"""Extract item from .cbin into .bin."""
|
||||
cmd = [
|
||||
global_vars['Tools']['SevenZip'], 'x', '-aos', '-bso0', '-bse0',
|
||||
'-p{ArchivePassword}'.format(**global_vars),
|
||||
r'-o{BinDir}\{item}'.format(item=item, **global_vars),
|
||||
r'{CBinDir}\{item}.7z'.format(item=item, **global_vars),
|
||||
filter]
|
||||
if not silent:
|
||||
print_standard('Extracting "{item}"...'.format(item=item))
|
||||
try:
|
||||
run_program(cmd)
|
||||
except FileNotFoundError:
|
||||
if not silent:
|
||||
print_warning('WARNING: Archive not found')
|
||||
except subprocess.CalledProcessError:
|
||||
if not silent:
|
||||
print_warning('WARNING: Errors encountered while exctracting data')
|
||||
|
||||
|
||||
def get_process(name=None):
|
||||
"""Get process by name, returns psutil.Process obj."""
|
||||
proc = None
|
||||
if not name:
|
||||
raise GenericError
|
||||
|
||||
for p in psutil.process_iter():
|
||||
try:
|
||||
if p.name() == name:
|
||||
proc = p
|
||||
except psutil._exceptions.NoSuchProcess:
|
||||
# Process finished during iteration? Going to ignore
|
||||
pass
|
||||
return proc
|
||||
|
||||
|
||||
def get_simple_string(prompt='Enter string'):
|
||||
"""Get string from user (restricted character set), returns str."""
|
||||
simple_string = None
|
||||
while simple_string is None:
|
||||
_input = input('{}: '.format(prompt))
|
||||
if re.match(r"^(\w|-| |\.|')+$", _input, re.ASCII):
|
||||
simple_string = _input.strip()
|
||||
return simple_string
|
||||
|
||||
|
||||
def get_ticket_number():
|
||||
"""Get TicketNumber from user, save in LogDir, and return as str."""
|
||||
if not ENABLED_TICKET_NUMBERS:
|
||||
return None
|
||||
ticket_number = None
|
||||
while ticket_number is None:
|
||||
_input = input('Enter ticket number: ')
|
||||
if re.match(r'^([0-9]+([-_]?\w+|))$', _input):
|
||||
ticket_number = _input
|
||||
out_file = r'{}\TicketNumber'.format(global_vars['LogDir'])
|
||||
if not psutil.WINDOWS:
|
||||
out_file = out_file.replace('\\', '/')
|
||||
with open(out_file, 'w', encoding='utf-8') as f:
|
||||
f.write(ticket_number)
|
||||
return ticket_number
|
||||
|
||||
|
||||
def human_readable_size(size, decimals=0):
|
||||
"""Convert size from bytes to a human-readable format, returns str."""
|
||||
# Prep string formatting
|
||||
width = 3+decimals
|
||||
if decimals > 0:
|
||||
width += 1
|
||||
|
||||
# Convert size to int
|
||||
try:
|
||||
size = int(size)
|
||||
except ValueError:
|
||||
size = convert_to_bytes(size)
|
||||
except TypeError:
|
||||
size = -1
|
||||
|
||||
# Verify we have a valid size
|
||||
if size < 0:
|
||||
return '{size:>{width}} b'.format(size='???', width=width)
|
||||
|
||||
# Convert to sensible units
|
||||
if size >= 1024 ** 5:
|
||||
size /= 1024 ** 5
|
||||
units = 'PB'
|
||||
elif size >= 1024 ** 4:
|
||||
size /= 1024 ** 4
|
||||
units = 'TB'
|
||||
elif size >= 1024 ** 3:
|
||||
size /= 1024 ** 3
|
||||
units = 'GB'
|
||||
elif size >= 1024 ** 2:
|
||||
size /= 1024 ** 2
|
||||
units = 'MB'
|
||||
elif size >= 1024 ** 1:
|
||||
size /= 1024 ** 1
|
||||
units = 'KB'
|
||||
else:
|
||||
size /= 1024 ** 0
|
||||
units = ' B'
|
||||
|
||||
# Return
|
||||
return '{size:>{width}.{decimals}f} {units}'.format(
|
||||
size=size, width=width, decimals=decimals, units=units)
|
||||
|
||||
|
||||
def kill_process(name):
|
||||
"""Kill any running caffeine.exe processes."""
|
||||
for proc in psutil.process_iter():
|
||||
if proc.name() == name:
|
||||
proc.kill()
|
||||
|
||||
|
||||
def major_exception():
|
||||
"""Display traceback and exit"""
|
||||
print_error('Major exception')
|
||||
print_warning(SUPPORT_MESSAGE)
|
||||
print(traceback.format_exc())
|
||||
print_log(traceback.format_exc())
|
||||
try:
|
||||
upload_crash_details()
|
||||
except GenericAbort:
|
||||
# User declined upload
|
||||
print_warning('Upload: Aborted')
|
||||
sleep(10)
|
||||
except GenericError:
|
||||
# No log file or uploading disabled
|
||||
sleep(10)
|
||||
except:
|
||||
print_error('Upload: NS')
|
||||
sleep(10)
|
||||
else:
|
||||
print_success('Upload: CS')
|
||||
pause('Press Enter to exit...')
|
||||
exit_script(1)
|
||||
|
||||
|
||||
def menu_select(
|
||||
title='[Untitled Menu]',
|
||||
prompt='Please make a selection', secret_actions=[], secret_exit=False,
|
||||
main_entries=[], action_entries=[], disabled_label='DISABLED',
|
||||
spacer=''):
|
||||
"""Display options in a menu and return selected option as a str."""
|
||||
# Bail early
|
||||
if not main_entries and not action_entries:
|
||||
raise Exception("MenuError: No items given")
|
||||
|
||||
# Set title
|
||||
if 'Title' in global_vars:
|
||||
title = '{}\n\n{}'.format(global_vars['Title'], title)
|
||||
|
||||
# Build menu
|
||||
menu_splash = '{}\n{}\n'.format(title, spacer)
|
||||
width = len(str(len(main_entries)))
|
||||
valid_answers = []
|
||||
if secret_exit:
|
||||
valid_answers.append('Q')
|
||||
if secret_actions:
|
||||
valid_answers.extend(secret_actions)
|
||||
|
||||
# Add main entries
|
||||
for i in range(len(main_entries)):
|
||||
entry = main_entries[i]
|
||||
# Add Spacer
|
||||
if ('CRLF' in entry):
|
||||
menu_splash += '{}\n'.format(spacer)
|
||||
entry_str = '{number:>{width}}: {name}'.format(
|
||||
number = i+1,
|
||||
width = width,
|
||||
name = entry.get('Display Name', entry['Name']))
|
||||
if entry.get('Disabled', False):
|
||||
entry_str = '{YELLOW}{entry_str} ({disabled}){CLEAR}'.format(
|
||||
entry_str = entry_str,
|
||||
disabled = disabled_label,
|
||||
**COLORS)
|
||||
else:
|
||||
valid_answers.append(str(i+1))
|
||||
menu_splash += '{}\n'.format(entry_str)
|
||||
menu_splash += '{}\n'.format(spacer)
|
||||
|
||||
# Add action entries
|
||||
for entry in action_entries:
|
||||
# Add Spacer
|
||||
if ('CRLF' in entry):
|
||||
menu_splash += '{}\n'.format(spacer)
|
||||
valid_answers.append(entry['Letter'])
|
||||
menu_splash += '{letter:>{width}}: {name}\n'.format(
|
||||
letter = entry['Letter'].upper(),
|
||||
width = len(str(len(action_entries))),
|
||||
name = entry['Name'])
|
||||
|
||||
answer = ''
|
||||
|
||||
while (answer.upper() not in valid_answers):
|
||||
clear_screen()
|
||||
print(menu_splash)
|
||||
answer = input('{}: '.format(prompt))
|
||||
|
||||
return answer.upper()
|
||||
|
||||
|
||||
def non_clobber_rename(full_path):
|
||||
"""Append suffix to path, if necessary, to avoid clobbering path"""
|
||||
new_path = full_path
|
||||
_i = 1;
|
||||
while os.path.exists(new_path):
|
||||
new_path = '{path}_{i}'.format(i=_i, path=full_path)
|
||||
_i += 1
|
||||
|
||||
return new_path
|
||||
|
||||
|
||||
def pause(prompt='Press Enter to continue... '):
|
||||
"""Simple pause implementation."""
|
||||
if prompt[-1] != ' ':
|
||||
prompt += ' '
|
||||
input(prompt)
|
||||
|
||||
|
||||
def ping(addr='google.com'):
|
||||
"""Attempt to ping addr."""
|
||||
cmd = [
|
||||
'ping',
|
||||
'-n' if psutil.WINDOWS else '-c',
|
||||
'2',
|
||||
addr]
|
||||
run_program(cmd)
|
||||
|
||||
|
||||
def popen_program(cmd, pipe=False, minimized=False, shell=False, **kwargs):
|
||||
"""Run program and return a subprocess.Popen object."""
|
||||
cmd_kwargs = {'args': cmd, 'shell': shell}
|
||||
for kw in ('encoding', 'errors'):
|
||||
if kw in kwargs:
|
||||
cmd_kwargs[kw] = kwargs[kw]
|
||||
|
||||
if minimized:
|
||||
startupinfo = subprocess.STARTUPINFO()
|
||||
startupinfo.dwFlags = subprocess.STARTF_USESHOWWINDOW
|
||||
startupinfo.wShowWindow = 6
|
||||
cmd_kwargs['startupinfo'] = startupinfo
|
||||
|
||||
if pipe:
|
||||
cmd_kwargs.update({
|
||||
'stdout': subprocess.PIPE,
|
||||
'stderr': subprocess.PIPE,
|
||||
})
|
||||
|
||||
if 'cwd' in kwargs:
|
||||
cmd_kwargs['cwd'] = kwargs['cwd']
|
||||
|
||||
return subprocess.Popen(**cmd_kwargs)
|
||||
|
||||
|
||||
def print_error(*args, **kwargs):
|
||||
"""Prints message to screen in RED."""
|
||||
print_standard(*args, color=COLORS['RED'], **kwargs)
|
||||
|
||||
|
||||
def print_info(*args, **kwargs):
|
||||
"""Prints message to screen in BLUE."""
|
||||
print_standard(*args, color=COLORS['BLUE'], **kwargs)
|
||||
|
||||
|
||||
def print_standard(message='Generic info',
|
||||
color=None, end='\n', timestamp=True, **kwargs):
|
||||
"""Prints message to screen and log (if set)."""
|
||||
display_message = message
|
||||
if color:
|
||||
display_message = color + message + COLORS['CLEAR']
|
||||
# **COLORS is used below to support non-"standard" color printing
|
||||
print(display_message.format(**COLORS), end=end, **kwargs)
|
||||
print_log(message, end, timestamp)
|
||||
|
||||
|
||||
def print_success(*args, **kwargs):
|
||||
"""Prints message to screen in GREEN."""
|
||||
print_standard(*args, color=COLORS['GREEN'], **kwargs)
|
||||
|
||||
|
||||
def print_warning(*args, **kwargs):
|
||||
"""Prints message to screen in YELLOW."""
|
||||
print_standard(*args, color=COLORS['YELLOW'], **kwargs)
|
||||
|
||||
|
||||
def print_log(message='', end='\n', timestamp=True):
|
||||
"""Writes message to a log if LogFile is set."""
|
||||
time_str = time.strftime("%Y-%m-%d %H%M%z: ") if timestamp else ''
|
||||
if 'LogFile' in global_vars and global_vars['LogFile']:
|
||||
with open(global_vars['LogFile'], 'a', encoding='utf-8') as f:
|
||||
for line in message.splitlines():
|
||||
f.write('{timestamp}{line}{end}'.format(
|
||||
timestamp = time_str,
|
||||
line = line,
|
||||
end = end))
|
||||
|
||||
|
||||
def run_program(cmd, check=True, pipe=True, shell=False, **kwargs):
|
||||
"""Run program and return a subprocess.CompletedProcess object."""
|
||||
cmd = [c for c in cmd if c]
|
||||
if shell:
|
||||
cmd = ' '.join(cmd)
|
||||
|
||||
cmd_kwargs = {'args': cmd, 'check': check, 'shell': shell}
|
||||
for kw in ('encoding', 'errors'):
|
||||
if kw in kwargs:
|
||||
cmd_kwargs[kw] = kwargs[kw]
|
||||
|
||||
if pipe:
|
||||
cmd_kwargs.update({
|
||||
'stdout': subprocess.PIPE,
|
||||
'stderr': subprocess.PIPE,
|
||||
})
|
||||
|
||||
if 'cwd' in kwargs:
|
||||
cmd_kwargs['cwd'] = kwargs['cwd']
|
||||
|
||||
return subprocess.run(**cmd_kwargs)
|
||||
|
||||
|
||||
def set_title(title='[Some Title]'):
|
||||
"""Set title.
|
||||
|
||||
Used for window title and menu titles."""
|
||||
global_vars['Title'] = title
|
||||
os.system('title {}'.format(title))
|
||||
|
||||
|
||||
def show_data(
|
||||
message='[Some message]', data='[Some data]',
|
||||
indent=8, width=32,
|
||||
info=False, warning=False, error=False):
|
||||
"""Display info with formatting."""
|
||||
message = '{indent}{message:<{width}}{data}'.format(
|
||||
indent=' '*indent, width=width, message=message, data=data)
|
||||
if error:
|
||||
print_error(message)
|
||||
elif warning:
|
||||
print_warning(message)
|
||||
elif info:
|
||||
print_info(message)
|
||||
else:
|
||||
print_standard(message)
|
||||
|
||||
|
||||
def sleep(seconds=2):
|
||||
"""Wait for a while."""
|
||||
time.sleep(seconds)
|
||||
|
||||
|
||||
def stay_awake():
|
||||
"""Prevent the system from sleeping or hibernating."""
|
||||
# DISABLED due to VCR2008 dependency
|
||||
return
|
||||
# Bail if caffeine is already running
|
||||
for proc in psutil.process_iter():
|
||||
if proc.name() == 'caffeine.exe':
|
||||
return
|
||||
# Extract and run
|
||||
extract_item('Caffeine', silent=True)
|
||||
try:
|
||||
popen_program([global_vars['Tools']['Caffeine']])
|
||||
except Exception:
|
||||
print_error('ERROR: No caffeine available.')
|
||||
print_warning('Please set the power setting to High Performance.')
|
||||
|
||||
|
||||
def strip_colors(s):
|
||||
"""Remove all ASCII color escapes from string, returns str."""
|
||||
for c in COLORS.values():
|
||||
s = s.replace(c, '')
|
||||
return s
|
||||
|
||||
|
||||
def get_exception(s):
|
||||
"""Get exception by name, returns Exception object."""
|
||||
try:
|
||||
obj = getattr(sys.modules[__name__], s)
|
||||
except AttributeError:
|
||||
# Try builtin classes
|
||||
obj = getattr(sys.modules['builtins'], s)
|
||||
return obj
|
||||
|
||||
|
||||
def try_and_print(message='Trying...',
|
||||
function=None, cs='CS', ns='NS', other_results={},
|
||||
catch_all=True, print_return=False, silent_function=True,
|
||||
indent=8, width=32, *args, **kwargs):
|
||||
"""Run function, print if successful or not, and return dict.
|
||||
|
||||
other_results is in the form of
|
||||
{
|
||||
'Warning': {'ExceptionClassName': 'Result Message'},
|
||||
'Error': {'ExceptionClassName': 'Result Message'}
|
||||
}
|
||||
The the ExceptionClassNames will be excepted conditions
|
||||
and the result string will be printed in the correct color.
|
||||
catch_all=False will re-raise unspecified exceptions."""
|
||||
err = None
|
||||
out = None
|
||||
w_exceptions = other_results.get('Warning', {}).keys()
|
||||
w_exceptions = tuple(get_exception(e) for e in w_exceptions)
|
||||
e_exceptions = other_results.get('Error', {}).keys()
|
||||
e_exceptions = tuple(get_exception(e) for e in e_exceptions)
|
||||
w_results = other_results.get('Warning', {})
|
||||
e_results = other_results.get('Error', {})
|
||||
|
||||
# Run function and catch errors
|
||||
print_standard('{indent}{message:<{width}}'.format(
|
||||
indent=' '*indent, message=message, width=width), end='', flush=True)
|
||||
try:
|
||||
out = function(*args, **kwargs)
|
||||
if print_return:
|
||||
str_list = out
|
||||
if isinstance(out, subprocess.CompletedProcess):
|
||||
str_list = out.stdout.decode().strip().splitlines()
|
||||
print_standard(str_list[0].strip(), timestamp=False)
|
||||
for item in str_list[1:]:
|
||||
print_standard('{indent}{item}'.format(
|
||||
indent=' '*(indent+width), item=item.strip()))
|
||||
elif silent_function:
|
||||
print_success(cs, timestamp=False)
|
||||
except w_exceptions as e:
|
||||
_result = w_results.get(e.__class__.__name__, 'Warning')
|
||||
print_warning(_result, timestamp=False)
|
||||
err = e
|
||||
except e_exceptions as e:
|
||||
_result = e_results.get(e.__class__.__name__, 'Error')
|
||||
print_error(_result, timestamp=False)
|
||||
err = e
|
||||
except Exception:
|
||||
print_error(ns, timestamp=False)
|
||||
err = traceback.format_exc()
|
||||
|
||||
# Return or raise?
|
||||
if err and not catch_all:
|
||||
raise
|
||||
else:
|
||||
return {'CS': not bool(err), 'Error': err, 'Out': out}
|
||||
|
||||
|
||||
def upload_crash_details():
|
||||
"""Upload log and runtime data to the CRASH_SERVER.
|
||||
|
||||
Intended for uploading to a public Nextcloud share."""
|
||||
if not ENABLED_UPLOAD_DATA:
|
||||
raise GenericError
|
||||
|
||||
import requests
|
||||
if 'LogFile' in global_vars and global_vars['LogFile']:
|
||||
if ask('Upload crash details to {}?'.format(CRASH_SERVER['Name'])):
|
||||
with open(global_vars['LogFile']) as f:
|
||||
data = '{}\n'.format(f.read())
|
||||
data += '#############################\n'
|
||||
data += 'Runtime Details:\n\n'
|
||||
data += 'sys.argv: {}\n\n'.format(sys.argv)
|
||||
try:
|
||||
data += generate_global_vars_report()
|
||||
except Exception:
|
||||
data += 'global_vars: {}\n'.format(global_vars)
|
||||
filename = global_vars.get('LogFile', 'Unknown')
|
||||
filename = re.sub(r'.*(\\|/)', '', filename)
|
||||
filename += '.txt'
|
||||
url = '{}/Crash_{}__{}'.format(
|
||||
CRASH_SERVER['Url'],
|
||||
global_vars.get('Date-Time', 'Unknown Date-Time'),
|
||||
filename)
|
||||
r = requests.put(
|
||||
url, data=data,
|
||||
headers={'X-Requested-With': 'XMLHttpRequest'},
|
||||
auth=(CRASH_SERVER['User'], CRASH_SERVER['Pass']))
|
||||
# Raise exception if upload NS
|
||||
if not r.ok:
|
||||
raise Exception
|
||||
else:
|
||||
# User said no
|
||||
raise GenericAbort
|
||||
else:
|
||||
# No LogFile defined (or invalid LogFile)
|
||||
raise GenericError
|
||||
|
||||
|
||||
def wait_for_process(name, poll_rate=3):
|
||||
"""Wait for process by name."""
|
||||
running = True
|
||||
while running:
|
||||
sleep(poll_rate)
|
||||
running = False
|
||||
for proc in psutil.process_iter():
|
||||
try:
|
||||
if re.search(r'^{}'.format(name), proc.name(), re.IGNORECASE):
|
||||
running = True
|
||||
except psutil._exceptions.NoSuchProcess:
|
||||
# Assuming process closed during iteration
|
||||
pass
|
||||
sleep(1)
|
||||
|
||||
|
||||
# global_vars functions
|
||||
def init_global_vars(silent=False):
|
||||
"""Sets global variables based on system info."""
|
||||
if not silent:
|
||||
print_info('Initializing')
|
||||
if psutil.WINDOWS:
|
||||
os.system('title Wizard Kit')
|
||||
if psutil.LINUX:
|
||||
init_functions = [
|
||||
['Checking environment...', set_linux_vars],
|
||||
['Clearing collisions...', clean_env_vars],
|
||||
]
|
||||
else:
|
||||
init_functions = [
|
||||
['Checking .bin...', find_bin],
|
||||
['Checking environment...', set_common_vars],
|
||||
['Checking OS...', check_os],
|
||||
['Checking tools...', check_tools],
|
||||
['Creating folders...', make_tmp_dirs],
|
||||
['Clearing collisions...', clean_env_vars],
|
||||
]
|
||||
try:
|
||||
if silent:
|
||||
for f in init_functions:
|
||||
f[1]()
|
||||
else:
|
||||
for f in init_functions:
|
||||
try_and_print(
|
||||
message=f[0], function=f[1],
|
||||
cs='Done', ns='Error', catch_all=False)
|
||||
except:
|
||||
major_exception()
|
||||
|
||||
|
||||
def check_os():
|
||||
"""Set OS specific variables."""
|
||||
tmp = {}
|
||||
|
||||
# Query registry
|
||||
path = r'SOFTWARE\Microsoft\Windows NT\CurrentVersion'
|
||||
with winreg.OpenKey(HKLM, path) as key:
|
||||
for name in ['CurrentBuild', 'CurrentVersion', 'ProductName']:
|
||||
try:
|
||||
tmp[name] = winreg.QueryValueEx(key, name)[0]
|
||||
except FileNotFoundError:
|
||||
tmp[name] = 'Unknown'
|
||||
|
||||
# Handle CurrentBuild collision
|
||||
if tmp['CurrentBuild'] == '9200':
|
||||
if tmp['CurrentVersion'] == '6.2':
|
||||
# Windown 8, set to fake build number
|
||||
tmp['CurrentBuild'] = '9199'
|
||||
else:
|
||||
# Windows 8.1, leave alone
|
||||
pass
|
||||
|
||||
# Check bit depth
|
||||
tmp['Arch'] = 32
|
||||
if 'PROGRAMFILES(X86)' in global_vars['Env']:
|
||||
tmp['Arch'] = 64
|
||||
|
||||
# Get Windows build info
|
||||
build_info = WINDOWS_BUILDS.get(tmp['CurrentBuild'], None)
|
||||
if build_info is None:
|
||||
# Not in windows_builds.py
|
||||
build_info = [
|
||||
'Unknown',
|
||||
'Build {}'.format(tmp['CurrentBuild']),
|
||||
None,
|
||||
None,
|
||||
'unrecognized']
|
||||
else:
|
||||
build_info = list(build_info)
|
||||
tmp['Version'] = build_info.pop(0)
|
||||
tmp['Release'] = build_info.pop(0)
|
||||
tmp['Codename'] = build_info.pop(0)
|
||||
tmp['Marketing Name'] = build_info.pop(0)
|
||||
tmp['Notes'] = build_info.pop(0)
|
||||
|
||||
# Set name
|
||||
tmp['Name'] = tmp['ProductName']
|
||||
if tmp['Release']:
|
||||
tmp['Name'] += ' {}'.format(tmp['Release'])
|
||||
if tmp['Codename']:
|
||||
tmp['Name'] += ' "{}"'.format(tmp['Codename'])
|
||||
if tmp['Marketing Name']:
|
||||
tmp['Name'] += ' / "{}"'.format(tmp['Marketing Name'])
|
||||
tmp['Name'] = re.sub(r'\s+', ' ', tmp['Name'])
|
||||
|
||||
# Set display name
|
||||
tmp['DisplayName'] = '{} x{}'.format(tmp['Name'], tmp['Arch'])
|
||||
if tmp['Notes']:
|
||||
tmp['DisplayName'] += ' ({})'.format(tmp['Notes'])
|
||||
|
||||
global_vars['OS'] = tmp
|
||||
|
||||
|
||||
def check_tools():
|
||||
"""Set tool variables based on OS bit-depth and tool availability."""
|
||||
if global_vars['OS'].get('Arch', 32) == 64:
|
||||
global_vars['Tools'] = {
|
||||
k: v.get('64', v.get('32')) for (k, v) in TOOLS.items()}
|
||||
else:
|
||||
global_vars['Tools'] = {k: v.get('32') for (k, v) in TOOLS.items()}
|
||||
|
||||
# Fix paths
|
||||
global_vars['Tools'] = {k: os.path.join(global_vars['BinDir'], v)
|
||||
for (k, v) in global_vars['Tools'].items()}
|
||||
|
||||
|
||||
def clean_env_vars():
|
||||
"""Remove conflicting global_vars and env variables.
|
||||
|
||||
This fixes an issue where both global_vars and
|
||||
global_vars['Env'] are expanded at the same time."""
|
||||
for key in global_vars.keys():
|
||||
global_vars['Env'].pop(key, None)
|
||||
|
||||
|
||||
def find_bin():
|
||||
"""Find .bin folder in the cwd or it's parents."""
|
||||
wd = os.getcwd()
|
||||
base = None
|
||||
while base is None:
|
||||
if os.path.exists('.bin'):
|
||||
base = os.getcwd()
|
||||
break
|
||||
if re.fullmatch(r'\w:\\', os.getcwd()):
|
||||
break
|
||||
os.chdir('..')
|
||||
os.chdir(wd)
|
||||
if base is None:
|
||||
raise BinNotFoundError
|
||||
global_vars['BaseDir'] = base
|
||||
|
||||
|
||||
def generate_global_vars_report():
|
||||
"""Build readable string from global_vars, returns str."""
|
||||
report = ['global_vars: {']
|
||||
for k, v in sorted(global_vars.items()):
|
||||
if k == 'Env':
|
||||
continue
|
||||
if isinstance(v, list):
|
||||
report.append(' {}: ['.format(str(k)))
|
||||
for item in v:
|
||||
report.append(' {}'.format(str(v)))
|
||||
report.append(' ]')
|
||||
elif isinstance(v, dict):
|
||||
report.append(' {}: {{'.format(str(k)))
|
||||
for item_k, item_v in sorted(v.items()):
|
||||
report.append(' {:<15} {}'.format(
|
||||
str(item_k)+':', str(item_v)))
|
||||
report.append(' }')
|
||||
else:
|
||||
report.append(' {:<18}{}'.format(str(k)+':', str(v)))
|
||||
report.append(' Env:')
|
||||
for k, v in sorted(global_vars.get('Env', {}).items()):
|
||||
report.append(' {:<15} {}'.format(
|
||||
str(k)+':', str(v)))
|
||||
report.append('}')
|
||||
|
||||
return '\n'.join(report)
|
||||
|
||||
|
||||
def make_tmp_dirs():
|
||||
"""Make temp directories."""
|
||||
os.makedirs(global_vars['BackupDir'], exist_ok=True)
|
||||
os.makedirs(global_vars['LogDir'], exist_ok=True)
|
||||
os.makedirs(r'{}\{}'.format(
|
||||
global_vars['LogDir'], KIT_NAME_FULL), exist_ok=True)
|
||||
os.makedirs(r'{}\Tools'.format(global_vars['LogDir']), exist_ok=True)
|
||||
os.makedirs(global_vars['TmpDir'], exist_ok=True)
|
||||
|
||||
|
||||
def set_common_vars():
|
||||
"""Set common variables."""
|
||||
global_vars['Date'] = time.strftime("%Y-%m-%d")
|
||||
global_vars['Date-Time'] = time.strftime("%Y-%m-%d_%H%M_%z")
|
||||
global_vars['Env'] = os.environ.copy()
|
||||
|
||||
global_vars['ArchivePassword'] = ARCHIVE_PASSWORD
|
||||
global_vars['BinDir'] = r'{BaseDir}\.bin'.format(**global_vars)
|
||||
global_vars['CBinDir'] = r'{BaseDir}\.cbin'.format(**global_vars)
|
||||
global_vars['ClientDir'] = r'{SYSTEMDRIVE}\{prefix}'.format(
|
||||
prefix=KIT_NAME_SHORT, **global_vars['Env'])
|
||||
global_vars['BackupDir'] = r'{ClientDir}\Backups'.format(**global_vars)
|
||||
global_vars['LogDir'] = r'{ClientDir}\Logs\{Date}'.format(**global_vars)
|
||||
global_vars['QuarantineDir'] = r'{ClientDir}\Quarantine'.format(**global_vars)
|
||||
global_vars['TmpDir'] = r'{BinDir}\tmp'.format(**global_vars)
|
||||
|
||||
|
||||
def set_linux_vars():
|
||||
"""Set common variables in a Linux environment.
|
||||
|
||||
These assume we're running under a WK-Linux build."""
|
||||
result = run_program(['mktemp', '-d'])
|
||||
global_vars['TmpDir'] = result.stdout.decode().strip()
|
||||
global_vars['Date'] = time.strftime("%Y-%m-%d")
|
||||
global_vars['Date-Time'] = time.strftime("%Y-%m-%d_%H%M_%z")
|
||||
global_vars['Env'] = os.environ.copy()
|
||||
global_vars['BinDir'] = '/usr/local/bin'
|
||||
global_vars['LogDir'] = '{}/Logs'.format(global_vars['Env']['HOME'])
|
||||
global_vars['Tools'] = {
|
||||
'wimlib-imagex': 'wimlib-imagex',
|
||||
'SevenZip': '7z',
|
||||
}
|
||||
|
||||
|
||||
def set_log_file(log_name):
|
||||
"""Sets global var LogFile and creates path as needed."""
|
||||
if psutil.LINUX:
|
||||
folder_path = global_vars['LogDir']
|
||||
else:
|
||||
folder_path = '{}{}{}'.format(
|
||||
global_vars['LogDir'],
|
||||
os.sep,
|
||||
KIT_NAME_FULL)
|
||||
log_file = '{}{}{}'.format(
|
||||
folder_path,
|
||||
os.sep,
|
||||
log_name)
|
||||
os.makedirs(folder_path, exist_ok=True)
|
||||
global_vars['LogFile'] = log_file
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
print("This file is not meant to be called directly.")
|
||||
|
||||
# vim: sts=2 sw=2 ts=2
|
||||
|
|
@ -1,53 +0,0 @@
|
|||
# Wizard Kit: Functions - Network
|
||||
|
||||
import os
|
||||
import shutil
|
||||
import sys
|
||||
|
||||
from functions.common import *
|
||||
|
||||
|
||||
# REGEX
|
||||
REGEX_VALID_IP = re.compile(
|
||||
r'(10.\d+.\d+.\d+'
|
||||
r'|172.(1[6-9]|2\d|3[0-1])'
|
||||
r'|192.168.\d+.\d+)',
|
||||
re.IGNORECASE)
|
||||
|
||||
|
||||
def is_connected():
|
||||
"""Check for a valid private IP."""
|
||||
devs = psutil.net_if_addrs()
|
||||
for dev in devs.values():
|
||||
for family in dev:
|
||||
if REGEX_VALID_IP.search(family.address):
|
||||
# Valid IP found
|
||||
return True
|
||||
# Else
|
||||
return False
|
||||
|
||||
|
||||
def show_valid_addresses():
|
||||
"""Show all valid private IP addresses assigned to the system."""
|
||||
devs = psutil.net_if_addrs()
|
||||
for dev, families in sorted(devs.items()):
|
||||
for family in families:
|
||||
if REGEX_VALID_IP.search(family.address):
|
||||
# Valid IP found
|
||||
show_data(message=dev, data=family.address)
|
||||
|
||||
|
||||
def speedtest():
|
||||
"""Run a network speedtest using speedtest-cli."""
|
||||
result = run_program(['speedtest-cli', '--simple'])
|
||||
output = [line.strip() for line in result.stdout.decode().splitlines()
|
||||
if line.strip()]
|
||||
output = [line.split() for line in output]
|
||||
output = [(a, float(b), c) for a, b, c in output]
|
||||
return ['{:10}{:6.2f} {}'.format(*line) for line in output]
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
print("This file is not meant to be called directly.")
|
||||
|
||||
# vim: sts=2 sw=2 ts=2
|
||||
|
|
@ -1,471 +0,0 @@
|
|||
"""Wizard Kit: Functions - UFD"""
|
||||
# pylint: disable=broad-except,wildcard-import
|
||||
# vim: sts=2 sw=2 ts=2
|
||||
|
||||
import os
|
||||
import re
|
||||
import shutil
|
||||
import pathlib
|
||||
from collections import OrderedDict
|
||||
from functions.common import *
|
||||
|
||||
|
||||
def case_insensitive_search(path, item):
|
||||
"""Search path for item case insensitively, returns str."""
|
||||
regex_match = '^{}$'.format(item)
|
||||
real_path = ''
|
||||
|
||||
# Quick check first
|
||||
if os.path.exists('{}/{}'.format(path, item)):
|
||||
real_path = '{}{}{}'.format(
|
||||
path,
|
||||
'' if path == '/' else '/',
|
||||
item,
|
||||
)
|
||||
|
||||
# Check all items in dir
|
||||
for entry in os.scandir(path):
|
||||
if re.match(regex_match, entry.name, re.IGNORECASE):
|
||||
real_path = '{}{}{}'.format(
|
||||
path,
|
||||
'' if path == '/' else '/',
|
||||
entry.name,
|
||||
)
|
||||
|
||||
# Done
|
||||
if not real_path:
|
||||
raise FileNotFoundError('{}/{}'.format(path, item))
|
||||
|
||||
return real_path
|
||||
|
||||
|
||||
def confirm_selections(args):
|
||||
"""Ask tech to confirm selections, twice if necessary."""
|
||||
if not ask('Is the above information correct?'):
|
||||
abort(False)
|
||||
## Safety check
|
||||
if not args['--update']:
|
||||
print_standard(' ')
|
||||
print_warning('SAFETY CHECK')
|
||||
print_standard(
|
||||
'All data will be DELETED from the disk and partition(s) listed above.')
|
||||
print_standard(
|
||||
'This is irreversible and will lead to {RED}DATA LOSS.{CLEAR}'.format(
|
||||
**COLORS))
|
||||
if not ask('Asking again to confirm, is this correct?'):
|
||||
abort(False)
|
||||
|
||||
print_standard(' ')
|
||||
|
||||
|
||||
def copy_source(source, items, overwrite=False):
|
||||
"""Copy source items to /mnt/UFD."""
|
||||
is_image = source.is_file()
|
||||
|
||||
# Mount source if necessary
|
||||
if is_image:
|
||||
mount(source, '/mnt/Source')
|
||||
|
||||
# Copy items
|
||||
for i_source, i_dest in items:
|
||||
i_source = '{}{}'.format(
|
||||
'/mnt/Source' if is_image else source,
|
||||
i_source,
|
||||
)
|
||||
i_dest = '/mnt/UFD{}'.format(i_dest)
|
||||
try:
|
||||
recursive_copy(i_source, i_dest, overwrite=overwrite)
|
||||
except FileNotFoundError:
|
||||
# Going to assume (hope) that this is fine
|
||||
pass
|
||||
|
||||
# Unmount source if necessary
|
||||
if is_image:
|
||||
unmount('/mnt/Source')
|
||||
|
||||
|
||||
def find_first_partition(dev_path):
|
||||
"""Find path to first partition of dev, returns str."""
|
||||
cmd = [
|
||||
'lsblk',
|
||||
'--list',
|
||||
'--noheadings',
|
||||
'--output', 'name',
|
||||
'--paths',
|
||||
dev_path,
|
||||
]
|
||||
result = run_program(cmd, encoding='utf-8', errors='ignore')
|
||||
part_path = result.stdout.splitlines()[-1].strip()
|
||||
|
||||
return part_path
|
||||
|
||||
|
||||
def find_path(path):
|
||||
"""Find path case-insensitively, returns pathlib.Path obj."""
|
||||
path_obj = pathlib.Path(path).resolve()
|
||||
|
||||
# Quick check first
|
||||
if path_obj.exists():
|
||||
return path_obj
|
||||
|
||||
# Fix case
|
||||
parts = path_obj.relative_to('/').parts
|
||||
real_path = '/'
|
||||
for part in parts:
|
||||
try:
|
||||
real_path = case_insensitive_search(real_path, part)
|
||||
except NotADirectoryError:
|
||||
# Reclassify error
|
||||
raise FileNotFoundError(path)
|
||||
|
||||
# Raise error if path doesn't exist
|
||||
path_obj = pathlib.Path(real_path)
|
||||
if not path_obj.exists():
|
||||
raise FileNotFoundError(path_obj)
|
||||
|
||||
# Done
|
||||
return path_obj
|
||||
|
||||
|
||||
def get_user_home(user):
|
||||
"""Get path to user's home dir, returns str."""
|
||||
home_dir = None
|
||||
cmd = ['getent', 'passwd', user]
|
||||
result = run_program(cmd, encoding='utf-8', errors='ignore', check=False)
|
||||
try:
|
||||
home_dir = result.stdout.split(':')[5]
|
||||
except Exception:
|
||||
# Just use HOME from ENV (or '/root' if that fails)
|
||||
home_dir = os.environ.get('HOME', '/root')
|
||||
|
||||
return home_dir
|
||||
|
||||
|
||||
def get_user_name():
|
||||
"""Get real user name, returns str."""
|
||||
user = None
|
||||
if 'SUDO_USER' in os.environ:
|
||||
user = os.environ.get('SUDO_USER', 'Unknown')
|
||||
else:
|
||||
user = os.environ.get('USER', 'Unknown')
|
||||
|
||||
return user
|
||||
|
||||
|
||||
def hide_items(ufd_dev, items):
|
||||
"""Set FAT32 hidden flag for items."""
|
||||
# pylint: disable=invalid-name
|
||||
with open('/root/.mtoolsrc', 'w') as f:
|
||||
f.write('drive U: file="{}"\n'.format(
|
||||
find_first_partition(ufd_dev)))
|
||||
f.write('mtools_skip_check=1\n')
|
||||
|
||||
# Hide items
|
||||
for item in items:
|
||||
cmd = ['yes | mattrib +h "U:/{}"'.format(item)]
|
||||
run_program(cmd, check=False, shell=True)
|
||||
|
||||
|
||||
def install_syslinux_to_dev(ufd_dev, use_mbr):
|
||||
"""Install Syslinux to UFD (dev)."""
|
||||
cmd = [
|
||||
'dd',
|
||||
'bs=440',
|
||||
'count=1',
|
||||
'if=/usr/lib/syslinux/bios/{}.bin'.format(
|
||||
'mbr' if use_mbr else 'gptmbr',
|
||||
),
|
||||
'of={}'.format(ufd_dev),
|
||||
]
|
||||
run_program(cmd)
|
||||
|
||||
|
||||
def install_syslinux_to_partition(partition):
|
||||
"""Install Syslinux to UFD (partition)."""
|
||||
cmd = [
|
||||
'syslinux',
|
||||
'--install',
|
||||
'--directory',
|
||||
'/arch/boot/syslinux/',
|
||||
partition,
|
||||
]
|
||||
run_program(cmd)
|
||||
|
||||
|
||||
def is_valid_path(path_obj, path_type):
|
||||
"""Verify path_obj is valid by type, returns bool."""
|
||||
valid_path = False
|
||||
if path_type == 'DIR':
|
||||
valid_path = path_obj.is_dir()
|
||||
elif path_type == 'KIT':
|
||||
valid_path = path_obj.is_dir() and path_obj.joinpath('.bin').exists()
|
||||
elif path_type == 'IMG':
|
||||
valid_path = path_obj.is_file() and path_obj.suffix.lower() == '.img'
|
||||
elif path_type == 'ISO':
|
||||
valid_path = path_obj.is_file() and path_obj.suffix.lower() == '.iso'
|
||||
elif path_type == 'UFD':
|
||||
valid_path = path_obj.is_block_device()
|
||||
|
||||
return valid_path
|
||||
|
||||
|
||||
def mount(mount_source, mount_point, read_write=False):
|
||||
"""Mount mount_source on mount_point."""
|
||||
os.makedirs(mount_point, exist_ok=True)
|
||||
cmd = [
|
||||
'mount',
|
||||
mount_source,
|
||||
mount_point,
|
||||
'-o',
|
||||
'rw' if read_write else 'ro',
|
||||
]
|
||||
run_program(cmd)
|
||||
|
||||
|
||||
def prep_device(dev_path, label, use_mbr=False, indent=2):
|
||||
"""Format device in preparation for applying the WizardKit components
|
||||
|
||||
This is done is four steps:
|
||||
1. Zero-out first 64MB (this deletes the partition table and/or bootloader)
|
||||
2. Create a new partition table (GPT by default, optionally MBR)
|
||||
3. Set boot flag
|
||||
4. Format partition (FAT32, 4K aligned)
|
||||
"""
|
||||
# Zero-out first 64MB
|
||||
cmd = 'dd bs=4M count=16 if=/dev/zero of={}'.format(dev_path).split()
|
||||
try_and_print(
|
||||
indent=indent,
|
||||
message='Zeroing first 64MB...',
|
||||
function=run_program,
|
||||
cmd=cmd,
|
||||
)
|
||||
|
||||
# Create partition table
|
||||
cmd = 'parted {} --script -- mklabel {} mkpart primary fat32 4MiB {}'.format(
|
||||
dev_path,
|
||||
'msdos' if use_mbr else 'gpt',
|
||||
'-1s' if use_mbr else '-4MiB',
|
||||
).split()
|
||||
try_and_print(
|
||||
indent=indent,
|
||||
message='Creating partition table...',
|
||||
function=run_program,
|
||||
cmd=cmd,
|
||||
)
|
||||
|
||||
# Set boot flag
|
||||
cmd = 'parted {} set 1 {} on'.format(
|
||||
dev_path,
|
||||
'boot' if use_mbr else 'legacy_boot',
|
||||
).split()
|
||||
try_and_print(
|
||||
indent=indent,
|
||||
message='Setting boot flag...',
|
||||
function=run_program,
|
||||
cmd=cmd,
|
||||
)
|
||||
|
||||
# Format partition
|
||||
cmd = [
|
||||
'mkfs.vfat', '-F', '32',
|
||||
'-n', label,
|
||||
find_first_partition(dev_path),
|
||||
]
|
||||
try_and_print(
|
||||
indent=indent,
|
||||
message='Formatting partition...',
|
||||
function=run_program,
|
||||
cmd=cmd,
|
||||
)
|
||||
|
||||
|
||||
def recursive_copy(source, dest, overwrite=False):
|
||||
"""Copy source to dest recursively.
|
||||
|
||||
NOTE: This uses rsync style source/dest syntax.
|
||||
If the source has a trailing slash then it's contents are copied,
|
||||
otherwise the source itself is copied.
|
||||
|
||||
Examples assuming "ExDir/ExFile.txt" exists:
|
||||
recursive_copy("ExDir", "Dest/") results in "Dest/ExDir/ExFile.txt"
|
||||
recursive_copy("ExDir/", "Dest/") results in "Dest/ExFile.txt"
|
||||
|
||||
NOTE 2: dest does not use find_path because it might not exist.
|
||||
"""
|
||||
copy_contents = source.endswith('/')
|
||||
source = find_path(source)
|
||||
dest = pathlib.Path(dest).resolve().joinpath(source.name)
|
||||
os.makedirs(dest.parent, exist_ok=True)
|
||||
|
||||
if source.is_dir():
|
||||
if copy_contents:
|
||||
# Trailing slash syntax
|
||||
for item in os.scandir(source):
|
||||
recursive_copy(item.path, dest.parent, overwrite=overwrite)
|
||||
elif not dest.exists():
|
||||
# No conflict, copying whole tree (no merging needed)
|
||||
shutil.copytree(source, dest)
|
||||
elif not dest.is_dir():
|
||||
# Refusing to replace file with dir
|
||||
raise FileExistsError('Refusing to replace file: {}'.format(dest))
|
||||
else:
|
||||
# Dest exists and is a dir, merge dirs
|
||||
for item in os.scandir(source):
|
||||
recursive_copy(item.path, dest, overwrite=overwrite)
|
||||
elif source.is_file():
|
||||
if not dest.exists():
|
||||
# No conflict, copying file
|
||||
shutil.copy2(source, dest)
|
||||
elif not dest.is_file():
|
||||
# Refusing to replace dir with file
|
||||
raise FileExistsError('Refusing to replace dir: {}'.format(dest))
|
||||
elif overwrite:
|
||||
# Dest file exists, deleting and replacing file
|
||||
os.remove(dest)
|
||||
shutil.copy2(source, dest)
|
||||
else:
|
||||
# Refusing to delete file when overwrite=False
|
||||
raise FileExistsError('Refusing to delete file: {}'.format(dest))
|
||||
|
||||
|
||||
def remove_arch():
|
||||
"""Remove arch dir from UFD.
|
||||
|
||||
This ensures a clean installation to the UFD and resets the boot files
|
||||
"""
|
||||
shutil.rmtree(find_path('/mnt/UFD/arch'))
|
||||
|
||||
|
||||
def running_as_root():
|
||||
"""Check if running with effective UID of 0, returns bool."""
|
||||
return os.geteuid() == 0
|
||||
|
||||
|
||||
def show_selections(args, sources, ufd_dev, ufd_sources):
|
||||
"""Show selections including non-specified options."""
|
||||
|
||||
# Sources
|
||||
print_info('Sources')
|
||||
for label in ufd_sources.keys():
|
||||
if label in sources:
|
||||
print_standard(' {label:<18} {path}'.format(
|
||||
label=label+':',
|
||||
path=sources[label],
|
||||
))
|
||||
else:
|
||||
print_standard(' {label:<18} {YELLOW}Not Specified{CLEAR}'.format(
|
||||
label=label+':',
|
||||
**COLORS,
|
||||
))
|
||||
print_standard(' ')
|
||||
|
||||
# Destination
|
||||
print_info('Destination')
|
||||
cmd = [
|
||||
'lsblk', '--nodeps', '--noheadings', '--paths',
|
||||
'--output', 'NAME,FSTYPE,TRAN,SIZE,VENDOR,MODEL,SERIAL',
|
||||
ufd_dev,
|
||||
]
|
||||
result = run_program(cmd, check=False, encoding='utf-8', errors='ignore')
|
||||
print_standard(result.stdout.strip())
|
||||
cmd = [
|
||||
'lsblk', '--noheadings', '--paths',
|
||||
'--output', 'NAME,SIZE,FSTYPE,LABEL,MOUNTPOINT',
|
||||
ufd_dev,
|
||||
]
|
||||
result = run_program(cmd, check=False, encoding='utf-8', errors='ignore')
|
||||
for line in result.stdout.splitlines()[1:]:
|
||||
print_standard(line)
|
||||
|
||||
# Notes
|
||||
if args['--update']:
|
||||
print_warning('Updating kit in-place')
|
||||
elif args['--use-mbr']:
|
||||
print_warning('Formatting using legacy MBR')
|
||||
print_standard(' ')
|
||||
|
||||
|
||||
def unmount(mount_point):
|
||||
"""Unmount mount_point."""
|
||||
cmd = ['umount', mount_point]
|
||||
run_program(cmd)
|
||||
|
||||
|
||||
def update_boot_entries(boot_entries, boot_files, iso_label, ufd_label):
|
||||
"""Update boot files for UFD usage"""
|
||||
configs = []
|
||||
|
||||
# Find config files
|
||||
for c_path, c_ext in boot_files.items():
|
||||
c_path = find_path('/mnt/UFD{}'.format(c_path))
|
||||
for item in os.scandir(c_path):
|
||||
if item.name.lower().endswith(c_ext.lower()):
|
||||
configs.append(item.path)
|
||||
|
||||
# Update Linux labels
|
||||
cmd = [
|
||||
'sed',
|
||||
'--in-place',
|
||||
'--regexp-extended',
|
||||
's/{}/{}/'.format(iso_label, ufd_label),
|
||||
*configs,
|
||||
]
|
||||
run_program(cmd)
|
||||
|
||||
# Uncomment extra entries if present
|
||||
for b_path, b_comment in boot_entries.items():
|
||||
try:
|
||||
find_path('/mnt/UFD{}'.format(b_path))
|
||||
except (FileNotFoundError, NotADirectoryError):
|
||||
# Entry not found, continue to next entry
|
||||
continue
|
||||
|
||||
# Entry found, update config files
|
||||
cmd = [
|
||||
'sed',
|
||||
'--in-place',
|
||||
's/#{}#//'.format(b_comment),
|
||||
*configs,
|
||||
]
|
||||
run_program(cmd, check=False)
|
||||
|
||||
|
||||
def verify_sources(args, ufd_sources):
|
||||
"""Check all sources and abort if necessary, returns dict."""
|
||||
sources = OrderedDict()
|
||||
|
||||
for label, data in ufd_sources.items():
|
||||
s_path = args[data['Arg']]
|
||||
if s_path:
|
||||
try:
|
||||
s_path_obj = find_path(s_path)
|
||||
except FileNotFoundError:
|
||||
print_error('ERROR: {} not found: {}'.format(label, s_path))
|
||||
abort(False)
|
||||
if not is_valid_path(s_path_obj, data['Type']):
|
||||
print_error('ERROR: Invalid {} source: {}'.format(label, s_path))
|
||||
abort(False)
|
||||
sources[label] = s_path_obj
|
||||
|
||||
return sources
|
||||
|
||||
|
||||
def verify_ufd(dev_path):
|
||||
"""Check that dev_path is a valid UFD, returns pathlib.Path obj."""
|
||||
ufd_dev = None
|
||||
|
||||
try:
|
||||
ufd_dev = find_path(dev_path)
|
||||
except FileNotFoundError:
|
||||
print_error('ERROR: UFD device not found: {}'.format(dev_path))
|
||||
abort(False)
|
||||
|
||||
if not is_valid_path(ufd_dev, 'UFD'):
|
||||
print_error('ERROR: Invalid UFD device: {}'.format(ufd_dev))
|
||||
abort(False)
|
||||
|
||||
return ufd_dev
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
print("This file is not meant to be called directly.")
|
||||
|
|
@ -1,42 +0,0 @@
|
|||
#!/bin/python3
|
||||
#
|
||||
## Wizard Kit: HW Diagnostics - Audio
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
# Init
|
||||
sys.path.append(os.path.dirname(os.path.realpath(__file__)))
|
||||
from functions.common import *
|
||||
init_global_vars()
|
||||
|
||||
if __name__ == '__main__':
|
||||
try:
|
||||
# Prep
|
||||
clear_screen()
|
||||
print_standard('Hardware Diagnostics: Audio\n')
|
||||
|
||||
# Set volume
|
||||
try:
|
||||
run_program('amixer -q set "Master" 80% unmute'.split())
|
||||
run_program('amixer -q set "PCM" 90% unmute'.split())
|
||||
except subprocess.CalledProcessError:
|
||||
print_error('Failed to set volume')
|
||||
|
||||
# Run tests
|
||||
for mode in ['pink', 'wav']:
|
||||
run_program(
|
||||
cmd = 'speaker-test -c 2 -l 1 -t {}'.format(mode).split(),
|
||||
check = False,
|
||||
pipe = False)
|
||||
|
||||
# Done
|
||||
#print_standard('\nDone.')
|
||||
#pause("Press Enter to exit...")
|
||||
exit_script()
|
||||
except SystemExit as sys_exit:
|
||||
exit_script(sys_exit.code)
|
||||
except:
|
||||
major_exception()
|
||||
|
||||
# vim: sts=2 sw=2 ts=2
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
#!/bin/bash
|
||||
#
|
||||
## Wizard Kit: HW Diagnostics - Benchmarks
|
||||
|
||||
function usage {
|
||||
echo "Usage: ${0} device log-file"
|
||||
echo " e.g. ${0} /dev/sda /tmp/tmp.XXXXXXX/benchmarks.log"
|
||||
}
|
||||
|
||||
# Bail early
|
||||
if [ ! -b "${1}" ]; then
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Run Benchmarks
|
||||
echo 3 | sudo tee -a /proc/sys/vm/drop_caches >/dev/null 2>&1
|
||||
sudo dd bs=4M if="${1}" of=/dev/null status=progress 2>&1 | tee -a "${2}"
|
||||
|
|
@ -1,66 +0,0 @@
|
|||
#!/bin/python3
|
||||
#
|
||||
## Wizard Kit: HW Diagnostics - Menu
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
# Init
|
||||
sys.path.append(os.path.dirname(os.path.realpath(__file__)))
|
||||
from functions.hw_diags import *
|
||||
from functions.tmux import *
|
||||
init_global_vars()
|
||||
|
||||
if __name__ == '__main__':
|
||||
# Show menu
|
||||
try:
|
||||
state = State()
|
||||
menu_diags(state, sys.argv)
|
||||
except KeyboardInterrupt:
|
||||
print_standard(' ')
|
||||
print_warning('Aborted')
|
||||
print_standard(' ')
|
||||
sleep(1)
|
||||
pause('Press Enter to exit...')
|
||||
except SystemExit as sys_exit:
|
||||
tmux_switch_client()
|
||||
exit_script(sys_exit.code)
|
||||
except:
|
||||
# Cleanup
|
||||
tmux_kill_all_panes()
|
||||
|
||||
if DEBUG_MODE:
|
||||
# Custom major exception
|
||||
print_standard(' ')
|
||||
print_error('Major exception')
|
||||
print_warning(SUPPORT_MESSAGE)
|
||||
print(traceback.format_exc())
|
||||
print_log(traceback.format_exc())
|
||||
|
||||
# Save debug reports and upload data
|
||||
try_and_print(
|
||||
message='Saving debug reports...',
|
||||
function=save_debug_reports,
|
||||
state=state, global_vars=global_vars)
|
||||
question = 'Upload crash details to {}?'.format(CRASH_SERVER['Name'])
|
||||
if ENABLED_UPLOAD_DATA and ask(question):
|
||||
try_and_print(
|
||||
message='Uploading Data...',
|
||||
function=upload_logdir,
|
||||
global_vars=global_vars)
|
||||
|
||||
# Done
|
||||
sleep(1)
|
||||
pause('Press Enter to exit...')
|
||||
exit_script(1)
|
||||
|
||||
else:
|
||||
# "Normal" major exception
|
||||
major_exception()
|
||||
|
||||
# Done
|
||||
tmux_kill_all_panes()
|
||||
tmux_switch_client()
|
||||
exit_script()
|
||||
|
||||
# vim: sts=2 sw=2 ts=2
|
||||
|
|
@ -1,48 +0,0 @@
|
|||
#!/bin/python3
|
||||
#
|
||||
## Wizard Kit: HW Diagnostics - Network
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
# Init
|
||||
sys.path.append(os.path.dirname(os.path.realpath(__file__)))
|
||||
from functions.network import *
|
||||
|
||||
|
||||
def check_connection():
|
||||
if not is_connected():
|
||||
# Raise to cause NS in try_and_print()
|
||||
raise Exception
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
try:
|
||||
# Prep
|
||||
clear_screen()
|
||||
print_standard('Hardware Diagnostics: Network\n')
|
||||
|
||||
# Connect
|
||||
print_standard('Initializing...')
|
||||
connect_to_network()
|
||||
|
||||
# Tests
|
||||
try_and_print(
|
||||
message='Network connection:', function=check_connection, cs='OK')
|
||||
show_valid_addresses()
|
||||
try_and_print(message='Internet connection:', function=ping,
|
||||
addr='8.8.8.8', cs='OK')
|
||||
try_and_print(message='DNS Resolution:', function=ping, cs='OK')
|
||||
try_and_print(message='Speedtest:', function=speedtest,
|
||||
print_return=True)
|
||||
|
||||
# Done
|
||||
print_standard('\nDone.')
|
||||
#pause("Press Enter to exit...")
|
||||
exit_script()
|
||||
except SystemExit as sys_exit:
|
||||
exit_script(sys_exit.code)
|
||||
except:
|
||||
major_exception()
|
||||
|
||||
# vim: sts=2 sw=2 ts=2
|
||||
|
|
@ -1,19 +0,0 @@
|
|||
#!/bin/bash
|
||||
#
|
||||
## Wizard Kit: HW Diagnostics - Prime95
|
||||
|
||||
function usage {
|
||||
echo "Usage: $0 log-dir"
|
||||
echo " e.g. $0 /tmp/tmp.7Mh5f1RhSL9001"
|
||||
}
|
||||
|
||||
# Bail early
|
||||
if [ ! -d "$1" ]; then
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Run Prime95
|
||||
cd "$1"
|
||||
mprime -t | grep -iv --line-buffered 'stress.txt' | tee -a "prime.log"
|
||||
|
||||
|
|
@ -1,39 +0,0 @@
|
|||
#!/bin/bash
|
||||
#
|
||||
|
||||
BLUE='\033[34m'
|
||||
CLEAR='\033[0m'
|
||||
IFS=$'\n'
|
||||
|
||||
# List devices
|
||||
for line in $(lsblk -do NAME,TRAN,SIZE,VENDOR,MODEL,SERIAL); do
|
||||
if [[ "${line:0:4}" == "NAME" ]]; then
|
||||
echo -e "${BLUE}${line}${CLEAR}"
|
||||
else
|
||||
echo "${line}"
|
||||
fi
|
||||
done
|
||||
echo ""
|
||||
|
||||
# List loopback devices
|
||||
if [[ "$(losetup -l | wc -l)" > 0 ]]; then
|
||||
for line in $(losetup -lO NAME,PARTSCAN,RO,BACK-FILE); do
|
||||
if [[ "${line:0:4}" == "NAME" ]]; then
|
||||
echo -e "${BLUE}${line}${CLEAR}"
|
||||
else
|
||||
echo "${line}" | sed -r 's#/dev/(loop[0-9]+)#\1 #'
|
||||
fi
|
||||
done
|
||||
echo ""
|
||||
fi
|
||||
|
||||
# List partitions
|
||||
for line in $(lsblk -o NAME,SIZE,FSTYPE,LABEL,MOUNTPOINT); do
|
||||
if [[ "${line:0:4}" == "NAME" ]]; then
|
||||
echo -e "${BLUE}${line}${CLEAR}"
|
||||
else
|
||||
echo "${line}"
|
||||
fi
|
||||
done
|
||||
echo ""
|
||||
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
#!/bin/bash
|
||||
#
|
||||
## Wizard Kit: Sensor monitoring tool
|
||||
|
||||
WINDOW_NAME="Hardware Sensors"
|
||||
MONITOR="hw-sensors-monitor"
|
||||
|
||||
# Start session
|
||||
tmux new-session -n "$WINDOW_NAME" "$MONITOR"
|
||||
|
||||
|
|
@ -1,36 +0,0 @@
|
|||
#!/bin/python3
|
||||
#
|
||||
## Wizard Kit: Sensor monitoring tool
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
# Init
|
||||
sys.path.append(os.path.dirname(os.path.realpath(__file__)))
|
||||
from functions.sensors import *
|
||||
from functions.tmux import *
|
||||
init_global_vars(silent=True)
|
||||
|
||||
if __name__ == '__main__':
|
||||
background = False
|
||||
try:
|
||||
if len(sys.argv) > 1 and os.path.exists(sys.argv[1]):
|
||||
background = True
|
||||
monitor_file = sys.argv[1]
|
||||
monitor_pane = None
|
||||
else:
|
||||
result = run_program(['mktemp'])
|
||||
monitor_file = result.stdout.decode().strip()
|
||||
if not background:
|
||||
monitor_pane = tmux_split_window(
|
||||
percent=1, vertical=True, watch=monitor_file)
|
||||
cmd = ['tmux', 'resize-pane', '-Z', '-t', monitor_pane]
|
||||
run_program(cmd, check=False)
|
||||
monitor_sensors(monitor_pane, monitor_file)
|
||||
exit_script()
|
||||
except SystemExit as sys_exit:
|
||||
exit_script(sys_exit.code)
|
||||
except:
|
||||
major_exception()
|
||||
|
||||
# vim: sts=2 sw=2 ts=2
|
||||
|
|
@ -1,38 +0,0 @@
|
|||
#!/bin/python3
|
||||
#
|
||||
## Wizard Kit: Volume mount tool
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
# Init
|
||||
sys.path.append(os.path.dirname(os.path.realpath(__file__)))
|
||||
from functions.data import *
|
||||
init_global_vars()
|
||||
|
||||
if __name__ == '__main__':
|
||||
try:
|
||||
# Prep
|
||||
clear_screen()
|
||||
print_standard('{}: Volume mount tool'.format(KIT_NAME_FULL))
|
||||
|
||||
# Mount volumes
|
||||
report = mount_volumes(all_devices=True)
|
||||
|
||||
# Print report
|
||||
print_info('\nResults')
|
||||
for vol_name, vol_data in sorted(report.items()):
|
||||
show_data(indent=4, width=20, **vol_data['show_data'])
|
||||
|
||||
# Done
|
||||
print_standard('\nDone.')
|
||||
if 'gui' in sys.argv:
|
||||
pause("Press Enter to exit...")
|
||||
popen_program(['nohup', 'thunar', '/media'], pipe=True)
|
||||
exit_script()
|
||||
except SystemExit as sys_exit:
|
||||
exit_script(sys_exit.code)
|
||||
except:
|
||||
major_exception()
|
||||
|
||||
# vim: sts=2 sw=2 ts=2
|
||||
|
|
@ -1,35 +0,0 @@
|
|||
#!/bin/python3
|
||||
#
|
||||
## Wizard Kit: Backup share mount tool
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
# Init
|
||||
sys.path.append(os.path.dirname(os.path.realpath(__file__)))
|
||||
from functions.data import *
|
||||
from functions.network import *
|
||||
init_global_vars()
|
||||
|
||||
if __name__ == '__main__':
|
||||
try:
|
||||
# Prep
|
||||
clear_screen()
|
||||
|
||||
# Mount
|
||||
if is_connected():
|
||||
mount_backup_shares(read_write=True)
|
||||
else:
|
||||
# Couldn't connect
|
||||
print_error('ERROR: No network connectivity.')
|
||||
|
||||
# Done
|
||||
print_standard('\nDone.')
|
||||
#pause("Press Enter to exit...")
|
||||
exit_script()
|
||||
except SystemExit as sys_exit:
|
||||
exit_script(sys_exit.code)
|
||||
except:
|
||||
major_exception()
|
||||
|
||||
# vim: sts=2 sw=2 ts=2
|
||||
|
|
@ -1,39 +0,0 @@
|
|||
# Wizard Kit: Enter SafeMode by editing the BCD
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
# Init
|
||||
sys.path.append(os.path.dirname(os.path.realpath(__file__)))
|
||||
from functions.safemode import *
|
||||
init_global_vars()
|
||||
os.system('title {}: SafeMode Tool'.format(KIT_NAME_FULL))
|
||||
|
||||
if __name__ == '__main__':
|
||||
try:
|
||||
clear_screen()
|
||||
print_info('{}: SafeMode Tool\n'.format(KIT_NAME_FULL))
|
||||
other_results = {
|
||||
'Error': {'CalledProcessError': 'Unknown Error'},
|
||||
'Warning': {}}
|
||||
|
||||
if not ask('Enable booting to SafeMode (with Networking)?'):
|
||||
abort()
|
||||
|
||||
# Configure SafeMode
|
||||
try_and_print(message='Set BCD option...',
|
||||
function=enable_safemode, other_results=other_results)
|
||||
try_and_print(message='Enable MSI in SafeMode...',
|
||||
function=enable_safemode_msi, other_results=other_results)
|
||||
|
||||
# Done
|
||||
print_standard('\nDone.')
|
||||
pause('Press Enter to reboot...')
|
||||
reboot()
|
||||
exit_script()
|
||||
except SystemExit as sys_exit:
|
||||
exit_script(sys_exit.code)
|
||||
except:
|
||||
major_exception()
|
||||
|
||||
# vim: sts=2 sw=2 ts=2
|
||||
|
|
@ -1,39 +0,0 @@
|
|||
# Wizard Kit: Exit SafeMode by editing the BCD
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
# Init
|
||||
sys.path.append(os.path.dirname(os.path.realpath(__file__)))
|
||||
from functions.safemode import *
|
||||
init_global_vars()
|
||||
os.system('title {}: SafeMode Tool'.format(KIT_NAME_FULL))
|
||||
|
||||
if __name__ == '__main__':
|
||||
try:
|
||||
clear_screen()
|
||||
print_info('{}: SafeMode Tool\n'.format(KIT_NAME_FULL))
|
||||
other_results = {
|
||||
'Error': {'CalledProcessError': 'Unknown Error'},
|
||||
'Warning': {}}
|
||||
|
||||
if not ask('Disable booting to SafeMode?'):
|
||||
abort()
|
||||
|
||||
# Configure SafeMode
|
||||
try_and_print(message='Remove BCD option...',
|
||||
function=disable_safemode, other_results=other_results)
|
||||
try_and_print(message='Disable MSI in SafeMode...',
|
||||
function=disable_safemode_msi, other_results=other_results)
|
||||
|
||||
# Done
|
||||
print_standard('\nDone.')
|
||||
pause('Press Enter to reboot...')
|
||||
reboot()
|
||||
exit_script()
|
||||
except SystemExit as sys_exit:
|
||||
exit_script(sys_exit.code)
|
||||
except:
|
||||
major_exception()
|
||||
|
||||
# vim: sts=2 sw=2 ts=2
|
||||
|
|
@ -1,40 +0,0 @@
|
|||
# Wizard Kit: Check, and possibly repair, system file health via SFC
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
# Init
|
||||
sys.path.append(os.path.dirname(os.path.realpath(__file__)))
|
||||
from functions.repairs import *
|
||||
init_global_vars()
|
||||
os.system('title {}: SFC Tool'.format(KIT_NAME_FULL))
|
||||
set_log_file('SFC Tool.log')
|
||||
|
||||
if __name__ == '__main__':
|
||||
try:
|
||||
stay_awake()
|
||||
clear_screen()
|
||||
print_info('{}: SFC Tool\n'.format(KIT_NAME_FULL))
|
||||
other_results = {
|
||||
'Error': {
|
||||
'CalledProcessError': 'Unknown Error',
|
||||
},
|
||||
'Warning': {
|
||||
'GenericRepair': 'Repaired',
|
||||
}}
|
||||
if ask('Run a SFC scan now?'):
|
||||
try_and_print(message='SFC scan...',
|
||||
function=run_sfc_scan, other_results=other_results)
|
||||
else:
|
||||
abort()
|
||||
|
||||
# Done
|
||||
print_standard('\nDone.')
|
||||
pause('Press Enter to exit...')
|
||||
exit_script()
|
||||
except SystemExit as sys_exit:
|
||||
exit_script(sys_exit.code)
|
||||
except:
|
||||
major_exception()
|
||||
|
||||
# vim: sts=2 sw=2 ts=2
|
||||
48
.gitignore
vendored
|
|
@ -1,41 +1,7 @@
|
|||
**/__pycache__/*
|
||||
*.bak
|
||||
*.exe
|
||||
*.swp
|
||||
.bin/7-Zip/
|
||||
.bin/AIDA64/
|
||||
.bin/BleachBit/
|
||||
.bin/ClassicStartSkin/
|
||||
.bin/ConEmu/
|
||||
.bin/Erunt/
|
||||
.bin/Everything/
|
||||
.bin/FastCopy/
|
||||
.bin/HWiNFO/HWiNFO*.ini
|
||||
.bin/NotepadPlusPlus/
|
||||
.bin/ProcessKiller/
|
||||
.bin/ProduKey/
|
||||
.bin/Python/
|
||||
.bin/Tmp/
|
||||
.bin/XMPlay/
|
||||
.bin/_Drivers/SDIO/
|
||||
.cbin/*.7z
|
||||
.cbin/AIDA64/
|
||||
.cbin/Autoruns/
|
||||
.cbin/BleachBit-Portable/
|
||||
.cbin/BlueScreenView/
|
||||
.cbin/Caffeine/
|
||||
.cbin/Du/
|
||||
.cbin/Everything/
|
||||
.cbin/FirefoxExtensions/
|
||||
.cbin/IObitUninstallerPortable/
|
||||
.cbin/ProduKey/
|
||||
.cbin/TestDisk/
|
||||
.cbin/TreeSizeFree-Portable/
|
||||
.cbin/XMPlay/
|
||||
.cbin/XYplorerFree/
|
||||
.cbin/_Drivers/
|
||||
.cbin/_Office/
|
||||
.cbin/_vcredists/
|
||||
.cbin/wimlib/
|
||||
BUILD*/
|
||||
OUT*/
|
||||
**/__pycache__
|
||||
**/*.7z
|
||||
**/*.bak
|
||||
**/*.exe
|
||||
**/*.swp
|
||||
setup/BUILD*
|
||||
setup/OUT*
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 113 KiB After Width: | Height: | Size: 113 KiB |
|
Before Width: | Height: | Size: 110 KiB After Width: | Height: | Size: 110 KiB |
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 168 KiB After Width: | Height: | Size: 168 KiB |
|
Before Width: | Height: | Size: 4.4 KiB After Width: | Height: | Size: 4.4 KiB |
|
Before Width: | Height: | Size: 98 KiB After Width: | Height: | Size: 98 KiB |
6
scripts/README.md
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
## pylint ##
|
||||
|
||||
These scripts use two spaces per indent instead of the default four. As such you will need to update your pylintrc file or run like this:
|
||||
|
||||
`pylint --indent-after-paren=2 --indent-string=' ' wk`
|
||||
|
||||
31
scripts/activate.py
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
"""Wizard Kit: Activate Windows using a BIOS key"""
|
||||
# vim: sts=2 sw=2 ts=2
|
||||
|
||||
import wk
|
||||
|
||||
|
||||
def main():
|
||||
"""Attempt to activate Windows and show result."""
|
||||
title = f'{wk.cfg.main.KIT_NAME_FULL}: Activation Tool'
|
||||
try_print = wk.std.TryAndPrint()
|
||||
wk.std.clear_screen()
|
||||
wk.std.set_title(title)
|
||||
wk.std.print_info(title)
|
||||
print('')
|
||||
|
||||
# Attempt activation
|
||||
try_print.run('Attempting activation...', wk.os.win.activate_with_bios)
|
||||
|
||||
# Done
|
||||
print('')
|
||||
print('Done.')
|
||||
wk.std.pause('Press Enter to exit...')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
try:
|
||||
main()
|
||||
except SystemExit:
|
||||
raise
|
||||
except: #pylint: disable=bare-except
|
||||
wk.std.major_exception()
|
||||
14
scripts/build-ufd
Executable file
|
|
@ -0,0 +1,14 @@
|
|||
#!/usr/bin/env python3
|
||||
"""Wizard Kit: Build UFD Tool"""
|
||||
# vim: sts=2 sw=2 ts=2
|
||||
|
||||
import wk
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
try:
|
||||
wk.kit.ufd.build_ufd()
|
||||
except SystemExit:
|
||||
raise
|
||||
except: #pylint: disable=bare-except
|
||||
wk.std.major_exception()
|
||||
49
scripts/check_disk.py
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
"""Wizard Kit: Check or repair the %SYSTEMDRIVE% filesystem via CHKDSK"""
|
||||
# vim: sts=2 sw=2 ts=2
|
||||
|
||||
import os
|
||||
import wk
|
||||
|
||||
|
||||
def main():
|
||||
"""Run or schedule CHKDSK and show result."""
|
||||
title = f'{wk.cfg.main.KIT_NAME_FULL}: Check Disk Tool'
|
||||
menu = wk.std.Menu(title=title)
|
||||
try_print = wk.std.TryAndPrint()
|
||||
wk.std.clear_screen()
|
||||
wk.std.set_title(title)
|
||||
print('')
|
||||
|
||||
# Add menu entries
|
||||
menu.add_option('Offline scan')
|
||||
menu.add_option('Online scan')
|
||||
|
||||
# Show menu and make selection
|
||||
selection = menu.simple_select()
|
||||
|
||||
# Run or schedule scan
|
||||
if 'Offline' in selection[0]:
|
||||
function = wk.os.win.run_chkdsk_offline
|
||||
msg_good = 'Scheduled'
|
||||
else:
|
||||
function = wk.os.win.run_chkdsk_online
|
||||
msg_good = 'No issues detected'
|
||||
try_print.run(
|
||||
message=f'CHKDSK ({os.environ.get("SYSTEMDRIVE")})...',
|
||||
function=function,
|
||||
msg_good=msg_good,
|
||||
)
|
||||
|
||||
# Done
|
||||
print('')
|
||||
print('Done.')
|
||||
wk.std.pause('Press Enter to exit...')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
try:
|
||||
main()
|
||||
except SystemExit:
|
||||
raise
|
||||
except: #pylint: disable=bare-except
|
||||
wk.std.major_exception()
|
||||
21
scripts/ddrescue-tui
Executable file
|
|
@ -0,0 +1,21 @@
|
|||
#!/bin/bash
|
||||
#
|
||||
## Wizard Kit: ddrescue TUI Launcher
|
||||
|
||||
# Check if running under Linux
|
||||
os_name="$(uname -s)"
|
||||
if [[ "$os_name" == "Darwin" ]]; then
|
||||
os_name="macOS"
|
||||
fi
|
||||
if [[ "$os_name" != "Linux" ]]; then
|
||||
echo "This script is not supported under $os_name." 1>&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
source ./launch-in-tmux
|
||||
|
||||
SESSION_NAME="ddrescue-tui"
|
||||
WINDOW_NAME="ddrescue TUI"
|
||||
TMUX_CMD="./ddrescue-tui.py"
|
||||
|
||||
launch_in_tmux "$@"
|
||||
14
scripts/ddrescue-tui.py
Executable file
|
|
@ -0,0 +1,14 @@
|
|||
#!/usr/bin/env python3
|
||||
"""Wizard Kit: ddrescue TUI"""
|
||||
# vim: sts=2 sw=2 ts=2
|
||||
|
||||
import wk
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
try:
|
||||
wk.hw.ddrescue.main()
|
||||
except SystemExit:
|
||||
raise
|
||||
except: #pylint: disable=bare-except
|
||||
wk.std.major_exception()
|
||||
|
|
@ -2,10 +2,10 @@
|
|||
#
|
||||
## Wizard Kit: HW Diagnostics Launcher
|
||||
|
||||
source launch-in-tmux
|
||||
source ./launch-in-tmux
|
||||
|
||||
SESSION_NAME="hw-diags"
|
||||
WINDOW_NAME="Hardware Diagnostics"
|
||||
TMUX_CMD="hw-diags-menu"
|
||||
TMUX_CMD="./hw-diags.py"
|
||||
|
||||
launch_in_tmux "$@"
|
||||
14
scripts/hw-diags.py
Executable file
|
|
@ -0,0 +1,14 @@
|
|||
#!/usr/bin/env python3
|
||||
"""Wizard Kit: Hardware Diagnostics"""
|
||||
# vim: sts=2 sw=2 ts=2
|
||||
|
||||
import wk
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
try:
|
||||
wk.hw.diags.main()
|
||||
except SystemExit:
|
||||
raise
|
||||
except: #pylint: disable=bare-except
|
||||
wk.std.major_exception()
|
||||
49
scripts/hw-drive-info
Executable file
|
|
@ -0,0 +1,49 @@
|
|||
#!/bin/bash
|
||||
#
|
||||
|
||||
BLUE='\033[34m'
|
||||
CLEAR='\033[0m'
|
||||
IFS=$'\n'
|
||||
|
||||
# Check if running under Linux
|
||||
os_name="$(uname -s)"
|
||||
if [[ "$os_name" == "Darwin" ]]; then
|
||||
os_name="macOS"
|
||||
fi
|
||||
if [[ "$os_name" != "Linux" ]]; then
|
||||
echo "This script is not supported under $os_name." 1>&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# List devices
|
||||
for line in $(lsblk -do NAME,TRAN,SIZE,VENDOR,MODEL,SERIAL); do
|
||||
if [[ "${line:0:4}" == "NAME" ]]; then
|
||||
echo -e "${BLUE}${line}${CLEAR}"
|
||||
else
|
||||
echo "${line}"
|
||||
fi
|
||||
done
|
||||
echo ""
|
||||
|
||||
# List loopback devices
|
||||
if [[ "$(losetup -l | wc -l)" > 0 ]]; then
|
||||
for line in $(losetup -lO NAME,PARTSCAN,RO,BACK-FILE); do
|
||||
if [[ "${line:0:4}" == "NAME" ]]; then
|
||||
echo -e "${BLUE}${line}${CLEAR}"
|
||||
else
|
||||
echo "${line}" | sed -r 's#/dev/(loop[0-9]+)#\1 #'
|
||||
fi
|
||||
done
|
||||
echo ""
|
||||
fi
|
||||
|
||||
# List partitions
|
||||
for line in $(lsblk -o NAME,SIZE,FSTYPE,LABEL,MOUNTPOINT); do
|
||||
if [[ "${line:0:4}" == "NAME" ]]; then
|
||||
echo -e "${BLUE}${line}${CLEAR}"
|
||||
else
|
||||
echo "${line}"
|
||||
fi
|
||||
done
|
||||
echo ""
|
||||
|
||||
|
|
@ -9,22 +9,32 @@ YELLOW="\e[33m"
|
|||
BLUE="\e[34m"
|
||||
|
||||
function print_in_columns() {
|
||||
string="$1"
|
||||
label="$(echo "$string" | sed -r 's/^\s*(.*:).*/\1/')"
|
||||
value="$(echo "$string" | sed -r 's/^\s*.*:\s*(.*)/\1/')"
|
||||
printf ' %-18s%s\n' "$label" "$value"
|
||||
string="$1"
|
||||
label="$(echo "$string" | sed -r 's/^\s*(.*:).*/\1/')"
|
||||
value="$(echo "$string" | sed -r 's/^\s*.*:\s*(.*)/\1/')"
|
||||
printf ' %-18s%s\n' "$label" "$value"
|
||||
}
|
||||
|
||||
function print_dmi_value() {
|
||||
name="$1"
|
||||
file="/sys/devices/virtual/dmi/id/$2"
|
||||
value="UNKNOWN"
|
||||
if [[ -e "$file" ]]; then
|
||||
value="$(cat "$file")"
|
||||
fi
|
||||
print_in_columns "$name: $value"
|
||||
name="$1"
|
||||
file="/sys/devices/virtual/dmi/id/$2"
|
||||
value="UNKNOWN"
|
||||
if [[ -e "$file" ]]; then
|
||||
value="$(cat "$file")"
|
||||
fi
|
||||
print_in_columns "$name: $value"
|
||||
}
|
||||
|
||||
# Check if running under Linux
|
||||
os_name="$(uname -s)"
|
||||
if [[ "$os_name" == "Darwin" ]]; then
|
||||
os_name="macOS"
|
||||
fi
|
||||
if [[ "$os_name" != "Linux" ]]; then
|
||||
echo "This script is not supported under $os_name." 1>&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# System
|
||||
echo -e "${BLUE}System Information${CLEAR}"
|
||||
print_dmi_value "Vendor" "sys_vendor"
|
||||
|
|
@ -50,58 +60,58 @@ echo ""
|
|||
# Processor
|
||||
echo -e "${BLUE}Processor${CLEAR}"
|
||||
lscpu | grep -E '^(Arch|CPU.s.|Core|Thread|Model name|Virt)' \
|
||||
| sed -r 's/\(s\)(.*:)/s\1 /' \
|
||||
| sed -r 's/CPUs: /Threads:/' \
|
||||
| sed -r 's/^(.*:) / \1/'
|
||||
| sed -r 's/\(s\)(.*:)/s\1 /' \
|
||||
| sed -r 's/CPUs: /Threads:/' \
|
||||
| sed -r 's/^(.*:) / \1/'
|
||||
echo ""
|
||||
|
||||
# Memory
|
||||
echo -e "${BLUE}Memory${CLEAR}"
|
||||
first_device="True"
|
||||
while read -r line; do
|
||||
if [[ "$line" == "Memory Device" ]]; then
|
||||
if [[ "$first_device" == "True" ]]; then
|
||||
first_device="False"
|
||||
else
|
||||
# Add space between devices
|
||||
echo ""
|
||||
fi
|
||||
if [[ "$line" == "Memory Device" ]]; then
|
||||
if [[ "$first_device" == "True" ]]; then
|
||||
first_device="False"
|
||||
else
|
||||
print_in_columns "$line"
|
||||
# Add space between devices
|
||||
echo ""
|
||||
fi
|
||||
else
|
||||
print_in_columns "$line"
|
||||
fi
|
||||
done <<< $(sudo dmidecode -t memory \
|
||||
| grep -E '^(Memory Device|\s+(Type|Size|Speed|Manuf.*|Locator|Part Number):)')
|
||||
| grep -E '^(Memory Device|\s+(Type|Size|Speed|Manuf.*|Locator|Part Number):)')
|
||||
echo ""
|
||||
|
||||
# Graphics
|
||||
echo -e "${BLUE}Graphics${CLEAR}"
|
||||
lspci | grep 'VGA' | sed -r 's/^.*:/ Device: /' \
|
||||
| sed 's/Intel Corporation/Intel/' \
|
||||
| sed 's/Generation Core Processor Family/Gen/' \
|
||||
| sed 's/Integrated Graphics Controller.*/iGPU/'
|
||||
glxinfo 2>/dev/null | grep 'OpenGL renderer' | sed -r 's/^.*:/ OpenGL Renderer: /' \
|
||||
| sed 's/Mesa DRI //'
|
||||
lspci | grep 'VGA' | sed -r 's/^.*:/ Device: /' \
|
||||
| sed 's/Intel Corporation/Intel/' \
|
||||
| sed 's/Generation Core Processor Family/Gen/' \
|
||||
| sed 's/Integrated Graphics Controller.*/iGPU/'
|
||||
glxinfo 2>/dev/null | grep 'OpenGL renderer' | sed -r 's/^.*:/ OpenGL Renderer: /' \
|
||||
| sed 's/Mesa DRI //'
|
||||
echo ""
|
||||
|
||||
# Audio
|
||||
echo -e "${BLUE}Audio${CLEAR}"
|
||||
while read -r line; do
|
||||
if [[ "$line" =~ .*no.soundcards.found.* ]]; then
|
||||
echo " No soundcards found"
|
||||
else
|
||||
print_in_columns "$line"
|
||||
fi
|
||||
if [[ "$line" = .*no.soundcards.found.* ]]; then
|
||||
echo " No soundcards found"
|
||||
else
|
||||
print_in_columns "$line"
|
||||
fi
|
||||
done <<< $(aplay -l 2>&1 | grep -Ei '(^card|no soundcards found)' | sed -r 's/.*\[(.*)\].*\[(.*)\].*/\1: \2/')
|
||||
echo ""
|
||||
|
||||
# Network
|
||||
echo -e "${BLUE}Network${CLEAR}"
|
||||
lspci | grep -Ei '(ethernet|network|wireless|wifi)' \
|
||||
| sed -r 's/.*: (.*)$/ \1/'
|
||||
| sed -r 's/.*: (.*)$/ \1/'
|
||||
echo ""
|
||||
|
||||
# Drives
|
||||
echo -e "${BLUE}Drives${CLEAR}"
|
||||
hw-drive-info | sed 's/^/ /'
|
||||
hw-drive-info | sed 's/^/ /'
|
||||
echo ""
|
||||
|
||||
46
scripts/hw-sensors
Executable file
|
|
@ -0,0 +1,46 @@
|
|||
#!/usr/bin/env python3
|
||||
"""Wizard Kit: Hardware Sensors"""
|
||||
# vim: sts=2 sw=2 ts=2
|
||||
|
||||
import platform
|
||||
|
||||
import wk
|
||||
|
||||
|
||||
def main():
|
||||
"""Show sensor data on screen."""
|
||||
sensors = wk.hw.sensors.Sensors()
|
||||
if platform.system() == 'Darwin':
|
||||
wk.std.clear_screen()
|
||||
while True:
|
||||
print('\033[100A', end='')
|
||||
sensors.update_sensor_data()
|
||||
wk.std.print_report(sensors.generate_report('Current', 'Max'))
|
||||
wk.std.sleep(1)
|
||||
elif platform.system() == 'Linux':
|
||||
proc = wk.exe.run_program(cmd=['mktemp'])
|
||||
sensors.start_background_monitor(
|
||||
out_path=proc.stdout.strip(),
|
||||
exit_on_thermal_limit=False,
|
||||
temp_labels=('Current', 'Max'),
|
||||
)
|
||||
watch_cmd = [
|
||||
'watch',
|
||||
'--color',
|
||||
'--exec',
|
||||
'--no-title',
|
||||
'--interval', '1',
|
||||
'cat',
|
||||
proc.stdout.strip(),
|
||||
]
|
||||
wk.exe.run_program(watch_cmd, check=False, pipe=False)
|
||||
|
||||
if __name__ == '__main__':
|
||||
try:
|
||||
main()
|
||||
except KeyboardInterrupt:
|
||||
pass
|
||||
except SystemExit:
|
||||
raise
|
||||
except: #pylint: disable=bare-except
|
||||
wk.std.major_exception()
|
||||
|
|
@ -13,16 +13,16 @@ function ask() {
|
|||
done
|
||||
}
|
||||
|
||||
die () {
|
||||
function err () {
|
||||
echo "$0:" "$@" >&2
|
||||
exit 1
|
||||
return 1
|
||||
}
|
||||
|
||||
function launch_in_tmux() {
|
||||
# Check for required vars
|
||||
[[ -n "${SESSION_NAME:-}" ]] || die "Required variable missing (SESSION_NAME)"
|
||||
[[ -n "${WINDOW_NAME:-}" ]] || die "Required variable missing (WINDOW_NAME)"
|
||||
[[ -n "${TMUX_CMD:-}" ]] || die "Required variable missing (TMUX_CMD)"
|
||||
[[ -n "${SESSION_NAME:-}" ]] || return $(err "Required variable missing (SESSION_NAME)")
|
||||
[[ -n "${WINDOW_NAME:-}" ]] || return $(err "Required variable missing (WINDOW_NAME)")
|
||||
[[ -n "${TMUX_CMD:-}" ]] || return $(err "Required variable missing (TMUX_CMD)")
|
||||
|
||||
# Check for running session
|
||||
if tmux list-session | grep -q "$SESSION_NAME"; then
|
||||
|
|
@ -32,31 +32,35 @@ function launch_in_tmux() {
|
|||
if [[ -n "${TMUX:-}" ]]; then
|
||||
# Running inside TMUX, switch to session
|
||||
tmux switch-client -t "$SESSION_NAME"
|
||||
if ! jobs %% >/dev/null 2>&1; then
|
||||
# No running jobs, try exiting abandoned tmux session
|
||||
exit 0
|
||||
fi
|
||||
else
|
||||
# Running outside TMUX, attach to session
|
||||
tmux attach-session -t "$SESSION_NAME"
|
||||
fi
|
||||
exit 0
|
||||
return 0
|
||||
elif ask "Kill current session and start new session?"; then
|
||||
tmux kill-session -t "$SESSION_NAME" || \
|
||||
die "Failed to kill session: $SESSION_NAME"
|
||||
else
|
||||
echo "Aborted."
|
||||
echo ""
|
||||
echo -n "Press Enter to exit... "
|
||||
read -r
|
||||
exit 0
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# Start/Rename session
|
||||
# Start session
|
||||
if [[ -n "${TMUX:-}" ]]; then
|
||||
# Running inside TMUX, rename session/window and open the menu
|
||||
# Running inside TMUX, save current session/window names
|
||||
ORIGINAL_SESSION_NAME="$(tmux display-message -p '#S')"
|
||||
ORIGINAL_WINDOW_NAME="$(tmux display-message -p '#W')"
|
||||
tmux rename-session "$SESSION_NAME"
|
||||
tmux rename-window "$WINDOW_NAME"
|
||||
"$TMUX_CMD" "$@"
|
||||
tmux rename-session "${SESSION_NAME}_DONE"
|
||||
tmux rename-window "${WINDOW_NAME}_DONE"
|
||||
# Restore previous session/window names
|
||||
tmux rename-session "${ORIGINAL_SESSION_NAME}"
|
||||
tmux rename-window "${ORIGINAL_WINDOW_NAME}"
|
||||
else
|
||||
# Running outside TMUX, start/attach to session
|
||||
tmux new-session -s "$SESSION_NAME" -n "$WINDOW_NAME" "$TMUX_CMD" "$@"
|
||||
33
scripts/mount-all-volumes
Executable file
|
|
@ -0,0 +1,33 @@
|
|||
#!/usr/bin/env python3
|
||||
"""Wizard Kit: Mount all volumes"""
|
||||
# vim: sts=2 sw=2 ts=2
|
||||
|
||||
import wk
|
||||
|
||||
|
||||
# Functions
|
||||
def main():
|
||||
"""Mount all volumes and show results."""
|
||||
wk.std.print_standard(f'{wk.cfg.main.KIT_NAME_FULL}: Volume mount tool')
|
||||
wk.std.print_standard(' ')
|
||||
|
||||
# Mount volumes and get report
|
||||
wk.std.print_standard('Mounting volumes...')
|
||||
report = wk.os.linux.mount_volumes()
|
||||
|
||||
# Show results
|
||||
wk.std.print_info('Results')
|
||||
wk.std.print_report(report, indent=2)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
if wk.std.PLATFORM != 'Linux':
|
||||
os_name = wk.std.PLATFORM.replace('Darwin', 'macOS')
|
||||
wk.std.print_error(f'This script is not supported under {os_name}.')
|
||||
wk.std.abort()
|
||||
try:
|
||||
main()
|
||||
except SystemExit:
|
||||
raise
|
||||
except: #pylint: disable=bare-except
|
||||
wk.std.major_exception()
|
||||
30
scripts/mount-backup-shares
Executable file
|
|
@ -0,0 +1,30 @@
|
|||
#!/usr/bin/env python3
|
||||
"""Wizard Kit: Mount Backup Shares"""
|
||||
# pylint: disable=invalid-name
|
||||
# vim: sts=2 sw=2 ts=2
|
||||
|
||||
import wk
|
||||
|
||||
|
||||
# Functions
|
||||
def main():
|
||||
"""Attempt to mount backup shares and print report."""
|
||||
wk.std.print_info('Mounting Backup Shares')
|
||||
report = wk.net.mount_backup_shares()
|
||||
for line in report:
|
||||
color = 'GREEN'
|
||||
line = f' {line}'
|
||||
if 'Failed' in line:
|
||||
color = 'RED'
|
||||
elif 'Already' in line:
|
||||
color = 'YELLOW'
|
||||
print(wk.std.color_string(line, color))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
try:
|
||||
main()
|
||||
except SystemExit:
|
||||
raise
|
||||
except: #pylint: disable=bare-except
|
||||
wk.std.major_exception()
|
||||
37
scripts/safemode_enter.py
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
"""Wizard Kit: Enter SafeMode by editing the BCD"""
|
||||
# vim: sts=2 sw=2 ts=2
|
||||
|
||||
import wk
|
||||
|
||||
|
||||
def main():
|
||||
"""Prompt user to enter safe mode."""
|
||||
title = f'{wk.cfg.main.KIT_NAME_FULL}: SafeMode Tool'
|
||||
try_print = wk.std.TryAndPrint()
|
||||
wk.std.clear_screen()
|
||||
wk.std.set_title(title)
|
||||
wk.std.print_info(title)
|
||||
print('')
|
||||
|
||||
# Ask
|
||||
if not wk.std.ask('Enable booting to SafeMode (with Networking)?'):
|
||||
wk.std.abort()
|
||||
print('')
|
||||
|
||||
# Configure SafeMode
|
||||
try_print.run('Set BCD option...', wk.os.win.enable_safemode)
|
||||
try_print.run('Enable MSI in SafeMode...', wk.os.win.enable_safemode_msi)
|
||||
|
||||
# Done
|
||||
print('Done.')
|
||||
wk.std.pause('Press Enter to reboot...')
|
||||
wk.exe.run_program('shutdown -r -t 3'.split(), check=False)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
try:
|
||||
main()
|
||||
except SystemExit:
|
||||
raise
|
||||
except: #pylint: disable=bare-except
|
||||
wk.std.major_exception()
|
||||
37
scripts/safemode_exit.py
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
"""Wizard Kit: Exit SafeMode by editing the BCD"""
|
||||
# vim: sts=2 sw=2 ts=2
|
||||
|
||||
import wk
|
||||
|
||||
|
||||
def main():
|
||||
"""Prompt user to exit safe mode."""
|
||||
title = f'{wk.cfg.main.KIT_NAME_FULL}: SafeMode Tool'
|
||||
try_print = wk.std.TryAndPrint()
|
||||
wk.std.clear_screen()
|
||||
wk.std.set_title(title)
|
||||
wk.std.print_info(title)
|
||||
print('')
|
||||
|
||||
# Ask
|
||||
if not wk.std.ask('Disable booting to SafeMode?'):
|
||||
wk.std.abort()
|
||||
print('')
|
||||
|
||||
# Configure SafeMode
|
||||
try_print.run('Remove BCD option...', wk.os.win.disable_safemode)
|
||||
try_print.run('Disable MSI in SafeMode...', wk.os.win.disable_safemode_msi)
|
||||
|
||||
# Done
|
||||
print('Done.')
|
||||
wk.std.pause('Press Enter to reboot...')
|
||||
wk.exe.run_program('shutdown -r -t 3'.split(), check=False)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
try:
|
||||
main()
|
||||
except SystemExit:
|
||||
raise
|
||||
except: #pylint: disable=bare-except
|
||||
wk.std.major_exception()
|
||||
35
scripts/sfc_scan.py
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
"""Wizard Kit: Check, and possibly repair, system file health via SFC"""
|
||||
# vim: sts=2 sw=2 ts=2
|
||||
|
||||
import wk
|
||||
|
||||
|
||||
def main():
|
||||
"""Run SFC and report result."""
|
||||
title = f'{wk.cfg.main.KIT_NAME_FULL}: SFC Tool'
|
||||
try_print = wk.std.TryAndPrint()
|
||||
wk.std.clear_screen()
|
||||
wk.std.set_title(title)
|
||||
wk.std.print_info(title)
|
||||
print('')
|
||||
|
||||
# Ask
|
||||
if not wk.std.ask('Run a SFC scan now?'):
|
||||
wk.std.abort()
|
||||
print('')
|
||||
|
||||
# Run
|
||||
try_print.run('SFC scan...', wk.os.win.run_sfc_scan)
|
||||
|
||||
# Done
|
||||
print('Done')
|
||||
wk.std.pause('Press Enter to exit...')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
try:
|
||||
main()
|
||||
except SystemExit:
|
||||
raise
|
||||
except: #pylint: disable=bare-except
|
||||
wk.std.major_exception()
|
||||
28
scripts/unmount-backup-shares
Executable file
|
|
@ -0,0 +1,28 @@
|
|||
#!/usr/bin/env python3
|
||||
"""Wizard Kit: Unmount Backup Shares"""
|
||||
# pylint: disable=invalid-name
|
||||
# vim: sts=2 sw=2 ts=2
|
||||
|
||||
import wk
|
||||
|
||||
|
||||
# Functions
|
||||
def main():
|
||||
"""Attempt to mount backup shares and print report."""
|
||||
wk.std.print_info('Unmounting Backup Shares')
|
||||
report = wk.net.unmount_backup_shares()
|
||||
for line in report:
|
||||
color = 'GREEN'
|
||||
line = f' {line}'
|
||||
if 'Not mounted' in line:
|
||||
color = 'YELLOW'
|
||||
print(wk.std.color_string(line, color))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
try:
|
||||
main()
|
||||
except SystemExit:
|
||||
raise
|
||||
except: #pylint: disable=bare-except
|
||||
wk.std.major_exception()
|
||||
11
scripts/watch-mac
Executable file
|
|
@ -0,0 +1,11 @@
|
|||
#!/bin/zsh
|
||||
#
|
||||
## watch-like utility
|
||||
|
||||
WATCH_FILE="${1}"
|
||||
|
||||
while :; do
|
||||
echo -n "\e[100A"
|
||||
cat "${WATCH_FILE}"
|
||||
sleep 1s
|
||||
done
|
||||
434
scripts/wk.prev/functions/common.py
Normal file
|
|
@ -0,0 +1,434 @@
|
|||
# Wizard Kit: Functions - Common
|
||||
|
||||
import os
|
||||
import psutil
|
||||
import re
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
import time
|
||||
import traceback
|
||||
try:
|
||||
import winreg
|
||||
except ModuleNotFoundError:
|
||||
if psutil.WINDOWS:
|
||||
raise
|
||||
|
||||
from settings.main import *
|
||||
from settings.tools import *
|
||||
from settings.windows_builds import *
|
||||
from subprocess import CalledProcessError
|
||||
|
||||
|
||||
# Global variables
|
||||
global_vars = {}
|
||||
|
||||
|
||||
# STATIC VARIABLES
|
||||
COLORS = {
|
||||
'CLEAR': '\033[0m',
|
||||
'RED': '\033[31m',
|
||||
'ORANGE': '\033[31;1m',
|
||||
'GREEN': '\033[32m',
|
||||
'YELLOW': '\033[33m',
|
||||
'BLUE': '\033[34m',
|
||||
'PURPLE': '\033[35m',
|
||||
'CYAN': '\033[36m',
|
||||
}
|
||||
try:
|
||||
HKU = winreg.HKEY_USERS
|
||||
HKCR = winreg.HKEY_CLASSES_ROOT
|
||||
HKCU = winreg.HKEY_CURRENT_USER
|
||||
HKLM = winreg.HKEY_LOCAL_MACHINE
|
||||
except NameError:
|
||||
if psutil.WINDOWS:
|
||||
raise
|
||||
|
||||
|
||||
# Error Classes
|
||||
class BIOSKeyNotFoundError(Exception):
|
||||
pass
|
||||
|
||||
class BinNotFoundError(Exception):
|
||||
pass
|
||||
|
||||
class GenericAbort(Exception):
|
||||
pass
|
||||
|
||||
class GenericError(Exception):
|
||||
pass
|
||||
|
||||
class GenericRepair(Exception):
|
||||
pass
|
||||
|
||||
class MultipleInstallationsError(Exception):
|
||||
pass
|
||||
|
||||
class NoProfilesError(Exception):
|
||||
pass
|
||||
|
||||
class Not4KAlignedError(Exception):
|
||||
pass
|
||||
|
||||
class NotInstalledError(Exception):
|
||||
pass
|
||||
|
||||
class OSInstalledLegacyError(Exception):
|
||||
pass
|
||||
|
||||
class PathNotFoundError(Exception):
|
||||
pass
|
||||
|
||||
class UnsupportedOSError(Exception):
|
||||
pass
|
||||
|
||||
class SecureBootDisabledError(Exception):
|
||||
pass
|
||||
|
||||
class SecureBootNotAvailError(Exception):
|
||||
pass
|
||||
|
||||
class SecureBootUnknownError(Exception):
|
||||
pass
|
||||
|
||||
class WindowsOutdatedError(Exception):
|
||||
pass
|
||||
|
||||
class WindowsUnsupportedError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
# General functions
|
||||
def exit_script(return_value=0):
|
||||
"""Exits the script after some cleanup and opens the log (if set)."""
|
||||
# Remove dirs (if empty)
|
||||
for dir in ['BackupDir', 'LogDir', 'TmpDir']:
|
||||
try:
|
||||
os.rmdir(global_vars[dir])
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
# Open Log (if it exists)
|
||||
log = global_vars.get('LogFile', '')
|
||||
if log and os.path.exists(log) and psutil.WINDOWS and ENABLED_OPEN_LOGS:
|
||||
try:
|
||||
extract_item('NotepadPlusPlus', silent=True)
|
||||
popen_program(
|
||||
[global_vars['Tools']['NotepadPlusPlus'],
|
||||
global_vars['LogFile']])
|
||||
except Exception:
|
||||
print_error('ERROR: Failed to extract Notepad++ and open log.')
|
||||
pause('Press Enter to exit...')
|
||||
|
||||
# Kill Caffeine if still running
|
||||
kill_process('caffeine.exe')
|
||||
|
||||
# Exit
|
||||
sys.exit(return_value)
|
||||
|
||||
|
||||
def extract_item(item, filter='', silent=False):
|
||||
"""Extract item from .cbin into .bin."""
|
||||
cmd = [
|
||||
global_vars['Tools']['SevenZip'], 'x', '-aos', '-bso0', '-bse0',
|
||||
'-p{ArchivePassword}'.format(**global_vars),
|
||||
r'-o{BinDir}\{item}'.format(item=item, **global_vars),
|
||||
r'{CBinDir}\{item}.7z'.format(item=item, **global_vars),
|
||||
filter]
|
||||
if not silent:
|
||||
print_standard('Extracting "{item}"...'.format(item=item))
|
||||
try:
|
||||
run_program(cmd)
|
||||
except FileNotFoundError:
|
||||
if not silent:
|
||||
print_warning('WARNING: Archive not found')
|
||||
except subprocess.CalledProcessError:
|
||||
if not silent:
|
||||
print_warning('WARNING: Errors encountered while exctracting data')
|
||||
|
||||
|
||||
def get_process(name=None):
|
||||
"""Get process by name, returns psutil.Process obj."""
|
||||
proc = None
|
||||
if not name:
|
||||
raise GenericError
|
||||
|
||||
for p in psutil.process_iter():
|
||||
try:
|
||||
if p.name() == name:
|
||||
proc = p
|
||||
except psutil._exceptions.NoSuchProcess:
|
||||
# Process finished during iteration? Going to ignore
|
||||
pass
|
||||
return proc
|
||||
|
||||
|
||||
def get_ticket_number():
|
||||
"""Get TicketNumber from user, save in LogDir, and return as str."""
|
||||
if not ENABLED_TICKET_NUMBERS:
|
||||
return None
|
||||
ticket_number = None
|
||||
while ticket_number is None:
|
||||
_input = input('Enter ticket number: ')
|
||||
if re.match(r'^([0-9]+([-_]?\w+|))$', _input):
|
||||
ticket_number = _input
|
||||
out_file = r'{}\TicketNumber'.format(global_vars['LogDir'])
|
||||
if not psutil.WINDOWS:
|
||||
out_file = out_file.replace('\\', '/')
|
||||
with open(out_file, 'w', encoding='utf-8') as f:
|
||||
f.write(ticket_number)
|
||||
return ticket_number
|
||||
|
||||
|
||||
def kill_process(name):
|
||||
"""Kill any running caffeine.exe processes."""
|
||||
for proc in psutil.process_iter():
|
||||
if proc.name() == name:
|
||||
proc.kill()
|
||||
|
||||
|
||||
def stay_awake():
|
||||
"""Prevent the system from sleeping or hibernating."""
|
||||
# DISABLED due to VCR2008 dependency
|
||||
return
|
||||
# Bail if caffeine is already running
|
||||
for proc in psutil.process_iter():
|
||||
if proc.name() == 'caffeine.exe':
|
||||
return
|
||||
# Extract and run
|
||||
extract_item('Caffeine', silent=True)
|
||||
try:
|
||||
popen_program([global_vars['Tools']['Caffeine']])
|
||||
except Exception:
|
||||
print_error('ERROR: No caffeine available.')
|
||||
print_warning('Please set the power setting to High Performance.')
|
||||
|
||||
|
||||
def wait_for_process(name, poll_rate=3):
|
||||
"""Wait for process by name."""
|
||||
running = True
|
||||
while running:
|
||||
sleep(poll_rate)
|
||||
running = False
|
||||
for proc in psutil.process_iter():
|
||||
try:
|
||||
if re.search(r'^{}'.format(name), proc.name(), re.IGNORECASE):
|
||||
running = True
|
||||
except psutil._exceptions.NoSuchProcess:
|
||||
# Assuming process closed during iteration
|
||||
pass
|
||||
sleep(1)
|
||||
|
||||
|
||||
# global_vars functions
|
||||
def init_global_vars(silent=False):
|
||||
"""Sets global variables based on system info."""
|
||||
if not silent:
|
||||
print_info('Initializing')
|
||||
if psutil.WINDOWS:
|
||||
os.system('title Wizard Kit')
|
||||
if psutil.LINUX:
|
||||
init_functions = [
|
||||
['Checking environment...', set_linux_vars],
|
||||
['Clearing collisions...', clean_env_vars],
|
||||
]
|
||||
else:
|
||||
init_functions = [
|
||||
['Checking .bin...', find_bin],
|
||||
['Checking environment...', set_common_vars],
|
||||
['Checking OS...', check_os],
|
||||
['Checking tools...', check_tools],
|
||||
['Creating folders...', make_tmp_dirs],
|
||||
['Clearing collisions...', clean_env_vars],
|
||||
]
|
||||
try:
|
||||
if silent:
|
||||
for f in init_functions:
|
||||
f[1]()
|
||||
else:
|
||||
for f in init_functions:
|
||||
try_and_print(
|
||||
message=f[0], function=f[1],
|
||||
cs='Done', ns='Error', catch_all=False)
|
||||
except:
|
||||
major_exception()
|
||||
|
||||
|
||||
def check_os():
|
||||
"""Set OS specific variables."""
|
||||
tmp = {}
|
||||
|
||||
# Query registry
|
||||
path = r'SOFTWARE\Microsoft\Windows NT\CurrentVersion'
|
||||
with winreg.OpenKey(HKLM, path) as key:
|
||||
for name in ['CurrentBuild', 'CurrentVersion', 'ProductName']:
|
||||
try:
|
||||
tmp[name] = winreg.QueryValueEx(key, name)[0]
|
||||
except FileNotFoundError:
|
||||
tmp[name] = 'Unknown'
|
||||
|
||||
# Handle CurrentBuild collision
|
||||
if tmp['CurrentBuild'] == '9200':
|
||||
if tmp['CurrentVersion'] == '6.2':
|
||||
# Windown 8, set to fake build number
|
||||
tmp['CurrentBuild'] = '9199'
|
||||
else:
|
||||
# Windows 8.1, leave alone
|
||||
pass
|
||||
|
||||
# Check bit depth
|
||||
tmp['Arch'] = 32
|
||||
if 'PROGRAMFILES(X86)' in global_vars['Env']:
|
||||
tmp['Arch'] = 64
|
||||
|
||||
# Get Windows build info
|
||||
build_info = WINDOWS_BUILDS.get(tmp['CurrentBuild'], None)
|
||||
if build_info is None:
|
||||
# Not in windows_builds.py
|
||||
build_info = [
|
||||
'Unknown',
|
||||
'Build {}'.format(tmp['CurrentBuild']),
|
||||
None,
|
||||
None,
|
||||
'unrecognized']
|
||||
else:
|
||||
build_info = list(build_info)
|
||||
tmp['Version'] = build_info.pop(0)
|
||||
tmp['Release'] = build_info.pop(0)
|
||||
tmp['Codename'] = build_info.pop(0)
|
||||
tmp['Marketing Name'] = build_info.pop(0)
|
||||
tmp['Notes'] = build_info.pop(0)
|
||||
|
||||
# Set name
|
||||
tmp['Name'] = tmp['ProductName']
|
||||
if tmp['Release']:
|
||||
tmp['Name'] += ' {}'.format(tmp['Release'])
|
||||
if tmp['Codename']:
|
||||
tmp['Name'] += ' "{}"'.format(tmp['Codename'])
|
||||
if tmp['Marketing Name']:
|
||||
tmp['Name'] += ' / "{}"'.format(tmp['Marketing Name'])
|
||||
tmp['Name'] = re.sub(r'\s+', ' ', tmp['Name'])
|
||||
|
||||
# Set display name
|
||||
tmp['DisplayName'] = '{} x{}'.format(tmp['Name'], tmp['Arch'])
|
||||
if tmp['Notes']:
|
||||
tmp['DisplayName'] += ' ({})'.format(tmp['Notes'])
|
||||
|
||||
global_vars['OS'] = tmp
|
||||
|
||||
|
||||
def check_tools():
|
||||
"""Set tool variables based on OS bit-depth and tool availability."""
|
||||
if global_vars['OS'].get('Arch', 32) == 64:
|
||||
global_vars['Tools'] = {
|
||||
k: v.get('64', v.get('32')) for (k, v) in TOOLS.items()}
|
||||
else:
|
||||
global_vars['Tools'] = {k: v.get('32') for (k, v) in TOOLS.items()}
|
||||
|
||||
# Fix paths
|
||||
global_vars['Tools'] = {k: os.path.join(global_vars['BinDir'], v)
|
||||
for (k, v) in global_vars['Tools'].items()}
|
||||
|
||||
|
||||
def clean_env_vars():
|
||||
"""Remove conflicting global_vars and env variables.
|
||||
|
||||
This fixes an issue where both global_vars and
|
||||
global_vars['Env'] are expanded at the same time."""
|
||||
for key in global_vars.keys():
|
||||
global_vars['Env'].pop(key, None)
|
||||
|
||||
|
||||
def find_bin():
|
||||
"""Find .bin folder in the cwd or it's parents."""
|
||||
wd = os.getcwd()
|
||||
base = None
|
||||
while base is None:
|
||||
if os.path.exists('.bin'):
|
||||
base = os.getcwd()
|
||||
break
|
||||
if re.fullmatch(r'\w:\\', os.getcwd()):
|
||||
break
|
||||
os.chdir('..')
|
||||
os.chdir(wd)
|
||||
if base is None:
|
||||
raise BinNotFoundError
|
||||
global_vars['BaseDir'] = base
|
||||
|
||||
|
||||
def generate_global_vars_report():
|
||||
"""Build readable string from global_vars, returns str."""
|
||||
report = ['global_vars: {']
|
||||
for k, v in sorted(global_vars.items()):
|
||||
if k == 'Env':
|
||||
continue
|
||||
if isinstance(v, list):
|
||||
report.append(' {}: ['.format(str(k)))
|
||||
for item in v:
|
||||
report.append(' {}'.format(str(v)))
|
||||
report.append(' ]')
|
||||
elif isinstance(v, dict):
|
||||
report.append(' {}: {{'.format(str(k)))
|
||||
for item_k, item_v in sorted(v.items()):
|
||||
report.append(' {:<15} {}'.format(
|
||||
str(item_k)+':', str(item_v)))
|
||||
report.append(' }')
|
||||
else:
|
||||
report.append(' {:<18}{}'.format(str(k)+':', str(v)))
|
||||
report.append(' Env:')
|
||||
for k, v in sorted(global_vars.get('Env', {}).items()):
|
||||
report.append(' {:<15} {}'.format(
|
||||
str(k)+':', str(v)))
|
||||
report.append('}')
|
||||
|
||||
return '\n'.join(report)
|
||||
|
||||
|
||||
def make_tmp_dirs():
|
||||
"""Make temp directories."""
|
||||
os.makedirs(global_vars['BackupDir'], exist_ok=True)
|
||||
os.makedirs(global_vars['LogDir'], exist_ok=True)
|
||||
os.makedirs(r'{}\{}'.format(
|
||||
global_vars['LogDir'], KIT_NAME_FULL), exist_ok=True)
|
||||
os.makedirs(r'{}\Tools'.format(global_vars['LogDir']), exist_ok=True)
|
||||
os.makedirs(global_vars['TmpDir'], exist_ok=True)
|
||||
|
||||
|
||||
def set_common_vars():
|
||||
"""Set common variables."""
|
||||
global_vars['Date'] = time.strftime("%Y-%m-%d")
|
||||
global_vars['Date-Time'] = time.strftime("%Y-%m-%d_%H%M_%z")
|
||||
global_vars['Env'] = os.environ.copy()
|
||||
|
||||
global_vars['ArchivePassword'] = ARCHIVE_PASSWORD
|
||||
global_vars['BinDir'] = r'{BaseDir}\.bin'.format(**global_vars)
|
||||
global_vars['CBinDir'] = r'{BaseDir}\.cbin'.format(**global_vars)
|
||||
global_vars['ClientDir'] = r'{SYSTEMDRIVE}\{prefix}'.format(
|
||||
prefix=KIT_NAME_SHORT, **global_vars['Env'])
|
||||
global_vars['BackupDir'] = r'{ClientDir}\Backups'.format(**global_vars)
|
||||
global_vars['LogDir'] = r'{ClientDir}\Logs\{Date}'.format(**global_vars)
|
||||
global_vars['QuarantineDir'] = r'{ClientDir}\Quarantine'.format(**global_vars)
|
||||
global_vars['TmpDir'] = r'{BinDir}\tmp'.format(**global_vars)
|
||||
|
||||
|
||||
def set_linux_vars():
|
||||
"""Set common variables in a Linux environment.
|
||||
|
||||
These assume we're running under a WK-Linux build."""
|
||||
result = run_program(['mktemp', '-d'])
|
||||
global_vars['TmpDir'] = result.stdout.decode().strip()
|
||||
global_vars['Date'] = time.strftime("%Y-%m-%d")
|
||||
global_vars['Date-Time'] = time.strftime("%Y-%m-%d_%H%M_%z")
|
||||
global_vars['Env'] = os.environ.copy()
|
||||
global_vars['BinDir'] = '/usr/local/bin'
|
||||
global_vars['LogDir'] = '{}/Logs'.format(global_vars['Env']['HOME'])
|
||||
global_vars['Tools'] = {
|
||||
'wimlib-imagex': 'wimlib-imagex',
|
||||
'SevenZip': '7z',
|
||||
}
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
print("This file is not meant to be called directly.")
|
||||
|
||||
# vim: sts=2 sw=2 ts=2
|
||||