Merge remote-tracking branch 'upstream/dev' into dev
This commit is contained in:
commit
0fcfc4b5ac
10 changed files with 179 additions and 96 deletions
|
|
@ -7,6 +7,7 @@ import time
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
from functions.osticket import *
|
from functions.osticket import *
|
||||||
from functions.sensors import *
|
from functions.sensors import *
|
||||||
|
from functions.threading import *
|
||||||
from functions.tmux import *
|
from functions.tmux import *
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -83,6 +84,12 @@ TMUX_LAYOUT = OrderedDict({
|
||||||
'Top': {'y': 2, 'Check': True},
|
'Top': {'y': 2, 'Check': True},
|
||||||
'Started': {'x': SIDE_PANE_WIDTH, 'Check': True},
|
'Started': {'x': SIDE_PANE_WIDTH, 'Check': True},
|
||||||
'Progress': {'x': SIDE_PANE_WIDTH, 'Check': True},
|
'Progress': {'x': SIDE_PANE_WIDTH, 'Check': True},
|
||||||
|
# Testing panes
|
||||||
|
'Prime95': {'y': 11, 'Check': False},
|
||||||
|
'Temps': {'y': 1000, 'Check': False},
|
||||||
|
'SMART': {'y': 3, 'Check': True},
|
||||||
|
'badblocks': {'y': 5, 'Check': True},
|
||||||
|
'I/O Benchmark': {'y': 1000, 'Check': False},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -153,6 +160,11 @@ class DiskObj():
|
||||||
self.smartctl = {}
|
self.smartctl = {}
|
||||||
self.tests = OrderedDict()
|
self.tests = OrderedDict()
|
||||||
self.get_details()
|
self.get_details()
|
||||||
|
|
||||||
|
# Try enabling SMART
|
||||||
|
run_program(['sudo', 'smartctl', '--smart=on', self.path], check=False)
|
||||||
|
|
||||||
|
# Get NVMe/SMART data and set description
|
||||||
self.get_smart_details()
|
self.get_smart_details()
|
||||||
self.description = '{size} ({tran}) {model} {serial}'.format(
|
self.description = '{size} ({tran}) {model} {serial}'.format(
|
||||||
**self.lsblk)
|
**self.lsblk)
|
||||||
|
|
@ -421,7 +433,9 @@ class DiskObj():
|
||||||
|
|
||||||
# Check for attributes
|
# Check for attributes
|
||||||
if KEY_NVME in self.smartctl:
|
if KEY_NVME in self.smartctl:
|
||||||
self.nvme_attributes.update(self.smartctl[KEY_NVME])
|
self.nvme_attributes = {
|
||||||
|
k: {'name': k, 'raw': int(v), 'raw_str': str(v)}
|
||||||
|
for k, v in self.smartctl[KEY_NVME].items()}
|
||||||
elif KEY_SMART in self.smartctl:
|
elif KEY_SMART in self.smartctl:
|
||||||
for a in self.smartctl[KEY_SMART].get('table', {}):
|
for a in self.smartctl[KEY_SMART].get('table', {}):
|
||||||
try:
|
try:
|
||||||
|
|
@ -456,7 +470,7 @@ class DiskObj():
|
||||||
self.check_attributes(silent)
|
self.check_attributes(silent)
|
||||||
|
|
||||||
# Check if a self-test is currently running
|
# Check if a self-test is currently running
|
||||||
if 'remaining_percent' in self.smart_self_test['status']:
|
if 'remaining_percent' in self.smart_self_test.get('status', ''):
|
||||||
_msg = 'SMART self-test in progress, all tests disabled'
|
_msg = 'SMART self-test in progress, all tests disabled'
|
||||||
|
|
||||||
# Ask to abort
|
# Ask to abort
|
||||||
|
|
@ -643,12 +657,25 @@ def build_status_string(label, status, info_label=False):
|
||||||
**COLORS)
|
**COLORS)
|
||||||
|
|
||||||
|
|
||||||
def fix_tmux_panes(state, tmux_layout):
|
def fix_tmux_panes_loop(state):
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
fix_tmux_panes(state)
|
||||||
|
sleep(1)
|
||||||
|
except AttributeError:
|
||||||
|
# tmux_layout attribute has been deleted, exit function
|
||||||
|
return
|
||||||
|
except RuntimeError:
|
||||||
|
# Assuming layout definitions changes mid-run, ignoring
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def fix_tmux_panes(state):
|
||||||
"""Fix pane sizes if the window has been resized."""
|
"""Fix pane sizes if the window has been resized."""
|
||||||
needs_fixed = False
|
needs_fixed = False
|
||||||
|
|
||||||
# Check layout
|
# Check layout
|
||||||
for k, v in tmux_layout.items():
|
for k, v in state.tmux_layout.items():
|
||||||
if not v.get('Check'):
|
if not v.get('Check'):
|
||||||
# Not concerned with the size of this pane
|
# Not concerned with the size of this pane
|
||||||
continue
|
continue
|
||||||
|
|
@ -673,7 +700,7 @@ def fix_tmux_panes(state, tmux_layout):
|
||||||
return
|
return
|
||||||
|
|
||||||
# Update layout
|
# Update layout
|
||||||
for k, v in tmux_layout.items():
|
for k, v in state.tmux_layout.items():
|
||||||
# Get target
|
# Get target
|
||||||
target = None
|
target = None
|
||||||
if k != 'Current':
|
if k != 'Current':
|
||||||
|
|
@ -879,6 +906,18 @@ def run_badblocks_test(state, test):
|
||||||
if test.disabled:
|
if test.disabled:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
def _save_badblocks_output(read_all=False, timeout=0.1):
|
||||||
|
"""Get badblocks output and append to both file and var."""
|
||||||
|
_output = ''
|
||||||
|
while _output is not None:
|
||||||
|
_output = test.badblocks_nbsr.read(0.1)
|
||||||
|
if _output is not None:
|
||||||
|
test.badblocks_stderr += _output.decode()
|
||||||
|
with open(test.badblocks_out, 'a') as f:
|
||||||
|
f.write(_output.decode())
|
||||||
|
if not read_all:
|
||||||
|
break
|
||||||
|
|
||||||
# Prep
|
# Prep
|
||||||
print_log('Starting badblocks test for {}'.format(test.dev.path))
|
print_log('Starting badblocks test for {}'.format(test.dev.path))
|
||||||
test.started = True
|
test.started = True
|
||||||
|
|
@ -890,10 +929,6 @@ def run_badblocks_test(state, test):
|
||||||
state.panes['Top'],
|
state.panes['Top'],
|
||||||
text='{}\n{}'.format(
|
text='{}\n{}'.format(
|
||||||
TOP_PANE_TEXT, test.dev.description))
|
TOP_PANE_TEXT, test.dev.description))
|
||||||
test.tmux_layout = TMUX_LAYOUT.copy()
|
|
||||||
test.tmux_layout.update({
|
|
||||||
'badblocks': {'y': 5, 'Check': True},
|
|
||||||
})
|
|
||||||
|
|
||||||
# Create monitor pane
|
# Create monitor pane
|
||||||
test.badblocks_out = '{}/badblocks_{}.out'.format(
|
test.badblocks_out = '{}/badblocks_{}.out'.format(
|
||||||
|
|
@ -908,29 +943,26 @@ def run_badblocks_test(state, test):
|
||||||
|
|
||||||
# Start badblocks
|
# Start badblocks
|
||||||
print_standard('Running badblocks test...')
|
print_standard('Running badblocks test...')
|
||||||
try:
|
|
||||||
test.badblocks_proc = popen_program(
|
test.badblocks_proc = popen_program(
|
||||||
['sudo', 'hw-diags-badblocks', test.dev.path, test.badblocks_out],
|
['sudo', 'badblocks', '-sv', '-e', '1', test.dev.path],
|
||||||
pipe=True)
|
pipe=True, bufsize=1)
|
||||||
while True:
|
test.badblocks_nbsr = NonBlockingStreamReader(test.badblocks_proc.stderr)
|
||||||
try:
|
test.badblocks_stderr = ''
|
||||||
test.badblocks_proc.wait(timeout=1)
|
|
||||||
except subprocess.TimeoutExpired:
|
|
||||||
fix_tmux_panes(state, test.tmux_layout)
|
|
||||||
else:
|
|
||||||
# badblocks finished, exit loop
|
|
||||||
break
|
|
||||||
|
|
||||||
|
# Update progress loop
|
||||||
|
try:
|
||||||
|
while test.badblocks_proc.poll() is None:
|
||||||
|
_save_badblocks_output()
|
||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
|
run_program(['killall', 'badblocks'], check=False)
|
||||||
test.aborted = True
|
test.aborted = True
|
||||||
|
|
||||||
|
# Save remaining badblocks output
|
||||||
|
_save_badblocks_output(read_all=True)
|
||||||
|
|
||||||
# Check result and build report
|
# Check result and build report
|
||||||
test.report.append('{BLUE}badblocks{CLEAR}'.format(**COLORS))
|
test.report.append('{BLUE}badblocks{CLEAR}'.format(**COLORS))
|
||||||
try:
|
for line in test.badblocks_stderr.splitlines():
|
||||||
test.badblocks_out = test.badblocks_proc.stdout.read().decode()
|
|
||||||
except Exception as err:
|
|
||||||
test.badblocks_out = 'Error: {}'.format(err)
|
|
||||||
for line in test.badblocks_out.splitlines():
|
|
||||||
line = line.strip()
|
line = line.strip()
|
||||||
if not line or re.search(r'^Checking', line, re.IGNORECASE):
|
if not line or re.search(r'^Checking', line, re.IGNORECASE):
|
||||||
# Skip empty and progress lines
|
# Skip empty and progress lines
|
||||||
|
|
@ -964,7 +996,7 @@ def run_badblocks_test(state, test):
|
||||||
update_progress_pane(state)
|
update_progress_pane(state)
|
||||||
|
|
||||||
# Cleanup
|
# Cleanup
|
||||||
tmux_kill_pane(state.panes['badblocks'])
|
tmux_kill_pane(state.panes.pop('badblocks', None))
|
||||||
|
|
||||||
|
|
||||||
def run_hw_tests(state):
|
def run_hw_tests(state):
|
||||||
|
|
@ -979,6 +1011,7 @@ def run_hw_tests(state):
|
||||||
# Build Panes
|
# Build Panes
|
||||||
update_progress_pane(state)
|
update_progress_pane(state)
|
||||||
build_outer_panes(state)
|
build_outer_panes(state)
|
||||||
|
start_tmux_repair_thread(state)
|
||||||
|
|
||||||
# Show selected tests and create TestObj()s
|
# Show selected tests and create TestObj()s
|
||||||
print_info('Selected Tests:')
|
print_info('Selected Tests:')
|
||||||
|
|
@ -1031,16 +1064,22 @@ def run_hw_tests(state):
|
||||||
f = v['Function']
|
f = v['Function']
|
||||||
for test_obj in v['Objects']:
|
for test_obj in v['Objects']:
|
||||||
f(state, test_obj)
|
f(state, test_obj)
|
||||||
|
if not v['Objects']:
|
||||||
|
# No devices available
|
||||||
|
v['Objects'].append(TestObj(dev=None, label=''))
|
||||||
|
v['Objects'][-1].update_status('N/A')
|
||||||
if k == TESTS_CPU[-1]:
|
if k == TESTS_CPU[-1]:
|
||||||
# Last CPU test run, post CPU results
|
# Last CPU test run, post CPU results
|
||||||
state.ost.post_device_results(state.cpu, state.ticket_id)
|
state.ost.post_device_results(state.cpu, state.ticket_id)
|
||||||
except GenericAbort:
|
except GenericAbort:
|
||||||
# Cleanup
|
# Cleanup
|
||||||
|
stop_tmux_repair_thread(state)
|
||||||
tmux_kill_pane(*state.panes.values())
|
tmux_kill_pane(*state.panes.values())
|
||||||
|
|
||||||
# Rebuild panes
|
# Rebuild panes
|
||||||
update_progress_pane(state)
|
update_progress_pane(state)
|
||||||
build_outer_panes(state)
|
build_outer_panes(state)
|
||||||
|
start_tmux_repair_thread(state)
|
||||||
|
|
||||||
# Mark unfinished tests as aborted
|
# Mark unfinished tests as aborted
|
||||||
for k, v in state.tests.items():
|
for k, v in state.tests.items():
|
||||||
|
|
@ -1087,6 +1126,7 @@ def run_hw_tests(state):
|
||||||
print_standard(' ')
|
print_standard(' ')
|
||||||
|
|
||||||
# Done
|
# Done
|
||||||
|
sleep(1)
|
||||||
if state.quick_mode:
|
if state.quick_mode:
|
||||||
pause('Press Enter to exit... ')
|
pause('Press Enter to exit... ')
|
||||||
else:
|
else:
|
||||||
|
|
@ -1094,6 +1134,7 @@ def run_hw_tests(state):
|
||||||
|
|
||||||
# Cleanup
|
# Cleanup
|
||||||
state.ost.disconnect(full=True)
|
state.ost.disconnect(full=True)
|
||||||
|
stop_tmux_repair_thread(state)
|
||||||
tmux_kill_pane(*state.panes.values())
|
tmux_kill_pane(*state.panes.values())
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1114,11 +1155,7 @@ def run_io_benchmark(state, test):
|
||||||
state.panes['Top'],
|
state.panes['Top'],
|
||||||
text='{}\n{}'.format(
|
text='{}\n{}'.format(
|
||||||
TOP_PANE_TEXT, test.dev.description))
|
TOP_PANE_TEXT, test.dev.description))
|
||||||
test.tmux_layout = TMUX_LAYOUT.copy()
|
state.tmux_layout['Current'] = {'y': 15, 'Check': True}
|
||||||
test.tmux_layout.update({
|
|
||||||
'io_benchmark': {'y': 1000, 'Check': False},
|
|
||||||
'Current': {'y': 15, 'Check': True},
|
|
||||||
})
|
|
||||||
|
|
||||||
# Create monitor pane
|
# Create monitor pane
|
||||||
test.io_benchmark_out = '{}/io_benchmark_{}.out'.format(
|
test.io_benchmark_out = '{}/io_benchmark_{}.out'.format(
|
||||||
|
|
@ -1175,9 +1212,6 @@ def run_io_benchmark(state, test):
|
||||||
# Update offset
|
# Update offset
|
||||||
offset += test.dev.dd_chunk_blocks + skip
|
offset += test.dev.dd_chunk_blocks + skip
|
||||||
|
|
||||||
# Fix panes
|
|
||||||
fix_tmux_panes(state, test.tmux_layout)
|
|
||||||
|
|
||||||
except DeviceTooSmallError:
|
except DeviceTooSmallError:
|
||||||
# Device too small, skipping test
|
# Device too small, skipping test
|
||||||
test.update_status('N/A')
|
test.update_status('N/A')
|
||||||
|
|
@ -1252,7 +1286,8 @@ def run_io_benchmark(state, test):
|
||||||
update_progress_pane(state)
|
update_progress_pane(state)
|
||||||
|
|
||||||
# Cleanup
|
# Cleanup
|
||||||
tmux_kill_pane(state.panes['io_benchmark'])
|
state.tmux_layout.pop('Current', None)
|
||||||
|
tmux_kill_pane(state.panes.pop('io_benchmark', None))
|
||||||
|
|
||||||
|
|
||||||
def run_keyboard_test():
|
def run_keyboard_test():
|
||||||
|
|
@ -1278,12 +1313,6 @@ def run_mprime_test(state, test):
|
||||||
tmux_update_pane(
|
tmux_update_pane(
|
||||||
state.panes['Top'],
|
state.panes['Top'],
|
||||||
text='{}\n{}'.format(TOP_PANE_TEXT, test.dev.name))
|
text='{}\n{}'.format(TOP_PANE_TEXT, test.dev.name))
|
||||||
test.tmux_layout = TMUX_LAYOUT.copy()
|
|
||||||
test.tmux_layout.update({
|
|
||||||
'Temps': {'y': 1000, 'Check': False},
|
|
||||||
'mprime': {'y': 11, 'Check': False},
|
|
||||||
'Current': {'y': 3, 'Check': True},
|
|
||||||
})
|
|
||||||
|
|
||||||
# Start live sensor monitor
|
# Start live sensor monitor
|
||||||
test.sensors_out = '{}/sensors.out'.format(global_vars['TmpDir'])
|
test.sensors_out = '{}/sensors.out'.format(global_vars['TmpDir'])
|
||||||
|
|
@ -1296,11 +1325,12 @@ def run_mprime_test(state, test):
|
||||||
pipe=True)
|
pipe=True)
|
||||||
|
|
||||||
# Create monitor and worker panes
|
# Create monitor and worker panes
|
||||||
state.panes['mprime'] = tmux_split_window(
|
state.panes['Prime95'] = tmux_split_window(
|
||||||
lines=10, vertical=True, text=' ')
|
lines=10, vertical=True, text=' ')
|
||||||
state.panes['Temps'] = tmux_split_window(
|
state.panes['Temps'] = tmux_split_window(
|
||||||
behind=True, percent=80, vertical=True, watch=test.sensors_out)
|
behind=True, percent=80, vertical=True, watch=test.sensors_out)
|
||||||
tmux_resize_pane(global_vars['Env']['TMUX_PANE'], y=3)
|
tmux_resize_pane(global_vars['Env']['TMUX_PANE'], y=3)
|
||||||
|
state.tmux_layout['Current'] = {'y': 3, 'Check': True}
|
||||||
|
|
||||||
# Get idle temps
|
# Get idle temps
|
||||||
clear_screen()
|
clear_screen()
|
||||||
|
|
@ -1315,7 +1345,7 @@ def run_mprime_test(state, test):
|
||||||
test.abort_msg = 'If running too hot, press CTRL+c to abort the test'
|
test.abort_msg = 'If running too hot, press CTRL+c to abort the test'
|
||||||
run_program(['apple-fans', 'max'])
|
run_program(['apple-fans', 'max'])
|
||||||
tmux_update_pane(
|
tmux_update_pane(
|
||||||
state.panes['mprime'],
|
state.panes['Prime95'],
|
||||||
command=['hw-diags-prime95', global_vars['TmpDir']],
|
command=['hw-diags-prime95', global_vars['TmpDir']],
|
||||||
working_dir=global_vars['TmpDir'])
|
working_dir=global_vars['TmpDir'])
|
||||||
time_limit = int(MPRIME_LIMIT) * 60
|
time_limit = int(MPRIME_LIMIT) * 60
|
||||||
|
|
@ -1337,9 +1367,6 @@ def run_mprime_test(state, test):
|
||||||
print('{YELLOW}{msg}{CLEAR}'.format(msg=test.abort_msg, **COLORS))
|
print('{YELLOW}{msg}{CLEAR}'.format(msg=test.abort_msg, **COLORS))
|
||||||
update_sensor_data(test.sensor_data)
|
update_sensor_data(test.sensor_data)
|
||||||
|
|
||||||
# Fix panes
|
|
||||||
fix_tmux_panes(state, test.tmux_layout)
|
|
||||||
|
|
||||||
# Wait
|
# Wait
|
||||||
sleep(1)
|
sleep(1)
|
||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
|
|
@ -1357,7 +1384,7 @@ def run_mprime_test(state, test):
|
||||||
# Stop Prime95 (twice for good measure)
|
# Stop Prime95 (twice for good measure)
|
||||||
run_program(['killall', '-s', 'INT', 'mprime'], check=False)
|
run_program(['killall', '-s', 'INT', 'mprime'], check=False)
|
||||||
sleep(1)
|
sleep(1)
|
||||||
tmux_kill_pane(state.panes['mprime'])
|
tmux_kill_pane(state.panes.pop('Prime95', None))
|
||||||
|
|
||||||
# Get cooldown temp
|
# Get cooldown temp
|
||||||
run_program(['apple-fans', 'auto'])
|
run_program(['apple-fans', 'auto'])
|
||||||
|
|
@ -1451,7 +1478,11 @@ def run_mprime_test(state, test):
|
||||||
update_progress_pane(state)
|
update_progress_pane(state)
|
||||||
|
|
||||||
# Cleanup
|
# Cleanup
|
||||||
tmux_kill_pane(state.panes['mprime'], state.panes['Temps'])
|
state.tmux_layout.pop('Current', None)
|
||||||
|
tmux_kill_pane(
|
||||||
|
state.panes.pop('Prime95', None),
|
||||||
|
state.panes.pop('Temps', None),
|
||||||
|
)
|
||||||
test.monitor_proc.kill()
|
test.monitor_proc.kill()
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1480,10 +1511,6 @@ def run_nvme_smart_tests(state, test):
|
||||||
state.panes['Top'],
|
state.panes['Top'],
|
||||||
text='{}\n{}'.format(
|
text='{}\n{}'.format(
|
||||||
TOP_PANE_TEXT, test.dev.description))
|
TOP_PANE_TEXT, test.dev.description))
|
||||||
test.tmux_layout = TMUX_LAYOUT.copy()
|
|
||||||
test.tmux_layout.update({
|
|
||||||
'smart': {'y': 3, 'Check': True},
|
|
||||||
})
|
|
||||||
|
|
||||||
# NVMe
|
# NVMe
|
||||||
if test.dev.nvme_attributes:
|
if test.dev.nvme_attributes:
|
||||||
|
|
@ -1523,7 +1550,7 @@ def run_nvme_smart_tests(state, test):
|
||||||
global_vars['LogDir'], test.dev.name)
|
global_vars['LogDir'], test.dev.name)
|
||||||
with open(test.smart_out, 'w') as f:
|
with open(test.smart_out, 'w') as f:
|
||||||
f.write('SMART self-test status:\n Starting...')
|
f.write('SMART self-test status:\n Starting...')
|
||||||
state.panes['smart'] = tmux_split_window(
|
state.panes['SMART'] = tmux_split_window(
|
||||||
lines=3, vertical=True, watch=test.smart_out)
|
lines=3, vertical=True, watch=test.smart_out)
|
||||||
|
|
||||||
# Show attributes
|
# Show attributes
|
||||||
|
|
@ -1538,15 +1565,8 @@ def run_nvme_smart_tests(state, test):
|
||||||
|
|
||||||
# Monitor progress
|
# Monitor progress
|
||||||
try:
|
try:
|
||||||
for i in range(int(test.timeout*60)):
|
for i in range(int(test.timeout*60/5)):
|
||||||
sleep(1)
|
sleep(5)
|
||||||
|
|
||||||
# Fix panes
|
|
||||||
fix_tmux_panes(state, test.tmux_layout)
|
|
||||||
|
|
||||||
# Only update SMART progress every 5 seconds
|
|
||||||
if i % 5 != 0:
|
|
||||||
continue
|
|
||||||
|
|
||||||
# Update SMART data
|
# Update SMART data
|
||||||
test.dev.get_smart_details()
|
test.dev.get_smart_details()
|
||||||
|
|
@ -1596,7 +1616,7 @@ def run_nvme_smart_tests(state, test):
|
||||||
test.dev.disable_test(t, 'Denied')
|
test.dev.disable_test(t, 'Denied')
|
||||||
|
|
||||||
# Cleanup
|
# Cleanup
|
||||||
tmux_kill_pane(state.panes['smart'])
|
tmux_kill_pane(state.panes.pop('SMART', None))
|
||||||
|
|
||||||
# Save report
|
# Save report
|
||||||
test.report = test.dev.generate_attribute_report(
|
test.report = test.dev.generate_attribute_report(
|
||||||
|
|
@ -1651,11 +1671,27 @@ def show_results(state):
|
||||||
for disk in state.disks:
|
for disk in state.disks:
|
||||||
show_report(disk.generate_disk_report(), log_report=True)
|
show_report(disk.generate_disk_report(), log_report=True)
|
||||||
print_standard(' ')
|
print_standard(' ')
|
||||||
|
if not state.disks:
|
||||||
|
print_warning('No devices')
|
||||||
|
print_standard(' ')
|
||||||
|
|
||||||
# Update progress
|
# Update progress
|
||||||
update_progress_pane(state)
|
update_progress_pane(state)
|
||||||
|
|
||||||
|
|
||||||
|
def start_tmux_repair_thread(state):
|
||||||
|
"""Fix tmux panes as long as state.tmux_layout attribute exists."""
|
||||||
|
state.tmux_layout = TMUX_LAYOUT.copy()
|
||||||
|
start_thread(fix_tmux_panes_loop, args=[state])
|
||||||
|
|
||||||
|
|
||||||
|
def stop_tmux_repair_thread(state):
|
||||||
|
"""Stop previous thread by causing an AttributeError in the thread."""
|
||||||
|
if hasattr(state, 'tmux_layout'):
|
||||||
|
del state.tmux_layout
|
||||||
|
sleep(1)
|
||||||
|
|
||||||
|
|
||||||
def update_main_options(state, selection, main_options):
|
def update_main_options(state, selection, main_options):
|
||||||
"""Update menu and state based on selection."""
|
"""Update menu and state based on selection."""
|
||||||
index = int(selection) - 1
|
index = int(selection) - 1
|
||||||
|
|
|
||||||
|
|
@ -108,14 +108,27 @@ def get_raw_sensor_data():
|
||||||
"""Read sensor data and return dict."""
|
"""Read sensor data and return dict."""
|
||||||
data = {}
|
data = {}
|
||||||
cmd = ['sensors', '-j']
|
cmd = ['sensors', '-j']
|
||||||
|
|
||||||
|
# Get raw data
|
||||||
try:
|
try:
|
||||||
result = run_program(cmd)
|
result = run_program(cmd)
|
||||||
data = json.loads(result.stdout.decode())
|
|
||||||
except subprocess.CalledProcessError:
|
except subprocess.CalledProcessError:
|
||||||
# Assuming no sensors available, return empty dict below
|
# Assuming no sensors available, return empty dict below
|
||||||
pass
|
pass
|
||||||
|
|
||||||
return data
|
# Workaround for bad sensors
|
||||||
|
raw_data = []
|
||||||
|
for line in result.stdout.decode().splitlines():
|
||||||
|
if line.strip() == ',':
|
||||||
|
# Assuming malformatted line caused by missing data
|
||||||
|
continue
|
||||||
|
raw_data.append(line)
|
||||||
|
|
||||||
|
# Parse JSON data
|
||||||
|
json_data = json.loads('\n'.join(raw_data))
|
||||||
|
|
||||||
|
# Done
|
||||||
|
return json_data
|
||||||
|
|
||||||
|
|
||||||
def get_sensor_data():
|
def get_sensor_data():
|
||||||
|
|
@ -134,6 +147,9 @@ def get_sensor_data():
|
||||||
## current temp is labeled xxxx_input
|
## current temp is labeled xxxx_input
|
||||||
for _source, _labels in _sources.items():
|
for _source, _labels in _sources.items():
|
||||||
for _label, _temp in _labels.items():
|
for _label, _temp in _labels.items():
|
||||||
|
if _label.startswith('fan'):
|
||||||
|
# Skip fan RPMs
|
||||||
|
continue
|
||||||
if 'input' in _label:
|
if 'input' in _label:
|
||||||
sensor_data[_section][_adapter][_source] = {
|
sensor_data[_section][_adapter][_source] = {
|
||||||
'Current': _temp,
|
'Current': _temp,
|
||||||
|
|
|
||||||
47
.bin/Scripts/functions/threading.py
Normal file
47
.bin/Scripts/functions/threading.py
Normal file
|
|
@ -0,0 +1,47 @@
|
||||||
|
# Wizard Kit: Functions - Threading
|
||||||
|
|
||||||
|
from threading import Thread
|
||||||
|
from queue import Queue, Empty
|
||||||
|
|
||||||
|
# Classes
|
||||||
|
class NonBlockingStreamReader():
|
||||||
|
"""Class to allow non-blocking reads from a stream."""
|
||||||
|
# Credits:
|
||||||
|
## https://gist.github.com/EyalAr/7915597
|
||||||
|
## https://stackoverflow.com/a/4896288
|
||||||
|
|
||||||
|
def __init__(self, stream):
|
||||||
|
self.stream = stream
|
||||||
|
self.queue = Queue()
|
||||||
|
|
||||||
|
def populate_queue(stream, queue):
|
||||||
|
"""Collect lines from stream and put them in queue."""
|
||||||
|
while True:
|
||||||
|
line = stream.read(1)
|
||||||
|
if line:
|
||||||
|
queue.put(line)
|
||||||
|
|
||||||
|
self.thread = start_thread(
|
||||||
|
populate_queue,
|
||||||
|
args=(self.stream, self.queue))
|
||||||
|
|
||||||
|
def read(self, timeout=None):
|
||||||
|
try:
|
||||||
|
return self.queue.get(block = timeout is not None,
|
||||||
|
timeout = timeout)
|
||||||
|
except Empty:
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
# Functions
|
||||||
|
def start_thread(function, args=[], daemon=True):
|
||||||
|
"""Run function as thread in background, returns Thread object."""
|
||||||
|
thread = Thread(target=function, args=args, daemon=daemon)
|
||||||
|
thread.start()
|
||||||
|
return thread
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
print("This file is not meant to be called directly.")
|
||||||
|
|
||||||
|
# vim: sts=2 sw=2 ts=2
|
||||||
|
|
@ -44,6 +44,9 @@ def tmux_kill_pane(*panes):
|
||||||
"""Kill tmux pane by id."""
|
"""Kill tmux pane by id."""
|
||||||
cmd = ['tmux', 'kill-pane', '-t']
|
cmd = ['tmux', 'kill-pane', '-t']
|
||||||
for pane_id in panes:
|
for pane_id in panes:
|
||||||
|
if not pane_id:
|
||||||
|
# Skip empty strings, None values, etc
|
||||||
|
continue
|
||||||
run_program(cmd+[pane_id], check=False)
|
run_program(cmd+[pane_id], check=False)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,18 +0,0 @@
|
||||||
#!/bin/bash
|
|
||||||
#
|
|
||||||
## Wizard Kit: HW Diagnostics - badblocks
|
|
||||||
|
|
||||||
function usage {
|
|
||||||
echo "Usage: $0 device log-file"
|
|
||||||
echo " e.g. $0 /dev/sda /tmp/tmp.XXXXXXX/badblocks.log"
|
|
||||||
}
|
|
||||||
|
|
||||||
# Bail early
|
|
||||||
if [ ! -b "$1" ]; then
|
|
||||||
usage
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Run Badblocks
|
|
||||||
sudo badblocks -sv -e 1 "$1" 2>&1 | tee -a "$2"
|
|
||||||
|
|
||||||
|
|
@ -105,8 +105,3 @@ echo -e "${BLUE}Drives${CLEAR}"
|
||||||
hw-drive-info | sed 's/^/ /'
|
hw-drive-info | sed 's/^/ /'
|
||||||
echo ""
|
echo ""
|
||||||
|
|
||||||
# Sensors
|
|
||||||
echo -e "${BLUE}Sensors${CLEAR}"
|
|
||||||
hw-sensors | sed 's/^/ /'
|
|
||||||
echo ""
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ os.chdir(os.path.dirname(os.path.realpath(__file__)))
|
||||||
sys.path.append(os.getcwd())
|
sys.path.append(os.getcwd())
|
||||||
from functions.sensors import *
|
from functions.sensors import *
|
||||||
from functions.tmux import *
|
from functions.tmux import *
|
||||||
init_global_vars()
|
init_global_vars(silent=True)
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
background = False
|
background = False
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ aic94xx-firmware
|
||||||
bash-pipes
|
bash-pipes
|
||||||
hfsprogs
|
hfsprogs
|
||||||
i3lock-fancy-git
|
i3lock-fancy-git
|
||||||
|
macbook12-spi-driver-dkms
|
||||||
mprime
|
mprime
|
||||||
openbox-patched
|
openbox-patched
|
||||||
smartmontools-svn
|
smartmontools-svn
|
||||||
|
|
|
||||||
1
.linux_items/packages/live_add_min
Normal file
1
.linux_items/packages/live_add_min
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
macbook12-spi-driver-dkms
|
||||||
|
|
@ -198,7 +198,9 @@ function update_live_env() {
|
||||||
sed -i "/$p/d" "$LIVE_DIR/packages.x86_64"
|
sed -i "/$p/d" "$LIVE_DIR/packages.x86_64"
|
||||||
done < "$ROOT_DIR/.linux_items/packages/live_remove"
|
done < "$ROOT_DIR/.linux_items/packages/live_remove"
|
||||||
cat "$ROOT_DIR/.linux_items/packages/live_add" >> "$LIVE_DIR/packages.x86_64"
|
cat "$ROOT_DIR/.linux_items/packages/live_add" >> "$LIVE_DIR/packages.x86_64"
|
||||||
if [[ "${1:-}" != "--minimal" ]]; then
|
if [[ "${1:-}" == "--minimal" ]]; then
|
||||||
|
cat "$ROOT_DIR/.linux_items/packages/live_add_min" >> "$LIVE_DIR/packages.x86_64"
|
||||||
|
else
|
||||||
cat "$ROOT_DIR/.linux_items/packages/live_add_x" >> "$LIVE_DIR/packages.x86_64"
|
cat "$ROOT_DIR/.linux_items/packages/live_add_x" >> "$LIVE_DIR/packages.x86_64"
|
||||||
fi
|
fi
|
||||||
echo "[custom]" >> "$LIVE_DIR/pacman.conf"
|
echo "[custom]" >> "$LIVE_DIR/pacman.conf"
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue