Improved ddrescue map parsing
* Get data recovered instead of percentage, should be more acurate
This commit is contained in:
parent
73ca03da8e
commit
f2adf6f5c0
2 changed files with 28 additions and 20 deletions
|
|
@ -107,19 +107,19 @@ class BlockPair():
|
||||||
def load_map_data(self):
|
def load_map_data(self):
|
||||||
"""Load data from map file and set progress."""
|
"""Load data from map file and set progress."""
|
||||||
map_data = read_map_file(self.map_path)
|
map_data = read_map_file(self.map_path)
|
||||||
self.rescued_percent = map_data['rescued']
|
self.rescued = map_data.get('rescued', 0)
|
||||||
self.rescued = (self.rescued_percent * self.size) / 100
|
self.rescued_percent = (self.rescued / self.size) * 100
|
||||||
if map_data['full recovery']:
|
if map_data['full recovery']:
|
||||||
self.pass_done = [True, True, True]
|
self.pass_done = [True, True, True]
|
||||||
self.rescued = self.size
|
self.rescued = self.size
|
||||||
self.status = ['Skipped', 'Skipped', 'Skipped']
|
self.status = ['Skipped', 'Skipped', 'Skipped']
|
||||||
elif map_data['non-tried'] > 0:
|
elif map_data.get('non-tried', 0) > 0:
|
||||||
# Initial pass incomplete
|
# Initial pass incomplete
|
||||||
pass
|
pass
|
||||||
elif map_data['non-trimmed'] > 0:
|
elif map_data.get('non-trimmed', 0) > 0:
|
||||||
self.pass_done = [True, False, False]
|
self.pass_done = [True, False, False]
|
||||||
self.status = ['Skipped', 'Pending', 'Pending']
|
self.status = ['Skipped', 'Pending', 'Pending']
|
||||||
elif map_data['non-scraped'] > 0:
|
elif map_data.get('non-scraped', 0) > 0:
|
||||||
self.pass_done = [True, True, False]
|
self.pass_done = [True, True, False]
|
||||||
self.status = ['Skipped', 'Skipped', 'Pending']
|
self.status = ['Skipped', 'Skipped', 'Pending']
|
||||||
else:
|
else:
|
||||||
|
|
@ -147,8 +147,8 @@ class BlockPair():
|
||||||
"""Update progress using map file."""
|
"""Update progress using map file."""
|
||||||
if os.path.exists(self.map_path):
|
if os.path.exists(self.map_path):
|
||||||
map_data = read_map_file(self.map_path)
|
map_data = read_map_file(self.map_path)
|
||||||
self.rescued_percent = map_data.get('rescued', 0)
|
self.rescued = map_data.get('rescued', 0)
|
||||||
self.rescued = (self.rescued_percent * self.size) / 100
|
self.rescued_percent = (self.rescued / self.size) * 100
|
||||||
self.status[pass_num] = get_formatted_status(
|
self.status[pass_num] = get_formatted_status(
|
||||||
label='Pass {}'.format(pass_num+1),
|
label='Pass {}'.format(pass_num+1),
|
||||||
data=(self.rescued/self.size)*100)
|
data=(self.rescued/self.size)*100)
|
||||||
|
|
@ -1022,25 +1022,27 @@ def menu_settings(state):
|
||||||
|
|
||||||
def read_map_file(map_path):
|
def read_map_file(map_path):
|
||||||
"""Read map file with ddrescuelog and return data as dict."""
|
"""Read map file with ddrescuelog and return data as dict."""
|
||||||
map_data = {'full recovery': False}
|
cmd = [
|
||||||
|
'ddrescuelog',
|
||||||
|
'--binary-prefixes',
|
||||||
|
'--show-status',
|
||||||
|
map_path,
|
||||||
|
]
|
||||||
|
map_data = {'full recovery': False, 'pass completed': False}
|
||||||
try:
|
try:
|
||||||
result = run_program(['ddrescuelog', '-t', map_path])
|
result = run_program(cmd, encoding='utf-8', errors='ignore')
|
||||||
except CalledProcessError:
|
except CalledProcessError:
|
||||||
# (Grossly) assuming map_data hasn't been saved yet, return empty dict
|
# (Grossly) assuming map_data hasn't been saved yet, return empty dict
|
||||||
return map_data
|
return map_data
|
||||||
|
|
||||||
# Parse output
|
# Parse output
|
||||||
for line in result.stdout.decode().splitlines():
|
for line in result.stdout.splitlines():
|
||||||
data = re.match(
|
line = line.strip()
|
||||||
r'^\s*(?P<key>\S+):.*\(\s*(?P<value>\d+\.?\d*)%.*', line.strip())
|
_r = REGEX_DDRESCUE_LOG.search(line)
|
||||||
if data:
|
if _r:
|
||||||
try:
|
map_data[_r.group('key')] = convert_to_bytes('{size} {unit}B'.format(
|
||||||
map_data[data.group('key')] = float(data.group('value'))
|
**_r.groupdict()))
|
||||||
except ValueError:
|
map_data['pass completed'] = 'current status: finished' in line
|
||||||
raise GenericError('Failed to read map data')
|
|
||||||
data = re.match(r'.*current status:\s+(?P<status>.*)', line.strip())
|
|
||||||
if data:
|
|
||||||
map_data['pass completed'] = bool(data.group('status') == 'finished')
|
|
||||||
|
|
||||||
# Check if 100% done
|
# Check if 100% done
|
||||||
try:
|
try:
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,12 @@ DDRESCUE_SETTINGS = {
|
||||||
'-vvvv': {'Enabled': True, 'Hidden': True, },
|
'-vvvv': {'Enabled': True, 'Hidden': True, },
|
||||||
}
|
}
|
||||||
ETOC_REFRESH_RATE = 30 # in seconds
|
ETOC_REFRESH_RATE = 30 # in seconds
|
||||||
|
REGEX_DDRESCUE_LOG = re.compile(
|
||||||
|
r'^\s*(?P<key>\S+):\s+'
|
||||||
|
r'(?P<size>\d+)\s+'
|
||||||
|
r'(?P<unit>[PTGMKB])i?B?',
|
||||||
|
re.IGNORECASE,
|
||||||
|
)
|
||||||
REGEX_REMAINING_TIME = re.compile(
|
REGEX_REMAINING_TIME = re.compile(
|
||||||
r'remaining time:'
|
r'remaining time:'
|
||||||
r'\s*((?P<days>\d+)d)?'
|
r'\s*((?P<days>\d+)d)?'
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue