Config.hs 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
  1. {-# LANGUAGE OverloadedStrings #-}
  2. {-# LANGUAGE RecordWildCards #-}
  3. module Config
  4. ( ConfigFile
  5. , readConfig
  6. , readProjectConfig
  7. , Ini.iniValueL
  8. ) where
  9. import Control.Monad (forM)
  10. import Data.Ini.Config.Bidir ((.=), (.=?), (&))
  11. import qualified Data.Ini.Config.Bidir as Ini
  12. import qualified Data.Text as T
  13. import qualified Data.Text.IO as T
  14. import Data.Monoid ((<>))
  15. import qualified Distribution.ParseUtils as Cabal
  16. import qualified System.Directory as Sys
  17. import System.FilePath ((</>))
  18. import qualified System.FilePath as Sys
  19. import qualified System.Exit as Sys
  20. import qualified System.Environment.XDG.BaseDir as Sys
  21. import Text.Read (readMaybe)
  22. import Types
  23. import Util
  24. type ConfigFile = Ini.Ini Config
  25. defaultConfig :: IO Config
  26. defaultConfig = do
  27. _configInstallPath <- Sys.getUserDataDir ("hatch" </> "install")
  28. let _configCurrentCompiler = Nothing
  29. return Config { .. }
  30. configSpec :: Ini.IniSpec Config ()
  31. configSpec = do
  32. Ini.section "hatch" $ do
  33. configInstallPath .= Ini.field "path" Ini.string
  34. & Ini.optional
  35. configCurrentCompiler .=? Ini.field "current" versionField
  36. versionField :: Ini.FieldValue Compiler
  37. versionField = Ini.FieldValue { .. }
  38. where
  39. fvParse t
  40. | Just ver <- T.stripPrefix "ghc-" t
  41. , [x,y,z] <- T.splitOn "." ver
  42. , Just x' <- readMaybe (T.unpack x)
  43. , Just y' <- readMaybe (T.unpack y)
  44. , Just z' <- readMaybe (T.unpack z)
  45. = Right (Compiler (x', y', z'))
  46. | otherwise = Left ("Bad GHC version: " ++ show t)
  47. fvEmit = T.pack . compilerString
  48. locateConfig :: FilePath -> IO (Maybe FilePath)
  49. locateConfig filename = do
  50. xdgLocs <- Sys.getAllConfigFiles "hatch" filename
  51. let confLocations = ["./" <> filename] ++
  52. xdgLocs ++
  53. ["/etc/hatch/" <> filename]
  54. results <- forM confLocations (\fp -> (,) fp <$> Sys.doesFileExist fp)
  55. case filter snd results of
  56. [] -> return Nothing
  57. ((fp, _):_) -> return (Just fp)
  58. readProjectConfig :: IO ([Cabal.Field])
  59. readProjectConfig = Sys.getCurrentDirectory >>= go
  60. where go "/" = return []
  61. go path = do
  62. exists <- Sys.doesFileExist (path </> ".hatch")
  63. if exists
  64. then do
  65. content <- readFile (path </> ".hatch")
  66. case Cabal.readFields content of
  67. Cabal.ParseOk _ rs -> return rs
  68. _ -> return []
  69. else go (Sys.takeDirectory path)
  70. readConfig :: IO (Ini.Ini Config)
  71. readConfig = do
  72. def <- defaultConfig
  73. let ini = Ini.ini def configSpec
  74. confLocation <- locateConfig "config.ini"
  75. print confLocation
  76. case confLocation of
  77. Nothing -> return ini
  78. Just fp -> do
  79. content <- T.readFile fp
  80. case Ini.parseIni content ini of
  81. Left err -> do
  82. printErr err
  83. Sys.die err
  84. Right x -> return x