packages feed

cachix-0.2.0: src/Cachix/Client/NetRc.hs

-- Deals with adding private caches to netrc
module Cachix.Client.NetRc
  ( add
  ) where

import qualified Data.ByteString    as BS
import           Data.List            (nubBy)
import qualified Data.Text          as T
import           Network.NetRc
import           Protolude
import           System.Directory     ( doesFileExist )
import           Servant.Auth.Client  (getToken)

import qualified Cachix.Api as Api
import           Cachix.Api.Error     (escalateAs)
import           Cachix.Client.Config (Config, authToken)
import           Cachix.Client.Exception (CachixException(NetRcParseError))


-- | Add a list of binary caches to netrc under `filename`.
--   Makes sure there are no duplicate entries (using domain as a key).
--   If file under filename doesn't exist it's created.
add :: Config
    -> [Api.BinaryCache]
    -> FilePath
    -> IO ()
add config binarycaches filename = do
  doesExist <- doesFileExist filename
  netrc <- if doesExist
           then BS.readFile filename >>= parse
           else return $ NetRc [] []
  BS.writeFile filename $ netRcToByteString $ uniqueAppend netrc
  where
    parse :: ByteString -> IO NetRc
    parse contents = escalateAs (NetRcParseError . show) $ parseNetRc filename contents

    -- O(n^2) but who cares?
    uniqueAppend :: NetRc -> NetRc
    uniqueAppend (NetRc hosts macdefs) =
      let
        f :: NetRcHost -> NetRcHost -> Bool
        f x y = nrhName x == nrhName y
      in NetRc (nubBy f (new ++ hosts)) macdefs

    new :: [NetRcHost]
    new = map mkHost $ filter (not . Api.isPublic) binarycaches

    mkHost :: Api.BinaryCache -> NetRcHost
    mkHost bc = NetRcHost
      { nrhName = toS $ stripPrefix "http://" $ stripPrefix "https://" (Api.uri bc)
      , nrhLogin = ""
      , nrhPassword = getToken (authToken config)
      , nrhAccount = ""
      , nrhMacros = []
      }
      where
        -- stripPrefix that either strips or returns the same string
        stripPrefix :: Text -> Text -> Text
        stripPrefix prefix str =
          maybe str identity $ T.stripPrefix prefix str