Hello community,
here is the log from the commit of package ghc-zip for openSUSE:Factory checked in at 2017-04-14 13:41:43
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/ghc-zip (Old)
and /work/SRC/openSUSE:Factory/.ghc-zip.new (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "ghc-zip"
Fri Apr 14 13:41:43 2017 rev:2 rq:487394 version:0.1.10
Changes:
--------
--- /work/SRC/openSUSE:Factory/ghc-zip/ghc-zip.changes 2017-03-28 15:19:31.284516948 +0200
+++ /work/SRC/openSUSE:Factory/.ghc-zip.new/ghc-zip.changes 2017-04-14 13:41:43.569428613 +0200
@@ -1,0 +2,30 @@
+Tue Apr 4 11:02:12 UTC 2017 - psimons@suse.com
+
+- Update to version 0.1.10 with cabal2obs.
+
+-------------------------------------------------------------------
+Tue Mar 7 11:19:19 UTC 2017 - psimons@suse.com
+
+- Update to version 0.1.9 with cabal2obs.
+
+-------------------------------------------------------------------
+Mon Feb 27 10:12:12 UTC 2017 - psimons@suse.com
+
+- Update to version 0.1.8 with cabal2obs.
+
+-------------------------------------------------------------------
+Sun Feb 12 14:17:56 UTC 2017 - psimons@suse.com
+
+- Update to version 0.1.7 with cabal2obs.
+
+-------------------------------------------------------------------
+Mon Jan 9 06:33:37 UTC 2017 - psimons@suse.com
+
+- Update to version 0.1.5 with cabal2obs.
+
+-------------------------------------------------------------------
+Mon Dec 19 10:18:57 UTC 2016 - psimons@suse.com
+
+- Update to version 0.1.4 with cabal2obs.
+
+-------------------------------------------------------------------
Old:
----
zip-0.1.3.tar.gz
New:
----
zip-0.1.10.tar.gz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ ghc-zip.spec ++++++
--- /var/tmp/diff_new_pack.Sdj484/_old 2017-04-14 13:41:44.813252819 +0200
+++ /var/tmp/diff_new_pack.Sdj484/_new 2017-04-14 13:41:44.813252819 +0200
@@ -1,7 +1,7 @@
#
# spec file for package ghc-zip
#
-# Copyright (c) 2016 SUSE LINUX GmbH, Nuernberg, Germany.
+# Copyright (c) 2017 SUSE LINUX GmbH, Nuernberg, Germany.
#
# All modifications and additions to the file contributed by third parties
# remain the property of their copyright owners, unless otherwise agreed
@@ -19,15 +19,14 @@
%global pkg_name zip
%bcond_with tests
Name: ghc-%{pkg_name}
-Version: 0.1.3
+Version: 0.1.10
Release: 0
Summary: Operations on zip archives
License: BSD-3-Clause
-Group: System/Libraries
+Group: Development/Languages/Other
Url: https://hackage.haskell.org/package/%{pkg_name}
Source0: https://hackage.haskell.org/package/%{pkg_name}-%{version}/%{pkg_name}-%{version}.tar.gz
BuildRequires: ghc-Cabal-devel
-# Begin cabal-rpm deps:
BuildRequires: ghc-bytestring-devel
BuildRequires: ghc-bzlib-conduit-devel
BuildRequires: ghc-case-insensitive-devel
@@ -44,7 +43,6 @@
BuildRequires: ghc-plan-b-devel
BuildRequires: ghc-resourcet-devel
BuildRequires: ghc-rpm-macros
-BuildRequires: ghc-semigroups-devel
BuildRequires: ghc-text-devel
BuildRequires: ghc-time-devel
BuildRequires: ghc-transformers-devel
@@ -53,7 +51,6 @@
BuildRequires: ghc-QuickCheck-devel
BuildRequires: ghc-hspec-devel
%endif
-# End cabal-rpm deps
%description
Operations on zip archives.
@@ -72,20 +69,14 @@
%prep
%setup -q -n %{pkg_name}-%{version}
-
%build
%ghc_lib_build
-
%install
%ghc_lib_install
-
%check
-%if %{with tests}
-%{cabal} test
-%endif
-
+%cabal_test
%post devel
%ghc_pkg_recache
++++++ zip-0.1.3.tar.gz -> zip-0.1.10.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/zip-0.1.3/CHANGELOG.md new/zip-0.1.10/CHANGELOG.md
--- old/zip-0.1.3/CHANGELOG.md 2016-05-15 18:55:15.000000000 +0200
+++ new/zip-0.1.10/CHANGELOG.md 2017-04-01 17:44:40.000000000 +0200
@@ -1,3 +1,50 @@
+## Zip 0.1.10
+
+* Made `getEntrySource` polymorphic in terms of the `Source` it returns.
+
+* Numerous cosmetic corrections to the docs.
+
+* Derived `Eq` and `Ord` for `EntrySelectorException` and `ZipException`.
+
+## Zip 0.1.9
+
+* Fixed a bug with modification time serialization on 32 bit systems.
+
+## Zip 0.1.8
+
+* Fixed a bug that caused `zip` to write incorrect number of entries
+ (instead of `0xffff`) in central directory when Zip64 feature is enabled.
+
+## Zip 0.1.7
+
+* Fix literal overflows on 32 bit systems.
+
+## Zip 0.1.6
+
+* Allowed `time-1.7`.
+
+* Fixed an issue when empty archives with Zip 64 feature enabled could not
+ be read (the “Parsing of archive structure failed: Cannot locate end of
+ central directory”).
+
+## Zip 0.1.5
+
+* Switched to using `withBinaryFile` instead of `withFile`, because the
+ latter does nasty conversions on Windows, see docs for `openBinaryFile`.
+
+## Zip 0.1.4
+
+* Added several simple code examples in `Codec.Archive.Zip`.
+
+* Derived `Typeable`, `Data`, `Generic` for `EntrySelector`.
+
+* Derived `Typeable` for `EntryDescription`.
+
+* Derived `Show`, `Ord`, `Bounded`, `Data`, and `Typeable` for
+ `CompressionMethod`.
+
+* Derived `Read`, `Ord`, `Typeable`, and `Data` for `ArchiveDescription`.
+
## Zip 0.1.3
* Improved speed of detection of invalid archives.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/zip-0.1.3/Codec/Archive/Zip/CP437.hs new/zip-0.1.10/Codec/Archive/Zip/CP437.hs
--- old/zip-0.1.3/Codec/Archive/Zip/CP437.hs 2016-03-05 18:53:43.000000000 +0100
+++ new/zip-0.1.10/Codec/Archive/Zip/CP437.hs 2017-04-01 17:20:59.000000000 +0200
@@ -1,13 +1,13 @@
-- |
-- Module : Codec.Archive.Zip.CP437
--- Copyright : © 2016 Mark Karpov
+-- Copyright : © 2016–2017 Mark Karpov
-- License : BSD 3 clause
--
-- Maintainer : Mark Karpov
-- Stability : experimental
-- Portability : portable
--
--- Support for decoding of CP437 text.
+-- Support for decoding of CP 437 text.
module Codec.Archive.Zip.CP437
( decodeCP437 )
@@ -29,7 +29,7 @@
(fmap (first decodeByteCP437) . B.uncons)
bs
--- | Decode single byte of CP437 encoded text.
+-- | Decode a single byte of CP437 encoded text.
decodeByteCP437 :: Word8 -> Char
decodeByteCP437 byte = chr $ case byte of
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/zip-0.1.3/Codec/Archive/Zip/Internal.hs new/zip-0.1.10/Codec/Archive/Zip/Internal.hs
--- old/zip-0.1.3/Codec/Archive/Zip/Internal.hs 2016-05-15 17:55:30.000000000 +0200
+++ new/zip-0.1.10/Codec/Archive/Zip/Internal.hs 2017-04-01 17:36:02.000000000 +0200
@@ -1,6 +1,6 @@
-- |
-- Module : Codec.Archive.Zip.Internal
--- Copyright : © 2016 Mark Karpov
+-- Copyright : © 2016–2017 Mark Karpov
-- License : BSD 3 clause
--
-- Maintainer : Mark Karpov
@@ -25,7 +25,7 @@
import Control.Applicative (many, (<|>))
import Control.Monad
import Control.Monad.Catch
-import Control.Monad.Trans.Resource (ResourceT, runResourceT)
+import Control.Monad.Trans.Resource (ResourceT, runResourceT, MonadResource)
import Data.Bits
import Data.Bool (bool)
import Data.ByteString (ByteString)
@@ -33,6 +33,7 @@
import Data.Conduit (Conduit, Source, Sink, (=$=), ($$), awaitForever, yield)
import Data.Conduit.Internal (zipSinks)
import Data.Digest.CRC32 (crc32Update)
+import Data.Fixed (Fixed (..))
import Data.Foldable (foldl')
import Data.Map.Strict (Map, (!))
import Data.Maybe (fromJust, catMaybes, isNothing)
@@ -108,7 +109,7 @@
, eaExtraField :: Map EntrySelector (Map Word16 ByteString)
, eaDeleteField :: Map EntrySelector (Map Word16 ()) }
--- | Origins of entries that can be streamed into archive.
+-- | Origin of entries that can be streamed into archive.
data EntryOrigin
= GenericOrigin
@@ -159,8 +160,8 @@
----------------------------------------------------------------------------
-- Higher-level operations
--- | Scan central directory of an archive and return its description
--- 'ArchiveDescription' as well as collection of its entries.
+-- | Scan the central directory of an archive and return its description
+-- 'ArchiveDescription' as well as a collection of its entries.
--
-- This operation may fail with:
--
@@ -176,18 +177,18 @@
-- cannot parse (this includes multi-disk archives, for example).
--
-- Please note that entries with invalid (non-portable) file names may be
--- missing in list of entries. Files that are compressed with unsupported
--- compression methods are skipped as well. Also, if several entries would
--- collide on some operating systems (such as Windows, because of its
--- case-insensitivity), only one of them will be available, because
--- 'EntrySelector' is case-insensitive. These are consequences of the design
--- decision to make it impossible to create non-portable archives with this
--- library.
+-- missing in the list of entries. Files that are compressed with
+-- unsupported compression methods are skipped as well. Also, if several
+-- entries would collide on some operating systems (such as Windows, because
+-- of its case-insensitivity), only one of them will be available, because
+-- 'EntrySelector' is case-insensitive. These are the consequences of the
+-- design decision to make it impossible to create non-portable archives
+-- with this library.
scanArchive
:: Path Abs File -- ^ Path to archive to scan
-> IO (ArchiveDescription, Map EntrySelector EntryDescription)
-scanArchive path = withFile (toFilePath path) ReadMode $ \h -> do
+scanArchive path = withBinaryFile (toFilePath path) ReadMode $ \h -> do
mecdOffset <- locateECD path h
case mecdOffset of
Just ecdOffset -> do
@@ -210,10 +211,11 @@
-- compressed or uncompressed depending on the third argument.
sourceEntry
- :: Path Abs File -- ^ Path to archive that contains the entry
+ :: MonadResource m
+ => Path Abs File -- ^ Path to archive that contains the entry
-> EntryDescription -- ^ Information needed to extract entry of interest
-> Bool -- ^ Should we stream uncompressed data?
- -> Source (ResourceT IO) ByteString -- ^ Source of uncompressed data
+ -> Source m ByteString -- ^ Source of uncompressed data
sourceEntry path EntryDescription {..} d =
source =$= CB.isolate (fromIntegral edCompressedSize) =$= decompress
where
@@ -248,7 +250,7 @@
let (ProducingActions coping sinking, editing) =
optimize (toRecreatingActions path entries >< xs)
comment = predictComment adComment xs
- withFile (toFilePath temp) WriteMode $ \h -> do
+ withBinaryFile (toFilePath temp) WriteMode $ \h -> do
copiedCD <- M.unions <$> forM (M.keys coping) (\srcPath ->
copyEntries h srcPath (coping ! srcPath) editing)
let sinkingKeys = M.keys $ sinking `M.difference` copiedCD
@@ -257,7 +259,7 @@
writeCD h comment (copiedCD `M.union` sunkCD)
-- | Determine what comment in new archive will look like given its original
--- value and collection of pending actions.
+-- value and a collection of pending actions.
predictComment :: Maybe Text -> Seq PendingAction -> Maybe Text
predictComment original xs =
@@ -267,19 +269,18 @@
Just (SetArchiveComment txt) -> Just txt
Just _ -> Nothing
--- | Transform map representing existing entries into collection of actions
--- that re-create those entires.
+-- | Transform a map representing existing entries into a collection of
+-- actions that re-create those entires.
toRecreatingActions
- :: Path Abs File -- ^ Name of archive file where entires are found
+ :: Path Abs File -- ^ Name of the archive file where entires are found
-> Map EntrySelector EntryDescription -- ^ Actual list of entires
-> Seq PendingAction -- ^ Actions that recreate the archive entries
toRecreatingActions path entries = E.foldl' f S.empty (M.keysSet entries)
where f s e = s |> CopyEntry path e e
--- | Transform collection of 'PendingAction's into 'ProducingActions' and
--- 'EditingActions' — collection of data describing how to create resulting
--- archive.
+-- | Transform a collection of 'PendingAction's into 'ProducingActions' and
+-- 'EditingActions' — data that describes how to create resulting archive.
optimize
:: Seq PendingAction -- ^ Collection of pending actions
@@ -346,8 +347,8 @@
if M.null n then Nothing else Just n
er _ Nothing = Nothing
--- | Copy entries from another archive and write them into file associated
--- with given handle. This actually can throw 'EntryDoesNotExist' if there
+-- | Copy entries from another archive and write them into the file
+-- associated with given handle. This can throw 'EntryDoesNotExist' if there
-- is no such entry in that archive.
copyEntries
@@ -367,7 +368,8 @@
(sourceEntry path desc False) e
return (M.fromList done)
--- | Sink entry from given stream into file associated with given 'Handle'.
+-- | Sink entry from given stream into the file associated with given
+-- 'Handle'.
sinkEntry
:: Handle -- ^ Opened 'Handle' of zip archive file
@@ -465,9 +467,9 @@
, ddUncompressedSize = uncompressedSize }
-- | Append central directory entries and end of central directory record to
--- file that given 'Handle' is associated with. Note that this automatically
--- writes Zip64 end of central directory record and Zip64 end of central
--- directory locator when necessary.
+-- the file that given 'Handle' is associated with. Note that this
+-- automatically writes Zip64 end of central directory record and Zip64 end
+-- of central directory locator when necessary.
writeCD
:: Handle -- ^ Opened handle of zip archive file
@@ -477,24 +479,25 @@
-> IO ()
writeCD h comment m = do
let cd = runPut (putCD m)
- cdOffset <- hTell h
+ cdOffset <- fromIntegral <$> hTell h
B.hPut h cd -- write central directory
- let totalCount = M.size m
- cdSize = B.length cd
- needZip64 = totalCount >= 0xffff
- || cdSize >= 0xffffffff
- || cdOffset >= 0xffffffff
+ let totalCount = fromIntegral (M.size m)
+ cdSize = fromIntegral (B.length cd)
+ needZip64 =
+ totalCount >= ffff
+ || cdSize >= ffffffff
+ || cdOffset >= ffffffff
when needZip64 $ do
- zip64ecdOffset <- hTell h
- B.hPut h . runPut $ putZip64ECD totalCount cdSize cdOffset
- B.hPut h . runPut $ putZip64ECDLocator zip64ecdOffset
- B.hPut h . runPut $ putECD totalCount cdSize cdOffset comment
+ zip64ecdOffset <- fromIntegral <$> hTell h
+ (B.hPut h . runPut) (putZip64ECD totalCount cdSize cdOffset)
+ (B.hPut h . runPut) (putZip64ECDLocator zip64ecdOffset)
+ (B.hPut h . runPut) (putECD totalCount cdSize cdOffset comment)
----------------------------------------------------------------------------
-- Binary serialization
--- | Extract number of bytes between start of file name in local header and
--- start of actual data.
+-- | Extract the number of bytes between start of file name in local header
+-- and start of actual data.
getLocalHeaderGap :: Get Integer
getLocalHeaderGap = do
@@ -516,8 +519,9 @@
getCD :: Get (Map EntrySelector EntryDescription)
getCD = M.fromList . catMaybes <$> many getCDHeader
--- | Parse single central directory file header. If it's a directory or file
--- compressed with unsupported compression method, 'Nothing' is returned.
+-- | Parse a single central directory file header. If it's a directory or
+-- file compressed with unsupported compression method, 'Nothing' is
+-- returned.
getCDHeader :: Get (Maybe (EntrySelector, EntryDescription))
getCDHeader = do
@@ -583,8 +587,8 @@
body <- getBytes (fromIntegral size) -- content
return (header, body)
--- | Get signature. If extracted data is not equal to provided signature,
--- fail.
+-- | Get signature. If the extracted data is not equal to provided
+-- signature, fail.
getSignature :: Word32 -> Get ()
getSignature sig = do
@@ -600,7 +604,7 @@
-> Zip64ExtraField -- ^ Result
parseZip64ExtraField dflt@Zip64ExtraField {..} b =
either (const dflt) id . flip runGet b $ do
- let ifsat v = if v >= 0xffffffff
+ let ifsat v = if v >= ffffffff
then fromIntegral <$> getWord64le
else return v
uncompressed <- ifsat z64efUncompressedSize -- uncompressed size
@@ -615,11 +619,11 @@
-> Zip64ExtraField -- ^ Zip64 extra field's data
-> ByteString -- ^ Resulting representation
makeZip64ExtraField c Zip64ExtraField {..} = runPut $ do
- when (c == LocalHeader || z64efUncompressedSize >= 0xffffffff) $
+ when (c == LocalHeader || z64efUncompressedSize >= ffffffff) $
putWord64le (fromIntegral z64efUncompressedSize) -- uncompressed size
- when (c == LocalHeader || z64efCompressedSize >= 0xffffffff) $
+ when (c == LocalHeader || z64efCompressedSize >= ffffffff) $
putWord64le (fromIntegral z64efCompressedSize) -- compressed size
- when (c == CentralDirHeader && z64efOffset >= 0xffffffff) $
+ when (c == CentralDirHeader && z64efOffset >= ffffffff) $
putWord64le (fromIntegral z64efOffset) -- offset of local file header
-- | Create 'ByteString' representing an extra field.
@@ -687,9 +691,9 @@
-- | Create 'ByteString' representing Zip64 end of central directory record.
putZip64ECD
- :: Int -- ^ Total number of entries
- -> Int -- ^ Size of the central directory
- -> Integer -- ^ Offset of central directory record
+ :: Natural -- ^ Total number of entries
+ -> Natural -- ^ Size of the central directory
+ -> Natural -- ^ Offset of central directory record
-> Put
putZip64ECD totalCount cdSize cdOffset = do
putWord32le 0x06064b50 -- zip64 end of central dir signature
@@ -708,7 +712,7 @@
-- locator.
putZip64ECDLocator
- :: Integer -- ^ Offset of Zip64 end of central directory
+ :: Natural -- ^ Offset of Zip64 end of central directory
-> Put
putZip64ECDLocator ecdOffset = do
putWord32le 0x07064b50 -- zip64 end of central dir locator signature
@@ -760,9 +764,9 @@
-- | Create 'ByteString' representing end of central directory record.
putECD
- :: Int -- ^ Total number of entries
- -> Int -- ^ Size of the central directory
- -> Integer -- ^ Offset of central directory record
+ :: Natural -- ^ Total number of entries
+ -> Natural -- ^ Size of the central directory
+ -> Natural -- ^ Offset of central directory record
-> Maybe Text -- ^ Zip file comment
-> Put
putECD totalCount cdSize cdOffset mcomment = do
@@ -821,7 +825,12 @@
else do
hSeek h AbsoluteSeek sigPos
cdSig <- getNum getWord32le 4
- return $ if cdSig == 0x02014b50 || cdSig == 0x06054b50
+ return $ if cdSig == 0x02014b50 ||
+ -- ↑ normal case: central directory file header signature
+ cdSig == 0x06064b50 ||
+ -- ↑ happens when zip 64 archive is empty
+ cdSig == 0x06054b50
+ -- ↑ happens when vanilla archive is empty
then Just pos
else Nothing
@@ -853,7 +862,7 @@
(>>+) :: IO (Maybe a) -> (a -> IO (Maybe b)) -> IO (Maybe b)
a >>+ b = a >>= maybe (return Nothing) b
--- | Rename entry (key) in a 'Map'.
+-- | Rename an entry (key) in a 'Map'.
renameKey :: Ord k => k -> k -> Map k a -> Map k a
renameKey ok nk m = case M.lookup ok m of
@@ -865,9 +874,10 @@
withSaturation :: forall a b. (Integral a, Integral b, Bounded b) => a -> b
withSaturation x =
- if x > fromIntegral (maxBound :: b)
- then maxBound :: b
+ if (fromIntegral x :: Integer) > (fromIntegral bound :: Integer)
+ then bound
else fromIntegral x
+ where bound = maxBound :: b
-- | Determine target entry of action.
@@ -935,13 +945,13 @@
fromCompressionMethod Deflate = 8
fromCompressionMethod BZip2 = 12
--- | Check if entry with these parameters needs Zip64 extension.
+-- | Check if an entry with these parameters needs Zip64 extension.
needsZip64 :: EntryDescription -> Bool
-needsZip64 EntryDescription {..} = any (>= 0xffffffff)
+needsZip64 EntryDescription {..} = any (>= ffffffff)
[edOffset, edCompressedSize, edUncompressedSize]
--- | Determine “version needed to extract” that should be written headers
+-- | Determine “version needed to extract” that should be written to headers
-- given need of Zip64 feature and compression method.
getZipVersion :: Bool -> Maybe CompressionMethod -> Version
@@ -953,12 +963,13 @@
Just Deflate -> [2,0]
Just BZip2 -> [4,6]
--- | Return decompressing 'Conduit' corresponding to given compression
+-- | Return decompressing 'Conduit' corresponding to the given compression
-- method.
decompressingPipe
- :: CompressionMethod
- -> Conduit ByteString (ResourceT IO) ByteString
+ :: MonadResource m
+ => CompressionMethod
+ -> Conduit ByteString m ByteString
decompressingPipe Store = awaitForever yield
decompressingPipe Deflate = Z.decompress $ Z.WindowBits (-15)
decompressingPipe BZip2 = BZ.bunzip2
@@ -976,7 +987,9 @@
dosTime = fromIntegral (seconds + shiftL minutes 5 + shiftL hours 11)
dosDate = fromIntegral (day + shiftL month 5 + shiftL year 9)
- seconds = fromEnum (todSec tod) `quot` 2000000000000
+ seconds =
+ let (MkFixed x) = todSec tod
+ in fromIntegral (x `quot` 2000000000000)
minutes = todMin tod
hours = todHour tod
tod = timeToTimeOfDay utctDayTime
@@ -998,3 +1011,10 @@
day = fromIntegral (msDosDate .&. 0x1f)
month = fromIntegral $ shiftR msDosDate 5 .&. 0x0f
year = 1980 + fromIntegral (shiftR msDosDate 9)
+
+-- | We use the constants of type 'Natural' instead of literals to protect
+-- ourselves from overflows on 32 bit systems.
+
+ffff, ffffffff :: Natural
+ffff = 0xffff
+ffffffff = 0xffffffff
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/zip-0.1.3/Codec/Archive/Zip/Type.hs new/zip-0.1.10/Codec/Archive/Zip/Type.hs
--- old/zip-0.1.3/Codec/Archive/Zip/Type.hs 2016-03-02 18:19:09.000000000 +0100
+++ new/zip-0.1.10/Codec/Archive/Zip/Type.hs 2017-04-01 17:26:49.000000000 +0200
@@ -1,6 +1,6 @@
-- |
-- Module : Codec.Archive.Zip.Type
--- Copyright : © 2016 Mark Karpov
+-- Copyright : © 2016–2017 Mark Karpov
-- License : BSD 3 clause
--
-- Maintainer : Mark Karpov
@@ -12,6 +12,7 @@
-- that module instead.
{-# LANGUAGE DeriveDataTypeable #-}
+{-# LANGUAGE DeriveGeneric #-}
module Codec.Archive.Zip.Type
( -- * Entry selector
@@ -34,6 +35,7 @@
import Control.Monad.Catch (MonadThrow (..))
import Data.ByteString (ByteString)
import Data.CaseInsensitive (CI)
+import Data.Data (Data)
import Data.List.NonEmpty (NonEmpty)
import Data.Map (Map)
import Data.Maybe (mapMaybe, fromJust)
@@ -42,6 +44,7 @@
import Data.Typeable (Typeable)
import Data.Version (Version)
import Data.Word (Word16, Word32)
+import GHC.Generics (Generic)
import Numeric.Natural
import Path
import qualified Data.ByteString as B
@@ -56,31 +59,31 @@
----------------------------------------------------------------------------
-- Entry selector
--- | This data type serves for naming and selection of archive
--- entries. It can be created only with help of smart constructor
+-- | This data type serves for naming and selection of archive entries. It
+-- can be created only with the help of the smart constructor
-- 'mkEntrySelector', and it's the only “key” that can be used to select
-- files in archive or to name new files.
--
-- The abstraction is crucial for ensuring that created archives are
--- portable across operating systems, file systems, and different
--- platforms. Since on some operating systems, file paths are
--- case-insensitive, this selector is also case-insensitive. It makes sure
--- that only relative paths are used to name files inside archive, as it's
--- recommended in the specification. It also guarantees that forward slashes
--- are used when the path is stored inside archive for compatibility with
--- Unix-like operating systems (as it is recommended in the
--- specification). On the other hand, in can be rendered as ordinary
--- relative file path in OS-specific format, when needed.
+-- portable across operating systems, file systems, and different platforms.
+-- Since on some operating systems, file paths are case-insensitive, this
+-- selector is also case-insensitive. It makes sure that only relative paths
+-- are used to name files inside archive, as it's recommended in the
+-- specification. It also guarantees that forward slashes are used when the
+-- path is stored inside archive for compatibility with Unix-like operating
+-- systems (as it is recommended in the specification). On the other hand,
+-- in can be rendered as ordinary relative file path in OS-specific format,
+-- when needed.
newtype EntrySelector = EntrySelector
{ unES :: NonEmpty (CI String)
-- ^ Path pieces of relative path inside archive
- } deriving (Eq, Ord)
+ } deriving (Eq, Ord, Typeable, Data, Generic)
instance Show EntrySelector where
show = show . unEntrySelector
--- | Create 'EntrySelector' from @Path Rel File@. To avoid problems with
+-- | Create an 'EntrySelector' from @Path Rel File@. To avoid problems with
-- distribution of the archive, characters that some operating systems do
-- not expect in paths are not allowed. Proper paths should pass these
-- checks:
@@ -119,7 +122,7 @@
parseRelFile
fromJust
--- | Get entry name given 'EntrySelector' in from that is suitable for
+-- | Get entry name given 'EntrySelector' in the from that is suitable for
-- writing to file header.
getEntryName :: EntrySelector -> Text
@@ -130,13 +133,13 @@
concat
T.pack
--- | Exception describing various troubles you can have with
+-- | The exception describing various troubles you can have with
-- 'EntrySelector'.
data EntrySelectorException
= InvalidEntrySelector (Path Rel File)
-- ^ Selector cannot be created from this path
- deriving (Typeable)
+ deriving (Eq, Ord, Typeable)
instance Show EntrySelectorException where
show (InvalidEntrySelector path) = "Cannot build selector from " ++ show path
@@ -147,7 +150,7 @@
-- Entry description
-- | This record represents all information about archive entry that can be
--- stored in a .ZIP archive. It does not mirror local file header or central
+-- stored in a zip archive. It does not mirror local file header or central
-- directory file header, but their binary representation can be built given
-- this date structure and actual archive contents.
@@ -162,7 +165,7 @@
, edOffset :: Natural -- ^ Absolute offset of local file header
, edComment :: Maybe Text -- ^ Entry comment
, edExtraField :: Map Word16 ByteString -- ^ All extra fields found
- } deriving Eq
+ } deriving (Eq, Typeable)
-- | Supported compression methods.
@@ -170,7 +173,7 @@
= Store -- ^ Store file uncompressed
| Deflate -- ^ Deflate
| BZip2 -- ^ Compressed using BZip2 algorithm
- deriving (Eq, Enum, Read, Show)
+ deriving (Show, Read, Eq, Ord, Enum, Bounded, Data, Typeable)
----------------------------------------------------------------------------
-- Archive description
@@ -181,19 +184,19 @@
{ adComment :: Maybe Text -- ^ Comment of entire archive
, adCDOffset :: Natural -- ^ Absolute offset of start of central directory
, adCDSize :: Natural -- ^ Size of central directory record
- } deriving (Eq, Show)
+ } deriving (Show, Read, Eq, Ord, Typeable, Data)
----------------------------------------------------------------------------
-- Exceptions
--- | Bad things that can happen when you use the library.
+-- | The bad things that can happen when you use the library.
data ZipException
= EntryDoesNotExist (Path Abs File) EntrySelector
-- ^ Thrown when you try to get contents of non-existing entry
| ParsingFailed (Path Abs File) String
-- ^ Thrown when archive structure cannot be parsed
- deriving (Typeable)
+ deriving (Eq, Ord, Typeable)
instance Show ZipException where
show (EntryDoesNotExist file s) =
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/zip-0.1.3/Codec/Archive/Zip.hs new/zip-0.1.10/Codec/Archive/Zip.hs
--- old/zip-0.1.3/Codec/Archive/Zip.hs 2016-05-15 18:49:17.000000000 +0200
+++ new/zip-0.1.10/Codec/Archive/Zip.hs 2017-04-01 17:14:32.000000000 +0200
@@ -1,22 +1,22 @@
-- |
-- Module : Codec.Archive.Zip
--- Copyright : © 2016 Mark Karpov
+-- Copyright : © 2016–2017 Mark Karpov
-- License : BSD 3 clause
--
-- Maintainer : Mark Karpov
-- Stability : experimental
-- Portability : portable
--
--- The module provides everything you need to manipulate Zip archives. There
--- are three things that should be clarified right away, to avoid confusion
--- in the future.
+-- The module provides everything you may need to manipulate Zip archives.
+-- There are three things that should be clarified right away, to avoid
+-- confusion in the future.
--
-- First, we use 'EntrySelector' type that can be obtained from 'Path' 'Rel'
-- 'File' paths. This method may seem awkward at first, but it will protect
-- you from problems with portability when your archive is unpacked on a
-- different platform. Using of well-typed paths is also something you
-- should consider doing in your projects anyway. Even if you don't want to
--- use "Path" module in your project, it's easy to marshal 'FilePath' to
+-- use the "Path" module in your project, it's easy to marshal 'FilePath' to
-- 'Path' just before using functions from the library.
--
-- The second thing, that is rather a consequence of the first, is that
@@ -26,11 +26,56 @@
-- Finally, the third feature of the library is that it does not modify
-- archive instantly, because doing so on every manipulation would often be
-- inefficient. Instead we maintain collection of pending actions that can
--- be turned into optimized procedure that efficiently modifies archive in
--- one pass. Normally this should be of no concern to you, because all
+-- be turned into an optimized procedure that efficiently modifies archive
+-- in one pass. Normally this should be of no concern to you, because all
-- actions are performed automatically when you leave the realm of
--- 'ZipArchive' monad. If, however, you ever need to force update, 'commit'
--- function is your friend. There are even “undo” functions, by the way.
+-- 'ZipArchive' monad. If, however, you ever need to force update, the
+-- 'commit' function is your friend. There are even “undo” functions, by the
+-- way.
+--
+-- An example of a program that prints list of archive entries:
+--
+-- > import Codec.Archive.Zip
+-- > import Path.IO (resolveFile')
+-- > import System.Environment (getArgs)
+-- > import qualified Data.Map as M
+-- >
+-- > main :: IO ()
+-- > main = do
+-- > [fp] <- getArgs
+-- > path <- resolveFile' fp
+-- > entries <- withArchive path (M.keys <$> getEntries)
+-- > mapM_ print entries
+--
+-- Create a Zip archive with a Hello World file:
+--
+-- > import Codec.Archive.Zip
+-- > import Path (parseRelFile)
+-- > import Path.IO (resolveFile')
+-- > import System.Environment (getArgs)
+-- >
+-- > main :: IO ()
+-- > main = do
+-- > [fp] <- getArgs
+-- > path <- resolveFile' fp
+-- > s <- parseRelFile "hello-world.txt" >>= mkEntrySelector
+-- > createArchive path (addEntry Store "Hello, World!" s)
+--
+-- Extract contents of specific file and print it:
+--
+-- > import Codec.Archive.Zip
+-- > import Path (parseRelFile)
+-- > import Path.IO (resolveFile')
+-- > import System.Environment (getArgs)
+-- > import qualified Data.ByteString.Char8 as B
+-- >
+-- > main :: IO ()
+-- > main = do
+-- > [fp,f] <- getArgs
+-- > path <- resolveFile' fp
+-- > s <- parseRelFile f >>= mkEntrySelector
+-- > bs <- withArchive path (getEntry s)
+-- > B.putStrLn bs
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
@@ -96,7 +141,7 @@
import Control.Monad
import Control.Monad.Catch
import Control.Monad.State.Strict
-import Control.Monad.Trans.Resource (ResourceT, runResourceT)
+import Control.Monad.Trans.Resource (ResourceT, runResourceT, MonadResource)
import Data.ByteString (ByteString)
import Data.Conduit (Source, Sink, ($$), yield)
import Data.Map.Strict (Map, (!))
@@ -116,7 +161,7 @@
----------------------------------------------------------------------------
-- Archive monad
--- | Monad that provides context necessary for performing operations on
+-- | Monad that provides context necessary for performing operations on zip
-- archives. It's intentionally opaque and not a monad transformer to limit
-- number of actions that can be performed in it to those provided by this
-- module and their combinations.
@@ -144,10 +189,10 @@
-- ^ Pending actions
}
--- | Create new archive given its location and action that describes how to
--- create content in the archive. This will silently overwrite specified
--- file if it already exists. See 'withArchive' if you want to work with
--- existing archive.
+-- | Create a new archive given its location and action that describes how
+-- to create contents of the archive. This will silently overwrite the
+-- specified file if it already exists. See 'withArchive' if you want to
+-- work with an existing archive.
createArchive :: (MonadIO m, MonadCatch m)
=> Path b File -- ^ Location of archive file to create
@@ -165,7 +210,7 @@
liftIO (evalStateT action st)
-- | Work with an existing archive. See 'createArchive' if you want to
--- create new archive instead.
+-- create a new archive instead.
--
-- This operation may fail with:
--
@@ -185,9 +230,9 @@
-- compression methods are skipped as well. Also, if several entries would
-- collide on some operating systems (such as Windows, because of its
-- case-insensitivity), only one of them will be available, because
--- 'EntrySelector' is case-insensitive. These are consequences of the design
--- decision to make it impossible to create non-portable archives with this
--- library.
+-- 'EntrySelector' is case-insensitive. These are the consequences of the
+-- design decision to make it impossible to create non-portable archives
+-- with this library.
withArchive :: (MonadIO m, MonadThrow m)
=> Path b File -- ^ Location of archive to work with
@@ -212,15 +257,15 @@
-- not hesitate to use the function frequently: scanning of archive happens
-- only once anyway.
--
--- Please note that returned value only reflects actual contents of archive
--- in file system, non-committed actions cannot influence list of entries,
--- see 'commit' for more information.
+-- Please note that the returned value only reflects actual contents of
+-- archive in file system, non-committed actions do not influence the list
+-- of entries, see 'commit' for more information.
getEntries :: ZipArchive (Map EntrySelector EntryDescription)
getEntries = ZipArchive (gets zsEntries)
--- | Check whether specified entry exists in the archive. This is a simple
--- shortcut defined as:
+-- | Check whether the specified entry exists in the archive. This is a
+-- simple shortcut defined as:
--
-- > doesEntryExist s = M.member s <$> getEntries
@@ -249,10 +294,13 @@
-- | Get entry source.
--
-- Throws: 'EntryDoesNotExist'.
+--
+-- @since 0.1.3
getEntrySource
- :: EntrySelector
- -> ZipArchive (Source (ResourceT IO) ByteString)
+ :: MonadResource m
+ => EntrySelector
+ -> ZipArchive (Source m ByteString)
getEntrySource s = do
path <- getFilePath
mdesc <- M.lookup s <$> getEntries
@@ -260,7 +308,7 @@
Nothing -> throwM (EntryDoesNotExist path s)
Just desc -> return (I.sourceEntry path desc True)
--- | Stream contents of archive entry to specified 'Sink'.
+-- | Stream contents of an archive entry to the given 'Sink'.
--
-- Throws: 'EntryDoesNotExist'.
@@ -275,7 +323,7 @@
src <- getEntrySource s
(liftIO . runResourceT) (src $$ sink)
--- | Save specific archive entry as a file in the file system.
+-- | Save a specific archive entry as a file in the file system.
--
-- Throws: 'EntryDoesNotExist'.
@@ -285,9 +333,9 @@
-> ZipArchive ()
saveEntry s path = sourceEntry s (CB.sinkFile (toFilePath path))
--- | Calculate CRC32 check sum and compare it with value read from
+-- | Calculate CRC32 check sum and compare it with the value read from the
-- archive. The function returns 'True' when the check sums are the same —
--- that is, data is not corrupted.
+-- that is, the data is not corrupted.
--
-- Throws: 'EntryDoesNotExist'.
@@ -301,8 +349,8 @@
-- 'sourceEntry' would have thrown 'EntryDoesNotExist' already.
return (calculated == given)
--- | Unpack entire archive into specified directory. The directory will be
--- created if it does not exist.
+-- | Unpack the entire archive into the specified directory. The directory
+-- will be created if it does not exist.
unpackInto :: Path b Dir -> ZipArchive ()
unpackInto dir' = do
@@ -315,12 +363,12 @@
forM_ selectors $ \s ->
saveEntry s (dir > unEntrySelector s)
--- | Get archive comment.
+-- | Get the archive comment.
getArchiveComment :: ZipArchive (Maybe Text)
getArchiveComment = adComment <$> getArchiveDescription
--- | Get archive description record.
+-- | Get the archive description record.
getArchiveDescription :: ZipArchive ArchiveDescription
getArchiveDescription = ZipArchive (gets zsArchive)
@@ -328,7 +376,7 @@
----------------------------------------------------------------------------
-- Modifying archive
--- | Add a new entry to archive given its contents in binary form.
+-- | Add a new entry to the archive given its contents in binary form.
addEntry
:: CompressionMethod -- ^ Compression method to use
@@ -346,7 +394,7 @@
-> ZipArchive ()
sinkEntry t src s = addPending (I.SinkEntry t src s)
--- | Load entry from given file.
+-- | Load an entry from a given file.
loadEntry
:: CompressionMethod -- ^ Compression method to use
@@ -361,8 +409,8 @@
addPending (I.SinkEntry t src s)
addPending (I.SetModTime modTime s)
--- | Copy entry “as is” from another .ZIP archive. If the entry does not
--- exists in that archive, 'EntryDoesNotExist' will be eventually thrown.
+-- | Copy an entry “as is” from another zip archive. If the entry does not
+-- exist in that archive, 'EntryDoesNotExist' will be eventually thrown.
copyEntry
:: Path b File -- ^ Path to archive to copy from
@@ -373,8 +421,8 @@
apath <- liftIO (canonicalizePath path)
addPending (I.CopyEntry apath s' s)
--- | Add entire directory to archive. Please note that due to design of the
--- library, empty sub-directories won't be added.
+-- | Add an entire directory to the archive. Please note that due to the
+-- design of the library, empty sub-directories won't be added.
--
-- The action can throw the same exceptions as 'listDirRecur' and
-- 'InvalidEntrySelector'.
@@ -388,8 +436,8 @@
files <- snd <$> liftIO (listDirRecur path)
mapM_ (loadEntry t f) files
--- | Rename entry in archive. If the entry does not exist, nothing will
--- happen.
+-- | Rename an entry in the archive. If the entry does not exist, nothing
+-- will happen.
renameEntry
:: EntrySelector -- ^ Original entry name
@@ -397,7 +445,8 @@
-> ZipArchive ()
renameEntry old new = addPending (I.RenameEntry old new)
--- | Delete entry from archive, if it does not exist, nothing will happen.
+-- | Delete an entry from the archive, if it does not exist, nothing will
+-- happen.
deleteEntry :: EntrySelector -> ZipArchive ()
deleteEntry s = addPending (I.DeleteEntry s)
@@ -411,24 +460,24 @@
-> ZipArchive ()
recompress t s = addPending (I.Recompress t s)
--- | Set entry comment, if that entry does not exist, nothing will
--- happen. Note that if binary representation of comment is longer than
+-- | Set an entry comment, if that entry does not exist, nothing will
+-- happen. Note that if binary representation of the comment is longer than
-- 65535 bytes, it will be truncated on writing.
setEntryComment
:: Text -- ^ Text of the comment
- -> EntrySelector -- ^ Name of entry to comment upon
+ -> EntrySelector -- ^ Name of entry to comment on
-> ZipArchive ()
setEntryComment text s = addPending (I.SetEntryComment text s)
--- | Delete entry's comment, if that entry does not exist, nothing will
+-- | Delete an entry's comment, if that entry does not exist, nothing will
-- happen.
deleteEntryComment :: EntrySelector -> ZipArchive ()
deleteEntryComment s = addPending (I.DeleteEntryComment s)
--- | Set “last modification” date\/time. Specified entry may be missing, in
--- that case this action has no effect.
+-- | Set the “last modification” date\/time. The specified entry may be
+-- missing, in that case the action has no effect.
setModTime
:: UTCTime -- ^ New modification time
@@ -436,8 +485,8 @@
-> ZipArchive ()
setModTime time s = addPending (I.SetModTime time s)
--- | Add an extra field. Specified entry may be missing, in that case this
--- action has no effect.
+-- | Add an extra field. The specified entry may be missing, in that case
+-- this action has no effect.
addExtraField
:: Word16 -- ^ Tag (header id) of extra field to add
@@ -446,7 +495,7 @@
-> ZipArchive ()
addExtraField n b s = addPending (I.AddExtraField n b s)
--- | Delete an extra field by its type (tag). Specified entry may be
+-- | Delete an extra field by its type (tag). The specified entry may be
-- missing, in that case this action has no effect.
deleteExtraField
@@ -455,30 +504,30 @@
-> ZipArchive ()
deleteExtraField n s = addPending (I.DeleteExtraField n s)
--- | Perform an action on every entry in archive.
+-- | Perform an action on every entry in the archive.
forEntries
:: (EntrySelector -> ZipArchive ()) -- ^ Action to perform
-> ZipArchive ()
forEntries action = getEntries >>= mapM_ action . M.keysSet
--- | Set comment of entire archive.
+-- | Set comment of the entire archive.
setArchiveComment :: Text -> ZipArchive ()
setArchiveComment text = addPending (I.SetArchiveComment text)
--- | Delete archive comment if it's present.
+-- | Delete the archive comment if it's present.
deleteArchiveComment :: ZipArchive ()
deleteArchiveComment = addPending I.DeleteArchiveComment
--- | Undo changes to specific archive entry.
+-- | Undo changes to a specific archive entry.
undoEntryChanges :: EntrySelector -> ZipArchive ()
undoEntryChanges s = modifyActions f
where f = S.filter ((/= Just s) . I.targetEntry)
--- | Undo changes to archive as a whole (archive's comment).
+-- | Undo changes to the archive as a whole (archive's comment).
undoArchiveChanges :: ZipArchive ()
undoArchiveChanges = modifyActions f
@@ -490,12 +539,12 @@
undoAll = modifyActions (const S.empty)
-- | Archive contents are not modified instantly, but instead changes are
--- collected as “pending actions” that should be committed in order to
+-- collected as “pending actions” that should be committed, in order to
-- efficiently modify archive in one pass. The actions are committed
--- automatically when program leaves the realm of 'ZipArchive' monad
--- (i.e. as part of 'createArchive' or 'withArchive'), or can be forced
--- explicitly with help of this function. Once committed, changes take place
--- in the file system and cannot be undone.
+-- automatically when program leaves the realm of 'ZipArchive' monad (i.e.
+-- as part of 'createArchive' or 'withArchive'), or can be forced explicitly
+-- with the help of this function. Once committed, changes take place in the
+-- file system and cannot be undone.
commit :: ZipArchive ()
commit = do
@@ -519,23 +568,24 @@
----------------------------------------------------------------------------
-- Helpers
--- | Get path of actual archive file from inside of 'ZipArchive' monad.
+-- | Get the path of the actual archive file from inside of 'ZipArchive'
+-- monad.
getFilePath :: ZipArchive (Path Abs File)
getFilePath = ZipArchive (gets zsFilePath)
--- | Get collection of pending actions.
+-- | Get the collection of pending actions.
getPending :: ZipArchive (Seq I.PendingAction)
getPending = ZipArchive (gets zsActions)
--- | Modify collection of pending actions in some way.
+-- | Modify the collection of pending actions in some way.
modifyActions :: (Seq I.PendingAction -> Seq I.PendingAction) -> ZipArchive ()
modifyActions f = ZipArchive (modify g)
where g st = st { zsActions = f (zsActions st) }
--- | Add new action to the list of pending actions.
+-- | Add a new action to the list of pending actions.
addPending :: I.PendingAction -> ZipArchive ()
addPending a = modifyActions (|> a)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/zip-0.1.3/LICENSE.md new/zip-0.1.10/LICENSE.md
--- old/zip-0.1.3/LICENSE.md 2016-01-03 14:37:56.000000000 +0100
+++ new/zip-0.1.10/LICENSE.md 2017-01-01 12:27:24.000000000 +0100
@@ -1,4 +1,4 @@
-Copyright © 2016 Mark Karpov
+Copyright © 2016–2017 Mark Karpov
All rights reserved.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/zip-0.1.3/README.md new/zip-0.1.10/README.md
--- old/zip-0.1.3/README.md 2016-03-03 16:51:14.000000000 +0100
+++ new/zip-0.1.10/README.md 2017-04-01 14:44:13.000000000 +0200
@@ -3,6 +3,7 @@
[![License BSD3](https://img.shields.io/badge/license-BSD3-brightgreen.svg)](http://opensource.org/licenses/BSD-3-Clause)
[![Hackage](https://img.shields.io/hackage/v/zip.svg?style=flat)](https://hackage.haskell.org/package/zip)
[![Stackage Nightly](http://stackage.org/package/zip/badge/nightly)](http://stackage.org/nightly/package/zip)
+[![Stackage LTS](http://stackage.org/package/zip/badge/lts)](http://stackage.org/lts/package/zip)
[![Build Status](https://travis-ci.org/mrkkrp/zip.svg?branch=master)](https://travis-ci.org/mrkkrp/zip)
[![Coverage Status](https://coveralls.io/repos/mrkkrp/zip/badge.svg?branch=master&service=github)](https://coveralls.io/github/mrkkrp/zip?branch=master)
@@ -31,11 +32,11 @@
## Why this library is written
There are a few libraries to work with Zip archives, yet every one of them
-provides only subset of all functionality user may need (obviously the
-libraries provide functionality that their authors needed) and otherwise is
-flawed in some way so it cannot be easily used in some situations. Let's
-examine all libraries available on Hackage to understand motivation for this
-package.
+provides only a subset of all the functionality a user may need (obviously
+the libraries provide functionality that their authors needed) and otherwise
+is flawed in some way so it cannot be easily used in some situations. Let's
+examine all the libraries available on Hackage to understand motivation for
+this package.
### zip-archive
@@ -44,20 +45,20 @@
memory that you can then write to the file system. This is not acceptable if
you work with more-or-less big data. For example, if you have collection of
files with total size of 500 MB and you want to pack them into an archive,
-you can easily consume up to 1 GB of memory (files plus resulting
+you can easily consume up to 1 GB of memory (the files plus resulting
archive). Not always you can afford to do this or do this at scale. Even if
you want just to look at list of archive entries it will read it into memory
in all its entirety. For my use-case it's not acceptable.
### LibZip
-This is bindings to C library
-[`libzip`](https://en.wikipedia.org/wiki/Libzip). There is always certain
-kind of trouble when you are using bindings. For example, you need to take
-care that target library is installed and its version is compatible with
-version of your binding. Yes, this means additional headaches. It should be
-just “plug and play” (if you're using Stack), but now you need to watch out
-for compatibility.
+This is a binding to C
+library [`libzip`](https://en.wikipedia.org/wiki/Libzip). There is always
+certain kind of trouble when you are using bindings. For example, you need
+to take care that target library is installed and its version is compatible
+with the version of your binding. Yes, this means additional headaches. It
+should be just “plug and play”, but now you need to watch out for
+compatibility.
It's not that bad with libraries that do not break their API for years, but
it's not the case with `libzip`. As maintainer of `LibZip` puts it:
@@ -68,9 +69,9 @@
Now, on my machine I have version 1.0. To put the package on Stackage we had
to use version 0.10, because Stackage uses Ubuntu to build packages and
-libraries on Ubuntu are always ancient. This means that I cannot use version
-of the library from Stackage, and I don't yet know what will be on the
-server.
+libraries on Ubuntu are always ancient. This means that I cannot use the
+version of the library from Stackage, and I don't yet know what will be on
+the server.
After much frustration with all these things I decided to avoid using of
`LibZip`, because after all, this is not that sort of project that shouldn't
@@ -79,19 +80,19 @@
### zip-conduit
-This one uses the right approach: leverage good streaming library
+This one uses the right approach: leverage a good streaming library
(`conduit`) for memory-efficient processing. This is however is not
feature-rich and has certain problems (including programming style, it uses
`error` if an entry is missing in archive, among other things), some of them
are reported on its issue tracker. It also does not appear to be maintained
-(last sign of activity was on December 23, 2014).
+(the last sign of activity was on December 23, 2014).
## Features
-The library supports all features specified in modern .ZIP specification
+The library supports all features specified in the modern .ZIP specification
except for encryption and multi-disk archives. See more about this below.
-For reference, here is a [copy of the specification](https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT).
+For reference, here is a [copy of the specification](https://pkware.cachefly.net/webdocs/APPNOTE/APPNOTE-6.3.3.TXT).
### Compression methods
@@ -103,8 +104,8 @@
The best way to add new compression method to the library is to write
conduit that will do the compression and publish it as a library. `zip` can
-then depend on it and add it to the list of supported compression
-methods. Current list of compression methods reflects what is available on
+then depend on it and add it to the list of supported compression methods.
+The current list of compression methods reflects what is available on
Hackage at the moment.
### Encryption
@@ -128,8 +129,8 @@
* *ByteString.* Use it only with small data.
-* *Copy file from another archive.* Efficient operation, file is copied “as
- is” — no re-compression is performed.
+* *Copy file from another archive.* An efficient operation, file is copied
+ “as is” — no re-compression is performed.
### ZIP64
@@ -165,17 +166,17 @@
## Quick start
-The module `Codec.Archive.Zip` provides everything you need to manipulate
-Zip archives. There are three things that should be clarified right away, to
-avoid confusion in the future.
+The module `Codec.Archive.Zip` provides everything you may need to
+manipulate Zip archives. There are three things that should be clarified
+right away, to avoid confusion in the future.
First, we use `EntrySelector` type that can be obtained from `Path Rel File`
paths. This method may seem awkward at first, but it will protect you from
problems with portability when your archive is unpacked on a different
platform. Using of well-typed paths is also something you should consider
-doing in your projects anyway. Even if you don't want to use `Path` module
-in your project, it's easy to marshal `FilePath` to `Path` just before using
-functions from the library.
+doing in your projects anyway. Even if you don't want to use the `Path`
+module in your project, it's easy to marshal `FilePath` to `Path` just
+before using functions from the library.
The second thing, that is rather a consequence of the first, is that there
is no way to add directories, or to be precise, *empty directories* to your
@@ -184,10 +185,10 @@
Finally, the third feature of the library is that it does not modify archive
instantly, because doing so on every manipulation would often be
inefficient. Instead we maintain collection of pending actions that can be
-turned into optimized procedure that efficiently modifies archive in one
+turned into an optimized procedure that efficiently modifies archive in one
pass. Normally this should be of no concern to you, because all actions are
performed automatically when you leave the realm of `ZipArchive` monad. If,
-however, you ever need to force update, `commit` function is your
+however, you ever need to force update, the `commit` function is your
friend. There are even “undo” functions, by the way.
Let's take a look at some examples that show how to accomplish most typical
@@ -218,7 +219,7 @@
λ> withArchive archivePath (saveEntry entrySelector pathToFile)
```
-…and finally just unpack entire archive into some directory:
+…and finally just unpack the entire archive into some directory:
```haskell
λ> withArchive archivePath (unpackInto destDir)
@@ -226,9 +227,9 @@
See also `getArchiveComment` and `getArchiveDescription`.
-Modifying is also easy, efficient, and powerful. When you want to create new
-archive use `createArchive`, otherwise `withArchive` will do. To add entry
-from `ByteString`:
+Modifying is also easy, efficient, and powerful. When you want to create a
+new archive use `createArchive`, otherwise `withArchive` will do. To add
+entry from `ByteString`:
```haskell
λ> createArchive archivePath (addEntry Store "Hello, World!" entrySelector)
@@ -247,7 +248,7 @@
λ> createArchive archivePath (loadEntry BZip2 toSelector myFilePath)
```
-Finally, you can copy entry from another archive without re-compression
+Finally, you can copy an entry from another archive without re-compression
(unless you use `recompress`, see below):
```haskell
@@ -286,6 +287,6 @@
## License
-Copyright © 2016 Mark Karpov
+Copyright © 2016–2017 Mark Karpov
Distributed under BSD 3 clause license.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/zip-0.1.3/bench/Main.hs new/zip-0.1.10/bench/Main.hs
--- old/zip-0.1.3/bench/Main.hs 2016-01-28 10:53:21.000000000 +0100
+++ new/zip-0.1.10/bench/Main.hs 1970-01-01 01:00:00.000000000 +0100
@@ -1,38 +0,0 @@
---
--- Benchmarks for the ‘zip’ package.
---
--- Copyright © 2016 Mark Karpov
---
--- Redistribution and use in source and binary forms, with or without
--- modification, are permitted provided that the following conditions are
--- met:
---
--- * Redistributions of source code must retain the above copyright notice,
--- this list of conditions and the following disclaimer.
---
--- * Redistributions in binary form must reproduce the above copyright
--- notice, this list of conditions and the following disclaimer in the
--- documentation and/or other materials provided with the distribution.
---
--- * Neither the name Mark Karpov nor the names of contributors may be used
--- to endorse or promote products derived from this software without
--- specific prior written permission.
---
--- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS “AS IS” AND ANY
--- EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
--- WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
--- DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
--- DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
--- DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
--- OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
--- HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
--- STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
--- ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
--- POSSIBILITY OF SUCH DAMAGE.
-
-module Main (main) where
-
-import Criterion.Main
-
-main :: IO ()
-main = defaultMain [] -- TODO
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/zip-0.1.3/tests/Main.hs new/zip-0.1.10/tests/Main.hs
--- old/zip-0.1.3/tests/Main.hs 2016-04-09 09:49:26.000000000 +0200
+++ new/zip-0.1.10/tests/Main.hs 2017-02-09 19:09:50.000000000 +0100
@@ -1,7 +1,7 @@
--
-- Tests for the ‘zip’ package.
--
--- Copyright © 2016 Mark Karpov
+-- Copyright © 2016–2017 Mark Karpov
--
-- Redistribution and use in source and binary forms, with or without
-- modification, are permitted provided that the following conditions are
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/zip-0.1.3/zip.cabal new/zip-0.1.10/zip.cabal
--- old/zip-0.1.3/zip.cabal 2016-05-15 18:55:59.000000000 +0200
+++ new/zip-0.1.10/zip.cabal 2017-04-01 17:46:35.000000000 +0200
@@ -1,7 +1,7 @@
--
-- Cabal configuration for ‘zip’.
--
--- Copyright © 2016 Mark Karpov
+-- Copyright © 2016–2017 Mark Karpov
--
-- Redistribution and use in source and binary forms, with or without
-- modification, are permitted provided that the following conditions are
@@ -31,7 +31,7 @@
-- POSSIBILITY OF SUCH DAMAGE.
name: zip
-version: 0.1.3
+version: 0.1.10
cabal-version: >= 1.10
license: BSD3
license-file: LICENSE.md
@@ -43,7 +43,7 @@
synopsis: Operations on zip archives
build-type: Simple
description: Operations on zip archives.
-extra-source-files: CHANGELOG.md
+extra-doc-files: CHANGELOG.md
, README.md
flag dev
@@ -52,25 +52,25 @@
default: False
library
- build-depends: base >= 4.8 && < 5
- , bytestring >= 0.9 && < 0.11
- , bzlib-conduit >= 0.2 && < 0.3
+ build-depends: base >= 4.8 && < 5.0
+ , bytestring >= 0.9 && < 0.11
+ , bzlib-conduit >= 0.2 && < 0.3
, case-insensitive >= 1.2.0.2 && < 1.3
- , cereal >= 0.3 && < 0.6
- , conduit >= 1.1 && < 2
- , conduit-extra >= 1.1 && < 2
+ , cereal >= 0.3 && < 0.6
+ , conduit >= 1.1 && < 2.0
+ , conduit-extra >= 1.1 && < 2.0
, containers >= 0.5.6.2 && < 0.6
, digest < 0.1
- , exceptions >= 0.6 && < 0.9
- , filepath >= 1.2 && < 1.5
- , mtl >= 2.0 && < 3
- , path >= 0.5 && < 6
- , path-io >= 1.0.1 && < 2
- , plan-b >= 0.2.0
- , resourcet >= 1.0 && < 2
- , text >= 0.2 && < 1.3
- , time >= 1.4 && < 1.7
- , transformers >= 0.4 && < 0.6
+ , exceptions >= 0.6 && < 0.9
+ , filepath >= 1.2 && < 1.5
+ , mtl >= 2.0 && < 3.0
+ , path >= 0.5 && < 0.6
+ , path-io >= 1.0.1 && < 2.0
+ , plan-b >= 0.2 && < 0.3
+ , resourcet >= 1.0 && < 2.0
+ , text >= 0.2 && < 1.3
+ , time >= 1.4 && < 1.8
+ , transformers >= 0.4 && < 0.6
if !impl(ghc >= 8.0)
build-depends: semigroups >= 0.16
default-extensions: RecordWildCards
@@ -93,33 +93,20 @@
ghc-options: -Wall -Werror
else
ghc-options: -O2 -Wall
- build-depends: base >= 4.8 && < 5
- , bytestring >= 0.9 && < 0.11
- , conduit >= 1.1 && < 2
+ build-depends: base >= 4.8 && < 5.0
+ , bytestring >= 0.9 && < 0.11
+ , conduit >= 1.1 && < 2.0
, containers >= 0.5.6.2 && < 0.6
- , exceptions >= 0.6 && < 0.9
- , filepath >= 1.2 && < 1.5
- , QuickCheck >= 2.4 && < 3
- , hspec >= 2.0 && < 3
- , path >= 0.5 && < 6
- , path-io >= 1.0.1 && < 2
- , text >= 0.2 && < 1.3
- , time >= 1.4 && < 1.7
- , transformers >= 0.4 && < 0.6
- , zip >= 0.1.3
- default-language: Haskell2010
-
-benchmark bench
- main-is: Main.hs
- hs-source-dirs: bench
- type: exitcode-stdio-1.0
- if flag(dev)
- ghc-options: -O2 -Wall -Werror
- else
- ghc-options: -O2 -Wall
- build-depends: base >= 4.8 && < 5
- , criterion >= 1.0
- , zip >= 0.1.3
+ , exceptions >= 0.6 && < 0.9
+ , filepath >= 1.2 && < 1.5
+ , QuickCheck >= 2.4 && < 3.0
+ , hspec >= 2.0 && < 3.0
+ , path >= 0.5 && < 6.0
+ , path-io >= 1.0.1 && < 2.0
+ , text >= 0.2 && < 1.3
+ , time >= 1.4 && < 1.8
+ , transformers >= 0.4 && < 0.6
+ , zip >= 0.1.10
default-language: Haskell2010
source-repository head