/interpreter/ghc/libraries/Cabal/Distribution/Simple/Program/HcPkg.hs

https://github.com/khskrede/mehh · Haskell · 277 lines · 189 code · 43 blank · 45 comment · 13 complexity · 96fe6afc42313f034e404553c16d4e23 MD5 · raw file

  1. -----------------------------------------------------------------------------
  2. -- |
  3. -- Module : Distribution.Simple.Program.HcPkg
  4. -- Copyright : Duncan Coutts 2009
  5. --
  6. -- Maintainer : cabal-devel@haskell.org
  7. -- Portability : portable
  8. --
  9. -- This module provides an library interface to the @hc-pkg@ program.
  10. -- Currently only GHC and LHC have hc-pkg programs.
  11. module Distribution.Simple.Program.HcPkg (
  12. register,
  13. reregister,
  14. unregister,
  15. expose,
  16. hide,
  17. dump,
  18. -- * Program invocations
  19. registerInvocation,
  20. reregisterInvocation,
  21. unregisterInvocation,
  22. exposeInvocation,
  23. hideInvocation,
  24. dumpInvocation,
  25. ) where
  26. import Distribution.Package
  27. ( PackageId, InstalledPackageId(..) )
  28. import Distribution.InstalledPackageInfo
  29. ( InstalledPackageInfo, InstalledPackageInfo_(..)
  30. , showInstalledPackageInfo, parseInstalledPackageInfo )
  31. import Distribution.ParseUtils
  32. ( ParseResult(..) )
  33. import Distribution.Simple.Compiler
  34. ( PackageDB(..), PackageDBStack )
  35. import Distribution.Simple.Program.Types
  36. ( ConfiguredProgram(programId, programVersion) )
  37. import Distribution.Simple.Program.Run
  38. ( ProgramInvocation(..), IOEncoding(..), programInvocation
  39. , runProgramInvocation, getProgramInvocationOutput )
  40. import Distribution.Version
  41. ( Version(..) )
  42. import Distribution.Text
  43. ( display )
  44. import Distribution.Simple.Utils
  45. ( die )
  46. import Distribution.Verbosity
  47. ( Verbosity, deafening, silent )
  48. import Distribution.Compat.Exception
  49. ( catchExit )
  50. import Data.Char
  51. ( isSpace )
  52. import Control.Monad
  53. ( liftM )
  54. -- | Call @hc-pkg@ to register a package.
  55. --
  56. -- > hc-pkg register {filename | -} [--user | --global | --package-conf]
  57. --
  58. register :: Verbosity -> ConfiguredProgram -> PackageDBStack
  59. -> Either FilePath
  60. InstalledPackageInfo
  61. -> IO ()
  62. register verbosity hcPkg packagedb pkgFile =
  63. runProgramInvocation verbosity
  64. (registerInvocation hcPkg verbosity packagedb pkgFile)
  65. -- | Call @hc-pkg@ to re-register a package.
  66. --
  67. -- > hc-pkg register {filename | -} [--user | --global | --package-conf]
  68. --
  69. reregister :: Verbosity -> ConfiguredProgram -> PackageDBStack
  70. -> Either FilePath
  71. InstalledPackageInfo
  72. -> IO ()
  73. reregister verbosity hcPkg packagedb pkgFile =
  74. runProgramInvocation verbosity
  75. (reregisterInvocation hcPkg verbosity packagedb pkgFile)
  76. -- | Call @hc-pkg@ to unregister a package
  77. --
  78. -- > hc-pkg unregister [pkgid] [--user | --global | --package-conf]
  79. --
  80. unregister :: Verbosity -> ConfiguredProgram -> PackageDB -> PackageId -> IO ()
  81. unregister verbosity hcPkg packagedb pkgid =
  82. runProgramInvocation verbosity
  83. (unregisterInvocation hcPkg verbosity packagedb pkgid)
  84. -- | Call @hc-pkg@ to expose a package.
  85. --
  86. -- > hc-pkg expose [pkgid] [--user | --global | --package-conf]
  87. --
  88. expose :: Verbosity -> ConfiguredProgram -> PackageDB -> PackageId -> IO ()
  89. expose verbosity hcPkg packagedb pkgid =
  90. runProgramInvocation verbosity
  91. (exposeInvocation hcPkg verbosity packagedb pkgid)
  92. -- | Call @hc-pkg@ to expose a package.
  93. --
  94. -- > hc-pkg expose [pkgid] [--user | --global | --package-conf]
  95. --
  96. hide :: Verbosity -> ConfiguredProgram -> PackageDB -> PackageId -> IO ()
  97. hide verbosity hcPkg packagedb pkgid =
  98. runProgramInvocation verbosity
  99. (hideInvocation hcPkg verbosity packagedb pkgid)
  100. -- | Call @hc-pkg@ to get all the installed packages.
  101. --
  102. dump :: Verbosity -> ConfiguredProgram -> PackageDB -> IO [InstalledPackageInfo]
  103. dump verbosity hcPkg packagedb = do
  104. output <- getProgramInvocationOutput verbosity
  105. (dumpInvocation hcPkg verbosity packagedb)
  106. `catchExit` \_ -> die $ programId hcPkg ++ " dump failed"
  107. case parsePackages output of
  108. Left ok -> return ok
  109. _ -> die $ "failed to parse output of '"
  110. ++ programId hcPkg ++ " dump'"
  111. where
  112. parsePackages str =
  113. let parse = liftM setInstalledPackageId . parseInstalledPackageInfo
  114. parsed = map parse (splitPkgs str)
  115. in case [ msg | ParseFailed msg <- parsed ] of
  116. [] -> Left [ pkg | ParseOk _ pkg <- parsed ]
  117. msgs -> Right msgs
  118. --TODO: this could be a lot faster. We're doing normaliseLineEndings twice
  119. -- and converting back and forth with lines/unlines.
  120. splitPkgs :: String -> [String]
  121. splitPkgs = checkEmpty . map unlines . splitWith ("---" ==) . lines
  122. where
  123. -- Handle the case of there being no packages at all.
  124. checkEmpty [s] | all isSpace s = []
  125. checkEmpty ss = ss
  126. splitWith :: (a -> Bool) -> [a] -> [[a]]
  127. splitWith p xs = ys : case zs of
  128. [] -> []
  129. _:ws -> splitWith p ws
  130. where (ys,zs) = break p xs
  131. -- Older installed package info files did not have the installedPackageId
  132. -- field, so if it is missing then we fill it as the source package ID.
  133. setInstalledPackageId :: InstalledPackageInfo -> InstalledPackageInfo
  134. setInstalledPackageId pkginfo@InstalledPackageInfo {
  135. installedPackageId = InstalledPackageId "",
  136. sourcePackageId = pkgid
  137. }
  138. = pkginfo {
  139. --TODO use a proper named function for the conversion
  140. -- from source package id to installed package id
  141. installedPackageId = InstalledPackageId (display pkgid)
  142. }
  143. setInstalledPackageId pkginfo = pkginfo
  144. --------------------------
  145. -- The program invocations
  146. --
  147. registerInvocation, reregisterInvocation
  148. :: ConfiguredProgram -> Verbosity -> PackageDBStack
  149. -> Either FilePath InstalledPackageInfo
  150. -> ProgramInvocation
  151. registerInvocation = registerInvocation' "register"
  152. reregisterInvocation = registerInvocation' "update"
  153. registerInvocation' :: String
  154. -> ConfiguredProgram -> Verbosity -> PackageDBStack
  155. -> Either FilePath InstalledPackageInfo
  156. -> ProgramInvocation
  157. registerInvocation' cmdname hcPkg verbosity packagedbs (Left pkgFile) =
  158. programInvocation hcPkg args
  159. where
  160. args = [cmdname, pkgFile]
  161. ++ (if legacyVersion hcPkg
  162. then [packageDbOpts (last packagedbs)]
  163. else packageDbStackOpts packagedbs)
  164. ++ verbosityOpts hcPkg verbosity
  165. registerInvocation' cmdname hcPkg verbosity packagedbs (Right pkgInfo) =
  166. (programInvocation hcPkg args) {
  167. progInvokeInput = Just (showInstalledPackageInfo pkgInfo),
  168. progInvokeInputEncoding = IOEncodingUTF8
  169. }
  170. where
  171. args = [cmdname, "-"]
  172. ++ (if legacyVersion hcPkg
  173. then [packageDbOpts (last packagedbs)]
  174. else packageDbStackOpts packagedbs)
  175. ++ verbosityOpts hcPkg verbosity
  176. unregisterInvocation :: ConfiguredProgram
  177. -> Verbosity -> PackageDB -> PackageId
  178. -> ProgramInvocation
  179. unregisterInvocation hcPkg verbosity packagedb pkgid =
  180. programInvocation hcPkg $
  181. ["unregister", packageDbOpts packagedb, display pkgid]
  182. ++ verbosityOpts hcPkg verbosity
  183. exposeInvocation :: ConfiguredProgram
  184. -> Verbosity -> PackageDB -> PackageId -> ProgramInvocation
  185. exposeInvocation hcPkg verbosity packagedb pkgid =
  186. programInvocation hcPkg $
  187. ["expose", packageDbOpts packagedb, display pkgid]
  188. ++ verbosityOpts hcPkg verbosity
  189. hideInvocation :: ConfiguredProgram
  190. -> Verbosity -> PackageDB -> PackageId -> ProgramInvocation
  191. hideInvocation hcPkg verbosity packagedb pkgid =
  192. programInvocation hcPkg $
  193. ["hide", packageDbOpts packagedb, display pkgid]
  194. ++ verbosityOpts hcPkg verbosity
  195. dumpInvocation :: ConfiguredProgram
  196. -> Verbosity -> PackageDB -> ProgramInvocation
  197. dumpInvocation hcPkg verbosity packagedb =
  198. (programInvocation hcPkg args) {
  199. progInvokeOutputEncoding = IOEncodingUTF8
  200. }
  201. where
  202. args = ["dump", packageDbOpts packagedb]
  203. ++ verbosityOpts hcPkg verbosity
  204. packageDbStackOpts :: PackageDBStack -> [String]
  205. packageDbStackOpts dbstack = case dbstack of
  206. (GlobalPackageDB:UserPackageDB:dbs) -> "--global"
  207. : "--user"
  208. : map specific dbs
  209. (GlobalPackageDB:dbs) -> "--global"
  210. : "--no-user-package-conf"
  211. : map specific dbs
  212. _ -> ierror
  213. where
  214. specific (SpecificPackageDB db) = "--package-conf=" ++ db
  215. specific _ = ierror
  216. ierror :: a
  217. ierror = error ("internal error: unexpected package db stack: " ++ show dbstack)
  218. packageDbOpts :: PackageDB -> String
  219. packageDbOpts GlobalPackageDB = "--global"
  220. packageDbOpts UserPackageDB = "--user"
  221. packageDbOpts (SpecificPackageDB db) = "--package-conf=" ++ db
  222. verbosityOpts :: ConfiguredProgram -> Verbosity -> [String]
  223. verbosityOpts hcPkg v
  224. -- ghc-pkg < 6.11 does not support -v
  225. | programId hcPkg == "ghc-pkg"
  226. && programVersion hcPkg < Just (Version [6,11] [])
  227. = []
  228. | v >= deafening = ["-v2"]
  229. | v == silent = ["-v0"]
  230. | otherwise = []
  231. -- Handle quirks in ghc-pkg 6.8 and older
  232. legacyVersion :: ConfiguredProgram -> Bool
  233. legacyVersion hcPkg = programId hcPkg == "ghc-pkg"
  234. && programVersion hcPkg < Just (Version [6,9] [])