2 {-# LANGUAGE ScopedTypeVariables #-}
3 {-# LANGUAGE LambdaCase #-}
4 {-# OPTIONS_GHC -Wno-deferred-out-of-scope-variables #-}
6 module Main
(main
) where
8 import Data
.Either (partitionEithers
)
9 import Data
.Foldable
(for_
)
10 import Data
.String (fromString
)
11 import Data
.Traversable
(for
)
12 import System
.Environment
(getArgs)
13 import System
.Exit
(exitFailure)
14 import System
.IO (hPutStrLn, stderr)
16 import qualified Data
.Text
as T
17 import qualified Cabal
.Index
as I
18 import qualified Cabal
.Plan
as P
19 import qualified Data
.Aeson
as A
20 import qualified Data
.ByteString
.Lazy
as LBS
21 import qualified Data
.Map
.Strict
as Map
22 import qualified Distribution
.Types
.PackageName
as C
23 import qualified Distribution
.Types
.Version
as C
24 import qualified Topograph
as TG
25 import Control
.Exception
26 import System
.IO.Error
(isDoesNotExistError)
28 -------------------------------------------------------------------------------
30 -------------------------------------------------------------------------------
38 (\e
-> if isDoesNotExistError e
then Just e
else Nothing
)
39 (\e
-> die
$ unlines ["~~~ ERROR ~~~", "", displayException e
, "", cabalDirWarning
])
41 _
-> die
"Usage: cabal-bootstrap-gen plan.json"
43 cabalDirWarning
:: String
48 "This script will look for cabal global config file in the following locations",
50 " - $CABAL_DIR/config",
51 " - $HOME/.cabal/config (on Unix-like systems)",
52 " - %APPDATA%/cabal (on Windows)",
54 "If you are using XDG paths or a entirely different location, you can set either",
55 "CABAL_CONFIG or CABAL_DIR to guide the script to the correct location.",
58 " $ CABAL_DIR=$HOME/.config/cabal cabal-bootstrap-gen"
61 main1
:: FilePath -> IO ()
63 meta
<- getMap
<$> I
.cachedHackageMetadata
64 plan
<- P
.decodePlanJson planPath
67 #if MIN_VERSION_cabal_install_parsers
(0,4,0)
73 main2
:: Map
.Map C
.PackageName I
.PackageInfo
-> P
.PlanJson
-> IO ()
75 info
$ show $ Map
.keys
$ P
.pjUnits plan
77 let res
= TG
.runG
(P
.planJsonIdGraph plan
) $ \g
->
78 map (TG
.gFromVertex g
) (reverse $ TG
.gVertices g
)
81 Left loop
-> die
$ "Loop in install-plan: " ++ show loop
82 Right uids
-> for uids
$ lookupUnit
(P
.pjUnits plan
)
85 for_ units
$ \unit
-> do
86 info
$ " - " ++ show (P
.uId unit
)
88 (builtin
, deps
) <- fmap partitionEithers
$ for units
$ \unit
-> do
89 let P
.PkgId pkgname
@(P
.PkgName tpkgname
) ver
@(P
.Ver verdigits
) = P
.uPId unit
91 let cpkgname
:: C
.PackageName
92 cpkgname
= C
.mkPackageName
(T
.unpack tpkgname
)
94 let cversion
:: C
.Version
95 cversion
= C
.mkVersion verdigits
97 let flags
= [ (if fval
then "+" else "-") ++ T
.unpack fname
98 |
(P
.FlagName fname
, fval
) <- Map
.toList
(P
.uFlags unit
)
100 let relInfo
= Map
.lookup cpkgname meta
>>= \pkgInfo
-> Map
.lookup cversion
$ I
.piVersions pkgInfo
103 return $ Left Builtin
104 { builtinPackageName
= pkgname
105 , builtinVersion
= ver
108 let component
= case Map
.keys
(P
.uComps unit
) of
109 [c
] -> Just
(P
.dispCompNameTarget pkgname c
)
113 case P
.uPkgSrc unit
of
114 Just
(P
.RepoTarballPackage
(P
.RepoSecure _uri
)) ->
116 Just
(P
.LocalUnpackedPackage _path
) ->
119 die
$ "package source not supported: " ++ show pkgsrc
122 { depPackageName
= pkgname
125 , depSrcHash
= P
.uSha256 unit
126 , depRevision
= fromIntegral . I
.riRevision
<$> relInfo
127 , depRevHash
= relInfo
>>= P
.sha256FromByteString
. I
.getSHA256
. getHash
129 , depComponent
= component
131 LBS
.putStr $ A
.encode Result
132 { resBuiltin
= builtin
133 , resDependencies
= deps
136 #if MIN_VERSION_cabal_install_parsers
(0,6,0)
137 getHash
= I
.riCabalHash
142 lookupUnit
:: Map
.Map P
.UnitId P
.Unit
-> P
.UnitId
-> IO P
.Unit
144 = maybe (die
$ "Cannot find unit " ++ show uid
) return
145 $ Map
.lookup uid units
147 -------------------------------------------------------------------------------
149 -------------------------------------------------------------------------------
152 { resBuiltin
:: [Builtin
]
153 , resDependencies
:: [Dep
]
157 data Builtin
= Builtin
158 { builtinPackageName
:: P
.PkgName
159 , builtinVersion
:: P
.Ver
164 { depPackageName
:: P
.PkgName
165 , depVersion
:: P
.Ver
166 , depSource
:: SrcType
167 , depSrcHash
:: Maybe P
.Sha256
168 , depRevision
:: Maybe Int
169 , depRevHash
:: Maybe P
.Sha256
170 , depFlags
:: [String]
171 , depComponent
:: Maybe T
.Text
180 instance A
.ToJSON Result
where
181 toJSON res
= A
.object
182 [ fromString
"builtin" A
..= resBuiltin res
183 , fromString
"dependencies" A
..= resDependencies res
186 instance A
.ToJSON Builtin
where
188 [ fromString
"package" A
..= builtinPackageName b
189 , fromString
"version" A
..= builtinVersion b
192 instance A
.ToJSON Dep
where
193 toJSON dep
= A
.object
194 [ fromString
"package" A
..= depPackageName dep
195 , fromString
"version" A
..= depVersion dep
196 , fromString
"source" A
..= depSource dep
197 , fromString
"src_sha256" A
..= depSrcHash dep
198 , fromString
"revision" A
..= depRevision dep
199 , fromString
"cabal_sha256" A
..= depRevHash dep
200 , fromString
"flags" A
..= depFlags dep
201 , fromString
"component" A
..= depComponent dep
204 instance A
.ToJSON SrcType
where
205 toJSON Hackage
= fromString
"hackage"
206 toJSON Local
= fromString
"local"
208 -------------------------------------------------------------------------------
210 -------------------------------------------------------------------------------
212 -- | Log some debug information to stderr.
214 -- Disabled by default to keep the output tidy, replace by
215 -- the version with 'hPutStrLn' when debugging.
217 info
:: String -> IO ()
218 info _msg
= return ()
219 -- info msg = hPutStrLn stderr $ "INFO: " ++ msg
221 die
:: String -> IO a