1 {-# LANGUAGE OverloadedStrings #-}
3 -- | Utilities to implement cabal @v2-sdist@.
4 module Distribution
.Client
.SrcDist
5 ( allPackageSourceFiles
9 import Distribution
.Client
.Compat
.Prelude
12 import Control
.Monad
.State
.Lazy
(StateT
, evalStateT
, gets
, modify
)
13 import Control
.Monad
.Trans
(liftIO
)
14 import Control
.Monad
.Writer
.Lazy
(WriterT
, execWriterT
, tell
)
15 import System
.FilePath (normalise
, takeDirectory
, (</>))
17 import Distribution
.Client
.Utils
(tryFindAddSourcePackageDesc
)
18 import Distribution
.Package
(Package
(packageId
))
19 import Distribution
.PackageDescription
.Configuration
(flattenPackageDescription
)
20 import Distribution
.Simple
.PackageDescription
(readGenericPackageDescription
)
21 import Distribution
.Simple
.PreProcess
(knownSuffixHandlers
)
22 import Distribution
.Simple
.SrcDist
(listPackageSourcesWithDie
)
23 import Distribution
.Simple
.Utils
(dieWithException
)
24 import Distribution
.Types
.GenericPackageDescription
(GenericPackageDescription
)
26 import qualified Codec
.Archive
.Tar
as Tar
27 import qualified Codec
.Archive
.Tar
.Entry
as Tar
28 import qualified Codec
.Compression
.GZip
as GZip
29 import qualified Data
.ByteString
as BS
30 import qualified Data
.ByteString
.Lazy
as BSL
31 import qualified Data
.Set
as Set
32 import Distribution
.Client
.Errors
34 -- | List all source files of a given add-source dependency. Exits with error if
35 -- something is wrong (e.g. there is no .cabal file in the given directory).
37 -- Used in sandbox and projectbuilding.
38 -- TODO: when sandboxes are removed, move to ProjectBuilding.
39 allPackageSourceFiles
:: Verbosity
-> FilePath -> IO [FilePath]
40 allPackageSourceFiles verbosity packageDir
= do
42 let err
= "Error reading source files of package."
43 desc
<- tryFindAddSourcePackageDesc verbosity packageDir err
44 flattenPackageDescription `
fmap` readGenericPackageDescription verbosity desc
46 listPackageSourcesWithDie verbosity
(\_ _
-> return []) packageDir pd knownSuffixHandlers
48 -- | Create a tarball for a package in a directory
51 -> GenericPackageDescription
54 -- ^ directory containing that GPD
56 -- ^ resulting sdist tarball
57 packageDirToSdist verbosity gpd dir
= do
58 -- let thisDie :: Verbosity -> String -> IO a
59 -- thisDie v s = die' v $ "sdist of " <> prettyShow (packageId gpd) ++ ": " ++ s
61 files
' <- listPackageSourcesWithDie verbosity dieWithException dir
(flattenPackageDescription gpd
) knownSuffixHandlers
62 let files
:: [FilePath]
63 files
= nub $ sort $ map normalise files
'
65 let entriesM
:: StateT
(Set
.Set
FilePath) (WriterT
[Tar
.Entry
] IO) ()
67 let prefix
= prettyShow
(packageId gpd
)
68 modify
(Set
.insert prefix
)
69 case Tar
.toTarPath
True prefix
of
70 Left err
-> liftIO
$ dieWithException verbosity
$ ErrorPackingSdist err
71 Right path
-> tell
[Tar
.directoryEntry path
]
73 for_ files
$ \file
-> do
74 let fileDir
= takeDirectory
(prefix
</> file
)
75 needsEntry
<- gets
(Set
.notMember fileDir
)
78 modify
(Set
.insert fileDir
)
79 case Tar
.toTarPath
True fileDir
of
80 Left err
-> liftIO
$ dieWithException verbosity
$ ErrorPackingSdist err
81 Right path
-> tell
[Tar
.directoryEntry path
]
83 contents
<- liftIO
. fmap BSL
.fromStrict
. BS
.readFile $ dir
</> file
84 case Tar
.toTarPath
False (prefix
</> file
) of
85 Left err
-> liftIO
$ dieWithException verbosity
$ ErrorPackingSdist err
86 Right path
-> tell
[(Tar
.fileEntry path contents
){Tar
.entryPermissions
= Tar
.ordinaryFilePermissions
}]
88 entries
<- execWriterT
(evalStateT entriesM mempty
)
90 -- Pretend our GZip file is made on Unix.
91 normalize bs
= BSL
.concat [pfx
, "\x03", rest
']
93 (pfx
, rest
) = BSL
.splitAt 9 bs
95 -- The Unix epoch, which is the default value, is
96 -- unsuitable because it causes unpacking problems on
97 -- Windows; we need a post-1980 date. One gigasecond
98 -- after the epoch is during 2001-09-09, so that does
100 setModTime
:: Tar
.Entry
-> Tar
.Entry
101 setModTime entry
= entry
{Tar
.entryTime
= 1000000000}
102 return . normalize
. GZip
.compress
. Tar
.write
$ fmap setModTime entries