1
1
{-# LANGUAGE OverloadedStrings #-}
2
2
{-# LANGUAGE NamedFieldPuns #-}
3
3
4
- module Main
5
- where
4
+ module Main where
6
5
7
6
import Cabal2Nix
8
7
import Cabal2Nix.Util ( quoted )
9
- import Crypto.Hash.SHA256 ( hash
10
- , hashlazy
11
- )
8
+ import Control.Applicative ( liftA2 )
9
+ import Control.Monad.Trans.State.Strict
10
+ import Crypto.Hash.SHA256 ( hashlazy )
12
11
import qualified Data.ByteString.Base16 as Base16
13
12
import qualified Data.ByteString.Char8 as BS
14
13
import qualified Data.ByteString.Lazy as BL
15
- import Data.Foldable ( toList )
14
+ import Data.Foldable ( toList
15
+ , for_
16
+ )
17
+ import Data.List ( intersperse )
18
+ import Data.Map ( Map )
16
19
import qualified Data.Map as Map
20
+ import Data.Semigroup as Sem
21
+ import Data.Sequence ( Seq )
17
22
import qualified Data.Sequence as Seq
18
- import Data.String ( IsString (fromString ) )
23
+ import Data.String ( IsString (fromString )
24
+ )
25
+ import Data.Text ( Text )
19
26
import Data.Text.Encoding ( decodeUtf8 )
20
27
import Distribution.Hackage.DB ( hackageTarball )
21
28
import qualified Distribution.Hackage.DB.Parsed
22
29
as P
23
- import Distribution.Hackage.DB.Parsed ( parseMetaData
24
- , parseVersionData
25
- )
26
- import Distribution.Hackage.DB.Unparsed
30
+ import qualified Distribution.Hackage.DB.Unparsed
31
+ as U
27
32
import Distribution.Pretty ( prettyShow
28
33
, Pretty
29
34
)
35
+ import Distribution.Types.PackageName ( PackageName )
36
+ import Distribution.Types.Version ( Version )
30
37
import Nix.Expr
31
38
import Nix.Pretty ( prettyNix )
32
- import System.Directory ( createDirectoryIfMissing )
39
+ import System.Directory ( createDirectoryIfMissing
40
+ )
33
41
import System.Environment ( getArgs )
34
42
import System.FilePath ( (</>)
35
43
, (<.>)
@@ -38,50 +46,78 @@ import System.FilePath ( (</>)
38
46
main :: IO ()
39
47
main = do
40
48
[out] <- getArgs
41
- db <- readTarball Nothing =<< hackageTarball
49
+ db <- U. readTarball Nothing =<< hackageTarball
50
+
51
+ let (defaultNix, cabalFiles) =
52
+ runState (fmap seqToSet $ foldMapWithKeyA package2nix db) mempty
42
53
43
- let defaultNix = seqToSet $ Map. foldMapWithKey package2nix db
44
54
createDirectoryIfMissing False out
45
55
writeFile (out </> " default.nix" ) $ show $ prettyNix defaultNix
56
+ createDirectoryIfMissing False (out </> " hackage" )
57
+
58
+ for_ cabalFiles $ \ (cabalFile, pname, path) -> do
59
+ gpd <- cabal2nix Nothing $ InMemory Nothing pname $ BL. toStrict cabalFile
60
+ writeFile (out </> path) $ show $ prettyNix gpd
61
+
62
+ type GPDWriter = State (Seq (BL. ByteString , String , FilePath ))
63
+
64
+ newtype ApplicativeMonoid f a = ApplicativeMonoid { unApplicativeMonoid :: f a }
65
+ instance (Applicative f , Semigroup a ) => Sem. Semigroup (ApplicativeMonoid f a ) where
66
+ ApplicativeMonoid a <> ApplicativeMonoid b = ApplicativeMonoid $ liftA2 (Sem. <>) a b
67
+ instance (Applicative f , Monoid a ) => Monoid (ApplicativeMonoid f a ) where
68
+ mempty = ApplicativeMonoid $ pure mempty
69
+ mappend = (Sem. <>)
70
+
71
+ foldMapWithKeyA
72
+ :: (Applicative f , Monoid b ) => (k -> a -> f b ) -> Map k a -> f b
73
+ foldMapWithKeyA f =
74
+ unApplicativeMonoid . Map. foldMapWithKey (\ k -> ApplicativeMonoid . f k)
75
+
76
+ seqToSet :: Seq (Binding NExpr ) -> NExpr
77
+ seqToSet = mkNonRecSet . toList
78
+
79
+ fromPretty :: (Pretty a , IsString b ) => a -> b
80
+ fromPretty = fromString . prettyShow
81
+
82
+ package2nix :: PackageName -> U. PackageData -> GPDWriter (Seq (Binding NExpr ))
83
+ package2nix pname (U. PackageData { U. versions }) = do
84
+ versionBindings <- foldMapWithKeyA (version2nix pname) versions
85
+ return $ Seq. singleton $ quoted (fromPretty pname) $= seqToSet versionBindings
86
+
87
+ version2nix
88
+ :: PackageName -> Version -> U. VersionData -> GPDWriter (Seq (Binding NExpr ))
89
+ version2nix pname vnum (U. VersionData { U. cabalFileRevisions, U. metaFile }) =
90
+ do
91
+ revisionBindings <- sequenceA
92
+ $ zipWith (revBinding pname vnum) cabalFileRevisions [0 .. ]
93
+ return $ Seq. singleton $ quoted (fromPretty vnum) $= mkRecSet
94
+ [ " sha256" $= mkStr
95
+ (fromString $ P. parseMetaData pname vnum metaFile Map. ! " sha256" )
96
+ , " revisions" $= mkNonRecSet
97
+ ( fmap (uncurry ($=) ) revisionBindings
98
+ ++ [" default" $= (mkSym " revisions" @. fst (last revisionBindings))]
99
+ )
100
+ ]
46
101
47
- _ <- forWithKey db $ \ pname (PackageData { versions }) ->
48
- forWithKey versions $ \ vnum vdata@ (VersionData { cabalFileRevisions }) ->
49
- let parsedVData = parseVersionData pname vnum vdata
50
- writeFiles gpd cabalFile revNum = do
51
- let dir = out </> packagePath pname </> fromPretty vnum
52
- revPath = dir </> revName revNum
53
- createDirectoryIfMissing True dir
54
- BL. writeFile (revPath <.> " cabal" ) cabalFile
55
- writeFile (revPath <.> " nix" ) $ show $ prettyNix $ gpd2nix Nothing Nothing gpd
56
- in sequence $ zipWith3 writeFiles
57
- (toList (P. cabalFileRevisions parsedVData))
58
- cabalFileRevisions
59
- [(0 :: Int ) .. ]
60
- return ()
61
- where
62
- forWithKey :: Applicative f => Map. Map k v -> (k -> v -> f x ) -> f (Map. Map k x )
63
- forWithKey = flip Map. traverseWithKey
64
- seqToSet = mkNonRecSet . toList
65
- fromPretty :: (Pretty a , IsString b ) => a -> b
66
- fromPretty = fromString . prettyShow
67
- package2nix pname (PackageData { versions }) =
68
- Seq. singleton $ quoted (fromPretty pname) $= seqToSet
69
- (Map. foldMapWithKey (version2nix pname) versions)
70
- version2nix pname vnum (VersionData { cabalFileRevisions, metaFile }) =
71
- Seq. singleton $ quoted (fromPretty vnum) $= mkRecSet
72
- ( (" revision" $= mkSym (revName $ length cabalFileRevisions - 1 ))
73
- : (" sha256" $= mkStr (fromString $ parseMetaData pname vnum metaFile Map. ! " sha256" ))
74
- : zipWith (revBinding (packagePath pname) vnum) cabalFileRevisions [(0 :: Int ) .. ]
75
- )
76
- revName revNum = " r" <> fromString (show revNum)
77
- revBinding ppath vnum cabalFile revNum =
78
- let name :: (IsString a , Semigroup a ) => a
79
- name = revName revNum
80
- revPath = " ." </> ppath </> fromPretty vnum </> name
81
- in name $= mkNonRecSet
82
- [ " outPath" $= mkRelPath (revPath <.> " nix" )
83
- , " cabalFile" $= mkRelPath (revPath <.> " cabal" )
84
- , " cabalSha256" $= mkStr (decodeUtf8 $ Base16. encode $ hashlazy cabalFile)
85
- ]
86
- packagePath pname =
87
- BS. unpack (BS. take 30 $ Base16. encode $ hash $ fromPretty pname) ++ " -" ++ fromPretty pname
102
+ revBinding
103
+ :: PackageName
104
+ -> Version
105
+ -> BL. ByteString
106
+ -> Integer
107
+ -> GPDWriter (Text , NExpr )
108
+ revBinding pname vnum cabalFile revNum = do
109
+ let qualifiedName = mconcat $ intersperse
110
+ " -"
111
+ [prettyPname, fromPretty vnum, revName, BS. unpack cabalHash]
112
+ revName :: (Semigroup a , IsString a ) => a
113
+ revName = " r" <> fromString (show revNum)
114
+ revPath = " ." </> " hackage" </> qualifiedName <.> " nix"
115
+ prettyPname = fromPretty pname
116
+ cabalHash = Base16. encode $ hashlazy cabalFile
117
+ modify' $ mappend $ Seq. singleton
118
+ (cabalFile, prettyPname ++ " .cabal" , revPath)
119
+ return $ (,) revName $ mkNonRecSet
120
+ [ " outPath" $= mkRelPath revPath
121
+ , " revNum" $= mkInt revNum
122
+ , " sha256" $= mkStr (decodeUtf8 cabalHash)
123
+ ]
0 commit comments