Merge pull request #158 from jmathai/regen-stats
Add command to check all files for bit rot
This commit is contained in:
commit
a7c9a5ffbd
35
elodie.py
35
elodie.py
|
@ -30,7 +30,6 @@ from elodie.result import Result
|
|||
|
||||
|
||||
FILESYSTEM = FileSystem()
|
||||
RESULT = Result()
|
||||
|
||||
|
||||
def import_file(_file, destination, album_from_folder, trash, allow_duplicates):
|
||||
|
@ -83,6 +82,7 @@ def import_file(_file, destination, album_from_folder, trash, allow_duplicates):
|
|||
def _import(destination, source, file, album_from_folder, trash, paths, allow_duplicates):
|
||||
"""Import files or directories by reading their EXIF and organizing them accordingly.
|
||||
"""
|
||||
result = Result()
|
||||
destination = os.path.abspath(os.path.expanduser(destination))
|
||||
|
||||
files = set()
|
||||
|
@ -101,9 +101,9 @@ def _import(destination, source, file, album_from_folder, trash, paths, allow_du
|
|||
for current_file in files:
|
||||
dest_path = import_file(current_file, destination, album_from_folder,
|
||||
trash, allow_duplicates)
|
||||
RESULT.append((current_file, dest_path))
|
||||
result.append((current_file, dest_path))
|
||||
|
||||
RESULT.write()
|
||||
result.write()
|
||||
|
||||
|
||||
@click.command('generate-db')
|
||||
|
@ -112,6 +112,7 @@ def _import(destination, source, file, album_from_folder, trash, paths, allow_du
|
|||
def _generate_db(source):
|
||||
"""Regenerate the hash.json database which contains all of the sha1 signatures of media files.
|
||||
"""
|
||||
result = Result()
|
||||
source = os.path.abspath(os.path.expanduser(source))
|
||||
|
||||
extensions = set()
|
||||
|
@ -135,11 +136,31 @@ def _generate_db(source):
|
|||
for current_file in all_files:
|
||||
if os.path.splitext(current_file)[1][1:].lower() not in extensions:
|
||||
log.info('Skipping invalid file %s' % current_file)
|
||||
result.append((current_file, False))
|
||||
continue
|
||||
|
||||
result.append((current_file, True))
|
||||
db.add_hash(db.checksum(current_file), current_file)
|
||||
|
||||
db.update_hash_db()
|
||||
result.write()
|
||||
|
||||
@click.command('verify')
|
||||
def _verify():
|
||||
result = Result()
|
||||
db = Db()
|
||||
for checksum, file_path in db.all():
|
||||
if not os.path.isfile(file_path):
|
||||
result.append((file_path, False))
|
||||
continue
|
||||
|
||||
actual_checksum = db.checksum(file_path)
|
||||
if checksum == actual_checksum:
|
||||
result.append((file_path, True))
|
||||
else:
|
||||
result.append((file_path, False))
|
||||
|
||||
result.write()
|
||||
|
||||
|
||||
def update_location(media, file_path, location_name):
|
||||
|
@ -189,6 +210,7 @@ def update_time(media, file_path, time_string):
|
|||
def _update(album, location, time, title, files):
|
||||
"""Update a file's EXIF. Automatically modifies the file's location and file name accordingly.
|
||||
"""
|
||||
result = Result()
|
||||
for current_file in files:
|
||||
if not os.path.exists(current_file):
|
||||
if constants.debug:
|
||||
|
@ -258,11 +280,11 @@ def _update(album, location, time, title, files):
|
|||
FILESYSTEM.delete_directory_if_empty(os.path.dirname(current_file))
|
||||
FILESYSTEM.delete_directory_if_empty(
|
||||
os.path.dirname(os.path.dirname(current_file)))
|
||||
RESULT.append((current_file, dest_path))
|
||||
result.append((current_file, dest_path))
|
||||
else:
|
||||
RESULT.append((current_file, None))
|
||||
result.append((current_file, False))
|
||||
|
||||
RESULT.write()
|
||||
result.write()
|
||||
|
||||
|
||||
@click.group()
|
||||
|
@ -273,6 +295,7 @@ def main():
|
|||
main.add_command(_import)
|
||||
main.add_command(_update)
|
||||
main.add_command(_generate_db)
|
||||
main.add_command(_verify)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
|
|
@ -183,6 +183,14 @@ class Db(object):
|
|||
|
||||
return None
|
||||
|
||||
def all(self):
|
||||
"""Generator to get all entries from self.hash_db
|
||||
|
||||
:returns tuple(string)
|
||||
"""
|
||||
for checksum, path in self.hash_db.items():
|
||||
yield (checksum, path)
|
||||
|
||||
def reset_hash_db(self):
|
||||
self.hash_db = {}
|
||||
|
||||
|
|
|
@ -379,6 +379,42 @@ def test_regenerate_valid_source_with_invalid_files():
|
|||
assert 'bde2dc0b839a5d20b0b4c1f57605f84e0e2a4562aaebc1c362de6cb7cc02eeb3' in db.hash_db, db.hash_db
|
||||
assert 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855' not in db.hash_db, db.hash_db
|
||||
|
||||
def test_verify_ok():
|
||||
temporary_folder, folder = helper.create_working_folder()
|
||||
|
||||
origin = '%s/valid.txt' % folder
|
||||
shutil.copyfile(helper.get_file('valid.txt'), origin)
|
||||
|
||||
reset_hash_db()
|
||||
runner = CliRunner()
|
||||
runner.invoke(elodie._generate_db, ['--source', folder])
|
||||
result = runner.invoke(elodie._verify)
|
||||
restore_hash_db()
|
||||
|
||||
shutil.rmtree(folder)
|
||||
|
||||
assert 'Success 1' in result.output, result.output
|
||||
assert 'Error 0' in result.output, result.output
|
||||
|
||||
def test_verify_error():
|
||||
temporary_folder, folder = helper.create_working_folder()
|
||||
|
||||
origin = '%s/valid.txt' % folder
|
||||
shutil.copyfile(helper.get_file('valid.txt'), origin)
|
||||
|
||||
reset_hash_db()
|
||||
runner = CliRunner()
|
||||
runner.invoke(elodie._generate_db, ['--source', folder])
|
||||
with open(origin, 'w') as f:
|
||||
f.write('changed text')
|
||||
result = runner.invoke(elodie._verify)
|
||||
restore_hash_db()
|
||||
|
||||
shutil.rmtree(folder)
|
||||
|
||||
assert origin in result.output, result.output
|
||||
assert 'Error 1' in result.output, result.output
|
||||
|
||||
def reset_hash_db():
|
||||
hash_db = constants.hash_db
|
||||
if os.path.isfile(hash_db):
|
||||
|
|
|
@ -107,6 +107,50 @@ def test_get_hash_does_not_exist():
|
|||
|
||||
assert db.get_hash(random_key) is None, 'Lookup for hash that should not exist did not return None'
|
||||
|
||||
def test_get_all():
|
||||
db = Db()
|
||||
db.reset_hash_db()
|
||||
|
||||
random_keys = []
|
||||
random_values = []
|
||||
for _ in range(10):
|
||||
random_keys.append(helper.random_string(10))
|
||||
random_values.append(helper.random_string(12))
|
||||
db.add_hash(random_keys[-1:][0], random_values[-1:][0], False)
|
||||
|
||||
counter = 0
|
||||
for key, value in db.all():
|
||||
assert key in random_keys, key
|
||||
assert value in random_values, value
|
||||
counter += 1
|
||||
|
||||
assert counter == 10, counter
|
||||
|
||||
def test_get_all_empty():
|
||||
db = Db()
|
||||
db.reset_hash_db()
|
||||
|
||||
counter = 0
|
||||
for key, value in db.all():
|
||||
counter += 1
|
||||
|
||||
# there's a final iteration because of the generator
|
||||
assert counter == 0, counter
|
||||
|
||||
def test_reset_hash_db():
|
||||
db = Db()
|
||||
|
||||
random_key = helper.random_string(10)
|
||||
random_value = helper.random_string(12)
|
||||
|
||||
# Test with explicit False value as 3rd param
|
||||
db.add_hash(random_key, random_value, False)
|
||||
|
||||
assert random_key in db.hash_db, random_key
|
||||
db.reset_hash_db()
|
||||
assert random_key not in db.hash_db, random_key
|
||||
|
||||
|
||||
def test_update_hash_db():
|
||||
db = Db()
|
||||
|
||||
|
|
|
@ -24,11 +24,40 @@ def call_result_and_assert(result, expected):
|
|||
sys.stdout = out
|
||||
result.write()
|
||||
output = out.getvalue().strip()
|
||||
assert output == expected, expected
|
||||
assert output == expected, output
|
||||
finally:
|
||||
sys.stdout = saved_stdout
|
||||
|
||||
def test_add_multiple_rows():
|
||||
def test_add_multiple_rows_with_success():
|
||||
expected = """****** SUMMARY ******
|
||||
Metric Count
|
||||
-------- -------
|
||||
Success 2
|
||||
Error 0"""
|
||||
result = Result()
|
||||
result.append(('id1', '/some/path/1'))
|
||||
result.append(('id2', '/some/path/2'))
|
||||
call_result_and_assert(result, expected)
|
||||
|
||||
def test_add_multiple_rows_with_failure():
|
||||
expected = """****** ERROR DETAILS ******
|
||||
File
|
||||
------
|
||||
id1
|
||||
id2
|
||||
|
||||
|
||||
****** SUMMARY ******
|
||||
Metric Count
|
||||
-------- -------
|
||||
Success 0
|
||||
Error 2"""
|
||||
result = Result()
|
||||
result.append(('id1', False))
|
||||
result.append(('id2', False))
|
||||
call_result_and_assert(result, expected)
|
||||
|
||||
def test_add_multiple_rows_with_failure_and_success():
|
||||
expected = """****** ERROR DETAILS ******
|
||||
File
|
||||
------
|
||||
|
@ -41,6 +70,6 @@ Metric Count
|
|||
Success 1
|
||||
Error 1"""
|
||||
result = Result()
|
||||
result.append(('id1', None))
|
||||
result.append(('id1', False))
|
||||
result.append(('id2', '/some/path'))
|
||||
call_result_and_assert(result, expected)
|
||||
|
|
Loading…
Reference in New Issue