{-# 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 "<nix/hash.hh>"

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

#if NIX_IS_AT_LEAST(2,19,0)

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

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

#endif

#if ! NIX_IS_AT_LEAST(2,20,0)

C.include "<nix/nar-info-disk-cache.hh>"

#endif

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 = ((Ptr a -> m b) -> Ptr a -> m (Maybe b))
-> Ptr a -> (Ptr a -> m b) -> m (Maybe b)
forall a b c. (a -> b -> c) -> b -> a -> c
flip (Ptr a -> m b) -> Ptr a -> m (Maybe b)
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 Ptr a -> Ptr a -> Bool
forall a. Eq a => a -> a -> Bool
== Ptr a
forall a. Ptr a
nullPtr then Maybe b -> m (Maybe b)
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Maybe b
forall a. Maybe a
Nothing else b -> Maybe b
forall a. a -> Maybe a
Just (b -> Maybe b) -> m b -> m (Maybe b)
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 =
  IO (Ptr (Ref NixStore)) -> IO Store
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 <- m (UnliftIO m)
forall (m :: * -> *). MonadUnliftIO m => m (UnliftIO m)
askUnliftIO
  IO a -> m a
forall a. IO a -> m a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO a -> m a) -> IO a -> m a
forall a b. (a -> b) -> a -> b
$ (Store -> IO a) -> IO a
forall r. (Store -> IO r) -> IO r
withStore' ((Store -> IO a) -> IO a) -> (Store -> IO a) -> IO a
forall a b. (a -> b) -> a -> b
$ \Store
a -> m a -> IO 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' =
  IO Store -> (Store -> IO ()) -> (Store -> IO r) -> IO r
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) <- m (UnliftIO m)
forall (m :: * -> *). MonadUnliftIO m => m (UnliftIO m)
askUnliftIO
  IO r -> m r
forall a. IO a -> m a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO r -> m r) -> IO r -> m r
forall a b. (a -> b) -> a -> b
$
    IO (Ptr (Ref NixStore))
-> (Ptr (Ref NixStore) -> IO ())
-> (Ptr (Ref NixStore) -> IO r)
-> IO r
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) } |])
      (m r -> IO r
forall a. m a -> IO a
unlift (m r -> IO r)
-> (Ptr (Ref NixStore) -> m r) -> Ptr (Ref NixStore) -> IO r
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Store -> m r
f (Store -> m r)
-> (Ptr (Ref NixStore) -> Store) -> Ptr (Ref NixStore) -> m r
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) =
  IO (Ptr CChar) -> m ByteString
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) =
  IO (Ptr CChar) -> m ByteString
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) =
  CInt -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral
    (CInt -> Int) -> IO CInt -> IO Int
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 =
  CInt -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral
    (CInt -> Int) -> IO CInt -> IO Int
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 =
  IO (FinalizerPtr NixStorePath) -> FinalizerPtr NixStorePath
forall a. IO a -> a
unsafePerformIO
    IO (FinalizerPtr NixStorePath)
[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 (ForeignPtr NixStorePath -> StorePath)
-> IO (ForeignPtr NixStorePath) -> IO StorePath
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> FinalizerPtr NixStorePath
-> Ptr NixStorePath -> IO (ForeignPtr NixStorePath)
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 = (Ptr NixStorePath -> IO StorePath)
-> Ptr NixStorePath -> IO (Maybe StorePath)
forall (m :: * -> *) a b.
Applicative m =>
(Ptr a -> m b) -> Ptr a -> m (Maybe b)
traverseNonNull ((Ptr NixStorePath -> IO StorePath)
 -> Ptr NixStorePath -> IO (Maybe StorePath))
-> (Ptr NixStorePath -> IO StorePath)
-> Ptr NixStorePath
-> IO (Maybe StorePath)
forall a b. (a -> b) -> a -> b
$ (ForeignPtr NixStorePath -> StorePath)
-> IO (ForeignPtr NixStorePath) -> IO StorePath
forall a b. (a -> b) -> IO a -> IO b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ForeignPtr NixStorePath -> StorePath
StorePath (IO (ForeignPtr NixStorePath) -> IO StorePath)
-> (Ptr NixStorePath -> IO (ForeignPtr NixStorePath))
-> Ptr NixStorePath
-> IO StorePath
forall b c a. (b -> c) -> (a -> b) -> a -> c
. FinalizerPtr NixStorePath
-> Ptr NixStorePath -> IO (ForeignPtr NixStorePath)
forall a. FinalizerPtr a -> Ptr a -> IO (ForeignPtr a)
newForeignPtr FinalizerPtr NixStorePath
finalizeStorePath

instance Prelude.Show StorePath where
  show :: StorePath -> String
show StorePath
storePath = IO String -> String
forall a. IO a -> a
unsafePerformIO do
    ByteString
bs <-
      Ptr CChar -> IO ByteString
BS.unsafePackMallocCString
        (Ptr CChar -> IO ByteString) -> IO (Ptr CChar) -> IO ByteString
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());
        }|]
    String -> IO String
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (String -> IO String) -> String -> IO String
forall a b. (a -> b) -> a -> b
$ Text -> String
forall a b. ConvertText a b => a -> b
toS (Text -> String) -> Text -> String
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 = StorePath -> StorePath -> Ordering
forall a. Ord a => a -> a -> Ordering
compare StorePath
a StorePath
b Ordering -> Ordering -> Bool
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) =
    CInt -> CInt -> Ordering
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
    (Ptr NixStorePath -> IO StorePath)
-> IO (Ptr NixStorePath) -> IO StorePath
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
    (Ptr NixStorePath -> IO StorePath)
-> IO (Ptr NixStorePath) -> IO StorePath
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
    (Ptr CChar -> IO ByteString) -> IO (Ptr CChar) -> IO ByteString
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
    (Ptr CChar -> IO ByteString) -> IO (Ptr CChar) -> IO ByteString
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
    (Ptr CChar -> IO ByteString) -> IO (Ptr CChar) -> IO ByteString
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 (ForeignPtr NixStorePathWithOutputs -> StorePathWithOutputs)
-> IO (ForeignPtr NixStorePathWithOutputs)
-> IO StorePathWithOutputs
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> FinalizerPtr NixStorePathWithOutputs
-> Ptr NixStorePathWithOutputs
-> IO (ForeignPtr NixStorePathWithOutputs)
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 =
  IO (FinalizerPtr NixStorePathWithOutputs)
-> FinalizerPtr NixStorePathWithOutputs
forall a. IO a -> a
unsafePerformIO
    IO (FinalizerPtr NixStorePathWithOutputs)
[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 <- IO (StdSet CStdString)
forall a. HasStdSet a => IO (StdSet a)
Std.Set.new
  [ByteString] -> (ByteString -> IO ()) -> IO ()
forall (t :: * -> *) (f :: * -> *) a b.
(Foldable t, Applicative f) =>
t a -> (a -> f b) -> f ()
for_ [ByteString]
outputs (\ByteString
o -> ByteString -> (Ptr CStdString -> IO ()) -> IO ()
forall a. ByteString -> (Ptr CStdString -> IO a) -> IO a
Std.String.withString ByteString
o (StdSet CStdString -> Ptr CStdString -> IO ()
forall a. HasStdSet a => StdSet a -> Ptr a -> IO ()
Std.Set.insertP StdSet CStdString
set))
  Ptr NixStorePathWithOutputs -> IO StorePathWithOutputs
forall a b. HasEncapsulation a b => Ptr a -> IO b
moveToForeignPtrWrapper
    (Ptr NixStorePathWithOutputs -> IO StorePathWithOutputs)
-> IO (Ptr NixStorePathWithOutputs) -> IO StorePathWithOutputs
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 = IO StorePath -> IO StorePath
forall a. IO a -> IO a
mask_ do
  Ptr NixStorePath -> IO StorePath
forall a b. HasEncapsulation a b => Ptr a -> IO b
moveToForeignPtrWrapper
    (Ptr NixStorePath -> IO StorePath)
-> IO (Ptr NixStorePath) -> IO StorePath
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 = IO [ByteString] -> IO [ByteString]
forall a. IO a -> IO a
mask_ do
  (Ptr CStdString -> IO ByteString)
-> [Ptr CStdString] -> IO [ByteString]
forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
(a -> f b) -> t a -> f (t b)
forall (f :: * -> *) a b.
Applicative f =>
(a -> f b) -> [a] -> f [b]
traverse Ptr CStdString -> IO ByteString
Std.String.moveToByteString ([Ptr CStdString] -> IO [ByteString])
-> IO [Ptr CStdString] -> IO [ByteString]
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< StdVector CStdString -> IO [Ptr CStdString]
forall a. HasStdVector a => StdVector a -> IO [Ptr a]
toListP (StdVector CStdString -> IO [Ptr CStdString])
-> IO (StdVector CStdString) -> IO [Ptr CStdString]
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< Ptr (CStdVector CStdString) -> IO (StdVector CStdString)
forall a b. HasEncapsulation a b => Ptr a -> IO b
moveToForeignPtrWrapper
    (Ptr (CStdVector CStdString) -> IO (StdVector CStdString))
-> IO (Ptr (CStdVector CStdString)) -> IO (StdVector CStdString)
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 (StdVector NixStorePathWithOutputs -> IO ())
-> IO (StdVector NixStorePathWithOutputs) -> IO ()
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< [StorePathWithOutputs] -> IO (StdVector NixStorePathWithOutputs)
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 = (ForeignPtr Derivation -> Derivation)
-> IO (ForeignPtr Derivation) -> IO Derivation
forall a b. (a -> b) -> IO a -> IO b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ForeignPtr Derivation -> Derivation
Derivation (IO (ForeignPtr Derivation) -> IO Derivation)
-> (Ptr Derivation -> IO (ForeignPtr Derivation))
-> Ptr Derivation
-> IO Derivation
forall b c a. (b -> c) -> (a -> b) -> a -> c
. FinalizerPtr Derivation
-> Ptr Derivation -> IO (ForeignPtr Derivation)
forall a. FinalizerPtr a -> Ptr a -> IO (ForeignPtr a)
newForeignPtr FinalizerPtr Derivation
finalizeDerivation

finalizeDerivation :: FinalizerPtr C.Derivation
{-# NOINLINE finalizeDerivation #-}
finalizeDerivation :: FinalizerPtr Derivation
finalizeDerivation =
  IO (FinalizerPtr Derivation) -> FinalizerPtr Derivation
forall a. IO a -> a
unsafePerformIO
    IO (FinalizerPtr Derivation)
[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
  Ptr Derivation -> IO Derivation
forall a b. HasEncapsulation a b => Ptr a -> IO b
moveToForeignPtrWrapper
    (Ptr Derivation -> IO Derivation)
-> IO (Ptr Derivation) -> IO Derivation
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
  Ptr Derivation -> IO Derivation
forall a b. HasEncapsulation a b => Ptr a -> IO b
moveToForeignPtrWrapper
    (Ptr Derivation -> IO Derivation)
-> IO (Ptr Derivation) -> IO Derivation
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
    (Ptr CChar -> IO ByteString) -> IO (Ptr CChar) -> IO ByteString
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
(DerivationOutput -> DerivationOutput -> Bool)
-> (DerivationOutput -> DerivationOutput -> Bool)
-> Eq DerivationOutput
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: DerivationOutput -> DerivationOutput -> Bool
== :: DerivationOutput -> DerivationOutput -> Bool
$c/= :: DerivationOutput -> DerivationOutput -> Bool
/= :: DerivationOutput -> DerivationOutput -> Bool
Eq, Int -> DerivationOutput -> ShowS
[DerivationOutput] -> ShowS
DerivationOutput -> String
(Int -> DerivationOutput -> ShowS)
-> (DerivationOutput -> String)
-> ([DerivationOutput] -> ShowS)
-> Show DerivationOutput
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> DerivationOutput -> ShowS
showsPrec :: Int -> DerivationOutput -> ShowS
$cshow :: DerivationOutput -> String
show :: DerivationOutput -> String
$cshowList :: [DerivationOutput] -> ShowS
showList :: [DerivationOutput] -> ShowS
Show)

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

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

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

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

-- | See @hash.hh@
data HashType = MD5 | SHA1 | SHA256 | SHA512
  deriving (HashType -> HashType -> Bool
(HashType -> HashType -> Bool)
-> (HashType -> HashType -> Bool) -> Eq HashType
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: HashType -> HashType -> Bool
== :: HashType -> HashType -> Bool
$c/= :: HashType -> HashType -> Bool
/= :: HashType -> HashType -> Bool
Eq, Int -> HashType -> ShowS
[HashType] -> ShowS
HashType -> String
(Int -> HashType -> ShowS)
-> (HashType -> String) -> ([HashType] -> ShowS) -> Show HashType
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> HashType -> ShowS
showsPrec :: Int -> HashType -> ShowS
$cshow :: HashType -> String
show :: HashType -> String
$cshowList :: [HashType] -> ShowS
showList :: [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) =
  IO (Ptr DerivationOutputsIterator)
-> (Ptr DerivationOutputsIterator -> IO ())
-> (Ptr DerivationOutputsIterator -> IO [DerivationOutput])
-> IO [DerivationOutput]
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
    ((Ptr DerivationOutputsIterator -> IO [DerivationOutput])
 -> IO [DerivationOutput])
-> (Ptr DerivationOutputsIterator -> IO [DerivationOutput])
-> IO [DerivationOutput]
forall a b. (a -> b) -> a -> b
$ \Ptr DerivationOutputsIterator
i -> (IO [DerivationOutput] -> IO [DerivationOutput])
-> IO [DerivationOutput]
forall a. (a -> a) -> a
fix ((IO [DerivationOutput] -> IO [DerivationOutput])
 -> IO [DerivationOutput])
-> (IO [DerivationOutput] -> IO [DerivationOutput])
-> IO [DerivationOutput]
forall a b. (a -> b) -> a -> b
$ \IO [DerivationOutput]
continue -> do
      Bool
isEnd <- (CBool
0 CBool -> CBool -> Bool
forall a. Eq a => a -> a -> Bool
/=) (CBool -> Bool) -> IO CBool -> IO 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 [DerivationOutput] -> IO [DerivationOutput]
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure []
        else
          ( IO ([DerivationOutput] -> [DerivationOutput])
-> IO ([DerivationOutput] -> [DerivationOutput])
forall a. IO a -> IO a
mask_ do
              (Ptr (Ptr CChar) -> IO ([DerivationOutput] -> [DerivationOutput]))
-> IO ([DerivationOutput] -> [DerivationOutput])
forall a b. Storable a => (Ptr a -> IO b) -> IO b
alloca \Ptr (Ptr CChar)
nameP -> (Ptr (Ptr NixStorePath)
 -> IO ([DerivationOutput] -> [DerivationOutput]))
-> IO ([DerivationOutput] -> [DerivationOutput])
forall a b. Storable a => (Ptr a -> IO b) -> IO b
alloca \Ptr (Ptr NixStorePath)
pathP -> (Ptr CInt -> IO ([DerivationOutput] -> [DerivationOutput]))
-> IO ([DerivationOutput] -> [DerivationOutput])
forall a b. Storable a => (Ptr a -> IO b) -> IO b
alloca \Ptr CInt
typP -> (Ptr CInt -> IO ([DerivationOutput] -> [DerivationOutput]))
-> IO ([DerivationOutput] -> [DerivationOutput])
forall a b. Storable a => (Ptr a -> IO b) -> IO b
alloca \Ptr CInt
fimP ->
                (Ptr CInt -> IO ([DerivationOutput] -> [DerivationOutput]))
-> IO ([DerivationOutput] -> [DerivationOutput])
forall a b. Storable a => (Ptr a -> IO b) -> IO b
alloca \Ptr CInt
hashTypeP -> (Ptr (Ptr CChar) -> IO ([DerivationOutput] -> [DerivationOutput]))
-> IO ([DerivationOutput] -> [DerivationOutput])
forall a b. Storable a => (Ptr a -> IO b) -> IO b
alloca \Ptr (Ptr CChar)
hashValueP -> (Ptr CInt -> IO ([DerivationOutput] -> [DerivationOutput]))
-> IO ([DerivationOutput] -> [DerivationOutput])
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 {
#if NIX_IS_AT_LEAST(2, 18, 0)
                      [&](DerivationOutput::InputAddressed doi) -> void {
                        typ = 0;
                        path = new StorePath(doi.path);
                      },
                      [&](DerivationOutput::CAFixed dof) -> void {
                        typ = 1;
                        path = new StorePath(dof.path(store, $fptr-ptr:(Derivation *derivation)->name, nameString));
                        std::visit(overloaded {
                          [&](nix::FileIngestionMethod fim_) -> void {
                            switch (fim_) {
                              case nix::FileIngestionMethod::Flat:
                                fim = 0;
                                break;
                              case nix::FileIngestionMethod::Recursive:
                                fim = 1;
                                break;
                              default:
                                fim = -1;
                                break;
                            }
                          },
                          [&](nix::TextIngestionMethod) -> void {
                            // FIXME (RFC 92)
                            fim = -1;
                          }
                        }, dof.ca.method.raw);

                        const Hash & hash = dof.ca.hash;

#if NIX_IS_AT_LEAST(2, 20, 0)
                        switch (hash.algo) {
                          case HashAlgorithm::MD5:
                            hashType = 0;
                            break;
                          case HashAlgorithm::SHA1:
                            hashType = 1;
                            break;
                          case HashAlgorithm::SHA256:
                            hashType = 2;
                            break;
                          case HashAlgorithm::SHA512:
                            hashType = 3;
                            break;
#else
                        switch (hash.type) {
                          case htMD5:
                            hashType = 0;
                            break;
                          case htSHA1:
                            hashType = 1;
                            break;
                          case htSHA256:
                            hashType = 2;
                            break;
                          case htSHA512:
                            hashType = 3;
                            break;
#endif
                          default:
                            hashType = -1;
                            break;
                        }
                        hashSize = hash.hashSize;
                        hashValue = (char*)malloc(hashSize);
                        std::memcpy((void*)(hashValue),
                                    (void*)(hash.hash),
                                    hashSize);
                      },
                      [&](DerivationOutput::CAFloating dof) -> void {
                        typ = 2;
                        std::visit(overloaded {
                          [&](nix::FileIngestionMethod fim_) -> void {
                            switch (fim_) {
                              case nix::FileIngestionMethod::Flat:
                                fim = 0;
                                break;
                              case nix::FileIngestionMethod::Recursive:
                                fim = 1;
                                break;
                              default:
                                fim = -1;
                                break;
                            }
                          },
                          [&](nix::TextIngestionMethod) -> void {
                            // FIXME (RFC 92)
                            fim = -1;
                          }
                        }, dof.method.raw);
#if NIX_IS_AT_LEAST(2, 20, 0)
                        switch (dof.hashAlgo) {
                          case HashAlgorithm::MD5:
                            hashType = 0;
                            break;
                          case HashAlgorithm::SHA1:
                            hashType = 1;
                            break;
                          case HashAlgorithm::SHA256:
                            hashType = 2;
                            break;
                          case HashAlgorithm::SHA512:
                            hashType = 3;
                            break;
#else
                        switch (dof.hashType) {
                          case htMD5:
                            hashType = 0;
                            break;
                          case htSHA1:
                            hashType = 1;
                            break;
                          case htSHA256:
                            hashType = 2;
                            break;
                          case htSHA512:
                            hashType = 3;
                            break;
#endif
                          default:
                            hashType = -1;
                            break;
                        }
                      },
                      [&](DerivationOutput::Deferred) -> void {
                        typ = 3;
                      },
                      [&](DerivationOutput::Impure) -> void {
                        typ = 4;
                      },
                    },
                    i->second.raw
#else
                      [&](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));
#if NIX_IS_AT_LEAST(2, 16, 0)
                        std::visit(overloaded {
                          [&](nix::FileIngestionMethod fim_) -> void {
                            switch (fim_) {
                              case nix::FileIngestionMethod::Flat:
                                fim = 0;
                                break;
                              case nix::FileIngestionMethod::Recursive:
                                fim = 1;
                                break;
                              default:
                                fim = -1;
                                break;
                            }
                          },
                          [&](nix::TextIngestionMethod) -> void {
                            // FIXME (RFC 92)
                            fim = -1;
                          }
#  if NIX_IS_AT_LEAST(2, 17, 0)
                        }, dof.ca.method.raw);
#  else
                        }, dof.ca.getMethod().raw);
#  endif
#else
                        switch (dof.hash.method) {
                          case nix::FileIngestionMethod::Flat:
                            fim = 0;
                            break;
                          case nix::FileIngestionMethod::Recursive:
                            fim = 1;
                            break;
                          default:
                            fim = -1;
                            break;
                        }
#endif

#if NIX_IS_AT_LEAST(2, 17, 0)
                        const Hash & hash = dof.ca.hash;
#elif NIX_IS_AT_LEAST(2, 16, 0)
                        const Hash & hash = dof.ca.getHash();
#else
                        const Hash & hash = dof.hash.hash;
#endif
                        switch (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 = hash.hashSize;
                        hashValue = (char*)malloc(hashSize);
                        std::memcpy((void*)(hashValue),
                                    (void*)(hash.hash),
                                    hashSize);
                      },
                      [&](DerivationOutputCAFloating dof) -> void {
                        typ = 2;
#if NIX_IS_AT_LEAST(2, 16, 0)
                        std::visit(overloaded {
                          [&](nix::FileIngestionMethod fim_) -> void {
                            switch (fim_) {
                              case nix::FileIngestionMethod::Flat:
                                fim = 0;
                                break;
                              case nix::FileIngestionMethod::Recursive:
                                fim = 1;
                                break;
                              default:
                                fim = -1;
                                break;
                            }
                          },
                          [&](nix::TextIngestionMethod) -> void {
                            // FIXME (RFC 92)
                            fim = -1;
                          }
                        }, dof.method.raw);
#else
                        switch (dof.method) {
                          case nix::FileIngestionMethod::Flat:
                            fim = 0;
                            break;
                          case nix::FileIngestionMethod::Recursive:
                            fim = 1;
                            break;
                          default:
                            fim = -1;
                            break;
                        }
#endif
                        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
#endif
                    );
                    i++;
                  }|]
                  name <- unsafePackMallocCString =<< peek nameP
                  path <- moveStorePathMaybe =<< peek pathP
                  typ <- peek typP
                  let getFileIngestionMethod = peek fimP <&> \case 0 -> Flat; 1 -> Recursive; _ -> panic "getDerivationOutputs: unknown fim"
                      getHashType =
                        peek hashTypeP <&> \case
                          0 -> MD5
                          1 -> SHA1
                          2 -> SHA256
                          3 -> SHA512
                          _ -> panic "getDerivationOutputs: unknown hashType"
                  detail <- case typ of
                    0 -> pure $ DerivationOutputInputAddressed (fromMaybe (panic "getDerivationOutputs: impossible DOIA path missing") path)
                    1 -> do
                      hashValue <- peek hashValueP
                      hashSize <- peek hashSizeP
                      hashString <- SBS.packCStringLen (hashValue, fromIntegral hashSize)
                      free hashValue
                      hashType <- getHashType
                      fim <- getFileIngestionMethod
                      pure $ DerivationOutputCAFixed (FixedOutputHash fim (Hash hashType hashString)) (fromMaybe (panic "getDerivationOutputs: impossible DOCF path missing") path)
                    2 -> do
                      hashType <- getHashType
                      fim <- getFileIngestionMethod
                      pure $ DerivationOutputCAFloating fim hashType
                    3 -> pure DerivationOutputDeferred
                    4 -> panic "getDerivationOutputs: impure derivations not supported yet"
                    _ -> panic "getDerivationOutputs: impossible getDerivationOutputs typ"
                  pure
                    ( DerivationOutput
                        { derivationOutputName = name,
                          derivationOutputPath = path,
                          derivationOutputDetail = detail
                        }
                        :
                    )
          )
            <*> continue

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

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

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

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

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

getDerivationSources' :: Derivation -> IO [StorePath]
getDerivationSources' derivation = mask_ do
  vec <-
    moveToForeignPtrWrapper
      =<< [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;
      }|]
  traverse moveStorePath =<< Std.Vector.toList vec

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

-- | Get the inputs of a derivation, ignoring dependencies on outputs of outputs (RFC 92 inputs).
getDerivationInputs' :: Derivation -> IO [(StorePath, [ByteString])]
#if NIX_IS_AT_LEAST(2, 18, 0)
getDerivationInputs' derivation =
  bracket
    [C.exp| DerivationInputsIterator* {
      new DerivationInputsIterator($fptr-ptr:(Derivation *derivation)->inputDrvs.map.begin())
    }|]
    deleteDerivationInputsIterator
    $ \i -> fix $ \continue -> do
      isEnd <- (0 /=) <$> [C.exp| bool { *$(DerivationInputsIterator *i) == $fptr-ptr:(Derivation *derivation)->inputDrvs.map.end() }|]
      if isEnd
        then pure []
        else do
          name <-
            [C.throwBlock| nix::StorePath *{
              return new StorePath((*$(DerivationInputsIterator *i))->first);
            }|]
              >>= moveStorePath
          outs <-
            bracket
              [C.block| Strings* {
                Strings *r = new Strings();

                for (const auto & i : (*$(DerivationInputsIterator *i))->second.value) {
                  r->push_back(i);
                }

                // for (const auto &i : iter->second.childMap) {
                // TODO (RFC 92)
                //}

                return r;
              }|]
              deleteStrings
              toByteStrings
          [C.block| void { (*$(DerivationInputsIterator *i))++; }|]
          ((name, outs) :) <$> continue
#else
getDerivationInputs' derivation =
  bracket
    [C.exp| DerivationInputsIterator* {
      new DerivationInputsIterator($fptr-ptr:(Derivation *derivation)->inputDrvs.begin())
    }|]
    deleteDerivationInputsIterator
    $ \i -> fix $ \continue -> do
      isEnd <- (0 /=) <$> [C.exp| bool { *$(DerivationInputsIterator *i) == $fptr-ptr:(Derivation *derivation)->inputDrvs.end() }|]
      if isEnd
        then pure []
        else do
          name <-
            [C.throwBlock| nix::StorePath *{
              return new StorePath((*$(DerivationInputsIterator *i))->first);
            }|]
              >>= moveStorePath
          outs <-
            bracket
              [C.block| Strings*{ 
                Strings *r = new Strings();
                for (auto i : (*$(DerivationInputsIterator *i))->second) {
                  r->push_back(i);
                }
                return r;
              }|]
              deleteStrings
              toByteStrings
          [C.block| void { (*$(DerivationInputsIterator *i))++; }|]
          ((name, outs) :) <$> continue
#endif

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) }|]
    IO (Ptr StringPairs)
-> (Ptr StringPairs -> IO (Map ByteString ByteString))
-> IO (Map ByteString ByteString)
forall a b. IO a -> (a -> IO b) -> IO b
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 =
  IO (Ptr Strings)
-> (Ptr Strings -> IO ())
-> (Ptr Strings -> IO [ByteString])
-> IO [ByteString]
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 =
  IO (FinalizerPtr Strings) -> FinalizerPtr Strings
forall a. IO a -> a
unsafePerformIO
    IO (FinalizerPtr Strings)
[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()) } |]
  (IO [ByteString] -> IO [ByteString]) -> IO [ByteString]
forall a. (a -> a) -> a
fix ((IO [ByteString] -> IO [ByteString]) -> IO [ByteString])
-> (IO [ByteString] -> IO [ByteString]) -> IO [ByteString]
forall a b. (a -> b) -> a -> b
$ \IO [ByteString]
go -> do
    Bool
isEnd <- (CBool
0 CBool -> CBool -> Bool
forall a. Eq a => a -> a -> Bool
/=) (CBool -> Bool) -> IO CBool -> IO 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 [ByteString] -> IO [ByteString]
forall a. a -> IO a
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 ByteString -> [ByteString] -> [ByteString]
forall a. a -> [a] -> [a]
:) ([ByteString] -> [ByteString])
-> IO [ByteString] -> IO [ByteString]
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 =
  [(ByteString, ByteString)] -> Map ByteString ByteString
forall k a. Ord k => [(k, a)] -> Map k a
M.fromList ([(ByteString, ByteString)] -> Map ByteString ByteString)
-> IO [(ByteString, ByteString)] -> IO (Map ByteString ByteString)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> do
    Ptr StringPairsIterator
i <- [C.exp| StringPairsIterator *{ new StringPairsIterator($(StringPairs *strings)->begin()) } |]
    (IO [(ByteString, ByteString)] -> IO [(ByteString, ByteString)])
-> IO [(ByteString, ByteString)]
forall a. (a -> a) -> a
fix ((IO [(ByteString, ByteString)] -> IO [(ByteString, ByteString)])
 -> IO [(ByteString, ByteString)])
-> (IO [(ByteString, ByteString)] -> IO [(ByteString, ByteString)])
-> IO [(ByteString, ByteString)]
forall a b. (a -> b) -> a -> b
$ \IO [(ByteString, ByteString)]
go -> do
      Bool
isEnd <- (CBool
0 CBool -> CBool -> Bool
forall a. Eq a => a -> a -> Bool
/=) (CBool -> Bool) -> IO CBool -> IO 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 [(ByteString, ByteString)] -> IO [(ByteString, ByteString)]
forall a. a -> IO a
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) (ByteString, ByteString)
-> [(ByteString, ByteString)] -> [(ByteString, ByteString)]
forall a. a -> [a] -> [a]
:) ([(ByteString, ByteString)] -> [(ByteString, ByteString)])
-> IO [(ByteString, ByteString)] -> IO [(ByteString, ByteString)]
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 =
  IO (Ptr Strings)
-> (Ptr Strings -> IO ()) -> (Ptr Strings -> IO a) -> IO a
forall a b c. IO a -> (a -> IO b) -> (a -> IO c) -> IO c
bracket
    IO (Ptr Strings)
[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 =
  (Ptr Strings -> IO a) -> IO a
forall a. (Ptr Strings -> IO a) -> IO a
withStrings \Ptr Strings
strings -> do
    [ByteString] -> (ByteString -> IO ()) -> IO ()
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') <- [Ptr NixStorePath] -> IO (StdVector (Ptr NixStorePath))
forall a. HasStdVectorCopyable a => [a] -> IO (StdVector a)
Std.Vector.fromList ([StorePath]
pathList [StorePath]
-> (StorePath -> Ptr NixStorePath) -> [Ptr NixStorePath]
forall (f :: * -> *) a b. Functor f => f a -> (a -> b) -> f b
<&> \(StorePath ForeignPtr NixStorePath
c) -> ForeignPtr NixStorePath -> Ptr NixStorePath
forall a. ForeignPtr a -> Ptr a
unsafeForeignPtrToPtr ForeignPtr NixStorePath
c)
  ForeignPtr (CStdVector (Ptr NixStorePath))
-> (Ptr (CStdVector (Ptr NixStorePath)) -> IO ()) -> IO ()
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);
    }|]
  [StorePath] -> (StorePath -> IO ()) -> IO ()
forall (t :: * -> *) (f :: * -> *) a b.
(Foldable t, Applicative f) =>
t a -> (a -> f b) -> f ()
for_ [StorePath]
pathList (\(StorePath ForeignPtr NixStorePath
c) -> ForeignPtr NixStorePath -> IO ()
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);
  }|]
    IO (Ptr SecretKey)
-> (Ptr SecretKey -> IO (ForeignPtr SecretKey))
-> IO (ForeignPtr SecretKey)
forall a b. IO a -> (a -> IO b) -> IO b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= FinalizerPtr SecretKey
-> Ptr SecretKey -> IO (ForeignPtr SecretKey)
forall a. FinalizerPtr a -> Ptr a -> IO (ForeignPtr a)
newForeignPtr FinalizerPtr SecretKey
finalizeSecretKey

finalizeSecretKey :: FinalizerPtr SecretKey
{-# NOINLINE finalizeSecretKey #-}
finalizeSecretKey :: FinalizerPtr SecretKey
finalizeSecretKey =
  IO (FinalizerPtr SecretKey) -> FinalizerPtr SecretKey
forall a. IO a -> a
unsafePerformIO
    IO (FinalizerPtr SecretKey)
[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) =
  (CInt -> CInt -> Bool
forall a. Eq a => a -> a -> Bool
== CInt
1) (CInt -> Bool) -> IO CInt -> IO Bool
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();
#if NIX_IS_AT_LEAST(2, 20, 0)
    {
      auto signer = std::make_unique<LocalSigner>(SecretKey { secretKey });
      info2.sign(*store, *signer);
    }
#else
    info2.sign(*store, secretKey);
#endif
    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
    (Ptr NixStorePath -> IO StorePath)
-> IO (Ptr NixStorePath) -> IO StorePath
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);
  }|]
    IO CBool -> (CBool -> Bool) -> IO Bool
forall (f :: * -> *) a b. Functor f => f a -> (a -> b) -> f b
<&> (CBool -> CBool -> Bool
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));
    }|]
  FinalizerPtr (Ref ValidPathInfo)
-> Ptr (Ref ValidPathInfo) -> IO (ForeignPtr (Ref ValidPathInfo))
forall a. FinalizerPtr a -> Ptr a -> IO (ForeignPtr a)
newForeignPtr FinalizerPtr (Ref ValidPathInfo)
finalizeRefValidPathInfo Ptr (Ref ValidPathInfo)
vpi

-- | Query only the local client cache ("narinfo cache") - does not query the actual store or daemon.
--
-- Returns 'Nothing' if nothing is known about the path.
-- Returns 'Just Nothing' if the path is known to not exist.
-- Returns 'Just (Just vpi)' if the path is known to exist, with the given 'ValidPathInfo'.
queryPathInfoFromClientCache ::
  Store ->
  StorePath ->
  IO (Maybe (Maybe (ForeignPtr (Ref ValidPathInfo))))
queryPathInfoFromClientCache :: Store
-> StorePath -> IO (Maybe (Maybe (ForeignPtr (Ref ValidPathInfo))))
queryPathInfoFromClientCache (Store Ptr (Ref NixStore)
store) (StorePath ForeignPtr NixStorePath
path) =
#if NIX_IS_AT_LEAST(2, 20, 0)
  alloca \isKnownP -> do
    mvpi <- [C.throwBlock| refValidPathInfo* {
        ReceiveInterrupts _;
        Store &store = **$(refStore* store);
        StorePath &path = *$fptr-ptr:(nix::StorePath *path);
        bool &isKnown = *$(bool* isKnownP);
        std::optional<std::shared_ptr<const ValidPathInfo>> maybeVPI =
            store.queryPathInfoFromClientCache(path);
        if (!maybeVPI) {
          isKnown = false;
          return nullptr;
        }
        else {
          isKnown = true;
          std::shared_ptr<const ValidPathInfo> &vpi = *maybeVPI;
          if (vpi)
            return new refValidPathInfo(vpi);
          else
            return nullptr;
        }
      }|]
    isKnown <- peek isKnownP <&> (/= 0)
    for (guard isKnown) \_ -> do
      mvpi & traverseNonNull (newForeignPtr finalizeRefValidPathInfo)
#else
  (Ptr CBool -> IO (Maybe (Maybe (ForeignPtr (Ref ValidPathInfo)))))
-> IO (Maybe (Maybe (ForeignPtr (Ref ValidPathInfo))))
forall a b. Storable a => (Ptr a -> IO b) -> IO b
alloca \Ptr CBool
isKnownP -> do
    Ptr (Ref ValidPathInfo)
mvpi <- [C.throwBlock| refValidPathInfo* {
        ReceiveInterrupts _;
        Store &store = **$(refStore* store);
        StorePath &path = *$fptr-ptr:(nix::StorePath *path);
        bool &isKnown = *$(bool* isKnownP);

        std::string uri = store.getUri();
        ref<NarInfoDiskCache> cache = nix::getNarInfoDiskCache();

        // std::pair<nix::NarInfoDiskCache::Outcome, std::shared_ptr<NarInfo>>
        auto [outcome, maybeNarInfo] =
          cache->lookupNarInfo(uri, std::string(path.hashPart()));

        if (outcome == nix::NarInfoDiskCache::oValid) {
          assert(maybeNarInfo);
          isKnown = true;
          return new refValidPathInfo(maybeNarInfo);
        }
        else if (outcome == nix::NarInfoDiskCache::oInvalid) {
          isKnown = true;
          return nullptr;
        }
        else {
          // nix::NarInfoDiskCache::oUnknown or unexpected value
          isKnown = false;
          return nullptr;
        }
      }|]
    Bool
isKnown <- Ptr CBool -> IO CBool
forall a. Storable a => Ptr a -> IO a
peek Ptr CBool
isKnownP IO CBool -> (CBool -> Bool) -> IO Bool
forall (f :: * -> *) a b. Functor f => f a -> (a -> b) -> f b
<&> (CBool -> CBool -> Bool
forall a. Eq a => a -> a -> Bool
/= CBool
0)
    Maybe ()
-> (() -> IO (Maybe (ForeignPtr (Ref ValidPathInfo))))
-> IO (Maybe (Maybe (ForeignPtr (Ref ValidPathInfo))))
forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
t a -> (a -> f b) -> f (t b)
for (Bool -> Maybe ()
forall (f :: * -> *). Alternative f => Bool -> f ()
guard Bool
isKnown) \()
_ -> do
      Ptr (Ref ValidPathInfo)
mvpi Ptr (Ref ValidPathInfo)
-> (Ptr (Ref ValidPathInfo)
    -> IO (Maybe (ForeignPtr (Ref ValidPathInfo))))
-> IO (Maybe (ForeignPtr (Ref ValidPathInfo)))
forall a b. a -> (a -> b) -> b
& (Ptr (Ref ValidPathInfo) -> IO (ForeignPtr (Ref ValidPathInfo)))
-> Ptr (Ref ValidPathInfo)
-> IO (Maybe (ForeignPtr (Ref ValidPathInfo)))
forall (m :: * -> *) a b.
Applicative m =>
(Ptr a -> m b) -> Ptr a -> m (Maybe b)
traverseNonNull (FinalizerPtr (Ref ValidPathInfo)
-> Ptr (Ref ValidPathInfo) -> IO (ForeignPtr (Ref ValidPathInfo))
forall a. FinalizerPtr a -> Ptr a -> IO (ForeignPtr a)
newForeignPtr FinalizerPtr (Ref ValidPathInfo)
finalizeRefValidPathInfo)  
#endif

finalizeRefValidPathInfo :: FinalizerPtr (Ref ValidPathInfo)
{-# NOINLINE finalizeRefValidPathInfo #-}
finalizeRefValidPathInfo :: FinalizerPtr (Ref ValidPathInfo)
finalizeRefValidPathInfo =
  IO (FinalizerPtr (Ref ValidPathInfo))
-> FinalizerPtr (Ref ValidPathInfo)
forall a. IO a -> a
unsafePerformIO
    IO (FinalizerPtr (Ref ValidPathInfo))
[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 =
  Integer -> Int64
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Integer -> Int64) -> Integer -> Int64
forall a b. (a -> b) -> a -> b
$
    CLong -> Integer
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
    (Ptr CChar -> IO ByteString) -> IO (Ptr CChar) -> IO ByteString
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< [C.block| const char *{
#if NIX_IS_AT_LEAST(2,20,0)
      std::string s((*$fptr-ptr:(refValidPathInfo* vpi))->narHash.to_string(nix::HashFormat::Nix32, true));
#elif NIX_IS_AT_LEAST(2,19,0)
      std::string s((*$fptr-ptr:(refValidPathInfo* vpi))->narHash.to_string(nix::HashFormat::Base32, true));
#else
      std::string s((*$fptr-ptr:(refValidPathInfo* vpi))->narHash.to_string(nix::Base32, true));
#endif
      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
    (Ptr NixStorePath -> IO (Maybe StorePath))
-> IO (Ptr NixStorePath) -> IO (Maybe StorePath)
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 <-
    Ptr (CStdVector (Ptr NixStorePath))
-> IO (StdVector (Ptr NixStorePath))
forall a b. HasEncapsulation a b => Ptr a -> IO b
moveToForeignPtrWrapper
      (Ptr (CStdVector (Ptr NixStorePath))
 -> IO (StdVector (Ptr NixStorePath)))
-> IO (Ptr (CStdVector (Ptr NixStorePath)))
-> IO (StdVector (Ptr NixStorePath))
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 <- StdVector (Ptr NixStorePath) -> IO [Ptr NixStorePath]
forall a.
(HasStdVectorCopyable a, Storable a) =>
StdVector a -> IO [a]
Std.Vector.toList StdVector (Ptr NixStorePath)
sps
  [Ptr NixStorePath]
-> (Ptr NixStorePath -> IO StorePath) -> IO [StorePath]
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 (Bool -> CInt) -> Bool -> CInt
forall a b. (a -> b) -> a -> b
$ ClosureParams -> Bool
flipDirection ClosureParams
params
      inclOut :: CInt
inclOut = Bool -> CInt
countTrue (Bool -> CInt) -> Bool -> CInt
forall a b. (a -> b) -> a -> b
$ ClosureParams -> Bool
includeOutputs ClosureParams
params
      inclDrv :: CInt
inclDrv = Bool -> CInt
countTrue (Bool -> CInt) -> Bool -> CInt
forall a b. (a -> b) -> a -> b
$ ClosureParams -> Bool
includeDerivers ClosureParams
params
  ret :: StdSet NixStorePath
ret@(Std.Set.StdSet ForeignPtr (CStdSet NixStorePath)
retSet) <- IO (StdSet NixStorePath)
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));
  }|]
  StdSet NixStorePath -> IO (StdSet NixStorePath)
forall a. a -> IO a
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 = ForeignPtr a -> (Ptr a -> IO b) -> IO b
forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
withForeignPtr (a' -> ForeignPtr a
forall a b. Coercible a b => a -> b
coerce a'
p)