Skip to content

Commit

Permalink
Merge pull request #118 from Changaco/v4
Browse files Browse the repository at this point in the history
  • Loading branch information
Changaco authored Jan 22, 2022
2 parents 8256dba + ad73e00 commit 382ea82
Show file tree
Hide file tree
Showing 12 changed files with 586 additions and 220 deletions.
32 changes: 32 additions & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
name: CI
on:
# Trigger the workflow on push or pull request events but only for the master branch
push:
branches: [ master ]
pull_request:
branches: [ master ]
# Allow running this workflow manually from the Actions tab
workflow_dispatch:
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Install libarchive
run: sudo apt-get install -y libarchive13
- name: Install Python 3.9
uses: actions/setup-python@v2
with:
python-version: '3.9'
- name: Install Python 3.8
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
run: tox
42 changes: 0 additions & 42 deletions .travis.yml

This file was deleted.

83 changes: 67 additions & 16 deletions README.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
.. image:: https://travis-ci.org/Changaco/python-libarchive-c.svg
:target: https://travis-ci.org/Changaco/python-libarchive-c

A Python interface to libarchive. It uses the standard ctypes_ module to
dynamically load and access the C library.

Expand All @@ -17,7 +14,7 @@ Compatibility
python
------

python-libarchive-c is currently tested with python 3.6, 3.7, 3.8, and 3.9.
python-libarchive-c is currently tested with python 3.7, 3.8, and 3.9.

If you find an incompatibility with older versions you can send us a small patch,
but we won't accept big changes.
Expand All @@ -36,32 +33,86 @@ Import::

import libarchive

To extract an archive to the current directory::
Extracting archives
-------------------

To extract an archive, use the ``extract_file`` function::

os.chdir('/path/to/target/directory')
libarchive.extract_file('test.zip')

``extract_memory`` extracts from a buffer instead, and ``extract_fd`` extracts
from a file descriptor.
Alternatively, the ``extract_memory`` function can be used to extract from a buffer,
and ``extract_fd`` from a file descriptor.

The ``extract_*`` functions all have an integer ``flags`` argument which is passed
directly to the C function ``archive_write_disk_set_options()``. You can import
the ``EXTRACT_*`` constants from the ``libarchive.extract`` module and see the
official description of each flag in the ``archive_write_disk(3)`` man page.

By default, when the ``flags`` argument is ``None``, the ``SECURE_NODOTDOT``,
``SECURE_NOABSOLUTEPATHS`` and ``SECURE_SYMLINKS`` flags are passed to
libarchive, unless the current directory is the root (``/``).

To read an archive::
Reading archives
----------------

To read an archive, use the ``file_reader`` function::

with libarchive.file_reader('test.7z') as archive:
for entry in archive:
for block in entry.get_blocks():
...

``memory_reader`` reads from a memory buffer instead, and ``fd_reader`` reads
from a file descriptor.
Alternatively, the ``memory_reader`` function can be used to read from a buffer,
``fd_reader`` from a file descriptor, ``stream_reader`` from a stream object
(which must support the standard ``readinto`` method), and ``custom_reader``
from anywhere using callbacks.

To create an archive::
To learn about the attributes of the ``entry`` object, see the ``libarchive/entry.py``
source code or run ``help(libarchive.entry.ArchiveEntry)`` in a Python shell.

with libarchive.file_writer('test.tar.gz', 'ustar', 'gzip') as archive:
archive.add_files('libarchive/', 'README.rst')
Displaying progress
~~~~~~~~~~~~~~~~~~~

``memory_writer`` writes to a memory buffer instead, ``fd_writer`` writes to a
file descriptor, and ``custom_writer`` sends the data to a callback function.
If your program processes large archives, you can keep track of its progress
with the ``bytes_read`` attribute. Here's an example of a progress bar using
`tqdm <https://pypi.org/project/tqdm/>`_::

You can also find more thorough examples in the ``tests/`` directory.
with tqdm(total=os.stat(archive_path).st_size, unit='bytes') as pbar, \
libarchive.file_reader(archive_path) as archive:
for entry in archive:
...
pbar.update(archive.bytes_read - pbar.n)

Creating archives
-----------------

To create an archive, use the ``file_writer`` function::

from libarchive.entry import FileType

with libarchive.file_writer('test.tar.gz', 'ustar', 'gzip') as archive:
# Add the `libarchive/` directory and everything in it (recursively),
# then the `README.rst` file.
archive.add_files('libarchive/', 'README.rst')
# Add a regular file defined from scratch.
data = b'foobar'
archive.add_file_from_memory('../escape-test', len(data), data)
# Add a directory defined from scratch.
early_epoch = (42, 42) # 1970-01-01 00:00:42.000000042
archive.add_file_from_memory(
'metadata-test', 0, b'',
filetype=FileType.DIRECTORY, permission=0o755, uid=4242, gid=4242,
atime=early_epoch, mtime=early_epoch, ctime=early_epoch, birthtime=early_epoch,
)

Alternatively, the ``memory_writer`` function can be used to write to a memory buffer,
``fd_writer`` to a file descriptor, and ``custom_writer`` to a callback function.

For each of those functions, the mandatory second argument is the archive format,
and the optional third argument is the compression format (called “filter” in
libarchive). The acceptable values are listed in ``libarchive.ffi.WRITE_FORMATS``
and ``libarchive.ffi.WRITE_FILTERS``.

License
=======
Expand Down
Loading

0 comments on commit 382ea82

Please sign in to comment.