Repository navigation
Expand file tree
/
Copy pathutils.py
More file actions
108 lines (87 loc) · 2.59 KB
/
Copy pathutils.py
File metadata and controls
108 lines (87 loc) · 2.59 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Author: Li Yuanming
Email: yuanmingleee@gmail.com
Date: Mar 15, 2023
"""
import hashlib
import os
import sys
from contextlib import contextmanager
from pathlib import Path
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from typing import Union, List
@contextmanager
def cwd(path):
oldpwd = os.getcwd()
os.chdir(path)
try:
yield
finally:
os.chdir(oldpwd)
def symlink_force(target, link_name, target_is_directory=False):
"""Force to create a symbolic link"""
try:
os.unlink(link_name)
except FileNotFoundError:
pass
os.symlink(target, link_name, target_is_directory)
def hash_file(filepaths: 'Union[str, os.PathLike, List[Union[os.PathLike, str]]]'):
"""
Compute the hash of a single file or a directory tree, including all files and subdirectories.
Args:
filepaths: A list of file path or the directory to hash
Returns:
The hash of the directory tree.
References:
https://stackoverflow.com/a/24937710
"""
sha_hash = hashlib.md5()
if isinstance(filepaths, (str, os.PathLike)):
filepaths = [filepaths]
# Find common prefix
root = Path(os.path.commonpath(filepaths))
root = root.parent if root.is_file() else root
# Tree scan of all file paths / directories
paths = list()
for path in filepaths:
paths.append(path)
paths.extend(Path(path).glob('**/*'))
# Sort the file paths for consistent hash
for path in sorted(paths):
if not path.is_file():
# Skip directories
continue
# hash relative name
sha_hash.update(path.relative_to(root).as_posix().encode())
with open(path, 'rb') as f:
while True:
# Read file in as little chunks
buf = f.read(4096)
if not buf:
break
sha_hash.update(buf)
return sha_hash.hexdigest()
def hash_binary(b: bytes):
"""
Compute the hash of a binary.
Args:
b: file binary
Returns:
The hash of the directory tree.
References:
https://stackoverflow.com/a/24937710
"""
sha_hash = hashlib.md5()
sha_hash.update(b)
return sha_hash.hexdigest()
if sys.version_info < (3, 9):
def removeprefix(text, prefix):
return text[text.startswith(prefix) and len(prefix):]
def removesuffix(text, suffix):
return text[:len(text) - len(suffix)] if text.endswith(suffix) else text
else:
removeprefix = str.removeprefix
removesuffix = str.removesuffix