Skip to content

Commit 4f86aa9

Browse files
authored
hackage2nix: switch to json output (input-output-hk#79)
this decreases hackage.nix loading time by approximately 5x (to 0.3s), dropping my evaluation time from 8s to 6s in total
1 parent 820db7a commit 4f86aa9

File tree

2 files changed

+46
-32
lines changed

2 files changed

+46
-32
lines changed

hackage2nix/Main.hs

Lines changed: 43 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,14 @@
44
module Main where
55

66
import Cabal2Nix
7-
import Cabal2Nix.Util ( quoted )
87
import Control.Applicative ( liftA2 )
98
import Control.Monad.Trans.State.Strict
109
import Crypto.Hash.SHA256 ( hashlazy )
10+
import Data.Aeson
11+
import Data.Aeson.Types ( Pair )
12+
import Data.Aeson.Encode.Pretty
1113
import qualified Data.ByteString.Base16 as Base16
14+
import qualified Data.ByteString.Base64 as Base64
1215
import qualified Data.ByteString.Char8 as BS
1316
import qualified Data.ByteString.Lazy as BL
1417
import Data.Foldable ( toList
@@ -34,7 +37,6 @@ import Distribution.Pretty ( prettyShow
3437
)
3538
import Distribution.Types.PackageName ( PackageName )
3639
import Distribution.Types.Version ( Version )
37-
import Nix.Expr
3840
import Nix.Pretty ( prettyNix )
3941
import System.Directory ( createDirectoryIfMissing
4042
)
@@ -48,11 +50,23 @@ main = do
4850
[out] <- getArgs
4951
db <- U.readTarball Nothing =<< hackageTarball
5052

51-
let (defaultNix, cabalFiles) =
52-
runState (fmap seqToSet $ foldMapWithKeyA package2nix db) mempty
53-
53+
let (defaultJson, cabalFiles) =
54+
runState (fmap (object . toList . (Seq.sortOn fst)) $ foldMapWithKeyA package2json db) mempty
5455
createDirectoryIfMissing False out
55-
writeFile (out </> "default.nix") $ show $ prettyNix defaultNix
56+
BL.writeFile (out </> "default.nix") $
57+
"with builtins; mapAttrs (_: mapAttrs (_: data: rec {\n\
58+
\ inherit (data) sha256;\n\
59+
\ revisions = (mapAttrs (rev: rdata: {\n\
60+
\ inherit (rdata) revNum sha256;\n\
61+
\ outPath = ./. + \"/hackage/${rdata.outPath}\";\n\
62+
\ }) data.revisions) // {\n\
63+
\ default = revisions.\"${data.revisions.default}\";\n\
64+
\ };\n\
65+
\})) (fromJSON (readFile ./hackage.json))\n"
66+
67+
BL.writeFile (out </> "hackage.json") $ encodePretty'
68+
(defConfig {confCompare = compare, confIndent = Spaces 1})
69+
defaultJson
5670
createDirectoryIfMissing False (out </> "hackage")
5771

5872
for_ cabalFiles $ \(cabalFile, pname, path) -> do
@@ -73,51 +87,48 @@ foldMapWithKeyA
7387
foldMapWithKeyA f =
7488
unApplicativeMonoid . Map.foldMapWithKey (\k -> ApplicativeMonoid . f k)
7589

76-
seqToSet :: Seq (Binding NExpr) -> NExpr
77-
seqToSet = mkNonRecSet . toList
78-
7990
fromPretty :: (Pretty a, IsString b) => a -> b
8091
fromPretty = fromString . prettyShow
8192

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
93+
package2json :: PackageName -> U.PackageData -> GPDWriter (Seq Pair)
94+
package2json pname (U.PackageData { U.versions }) = do
95+
versionBindings <- foldMapWithKeyA (version2json pname) versions
96+
return $ Seq.singleton $ fromPretty pname .= (object . toList $ Seq.sortOn fst $ versionBindings)
8697

87-
version2nix
88-
:: PackageName -> Version -> U.VersionData -> GPDWriter (Seq (Binding NExpr))
89-
version2nix pname vnum (U.VersionData { U.cabalFileRevisions, U.metaFile }) =
98+
version2json
99+
:: PackageName -> Version -> U.VersionData -> GPDWriter (Seq (Pair))
100+
version2json pname vnum (U.VersionData { U.cabalFileRevisions, U.metaFile }) =
90101
do
91102
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))]
103+
$ zipWith (revBindingJson pname vnum) cabalFileRevisions [0 ..]
104+
let hash = decodeUtf8 $ Base64.encode $ fst $ Base16.decode $ fromString $ P.parseMetaData pname vnum metaFile Map.! "sha256"
105+
return $ Seq.singleton $ fromPretty vnum .= object
106+
[ "sha256" .= ("sha256-" <> hash)
107+
, "revisions" .= object
108+
( revisionBindings
109+
++ ["default" .= fst (last revisionBindings)]
99110
)
100111
]
101112

102-
revBinding
113+
revBindingJson
103114
:: PackageName
104115
-> Version
105116
-> BL.ByteString
106117
-> Integer
107-
-> GPDWriter (Text, NExpr)
108-
revBinding pname vnum cabalFile revNum = do
118+
-> GPDWriter (Text, Value)
119+
revBindingJson pname vnum cabalFile revNum = do
109120
let qualifiedName = mconcat $ intersperse
110121
"-"
111-
[prettyPname, fromPretty vnum, revName, BS.unpack cabalHash]
122+
[prettyPname, fromPretty vnum, revName, BS.unpack $ Base16.encode cabalHash]
112123
revName :: (Semigroup a, IsString a) => a
113124
revName = "r" <> fromString (show revNum)
114125
revPath = "." </> "hackage" </> qualifiedName <.> "nix"
115126
prettyPname = fromPretty pname
116-
cabalHash = Base16.encode $ hashlazy cabalFile
127+
cabalHash = hashlazy cabalFile
117128
modify' $ mappend $ Seq.singleton
118129
(cabalFile, prettyPname ++ ".cabal", revPath)
119-
return $ (,) revName $ mkNonRecSet
120-
[ "outPath" $= mkRelPath revPath
121-
, "revNum" $= mkInt revNum
122-
, "sha256" $= mkStr (decodeUtf8 cabalHash)
130+
return $ revName .= object
131+
[ "outPath" .= (qualifiedName <> ".nix")
132+
, "revNum" .= revNum
133+
, "sha256" .= ("sha256-" <> decodeUtf8 (Base64.encode cabalHash))
123134
]

nix-tools.cabal

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,11 +127,14 @@ executable hackage-to-nix
127127
, hackage-db
128128
, hnix
129129
, Cabal
130+
, aeson
131+
, aeson-pretty
130132
, containers
131133
, bytestring
132134
, text
133135
, cryptohash-sha256
134136
, base16-bytestring
137+
, base64-bytestring
135138
, filepath
136139
, directory
137140
, transformers

0 commit comments

Comments
 (0)