Skip to content

Commit 9f95bf6

Browse files
authored
Merge pull request #7 from memory/add-zstandard
Add support for zstandard control archives
2 parents b88fe8f + e2722e9 commit 9f95bf6

8 files changed

Lines changed: 125 additions & 13 deletions

File tree

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ else
4545
endif
4646

4747
${PYENV}: ${BREW_SSL} ${BREW_READLINE} ${PYENV_BIN}
48-
${ARCH_PREFIX} pyenv install ${PYVERSION}
48+
${ARCH_PREFIX} pyenv install -s ${PYVERSION}
4949

5050
${VENV}: ${PYENV}
5151
${ARCH_PREFIX} ${PYENV_BIN} virtualenv ${PYVERSION} ${VENV_NAME}

poetry.lock

Lines changed: 63 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pydpkg/dpkg.py

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
# pypi imports
1515
import six
16+
import zstandard
1617
from arpy import Archive
1718

1819
# local imports
@@ -255,9 +256,12 @@ def _process_dpkg_file(self, filename):
255256
elif b"control.tar.xz" in dpkg_archive.archived_files:
256257
control_archive = dpkg_archive.archived_files[b"control.tar.xz"]
257258
control_archive_type = "xz"
259+
elif b"control.tar.zst" in dpkg_archive.archived_files:
260+
control_archive = dpkg_archive.archived_files[b"control.tar.zst"]
261+
control_archive_type = "zst"
258262
else:
259263
raise DpkgMissingControlGzipFile(
260-
"Corrupt dpkg file: no control.tar.gz/xz file in ar archive."
264+
"Corrupt dpkg file: no control.tar.gz/xz/zst file in ar archive."
261265
)
262266
self._log.debug("found controlgz: %s", control_archive)
263267

@@ -267,12 +271,19 @@ def _process_dpkg_file(self, filename):
267271
with tarfile.open(fileobj=io.BytesIO(gzf.read())) as ctar:
268272
self._log.debug("opened tar file: %s", ctar)
269273
message = self._extract_message(ctar)
270-
else:
274+
elif control_archive_type == "xz":
271275
with lzma.open(control_archive) as xzf:
272276
self._log.debug("opened xz control archive: %s", xzf)
273277
with tarfile.open(fileobj=io.BytesIO(xzf.read())) as ctar:
274278
self._log.debug("opened tar file: %s", ctar)
275279
message = self._extract_message(ctar)
280+
else:
281+
zst = zstandard.ZstdDecompressor()
282+
with zst.stream_reader(control_archive) as reader:
283+
self._log.debug("opened zst control archive: %s", reader)
284+
with tarfile.open(fileobj=io.BytesIO(reader.read())) as ctar:
285+
self._log.debug("opened tar file: %s", ctar)
286+
message = self._extract_message(ctar)
276287

277288
for req in REQUIRED_HEADERS:
278289
if req not in list(map(str.lower, message.keys())):

pydpkg/exceptions.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,11 @@ class DpkgVersionError(DpkgError):
1414

1515

1616
class DpkgMissingControlFile(DpkgError):
17-
"""No control file found in control.tar.gz/xz"""
17+
"""No control file found in control.tar.gz/xz/zst"""
1818

1919

2020
class DpkgMissingControlGzipFile(DpkgError):
21-
"""No control.tar.gz/xz file found in dpkg file"""
21+
"""No control.tar.gz/xz/zst file found in dpkg file"""
2222

2323

2424
class DpkgMissingRequiredHeaderError(DpkgError):

pyproject.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[tool.poetry]
22
name = "pydpkg"
3-
version = "1.6.0"
3+
version = "1.7.0"
44
description = "A python library for parsing debian package control headers and version strings"
55
authors = ["Nathan J. Mehl <pypi@memory.blank.org>"]
66
homepage = "https://github.com/memory/python-dpkg"
@@ -31,6 +31,7 @@ python = "^3.6.2"
3131
arpy = "^2.2.0"
3232
six = "^1.16.0"
3333
PGPy = "0.5.4"
34+
zstandard = "^0.18.0"
3435

3536
[tool.poetry.dev-dependencies]
3637
black = "^21.11b1"
694 Bytes
Binary file not shown.

tests/sample_package_zst.deb

674 Bytes
Binary file not shown.

tests/test_dpkg.py

Lines changed: 44 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,17 @@
11
#!/usr/bin/env python
22

33
import os
4+
import pytest
45
import unittest
56
from email.message import Message
67

78
from pydpkg.dpkg import Dpkg
8-
from pydpkg.exceptions import DpkgVersionError
9+
from pydpkg.exceptions import DpkgVersionError, DpkgMissingControlGzipFile
910

1011
TEST_DPKG_GZ_FILE = "testdeb_1:0.0.0-test_all.deb"
1112
TEST_DPKG_XZ_FILE = "sample_package_xz.deb"
13+
TEST_DPKG_ZST_FILE = "sample_package_zst.deb"
14+
TEST_DPKG_BAD_FILE = "sample_package_badcontrol.deb"
1215

1316

1417
class DpkgGzTest(unittest.TestCase):
@@ -67,6 +70,41 @@ def test_message(self):
6770
self.assertIsInstance(self.dpkg.message, type(Message()))
6871

6972

73+
class DpkgZstTest(unittest.TestCase):
74+
def setUp(self):
75+
dpkgfile = os.path.join(os.path.dirname(__file__), TEST_DPKG_ZST_FILE)
76+
self.dpkg = Dpkg(dpkgfile)
77+
78+
def test_get_versions(self):
79+
self.assertEqual(self.dpkg.epoch, 0)
80+
self.assertEqual(self.dpkg.upstream_version, "0.0.1")
81+
self.assertEqual(self.dpkg.debian_revision, "0")
82+
83+
def test_get_message_headers(self):
84+
self.assertEqual(self.dpkg.package, "samplepackage.test")
85+
self.assertEqual(self.dpkg.PACKAGE, "samplepackage.test")
86+
self.assertEqual(self.dpkg["package"], "samplepackage.test")
87+
self.assertEqual(self.dpkg["PACKAGE"], "samplepackage.test")
88+
self.assertEqual(self.dpkg.get("package"), "samplepackage.test")
89+
self.assertEqual(self.dpkg.get("PACKAGE"), "samplepackage.test")
90+
self.assertEqual(self.dpkg.get("nonexistent"), None)
91+
self.assertEqual(self.dpkg.get("nonexistent", "foo"), "foo")
92+
93+
def test_missing_header(self):
94+
self.assertRaises(KeyError, self.dpkg.__getitem__, "xyzzy")
95+
self.assertRaises(AttributeError, self.dpkg.__getattr__, "xyzzy")
96+
97+
def test_message(self):
98+
self.assertIsInstance(self.dpkg.message, type(Message()))
99+
100+
101+
class DpkgBadTest(unittest.TestCase):
102+
def test_bad_control(self):
103+
with pytest.raises(DpkgMissingControlGzipFile):
104+
dpkgfile = os.path.join(os.path.dirname(__file__), TEST_DPKG_BAD_FILE)
105+
Dpkg(dpkgfile).message
106+
107+
70108
class DpkgVersionsTest(unittest.TestCase):
71109
def test_get_epoch(self):
72110
self.assertEqual(Dpkg.get_epoch("0"), (0, "0"))
@@ -222,15 +260,17 @@ def test_compare_versions(self):
222260
)
223261

224262
# unicode me harder
225-
self.assertEqual(Dpkg.compare_versions(u"2:0.0.44-1", u"2:0.0.44-nobin"), -1)
226-
self.assertEqual(Dpkg.compare_versions(u"2:0.0.44-nobin", u"2:0.0.44-1"), 1)
227-
self.assertEqual(Dpkg.compare_versions(u"2:0.0.44-1", u"2:0.0.44-1"), 0)
263+
self.assertEqual(Dpkg.compare_versions("2:0.0.44-1", "2:0.0.44-nobin"), -1)
264+
self.assertEqual(Dpkg.compare_versions("2:0.0.44-nobin", "2:0.0.44-1"), 1)
265+
self.assertEqual(Dpkg.compare_versions("2:0.0.44-1", "2:0.0.44-1"), 0)
228266

229267

230268
if __name__ == "__main__":
231269
suite = unittest.TestLoader().loadTestsFromTestCase(DpkgGzTest)
232270
unittest.TextTestRunner(verbosity=2).run(suite)
233271
suite = unittest.TestLoader().loadTestsFromTestCase(DpkgXzTest)
234272
unittest.TextTestRunner(verbosity=2).run(suite)
273+
suite = unittest.TestLoader().loadTestsFromTestCase(DpkgZstTest)
274+
unittest.TextTestRunner(verbosity=2).run(suite)
235275
suite = unittest.TestLoader().loadTestsFromTestCase(DpkgVersionsTest)
236276
unittest.TextTestRunner(verbosity=2).run(suite)

0 commit comments

Comments
 (0)