3 module Main
(main
) where
5 import Control
.Monad
(when)
6 import Data
.Either (partitionEithers
)
7 import Data
.Foldable
(for_
, traverse_
)
8 import Data
.Maybe (listToMaybe)
9 import Data
.String (fromString
)
10 import Data
.Traversable
(for
)
11 import System
.Environment
(getArgs)
12 import System
.Exit
(exitFailure)
13 import System
.IO (hPutStrLn, stderr)
15 import qualified Data
.Text
as T
16 import qualified Cabal
.Index
as I
17 import qualified Cabal
.Plan
as P
18 import qualified Data
.Aeson
as A
19 import qualified Data
.ByteString
.Lazy
as LBS
20 import qualified Data
.Map
.Strict
as Map
21 import qualified Data
.Set
as Set
22 import qualified Distribution
.Types
.PackageName
as C
23 import qualified Distribution
.Types
.Version
as C
24 import qualified Topograph
as TG
26 -------------------------------------------------------------------------------
28 -------------------------------------------------------------------------------
35 _
-> die
"Usage: cabal-bootstrap-gen plan.json"
37 main1
:: FilePath -> IO ()
39 meta
<- getMap
<$> I
.cachedHackageMetadata
40 plan
<- P
.decodePlanJson planPath
43 #if MIN_VERSION_cabal_install_parsers
(0,4,0)
49 main2
:: Map
.Map C
.PackageName I
.PackageInfo
-> P
.PlanJson
-> IO ()
51 info
$ show $ Map
.keys
$ P
.pjUnits plan
53 -- find cabal-install:exe:cabal unit
54 (cabalUid
, cabalUnit
) <- case findCabalExe plan
of
56 Nothing
-> die
"Cannot find cabal-install:exe:cabal unit"
58 info
$ "cabal-install:exe:cabal unit " ++ show cabalUid
60 -- BFS from cabal unit, getting all dependencies
61 units
<- bfs plan cabalUnit
64 for_ units
$ \unit
-> do
65 info
$ " - " ++ show (P
.uId unit
)
67 (builtin
, deps
) <- fmap partitionEithers
$ for units
$ \unit
-> do
68 let P
.PkgId pkgname
@(P
.PkgName tpkgname
) ver
@(P
.Ver verdigits
) = P
.uPId unit
72 let cpkgname
:: C
.PackageName
73 cpkgname
= C
.mkPackageName
(T
.unpack tpkgname
)
75 let cversion
:: C
.Version
76 cversion
= C
.mkVersion verdigits
81 { builtinPackageName
= pkgname
82 , builtinVersion
= ver
86 (src
, rev
, revhash
) <- case P
.uSha256 unit
of
88 pkgInfo
<- maybe (die
$ "Cannot find " ++ show uid
++ " package metadata") return $
89 Map
.lookup cpkgname meta
90 relInfo
<- maybe (die
$ "Cannot find " ++ show uid
++ " version metadata") return $
91 Map
.lookup cversion
$ I
.piVersions pkgInfo
95 , Just
$ fromIntegral (I
.riRevision relInfo
)
96 , P
.sha256FromByteString
$ I
.getSHA256
$ I
.riCabal relInfo
99 Nothing
-> case P
.uType unit
of
100 P
.UnitTypeLocal
-> return (Local
, Nothing
, Nothing
)
101 t
-> die
$ "Unit of wrong type " ++ show uid
++ " " ++ show t
104 { depPackageName
= pkgname
107 , depSrcHash
= P
.uSha256 unit
109 , depRevHash
= revhash
111 [ (if fval
then "+" else "-") ++ T
.unpack fname
112 |
(P
.FlagName fname
, fval
) <- Map
.toList
(P
.uFlags unit
)
116 LBS
.putStr $ A
.encode Result
117 { resBuiltin
= builtin
118 , resDependencies
= deps
121 bfs
:: P
.PlanJson
-> P
.Unit
-> IO [P
.Unit
]
123 uids
<- either (\loop
-> die
$ "Loop in install-plan " ++ show loop
) id $ TG
.runG am
$ \g
-> do
124 v
<- maybe (die
"Cannot find cabal-install unit in topograph") return $
125 TG
.gToVertex g
$ P
.uId unit0
129 return $ map (TG
.gFromVertex g
) $
131 reverse $ Set
.toList
$ Set
.fromList
$ concat t
133 units
<- for uids
$ \uid
-> do
134 unit
<- lookupUnit
(P
.pjUnits plan
) uid
135 case Map
.toList
(P
.uComps unit
) of
136 [(_
, compinfo
)] -> checkExeDeps uid
(P
.pjUnits plan
) (P
.ciExeDeps compinfo
)
137 _
-> die
$ "Unit with multiple components " ++ show uid
140 -- Remove non-exe copies of cabal-install. Otherwise, cabal-install
141 -- may appear as cabal-install:lib before dependencies of
142 -- cabal-install:exe:cabal, and the bootstrap build tries to build
143 -- all of cabal-install before those dependencies.
144 return $ filter (\u
-> P
.uId u
== P
.uId unit0 || P
.uPId u
/= P
.uPId unit0
) units
146 am
:: Map
.Map P
.UnitId
(Set
.Set P
.UnitId
)
147 am
= fmap (foldMap P
.ciLibDeps
. P
.uComps
) (P
.pjUnits plan
)
149 checkExeDeps
:: P
.UnitId
-> Map
.Map P
.UnitId P
.Unit
-> Set
.Set P
.UnitId
-> IO ()
150 checkExeDeps pkgUid units
= traverse_ check
. Set
.toList
where
152 unit
<- lookupUnit units uid
153 let P
.PkgId pkgname _
= P
.uPId unit
154 when (pkgname
/= P
.PkgName
(fromString
"hsc2hs")) $ do
155 die
$ "unit " ++ show pkgUid
++ " depends on executable " ++ show uid
157 lookupUnit
:: Map
.Map P
.UnitId P
.Unit
-> P
.UnitId
-> IO P
.Unit
159 = maybe (die
$ "Cannot find unit " ++ show uid
) return
160 $ Map
.lookup uid units
162 -------------------------------------------------------------------------------
164 -------------------------------------------------------------------------------
167 { resBuiltin
:: [Builtin
]
168 , resDependencies
:: [Dep
]
172 data Builtin
= Builtin
173 { builtinPackageName
:: P
.PkgName
174 , builtinVersion
:: P
.Ver
179 { depPackageName
:: P
.PkgName
180 , depVersion
:: P
.Ver
181 , depSource
:: SrcType
182 , depSrcHash
:: Maybe P
.Sha256
183 , depRevision
:: Maybe Int
184 , depRevHash
:: Maybe P
.Sha256
185 , depFlags
:: [String]
194 instance A
.ToJSON Result
where
195 toJSON res
= A
.object
196 [ fromString
"builtin" A
..= resBuiltin res
197 , fromString
"dependencies" A
..= resDependencies res
200 instance A
.ToJSON Builtin
where
202 [ fromString
"package" A
..= builtinPackageName b
203 , fromString
"version" A
..= builtinVersion b
206 instance A
.ToJSON Dep
where
207 toJSON dep
= A
.object
208 [ fromString
"package" A
..= depPackageName dep
209 , fromString
"version" A
..= depVersion dep
210 , fromString
"source" A
..= depSource dep
211 , fromString
"src_sha256" A
..= depSrcHash dep
212 , fromString
"revision" A
..= depRevision dep
213 , fromString
"cabal_sha256" A
..= depRevHash dep
214 , fromString
"flags" A
..= depFlags dep
217 instance A
.ToJSON SrcType
where
218 toJSON Hackage
= fromString
"hackage"
219 toJSON Local
= fromString
"local"
221 -------------------------------------------------------------------------------
223 -------------------------------------------------------------------------------
225 -- | Log some debug information to stderr.
227 -- Disabled by default to keep the output tidy, replace by
228 -- the version with 'hPutStrLn' when debugging.
230 info
:: String -> IO ()
231 info _msg
= return ()
232 -- info msg = hPutStrLn stderr $ "INFO: " ++ msg
234 die
:: String -> IO a
239 -------------------------------------------------------------------------------
241 -------------------------------------------------------------------------------
243 findCabalExe
:: P
.PlanJson
-> Maybe (P
.UnitId
, P
.Unit
)
244 findCabalExe plan
= listToMaybe
246 |
(uid
, unit
) <- Map
.toList
(P
.pjUnits plan
)
247 , let P
.PkgId pkgname _
= P
.uPId unit
248 , pkgname
== P
.PkgName
(fromString
"cabal-install")
249 , Map
.keys
(P
.uComps unit
) == [P
.CompNameExe
(fromString
"cabal")]