{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RecordWildCards   #-}

-- | Rendering logic

module Nix.Derivation.Builder
    ( -- * Builder
      buildDerivation
    , buildDerivationWith
    ) where

import Data.Map (Map)
import Data.Set (Set)
import Data.Text (Text)
import Data.Text.Lazy.Builder (Builder)
import Data.Vector (Vector)
import Nix.Derivation.Types (Derivation(..), DerivationOutput(..))

import qualified Data.Map
import qualified Data.Set
import qualified Data.Text
import qualified Data.Text.Lazy.Builder
import qualified Data.Vector

-- | Render a derivation as a `Builder`
buildDerivation :: Derivation FilePath Text -> Builder
buildDerivation :: Derivation FilePath Text -> Builder
buildDerivation = forall fp txt.
(fp -> Builder) -> (txt -> Builder) -> Derivation fp txt -> Builder
buildDerivationWith FilePath -> Builder
filepath' Text -> Builder
string'

-- | Render a derivation as a `Builder` using custom
-- renderer for filepath and string
buildDerivationWith :: (fp -> Builder)
                    -> (txt -> Builder)
                    -> Derivation fp txt
                    -> Builder
buildDerivationWith :: forall fp txt.
(fp -> Builder) -> (txt -> Builder) -> Derivation fp txt -> Builder
buildDerivationWith fp -> Builder
filepath txt -> Builder
string (Derivation {txt
Map fp (Set txt)
Map txt txt
Map txt (DerivationOutput fp txt)
Set fp
Vector txt
env :: forall fp txt. Derivation fp txt -> Map txt txt
args :: forall fp txt. Derivation fp txt -> Vector txt
builder :: forall fp txt. Derivation fp txt -> txt
platform :: forall fp txt. Derivation fp txt -> txt
inputSrcs :: forall fp txt. Derivation fp txt -> Set fp
inputDrvs :: forall fp txt. Derivation fp txt -> Map fp (Set txt)
outputs :: forall fp txt.
Derivation fp txt -> Map txt (DerivationOutput fp txt)
env :: Map txt txt
args :: Vector txt
builder :: txt
platform :: txt
inputSrcs :: Set fp
inputDrvs :: Map fp (Set txt)
outputs :: Map txt (DerivationOutput fp txt)
..}) =
        Builder
"Derive("
    forall a. Semigroup a => a -> a -> a
<>  forall k v. ((k, v) -> Builder) -> Map k v -> Builder
mapOf (txt, DerivationOutput fp txt) -> Builder
keyValue0 Map txt (DerivationOutput fp txt)
outputs
    forall a. Semigroup a => a -> a -> a
<>  Builder
","
    forall a. Semigroup a => a -> a -> a
<>  forall k v. ((k, v) -> Builder) -> Map k v -> Builder
mapOf (fp, Set txt) -> Builder
keyValue1 Map fp (Set txt)
inputDrvs
    forall a. Semigroup a => a -> a -> a
<>  Builder
","
    forall a. Semigroup a => a -> a -> a
<>  forall a. (a -> Builder) -> Set a -> Builder
setOf fp -> Builder
filepath Set fp
inputSrcs
    forall a. Semigroup a => a -> a -> a
<>  Builder
","
    forall a. Semigroup a => a -> a -> a
<>  txt -> Builder
string txt
platform
    forall a. Semigroup a => a -> a -> a
<>  Builder
","
    forall a. Semigroup a => a -> a -> a
<>  txt -> Builder
string txt
builder
    forall a. Semigroup a => a -> a -> a
<>  Builder
","
    forall a. Semigroup a => a -> a -> a
<>  forall a. (a -> Builder) -> Vector a -> Builder
vectorOf txt -> Builder
string Vector txt
args
    forall a. Semigroup a => a -> a -> a
<>  Builder
","
    forall a. Semigroup a => a -> a -> a
<>  forall k v. ((k, v) -> Builder) -> Map k v -> Builder
mapOf (txt, txt) -> Builder
keyValue2 Map txt txt
env
    forall a. Semigroup a => a -> a -> a
<>  Builder
")"
  where
    keyValue0 :: (txt, DerivationOutput fp txt) -> Builder
keyValue0 (txt
key, DerivationOutput {fp
txt
hash :: forall fp txt. DerivationOutput fp txt -> txt
hashAlgo :: forall fp txt. DerivationOutput fp txt -> txt
path :: forall fp txt. DerivationOutput fp txt -> fp
hash :: txt
hashAlgo :: txt
path :: fp
..}) =
            Builder
"("
        forall a. Semigroup a => a -> a -> a
<>  txt -> Builder
string txt
key
        forall a. Semigroup a => a -> a -> a
<>  Builder
","
        forall a. Semigroup a => a -> a -> a
<>  fp -> Builder
filepath fp
path
        forall a. Semigroup a => a -> a -> a
<>  Builder
","
        forall a. Semigroup a => a -> a -> a
<>  txt -> Builder
string txt
hashAlgo
        forall a. Semigroup a => a -> a -> a
<>  Builder
","
        forall a. Semigroup a => a -> a -> a
<>  txt -> Builder
string txt
hash
        forall a. Semigroup a => a -> a -> a
<>  Builder
")"

    keyValue1 :: (fp, Set txt) -> Builder
keyValue1 (fp
key, Set txt
value) =
            Builder
"("
        forall a. Semigroup a => a -> a -> a
<>  fp -> Builder
filepath fp
key
        forall a. Semigroup a => a -> a -> a
<>  Builder
","
        forall a. Semigroup a => a -> a -> a
<>  forall a. (a -> Builder) -> Set a -> Builder
setOf txt -> Builder
string Set txt
value
        forall a. Semigroup a => a -> a -> a
<>  Builder
")"

    keyValue2 :: (txt, txt) -> Builder
keyValue2 (txt
key, txt
value) =
            Builder
"("
        forall a. Semigroup a => a -> a -> a
<>  txt -> Builder
string txt
key
        forall a. Semigroup a => a -> a -> a
<>  Builder
","
        forall a. Semigroup a => a -> a -> a
<>  txt -> Builder
string txt
value
        forall a. Semigroup a => a -> a -> a
<>  Builder
")"

mapOf :: ((k, v) -> Builder) -> Map k v -> Builder
mapOf :: forall k v. ((k, v) -> Builder) -> Map k v -> Builder
mapOf (k, v) -> Builder
keyValue Map k v
m = forall a. (a -> Builder) -> [a] -> Builder
listOf (k, v) -> Builder
keyValue (forall k a. Map k a -> [(k, a)]
Data.Map.toList Map k v
m)

listOf :: (a -> Builder) -> [a] -> Builder
listOf :: forall a. (a -> Builder) -> [a] -> Builder
listOf a -> Builder
_          []  = Builder
"[]"
listOf a -> Builder
element (a
x:[a]
xs) =
        Builder
"[" 
    forall a. Semigroup a => a -> a -> a
<>  a -> Builder
element a
x
    forall a. Semigroup a => a -> a -> a
<>  forall (t :: * -> *) m a.
(Foldable t, Monoid m) =>
(a -> m) -> t a -> m
foldMap a -> Builder
rest [a]
xs
    forall a. Semigroup a => a -> a -> a
<>  Builder
"]"
  where
    rest :: a -> Builder
rest a
y = Builder
"," forall a. Semigroup a => a -> a -> a
<> a -> Builder
element a
y

setOf :: (a -> Builder) -> Set a -> Builder
setOf :: forall a. (a -> Builder) -> Set a -> Builder
setOf a -> Builder
element Set a
xs = forall a. (a -> Builder) -> [a] -> Builder
listOf a -> Builder
element (forall a. Set a -> [a]
Data.Set.toList Set a
xs)

vectorOf :: (a -> Builder) -> Vector a -> Builder
vectorOf :: forall a. (a -> Builder) -> Vector a -> Builder
vectorOf a -> Builder
element Vector a
xs = forall a. (a -> Builder) -> [a] -> Builder
listOf a -> Builder
element (forall a. Vector a -> [a]
Data.Vector.toList Vector a
xs)

string' :: Text -> Builder
string' :: Text -> Builder
string' = Text -> Builder
Data.Text.Lazy.Builder.fromText forall b c a. (b -> c) -> (a -> b) -> a -> c
. FilePath -> Text
Data.Text.pack forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Show a => a -> FilePath
show

filepath' :: FilePath -> Builder
filepath' :: FilePath -> Builder
filepath' FilePath
p = Text -> Builder
string' forall a b. (a -> b) -> a -> b
$ FilePath -> Text
Data.Text.pack FilePath
p