Skip to content

Commit ca34f1b

Browse files
authored
Merge pull request #195 from joseacl/issue-194
Make targz without mimetype
2 parents b79267d + e4a250f commit ca34f1b

File tree

4 files changed

+38
-4
lines changed

4 files changed

+38
-4
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ and **Merged pull requests**. Critical items to know are:
1414
The versions coincide with releases on pip. Only major versions will be released as tags on Github.
1515

1616
## [0.0.x](https://github.com/oras-project/oras-py/tree/main) (0.0.x)
17+
- Make reproducible targz without mimetype (0.2.30)
1718
- don't include Content-Length header in upload_manifest (0.2.29)
1819
- propagate the tls_verify parameter to auth backends (0.2.28)
1920
- don't add an Authorization header is there is no token (0.2.27), closes issue [182](https://github.com/oras-project/oras-py/issues/182)

oras/tests/test_utils.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,3 +130,19 @@ def test_split_path_and_content():
130130
path_content = utils.split_path_and_content(testref)
131131
assert path_content.path == "path/to/config.json"
132132
assert not path_content.content
133+
134+
135+
def test_make_targz_files_with_same_content_generates_same_hash(tmp_path):
136+
tmp_file = str(tmp_path / "written_file.txt")
137+
utils.write_file(tmp_file, "hello!")
138+
139+
tmp_tar_1 = str(tmp_path / "test1.tar.gz")
140+
utils.make_targz(tmp_file, tmp_tar_1)
141+
142+
tmp_tar_2 = str(tmp_path / "test2.tar.gz")
143+
utils.make_targz(tmp_file, tmp_tar_2)
144+
145+
hash_tar_1 = utils.get_file_hash(tmp_tar_1)
146+
hash_tar_2 = utils.get_file_hash(tmp_tar_2)
147+
148+
assert hash_tar_1 == hash_tar_2

oras/utils/fileio.py

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
__license__ = "Apache-2.0"
44

55
import errno
6+
import gzip
67
import hashlib
78
import io
89
import json
@@ -26,13 +27,29 @@ def __init__(self, path: str, content: Optional[str] = None):
2627
self.content = content
2728

2829

30+
def reset(tarinfo):
31+
"""Helper to reset modification time for tar entries"""
32+
tarinfo.mtime = 0
33+
return tarinfo
34+
35+
2936
def make_targz(source_dir: str, dest_name: Optional[str] = None) -> str:
3037
"""
31-
Make a targz (compressed) archive from a source directory.
38+
Make a reproducible (no mtime) targz (compressed) archive from a source directory.
3239
"""
3340
dest_name = dest_name or get_tmpfile(suffix=".tar.gz")
34-
with tarfile.open(dest_name, "w:gz") as tar:
35-
tar.add(source_dir, arcname=os.path.basename(source_dir))
41+
42+
# os.O_WRONLY tells the computer you are only going to writo to the file, not read
43+
# os.O_CREATE tells the computer to create the file if it doesn't exist
44+
with os.fdopen(
45+
os.open(dest_name, os.O_WRONLY | os.O_CREAT, 0o644), "wb"
46+
) as out_file:
47+
with gzip.GzipFile(mode="wb", fileobj=out_file, mtime=0) as gzip_file:
48+
with tarfile.open(fileobj=gzip_file, mode="w:") as tar_file:
49+
tar_file.add(
50+
source_dir, filter=reset, arcname=os.path.basename(source_dir)
51+
)
52+
3653
return dest_name
3754

3855

oras/version.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
__copyright__ = "Copyright The ORAS Authors."
33
__license__ = "Apache-2.0"
44

5-
__version__ = "0.2.29"
5+
__version__ = "0.2.30"
66
AUTHOR = "Vanessa Sochat"
77
EMAIL = "vsoch@users.noreply.github.com"
88
NAME = "oras"

0 commit comments

Comments
 (0)