Skip to content

Commit

Permalink
Support hash computation of symbolic links
Browse files Browse the repository at this point in the history
  • Loading branch information
tovrstra committed May 19, 2024
1 parent c95bdab commit f14e5e3
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 2 deletions.
4 changes: 4 additions & 0 deletions docs/changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Completed and revised docstrings in `stepup.core.nglob`,
and added this module to the reference documentation.

### Fixed

- Improve hash computation of a symbolic links in `stepup.core.hash`.


## [1.2.2] - 2024-05-16

Expand Down
23 changes: 22 additions & 1 deletion stepup/core/hash.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,28 @@ def digest(self):
return self._hash.digest()


def compute_file_digest(path) -> bytes:
def compute_file_digest(path: str, dereference=True) -> bytes:
"""Compute the blake2b digest of a file or a symbolic link.
Parameters
----------
path
The file of which the hash must be computed.
dereference
If True (default) and the path is a symbolic link,
try to read the destination of the link.
If False, the destination path itself is hashed.
Returns
-------
digest
A 64 bytes blake2b hash.
"""
path = Path(path)
if path.islink() and not dereference:
return hashlib.blake2b(path.readlink().encode("utf-8")).digest()
if path.is_dir():
raise OSError("File digests of directories are not supported.")
with open(path, "rb") as fh:
return hashlib.file_digest(fh, hashlib.blake2b).digest()

Expand Down
31 changes: 30 additions & 1 deletion tests/test_hash.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,13 @@
# --
"""Unit tests for stepup.core.hash"""

from hashlib import blake2b

import msgpack
import pytest
from path import Path

from stepup.core.hash import FileHash
from stepup.core.hash import FileHash, compute_file_digest


def test_new():
Expand Down Expand Up @@ -68,3 +71,29 @@ def test_dir():
assert file_hash.update("stepup/") is False
data = msgpack.packb(file_hash.unstructure())
assert file_hash == FileHash.structure(msgpack.unpackb(data))


def test_symbolic_link(path_tmp: Path):
path_dest = path_tmp / "dest.txt"
with open(path_dest, "w") as fh:
fh.write("Hello!")
assert compute_file_digest(path_dest) == blake2b(b"Hello!").digest()
path_symlink = path_tmp / "link.txt"
path_symlink.symlink_to("dest.txt")
assert compute_file_digest(path_symlink) == blake2b(b"Hello!").digest()
assert compute_file_digest(path_symlink, dereference=False) == blake2b(b"dest.txt").digest()


def test_hash_dir(path_tmp: Path):
with pytest.raises(IOError):
compute_file_digest(path_tmp)


def test_hash_symbolic_link_dir(path_tmp: Path):
path_sub = path_tmp / "sub"
path_sub.mkdir()
path_symlink = path_tmp / "link"
path_symlink.symlink_to("sub", target_is_directory=True)
with pytest.raises(IOError):
assert compute_file_digest(path_symlink)
assert compute_file_digest(path_symlink, dereference=False) == blake2b(b"sub").digest()

0 comments on commit f14e5e3

Please sign in to comment.