{-# 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 = (FilePath -> Builder)
-> (Text -> Builder) -> Derivation FilePath Text -> Builder
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 :: (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("
    Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<>  ((txt, DerivationOutput fp txt) -> Builder)
-> Map txt (DerivationOutput fp txt) -> Builder
forall k v. ((k, v) -> Builder) -> Map k v -> Builder
mapOf (txt, DerivationOutput fp txt) -> Builder
keyValue0 Map txt (DerivationOutput fp txt)
outputs
    Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<>  Builder
","
    Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<>  ((fp, Set txt) -> Builder) -> Map fp (Set txt) -> Builder
forall k v. ((k, v) -> Builder) -> Map k v -> Builder
mapOf (fp, Set txt) -> Builder
keyValue1 Map fp (Set txt)
inputDrvs
    Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<>  Builder
","
    Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<>  (fp -> Builder) -> Set fp -> Builder
forall a. (a -> Builder) -> Set a -> Builder
setOf fp -> Builder
filepath Set fp
inputSrcs
    Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<>  Builder
","
    Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<>  txt -> Builder
string txt
platform
    Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<>  Builder
","
    Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<>  txt -> Builder
string txt
builder
    Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<>  Builder
","
    Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<>  (txt -> Builder) -> Vector txt -> Builder
forall a. (a -> Builder) -> Vector a -> Builder
vectorOf txt -> Builder
string Vector txt
args
    Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<>  Builder
","
    Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<>  ((txt, txt) -> Builder) -> Map txt txt -> Builder
forall k v. ((k, v) -> Builder) -> Map k v -> Builder
mapOf (txt, txt) -> Builder
keyValue2 Map txt txt
env
    Builder -> Builder -> Builder
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
"("
        Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<>  txt -> Builder
string txt
key
        Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<>  Builder
","
        Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<>  fp -> Builder
filepath fp
path
        Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<>  Builder
","
        Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<>  txt -> Builder
string txt
hashAlgo
        Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<>  Builder
","
        Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<>  txt -> Builder
string txt
hash
        Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<>  Builder
")"

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

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

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

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

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

vectorOf :: (a -> Builder) -> Vector a -> Builder
vectorOf :: (a -> Builder) -> Vector a -> Builder
vectorOf a -> Builder
element Vector a
xs = (a -> Builder) -> [a] -> Builder
forall a. (a -> Builder) -> [a] -> Builder
listOf a -> Builder
element (Vector a -> [a]
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 (Text -> Builder) -> (Text -> Text) -> Text -> Builder
forall b c a. (b -> c) -> (a -> b) -> a -> c
. FilePath -> Text
Data.Text.pack (FilePath -> Text) -> (Text -> FilePath) -> Text -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> FilePath
forall a. Show a => a -> FilePath
show

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