Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package python-libarchive-c for openSUSE:Factory checked in at 2023-12-08 22:32:00 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-libarchive-c (Old) and /work/SRC/openSUSE:Factory/.python-libarchive-c.new.25432 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-libarchive-c" Fri Dec 8 22:32:00 2023 rev:7 rq:1131722 version:5.0 Changes: -------- --- /work/SRC/openSUSE:Factory/python-libarchive-c/python-libarchive-c.changes 2022-06-04 23:26:57.884751500 +0200 +++ /work/SRC/openSUSE:Factory/.python-libarchive-c.new.25432/python-libarchive-c.changes 2023-12-08 22:32:19.048582807 +0100 @@ -1,0 +2,18 @@ +Thu Dec 7 22:21:33 UTC 2023 - Dirk Müller <dmuel...@suse.com> + +- update to 5.0: + * It is now possible to specify a codec for archive entry + metadata (`pathname`, `linkpath`, `uname` and `gname`) + * **BREAKING:** If you use the `archive_read_class` and + `archive_write_class` arguments, the classes you provide will + receive a codec name as a second positional argument. + * The `timestamp_nsec` arguments of the legacy + `ArchiveEntry.set_{a,c,m}time` methods are now optional + * Removed obsolete dependencies (`mock` and `six`) from + `tox.ini` (#119). + * Always use `UTF-8` when reading the `PKG-INFO` and + `README.rst` files (#120). + * Replaced `pytest-xdist` with `pytest-forked` in `tox.ini` +- drop python-libarchive-c-no-mock.patch (upstream) + +------------------------------------------------------------------- Old: ---- libarchive-c-4.0.tar.gz python-libarchive-c-no-mock.patch New: ---- libarchive-c-5.0.tar.gz BETA DEBUG BEGIN: Old: * Replaced `pytest-xdist` with `pytest-forked` in `tox.ini` - drop python-libarchive-c-no-mock.patch (upstream) BETA DEBUG END: ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-libarchive-c.spec ++++++ --- /var/tmp/diff_new_pack.8uEuSD/_old 2023-12-08 22:32:19.712607240 +0100 +++ /var/tmp/diff_new_pack.8uEuSD/_new 2023-12-08 22:32:19.724607681 +0100 @@ -1,7 +1,7 @@ # # spec file for package python-libarchive-c # -# Copyright (c) 2022 SUSE LLC +# Copyright (c) 2023 SUSE LLC # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -20,15 +20,13 @@ %{?!python_module:%define python_module() python-%{**} python3-%{**}} Name: python-libarchive-c -Version: 4.0 +Version: 5.0 Release: 0 Summary: Python interface to libarchive License: CC0-1.0 Group: Development/Languages/Python URL: https://github.com/Changaco/python-libarchive-c Source: https://files.pythonhosted.org/packages/source/l/libarchive-c/libarchive-c-%{version}.tar.gz -# https://github.com/Changaco/python-libarchive-c/commit/13b904e2b046db25a42cd63557d259b3d3998323 -Patch0: python-libarchive-c-no-mock.patch BuildRequires: %{python_module setuptools} BuildRequires: fdupes BuildRequires: python-rpm-macros @@ -49,8 +47,7 @@ dynamically load and access the C library. %prep -%setup -q -n libarchive-c-%{version} -%patch0 -p1 +%autosetup -p1 -n libarchive-c-%{version} %build %python_build ++++++ libarchive-c-4.0.tar.gz -> libarchive-c-5.0.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libarchive-c-4.0/.github/workflows/main.yml new/libarchive-c-5.0/.github/workflows/main.yml --- old/libarchive-c-4.0/.github/workflows/main.yml 2022-01-22 18:28:18.000000000 +0100 +++ new/libarchive-c-5.0/.github/workflows/main.yml 2023-06-29 10:33:58.000000000 +0200 @@ -14,6 +14,14 @@ - uses: actions/checkout@v2 - name: Install libarchive run: sudo apt-get install -y libarchive13 + - name: Install Python 3.11 + uses: actions/setup-python@v2 + with: + python-version: '3.11' + - name: Install Python 3.10 + uses: actions/setup-python@v2 + with: + python-version: '3.10' - name: Install Python 3.9 uses: actions/setup-python@v2 with: @@ -22,10 +30,6 @@ uses: actions/setup-python@v2 with: python-version: '3.8' - - name: Install Python 3.7 - uses: actions/setup-python@v2 - with: - python-version: '3.7' - name: Install tox run: pip install tox - name: Run the tests diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libarchive-c-4.0/PKG-INFO new/libarchive-c-5.0/PKG-INFO --- old/libarchive-c-4.0/PKG-INFO 2022-01-22 18:34:08.470586000 +0100 +++ new/libarchive-c-5.0/PKG-INFO 2023-07-04 10:24:25.007115000 +0200 @@ -1,13 +1,12 @@ Metadata-Version: 2.1 Name: libarchive-c -Version: 4.0 +Version: 5.0 Summary: Python interface to libarchive Home-page: https://github.com/Changaco/python-libarchive-c Author: Changaco Author-email: chang...@changaco.oy.lc License: CC0 Keywords: archive libarchive 7z tar bz2 zip gz -Platform: UNKNOWN Description-Content-Type: text/x-rst License-File: LICENSE.md @@ -27,7 +26,7 @@ python ------ -python-libarchive-c is currently tested with python 3.7, 3.8, and 3.9. +python-libarchive-c is currently tested with python 3.8, 3.9, 3.10 and 3.11. If you find an incompatibility with older versions you can send us a small patch, but we won't accept big changes. @@ -127,9 +126,22 @@ libarchive). The acceptable values are listed in ``libarchive.ffi.WRITE_FORMATS`` and ``libarchive.ffi.WRITE_FILTERS``. +File metadata codecs +-------------------- + +By default, UTF-8 is used to read and write file attributes from and to archives. +A different codec can be specified through the ``header_codec`` arguments of the +``*_reader`` and ``*_writer`` functions. Example:: + + with libarchive.file_writer('test.tar', 'ustar', header_codec='cp037') as archive: + ... + with file_reader('test.tar', header_codec='cp037') as archive: + ... + +In addition to file paths (``pathname`` and ``linkpath``), the specified codec is +used to encode and decode user and group names (``uname`` and ``gname``). + License ======= `CC0 Public Domain Dedication <http://creativecommons.org/publicdomain/zero/1.0/>`_ - - diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libarchive-c-4.0/README.rst new/libarchive-c-5.0/README.rst --- old/libarchive-c-4.0/README.rst 2022-01-22 18:28:18.000000000 +0100 +++ new/libarchive-c-5.0/README.rst 2023-07-04 10:05:38.000000000 +0200 @@ -14,7 +14,7 @@ python ------ -python-libarchive-c is currently tested with python 3.7, 3.8, and 3.9. +python-libarchive-c is currently tested with python 3.8, 3.9, 3.10 and 3.11. If you find an incompatibility with older versions you can send us a small patch, but we won't accept big changes. @@ -114,6 +114,21 @@ libarchive). The acceptable values are listed in ``libarchive.ffi.WRITE_FORMATS`` and ``libarchive.ffi.WRITE_FILTERS``. +File metadata codecs +-------------------- + +By default, UTF-8 is used to read and write file attributes from and to archives. +A different codec can be specified through the ``header_codec`` arguments of the +``*_reader`` and ``*_writer`` functions. Example:: + + with libarchive.file_writer('test.tar', 'ustar', header_codec='cp037') as archive: + ... + with file_reader('test.tar', header_codec='cp037') as archive: + ... + +In addition to file paths (``pathname`` and ``linkpath``), the specified codec is +used to encode and decode user and group names (``uname`` and ``gname``). + License ======= diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libarchive-c-4.0/libarchive/entry.py new/libarchive-c-5.0/libarchive/entry.py --- old/libarchive-c-4.0/libarchive/entry.py 2022-01-22 18:28:18.000000000 +0100 +++ new/libarchive-c-5.0/libarchive/entry.py 2023-07-04 10:05:38.000000000 +0200 @@ -1,5 +1,5 @@ from contextlib import contextmanager -from ctypes import c_char_p, create_string_buffer +from ctypes import create_string_buffer from enum import IntEnum import math @@ -34,15 +34,19 @@ class ArchiveEntry: - __slots__ = ('_archive_p', '_entry_p') + __slots__ = ('_archive_p', '_entry_p', 'header_codec') - def __init__(self, archive_p=None, **attributes): + def __init__(self, archive_p=None, header_codec='utf-8', **attributes): """Allocate memory for an `archive_entry` struct. - The attributes are passed to the `modify` method. + The `header_codec` is used to decode and encode file paths and other + attributes. + + The `**attributes` are passed to the `modify` method. """ self._archive_p = archive_p self._entry_p = ffi.entry_new() + self.header_codec = header_codec if attributes: self.modify(**attributes) @@ -54,7 +58,7 @@ """Returns the file's path""" return self.pathname - def modify(self, **attributes): + def modify(self, header_codec=None, **attributes): """Convenience method to modify the entry's attributes. Args: @@ -83,6 +87,8 @@ rdevmajor (int): major part of the device number rdevminor (int): minor part of the device number """ + if header_codec: + self.header_codec = header_codec for name, value in attributes.items(): setattr(self, name, value) @@ -112,23 +118,45 @@ @property def uname(self): - return ffi.entry_uname_w(self._entry_p) + uname = ffi.entry_uname_w(self._entry_p) + if not uname: + uname = ffi.entry_uname(self._entry_p) + if uname is not None: + try: + uname = uname.decode(self.header_codec) + except UnicodeError: + pass + return uname @uname.setter def uname(self, value): if not isinstance(value, bytes): - value = value.encode('utf8') - ffi.entry_update_uname_utf8(self._entry_p, value) + value = value.encode(self.header_codec) + if self.header_codec == 'utf-8': + ffi.entry_update_uname_utf8(self._entry_p, value) + else: + ffi.entry_copy_uname(self._entry_p, value) @property def gname(self): - return ffi.entry_gname_w(self._entry_p) + gname = ffi.entry_gname_w(self._entry_p) + if not gname: + gname = ffi.entry_gname(self._entry_p) + if gname is not None: + try: + gname = gname.decode(self.header_codec) + except UnicodeError: + pass + return gname @gname.setter def gname(self, value): if not isinstance(value, bytes): - value = value.encode('utf8') - ffi.entry_update_gname_utf8(self._entry_p, value) + value = value.encode(self.header_codec) + if self.header_codec == 'utf-8': + ffi.entry_update_gname_utf8(self._entry_p, value) + else: + ffi.entry_copy_gname(self._entry_p, value) def get_blocks(self, block_size=ffi.page_size): """Read the file's content, keeping only one chunk in memory at a time. @@ -211,7 +239,7 @@ seconds, fraction = math.modf(value) self.set_atime(int(seconds), int(fraction * 1_000_000_000)) - def set_atime(self, timestamp_sec, timestamp_nsec): + def set_atime(self, timestamp_sec, timestamp_nsec=0): "Kept for backward compatibility. `entry.atime = ...` is supported now." return ffi.entry_set_atime(self._entry_p, timestamp_sec, timestamp_nsec) @@ -235,7 +263,7 @@ seconds, fraction = math.modf(value) self.set_mtime(int(seconds), int(fraction * 1_000_000_000)) - def set_mtime(self, timestamp_sec, timestamp_nsec): + def set_mtime(self, timestamp_sec, timestamp_nsec=0): "Kept for backward compatibility. `entry.mtime = ...` is supported now." return ffi.entry_set_mtime(self._entry_p, timestamp_sec, timestamp_nsec) @@ -259,7 +287,7 @@ seconds, fraction = math.modf(value) self.set_ctime(int(seconds), int(fraction * 1_000_000_000)) - def set_ctime(self, timestamp_sec, timestamp_nsec): + def set_ctime(self, timestamp_sec, timestamp_nsec=0): "Kept for backward compatibility. `entry.ctime = ...` is supported now." return ffi.entry_set_ctime(self._entry_p, timestamp_sec, timestamp_nsec) @@ -294,28 +322,48 @@ path = ffi.entry_pathname_w(self._entry_p) if not path: path = ffi.entry_pathname(self._entry_p) - try: - path = path.decode() - except UnicodeError: - pass + if path is not None: + try: + path = path.decode(self.header_codec) + except UnicodeError: + pass return path @pathname.setter def pathname(self, value): if not isinstance(value, bytes): - value = value.encode('utf8') - ffi.entry_update_pathname_utf8(self._entry_p, c_char_p(value)) + value = value.encode(self.header_codec) + if self.header_codec == 'utf-8': + ffi.entry_update_pathname_utf8(self._entry_p, value) + else: + ffi.entry_copy_pathname(self._entry_p, value) @property def linkpath(self): - return (ffi.entry_symlink_w(self._entry_p) or + path = ( + ( + ffi.entry_symlink_w(self._entry_p) or + ffi.entry_symlink(self._entry_p) + ) if self.issym else ( ffi.entry_hardlink_w(self._entry_p) or - ffi.entry_symlink(self._entry_p) or - ffi.entry_hardlink(self._entry_p)) + ffi.entry_hardlink(self._entry_p) + ) + ) + if isinstance(path, bytes): + try: + path = path.decode(self.header_codec) + except UnicodeError: + pass + return path @linkpath.setter def linkpath(self, value): - ffi.entry_update_link_utf8(self._entry_p, value) + if not isinstance(value, bytes): + value = value.encode(self.header_codec) + if self.header_codec == 'utf-8': + ffi.entry_update_link_utf8(self._entry_p, value) + else: + ffi.entry_copy_link(self._entry_p, value) # aliases for compatibility with the standard `tarfile` module path = property(pathname.fget, pathname.fset, doc="alias of pathname") diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libarchive-c-4.0/libarchive/ffi.py new/libarchive-c-5.0/libarchive/ffi.py --- old/libarchive-c-4.0/libarchive/ffi.py 2022-01-22 18:28:18.000000000 +0100 +++ new/libarchive-c-5.0/libarchive/ffi.py 2023-07-04 10:05:38.000000000 +0200 @@ -200,6 +200,8 @@ ffi('entry_rdevminor', [c_archive_entry_p], c_uint) ffi('entry_uid', [c_archive_entry_p], c_longlong) ffi('entry_gid', [c_archive_entry_p], c_longlong) +ffi('entry_uname', [c_archive_entry_p], c_char_p) +ffi('entry_gname', [c_archive_entry_p], c_char_p) ffi('entry_uname_w', [c_archive_entry_p], c_wchar_p) ffi('entry_gname_w', [c_archive_entry_p], c_wchar_p) @@ -222,9 +224,13 @@ ffi('entry_unset_ctime', [c_archive_entry_p], None) ffi('entry_unset_birthtime', [c_archive_entry_p], None) +ffi('entry_copy_pathname', [c_archive_entry_p, c_char_p], None) ffi('entry_update_pathname_utf8', [c_archive_entry_p, c_char_p], c_int, check_int) +ffi('entry_copy_link', [c_archive_entry_p, c_char_p], None) ffi('entry_update_link_utf8', [c_archive_entry_p, c_char_p], c_int, check_int) +ffi('entry_copy_uname', [c_archive_entry_p, c_char_p], None) ffi('entry_update_uname_utf8', [c_archive_entry_p, c_char_p], c_int, check_int) +ffi('entry_copy_gname', [c_archive_entry_p, c_char_p], None) ffi('entry_update_gname_utf8', [c_archive_entry_p, c_char_p], c_int, check_int) ffi('entry_clear', [c_archive_entry_p], c_archive_entry_p) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libarchive-c-4.0/libarchive/read.py new/libarchive-c-5.0/libarchive/read.py --- old/libarchive-c-4.0/libarchive/read.py 2022-01-22 18:28:18.000000000 +0100 +++ new/libarchive-c-5.0/libarchive/read.py 2023-07-04 10:05:38.000000000 +0200 @@ -12,16 +12,18 @@ class ArchiveRead: - def __init__(self, archive_p): + def __init__(self, archive_p, header_codec='utf-8'): self._pointer = archive_p + self.header_codec = header_codec def __iter__(self): """Iterates through an archive's entries. """ archive_p = self._pointer + header_codec = self.header_codec read_next_header2 = ffi.read_next_header2 while 1: - entry = ArchiveEntry(archive_p) + entry = ArchiveEntry(archive_p, header_codec) r = read_next_header2(archive_p, entry._entry_p) if r == ARCHIVE_EOF: return @@ -68,6 +70,7 @@ read_func, format_name='all', filter_name='all', open_func=None, seek_func=None, close_func=None, block_size=page_size, archive_read_class=ArchiveRead, passphrase=None, + header_codec='utf-8', ): """Read an archive using a custom function. """ @@ -79,12 +82,13 @@ if seek_func: ffi.read_set_seek_callback(archive_p, seek_cb) ffi.read_open(archive_p, None, open_cb, read_cb, close_cb) - yield archive_read_class(archive_p) + yield archive_read_class(archive_p, header_codec) @contextmanager def fd_reader( fd, format_name='all', filter_name='all', block_size=4096, passphrase=None, + header_codec='utf-8', ): """Read an archive from a file descriptor. """ @@ -94,12 +98,13 @@ except (OSError, AttributeError): # pragma: no cover pass ffi.read_open_fd(archive_p, fd, block_size) - yield ArchiveRead(archive_p) + yield ArchiveRead(archive_p, header_codec) @contextmanager def file_reader( path, format_name='all', filter_name='all', block_size=4096, passphrase=None, + header_codec='utf-8', ): """Read an archive from a file. """ @@ -109,22 +114,25 @@ except (OSError, AttributeError): # pragma: no cover pass ffi.read_open_filename_w(archive_p, path, block_size) - yield ArchiveRead(archive_p) + yield ArchiveRead(archive_p, header_codec) @contextmanager -def memory_reader(buf, format_name='all', filter_name='all', passphrase=None): +def memory_reader( + buf, format_name='all', filter_name='all', passphrase=None, + header_codec='utf-8', +): """Read an archive from memory. """ with new_archive_read(format_name, filter_name, passphrase) as archive_p: ffi.read_open_memory(archive_p, cast(buf, c_void_p), len(buf)) - yield ArchiveRead(archive_p) + yield ArchiveRead(archive_p, header_codec) @contextmanager def stream_reader( stream, format_name='all', filter_name='all', block_size=page_size, - passphrase=None, + passphrase=None, header_codec='utf-8', ): """Read an archive from a stream. @@ -158,7 +166,7 @@ if stream.seekable(): ffi.read_set_seek_callback(archive_p, seek_cb) ffi.read_open(archive_p, None, open_cb, read_cb, close_cb) - yield ArchiveRead(archive_p) + yield ArchiveRead(archive_p, header_codec) seekable_stream_reader = stream_reader diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libarchive-c-4.0/libarchive/write.py new/libarchive-c-5.0/libarchive/write.py --- old/libarchive-c-4.0/libarchive/write.py 2022-01-22 18:28:18.000000000 +0100 +++ new/libarchive-c-5.0/libarchive/write.py 2023-07-04 10:05:38.000000000 +0200 @@ -30,8 +30,9 @@ class ArchiveWrite: - def __init__(self, archive_p): + def __init__(self, archive_p, header_codec='utf-8'): self._pointer = archive_p + self.header_codec = header_codec def add_entries(self, entries): """Add the given entries to the archive. @@ -44,7 +45,8 @@ write_finish_entry(write_p) def add_files( - self, *paths, flags=0, lookup=False, pathname=None, **attributes + self, *paths, flags=0, lookup=False, pathname=None, recursive=True, + **attributes ): """Read files through the OS and add them to the archive. @@ -58,6 +60,9 @@ is called to enable the lookup of user and group names pathname (str | None): the path of the file in the archive, defaults to the source path + recursive (bool): + when False, if a path in `paths` is a directory, + only the directory itself is added. attributes (dict): passed to `ArchiveEntry.modify()` Raises: @@ -70,7 +75,7 @@ if block_size <= 0: block_size = 10240 # pragma: no cover - entry = ArchiveEntry() + entry = ArchiveEntry(header_codec=self.header_codec) entry_p = entry._entry_p destination_path = attributes.pop('pathname', None) for path in paths: @@ -103,6 +108,8 @@ write_data(write_p, data, len(data)) write_finish_entry(write_p) entry_clear(entry_p) + if not recursive: + break def add_file(self, path, **kw): "Single-path alias of `add_files()`" @@ -116,7 +123,7 @@ """"Add file from memory to archive. Args: - entry_path (str): the file's path + entry_path (str | bytes): the file's path entry_size (int): the file's size, in bytes entry_data (bytes | Iterable[bytes]): the file's content filetype (int): see `libarchive.entry.ArchiveEntry.modify()` @@ -134,7 +141,8 @@ entry = ArchiveEntry( pathname=entry_path, size=entry_size, filetype=filetype, - perm=permission, **other_attributes + perm=permission, header_codec=self.header_codec, + **other_attributes ) write_header(archive_pointer, entry._entry_p) @@ -194,6 +202,7 @@ write_func, format_name, filter_name=None, open_func=None, close_func=None, block_size=page_size, archive_write_class=ArchiveWrite, options='', passphrase=None, + header_codec='utf-8', ): """Create an archive and send it in chunks to the `write_func` function. @@ -214,13 +223,14 @@ ffi.write_set_bytes_in_last_block(archive_p, 1) ffi.write_set_bytes_per_block(archive_p, block_size) ffi.write_open(archive_p, None, open_cb, write_cb, close_cb) - yield archive_write_class(archive_p) + yield archive_write_class(archive_p, header_codec) @contextmanager def fd_writer( fd, format_name, filter_name=None, archive_write_class=ArchiveWrite, options='', passphrase=None, + header_codec='utf-8', ): """Create an archive and write it into a file descriptor. @@ -230,13 +240,14 @@ with new_archive_write(format_name, filter_name, options, passphrase) as archive_p: ffi.write_open_fd(archive_p, fd) - yield archive_write_class(archive_p) + yield archive_write_class(archive_p, header_codec) @contextmanager def file_writer( filepath, format_name, filter_name=None, archive_write_class=ArchiveWrite, options='', passphrase=None, + header_codec='utf-8', ): """Create an archive and write it into a file. @@ -246,13 +257,14 @@ with new_archive_write(format_name, filter_name, options, passphrase) as archive_p: ffi.write_open_filename_w(archive_p, filepath) - yield archive_write_class(archive_p) + yield archive_write_class(archive_p, header_codec) @contextmanager def memory_writer( buf, format_name, filter_name=None, archive_write_class=ArchiveWrite, options='', passphrase=None, + header_codec='utf-8', ): """Create an archive and write it into a buffer. @@ -264,4 +276,4 @@ used = byref(c_size_t()) buf_p = cast(buf, c_void_p) ffi.write_open_memory(archive_p, buf_p, len(buf), used) - yield archive_write_class(archive_p) + yield archive_write_class(archive_p, header_codec) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libarchive-c-4.0/libarchive_c.egg-info/PKG-INFO new/libarchive-c-5.0/libarchive_c.egg-info/PKG-INFO --- old/libarchive-c-4.0/libarchive_c.egg-info/PKG-INFO 2022-01-22 18:34:08.000000000 +0100 +++ new/libarchive-c-5.0/libarchive_c.egg-info/PKG-INFO 2023-07-04 10:24:24.000000000 +0200 @@ -1,13 +1,12 @@ Metadata-Version: 2.1 Name: libarchive-c -Version: 4.0 +Version: 5.0 Summary: Python interface to libarchive Home-page: https://github.com/Changaco/python-libarchive-c Author: Changaco Author-email: chang...@changaco.oy.lc License: CC0 Keywords: archive libarchive 7z tar bz2 zip gz -Platform: UNKNOWN Description-Content-Type: text/x-rst License-File: LICENSE.md @@ -27,7 +26,7 @@ python ------ -python-libarchive-c is currently tested with python 3.7, 3.8, and 3.9. +python-libarchive-c is currently tested with python 3.8, 3.9, 3.10 and 3.11. If you find an incompatibility with older versions you can send us a small patch, but we won't accept big changes. @@ -127,9 +126,22 @@ libarchive). The acceptable values are listed in ``libarchive.ffi.WRITE_FORMATS`` and ``libarchive.ffi.WRITE_FILTERS``. +File metadata codecs +-------------------- + +By default, UTF-8 is used to read and write file attributes from and to archives. +A different codec can be specified through the ``header_codec`` arguments of the +``*_reader`` and ``*_writer`` functions. Example:: + + with libarchive.file_writer('test.tar', 'ustar', header_codec='cp037') as archive: + ... + with file_reader('test.tar', header_codec='cp037') as archive: + ... + +In addition to file paths (``pathname`` and ``linkpath``), the specified codec is +used to encode and decode user and group names (``uname`` and ``gname``). + License ======= `CC0 Public Domain Dedication <http://creativecommons.org/publicdomain/zero/1.0/>`_ - - diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libarchive-c-4.0/setup.py new/libarchive-c-5.0/setup.py --- old/libarchive-c-4.0/setup.py 2019-11-22 10:30:52.000000000 +0100 +++ new/libarchive-c-5.0/setup.py 2023-06-29 10:33:58.000000000 +0200 @@ -7,6 +7,9 @@ os.umask(0o022) +with open(join(dirname(__file__), 'README.rst'), encoding="utf-8") as f: + README = f.read() + setup( name='libarchive-c', version=get_version(), @@ -16,7 +19,7 @@ url='https://github.com/Changaco/python-libarchive-c', license='CC0', packages=find_packages(exclude=['tests']), - long_description=open(join(dirname(__file__), 'README.rst')).read(), + long_description=README, long_description_content_type='text/x-rst', keywords='archive libarchive 7z tar bz2 zip gz', ) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libarchive-c-4.0/tests/test_entry.py new/libarchive-c-5.0/tests/test_entry.py --- old/libarchive-c-4.0/tests/test_entry.py 2022-01-22 18:28:18.000000000 +0100 +++ new/libarchive-c-5.0/tests/test_entry.py 2023-07-04 10:05:38.000000000 +0200 @@ -106,7 +106,7 @@ def test_the_life_cycle_of_archive_entries(): - """Check that the `get_blocks` method only works on the current entry, and only once. + """Check that `get_blocks` only works on the current entry, and only once. """ # Create a test archive in memory buf = bytes(bytearray(10_000_000)) @@ -135,3 +135,17 @@ assert type(entry3) is ArchiveEntry assert type(entry2) is PassedArchiveEntry assert type(entry1) is PassedArchiveEntry + + +def test_non_ASCII_encoding_of_file_metadata(): + buf = bytes(bytearray(100_000)) + file_name = 'README.rst' + encoded_file_name = 'README.rst'.encode('cp037') + with memory_writer(buf, 'ustar', header_codec='cp037') as archive: + archive.add_file(file_name) + with memory_reader(buf) as archive: + entry = next(iter(archive)) + assert entry.pathname == encoded_file_name + with memory_reader(buf, header_codec='cp037') as archive: + entry = next(iter(archive)) + assert entry.pathname == file_name diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libarchive-c-4.0/tests/test_rwx.py new/libarchive-c-5.0/tests/test_rwx.py --- old/libarchive-c-4.0/tests/test_rwx.py 2022-01-22 18:28:18.000000000 +0100 +++ new/libarchive-c-5.0/tests/test_rwx.py 2023-06-29 10:33:58.000000000 +0200 @@ -7,7 +7,7 @@ from libarchive.entry import format_time from libarchive.extract import EXTRACT_OWNER, EXTRACT_PERM, EXTRACT_TIME from libarchive.write import memory_writer -from mock import patch +from unittest.mock import patch import pytest from . import check_archive, in_dir, treestat diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libarchive-c-4.0/tox.ini new/libarchive-c-5.0/tox.ini --- old/libarchive-c-4.0/tox.ini 2022-01-22 18:28:18.000000000 +0100 +++ new/libarchive-c-5.0/tox.ini 2023-07-04 10:23:03.000000000 +0200 @@ -1,16 +1,14 @@ [tox] -envlist=py37,py38,py39 +envlist=py38,py39,py310,py311 skipsdist=True [testenv] passenv = LIBARCHIVE commands= - python -m pytest -Wd -vv --boxed --cov libarchive --cov-report term-missing {toxinidir}/tests {posargs} + python -m pytest -Wd -vv --forked --cov libarchive --cov-report term-missing {toxinidir}/tests {posargs} flake8 {toxinidir} deps= flake8 pytest pytest-cov - pytest-xdist - six - mock + pytest-forked diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libarchive-c-4.0/version.py new/libarchive-c-5.0/version.py --- old/libarchive-c-4.0/version.py 2016-11-29 19:03:26.000000000 +0100 +++ new/libarchive-c-5.0/version.py 2023-06-29 10:33:58.000000000 +0200 @@ -35,7 +35,7 @@ else: # Extract the version from the PKG-INFO file. - with open(join(d, 'PKG-INFO')) as f: + with open(join(d, 'PKG-INFO'), encoding='utf-8', errors='replace') as f: version = version_re.search(f.read()).group(1) return version