packages feed

zip2tar (empty) → 0.0

raw patch · 4 files changed

+269/−0 lines, 4 filesdep +basedep +bytestringdep +conduitsetup-changed

Dependencies added: base, bytestring, conduit, containers, optparse-applicative, tar-conduit, time, zip

Files

+ LICENSE view
@@ -0,0 +1,30 @@+Copyright (c) 2026, Henning Thielemann++All rights reserved.++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 of Henning Thielemann nor the names of other+      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 AND CONTRIBUTORS+"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+OWNER OR CONTRIBUTORS 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.
+ Setup.lhs view
@@ -0,0 +1,3 @@+#! /usr/bin/env runhaskell+> import Distribution.Simple+> main = defaultMain
+ src/Main.hs view
@@ -0,0 +1,166 @@+module Main where++import qualified Options.Applicative as OP+import System.Posix.Types (FileMode)++import qualified Codec.Archive.Zip.Unix as ZipUnix+import qualified Codec.Archive.Zip as Zip+import qualified Data.Conduit.Tar as CTar+import qualified Conduit as C+import Data.Conduit (runConduitRes, (.|))++import qualified Data.Time.Clock.POSIX as PosixTime+import qualified Data.ByteString.Char8 as BC+import qualified Data.Map as Map+import qualified Data.List as List+import qualified Data.Char as Char+import Data.Traversable (for)+import Data.Ord (comparing)+import Data.Bits ((.&.), (.|.))+import Data.Word (Word32)++import Control.Monad (join, void)++++info :: OP.Parser a -> OP.ParserInfo a+info p =+   OP.info+      (OP.helper <*> p)+      (OP.fullDesc <>+       OP.progDesc "Convert ZIP to TAR archive")++data Sort = SortPosition | SortLexicographic+   deriving (Eq, Ord)++parser :: OP.Parser (IO ())+parser =+   pure convertZipToTar+   <*> parseInfoConversion+   <*>+      OP.flag SortPosition SortLexicographic+         (OP.long "sort-by-name" <>+          OP.help+            "sort files by names (default: storage order)")+   <*>+      OP.strArgument+         (OP.metavar "INPUT" <>+          OP.help "Input ZIP archive")++parseInfoConversion ::+   OP.Parser (Zip.EntrySelector -> Zip.EntryDescription -> CTar.FileInfo)+parseInfoConversion =+   pure fileInfoFromZipEntry+   <*>+      OP.option (OP.eitherReader packName)+         (OP.long "user-name" <>+          OP.metavar "NAME" <>+          OP.value BC.empty <>+          OP.help "UNIX user name for files in TAR output")+   <*>+      OP.option OP.auto+         (OP.long "user-id" <>+          OP.metavar "UID" <>+          OP.value 0 <>+          OP.help "UNIX user id for files in TAR output")+   <*>+      OP.option (OP.eitherReader packName)+         (OP.long "group-name" <>+          OP.metavar "NAME" <>+          OP.value BC.empty <>+          OP.help "UNIX group name for files in TAR output")+   <*>+      OP.option OP.auto+         (OP.long "group-id" <>+          OP.metavar "GID" <>+          OP.value 0 <>+          OP.help "UNIX group id for files in TAR output")+   <*>+      OP.flag AttributeWindows AttributeUNIX+         (OP.long "use-unix-permissions" <>+          OP.help+            ("respect UNIX file permissions of zipped files " +++             "(default: read Windows attributes)"))++packName :: String -> Either String BC.ByteString+packName name =+   if all Char.isAscii name+   then Right $ BC.pack name+   else Left "name contains non-ASCII characters"+++main :: IO ()+main = join $ OP.execParser $ info parser+++convertZipToTar ::+   (Zip.EntrySelector -> Zip.EntryDescription -> CTar.FileInfo) ->+   Sort -> FilePath -> IO ()+convertZipToTar fileInfoFromZipEntry_ sortMode zipPath =+   Zip.withArchive zipPath $ do+      let sort =+            case sortMode of+               SortPosition -> List.sortBy (comparing (Zip.edOffset . snd))+               SortLexicographic -> id+      entries <- sort . Map.toList <$> Zip.getEntries+      files <-+         for entries $ \(selector, descr) ->+            flip fmap (Zip.getEntrySource selector) $ \src ->+               src+               .|+               (C.yield (Left $ fileInfoFromZipEntry_ selector descr)+                >>+                C.mapC Right)+      C.liftIO $ runConduitRes $+         sequence_ files+         .|+         void CTar.tar+         .|+         C.stdoutC+++data AttributeSource = AttributeWindows | AttributeUNIX+   deriving (Eq, Ord)+++windowsReadonlyAttr :: Word32+windowsReadonlyAttr = 1++unixUserReadable :: FileMode+unixUserReadable = 0o400++unixUserWriteable :: FileMode+unixUserWriteable = 0o200++unixPermFromWindowsAttr :: Word32 -> FileMode+unixPermFromWindowsAttr attrs =+   unixUserReadable+   .|.+   if attrs .&. windowsReadonlyAttr == 0+      then unixUserWriteable+      else 0++fileInfoFromZipEntry ::+   BC.ByteString -> CTar.UserID ->+   BC.ByteString -> CTar.GroupID ->+   AttributeSource ->+   Zip.EntrySelector -> Zip.EntryDescription -> CTar.FileInfo+fileInfoFromZipEntry userName userId groupName groupId attrSrc sel descr =+   CTar.FileInfo {+      CTar.filePath      = BC.pack $ Zip.unEntrySelector sel,+      CTar.fileUserId    = userId,+      CTar.fileUserName  = userName,+      CTar.fileGroupId   = groupId,+      CTar.fileGroupName = groupName,+      CTar.fileMode      =+         (case attrSrc of+            AttributeWindows -> unixPermFromWindowsAttr+            AttributeUNIX -> ZipUnix.toFileMode) $+         Zip.edExternalFileAttrs descr,+      CTar.fileSize      = fromIntegral $ Zip.edUncompressedSize descr,+      CTar.fileType      = CTar.FTNormal,+      CTar.fileModTime   =+         fromInteger $ round $+         (realToFrac $ PosixTime.utcTimeToPOSIXSeconds $ Zip.edModTime descr+            :: Rational)+   }
+ zip2tar.cabal view
@@ -0,0 +1,70 @@+Name:                zip2tar+Version:             0.0+Synopsis:            Convert ZIP to TAR archives+Description:+  Convert ZIP to TAR archives with minimal memory footprint.+  .+  Usage:+  .+  > zip2tar input.zip >output.tar+  .+  > zip2tar input.zip | lzip >output.tar.lz+  .+  ZIP archives cannot be read in a purely sequential way,+  because the central file catalogue is stored at the end of the archive file.+  Thus we do not provide reading ZIP archives from Stdin.+  .+  Per default @zip2tar@ stores files in the TAR archive+  in the same order as the ZIP archive in order to minimize seeking.+  However this means unsorted filenames.+  You can order with respect to filenames with the @--sort-by-name@ option.+  .+  Per default @zip2tar@ sets user and group+  ids to zero and names to empty strings,+  because we do not know what is available on the system+  where the TAR archive gets unpacked.+  You may set those values individually like in:+  .+  > zip2tar --user-name janedoe --user-id 42 --group-name users --group-id 23 input.zip+  .+  @zip2tar@ does not try to derive id from name or vice versa.+  If you want certain values you must set them explicitly.+  You may want to set the values to the settings of the current system like so:+  .+  > zip2tar --user-name $USER --user-id $UID --group-name $(id -gn) --group-id $(id -g) input.zip+Homepage:            https://hub.darcs.net/thielema/zip2tar+License:             BSD3+License-File:        LICENSE+Author:              Henning Thielemann+Maintainer:          haskell@henning-thielemann.de+Category:            Archive, Codec+Build-Type:          Simple+Cabal-Version:       >=1.10++Source-Repository this+  Tag:         0.0+  Type:        darcs+  Location:    https://hub.darcs.net/thielema/zip2tar++Source-Repository head+  Type:        darcs+  Location:    https://hub.darcs.net/thielema/zip2tar++-- Alternative: https://github.com/dylex/zip-stream 2017+-- Alternative: https://github.com/timcherganov/zip-conduit 2022, has no way to "conduit" the whole archive++Executable zip2tar+  Build-Depends:+    zip >=2.2 && <2.3,+    tar-conduit >=0.4.1 && <0.5,+    conduit >=1.3 && <1.4,+    optparse-applicative >=0.11 && <0.20,+    time >=1.0 && <1.16,+    bytestring >=0.10 && <0.13,+    containers >=0.6 && <0.9,+    base >=4.5 && <5+  Hs-Source-Dirs:      src+  Main-Is:             Main.hs+  Default-Language:    Haskell2010+  GHC-Options:+    -Wall -fwarn-incomplete-uni-patterns -fwarn-tabs