packages feed

kit-0.6: Kit/Repository.hs

module Kit.Repository (
    getKit,
    getKitSpec,
    webRepo,
    fileRepo,
    KitRepository
  ) where

  import Kit.Spec
  import Kit.Util

  import Network.BufferType
  import Network.HTTP
  import Network.URI
  import Control.Monad.Error
  import Data.Maybe
  import qualified Data.List as L
  import qualified Data.Traversable as T
  import qualified Data.ByteString as BS

  data KitRepository = KitRepository {
    repoSave :: String -> FilePath -> IO (Maybe ()),
    repoRead :: String -> IO (Maybe BS.ByteString)
  }

  getKit :: KitRepository -> Kit -> FilePath -> IO (Maybe ())
  getKit kr k = repoSave kr (kitPackagePath k)

  getKitSpec :: KitRepository -> Kit -> KitIO KitSpec
  getKitSpec kr k = do
    mbKitStuff <- liftIO $ repoRead kr (kitSpecPath k)
    maybe (throwError $ "Missing " ++ packageFileName k) f mbKitStuff
    where f contents = maybeToKitIO ("Invalid KitSpec file for " ++ packageFileName k) $ decodeSpec contents

  -- TODO: Use the base url!
  webRepo :: String -> KitRepository
  webRepo _ = KitRepository save doRead where
    save = download
    doRead = getBody

  fileRepo :: String -> KitRepository
  fileRepo baseDir = KitRepository save doRead where
    save src destPath = Just <$> copyFile (baseDir </> src) destPath
    doRead fp = let file = (baseDir </> fp) in do
      exists <- doesFileExist file
      T.sequenceA $ justTrue exists $ BS.readFile file

  -- private!
  baseKitPath :: Kit -> String
  baseKitPath k = joinS ["kits", kitName k, kitVersion k] "/"
    where joinS xs x = foldl1 (++) $ L.intersperse x xs

  kitPackagePath, kitSpecPath :: Kit -> String

  kitPackagePath k = baseKitPath k ++ "/" ++ packageFileName k ++ ".tar.gz"
  kitSpecPath k = baseKitPath k ++ "/" ++ "KitSpec"

  getBody :: BufferType a => HStream a => String -> IO (Maybe a)
  getBody p = let
      request = defaultGETRequest_ . fromJust . parseURI
      leftMaybe = either (const Nothing) Just
    in do
      rr <- Network.HTTP.simpleHTTP $ request p 
      return $ fmap rspBody $ leftMaybe rr

  download :: String -> FilePath -> IO (Maybe ())
  download url destination = do
      body <- getBody url
      T.sequenceA $ fmap (BS.writeFile destination) body