{-# LANGUAGE BlockArguments #-}
{-# LANGUAGE CPP #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE QuasiQuotes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TemplateHaskell #-}
#ifdef __GHCIDE__
# define NIX_IS_AT_LEAST(mm,m,p) 1
#endif

module Hercules.CNix.Store
  ( module Hercules.CNix.Store,
    module Hercules.CNix.Store.Context,
  )
where

import Control.Exception
import Control.Monad.IO.Unlift
import Data.ByteString.Short (ShortByteString)
import qualified Data.ByteString.Short as SBS
import Data.ByteString.Unsafe (unsafePackMallocCString)
import qualified Data.ByteString.Unsafe as BS
import Data.Coerce (coerce)
import qualified Data.Map as M
import Foreign (alloca, free, nullPtr)
import Foreign.ForeignPtr
import Foreign.ForeignPtr.Unsafe (unsafeForeignPtrToPtr)
import Foreign.Storable (peek)
import Hercules.CNix.Encapsulation (HasEncapsulation (..))
import Hercules.CNix.Std.Set (StdSet, stdSetCtx)
import qualified Hercules.CNix.Std.Set as Std.Set
import Hercules.CNix.Std.String (stdStringCtx)
import qualified Hercules.CNix.Std.String as Std.String
import Hercules.CNix.Std.Vector
import qualified Hercules.CNix.Std.Vector as Std.Vector
import Hercules.CNix.Store.Context
  ( DerivationInputsIterator,
    DerivationOutputsIterator,
    NixStore,
    NixStorePath,
    Ref,
    SecretKey,
    StringPairs,
    Strings,
    ValidPathInfo,
    context,
    unsafeMallocBS,
  )
import qualified Hercules.CNix.Store.Context as C hiding (context)
import Hercules.CNix.Store.Instances ()
import qualified Language.C.Inline.Cpp as C
import qualified Language.C.Inline.Cpp.Exception as C
import Protolude
import System.IO.Unsafe (unsafePerformIO)
import qualified Prelude

C.context (context <> stdVectorCtx <> stdSetCtx <> stdStringCtx)

C.include "<cstring>"

C.include "<nix/config.h>"

C.include "<nix/shared.hh>"

C.include "<nix/store-api.hh>"

C.include "<nix/get-drvs.hh>"

C.include "<nix/derivations.hh>"

C.include "<nix/globals.hh>"

C.include "<nix/path.hh>"

C.include "<variant>"

C.include "<nix/worker-protocol.hh>"

C.include "<nix/path-with-outputs.hh>"

C.include "hercules-ci-cnix/store.hxx"

C.using "namespace nix"

forNonNull :: Applicative m => Ptr a -> (Ptr a -> m b) -> m (Maybe b)
forNonNull :: forall (m :: * -> *) a b.
Applicative m =>
Ptr a -> (Ptr a -> m b) -> m (Maybe b)
forNonNull = forall a b c. (a -> b -> c) -> b -> a -> c
flip forall (m :: * -> *) a b.
Applicative m =>
(Ptr a -> m b) -> Ptr a -> m (Maybe b)
traverseNonNull

traverseNonNull :: Applicative m => (Ptr a -> m b) -> Ptr a -> m (Maybe b)
traverseNonNull :: forall (m :: * -> *) a b.
Applicative m =>
(Ptr a -> m b) -> Ptr a -> m (Maybe b)
traverseNonNull Ptr a -> m b
f Ptr a
p = if Ptr a
p forall a. Eq a => a -> a -> Bool
== forall a. Ptr a
nullPtr then forall (f :: * -> *) a. Applicative f => a -> f a
pure forall a. Maybe a
Nothing else forall a. a -> Maybe a
Just forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Ptr a -> m b
f Ptr a
p

newtype Store = Store (Ptr (Ref NixStore))

openStore :: IO Store
openStore :: IO Store
openStore =
  coerce :: forall a b. Coercible a b => a -> b
coerce
    [C.throwBlock| refStore * {
      refStore s = openStore();
      return new refStore(s);
    } |]

releaseStore :: Store -> IO ()
releaseStore :: Store -> IO ()
releaseStore (Store Ptr (Ref NixStore)
store) = [C.exp| void { delete $(refStore* store) } |]

withStore :: MonadUnliftIO m => (Store -> m a) -> m a
withStore :: forall (m :: * -> *) a. MonadUnliftIO m => (Store -> m a) -> m a
withStore Store -> m a
m = do
  UnliftIO forall a. m a -> IO a
ul <- forall (m :: * -> *). MonadUnliftIO m => m (UnliftIO m)
askUnliftIO
  forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO forall a b. (a -> b) -> a -> b
$ forall r. (Store -> IO r) -> IO r
withStore' forall a b. (a -> b) -> a -> b
$ \Store
a -> forall a. m a -> IO a
ul (Store -> m a
m Store
a)

withStore' ::
  (Store -> IO r) ->
  IO r
withStore' :: forall r. (Store -> IO r) -> IO r
withStore' =
  forall a b c. IO a -> (a -> IO b) -> (a -> IO c) -> IO c
bracket IO Store
openStore Store -> IO ()
releaseStore

withStoreFromURI ::
  MonadUnliftIO m =>
  Text ->
  (Store -> m r) ->
  m r
withStoreFromURI :: forall (m :: * -> *) r.
MonadUnliftIO m =>
Text -> (Store -> m r) -> m r
withStoreFromURI Text
storeURIText Store -> m r
f = do
  let storeURI :: ByteString
storeURI = Text -> ByteString
encodeUtf8 Text
storeURIText
  (UnliftIO forall a. m a -> IO a
unlift) <- forall (m :: * -> *). MonadUnliftIO m => m (UnliftIO m)
askUnliftIO
  forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO forall a b. (a -> b) -> a -> b
$
    forall a b c. IO a -> (a -> IO b) -> (a -> IO c) -> IO c
bracket
      [C.throwBlock| refStore* {
        refStore s = openStore($bs-cstr:storeURI);
        return new refStore(s);
      }|]
      (\Ptr (Ref NixStore)
x -> [C.exp| void { delete $(refStore* x) } |])
      (forall a. m a -> IO a
unlift forall b c a. (b -> c) -> (a -> b) -> a -> c
. Store -> m r
f forall b c a. (b -> c) -> (a -> b) -> a -> c
. Ptr (Ref NixStore) -> Store
Store)

storeUri :: MonadIO m => Store -> m ByteString
storeUri :: forall (m :: * -> *). MonadIO m => Store -> m ByteString
storeUri (Store Ptr (Ref NixStore)
store) =
  forall (m :: * -> *). MonadIO m => IO (Ptr CChar) -> m ByteString
unsafeMallocBS
    [C.block| const char* {
       std::string uri = (*$(refStore* store))->getUri();
       return strdup(uri.c_str());
     } |]

-- | Usually @"/nix/store"@
storeDir :: MonadIO m => Store -> m ByteString
storeDir :: forall (m :: * -> *). MonadIO m => Store -> m ByteString
storeDir (Store Ptr (Ref NixStore)
store) =
  forall (m :: * -> *). MonadIO m => IO (Ptr CChar) -> m ByteString
unsafeMallocBS
    [C.block| const char* {
       std::string uri = (*$(refStore* store))->storeDir;
       return strdup(uri.c_str());
     } |]

getStoreProtocolVersion :: Store -> IO Int
getStoreProtocolVersion :: Store -> IO Int
getStoreProtocolVersion (Store Ptr (Ref NixStore)
store) =
  forall a b. (Integral a, Num b) => a -> b
fromIntegral
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [C.throwBlock| int {
       Store &store = **$(refStore* store);
       return store.getProtocol();
     } |]

getClientProtocolVersion :: IO Int
getClientProtocolVersion :: IO Int
getClientProtocolVersion =
  forall a b. (Integral a, Num b) => a -> b
fromIntegral
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [C.throwBlock| int {
       return PROTOCOL_VERSION;
     } |]

-- | Store-agnostic store path representation: hash and name. Does not have a storedir or subpath inside the store path.
newtype StorePath = StorePath (ForeignPtr NixStorePath)

instance HasEncapsulation NixStorePath StorePath where
  moveToForeignPtrWrapper :: Ptr NixStorePath -> IO StorePath
moveToForeignPtrWrapper = Ptr NixStorePath -> IO StorePath
moveStorePath

finalizeStorePath :: FinalizerPtr NixStorePath
{-# NOINLINE finalizeStorePath #-}
finalizeStorePath :: FinalizerPtr NixStorePath
finalizeStorePath =
  forall a. IO a -> a
unsafePerformIO
    [C.exp|
      void (*)(nix::StorePath *) {
        [](StorePath *v) {
          delete v;
        }
      }
    |]

-- | Move ownership of a Ptr NixStorePath into 'StorePath'
moveStorePath :: Ptr NixStorePath -> IO StorePath
moveStorePath :: Ptr NixStorePath -> IO StorePath
moveStorePath Ptr NixStorePath
x = ForeignPtr NixStorePath -> StorePath
StorePath forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall a. FinalizerPtr a -> Ptr a -> IO (ForeignPtr a)
newForeignPtr FinalizerPtr NixStorePath
finalizeStorePath Ptr NixStorePath
x

-- | Move ownership of a Ptr NixStorePath into 'StorePath'
moveStorePathMaybe :: Ptr NixStorePath -> IO (Maybe StorePath)
moveStorePathMaybe :: Ptr NixStorePath -> IO (Maybe StorePath)
moveStorePathMaybe = forall (m :: * -> *) a b.
Applicative m =>
(Ptr a -> m b) -> Ptr a -> m (Maybe b)
traverseNonNull forall a b. (a -> b) -> a -> b
$ forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ForeignPtr NixStorePath -> StorePath
StorePath forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. FinalizerPtr a -> Ptr a -> IO (ForeignPtr a)
newForeignPtr FinalizerPtr NixStorePath
finalizeStorePath

instance Prelude.Show StorePath where
  show :: StorePath -> String
show StorePath
storePath = forall a. IO a -> a
unsafePerformIO do
    ByteString
bs <-
      Ptr CChar -> IO ByteString
BS.unsafePackMallocCString
        forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< [C.block| const char* {
          std::string s($fptr-ptr:(nix::StorePath *storePath)->to_string());
          return strdup(s.c_str());
        }|]
    forall (f :: * -> *) a. Applicative f => a -> f a
pure forall a b. (a -> b) -> a -> b
$ forall a b. ConvertText a b => a -> b
toS forall a b. (a -> b) -> a -> b
$ OnDecodeError -> ByteString -> Text
decodeUtf8With OnDecodeError
lenientDecode ByteString
bs

instance Eq StorePath where
  StorePath
a == :: StorePath -> StorePath -> Bool
== StorePath
b = forall a. Ord a => a -> a -> Ordering
compare StorePath
a StorePath
b forall a. Eq a => a -> a -> Bool
== Ordering
EQ

-- FIXME
instance Ord StorePath where
  compare :: StorePath -> StorePath -> Ordering
compare (StorePath ForeignPtr NixStorePath
a) (StorePath ForeignPtr NixStorePath
b) =
    forall a. Ord a => a -> a -> Ordering
compare
      CInt
0
      [C.pure| int {
        $fptr-ptr:(nix::StorePath *a)->to_string().compare($fptr-ptr:(nix::StorePath *b)->to_string())
      }|]

-- | Create 'StorePath' from hash and name.
--
-- Throws C++ `BadStorePath` exception when invalid.
parseStorePathBaseName :: ByteString -> IO StorePath
parseStorePathBaseName :: ByteString -> IO StorePath
parseStorePathBaseName ByteString
bs =
  Ptr NixStorePath -> IO StorePath
moveStorePath
    forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< [C.throwBlock| nix::StorePath *{
      return new StorePath(std::string($bs-ptr:bs, $bs-len:bs));
    }|]

-- | Parse a complete store path including storeDir into a 'StorePath'.
--
-- Throws C++ `BadStorePath` exception when invalid.
parseStorePath :: Store -> ByteString -> IO StorePath
parseStorePath :: Store -> ByteString -> IO StorePath
parseStorePath (Store Ptr (Ref NixStore)
store) ByteString
bs =
  Ptr NixStorePath -> IO StorePath
moveStorePath
    forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< [C.throwBlock| nix::StorePath *{
      return new StorePath(std::move((*$(refStore* store))->parseStorePath(std::string($bs-ptr:bs, $bs-len:bs))));
    }|]

getStorePathBaseName :: StorePath -> IO ByteString
getStorePathBaseName :: StorePath -> IO ByteString
getStorePathBaseName (StorePath ForeignPtr NixStorePath
sp) = do
  Ptr CChar -> IO ByteString
BS.unsafePackMallocCString
    forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< [C.block| const char *{
      std::string s($fptr-ptr:(nix::StorePath *sp)->to_string());
      return strdup(s.c_str());
    }|]

getStorePathHash :: StorePath -> IO ByteString
getStorePathHash :: StorePath -> IO ByteString
getStorePathHash (StorePath ForeignPtr NixStorePath
sp) = do
  Ptr CChar -> IO ByteString
BS.unsafePackMallocCString
    forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< [C.block| const char *{
      std::string s($fptr-ptr:(nix::StorePath *sp)->hashPart());
      return strdup(s.c_str());
    }|]

storePathToPath :: Store -> StorePath -> IO ByteString
storePathToPath :: Store -> StorePath -> IO ByteString
storePathToPath (Store Ptr (Ref NixStore)
store) (StorePath ForeignPtr NixStorePath
sp) =
  Ptr CChar -> IO ByteString
BS.unsafePackMallocCString
    forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< [C.block| const char *{
      Store & store = **$(refStore* store);
      StorePath &sp = *$fptr-ptr:(nix::StorePath *sp);
      std::string s(store.printStorePath(sp));
      return strdup(s.c_str());
    }|]

ensurePath :: Store -> StorePath -> IO ()
ensurePath :: Store -> StorePath -> IO ()
ensurePath (Store Ptr (Ref NixStore)
store) (StorePath ForeignPtr NixStorePath
storePath) =
  [C.throwBlock| void {
    ReceiveInterrupts _;
    Store &store = **$(refStore* store);
    StorePath &storePath = *$fptr-ptr:(nix::StorePath *storePath);
    store.ensurePath(storePath);
  } |]

addTemporaryRoot :: Store -> StorePath -> IO ()
addTemporaryRoot :: Store -> StorePath -> IO ()
addTemporaryRoot (Store Ptr (Ref NixStore)
store) StorePath
storePath = do
  [C.throwBlock| void {
    ReceiveInterrupts _;
    Store &store = **$(refStore* store);
    StorePath &storePath = *$fptr-ptr:(nix::StorePath *storePath);
    store.addTempRoot(storePath);
  } |]

clearPathInfoCache :: Store -> IO ()
clearPathInfoCache :: Store -> IO ()
clearPathInfoCache (Store Ptr (Ref NixStore)
store) =
  [C.throwBlock| void {
    (*$(refStore* store))->clearPathInfoCache();
  } |]

clearSubstituterCaches :: IO ()
clearSubstituterCaches :: IO ()
clearSubstituterCaches =
  [C.throwBlock| void {
    auto subs = nix::getDefaultSubstituters();
    for (auto sub : subs) {
      sub->clearPathInfoCache();
    }
  } |]

newtype StorePathWithOutputs = StorePathWithOutputs (ForeignPtr C.NixStorePathWithOutputs)

instance HasEncapsulation C.NixStorePathWithOutputs StorePathWithOutputs where
  moveToForeignPtrWrapper :: Ptr NixStorePathWithOutputs -> IO StorePathWithOutputs
moveToForeignPtrWrapper Ptr NixStorePathWithOutputs
x = ForeignPtr NixStorePathWithOutputs -> StorePathWithOutputs
StorePathWithOutputs forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall a. FinalizerPtr a -> Ptr a -> IO (ForeignPtr a)
newForeignPtr FinalizerPtr NixStorePathWithOutputs
finalizeStorePathWithOutputs Ptr NixStorePathWithOutputs
x

finalizeStorePathWithOutputs :: FinalizerPtr C.NixStorePathWithOutputs
{-# NOINLINE finalizeStorePathWithOutputs #-}
finalizeStorePathWithOutputs :: FinalizerPtr NixStorePathWithOutputs
finalizeStorePathWithOutputs =
  forall a. IO a -> a
unsafePerformIO
    [C.exp|
      void (*)(nix::StorePathWithOutputs *) {
        [](StorePathWithOutputs *v) {
          delete v;
        }
      }
    |]

newStorePathWithOutputs :: StorePath -> [ByteString] -> IO StorePathWithOutputs
newStorePathWithOutputs :: StorePath -> [ByteString] -> IO StorePathWithOutputs
newStorePathWithOutputs StorePath
storePath [ByteString]
outputs = do
  StdSet CStdString
set <- forall a. HasStdSet a => IO (StdSet a)
Std.Set.new
  forall (t :: * -> *) (f :: * -> *) a b.
(Foldable t, Applicative f) =>
t a -> (a -> f b) -> f ()
for_ [ByteString]
outputs (\ByteString
o -> forall a. ByteString -> (Ptr CStdString -> IO a) -> IO a
Std.String.withString ByteString
o (forall a. HasStdSet a => StdSet a -> Ptr a -> IO ()
Std.Set.insertP StdSet CStdString
set))
  forall a b. HasEncapsulation a b => Ptr a -> IO b
moveToForeignPtrWrapper
    forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< [C.exp| nix::StorePathWithOutputs * {
    new StorePathWithOutputs {*$fptr-ptr:(nix::StorePath *storePath), *$fptr-ptr:(std::set<std::string>* set)}
  }|]

getStorePath :: StorePathWithOutputs -> IO StorePath
getStorePath :: StorePathWithOutputs -> IO StorePath
getStorePath StorePathWithOutputs
swo = forall a. IO a -> IO a
mask_ do
  forall a b. HasEncapsulation a b => Ptr a -> IO b
moveToForeignPtrWrapper
    forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< [C.exp| nix::StorePath * {
    new StorePath($fptr-ptr:(nix::StorePathWithOutputs *swo)->path)
  }|]

getOutputs :: StorePathWithOutputs -> IO [ByteString]
getOutputs :: StorePathWithOutputs -> IO [ByteString]
getOutputs StorePathWithOutputs
swo = forall a. IO a -> IO a
mask_ do
  forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
(a -> f b) -> t a -> f (t b)
traverse Ptr CStdString -> IO ByteString
Std.String.moveToByteString forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< forall a. HasStdVector a => StdVector a -> IO [Ptr a]
toListP forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< forall a b. HasEncapsulation a b => Ptr a -> IO b
moveToForeignPtrWrapper
    forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< [C.throwBlock| std::vector<std::string>* {
      auto r = new std::vector<std::string>();
      for (auto s : $fptr-ptr:(nix::StorePathWithOutputs *swo)->outputs)
        r->push_back(s);
      return r;
    }|]

buildPaths :: Store -> StdVector C.NixStorePathWithOutputs -> IO ()
buildPaths :: Store -> StdVector NixStorePathWithOutputs -> IO ()
buildPaths (Store Ptr (Ref NixStore)
store) (StdVector ForeignPtr (CStdVector NixStorePathWithOutputs)
paths) = do
  [C.throwBlock| void {
    ReceiveInterrupts _;
    Store &store = **$(refStore* store);
    std::vector<StorePathWithOutputs> &paths = *$fptr-ptr:(std::vector<nix::StorePathWithOutputs>* paths);
    store.buildPaths(toDerivedPaths(paths));
  }|]

buildPath :: Store -> StorePathWithOutputs -> IO ()
buildPath :: Store -> StorePathWithOutputs -> IO ()
buildPath Store
store StorePathWithOutputs
spwo = do
  Store -> StdVector NixStorePathWithOutputs -> IO ()
buildPaths Store
store forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< forall a' a.
(Coercible a' (ForeignPtr a), HasStdVector a) =>
[a'] -> IO (StdVector a)
Std.Vector.fromListFP [StorePathWithOutputs
spwo]

newtype Derivation = Derivation (ForeignPtr C.Derivation)

instance HasEncapsulation C.Derivation Derivation where
  moveToForeignPtrWrapper :: Ptr Derivation -> IO Derivation
moveToForeignPtrWrapper = forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ForeignPtr Derivation -> Derivation
Derivation forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. FinalizerPtr a -> Ptr a -> IO (ForeignPtr a)
newForeignPtr FinalizerPtr Derivation
finalizeDerivation

finalizeDerivation :: FinalizerPtr C.Derivation
{-# NOINLINE finalizeDerivation #-}
finalizeDerivation :: FinalizerPtr Derivation
finalizeDerivation =
  forall a. IO a -> a
unsafePerformIO
    [C.exp|
    void (*)(Derivation *) {
      [](Derivation *v) {
        delete v;
      }
    } |]

getDerivation :: Store -> StorePath -> IO Derivation
getDerivation :: Store -> StorePath -> IO Derivation
getDerivation (Store Ptr (Ref NixStore)
store) (StorePath ForeignPtr NixStorePath
spwo) = do
  forall a b. HasEncapsulation a b => Ptr a -> IO b
moveToForeignPtrWrapper
    forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< [C.throwBlock| Derivation *{
      ReceiveInterrupts _;
      Store &store = **$(refStore* store);
      return new Derivation(
          store.derivationFromPath(*$fptr-ptr:(nix::StorePath *spwo))
        );
    } |]

-- Useful for testing
getDerivationFromString ::
  Store ->
  -- | Derivation name (store path name with ".drv" extension removed)
  ByteString ->
  -- | Contents
  ByteString ->
  IO Derivation
getDerivationFromString :: Store -> ByteString -> ByteString -> IO Derivation
getDerivationFromString (Store Ptr (Ref NixStore)
store) ByteString
name ByteString
contents = do
  forall a b. HasEncapsulation a b => Ptr a -> IO b
moveToForeignPtrWrapper
    forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< [C.throwBlock| Derivation *{
      Store &store = **$(refStore* store);
      std::string name($bs-ptr:name, $bs-len:name);
      return new Derivation(parseDerivation(store, std::string($bs-ptr:contents, $bs-len:contents), name));
    }|]

getDerivationNameFromPath :: StorePath -> IO ByteString
getDerivationNameFromPath :: StorePath -> IO ByteString
getDerivationNameFromPath StorePath
storePath =
  Ptr CChar -> IO ByteString
BS.unsafePackMallocCString
    forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< [C.throwBlock| const char *{
      StorePath &sp = *$fptr-ptr:(nix::StorePath *storePath);
      std::string s(Derivation::nameFromPath(sp));
      return strdup(s.c_str());
    }|]

data DerivationOutput = DerivationOutput
  { DerivationOutput -> ByteString
derivationOutputName :: !ByteString,
    DerivationOutput -> Maybe StorePath
derivationOutputPath :: !(Maybe StorePath),
    DerivationOutput -> DerivationOutputDetail
derivationOutputDetail :: !DerivationOutputDetail
  }
  deriving (DerivationOutput -> DerivationOutput -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: DerivationOutput -> DerivationOutput -> Bool
$c/= :: DerivationOutput -> DerivationOutput -> Bool
== :: DerivationOutput -> DerivationOutput -> Bool
$c== :: DerivationOutput -> DerivationOutput -> Bool
Eq, Int -> DerivationOutput -> ShowS
[DerivationOutput] -> ShowS
DerivationOutput -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [DerivationOutput] -> ShowS
$cshowList :: [DerivationOutput] -> ShowS
show :: DerivationOutput -> String
$cshow :: DerivationOutput -> String
showsPrec :: Int -> DerivationOutput -> ShowS
$cshowsPrec :: Int -> DerivationOutput -> ShowS
Show)

data DerivationOutputDetail
  = DerivationOutputInputAddressed StorePath
  | DerivationOutputCAFixed FixedOutputHash StorePath
  | DerivationOutputCAFloating FileIngestionMethod HashType
  | DerivationOutputDeferred
  deriving (DerivationOutputDetail -> DerivationOutputDetail -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: DerivationOutputDetail -> DerivationOutputDetail -> Bool
$c/= :: DerivationOutputDetail -> DerivationOutputDetail -> Bool
== :: DerivationOutputDetail -> DerivationOutputDetail -> Bool
$c== :: DerivationOutputDetail -> DerivationOutputDetail -> Bool
Eq, Int -> DerivationOutputDetail -> ShowS
[DerivationOutputDetail] -> ShowS
DerivationOutputDetail -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [DerivationOutputDetail] -> ShowS
$cshowList :: [DerivationOutputDetail] -> ShowS
show :: DerivationOutputDetail -> String
$cshow :: DerivationOutputDetail -> String
showsPrec :: Int -> DerivationOutputDetail -> ShowS
$cshowsPrec :: Int -> DerivationOutputDetail -> ShowS
Show)

data FixedOutputHash = FixedOutputHash !FileIngestionMethod {-# UNPACK #-} !Hash
  deriving (FixedOutputHash -> FixedOutputHash -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: FixedOutputHash -> FixedOutputHash -> Bool
$c/= :: FixedOutputHash -> FixedOutputHash -> Bool
== :: FixedOutputHash -> FixedOutputHash -> Bool
$c== :: FixedOutputHash -> FixedOutputHash -> Bool
Eq, Int -> FixedOutputHash -> ShowS
[FixedOutputHash] -> ShowS
FixedOutputHash -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [FixedOutputHash] -> ShowS
$cshowList :: [FixedOutputHash] -> ShowS
show :: FixedOutputHash -> String
$cshow :: FixedOutputHash -> String
showsPrec :: Int -> FixedOutputHash -> ShowS
$cshowsPrec :: Int -> FixedOutputHash -> ShowS
Show)

-- | See @content-address.hh@
data FileIngestionMethod = Flat | Recursive
  deriving (FileIngestionMethod -> FileIngestionMethod -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: FileIngestionMethod -> FileIngestionMethod -> Bool
$c/= :: FileIngestionMethod -> FileIngestionMethod -> Bool
== :: FileIngestionMethod -> FileIngestionMethod -> Bool
$c== :: FileIngestionMethod -> FileIngestionMethod -> Bool
Eq, Int -> FileIngestionMethod -> ShowS
[FileIngestionMethod] -> ShowS
FileIngestionMethod -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [FileIngestionMethod] -> ShowS
$cshowList :: [FileIngestionMethod] -> ShowS
show :: FileIngestionMethod -> String
$cshow :: FileIngestionMethod -> String
showsPrec :: Int -> FileIngestionMethod -> ShowS
$cshowsPrec :: Int -> FileIngestionMethod -> ShowS
Show)

-- | See @hash.hh@
data Hash = Hash !HashType {-# UNPACK #-} !ShortByteString
  deriving (Hash -> Hash -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Hash -> Hash -> Bool
$c/= :: Hash -> Hash -> Bool
== :: Hash -> Hash -> Bool
$c== :: Hash -> Hash -> Bool
Eq, Int -> Hash -> ShowS
[Hash] -> ShowS
Hash -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Hash] -> ShowS
$cshowList :: [Hash] -> ShowS
show :: Hash -> String
$cshow :: Hash -> String
showsPrec :: Int -> Hash -> ShowS
$cshowsPrec :: Int -> Hash -> ShowS
Show)

-- | See @hash.hh@
data HashType = MD5 | SHA1 | SHA256 | SHA512
  deriving (HashType -> HashType -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: HashType -> HashType -> Bool
$c/= :: HashType -> HashType -> Bool
== :: HashType -> HashType -> Bool
$c== :: HashType -> HashType -> Bool
Eq, Int -> HashType -> ShowS
[HashType] -> ShowS
HashType -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [HashType] -> ShowS
$cshowList :: [HashType] -> ShowS
show :: HashType -> String
$cshow :: HashType -> String
showsPrec :: Int -> HashType -> ShowS
$cshowsPrec :: Int -> HashType -> ShowS
Show)

getDerivationOutputs :: Store -> ByteString -> Derivation -> IO [DerivationOutput]
getDerivationOutputs :: Store -> ByteString -> Derivation -> IO [DerivationOutput]
getDerivationOutputs (Store Ptr (Ref NixStore)
store) ByteString
drvName (Derivation ForeignPtr Derivation
derivation) =
  forall a b c. IO a -> (a -> IO b) -> (a -> IO c) -> IO c
bracket
    [C.exp| DerivationOutputsIterator* {
      new DerivationOutputsIterator($fptr-ptr:(Derivation *derivation)->outputs.begin())
    }|]
    Ptr DerivationOutputsIterator -> IO ()
deleteDerivationOutputsIterator
    forall a b. (a -> b) -> a -> b
$ \Ptr DerivationOutputsIterator
i -> forall a. (a -> a) -> a
fix forall a b. (a -> b) -> a -> b
$ \IO [DerivationOutput]
continue -> do
      Bool
isEnd <- (CBool
0 forall a. Eq a => a -> a -> Bool
/=) forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [C.exp| bool { *$(DerivationOutputsIterator *i) == $fptr-ptr:(Derivation *derivation)->outputs.end() }|]
      if Bool
isEnd
        then forall (f :: * -> *) a. Applicative f => a -> f a
pure []
        else
          ( forall a. IO a -> IO a
mask_ do
              forall a b. Storable a => (Ptr a -> IO b) -> IO b
alloca \Ptr (Ptr CChar)
nameP -> forall a b. Storable a => (Ptr a -> IO b) -> IO b
alloca \Ptr (Ptr NixStorePath)
pathP -> forall a b. Storable a => (Ptr a -> IO b) -> IO b
alloca \Ptr CInt
typP -> forall a b. Storable a => (Ptr a -> IO b) -> IO b
alloca \Ptr CInt
fimP ->
                forall a b. Storable a => (Ptr a -> IO b) -> IO b
alloca \Ptr CInt
hashTypeP -> forall a b. Storable a => (Ptr a -> IO b) -> IO b
alloca \Ptr (Ptr CChar)
hashValueP -> forall a b. Storable a => (Ptr a -> IO b) -> IO b
alloca \Ptr CInt
hashSizeP -> do
                  [C.throwBlock| void {
                    Store &store = **$(refStore *store);
                    std::string drvName = std::string($bs-ptr:drvName, $bs-len:drvName);
                    nix::DerivationOutputs::iterator &i = *$(DerivationOutputsIterator *i);
                    const char *&name = *$(const char **nameP);
                    int &typ = *$(int *typP);
                    StorePath *& path = *$(nix::StorePath **pathP);
                    int &fim = *$(int *fimP);
                    int &hashType = *$(int *hashTypeP);
                    char *&hashValue = *$(char **hashValueP);
                    int &hashSize = *$(int *hashSizeP);

                    std::string nameString = i->first;
                    name = strdup(nameString.c_str());
                    path = nullptr;
                    std::visit(overloaded {
                      [&](DerivationOutputInputAddressed doi) -> void {
                        typ = 0;
                        path = new StorePath(doi.path);
                      },
                      [&](DerivationOutputCAFixed dof) -> void {
                        typ = 1;
                        path = new StorePath(dof.path(store, $fptr-ptr:(Derivation *derivation)->name, nameString));
                        switch (dof.hash.method) {
                          case nix::FileIngestionMethod::Flat:
                            fim = 0;
                            break;
                          case nix::FileIngestionMethod::Recursive:
                            fim = 1;
                            break;
                          default:
                            fim = -1;
                            break;
                        }
                        switch (dof.hash.hash.type) {
                          case htMD5: 
                            hashType = 0;
                            break;
                          case htSHA1: 
                            hashType = 1;
                            break;
                          case htSHA256: 
                            hashType = 2;
                            break;
                          case htSHA512: 
                            hashType = 3;
                            break;
                          default:
                            hashType = -1;
                            break;
                        }
                        hashSize = dof.hash.hash.hashSize;
                        hashValue = (char*)malloc(hashSize);
                        std::memcpy((void*)(hashValue),
                                    (void*)(dof.hash.hash.hash),
                                    hashSize);
                      },
                      [&](DerivationOutputCAFloating dof) -> void {
                        typ = 2;
                        switch (dof.method) {
                          case nix::FileIngestionMethod::Flat:
                            fim = 0;
                            break;
                          case nix::FileIngestionMethod::Recursive:
                            fim = 1;
                            break;
                          default:
                            fim = -1;
                            break;
                        }
                        switch (dof.hashType) {
                          case htMD5: 
                            hashType = 0;
                            break;
                          case htSHA1: 
                            hashType = 1;
                            break;
                          case htSHA256: 
                            hashType = 2;
                            break;
                          case htSHA512: 
                            hashType = 3;
                            break;
                          default:
                            hashType = -1;
                            break;
                        }
                      },
                      [&](DerivationOutputDeferred) -> void {
                        typ = 3;
                      },
#if NIX_IS_AT_LEAST(2,8,0)
                      [&](DerivationOutputImpure) -> void {
                        typ = 4;
                      },
#endif
                    },
#if NIX_IS_AT_LEAST(2,8,0)
                      i->second.raw()
#else
                      i->second.output
#endif
                    );
                    i++;
                  }|]
                  ByteString
name <- Ptr CChar -> IO ByteString
unsafePackMallocCString forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< forall a. Storable a => Ptr a -> IO a
peek Ptr (Ptr CChar)
nameP
                  Maybe StorePath
path <- Ptr NixStorePath -> IO (Maybe StorePath)
moveStorePathMaybe forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< forall a. Storable a => Ptr a -> IO a
peek Ptr (Ptr NixStorePath)
pathP
                  CInt
typ <- forall a. Storable a => Ptr a -> IO a
peek Ptr CInt
typP
                  let getFileIngestionMethod :: IO FileIngestionMethod
getFileIngestionMethod = forall a. Storable a => Ptr a -> IO a
peek Ptr CInt
fimP forall (f :: * -> *) a b. Functor f => f a -> (a -> b) -> f b
<&> \case CInt
0 -> FileIngestionMethod
Flat; CInt
1 -> FileIngestionMethod
Recursive; CInt
_ -> forall a. HasCallStack => Text -> a
panic Text
"getDerivationOutputs: unknown fim"
                      getHashType :: IO HashType
getHashType =
                        forall a. Storable a => Ptr a -> IO a
peek Ptr CInt
hashTypeP forall (f :: * -> *) a b. Functor f => f a -> (a -> b) -> f b
<&> \case
                          CInt
0 -> HashType
MD5
                          CInt
1 -> HashType
SHA1
                          CInt
2 -> HashType
SHA256
                          CInt
3 -> HashType
SHA512
                          CInt
_ -> forall a. HasCallStack => Text -> a
panic Text
"getDerivationOutputs: unknown hashType"
                  DerivationOutputDetail
detail <- case CInt
typ of
                    CInt
0 -> forall (f :: * -> *) a. Applicative f => a -> f a
pure forall a b. (a -> b) -> a -> b
$ StorePath -> DerivationOutputDetail
DerivationOutputInputAddressed (forall a. a -> Maybe a -> a
fromMaybe (forall a. HasCallStack => Text -> a
panic Text
"getDerivationOutputs: impossible DOIA path missing") Maybe StorePath
path)
                    CInt
1 -> do
                      Ptr CChar
hashValue <- forall a. Storable a => Ptr a -> IO a
peek Ptr (Ptr CChar)
hashValueP
                      CInt
hashSize <- forall a. Storable a => Ptr a -> IO a
peek Ptr CInt
hashSizeP
                      ShortByteString
hashString <- CStringLen -> IO ShortByteString
SBS.packCStringLen (Ptr CChar
hashValue, forall a b. (Integral a, Num b) => a -> b
fromIntegral CInt
hashSize)
                      forall a. Ptr a -> IO ()
free Ptr CChar
hashValue
                      HashType
hashType <- IO HashType
getHashType
                      FileIngestionMethod
fim <- IO FileIngestionMethod
getFileIngestionMethod
                      forall (f :: * -> *) a. Applicative f => a -> f a
pure forall a b. (a -> b) -> a -> b
$ FixedOutputHash -> StorePath -> DerivationOutputDetail
DerivationOutputCAFixed (FileIngestionMethod -> Hash -> FixedOutputHash
FixedOutputHash FileIngestionMethod
fim (HashType -> ShortByteString -> Hash
Hash HashType
hashType ShortByteString
hashString)) (forall a. a -> Maybe a -> a
fromMaybe (forall a. HasCallStack => Text -> a
panic Text
"getDerivationOutputs: impossible DOCF path missing") Maybe StorePath
path)
                    CInt
2 -> do
                      HashType
hashType <- IO HashType
getHashType
                      FileIngestionMethod
fim <- IO FileIngestionMethod
getFileIngestionMethod
                      forall (f :: * -> *) a. Applicative f => a -> f a
pure forall a b. (a -> b) -> a -> b
$ FileIngestionMethod -> HashType -> DerivationOutputDetail
DerivationOutputCAFloating FileIngestionMethod
fim HashType
hashType
                    CInt
3 -> forall (f :: * -> *) a. Applicative f => a -> f a
pure DerivationOutputDetail
DerivationOutputDeferred
                    CInt
4 -> forall a. HasCallStack => Text -> a
panic Text
"getDerivationOutputs: impure derivations not supported yet"
                    CInt
_ -> forall a. HasCallStack => Text -> a
panic Text
"getDerivationOutputs: impossible getDerivationOutputs typ"
                  forall (f :: * -> *) a. Applicative f => a -> f a
pure
                    ( DerivationOutput
                        { derivationOutputName :: ByteString
derivationOutputName = ByteString
name,
                          derivationOutputPath :: Maybe StorePath
derivationOutputPath = Maybe StorePath
path,
                          derivationOutputDetail :: DerivationOutputDetail
derivationOutputDetail = DerivationOutputDetail
detail
                        }
                        forall a. a -> [a] -> [a]
:
                    )
          )
            forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> IO [DerivationOutput]
continue

deleteDerivationOutputsIterator :: Ptr DerivationOutputsIterator -> IO ()
deleteDerivationOutputsIterator :: Ptr DerivationOutputsIterator -> IO ()
deleteDerivationOutputsIterator Ptr DerivationOutputsIterator
a = [C.block| void { delete $(DerivationOutputsIterator *a); }|]

getDerivationPlatform :: Derivation -> IO ByteString
getDerivationPlatform :: Derivation -> IO ByteString
getDerivationPlatform Derivation
derivation =
  forall (m :: * -> *). MonadIO m => IO (Ptr CChar) -> m ByteString
unsafeMallocBS
    [C.exp| const char* {
       strdup($fptr-ptr:(Derivation *derivation)->platform.c_str())
     } |]

getDerivationBuilder :: Derivation -> IO ByteString
getDerivationBuilder :: Derivation -> IO ByteString
getDerivationBuilder Derivation
derivation =
  forall (m :: * -> *). MonadIO m => IO (Ptr CChar) -> m ByteString
unsafeMallocBS
    [C.exp| const char* {
       strdup($fptr-ptr:(Derivation *derivation)->builder.c_str())
     } |]

getDerivationArguments :: Derivation -> IO [ByteString]
getDerivationArguments :: Derivation -> IO [ByteString]
getDerivationArguments Derivation
derivation =
  forall a b c. IO a -> (a -> IO b) -> (a -> IO c) -> IO c
bracket
    [C.throwBlock| Strings* {
      Strings *r = new Strings();
      for (auto i : $fptr-ptr:(Derivation *derivation)->args) {
        r->push_back(i);
      }
      return r;
    }|]
    Ptr Strings -> IO ()
deleteStrings
    Ptr Strings -> IO [ByteString]
toByteStrings

getDerivationSources :: Store -> Derivation -> IO [StorePath]
getDerivationSources :: Store -> Derivation -> IO [StorePath]
getDerivationSources Store
_ = Derivation -> IO [StorePath]
getDerivationSources'

getDerivationSources' :: Derivation -> IO [StorePath]
getDerivationSources' :: Derivation -> IO [StorePath]
getDerivationSources' Derivation
derivation = forall a. IO a -> IO a
mask_ do
  StdVector (Ptr NixStorePath)
vec <-
    forall a b. HasEncapsulation a b => Ptr a -> IO b
moveToForeignPtrWrapper
      forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< [C.throwBlock| std::vector<nix::StorePath*>* {
        auto r = new std::vector<StorePath *>();
        for (auto s : $fptr-ptr:(Derivation *derivation)->inputSrcs)
          r->push_back(new StorePath(s));
        return r;
      }|]
  forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
(a -> f b) -> t a -> f (t b)
traverse Ptr NixStorePath -> IO StorePath
moveStorePath forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< forall a.
(HasStdVectorCopyable a, Storable a) =>
StdVector a -> IO [a]
Std.Vector.toList StdVector (Ptr NixStorePath)
vec

getDerivationInputs :: Store -> Derivation -> IO [(StorePath, [ByteString])]
getDerivationInputs :: Store -> Derivation -> IO [(StorePath, [ByteString])]
getDerivationInputs Store
_ = Derivation -> IO [(StorePath, [ByteString])]
getDerivationInputs'

getDerivationInputs' :: Derivation -> IO [(StorePath, [ByteString])]
getDerivationInputs' :: Derivation -> IO [(StorePath, [ByteString])]
getDerivationInputs' Derivation
derivation =
  forall a b c. IO a -> (a -> IO b) -> (a -> IO c) -> IO c
bracket
    [C.exp| DerivationInputsIterator* {
      new DerivationInputsIterator($fptr-ptr:(Derivation *derivation)->inputDrvs.begin())
    }|]
    Ptr DerivationInputsIterator -> IO ()
deleteDerivationInputsIterator
    forall a b. (a -> b) -> a -> b
$ \Ptr DerivationInputsIterator
i -> forall a. (a -> a) -> a
fix forall a b. (a -> b) -> a -> b
$ \IO [(StorePath, [ByteString])]
continue -> do
      Bool
isEnd <- (CBool
0 forall a. Eq a => a -> a -> Bool
/=) forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [C.exp| bool { *$(DerivationInputsIterator *i) == $fptr-ptr:(Derivation *derivation)->inputDrvs.end() }|]
      if Bool
isEnd
        then forall (f :: * -> *) a. Applicative f => a -> f a
pure []
        else do
          StorePath
name <-
            [C.throwBlock| nix::StorePath *{
              return new StorePath((*$(DerivationInputsIterator *i))->first);
            }|]
              forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Ptr NixStorePath -> IO StorePath
moveStorePath
          [ByteString]
outs <-
            forall a b c. IO a -> (a -> IO b) -> (a -> IO c) -> IO c
bracket
              [C.block| Strings*{ 
                Strings *r = new Strings();
                for (auto i : (*$(DerivationInputsIterator *i))->second) {
                  r->push_back(i);
                }
                return r;
              }|]
              Ptr Strings -> IO ()
deleteStrings
              Ptr Strings -> IO [ByteString]
toByteStrings
          [C.block| void { (*$(DerivationInputsIterator *i))++; }|]
          ((StorePath
name, [ByteString]
outs) forall a. a -> [a] -> [a]
:) forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> IO [(StorePath, [ByteString])]
continue

deleteDerivationInputsIterator :: Ptr DerivationInputsIterator -> IO ()
deleteDerivationInputsIterator :: Ptr DerivationInputsIterator -> IO ()
deleteDerivationInputsIterator Ptr DerivationInputsIterator
a = [C.block| void { delete $(DerivationInputsIterator *a); }|]

getDerivationEnv :: Derivation -> IO (Map ByteString ByteString)
getDerivationEnv :: Derivation -> IO (Map ByteString ByteString)
getDerivationEnv Derivation
derivation =
  [C.exp| StringPairs* { &($fptr-ptr:(Derivation *derivation)->env) }|]
    forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Ptr StringPairs -> IO (Map ByteString ByteString)
toByteStringMap

getDerivationOutputNames :: ForeignPtr Derivation -> IO [ByteString]
getDerivationOutputNames :: ForeignPtr Derivation -> IO [ByteString]
getDerivationOutputNames ForeignPtr Derivation
derivation =
  forall a b c. IO a -> (a -> IO b) -> (a -> IO c) -> IO c
bracket
    [C.throwBlock| Strings* {
      Strings *r = new Strings();
      for (auto i : $fptr-ptr:(Derivation *derivation)->outputs) {
        r->push_back(i.first);
      }
      return r;
    }|]
    Ptr Strings -> IO ()
deleteStrings
    Ptr Strings -> IO [ByteString]
toByteStrings

deleteStringPairs :: Ptr StringPairs -> IO ()
deleteStringPairs :: Ptr StringPairs -> IO ()
deleteStringPairs Ptr StringPairs
s = [C.block| void { delete $(StringPairs *s); }|]

deleteStrings :: Ptr Strings -> IO ()
deleteStrings :: Ptr Strings -> IO ()
deleteStrings Ptr Strings
s = [C.block| void { delete $(Strings *s); }|]

finalizeStrings :: FinalizerPtr Strings
{-# NOINLINE finalizeStrings #-}
finalizeStrings :: FinalizerPtr Strings
finalizeStrings =
  forall a. IO a -> a
unsafePerformIO
    [C.exp|
    void (*)(Strings *) {
      [](Strings *v) {
        delete v;
      }
    } |]

getStringsLength :: Ptr Strings -> IO C.CSize
getStringsLength :: Ptr Strings -> IO CSize
getStringsLength Ptr Strings
strings = [C.exp| size_t { $(Strings *strings)->size() }|]

toByteStrings :: Ptr Strings -> IO [ByteString]
toByteStrings :: Ptr Strings -> IO [ByteString]
toByteStrings Ptr Strings
strings = do
  Ptr StringsIterator
i <- [C.exp| StringsIterator *{ new StringsIterator($(Strings *strings)->begin()) } |]
  forall a. (a -> a) -> a
fix forall a b. (a -> b) -> a -> b
$ \IO [ByteString]
go -> do
    Bool
isEnd <- (CBool
0 forall a. Eq a => a -> a -> Bool
/=) forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [C.exp| bool { *$(StringsIterator *i) == $(Strings *strings)->end() }|]
    if Bool
isEnd
      then forall (f :: * -> *) a. Applicative f => a -> f a
pure []
      else do
        Ptr CChar
s <- [C.exp| const char*{ strdup((*$(StringsIterator *i))->c_str()) }|]
        ByteString
bs <- Ptr CChar -> IO ByteString
BS.unsafePackMallocCString Ptr CChar
s
        [C.block| void { (*$(StringsIterator *i))++; }|]
        (ByteString
bs forall a. a -> [a] -> [a]
:) forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> IO [ByteString]
go

toByteStringMap :: Ptr StringPairs -> IO (Map ByteString ByteString)
toByteStringMap :: Ptr StringPairs -> IO (Map ByteString ByteString)
toByteStringMap Ptr StringPairs
strings =
  forall k a. Ord k => [(k, a)] -> Map k a
M.fromList forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> do
    Ptr StringPairsIterator
i <- [C.exp| StringPairsIterator *{ new StringPairsIterator($(StringPairs *strings)->begin()) } |]
    forall a. (a -> a) -> a
fix forall a b. (a -> b) -> a -> b
$ \IO [(ByteString, ByteString)]
go -> do
      Bool
isEnd <- (CBool
0 forall a. Eq a => a -> a -> Bool
/=) forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [C.exp| bool { *$(StringPairsIterator *i) == $(StringPairs *strings)->end() }|]
      if Bool
isEnd
        then forall (f :: * -> *) a. Applicative f => a -> f a
pure []
        else do
          Ptr CChar
k <- [C.exp| const char*{ strdup((*$(StringPairsIterator *i))->first.c_str()) }|]
          Ptr CChar
v <- [C.exp| const char*{ strdup((*$(StringPairsIterator *i))->second.c_str()) }|]
          ByteString
bk <- Ptr CChar -> IO ByteString
BS.unsafePackMallocCString Ptr CChar
k
          ByteString
bv <- Ptr CChar -> IO ByteString
BS.unsafePackMallocCString Ptr CChar
v
          [C.block| void { (*$(StringPairsIterator *i))++; }|]
          ((ByteString
bk, ByteString
bv) forall a. a -> [a] -> [a]
:) forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> IO [(ByteString, ByteString)]
go

withStrings :: (Ptr Strings -> IO a) -> IO a
withStrings :: forall a. (Ptr Strings -> IO a) -> IO a
withStrings =
  forall a b c. IO a -> (a -> IO b) -> (a -> IO c) -> IO c
bracket
    [C.exp| Strings *{ new Strings() }|]
    (\Ptr Strings
sp -> [C.block| void { delete $(Strings *sp); }|])

withStringsOf :: [ByteString] -> (Ptr Strings -> IO a) -> IO a
withStringsOf :: forall a. [ByteString] -> (Ptr Strings -> IO a) -> IO a
withStringsOf [ByteString]
paths Ptr Strings -> IO a
f =
  forall a. (Ptr Strings -> IO a) -> IO a
withStrings \Ptr Strings
strings -> do
    forall (t :: * -> *) (f :: * -> *) a b.
(Foldable t, Applicative f) =>
t a -> (a -> f b) -> f ()
for_ [ByteString]
paths (Ptr Strings -> ByteString -> IO ()
pushString Ptr Strings
strings)
    Ptr Strings -> IO a
f Ptr Strings
strings

pushString :: Ptr Strings -> ByteString -> IO ()
pushString :: Ptr Strings -> ByteString -> IO ()
pushString Ptr Strings
strings ByteString
s =
  [C.block| void { $(Strings *strings)->push_back($bs-cstr:s); }|]

copyClosure :: Store -> Store -> [StorePath] -> IO ()
copyClosure :: Store -> Store -> [StorePath] -> IO ()
copyClosure (Store Ptr (Ref NixStore)
src) (Store Ptr (Ref NixStore)
dest) [StorePath]
pathList = do
  (StdVector ForeignPtr (CStdVector (Ptr NixStorePath))
pathsVector') <- forall a. HasStdVectorCopyable a => [a] -> IO (StdVector a)
Std.Vector.fromList ([StorePath]
pathList forall (f :: * -> *) a b. Functor f => f a -> (a -> b) -> f b
<&> \(StorePath ForeignPtr NixStorePath
c) -> forall a. ForeignPtr a -> Ptr a
unsafeForeignPtrToPtr ForeignPtr NixStorePath
c)
  forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
withForeignPtr ForeignPtr (CStdVector (Ptr NixStorePath))
pathsVector' \Ptr (CStdVector (Ptr NixStorePath))
pathsVector ->
    [C.throwBlock| void {
      ReceiveInterrupts _;
      ref<Store> src = *$(refStore* src);
      ref<Store> dest = *$(refStore* dest);
      std::vector<nix::StorePath *> &pathsVector = *$(std::vector<nix::StorePath*>* pathsVector);

      StorePathSet pathSet;
      for (auto spp : pathsVector)
        pathSet.insert(*spp);

      StorePathSet closurePaths;
      src->computeFSClosure(pathSet, closurePaths);

      nix::copyPaths(*src, *dest, closurePaths);
    }|]
  forall (t :: * -> *) (f :: * -> *) a b.
(Foldable t, Applicative f) =>
t a -> (a -> f b) -> f ()
for_ [StorePath]
pathList (\(StorePath ForeignPtr NixStorePath
c) -> forall a. ForeignPtr a -> IO ()
touchForeignPtr ForeignPtr NixStorePath
c)

parseSecretKey :: ByteString -> IO (ForeignPtr SecretKey)
parseSecretKey :: ByteString -> IO (ForeignPtr SecretKey)
parseSecretKey ByteString
bs =
  [C.throwBlock| SecretKey* {
    return new SecretKey($bs-cstr:bs);
  }|]
    forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= forall a. FinalizerPtr a -> Ptr a -> IO (ForeignPtr a)
newForeignPtr FinalizerPtr SecretKey
finalizeSecretKey

finalizeSecretKey :: FinalizerPtr SecretKey
{-# NOINLINE finalizeSecretKey #-}
finalizeSecretKey :: FinalizerPtr SecretKey
finalizeSecretKey =
  forall a. IO a -> a
unsafePerformIO
    [C.exp|
    void (*)(SecretKey *) {
      [](SecretKey *v) {
        delete v;
      }
    } |]

signPath ::
  Store ->
  -- | Secret signing key
  Ptr SecretKey ->
  -- | Store path
  StorePath ->
  -- | False if the signature was already present, True if the signature was added
  IO Bool
signPath :: Store -> Ptr SecretKey -> StorePath -> IO Bool
signPath (Store Ptr (Ref NixStore)
store) Ptr SecretKey
secretKey (StorePath ForeignPtr NixStorePath
path) =
  (forall a. Eq a => a -> a -> Bool
== CInt
1) forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> do
    [C.throwBlock| int {
    ReceiveInterrupts _;
    nix::ref<nix::Store> store = *$(refStore *store);
    const StorePath &storePath = *$fptr-ptr:(nix::StorePath *path);
    const SecretKey &secretKey = *$(SecretKey *secretKey);
    auto currentInfo = store->queryPathInfo(storePath);

    auto info2(*currentInfo);
    info2.sigs.clear();
    info2.sign(*store, secretKey);
    assert(!info2.sigs.empty());
    auto sig = *info2.sigs.begin();

    if (currentInfo->sigs.count(sig)) {
      return 0;
    } else {
      store->addSignatures(storePath, info2.sigs);
      return 1;
    }
  }|]

-- | Follow symlinks to the store and chop off the parts after the top-level store name
followLinksToStorePath :: Store -> ByteString -> IO StorePath
followLinksToStorePath :: Store -> ByteString -> IO StorePath
followLinksToStorePath (Store Ptr (Ref NixStore)
store) ByteString
bs =
  Ptr NixStorePath -> IO StorePath
moveStorePath
    forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< [C.throwBlock| nix::StorePath *{
      ReceiveInterrupts _;
      Store &store = **$(refStore* store);
      std::string s = std::string($bs-ptr:bs, $bs-len:bs);
      return new StorePath(store.followLinksToStorePath(s));
    }|]

-- | Whether a path exists and is registered.
isValidPath :: Store -> StorePath -> IO Bool
isValidPath :: Store -> StorePath -> IO Bool
isValidPath (Store Ptr (Ref NixStore)
store) StorePath
path =
  [C.throwBlock| bool {
    ReceiveInterrupts _;
    Store &store = **$(refStore* store);
    StorePath &path = *$fptr-ptr:(nix::StorePath *path);
    return store.isValidPath(path);
  }|]
    forall (f :: * -> *) a b. Functor f => f a -> (a -> b) -> f b
<&> (forall a. Eq a => a -> a -> Bool
/= CBool
0)

queryPathInfo ::
  Store ->
  -- | Exact store path, not a subpath
  StorePath ->
  -- | ValidPathInfo or exception
  IO (ForeignPtr (Ref ValidPathInfo))
queryPathInfo :: Store -> StorePath -> IO (ForeignPtr (Ref ValidPathInfo))
queryPathInfo (Store Ptr (Ref NixStore)
store) (StorePath ForeignPtr NixStorePath
path) = do
  Ptr (Ref ValidPathInfo)
vpi <-
    [C.throwBlock| refValidPathInfo* {
      ReceiveInterrupts _;
      Store &store = **$(refStore* store);
      StorePath &path = *$fptr-ptr:(nix::StorePath *path);
      return new refValidPathInfo(store.queryPathInfo(path));
    }|]
  forall a. FinalizerPtr a -> Ptr a -> IO (ForeignPtr a)
newForeignPtr FinalizerPtr (Ref ValidPathInfo)
finalizeRefValidPathInfo Ptr (Ref ValidPathInfo)
vpi

finalizeRefValidPathInfo :: FinalizerPtr (Ref ValidPathInfo)
{-# NOINLINE finalizeRefValidPathInfo #-}
finalizeRefValidPathInfo :: FinalizerPtr (Ref ValidPathInfo)
finalizeRefValidPathInfo =
  forall a. IO a -> a
unsafePerformIO
    [C.exp|
      void (*)(refValidPathInfo *) {
        [](refValidPathInfo *v){ delete v; }
      }|]

-- | The narSize field of a ValidPathInfo struct. Source: path-info.hh / store-api.hh
validPathInfoNarSize :: ForeignPtr (Ref ValidPathInfo) -> Int64
validPathInfoNarSize :: ForeignPtr (Ref ValidPathInfo) -> Int64
validPathInfoNarSize ForeignPtr (Ref ValidPathInfo)
vpi =
  forall a b. (Integral a, Num b) => a -> b
fromIntegral forall a b. (a -> b) -> a -> b
$
    forall a. Integral a => a -> Integer
toInteger
      [C.pure| long
        { (*$fptr-ptr:(refValidPathInfo* vpi))->narSize }
      |]

-- | Copy the narHash field of a ValidPathInfo struct. Source: path-info.hh / store-api.hh
validPathInfoNarHash32 :: ForeignPtr (Ref ValidPathInfo) -> IO ByteString
validPathInfoNarHash32 :: ForeignPtr (Ref ValidPathInfo) -> IO ByteString
validPathInfoNarHash32 ForeignPtr (Ref ValidPathInfo)
vpi =
  Ptr CChar -> IO ByteString
unsafePackMallocCString
    forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< [C.block| const char *{ 
      std::string s((*$fptr-ptr:(refValidPathInfo* vpi))->narHash.to_string(nix::Base32, true));
      return strdup(s.c_str()); }
    |]

-- | Deriver field of a ValidPathInfo struct. Source: store-api.hh
validPathInfoDeriver :: Store -> ForeignPtr (Ref ValidPathInfo) -> IO (Maybe StorePath)
validPathInfoDeriver :: Store -> ForeignPtr (Ref ValidPathInfo) -> IO (Maybe StorePath)
validPathInfoDeriver Store
_ = ForeignPtr (Ref ValidPathInfo) -> IO (Maybe StorePath)
validPathInfoDeriver'

validPathInfoDeriver' :: ForeignPtr (Ref ValidPathInfo) -> IO (Maybe StorePath)
validPathInfoDeriver' :: ForeignPtr (Ref ValidPathInfo) -> IO (Maybe StorePath)
validPathInfoDeriver' ForeignPtr (Ref ValidPathInfo)
vpi =
  Ptr NixStorePath -> IO (Maybe StorePath)
moveStorePathMaybe
    forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< [C.throwBlock| nix::StorePath * {
      std::optional<StorePath> deriver = (*$fptr-ptr:(refValidPathInfo* vpi))->deriver;
      return deriver ? new StorePath(*deriver) : nullptr;
    }|]

-- | References field of a ValidPathInfo struct. Source: store-api.hh
validPathInfoReferences :: Store -> ForeignPtr (Ref ValidPathInfo) -> IO [StorePath]
validPathInfoReferences :: Store -> ForeignPtr (Ref ValidPathInfo) -> IO [StorePath]
validPathInfoReferences Store
_ = ForeignPtr (Ref ValidPathInfo) -> IO [StorePath]
validPathInfoReferences'

validPathInfoReferences' :: ForeignPtr (Ref ValidPathInfo) -> IO [StorePath]
validPathInfoReferences' :: ForeignPtr (Ref ValidPathInfo) -> IO [StorePath]
validPathInfoReferences' ForeignPtr (Ref ValidPathInfo)
vpi = do
  StdVector (Ptr NixStorePath)
sps <-
    forall a b. HasEncapsulation a b => Ptr a -> IO b
moveToForeignPtrWrapper
      forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< [C.throwBlock| std::vector<nix::StorePath *>* {
        auto sps = new std::vector<nix::StorePath *>();
        for (auto sp : (*$fptr-ptr:(refValidPathInfo* vpi))->references)
          sps->push_back(new StorePath(sp));
        return sps;
      }|]
  [Ptr NixStorePath]
l <- forall a.
(HasStdVectorCopyable a, Storable a) =>
StdVector a -> IO [a]
Std.Vector.toList StdVector (Ptr NixStorePath)
sps
  forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
t a -> (a -> f b) -> f (t b)
for [Ptr NixStorePath]
l Ptr NixStorePath -> IO StorePath
moveStorePath

----- computeFSClosure -----
data ClosureParams = ClosureParams
  { ClosureParams -> Bool
flipDirection :: Bool,
    ClosureParams -> Bool
includeOutputs :: Bool,
    ClosureParams -> Bool
includeDerivers :: Bool
  }

defaultClosureParams :: ClosureParams
defaultClosureParams :: ClosureParams
defaultClosureParams =
  ClosureParams
    { flipDirection :: Bool
flipDirection = Bool
False,
      includeOutputs :: Bool
includeOutputs = Bool
False,
      includeDerivers :: Bool
includeDerivers = Bool
False
    }

computeFSClosure :: Store -> ClosureParams -> StdSet NixStorePath -> IO (StdSet NixStorePath)
computeFSClosure :: Store
-> ClosureParams -> StdSet NixStorePath -> IO (StdSet NixStorePath)
computeFSClosure (Store Ptr (Ref NixStore)
store) ClosureParams
params (Std.Set.StdSet ForeignPtr (CStdSet NixStorePath)
startingSet) = do
  let countTrue :: Bool -> C.CInt
      countTrue :: Bool -> CInt
countTrue Bool
True = CInt
1
      countTrue Bool
False = CInt
0
      flipDir :: CInt
flipDir = Bool -> CInt
countTrue forall a b. (a -> b) -> a -> b
$ ClosureParams -> Bool
flipDirection ClosureParams
params
      inclOut :: CInt
inclOut = Bool -> CInt
countTrue forall a b. (a -> b) -> a -> b
$ ClosureParams -> Bool
includeOutputs ClosureParams
params
      inclDrv :: CInt
inclDrv = Bool -> CInt
countTrue forall a b. (a -> b) -> a -> b
$ ClosureParams -> Bool
includeDerivers ClosureParams
params
  ret :: StdSet NixStorePath
ret@(Std.Set.StdSet ForeignPtr (CStdSet NixStorePath)
retSet) <- forall a. HasStdSet a => IO (StdSet a)
Std.Set.new
  [C.throwBlock| void {
    ReceiveInterrupts _;
    Store &store = **$(refStore* store);
    StorePathSet &ret = *$fptr-ptr:(std::set<nix::StorePath>* retSet);
    store.computeFSClosure(*$fptr-ptr:(std::set<nix::StorePath>* startingSet), ret,
      $(int flipDir), $(int inclOut), $(int inclDrv));
  }|]
  forall (f :: * -> *) a. Applicative f => a -> f a
pure StdSet NixStorePath
ret

withPtr' :: (Coercible a' (ForeignPtr a)) => a' -> (Ptr a -> IO b) -> IO b
withPtr' :: forall a' a b.
Coercible a' (ForeignPtr a) =>
a' -> (Ptr a -> IO b) -> IO b
withPtr' a'
p = forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
withForeignPtr (coerce :: forall a b. Coercible a b => a -> b
coerce a'
p)