Simple ZIP archive manipulation.
- Creating archives
- Reading archives
- Compression methods:
- No compression
- DEFLATE
- In-memory manipulation via
zippy-memory streamingsupport viazippy-streaming
- Timestamps
- Updating archives
- Directories
- ZIP64
- Compression methods other than DEFLATE
If you like this library and would like to request a feature, then create an issue.
-
zip- the most complete ZIP library on Hackage. -
zip-archive- supports fewer features thanzip, but has a pure interface.
I created zippy for aesthetic reasons.
Neither zip nor zip-archive satisfy my sense of how the original problem should be solved,
so I wanted to build something that reflected my values.
The main thing I disagree with zip on is its choice of dependencies.
Specifically:
-
transformers-baseandmonad-controlTo me,
MonadBaseControlis a legacy concept from when the Haskell community was experimenting with ways to adaptbracketto monad transformers. In my opinion,MonadMaskfromexceptionsis the definitive solution. -
Based on the
unliftioecosystem (viaunliftio-core), which it uses formasking exceptions. Another place whereMonadMaskshould be used. -
conduitecosystemHaskell has an abundance of streaming libraries, and a ZIP archive library shouldn't mandate a particular choice.
zip-archive has a better dependency story, but it doesn't support streaming.
My goal with zippy was to keep a minimal dependency footprint while supporting opt-in streaming.
I did this by writing zippy such that it can be extended with new libraries that provide streaming support (e.g. zippy-streaming).
This meant exposing a low-level ZIP archive interface for such libraries, which is another place my taste departs from the norm.
zip provides
Codec.Archive.Zip.Internal
which contains "Low-level, non-public types and operations.".
"Internal" modules are conventional in Haskell12,
and in my experience tend to lack a coherent design and interface stability when compared to their non-internal counterparts.
Even though this kind of "internal" module allows some kind of extension, it's usually not a good experience.
In contrast, zippy provides a low-level ZIP interface (Zip.Archive) that is designed for external consumption.
The high-level Zip module hides datatype internals and implementation details,
and Zip.Archive exposes these in a structured, curated way.
Zip becomes the first client of the Zip.Archive interface, as if they were separate packages.
Adding another client of Zip.Archive (zippy-streaming) gives an even better feel for the module's usability.
There's now an organising principle for deciding where a feature goes:
Clients of Zip.Archive understand the logical structure of ZIP archives but doesn't care about bit-bashing,
and Zip.Archive provides an interface into that logical structure and takes care of the bit manipulation.
A solid low-level module with two usage examples makes it much easier to write extensions to zippy,
such as a package that supports your favourite streaming library.
This design also results in fewer dependencies for the core library as more dependencies are made opt-in via extension packages
(i.e. zippy-streaming depends on streaming so that zippy doesn't have to).