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

Reply via email to