{-# LANGUAGE DeriveFunctor #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}

{- (Very limited) parser, rendered and modifier of nix.conf

Supports subset of nix.conf given Nix 2.0 or Nix 1.0

When reading config files, it normalizes Nix 1.0/2.0 names to unified naming,
then when it writes the config back, it uses naming depending what given Nix
version considers as recommended.

-}
module Cachix.Client.NixConf
  ( NixConf,
    NixConfG (..),
    NixConfLine (..),
    NixConfLoc (..),
    render,
    add,
    read,
    update,
    write,
    getFilename,
    parser,
    parse,
    readLines,
    writeLines,
    isTrustedUsers,
    defaultPublicURI,
    defaultSigningKey,
    setNetRC,
  )
where

import qualified Cachix.Api as Api
import Data.Char (isSpace)
import Data.List (nub)
import qualified Data.Text as T
import Protolude
import System.Directory
  ( XdgDirectory (..),
    createDirectoryIfMissing,
    doesFileExist,
    getXdgDirectory,
  )
import System.FilePath.Posix (takeDirectory)
import qualified Text.Megaparsec as Mega
import Text.Megaparsec.Char

data NixConfLine
  = Substituters [Text]
  | TrustedUsers [Text]
  | TrustedPublicKeys [Text]
  | NetRcFile Text
  | Other Text
  deriving (Int -> NixConfLine -> ShowS
[NixConfLine] -> ShowS
NixConfLine -> String
(Int -> NixConfLine -> ShowS)
-> (NixConfLine -> String)
-> ([NixConfLine] -> ShowS)
-> Show NixConfLine
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [NixConfLine] -> ShowS
$cshowList :: [NixConfLine] -> ShowS
show :: NixConfLine -> String
$cshow :: NixConfLine -> String
showsPrec :: Int -> NixConfLine -> ShowS
$cshowsPrec :: Int -> NixConfLine -> ShowS
Show, NixConfLine -> NixConfLine -> Bool
(NixConfLine -> NixConfLine -> Bool)
-> (NixConfLine -> NixConfLine -> Bool) -> Eq NixConfLine
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: NixConfLine -> NixConfLine -> Bool
$c/= :: NixConfLine -> NixConfLine -> Bool
== :: NixConfLine -> NixConfLine -> Bool
$c== :: NixConfLine -> NixConfLine -> Bool
Eq)

newtype NixConfG a = NixConf a
  deriving (Int -> NixConfG a -> ShowS
[NixConfG a] -> ShowS
NixConfG a -> String
(Int -> NixConfG a -> ShowS)
-> (NixConfG a -> String)
-> ([NixConfG a] -> ShowS)
-> Show (NixConfG a)
forall a. Show a => Int -> NixConfG a -> ShowS
forall a. Show a => [NixConfG a] -> ShowS
forall a. Show a => NixConfG a -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [NixConfG a] -> ShowS
$cshowList :: forall a. Show a => [NixConfG a] -> ShowS
show :: NixConfG a -> String
$cshow :: forall a. Show a => NixConfG a -> String
showsPrec :: Int -> NixConfG a -> ShowS
$cshowsPrec :: forall a. Show a => Int -> NixConfG a -> ShowS
Show, NixConfG a -> NixConfG a -> Bool
(NixConfG a -> NixConfG a -> Bool)
-> (NixConfG a -> NixConfG a -> Bool) -> Eq (NixConfG a)
forall a. Eq a => NixConfG a -> NixConfG a -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: NixConfG a -> NixConfG a -> Bool
$c/= :: forall a. Eq a => NixConfG a -> NixConfG a -> Bool
== :: NixConfG a -> NixConfG a -> Bool
$c== :: forall a. Eq a => NixConfG a -> NixConfG a -> Bool
Eq, a -> NixConfG b -> NixConfG a
(a -> b) -> NixConfG a -> NixConfG b
(forall a b. (a -> b) -> NixConfG a -> NixConfG b)
-> (forall a b. a -> NixConfG b -> NixConfG a) -> Functor NixConfG
forall a b. a -> NixConfG b -> NixConfG a
forall a b. (a -> b) -> NixConfG a -> NixConfG b
forall (f :: * -> *).
(forall a b. (a -> b) -> f a -> f b)
-> (forall a b. a -> f b -> f a) -> Functor f
<$ :: a -> NixConfG b -> NixConfG a
$c<$ :: forall a b. a -> NixConfG b -> NixConfG a
fmap :: (a -> b) -> NixConfG a -> NixConfG b
$cfmap :: forall a b. (a -> b) -> NixConfG a -> NixConfG b
Functor)

type NixConf = NixConfG [NixConfLine]

readLines :: [NixConf] -> (NixConfLine -> Maybe [Text]) -> [Text]
readLines :: [NixConf] -> (NixConfLine -> Maybe [Text]) -> [Text]
readLines nixconfs :: [NixConf]
nixconfs predicate :: NixConfLine -> Maybe [Text]
predicate = (NixConf -> [Text]) -> [NixConf] -> [Text]
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap NixConf -> [Text]
forall (t :: * -> *).
Foldable t =>
NixConfG (t NixConfLine) -> [Text]
f [NixConf]
nixconfs
  where
    f :: NixConfG (t NixConfLine) -> [Text]
f (NixConf xs :: t NixConfLine
xs) = ([Text] -> NixConfLine -> [Text])
-> [Text] -> t NixConfLine -> [Text]
forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
foldl [Text] -> NixConfLine -> [Text]
foldIt [] t NixConfLine
xs
    foldIt :: [Text] -> NixConfLine -> [Text]
    foldIt :: [Text] -> NixConfLine -> [Text]
foldIt prev :: [Text]
prev new :: NixConfLine
new = [Text]
prev [Text] -> [Text] -> [Text]
forall a. Semigroup a => a -> a -> a
<> [Text] -> Maybe [Text] -> [Text]
forall a. a -> Maybe a -> a
fromMaybe [] (NixConfLine -> Maybe [Text]
predicate NixConfLine
new)

writeLines :: (NixConfLine -> Maybe [Text]) -> NixConfLine -> NixConf -> NixConf
writeLines :: (NixConfLine -> Maybe [Text]) -> NixConfLine -> NixConf -> NixConf
writeLines predicate :: NixConfLine -> Maybe [Text]
predicate addition :: NixConfLine
addition = ([NixConfLine] -> [NixConfLine]) -> NixConf -> NixConf
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap [NixConfLine] -> [NixConfLine]
f
  where
    f :: [NixConfLine] -> [NixConfLine]
f x :: [NixConfLine]
x = (NixConfLine -> Bool) -> [NixConfLine] -> [NixConfLine]
forall a. (a -> Bool) -> [a] -> [a]
filter (Maybe [Text] -> Bool
forall a. Maybe a -> Bool
isNothing (Maybe [Text] -> Bool)
-> (NixConfLine -> Maybe [Text]) -> NixConfLine -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. NixConfLine -> Maybe [Text]
predicate) [NixConfLine]
x [NixConfLine] -> [NixConfLine] -> [NixConfLine]
forall a. Semigroup a => a -> a -> a
<> [NixConfLine
addition]

isSubstituter :: NixConfLine -> Maybe [Text]
isSubstituter :: NixConfLine -> Maybe [Text]
isSubstituter (Substituters xs :: [Text]
xs) = [Text] -> Maybe [Text]
forall a. a -> Maybe a
Just [Text]
xs
isSubstituter _ = Maybe [Text]
forall a. Maybe a
Nothing

isPublicKey :: NixConfLine -> Maybe [Text]
isPublicKey :: NixConfLine -> Maybe [Text]
isPublicKey (TrustedPublicKeys xs :: [Text]
xs) = [Text] -> Maybe [Text]
forall a. a -> Maybe a
Just [Text]
xs
isPublicKey _ = Maybe [Text]
forall a. Maybe a
Nothing

isTrustedUsers :: NixConfLine -> Maybe [Text]
isTrustedUsers :: NixConfLine -> Maybe [Text]
isTrustedUsers (TrustedUsers xs :: [Text]
xs) = [Text] -> Maybe [Text]
forall a. a -> Maybe a
Just [Text]
xs
isTrustedUsers _ = Maybe [Text]
forall a. Maybe a
Nothing

-- | Pure version of addIO
add :: Api.BinaryCache -> [NixConf] -> NixConf -> NixConf
add :: BinaryCache -> [NixConf] -> NixConf -> NixConf
add bc :: BinaryCache
bc toRead :: [NixConf]
toRead toWrite :: NixConf
toWrite =
  (NixConfLine -> Maybe [Text]) -> NixConfLine -> NixConf -> NixConf
writeLines NixConfLine -> Maybe [Text]
isPublicKey ([Text] -> NixConfLine
TrustedPublicKeys ([Text] -> NixConfLine) -> [Text] -> NixConfLine
forall a b. (a -> b) -> a -> b
$ [Text] -> [Text]
forall a. Eq a => [a] -> [a]
nub [Text]
publicKeys) (NixConf -> NixConf) -> NixConf -> NixConf
forall a b. (a -> b) -> a -> b
$
    (NixConfLine -> Maybe [Text]) -> NixConfLine -> NixConf -> NixConf
writeLines NixConfLine -> Maybe [Text]
isSubstituter ([Text] -> NixConfLine
Substituters ([Text] -> NixConfLine) -> [Text] -> NixConfLine
forall a b. (a -> b) -> a -> b
$ [Text] -> [Text]
forall a. Eq a => [a] -> [a]
nub [Text]
substituters) NixConf
toWrite
  where
    -- Note: some defaults are always appended since overriding some setttings in nix.conf overrides defaults otherwise
    substituters :: [Text]
substituters = (Text
defaultPublicURI Text -> [Text] -> [Text]
forall a. a -> [a] -> [a]
: [NixConf] -> (NixConfLine -> Maybe [Text]) -> [Text]
readLines [NixConf]
toRead NixConfLine -> Maybe [Text]
isSubstituter) [Text] -> [Text] -> [Text]
forall a. Semigroup a => a -> a -> a
<> [BinaryCache -> Text
Api.uri BinaryCache
bc]
    publicKeys :: [Text]
publicKeys = (Text
defaultSigningKey Text -> [Text] -> [Text]
forall a. a -> [a] -> [a]
: [NixConf] -> (NixConfLine -> Maybe [Text]) -> [Text]
readLines [NixConf]
toRead NixConfLine -> Maybe [Text]
isPublicKey) [Text] -> [Text] -> [Text]
forall a. Semigroup a => a -> a -> a
<> BinaryCache -> [Text]
Api.publicSigningKeys BinaryCache
bc

defaultPublicURI :: Text
defaultPublicURI :: Text
defaultPublicURI = "https://cache.nixos.org"

defaultSigningKey :: Text
defaultSigningKey :: Text
defaultSigningKey = "cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY="

render :: NixConf -> Text
render :: NixConf -> Text
render (NixConf nixconflines :: [NixConfLine]
nixconflines) = [Text] -> Text
T.unlines ([Text] -> Text) -> [Text] -> Text
forall a b. (a -> b) -> a -> b
$ (NixConfLine -> Text) -> [NixConfLine] -> [Text]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap NixConfLine -> Text
go [NixConfLine]
nixconflines
  where
    go :: NixConfLine -> Text
    go :: NixConfLine -> Text
go (Substituters xs :: [Text]
xs) = "substituters" Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> " = " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> [Text] -> Text
T.unwords [Text]
xs
    go (TrustedUsers xs :: [Text]
xs) = "trusted-users = " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> [Text] -> Text
T.unwords [Text]
xs
    go (TrustedPublicKeys xs :: [Text]
xs) = "trusted-public-keys" Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> " = " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> [Text] -> Text
T.unwords [Text]
xs
    go (NetRcFile filename :: Text
filename) = "netrc-file = " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
filename
    go (Other line :: Text
line) = Text
line

write :: NixConfLoc -> NixConf -> IO ()
write :: NixConfLoc -> NixConf -> IO ()
write ncl :: NixConfLoc
ncl nc :: NixConf
nc = do
  String
filename <- NixConfLoc -> IO String
getFilename NixConfLoc
ncl
  Bool -> String -> IO ()
createDirectoryIfMissing Bool
True (ShowS
takeDirectory String
filename)
  String -> Text -> IO ()
writeFile String
filename (Text -> IO ()) -> Text -> IO ()
forall a b. (a -> b) -> a -> b
$ NixConf -> Text
render NixConf
nc

read :: NixConfLoc -> IO (Maybe NixConf)
read :: NixConfLoc -> IO (Maybe NixConf)
read ncl :: NixConfLoc
ncl = do
  String
filename <- NixConfLoc -> IO String
getFilename NixConfLoc
ncl
  Bool
doesExist <- String -> IO Bool
doesFileExist String
filename
  if Bool -> Bool
not Bool
doesExist
    then Maybe NixConf -> IO (Maybe NixConf)
forall (m :: * -> *) a. Monad m => a -> m a
return Maybe NixConf
forall a. Maybe a
Nothing
    else do
      Either (ParseErrorBundle Text Void) NixConf
result <- Text -> Either (ParseErrorBundle Text Void) NixConf
parse (Text -> Either (ParseErrorBundle Text Void) NixConf)
-> IO Text -> IO (Either (ParseErrorBundle Text Void) NixConf)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> String -> IO Text
readFile String
filename
      case Either (ParseErrorBundle Text Void) NixConf
result of
        Left err :: ParseErrorBundle Text Void
err -> do
          String -> IO ()
forall a (m :: * -> *). (Print a, MonadIO m) => a -> m ()
putStrLn (ParseErrorBundle Text Void -> String
forall s e.
(Stream s, ShowErrorComponent e) =>
ParseErrorBundle s e -> String
Mega.errorBundlePretty ParseErrorBundle Text Void
err)
          Text -> IO (Maybe NixConf)
forall a. HasCallStack => Text -> a
panic (Text -> IO (Maybe NixConf)) -> Text -> IO (Maybe NixConf)
forall a b. (a -> b) -> a -> b
$ String -> Text
forall a b. StringConv a b => a -> b
toS String
filename Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> " failed to parse, please copy the above error and contents of nix.conf and open an issue at https://github.com/cachix/cachix"
        Right conf :: NixConf
conf -> Maybe NixConf -> IO (Maybe NixConf)
forall (m :: * -> *) a. Monad m => a -> m a
return (Maybe NixConf -> IO (Maybe NixConf))
-> Maybe NixConf -> IO (Maybe NixConf)
forall a b. (a -> b) -> a -> b
$ NixConf -> Maybe NixConf
forall a. a -> Maybe a
Just NixConf
conf

update :: NixConfLoc -> (Maybe NixConf -> NixConf) -> IO ()
update :: NixConfLoc -> (Maybe NixConf -> NixConf) -> IO ()
update ncl :: NixConfLoc
ncl f :: Maybe NixConf -> NixConf
f = do
  NixConf
nc <- Maybe NixConf -> NixConf
f (Maybe NixConf -> NixConf) -> IO (Maybe NixConf) -> IO NixConf
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> NixConfLoc -> IO (Maybe NixConf)
read NixConfLoc
ncl
  NixConfLoc -> NixConf -> IO ()
write NixConfLoc
ncl NixConf
nc

setNetRC :: Text -> NixConf -> NixConf
setNetRC :: Text -> NixConf -> NixConf
setNetRC netrc :: Text
netrc (NixConf nc :: [NixConfLine]
nc) = [NixConfLine] -> NixConf
forall a. a -> NixConfG a
NixConf ([NixConfLine] -> NixConf) -> [NixConfLine] -> NixConf
forall a b. (a -> b) -> a -> b
$ (NixConfLine -> Bool) -> [NixConfLine] -> [NixConfLine]
forall a. (a -> Bool) -> [a] -> [a]
filter NixConfLine -> Bool
noNetRc [NixConfLine]
nc [NixConfLine] -> [NixConfLine] -> [NixConfLine]
forall a. [a] -> [a] -> [a]
++ [Text -> NixConfLine
NetRcFile Text
netrc]
  where
    noNetRc :: NixConfLine -> Bool
noNetRc (NetRcFile _) = Bool
False
    noNetRc _ = Bool
True

data NixConfLoc = Global | Local
  deriving (Int -> NixConfLoc -> ShowS
[NixConfLoc] -> ShowS
NixConfLoc -> String
(Int -> NixConfLoc -> ShowS)
-> (NixConfLoc -> String)
-> ([NixConfLoc] -> ShowS)
-> Show NixConfLoc
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [NixConfLoc] -> ShowS
$cshowList :: [NixConfLoc] -> ShowS
show :: NixConfLoc -> String
$cshow :: NixConfLoc -> String
showsPrec :: Int -> NixConfLoc -> ShowS
$cshowsPrec :: Int -> NixConfLoc -> ShowS
Show, NixConfLoc -> NixConfLoc -> Bool
(NixConfLoc -> NixConfLoc -> Bool)
-> (NixConfLoc -> NixConfLoc -> Bool) -> Eq NixConfLoc
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: NixConfLoc -> NixConfLoc -> Bool
$c/= :: NixConfLoc -> NixConfLoc -> Bool
== :: NixConfLoc -> NixConfLoc -> Bool
$c== :: NixConfLoc -> NixConfLoc -> Bool
Eq)

getFilename :: NixConfLoc -> IO FilePath
getFilename :: NixConfLoc -> IO String
getFilename ncl :: NixConfLoc
ncl = do
  String
dir <-
    case NixConfLoc
ncl of
      Global -> String -> IO String
forall (m :: * -> *) a. Monad m => a -> m a
return "/etc/nix"
      Local -> XdgDirectory -> String -> IO String
getXdgDirectory XdgDirectory
XdgConfig "nix"
  String -> IO String
forall (m :: * -> *) a. Monad m => a -> m a
return (String -> IO String) -> String -> IO String
forall a b. (a -> b) -> a -> b
$ String
dir String -> ShowS
forall a. Semigroup a => a -> a -> a
<> "/nix.conf"

-- nix.conf Parser
type Parser = Mega.Parsec Void Text

-- TODO: handle comments
parseLine :: ([Text] -> NixConfLine) -> Text -> Parser NixConfLine
parseLine :: ([Text] -> NixConfLine) -> Text -> Parser NixConfLine
parseLine constr :: [Text] -> NixConfLine
constr name :: Text
name = Parser NixConfLine -> Parser NixConfLine
forall e s (m :: * -> *) a. MonadParsec e s m => m a -> m a
Mega.try (Parser NixConfLine -> Parser NixConfLine)
-> Parser NixConfLine -> Parser NixConfLine
forall a b. (a -> b) -> a -> b
$ do
  Maybe String
_ <- ParsecT Void Text Identity String
-> ParsecT Void Text Identity (Maybe String)
forall (f :: * -> *) a. Alternative f => f a -> f (Maybe a)
optional (ParsecT Void Text Identity Char
-> ParsecT Void Text Identity String
forall (f :: * -> *) a. Alternative f => f a -> f [a]
some (Token Text -> ParsecT Void Text Identity (Token Text)
forall e s (m :: * -> *).
(MonadParsec e s m, Token s ~ Char) =>
Token s -> m (Token s)
char Token Text
' '))
  Text
_ <- Tokens Text -> ParsecT Void Text Identity (Tokens Text)
forall e s (m :: * -> *).
MonadParsec e s m =>
Tokens s -> m (Tokens s)
string Text
Tokens Text
name
  String
_ <- ParsecT Void Text Identity Char
-> ParsecT Void Text Identity String
forall (f :: * -> *) a. Alternative f => f a -> f [a]
many (Token Text -> ParsecT Void Text Identity (Token Text)
forall e s (m :: * -> *).
(MonadParsec e s m, Token s ~ Char) =>
Token s -> m (Token s)
char Token Text
' ')
  Char
_ <- Token Text -> ParsecT Void Text Identity (Token Text)
forall e s (m :: * -> *).
(MonadParsec e s m, Token s ~ Char) =>
Token s -> m (Token s)
char Token Text
'='
  String
_ <- ParsecT Void Text Identity Char
-> ParsecT Void Text Identity String
forall (f :: * -> *) a. Alternative f => f a -> f [a]
many (Token Text -> ParsecT Void Text Identity (Token Text)
forall e s (m :: * -> *).
(MonadParsec e s m, Token s ~ Char) =>
Token s -> m (Token s)
char Token Text
' ')
  [String]
values <- ParsecT Void Text Identity String
-> ParsecT Void Text Identity String
-> ParsecT Void Text Identity [String]
forall (m :: * -> *) a sep. MonadPlus m => m a -> m sep -> m [a]
Mega.sepBy1 (ParsecT Void Text Identity Char
-> ParsecT Void Text Identity String
forall (f :: * -> *) a. Alternative f => f a -> f [a]
many ((Token Text -> Bool) -> ParsecT Void Text Identity (Token Text)
forall e s (m :: * -> *).
MonadParsec e s m =>
(Token s -> Bool) -> m (Token s)
Mega.satisfy (Bool -> Bool
not (Bool -> Bool) -> (Char -> Bool) -> Char -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Char -> Bool
isSpace))) (ParsecT Void Text Identity Char
-> ParsecT Void Text Identity String
forall (f :: * -> *) a. Alternative f => f a -> f [a]
some (Token Text -> ParsecT Void Text Identity (Token Text)
forall e s (m :: * -> *).
(MonadParsec e s m, Token s ~ Char) =>
Token s -> m (Token s)
char Token Text
' '))
  String
_ <- ParsecT Void Text Identity Char
-> ParsecT Void Text Identity String
forall (f :: * -> *) a. Alternative f => f a -> f [a]
many ParsecT Void Text Identity Char
forall e s (m :: * -> *).
(MonadParsec e s m, Token s ~ Char) =>
m (Token s)
spaceChar
  NixConfLine -> Parser NixConfLine
forall (m :: * -> *) a. Monad m => a -> m a
return (NixConfLine -> Parser NixConfLine)
-> NixConfLine -> Parser NixConfLine
forall a b. (a -> b) -> a -> b
$ [Text] -> NixConfLine
constr ((String -> Text) -> [String] -> [Text]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap String -> Text
forall a b. StringConv a b => a -> b
toS [String]
values)

parseOther :: Parser NixConfLine
parseOther :: Parser NixConfLine
parseOther = Parser NixConfLine -> Parser NixConfLine
forall e s (m :: * -> *) a. MonadParsec e s m => m a -> m a
Mega.try (Parser NixConfLine -> Parser NixConfLine)
-> Parser NixConfLine -> Parser NixConfLine
forall a b. (a -> b) -> a -> b
$ Text -> NixConfLine
Other (Text -> NixConfLine) -> (String -> Text) -> String -> NixConfLine
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> Text
forall a b. StringConv a b => a -> b
toS (String -> NixConfLine)
-> ParsecT Void Text Identity String -> Parser NixConfLine
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ParsecT Void Text Identity Char
-> ParsecT Void Text Identity ()
-> ParsecT Void Text Identity String
forall (m :: * -> *) a sep. MonadPlus m => m a -> m sep -> m [a]
Mega.someTill ParsecT Void Text Identity Char
forall e s (m :: * -> *). MonadParsec e s m => m (Token s)
Mega.anySingle (ParsecT Void Text Identity Text -> ParsecT Void Text Identity ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void ParsecT Void Text Identity Text
forall e s (m :: * -> *).
(MonadParsec e s m, Token s ~ Char) =>
m (Tokens s)
eol ParsecT Void Text Identity ()
-> ParsecT Void Text Identity () -> ParsecT Void Text Identity ()
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> ParsecT Void Text Identity ()
forall e s (m :: * -> *). MonadParsec e s m => m ()
Mega.eof)

parseAltLine :: Parser NixConfLine
parseAltLine :: Parser NixConfLine
parseAltLine =
  (Text -> NixConfLine
Other "" NixConfLine
-> ParsecT Void Text Identity Text -> Parser NixConfLine
forall (f :: * -> *) a b. Functor f => a -> f b -> f a
<$ ParsecT Void Text Identity Text
forall e s (m :: * -> *).
(MonadParsec e s m, Token s ~ Char) =>
m (Tokens s)
eol)
    Parser NixConfLine -> Parser NixConfLine -> Parser NixConfLine
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> ([Text] -> NixConfLine) -> Text -> Parser NixConfLine
parseLine [Text] -> NixConfLine
Substituters "substituters"
    Parser NixConfLine -> Parser NixConfLine -> Parser NixConfLine
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> ([Text] -> NixConfLine) -> Text -> Parser NixConfLine
parseLine [Text] -> NixConfLine
TrustedPublicKeys "trusted-public-keys"
    Parser NixConfLine -> Parser NixConfLine -> Parser NixConfLine
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> ([Text] -> NixConfLine) -> Text -> Parser NixConfLine
parseLine [Text] -> NixConfLine
TrustedUsers "trusted-users"
    Parser NixConfLine -> Parser NixConfLine -> Parser NixConfLine
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> ([Text] -> NixConfLine) -> Text -> Parser NixConfLine
parseLine [Text] -> NixConfLine
TrustedPublicKeys "binary-cache-public-keys"
    Parser NixConfLine -> Parser NixConfLine -> Parser NixConfLine
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> ([Text] -> NixConfLine) -> Text -> Parser NixConfLine
parseLine [Text] -> NixConfLine
Substituters "binary-caches"
    -- NB: assume that space in this option means space in filename
    Parser NixConfLine -> Parser NixConfLine -> Parser NixConfLine
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> ([Text] -> NixConfLine) -> Text -> Parser NixConfLine
parseLine (Text -> NixConfLine
NetRcFile (Text -> NixConfLine) -> ([Text] -> Text) -> [Text] -> NixConfLine
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Text] -> Text
T.concat) "netrc-file"
    Parser NixConfLine -> Parser NixConfLine -> Parser NixConfLine
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> Parser NixConfLine
parseOther

parser :: Parser NixConf
parser :: Parser NixConf
parser = [NixConfLine] -> NixConf
forall a. a -> NixConfG a
NixConf ([NixConfLine] -> NixConf)
-> ParsecT Void Text Identity [NixConfLine] -> Parser NixConf
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Parser NixConfLine -> ParsecT Void Text Identity [NixConfLine]
forall (f :: * -> *) a. Alternative f => f a -> f [a]
many Parser NixConfLine
parseAltLine

parse :: Text -> Either (Mega.ParseErrorBundle Text Void) NixConf
parse :: Text -> Either (ParseErrorBundle Text Void) NixConf
parse = Parser NixConf
-> String -> Text -> Either (ParseErrorBundle Text Void) NixConf
forall e s a.
Parsec e s a -> String -> s -> Either (ParseErrorBundle s e) a
Mega.parse Parser NixConf
parser "nix.conf"