cabal init -i should sanitize suggested package name (fix #8404) (#8561)
[cabal.git] / cabal-install / src / Distribution / Client / Tar.hs
blobd59dcf8160ad297a42c2d0580382b671b36f0054
1 {-# LANGUAGE DeriveFunctor #-}
2 {-# OPTIONS_GHC -fno-warn-orphans #-}
3 -----------------------------------------------------------------------------
4 -- |
5 -- Module : Distribution.Client.Tar
6 -- Copyright : (c) 2007 Bjorn Bringert,
7 -- 2008 Andrea Vezzosi,
8 -- 2008-2009 Duncan Coutts
9 -- License : BSD3
11 -- Maintainer : duncan@community.haskell.org
12 -- Portability : portable
14 -- Reading, writing and manipulating \"@.tar@\" archive files.
16 -----------------------------------------------------------------------------
17 module Distribution.Client.Tar (
18 -- * @tar.gz@ operations
19 createTarGzFile,
20 extractTarGzFile,
22 -- * Other local utils
23 buildTreeRefTypeCode,
24 buildTreeSnapshotTypeCode,
25 isBuildTreeRefTypeCode,
26 filterEntries,
27 filterEntriesM,
28 entriesToList,
29 ) where
31 import Distribution.Client.Compat.Prelude
32 import Prelude ()
34 import qualified Data.ByteString.Lazy as BS
35 import qualified Codec.Archive.Tar as Tar
36 import qualified Codec.Archive.Tar.Entry as Tar
37 import qualified Codec.Archive.Tar.Check as Tar
38 import qualified Codec.Compression.GZip as GZip
39 import qualified Distribution.Client.GZipUtils as GZipUtils
41 -- for foldEntries...
42 import Control.Exception (throw)
45 -- * High level operations
48 createTarGzFile :: FilePath -- ^ Full Tarball path
49 -> FilePath -- ^ Base directory
50 -> FilePath -- ^ Directory to archive, relative to base dir
51 -> IO ()
52 createTarGzFile tar base dir =
53 BS.writeFile tar . GZip.compress . Tar.write =<< Tar.pack base [dir]
55 extractTarGzFile :: FilePath -- ^ Destination directory
56 -> FilePath -- ^ Expected subdir (to check for tarbombs)
57 -> FilePath -- ^ Tarball
58 -> IO ()
59 extractTarGzFile dir expected tar =
60 Tar.unpack dir . Tar.checkTarbomb expected . Tar.read
61 . GZipUtils.maybeDecompress =<< BS.readFile tar
63 instance (Exception a, Exception b) => Exception (Either a b) where
64 toException (Left e) = toException e
65 toException (Right e) = toException e
67 fromException e =
68 case fromException e of
69 Just e' -> Just (Left e')
70 Nothing -> case fromException e of
71 Just e' -> Just (Right e')
72 Nothing -> Nothing
75 -- | Type code for the local build tree reference entry type. We don't use the
76 -- symbolic link entry type because it allows only 100 ASCII characters for the
77 -- path.
78 buildTreeRefTypeCode :: Tar.TypeCode
79 buildTreeRefTypeCode = 'C'
81 -- | Type code for the local build tree snapshot entry type.
82 buildTreeSnapshotTypeCode :: Tar.TypeCode
83 buildTreeSnapshotTypeCode = 'S'
85 -- | Is this a type code for a build tree reference?
86 isBuildTreeRefTypeCode :: Tar.TypeCode -> Bool
87 isBuildTreeRefTypeCode typeCode
88 | (typeCode == buildTreeRefTypeCode
89 || typeCode == buildTreeSnapshotTypeCode) = True
90 | otherwise = False
92 filterEntries :: (Tar.Entry -> Bool) -> Tar.Entries e -> Tar.Entries e
93 filterEntries p =
94 Tar.foldEntries
95 (\e es -> if p e then Tar.Next e es else es)
96 Tar.Done
97 Tar.Fail
99 filterEntriesM :: Monad m => (Tar.Entry -> m Bool)
100 -> Tar.Entries e -> m (Tar.Entries e)
101 filterEntriesM p =
102 Tar.foldEntries
103 (\entry rest -> do
104 keep <- p entry
105 xs <- rest
106 if keep
107 then return (Tar.Next entry xs)
108 else return xs)
109 (return Tar.Done)
110 (return . Tar.Fail)
112 entriesToList :: Exception e => Tar.Entries e -> [Tar.Entry]
113 entriesToList = Tar.foldEntries (:) [] throw