Added map data loading sections
This commit is contained in:
parent
fc0a37999b
commit
7d7dc70630
1 changed files with 59 additions and 15 deletions
|
|
@ -10,10 +10,8 @@ import pathlib
|
||||||
import plistlib
|
import plistlib
|
||||||
import re
|
import re
|
||||||
import shutil
|
import shutil
|
||||||
import subprocess
|
|
||||||
import time
|
import time
|
||||||
|
|
||||||
from collections import OrderedDict
|
|
||||||
from docopt import docopt
|
from docopt import docopt
|
||||||
|
|
||||||
import psutil
|
import psutil
|
||||||
|
|
@ -46,6 +44,12 @@ CLONE_SETTINGS = {
|
||||||
# (5, 1) ## Clone source partition #5 to destination partition #1
|
# (5, 1) ## Clone source partition #5 to destination partition #1
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
DDRESCUE_LOG_REGEX = re.compile(
|
||||||
|
r'^\s*(?P<key>\S+):\s+'
|
||||||
|
r'(?P<size>\d+)\s+'
|
||||||
|
r'(?P<unit>[PTGMKB]i?B?)',
|
||||||
|
re.IGNORECASE,
|
||||||
|
)
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
MENU_ACTIONS = (
|
MENU_ACTIONS = (
|
||||||
'Start',
|
'Start',
|
||||||
|
|
@ -119,19 +123,51 @@ class BlockPair():
|
||||||
# Read map file
|
# Read map file
|
||||||
self.load_map_data()
|
self.load_map_data()
|
||||||
|
|
||||||
|
def get_rescued_size(self):
|
||||||
|
"""Get rescued size using map data.
|
||||||
|
|
||||||
|
NOTE: Returns 0 if no map data is available.
|
||||||
|
"""
|
||||||
|
self.load_map_data()
|
||||||
|
return self.map_data.get('rescued', 0)
|
||||||
|
|
||||||
def load_map_data(self):
|
def load_map_data(self):
|
||||||
"""Load map data from file.
|
"""Load map data from file.
|
||||||
|
|
||||||
NOTE: If the file is missing it is assumed that recovery hasn't
|
NOTE: If the file is missing it is assumed that recovery hasn't
|
||||||
started yet so default values will be returned instead.
|
started yet so default values will be returned instead.
|
||||||
"""
|
"""
|
||||||
self.map_data = {}
|
data = {'full recovery': False, 'pass completed': False}
|
||||||
|
|
||||||
# Read file
|
# Get output from ddrescuelog
|
||||||
if self.map_path.exists():
|
cmd = [
|
||||||
with open(self.map_path, 'r') as _f:
|
'ddrescuelog',
|
||||||
#TODO
|
'--binary-prefixes',
|
||||||
pass
|
'--show-status',
|
||||||
|
self.map_path,
|
||||||
|
]
|
||||||
|
proc = exe.run_program(cmd, check=False)
|
||||||
|
|
||||||
|
# Parse output
|
||||||
|
for line in proc.stdout.splitlines():
|
||||||
|
_r = DDRESCUE_LOG_REGEX.search(line)
|
||||||
|
if _r:
|
||||||
|
data[_r.group('key')] = std.string_to_bytes(
|
||||||
|
f'{_r.group("size")} {_r.group("unit")}',
|
||||||
|
)
|
||||||
|
data['pass completed'] = 'current status: finished' in line.lower()
|
||||||
|
|
||||||
|
# Check if 100% done
|
||||||
|
cmd = [
|
||||||
|
'ddrescuelog',
|
||||||
|
'--done-status',
|
||||||
|
self.map_path,
|
||||||
|
]
|
||||||
|
proc = exe.run_program(cmd, check=False)
|
||||||
|
data['full recovery'] = proc.returncode == 0
|
||||||
|
|
||||||
|
# Done
|
||||||
|
self.map_data.update(data)
|
||||||
|
|
||||||
def pass_complete(self, pass_num):
|
def pass_complete(self, pass_num):
|
||||||
"""Check if pass_num is complete based on map data, returns bool."""
|
"""Check if pass_num is complete based on map data, returns bool."""
|
||||||
|
|
@ -418,7 +454,6 @@ class State():
|
||||||
|
|
||||||
# Set working dir
|
# Set working dir
|
||||||
working_dir = get_working_dir(mode, self.destination)
|
working_dir = get_working_dir(mode, self.destination)
|
||||||
os.chdir(working_dir)
|
|
||||||
|
|
||||||
# Start fresh if requested
|
# Start fresh if requested
|
||||||
if docopt_args['--start-fresh']:
|
if docopt_args['--start-fresh']:
|
||||||
|
|
@ -523,10 +558,10 @@ class State():
|
||||||
def safety_check(self, mode, working_dir):
|
def safety_check(self, mode, working_dir):
|
||||||
"""Run safety check and abort if necessary."""
|
"""Run safety check and abort if necessary."""
|
||||||
required_size = sum([pair.size for pair in self.block_pairs])
|
required_size = sum([pair.size for pair in self.block_pairs])
|
||||||
|
settings = self.load_settings(working_dir) if mode == 'Clone' else {}
|
||||||
|
|
||||||
# Increase required_size if necessary
|
# Increase required_size if necessary
|
||||||
if mode == 'Clone' and settings['Needs Format']:
|
if mode == 'Clone' and settings.get('Needs Format', False):
|
||||||
settings = self.load_settings(working_dir)
|
|
||||||
if settings['Table Type'] == 'GPT':
|
if settings['Table Type'] == 'GPT':
|
||||||
# Below is the size calculation for the GPT
|
# Below is the size calculation for the GPT
|
||||||
# 1 LBA for the protective MBR
|
# 1 LBA for the protective MBR
|
||||||
|
|
@ -711,7 +746,14 @@ def build_block_pair_report(block_pairs, settings):
|
||||||
['BLUE', None],
|
['BLUE', None],
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
# TODO If anything recovered --> Add resume msg
|
if any([pair.get_rescued_size() > 0 for pair in block_pairs]):
|
||||||
|
report.append(' ')
|
||||||
|
report.append(
|
||||||
|
std.color_string(
|
||||||
|
['NOTE:', 'Resume data loaded from map file(s).'],
|
||||||
|
['BLUE', None],
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
# Remove double line-break
|
# Remove double line-break
|
||||||
if report[-1] == ' ':
|
if report[-1] == ' ':
|
||||||
|
|
@ -902,7 +944,7 @@ def fstype_is_ok(path, map_dir=False):
|
||||||
|
|
||||||
# Get fstype
|
# Get fstype
|
||||||
if PLATFORM == 'Darwin':
|
if PLATFORM == 'Darwin':
|
||||||
# TODO: leave as None for now
|
# TODO: Determine fstype under macOS
|
||||||
pass
|
pass
|
||||||
elif PLATFORM == 'Linux':
|
elif PLATFORM == 'Linux':
|
||||||
cmd = [
|
cmd = [
|
||||||
|
|
@ -1005,13 +1047,15 @@ def get_working_dir(mode, destination):
|
||||||
working_dir = pathlib.Path(os.getcwd())
|
working_dir = pathlib.Path(os.getcwd())
|
||||||
|
|
||||||
# Set subdir using ticket ID
|
# Set subdir using ticket ID
|
||||||
working_dir = working_dir.joinpath(ticket_id)
|
if mode == 'Clone':
|
||||||
LOG.info('Set working directory to: %s', working_dir)
|
working_dir = working_dir.joinpath(ticket_id)
|
||||||
|
|
||||||
# Create directory
|
# Create directory
|
||||||
working_dir.mkdir(parents=True, exist_ok=True)
|
working_dir.mkdir(parents=True, exist_ok=True)
|
||||||
|
os.chdir(working_dir)
|
||||||
|
|
||||||
# Done
|
# Done
|
||||||
|
LOG.info('Set working directory to: %s', working_dir)
|
||||||
return working_dir
|
return working_dir
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue