Merge branch 'master' into xml-string-context
This commit is contained in:
commit
824615aabe
|
@ -454,6 +454,7 @@ library
|
||||||
Nix.Expr.Types
|
Nix.Expr.Types
|
||||||
Nix.Expr.Types.Annotated
|
Nix.Expr.Types.Annotated
|
||||||
Nix.Frames
|
Nix.Frames
|
||||||
|
Nix.Json
|
||||||
Nix.Lint
|
Nix.Lint
|
||||||
Nix.Normal
|
Nix.Normal
|
||||||
Nix.Options
|
Nix.Options
|
||||||
|
|
|
@ -29,6 +29,7 @@ import Data.Text.Prettyprint.Doc.Render.Text
|
||||||
import Nix
|
import Nix
|
||||||
import Nix.Convert
|
import Nix.Convert
|
||||||
import qualified Nix.Eval as Eval
|
import qualified Nix.Eval as Eval
|
||||||
|
import Nix.Json
|
||||||
-- import Nix.Lint
|
-- import Nix.Lint
|
||||||
import Nix.Options.Parser
|
import Nix.Options.Parser
|
||||||
import qualified Nix.Type.Env as Env
|
import qualified Nix.Type.Env as Env
|
||||||
|
@ -145,7 +146,8 @@ main = do
|
||||||
. TL.decodeUtf8
|
. TL.decodeUtf8
|
||||||
. A.encodingToLazyByteString
|
. A.encodingToLazyByteString
|
||||||
. toEncodingSorted
|
. toEncodingSorted
|
||||||
<=< fromNix
|
. snd
|
||||||
|
<=< nvalueToJSON
|
||||||
| strict opts =
|
| strict opts =
|
||||||
liftIO . print . prettyNValueNF <=< normalForm
|
liftIO . print . prettyNValueNF <=< normalForm
|
||||||
| values opts =
|
| values opts =
|
||||||
|
|
|
@ -38,7 +38,6 @@ import qualified "hashing" Crypto.Hash.SHA1 as SHA1
|
||||||
import qualified "hashing" Crypto.Hash.SHA256 as SHA256
|
import qualified "hashing" Crypto.Hash.SHA256 as SHA256
|
||||||
import qualified "hashing" Crypto.Hash.SHA512 as SHA512
|
import qualified "hashing" Crypto.Hash.SHA512 as SHA512
|
||||||
#else
|
#else
|
||||||
import Data.ByteString.Base16 as Base16
|
|
||||||
import qualified "cryptohash-md5" Crypto.Hash.MD5 as MD5
|
import qualified "cryptohash-md5" Crypto.Hash.MD5 as MD5
|
||||||
import qualified "cryptohash-sha1" Crypto.Hash.SHA1 as SHA1
|
import qualified "cryptohash-sha1" Crypto.Hash.SHA1 as SHA1
|
||||||
import qualified "cryptohash-sha256" Crypto.Hash.SHA256 as SHA256
|
import qualified "cryptohash-sha256" Crypto.Hash.SHA256 as SHA256
|
||||||
|
@ -52,6 +51,7 @@ import Data.Array
|
||||||
import Data.Bits
|
import Data.Bits
|
||||||
import Data.ByteString (ByteString)
|
import Data.ByteString (ByteString)
|
||||||
import qualified Data.ByteString as B
|
import qualified Data.ByteString as B
|
||||||
|
import Data.ByteString.Base16 as Base16
|
||||||
import qualified Data.ByteString.Lazy as LBS
|
import qualified Data.ByteString.Lazy as LBS
|
||||||
import Data.Char (isDigit)
|
import Data.Char (isDigit)
|
||||||
import Data.Fix
|
import Data.Fix
|
||||||
|
@ -59,6 +59,7 @@ import Data.Foldable (foldrM)
|
||||||
import qualified Data.HashMap.Lazy as M
|
import qualified Data.HashMap.Lazy as M
|
||||||
import Data.List
|
import Data.List
|
||||||
import Data.Maybe
|
import Data.Maybe
|
||||||
|
import Data.Scientific
|
||||||
import Data.Set (Set)
|
import Data.Set (Set)
|
||||||
import qualified Data.Set as S
|
import qualified Data.Set as S
|
||||||
import Data.String.Interpolate.IsString
|
import Data.String.Interpolate.IsString
|
||||||
|
@ -70,6 +71,7 @@ import qualified Data.Text.Lazy.Builder as Builder
|
||||||
import Data.These (fromThese)
|
import Data.These (fromThese)
|
||||||
import qualified Data.Time.Clock.POSIX as Time
|
import qualified Data.Time.Clock.POSIX as Time
|
||||||
import Data.Traversable (for, mapM)
|
import Data.Traversable (for, mapM)
|
||||||
|
import qualified Data.Vector as V
|
||||||
import Nix.Atoms
|
import Nix.Atoms
|
||||||
import Nix.Convert
|
import Nix.Convert
|
||||||
import Nix.Effects
|
import Nix.Effects
|
||||||
|
@ -78,12 +80,13 @@ import Nix.Exec
|
||||||
import Nix.Expr.Types
|
import Nix.Expr.Types
|
||||||
import Nix.Expr.Types.Annotated
|
import Nix.Expr.Types.Annotated
|
||||||
import Nix.Frames
|
import Nix.Frames
|
||||||
import Nix.String
|
import Nix.Json
|
||||||
import Nix.Normal
|
import Nix.Normal
|
||||||
import Nix.Options
|
import Nix.Options
|
||||||
import Nix.Parser hiding (nixPath)
|
import Nix.Parser hiding (nixPath)
|
||||||
import Nix.Render
|
import Nix.Render
|
||||||
import Nix.Scope
|
import Nix.Scope
|
||||||
|
import Nix.String
|
||||||
import Nix.Thunk
|
import Nix.Thunk
|
||||||
import Nix.Utils
|
import Nix.Utils
|
||||||
import Nix.Value
|
import Nix.Value
|
||||||
|
@ -139,7 +142,7 @@ force' = force ?? pure
|
||||||
|
|
||||||
builtinsList :: forall e m. MonadNix e m => m [ Builtin m ]
|
builtinsList :: forall e m. MonadNix e m => m [ Builtin m ]
|
||||||
builtinsList = sequence [
|
builtinsList = sequence [
|
||||||
do version <- toValue ("2.0" :: Text)
|
do version <- toValue (principledMakeNixStringWithoutContext "2.0")
|
||||||
pure $ Builtin Normal ("nixVersion", version)
|
pure $ Builtin Normal ("nixVersion", version)
|
||||||
|
|
||||||
, do version <- toValue (5 :: Int)
|
, do version <- toValue (5 :: Int)
|
||||||
|
@ -160,7 +163,7 @@ builtinsList = sequence [
|
||||||
, add2 Normal "catAttrs" catAttrs
|
, add2 Normal "catAttrs" catAttrs
|
||||||
, add2 Normal "compareVersions" compareVersions_
|
, add2 Normal "compareVersions" compareVersions_
|
||||||
, add Normal "concatLists" concatLists
|
, add Normal "concatLists" concatLists
|
||||||
, add' Normal "concatStringsSep" (arity2 Text.intercalate)
|
, add' Normal "concatStringsSep" (arity2 principledIntercalateNixString)
|
||||||
, add0 Normal "currentSystem" currentSystem
|
, add0 Normal "currentSystem" currentSystem
|
||||||
, add0 Normal "currentTime" currentTime_
|
, add0 Normal "currentTime" currentTime_
|
||||||
, add2 Normal "deepSeq" deepSeq
|
, add2 Normal "deepSeq" deepSeq
|
||||||
|
@ -253,15 +256,13 @@ builtinsList = sequence [
|
||||||
, add2 Normal "split" split_
|
, add2 Normal "split" split_
|
||||||
, add Normal "splitVersion" splitVersion_
|
, add Normal "splitVersion" splitVersion_
|
||||||
, add0 Normal "storeDir" (return $ nvStr $ principledMakeNixStringWithoutContext "/nix/store")
|
, add0 Normal "storeDir" (return $ nvStr $ principledMakeNixStringWithoutContext "/nix/store")
|
||||||
, add' Normal "stringLength" (arity1 Text.length)
|
, add' Normal "stringLength" (arity1 $ Text.length . principledStringIgnoreContext)
|
||||||
, add' Normal "sub" (arity2 ((-) @Integer))
|
, add' Normal "sub" (arity2 ((-) @Integer))
|
||||||
, add' Normal "substring" substring
|
, add' Normal "substring" substring
|
||||||
, add Normal "tail" tail_
|
, add Normal "tail" tail_
|
||||||
, add0 Normal "true" (return $ nvConstant $ NBool True)
|
, add0 Normal "true" (return $ nvConstant $ NBool True)
|
||||||
, add TopLevel "throw" throw_
|
, add TopLevel "throw" throw_
|
||||||
, add' Normal "toJSON"
|
, add Normal "toJSON" prim_toJSON
|
||||||
(arity1 $ decodeUtf8 . LBS.toStrict . A.encodingToLazyByteString
|
|
||||||
. toEncodingSorted)
|
|
||||||
, add2 Normal "toFile" toFile
|
, add2 Normal "toFile" toFile
|
||||||
, add Normal "toPath" toPath
|
, add Normal "toPath" toPath
|
||||||
, add TopLevel "toString" toString
|
, add TopLevel "toString" toString
|
||||||
|
@ -298,9 +299,9 @@ foldNixPath f z = do
|
||||||
mres <- lookupVar "__includes"
|
mres <- lookupVar "__includes"
|
||||||
dirs <- case mres of
|
dirs <- case mres of
|
||||||
Nothing -> return []
|
Nothing -> return []
|
||||||
Just v -> fromNix @[Text] v
|
Just v -> fromNix v
|
||||||
menv <- getEnvVar "NIX_PATH"
|
menv <- getEnvVar "NIX_PATH"
|
||||||
foldrM go z $ map fromInclude dirs ++ case menv of
|
foldrM go z $ map (fromInclude . principledStringIgnoreContext) dirs ++ case menv of
|
||||||
Nothing -> []
|
Nothing -> []
|
||||||
Just str -> uriAwareSplit (Text.pack str)
|
Just str -> uriAwareSplit (Text.pack str)
|
||||||
where
|
where
|
||||||
|
@ -327,7 +328,7 @@ toString str = str >>= coerceToString DontCopyToStore CoerceAny >>= toNix
|
||||||
|
|
||||||
hasAttr :: forall e m. MonadNix e m => m (NValue m) -> m (NValue m) -> m (NValue m)
|
hasAttr :: forall e m. MonadNix e m => m (NValue m) -> m (NValue m) -> m (NValue m)
|
||||||
hasAttr x y =
|
hasAttr x y =
|
||||||
fromValue @Text x >>= \key ->
|
fromValue x >>= fromStringNoContext >>= \key ->
|
||||||
fromValue @(AttrSet (NThunk m), AttrSet SourcePos) y >>= \(aset, _) ->
|
fromValue @(AttrSet (NThunk m), AttrSet SourcePos) y >>= \(aset, _) ->
|
||||||
toNix $ M.member key aset
|
toNix $ M.member key aset
|
||||||
|
|
||||||
|
@ -343,7 +344,7 @@ hasContext =
|
||||||
|
|
||||||
getAttr :: forall e m. MonadNix e m => m (NValue m) -> m (NValue m) -> m (NValue m)
|
getAttr :: forall e m. MonadNix e m => m (NValue m) -> m (NValue m) -> m (NValue m)
|
||||||
getAttr x y =
|
getAttr x y =
|
||||||
fromValue @Text x >>= \key ->
|
fromValue x >>= fromStringNoContext >>= \key ->
|
||||||
fromValue @(AttrSet (NThunk m), AttrSet SourcePos) y >>= \(aset, _) ->
|
fromValue @(AttrSet (NThunk m), AttrSet SourcePos) y >>= \(aset, _) ->
|
||||||
attrsetGet key aset >>= force'
|
attrsetGet key aset >>= force'
|
||||||
|
|
||||||
|
@ -467,7 +468,7 @@ splitVersion s = case Text.uncons s of
|
||||||
in thisComponent : splitVersion rest
|
in thisComponent : splitVersion rest
|
||||||
|
|
||||||
splitVersion_ :: MonadNix e m => m (NValue m) -> m (NValue m)
|
splitVersion_ :: MonadNix e m => m (NValue m) -> m (NValue m)
|
||||||
splitVersion_ = fromStringNoContext >=> \s ->
|
splitVersion_ = fromValue >=> fromStringNoContext >=> \s ->
|
||||||
return $ nvList $ flip map (splitVersion s) $ \c ->
|
return $ nvList $ flip map (splitVersion s) $ \c ->
|
||||||
valueThunk $ nvStr $ principledMakeNixStringWithoutContext $ versionComponentToString c
|
valueThunk $ nvStr $ principledMakeNixStringWithoutContext $ versionComponentToString c
|
||||||
|
|
||||||
|
@ -480,8 +481,8 @@ compareVersions s1 s2 =
|
||||||
|
|
||||||
compareVersions_ :: MonadNix e m => m (NValue m) -> m (NValue m) -> m (NValue m)
|
compareVersions_ :: MonadNix e m => m (NValue m) -> m (NValue m) -> m (NValue m)
|
||||||
compareVersions_ t1 t2 =
|
compareVersions_ t1 t2 =
|
||||||
fromStringNoContext t1 >>= \s1 ->
|
fromValue t1 >>= fromStringNoContext >>= \s1 ->
|
||||||
fromStringNoContext t2 >>= \s2 ->
|
fromValue t2 >>= fromStringNoContext >>= \s2 ->
|
||||||
return $ nvConstant $ NInt $ case compareVersions s1 s2 of
|
return $ nvConstant $ NInt $ case compareVersions s1 s2 of
|
||||||
LT -> -1
|
LT -> -1
|
||||||
EQ -> 0
|
EQ -> 0
|
||||||
|
@ -507,29 +508,43 @@ splitDrvName s =
|
||||||
in (Text.intercalate sep namePieces, Text.intercalate sep versionPieces)
|
in (Text.intercalate sep namePieces, Text.intercalate sep versionPieces)
|
||||||
|
|
||||||
parseDrvName :: forall e m. MonadNix e m => m (NValue m) -> m (NValue m)
|
parseDrvName :: forall e m. MonadNix e m => m (NValue m) -> m (NValue m)
|
||||||
parseDrvName = fromValue >=> \(s :: Text) -> do
|
parseDrvName = fromValue >=> fromStringNoContext >=> \s -> do
|
||||||
let (name :: Text, version :: Text) = splitDrvName s
|
let (name :: Text, version :: Text) = splitDrvName s
|
||||||
-- jww (2018-04-15): There should be an easier way to write this.
|
-- jww (2018-04-15): There should be an easier way to write this.
|
||||||
(toValue =<<) $ sequence $ M.fromList
|
(toValue =<<) $ sequence $ M.fromList
|
||||||
[ ("name" :: Text, thunk (toValue @_ @_ @(NValue m) name))
|
[ ("name" :: Text, thunk (toValue @_ @_ @(NValue m) $ principledMakeNixStringWithoutContext name))
|
||||||
, ("version", thunk (toValue version)) ]
|
, ("version", thunk (toValue $ principledMakeNixStringWithoutContext version)) ]
|
||||||
|
|
||||||
match_ :: forall e m. MonadNix e m => m (NValue m) -> m (NValue m) -> m (NValue m)
|
match_ :: forall e m. MonadNix e m => m (NValue m) -> m (NValue m) -> m (NValue m)
|
||||||
match_ pat str =
|
match_ pat str =
|
||||||
fromValue pat >>= \p ->
|
fromValue pat >>= fromStringNoContext >>= \p ->
|
||||||
fromValue str >>= \s -> do
|
fromValue str >>= \ns -> do
|
||||||
|
-- NOTE: Currently prim_match in nix/src/libexpr/primops.cc ignores the
|
||||||
|
-- context of its second argument. This is probably a bug but we're
|
||||||
|
-- going to preserve the behavior here until it is fixed upstream.
|
||||||
|
-- Relevant issue: https://github.com/NixOS/nix/issues/2547
|
||||||
|
let s = principledStringIgnoreContext ns
|
||||||
|
|
||||||
let re = makeRegex (encodeUtf8 p) :: Regex
|
let re = makeRegex (encodeUtf8 p) :: Regex
|
||||||
|
let mkMatch t = if Text.null t
|
||||||
|
then toValue () -- Shorthand for Null
|
||||||
|
else toValue $ principledMakeNixStringWithoutContext t
|
||||||
case matchOnceText re (encodeUtf8 s) of
|
case matchOnceText re (encodeUtf8 s) of
|
||||||
Just ("", sarr, "") -> do
|
Just ("", sarr, "") -> do
|
||||||
let s = map fst (elems sarr)
|
let s = map fst (elems sarr)
|
||||||
nvList <$> traverse (toValue . decodeUtf8)
|
nvList <$> traverse (mkMatch . decodeUtf8)
|
||||||
(if length s > 1 then tail s else s)
|
(if length s > 1 then tail s else s)
|
||||||
_ -> pure $ nvConstant NNull
|
_ -> pure $ nvConstant NNull
|
||||||
|
|
||||||
split_ :: forall e m. MonadNix e m => m (NValue m) -> m (NValue m) -> m (NValue m)
|
split_ :: forall e m. MonadNix e m => m (NValue m) -> m (NValue m) -> m (NValue m)
|
||||||
split_ pat str =
|
split_ pat str =
|
||||||
fromValue pat >>= \p ->
|
fromValue pat >>= fromStringNoContext >>= \p ->
|
||||||
fromValue str >>= \s -> do
|
fromValue str >>= \ns -> do
|
||||||
|
-- NOTE: Currently prim_split in nix/src/libexpr/primops.cc ignores the
|
||||||
|
-- context of its second argument. This is probably a bug but we're
|
||||||
|
-- going to preserve the behavior here until it is fixed upstream.
|
||||||
|
-- Relevant issue: https://github.com/NixOS/nix/issues/2547
|
||||||
|
let s = principledStringIgnoreContext ns
|
||||||
let re = makeRegex (encodeUtf8 p) :: Regex
|
let re = makeRegex (encodeUtf8 p) :: Regex
|
||||||
haystack = encodeUtf8 s
|
haystack = encodeUtf8 s
|
||||||
return $ nvList $
|
return $ nvList $
|
||||||
|
@ -553,14 +568,14 @@ splitMatches numDropped (((_,(start,len)):captures):mts) haystack =
|
||||||
|
|
||||||
thunkStr s = valueThunk (nvStr (hackyMakeNixStringWithoutContext (decodeUtf8 s)))
|
thunkStr s = valueThunk (nvStr (hackyMakeNixStringWithoutContext (decodeUtf8 s)))
|
||||||
|
|
||||||
substring :: MonadNix e m => Int -> Int -> Text -> Prim m Text
|
substring :: MonadNix e m => Int -> Int -> NixString -> Prim m NixString
|
||||||
substring start len str = Prim $
|
substring start len str = Prim $
|
||||||
if start < 0 --NOTE: negative values of 'len' are OK
|
if start < 0 --NOTE: negative values of 'len' are OK
|
||||||
then throwError $ ErrorCall $ "builtins.substring: negative start position: " ++ show start
|
then throwError $ ErrorCall $ "builtins.substring: negative start position: " ++ show start
|
||||||
else pure $ Text.take len $ Text.drop start str
|
else pure $ principledModifyNixContents (Text.take len . Text.drop start) str
|
||||||
|
|
||||||
attrNames :: forall e m. MonadNix e m => m (NValue m) -> m (NValue m)
|
attrNames :: forall e m. MonadNix e m => m (NValue m) -> m (NValue m)
|
||||||
attrNames = fromValue @(ValueSet m) >=> toNix . sort . M.keys
|
attrNames = fromValue @(ValueSet m) >=> toNix . map principledMakeNixStringWithoutContext . sort . M.keys
|
||||||
|
|
||||||
attrValues :: forall e m. MonadNix e m => m (NValue m) -> m (NValue m)
|
attrValues :: forall e m. MonadNix e m => m (NValue m) -> m (NValue m)
|
||||||
attrValues = fromValue @(ValueSet m) >=>
|
attrValues = fromValue @(ValueSet m) >=>
|
||||||
|
@ -592,16 +607,15 @@ filter_ fun xs = fun >>= \f ->
|
||||||
|
|
||||||
catAttrs :: forall e m. MonadNix e m => m (NValue m) -> m (NValue m) -> m (NValue m)
|
catAttrs :: forall e m. MonadNix e m => m (NValue m) -> m (NValue m) -> m (NValue m)
|
||||||
catAttrs attrName xs =
|
catAttrs attrName xs =
|
||||||
fromValue @Text attrName >>= \n ->
|
fromValue attrName >>= fromStringNoContext >>= \n ->
|
||||||
fromValue @[NThunk m] xs >>= \l ->
|
fromValue @[NThunk m] xs >>= \l ->
|
||||||
fmap (nvList . catMaybes) $
|
fmap (nvList . catMaybes) $
|
||||||
forM l $ fmap (M.lookup n) . fromValue
|
forM l $ fmap (M.lookup n) . fromValue
|
||||||
|
|
||||||
baseNameOf :: MonadNix e m => m (NValue m) -> m (NValue m)
|
baseNameOf :: MonadNix e m => m (NValue m) -> m (NValue m)
|
||||||
baseNameOf x = x >>= \case
|
baseNameOf x = do
|
||||||
NVStr ns -> pure $ nvStr (principledModifyNixContents (Text.pack . takeFileName . Text.unpack) ns)
|
ns <- coerceToString DontCopyToStore CoerceStringy =<< x
|
||||||
NVPath path -> pure $ nvPath $ takeFileName path
|
pure $ nvStr (principledModifyNixContents (Text.pack . takeFileName . Text.unpack) ns)
|
||||||
v -> throwError $ ErrorCall $ "dirOf: expected string or path, got " ++ show v
|
|
||||||
|
|
||||||
bitAnd :: forall e m. MonadNix e m => m (NValue m) -> m (NValue m) -> m (NValue m)
|
bitAnd :: forall e m. MonadNix e m => m (NValue m) -> m (NValue m) -> m (NValue m)
|
||||||
bitAnd x y =
|
bitAnd x y =
|
||||||
|
@ -626,7 +640,9 @@ dirOf x = x >>= \case
|
||||||
|
|
||||||
-- jww (2018-04-28): This should only be a string argument, and not coerced?
|
-- jww (2018-04-28): This should only be a string argument, and not coerced?
|
||||||
unsafeDiscardStringContext :: MonadNix e m => m (NValue m) -> m (NValue m)
|
unsafeDiscardStringContext :: MonadNix e m => m (NValue m) -> m (NValue m)
|
||||||
unsafeDiscardStringContext = fromValue @Text >=> toNix
|
unsafeDiscardStringContext mnv = do
|
||||||
|
ns <- fromValue mnv
|
||||||
|
toNix $ principledMakeNixStringWithoutContext $ principledStringIgnoreContext ns
|
||||||
|
|
||||||
seq_ :: MonadNix e m => m (NValue m) -> m (NValue m) -> m (NValue m)
|
seq_ :: MonadNix e m => m (NValue m) -> m (NValue m) -> m (NValue m)
|
||||||
seq_ a b = a >> b
|
seq_ a b = a >> b
|
||||||
|
@ -705,39 +721,44 @@ genericClosure = fromValue @(AttrSet (NThunk m)) >=> \s ->
|
||||||
|
|
||||||
replaceStrings :: MonadNix e m => m (NValue m) -> m (NValue m) -> m (NValue m) -> m (NValue m)
|
replaceStrings :: MonadNix e m => m (NValue m) -> m (NValue m) -> m (NValue m) -> m (NValue m)
|
||||||
replaceStrings tfrom tto ts =
|
replaceStrings tfrom tto ts =
|
||||||
fromNix tfrom >>= \(from :: [Text]) ->
|
fromNix tfrom >>= \(nsFrom :: [NixString]) ->
|
||||||
fromNix tto >>= \(to :: [Text]) ->
|
fromNix tto >>= \(nsTo :: [NixString]) ->
|
||||||
fromValue ts >>= \(s :: Text) -> do
|
fromValue ts >>= \(ns :: NixString) -> do
|
||||||
when (length from /= length to) $
|
let from = map principledStringIgnoreContext nsFrom
|
||||||
|
when (length nsFrom /= length nsTo) $
|
||||||
throwError $ ErrorCall $
|
throwError $ ErrorCall $
|
||||||
"'from' and 'to' arguments to 'replaceStrings'"
|
"'from' and 'to' arguments to 'replaceStrings'"
|
||||||
++ " have different lengths"
|
++ " have different lengths"
|
||||||
let lookupPrefix s = do
|
let lookupPrefix s = do
|
||||||
(prefix, replacement) <-
|
(prefix, replacement) <-
|
||||||
find ((`Text.isPrefixOf` s) . fst) $ zip from to
|
find ((`Text.isPrefixOf` s) . fst) $ zip from nsTo
|
||||||
let rest = Text.drop (Text.length prefix) s
|
let rest = Text.drop (Text.length prefix) s
|
||||||
return (prefix, replacement, rest)
|
return (prefix, replacement, rest)
|
||||||
finish = LazyText.toStrict . Builder.toLazyText
|
finish b = principledMakeNixString (LazyText.toStrict $ Builder.toLazyText b)
|
||||||
go orig result = case lookupPrefix orig of
|
go orig result ctx = case lookupPrefix orig of
|
||||||
Nothing -> case Text.uncons orig of
|
Nothing -> case Text.uncons orig of
|
||||||
Nothing -> finish result
|
Nothing -> finish result ctx
|
||||||
Just (h, t) -> go t $ result <> Builder.singleton h
|
Just (h, t) -> go t (result <> Builder.singleton h) ctx
|
||||||
Just (prefix, replacement, rest) -> case prefix of
|
Just (prefix, replacementNS, rest) ->
|
||||||
"" -> case Text.uncons rest of
|
let replacement = principledStringIgnoreContext replacementNS
|
||||||
Nothing -> finish $ result <> Builder.fromText replacement
|
newCtx = principledGetContext replacementNS
|
||||||
Just (h, t) -> go t $ mconcat
|
in case prefix of
|
||||||
[ result
|
"" -> case Text.uncons rest of
|
||||||
, Builder.fromText replacement
|
Nothing -> finish (result <> Builder.fromText replacement) (ctx <> newCtx)
|
||||||
, Builder.singleton h
|
Just (h, t) -> go t (mconcat
|
||||||
]
|
[ result
|
||||||
_ -> go rest $ result <> Builder.fromText replacement
|
, Builder.fromText replacement
|
||||||
toNix $ go s mempty
|
, Builder.singleton h
|
||||||
|
]) (ctx <> newCtx)
|
||||||
|
_ -> go rest (result <> Builder.fromText replacement) (ctx <> newCtx)
|
||||||
|
toNix $ go (principledStringIgnoreContext ns) mempty $ principledGetContext ns
|
||||||
|
|
||||||
removeAttrs :: forall e m. MonadNix e m
|
removeAttrs :: forall e m. MonadNix e m
|
||||||
=> m (NValue m) -> m (NValue m) -> m (NValue m)
|
=> m (NValue m) -> m (NValue m) -> m (NValue m)
|
||||||
removeAttrs set = fromNix >=> \(toRemove :: [Text]) ->
|
removeAttrs set = fromNix >=> \(nsToRemove :: [NixString]) ->
|
||||||
fromValue @(AttrSet (NThunk m),
|
fromValue @(AttrSet (NThunk m),
|
||||||
AttrSet SourcePos) set >>= \(m, p) ->
|
AttrSet SourcePos) set >>= \(m, p) -> do
|
||||||
|
toRemove <- mapM fromStringNoContext nsToRemove
|
||||||
toNix (go m toRemove, go p toRemove)
|
toNix (go m toRemove, go p toRemove)
|
||||||
where
|
where
|
||||||
go = foldl' (flip M.delete)
|
go = foldl' (flip M.delete)
|
||||||
|
@ -763,10 +784,15 @@ functionArgs fun = fun >>= \case
|
||||||
|
|
||||||
toFile :: MonadNix e m => m (NValue m) -> m (NValue m) -> m (NValue m)
|
toFile :: MonadNix e m => m (NValue m) -> m (NValue m) -> m (NValue m)
|
||||||
toFile name s = do
|
toFile name s = do
|
||||||
name' <- fromValue name
|
name' <- fromStringNoContext =<< fromValue name
|
||||||
s' <- fromValue s
|
s' <- fromValue s
|
||||||
mres <- toFile_ (Text.unpack name') (Text.unpack s')
|
-- TODO Using hacky here because we still need to turn the context into
|
||||||
toNix $ Text.pack $ unStorePath mres
|
-- runtime references of the resulting file.
|
||||||
|
-- See prim_toFile in nix/src/libexpr/primops.cc
|
||||||
|
mres <- toFile_ (Text.unpack name') (Text.unpack $ hackyStringIgnoreContext s')
|
||||||
|
let t = Text.pack $ unStorePath mres
|
||||||
|
sc = StringContext t DirectPath
|
||||||
|
toNix $ principledMakeNixStringWithSingletonContext t sc
|
||||||
|
|
||||||
toPath :: MonadNix e m => m (NValue m) -> m (NValue m)
|
toPath :: MonadNix e m => m (NValue m) -> m (NValue m)
|
||||||
toPath = fromValue @Path >=> toNix @Path
|
toPath = fromValue @Path >=> toNix @Path
|
||||||
|
@ -789,7 +815,7 @@ isList :: forall e m. MonadNix e m => m (NValue m) -> m (NValue m)
|
||||||
isList = hasKind @[NThunk m]
|
isList = hasKind @[NThunk m]
|
||||||
|
|
||||||
isString :: forall e m. MonadNix e m => m (NValue m) -> m (NValue m)
|
isString :: forall e m. MonadNix e m => m (NValue m) -> m (NValue m)
|
||||||
isString = hasKind @Text
|
isString = hasKind @NixString
|
||||||
|
|
||||||
isInt :: forall e m. MonadNix e m => m (NValue m) -> m (NValue m)
|
isInt :: forall e m. MonadNix e m => m (NValue m) -> m (NValue m)
|
||||||
isInt = hasKind @Int
|
isInt = hasKind @Int
|
||||||
|
@ -809,7 +835,9 @@ isFunction func = func >>= \case
|
||||||
_ -> toValue False
|
_ -> toValue False
|
||||||
|
|
||||||
throw_ :: MonadNix e m => m (NValue m) -> m (NValue m)
|
throw_ :: MonadNix e m => m (NValue m) -> m (NValue m)
|
||||||
throw_ = fromValue >=> throwError . ErrorCall . Text.unpack
|
throw_ mnv = do
|
||||||
|
ns <- coerceToString CopyToStore CoerceStringy =<< mnv
|
||||||
|
throwError . ErrorCall . Text.unpack $ principledStringIgnoreContext ns
|
||||||
|
|
||||||
import_ :: forall e m. MonadNix e m => m (NValue m) -> m (NValue m)
|
import_ :: forall e m. MonadNix e m => m (NValue m) -> m (NValue m)
|
||||||
import_ = scopedImport (pure (nvSet M.empty M.empty))
|
import_ = scopedImport (pure (nvSet M.empty M.empty))
|
||||||
|
@ -834,9 +862,10 @@ scopedImport asetArg pathArg =
|
||||||
importPath @m path'
|
importPath @m path'
|
||||||
|
|
||||||
getEnv_ :: MonadNix e m => m (NValue m) -> m (NValue m)
|
getEnv_ :: MonadNix e m => m (NValue m) -> m (NValue m)
|
||||||
getEnv_ = fromValue >=> \s -> do
|
getEnv_ = fromValue >=> fromStringNoContext >=> \s -> do
|
||||||
mres <- getEnvVar (Text.unpack s)
|
mres <- getEnvVar (Text.unpack s)
|
||||||
toNix $ case mres of
|
toNix $ principledMakeNixStringWithoutContext $
|
||||||
|
case mres of
|
||||||
Nothing -> ""
|
Nothing -> ""
|
||||||
Just v -> Text.pack v
|
Just v -> Text.pack v
|
||||||
|
|
||||||
|
@ -878,32 +907,37 @@ listToAttrs :: forall e m. MonadNix e m => m (NValue m) -> m (NValue m)
|
||||||
listToAttrs = fromValue @[NThunk m] >=> \l ->
|
listToAttrs = fromValue @[NThunk m] >=> \l ->
|
||||||
fmap (flip nvSet M.empty . M.fromList . reverse) $
|
fmap (flip nvSet M.empty . M.fromList . reverse) $
|
||||||
forM l $ fromValue @(AttrSet (NThunk m)) >=> \s -> do
|
forM l $ fromValue @(AttrSet (NThunk m)) >=> \s -> do
|
||||||
name <- attrsetGet "name" s
|
name <- fromStringNoContext =<< fromValue =<< attrsetGet "name" s
|
||||||
val <- attrsetGet "value" s
|
val <- attrsetGet "value" s
|
||||||
fromValue name <&> (, val)
|
pure (name, val)
|
||||||
|
|
||||||
hashString :: MonadNix e m => Text -> Text -> Prim m Text
|
-- prim_hashString from nix/src/libexpr/primops.cc
|
||||||
hashString algo s = Prim $ do
|
-- fail if context in the algo arg
|
||||||
|
-- propagate context from the s arg
|
||||||
|
hashString :: MonadNix e m => NixString -> NixString -> Prim m NixString
|
||||||
|
hashString nsAlgo ns = Prim $ do
|
||||||
|
algo <- fromStringNoContext nsAlgo
|
||||||
|
let f g = pure $ principledModifyNixContents g ns
|
||||||
case algo of
|
case algo of
|
||||||
"md5" -> pure $
|
"md5" -> f $ \s ->
|
||||||
#if MIN_VERSION_hashing(0, 1, 0)
|
#if MIN_VERSION_hashing(0, 1, 0)
|
||||||
Text.pack $ show (hash (encodeUtf8 s) :: MD5.MD5)
|
Text.pack $ show (hash (encodeUtf8 s) :: MD5.MD5)
|
||||||
#else
|
#else
|
||||||
decodeUtf8 $ Base16.encode $ MD5.hash $ encodeUtf8 s
|
decodeUtf8 $ Base16.encode $ MD5.hash $ encodeUtf8 s
|
||||||
#endif
|
#endif
|
||||||
"sha1" -> pure $
|
"sha1" -> f $ \s ->
|
||||||
#if MIN_VERSION_hashing(0, 1, 0)
|
#if MIN_VERSION_hashing(0, 1, 0)
|
||||||
Text.pack $ show (hash (encodeUtf8 s) :: SHA1.SHA1)
|
Text.pack $ show (hash (encodeUtf8 s) :: SHA1.SHA1)
|
||||||
#else
|
#else
|
||||||
decodeUtf8 $ Base16.encode $ SHA1.hash $ encodeUtf8 s
|
decodeUtf8 $ Base16.encode $ SHA1.hash $ encodeUtf8 s
|
||||||
#endif
|
#endif
|
||||||
"sha256" -> pure $
|
"sha256" -> f $ \s ->
|
||||||
#if MIN_VERSION_hashing(0, 1, 0)
|
#if MIN_VERSION_hashing(0, 1, 0)
|
||||||
Text.pack $ show (hash (encodeUtf8 s) :: SHA256.SHA256)
|
Text.pack $ show (hash (encodeUtf8 s) :: SHA256.SHA256)
|
||||||
#else
|
#else
|
||||||
decodeUtf8 $ Base16.encode $ SHA256.hash $ encodeUtf8 s
|
decodeUtf8 $ Base16.encode $ SHA256.hash $ encodeUtf8 s
|
||||||
#endif
|
#endif
|
||||||
"sha512" -> pure $
|
"sha512" -> f $ \s ->
|
||||||
#if MIN_VERSION_hashing(0, 1, 0)
|
#if MIN_VERSION_hashing(0, 1, 0)
|
||||||
Text.pack $ show (hash (encodeUtf8 s) :: SHA512.SHA512)
|
Text.pack $ show (hash (encodeUtf8 s) :: SHA512.SHA512)
|
||||||
#else
|
#else
|
||||||
|
@ -913,9 +947,12 @@ hashString algo s = Prim $ do
|
||||||
++ "expected \"md5\", \"sha1\", \"sha256\", or \"sha512\", got " ++ show algo
|
++ "expected \"md5\", \"sha1\", \"sha256\", or \"sha512\", got " ++ show algo
|
||||||
|
|
||||||
placeHolder :: MonadNix e m => m (NValue m) -> m (NValue m)
|
placeHolder :: MonadNix e m => m (NValue m) -> m (NValue m)
|
||||||
placeHolder = fromValue @Text >=> \_ -> do
|
placeHolder = fromValue >=> fromStringNoContext >=> \t -> do
|
||||||
h <- runPrim (hashString "sha256" "fdasdfas")
|
h <- runPrim (hashString (principledMakeNixStringWithoutContext "sha256")
|
||||||
toNix h
|
(principledMakeNixStringWithoutContext ("nix-output:" <> t)))
|
||||||
|
toNix $ principledMakeNixStringWithoutContext $ Text.cons '/' $ printHash32 $
|
||||||
|
-- The result coming out of hashString is base16 encoded
|
||||||
|
fst $ Base16.decode $ encodeUtf8 $ principledStringIgnoreContext h
|
||||||
|
|
||||||
absolutePathFromValue :: MonadNix e m => NValue m -> m FilePath
|
absolutePathFromValue :: MonadNix e m => NValue m -> m FilePath
|
||||||
absolutePathFromValue = \case
|
absolutePathFromValue = \case
|
||||||
|
@ -952,7 +989,7 @@ data FileType
|
||||||
deriving (Show, Read, Eq, Ord)
|
deriving (Show, Read, Eq, Ord)
|
||||||
|
|
||||||
instance Applicative m => ToNix FileType m (NValue m) where
|
instance Applicative m => ToNix FileType m (NValue m) where
|
||||||
toNix = toNix . \case
|
toNix = toNix . principledMakeNixStringWithoutContext . \case
|
||||||
FileTypeRegular -> "regular" :: Text
|
FileTypeRegular -> "regular" :: Text
|
||||||
FileTypeDirectory -> "directory"
|
FileTypeDirectory -> "directory"
|
||||||
FileTypeSymlink -> "symlink"
|
FileTypeSymlink -> "symlink"
|
||||||
|
@ -972,18 +1009,40 @@ readDir_ pathThunk = do
|
||||||
pure (Text.pack item, t)
|
pure (Text.pack item, t)
|
||||||
toNix (M.fromList itemsWithTypes)
|
toNix (M.fromList itemsWithTypes)
|
||||||
|
|
||||||
fromJSON :: MonadNix e m => m (NValue m) -> m (NValue m)
|
fromJSON :: forall e m. (MonadNix e m, Typeable m) => m (NValue m) -> m (NValue m)
|
||||||
fromJSON = fromValue >=> \encoded ->
|
fromJSON = fromValue >=> fromStringNoContext >=> \encoded ->
|
||||||
case A.eitherDecodeStrict' @A.Value $ encodeUtf8 encoded of
|
case A.eitherDecodeStrict' @A.Value $ encodeUtf8 encoded of
|
||||||
Left jsonError ->
|
Left jsonError ->
|
||||||
throwError $ ErrorCall $ "builtins.fromJSON: " ++ jsonError
|
throwError $ ErrorCall $ "builtins.fromJSON: " ++ jsonError
|
||||||
Right v -> toValue v
|
Right v -> jsonToNValue v
|
||||||
|
where
|
||||||
|
jsonToNValue = \case
|
||||||
|
A.Object m -> flip nvSet M.empty
|
||||||
|
<$> traverse (thunk . jsonToNValue) m
|
||||||
|
A.Array l -> nvList <$>
|
||||||
|
traverse (\x -> thunk . whileForcingThunk (CoercionFromJson @m x)
|
||||||
|
. jsonToNValue $ x) (V.toList l)
|
||||||
|
A.String s -> pure $ nvStr $ hackyMakeNixStringWithoutContext s
|
||||||
|
A.Number n -> pure $ nvConstant $ case floatingOrInteger n of
|
||||||
|
Left r -> NFloat r
|
||||||
|
Right i -> NInt i
|
||||||
|
A.Bool b -> pure $ nvConstant $ NBool b
|
||||||
|
A.Null -> pure $ nvConstant NNull
|
||||||
|
|
||||||
|
prim_toJSON
|
||||||
|
:: MonadNix e m
|
||||||
|
=> m (NValue m)
|
||||||
|
-> m (NValue m)
|
||||||
|
prim_toJSON x = do
|
||||||
|
(ctx, v) <- nvalueToJSON =<< x
|
||||||
|
let t = decodeUtf8 $ LBS.toStrict $ A.encodingToLazyByteString $ toEncodingSorted v
|
||||||
|
pure $ nvStr $ principledMakeNixString t ctx
|
||||||
|
|
||||||
toXML_ :: MonadNix e m => m (NValue m) -> m (NValue m)
|
toXML_ :: MonadNix e m => m (NValue m) -> m (NValue m)
|
||||||
toXML_ v = v >>= normalForm >>= pure . nvStr . toXML
|
toXML_ v = v >>= normalForm >>= pure . nvStr . toXML
|
||||||
|
|
||||||
typeOf :: MonadNix e m => m (NValue m) -> m (NValue m)
|
typeOf :: MonadNix e m => m (NValue m) -> m (NValue m)
|
||||||
typeOf v = v >>= toNix @Text . \case
|
typeOf v = v >>= toNix . principledMakeNixStringWithoutContext . \case
|
||||||
NVConstant a -> case a of
|
NVConstant a -> case a of
|
||||||
NInt _ -> "int"
|
NInt _ -> "int"
|
||||||
NFloat _ -> "float"
|
NFloat _ -> "float"
|
||||||
|
@ -1013,7 +1072,7 @@ tryEval e = catch (onSuccess <$> e) (pure . onError)
|
||||||
|
|
||||||
trace_ :: forall e m. MonadNix e m => m (NValue m) -> m (NValue m) -> m (NValue m)
|
trace_ :: forall e m. MonadNix e m => m (NValue m) -> m (NValue m) -> m (NValue m)
|
||||||
trace_ msg action = do
|
trace_ msg action = do
|
||||||
traceEffect . Text.unpack =<< fromValue @Text msg
|
traceEffect . Text.unpack . principledStringIgnoreContext =<< fromValue msg
|
||||||
action
|
action
|
||||||
|
|
||||||
-- TODO: remember error context
|
-- TODO: remember error context
|
||||||
|
@ -1023,8 +1082,11 @@ addErrorContext _ action = action
|
||||||
exec_ :: forall e m. MonadNix e m => m (NValue m) -> m (NValue m)
|
exec_ :: forall e m. MonadNix e m => m (NValue m) -> m (NValue m)
|
||||||
exec_ xs = do
|
exec_ xs = do
|
||||||
ls <- fromValue @[NThunk m] xs
|
ls <- fromValue @[NThunk m] xs
|
||||||
xs <- traverse (fromValue @Text . force') ls
|
xs <- traverse (coerceToString DontCopyToStore CoerceStringy <=< force') ls
|
||||||
exec (map Text.unpack xs)
|
-- TODO Still need to do something with the context here
|
||||||
|
-- See prim_exec in nix/src/libexpr/primops.cc
|
||||||
|
-- Requires the implementation of EvalState::realiseContext
|
||||||
|
exec (map (Text.unpack . hackyStringIgnoreContext) xs)
|
||||||
|
|
||||||
fetchurl :: forall e m. MonadNix e m => m (NValue m) -> m (NValue m)
|
fetchurl :: forall e m. MonadNix e m => m (NValue m) -> m (NValue m)
|
||||||
fetchurl v = v >>= \case
|
fetchurl v = v >>= \case
|
||||||
|
|
|
@ -27,27 +27,35 @@ module Nix.Convert where
|
||||||
|
|
||||||
import Control.Monad
|
import Control.Monad
|
||||||
import Control.Monad.Free
|
import Control.Monad.Free
|
||||||
import Data.Aeson (toJSON)
|
|
||||||
import qualified Data.Aeson as A
|
|
||||||
import Data.ByteString
|
import Data.ByteString
|
||||||
import Data.HashMap.Lazy (HashMap)
|
import Data.HashMap.Lazy (HashMap)
|
||||||
import qualified Data.HashMap.Lazy as M
|
import qualified Data.HashMap.Lazy as M
|
||||||
import Data.Scientific
|
|
||||||
import Data.Text (Text)
|
import Data.Text (Text)
|
||||||
import qualified Data.Text as Text
|
import qualified Data.Text as Text
|
||||||
import Data.Text.Encoding (encodeUtf8, decodeUtf8)
|
import Data.Text.Encoding (encodeUtf8, decodeUtf8)
|
||||||
import qualified Data.Vector as V
|
|
||||||
import Nix.Atoms
|
import Nix.Atoms
|
||||||
import Nix.Effects
|
import Nix.Effects
|
||||||
import Nix.Expr.Types
|
import Nix.Expr.Types
|
||||||
import Nix.Expr.Types.Annotated
|
import Nix.Expr.Types.Annotated
|
||||||
import Nix.Frames
|
import Nix.Frames
|
||||||
import Nix.String
|
import Nix.String
|
||||||
import Nix.Normal
|
|
||||||
import Nix.Thunk
|
import Nix.Thunk
|
||||||
import Nix.Utils
|
import Nix.Utils
|
||||||
import Nix.Value
|
import Nix.Value
|
||||||
|
|
||||||
|
{-
|
||||||
|
|
||||||
|
IMPORTANT NOTE
|
||||||
|
|
||||||
|
We used to have Text instances of FromValue, ToValue, FromNix, and ToNix.
|
||||||
|
However, we're removing these instances because they are dangerous due to the
|
||||||
|
fact that they hide the way string contexts are handled. It's better to have to
|
||||||
|
explicitly handle string context in a way that is appropriate for the situation.
|
||||||
|
|
||||||
|
Do not add these instances back!
|
||||||
|
|
||||||
|
-}
|
||||||
|
|
||||||
class FromValue a m v where
|
class FromValue a m v where
|
||||||
fromValue :: v -> m a
|
fromValue :: v -> m a
|
||||||
fromValueMay :: v -> m (Maybe a)
|
fromValueMay :: v -> m (Maybe a)
|
||||||
|
@ -145,32 +153,6 @@ instance Convertible e m
|
||||||
Just b -> pure b
|
Just b -> pure b
|
||||||
_ -> throwError $ Expectation TFloat v
|
_ -> throwError $ Expectation TFloat v
|
||||||
|
|
||||||
instance (Convertible e m, MonadEffects m)
|
|
||||||
=> FromValue Text m (NValueNF m) where
|
|
||||||
fromValueMay = \case
|
|
||||||
Free (NVStrF ns) -> pure $ hackyGetStringNoContext ns
|
|
||||||
Free (NVPathF p) -> Just . Text.pack . unStorePath <$> addPath p
|
|
||||||
Free (NVSetF s _) -> case M.lookup "outPath" s of
|
|
||||||
Nothing -> pure Nothing
|
|
||||||
Just p -> fromValueMay @Text p
|
|
||||||
_ -> pure Nothing
|
|
||||||
fromValue v = fromValueMay v >>= \case
|
|
||||||
Just b -> pure b
|
|
||||||
_ -> throwError $ ExpectationNF (TString NoContext) v
|
|
||||||
|
|
||||||
instance (Convertible e m, MonadThunk (NValue m) (NThunk m) m, MonadEffects m)
|
|
||||||
=> FromValue Text m (NValue m) where
|
|
||||||
fromValueMay = \case
|
|
||||||
NVStr ns -> pure $ hackyGetStringNoContext ns
|
|
||||||
NVPath p -> Just . Text.pack . unStorePath <$> addPath p
|
|
||||||
NVSet s _ -> case M.lookup "outPath" s of
|
|
||||||
Nothing -> pure Nothing
|
|
||||||
Just p -> fromValueMay @Text p
|
|
||||||
_ -> pure Nothing
|
|
||||||
fromValue v = fromValueMay v >>= \case
|
|
||||||
Just b -> pure b
|
|
||||||
_ -> throwError $ Expectation (TString NoContext) v
|
|
||||||
|
|
||||||
instance (Convertible e m, MonadEffects m)
|
instance (Convertible e m, MonadEffects m)
|
||||||
=> FromValue NixString m (NValueNF m) where
|
=> FromValue NixString m (NValueNF m) where
|
||||||
fromValueMay = \case
|
fromValueMay = \case
|
||||||
|
@ -178,7 +160,7 @@ instance (Convertible e m, MonadEffects m)
|
||||||
Free (NVPathF p) -> Just . hackyMakeNixStringWithoutContext . Text.pack . unStorePath <$> addPath p
|
Free (NVPathF p) -> Just . hackyMakeNixStringWithoutContext . Text.pack . unStorePath <$> addPath p
|
||||||
Free (NVSetF s _) -> case M.lookup "outPath" s of
|
Free (NVSetF s _) -> case M.lookup "outPath" s of
|
||||||
Nothing -> pure Nothing
|
Nothing -> pure Nothing
|
||||||
Just p -> fmap hackyMakeNixStringWithoutContext <$> fromValueMay @Text p
|
Just p -> fromValueMay p
|
||||||
_ -> pure Nothing
|
_ -> pure Nothing
|
||||||
fromValue v = fromValueMay v >>= \case
|
fromValue v = fromValueMay v >>= \case
|
||||||
Just b -> pure b
|
Just b -> pure b
|
||||||
|
@ -191,7 +173,7 @@ instance (Convertible e m, MonadThunk (NValue m) (NThunk m) m, MonadEffects m)
|
||||||
NVPath p -> Just . hackyMakeNixStringWithoutContext . Text.pack . unStorePath <$> addPath p
|
NVPath p -> Just . hackyMakeNixStringWithoutContext . Text.pack . unStorePath <$> addPath p
|
||||||
NVSet s _ -> case M.lookup "outPath" s of
|
NVSet s _ -> case M.lookup "outPath" s of
|
||||||
Nothing -> pure Nothing
|
Nothing -> pure Nothing
|
||||||
Just p -> fmap hackyMakeNixStringWithoutContext <$> fromValueMay @Text p
|
Just p -> fromValueMay p
|
||||||
_ -> pure Nothing
|
_ -> pure Nothing
|
||||||
fromValue v = fromValueMay v >>= \case
|
fromValue v = fromValueMay v >>= \case
|
||||||
Just b -> pure b
|
Just b -> pure b
|
||||||
|
@ -314,26 +296,6 @@ instance (MonadThunk (NValue m) (NThunk m) m, FromValue a m (NValue m))
|
||||||
fromValueMay = force ?? fromValueMay
|
fromValueMay = force ?? fromValueMay
|
||||||
fromValue = force ?? fromValue
|
fromValue = force ?? fromValue
|
||||||
|
|
||||||
instance (Convertible e m, MonadEffects m)
|
|
||||||
=> FromValue A.Value m (NValueNF m) where
|
|
||||||
fromValueMay = \case
|
|
||||||
Free (NVConstantF a) -> pure $ Just $ case a of
|
|
||||||
NInt n -> toJSON n
|
|
||||||
NFloat n -> toJSON n
|
|
||||||
NBool b -> toJSON b
|
|
||||||
NNull -> A.Null
|
|
||||||
Free (NVStrF ns) -> pure $ toJSON <$> hackyGetStringNoContext ns
|
|
||||||
Free (NVListF l) ->
|
|
||||||
fmap (A.Array . V.fromList) . sequence
|
|
||||||
<$> traverse fromValueMay l
|
|
||||||
Free (NVSetF m _) ->
|
|
||||||
fmap A.Object . sequence <$> traverse fromValueMay m
|
|
||||||
Free (NVPathF p) -> Just . toJSON . unStorePath <$> addPath p
|
|
||||||
_ -> pure Nothing
|
|
||||||
fromValue v = fromValueMay v >>= \case
|
|
||||||
Just b -> pure b
|
|
||||||
_ -> throwError $ CoercionToJsonNF v
|
|
||||||
|
|
||||||
class ToValue a m v where
|
class ToValue a m v where
|
||||||
toValue :: a -> m v
|
toValue :: a -> m v
|
||||||
|
|
||||||
|
@ -367,12 +329,6 @@ instance Applicative m => ToValue Float m (NValueNF m) where
|
||||||
instance Applicative m => ToValue Float m (NValue m) where
|
instance Applicative m => ToValue Float m (NValue m) where
|
||||||
toValue = pure . nvConstant . NFloat
|
toValue = pure . nvConstant . NFloat
|
||||||
|
|
||||||
instance Applicative m => ToValue Text m (NValueNF m) where
|
|
||||||
toValue = pure . Free . NVStrF . hackyMakeNixStringWithoutContext
|
|
||||||
|
|
||||||
instance Applicative m => ToValue Text m (NValue m) where
|
|
||||||
toValue = pure . nvStr . hackyMakeNixStringWithoutContext
|
|
||||||
|
|
||||||
instance Applicative m => ToValue NixString m (NValueNF m) where
|
instance Applicative m => ToValue NixString m (NValueNF m) where
|
||||||
toValue = pure . Free . NVStrF
|
toValue = pure . Free . NVStrF
|
||||||
|
|
||||||
|
@ -400,7 +356,7 @@ instance Applicative m => ToValue StorePath m (NValue m) where
|
||||||
instance MonadThunk (NValue m) (NThunk m) m
|
instance MonadThunk (NValue m) (NThunk m) m
|
||||||
=> ToValue SourcePos m (NValue m) where
|
=> ToValue SourcePos m (NValue m) where
|
||||||
toValue (SourcePos f l c) = do
|
toValue (SourcePos f l c) = do
|
||||||
f' <- toValue (Text.pack f)
|
f' <- pure $ nvStr $ principledMakeNixStringWithoutContext (Text.pack f)
|
||||||
l' <- toValue (unPos l)
|
l' <- toValue (unPos l)
|
||||||
c' <- toValue (unPos c)
|
c' <- toValue (unPos c)
|
||||||
let pos = M.fromList
|
let pos = M.fromList
|
||||||
|
@ -446,21 +402,6 @@ whileForcingThunk :: forall s e m r. (Framed e m, Exception s, Typeable m)
|
||||||
whileForcingThunk frame =
|
whileForcingThunk frame =
|
||||||
withFrame Debug (ForcingThunk @m) . withFrame Debug frame
|
withFrame Debug (ForcingThunk @m) . withFrame Debug frame
|
||||||
|
|
||||||
instance (Convertible e m, MonadThunk (NValue m) (NThunk m) m)
|
|
||||||
=> ToValue A.Value m (NValue m) where
|
|
||||||
toValue = \case
|
|
||||||
A.Object m -> flip nvSet M.empty
|
|
||||||
<$> traverse (thunk . toValue @_ @_ @(NValue m)) m
|
|
||||||
A.Array l -> nvList <$>
|
|
||||||
traverse (\x -> thunk . whileForcingThunk (CoercionFromJson @m x)
|
|
||||||
. toValue $ x) (V.toList l)
|
|
||||||
A.String s -> pure $ nvStr $ hackyMakeNixStringWithoutContext s
|
|
||||||
A.Number n -> pure $ nvConstant $ case floatingOrInteger n of
|
|
||||||
Left r -> NFloat r
|
|
||||||
Right i -> NInt i
|
|
||||||
A.Bool b -> pure $ nvConstant $ NBool b
|
|
||||||
A.Null -> pure $ nvConstant NNull
|
|
||||||
|
|
||||||
class FromNix a m v where
|
class FromNix a m v where
|
||||||
fromNix :: v -> m a
|
fromNix :: v -> m a
|
||||||
default fromNix :: FromValue a m v => v -> m a
|
default fromNix :: FromValue a m v => v -> m a
|
||||||
|
@ -500,8 +441,6 @@ instance Convertible e m => FromNix Integer m (NValueNF m) where
|
||||||
instance Convertible e m => FromNix Integer m (NValue m) where
|
instance Convertible e m => FromNix Integer m (NValue m) where
|
||||||
instance Convertible e m => FromNix Float m (NValueNF m) where
|
instance Convertible e m => FromNix Float m (NValueNF m) where
|
||||||
instance Convertible e m => FromNix Float m (NValue m) where
|
instance Convertible e m => FromNix Float m (NValue m) where
|
||||||
instance (Convertible e m, MonadEffects m) => FromNix Text m (NValueNF m) where
|
|
||||||
instance (Convertible e m, MonadEffects m, MonadThunk (NValue m) (NThunk m) m) => FromNix Text m (NValue m) where
|
|
||||||
instance (Convertible e m, MonadEffects m) => FromNix NixString m (NValueNF m) where
|
instance (Convertible e m, MonadEffects m) => FromNix NixString m (NValueNF m) where
|
||||||
instance (Convertible e m, MonadEffects m, MonadThunk (NValue m) (NThunk m) m) => FromNix NixString m (NValue m) where
|
instance (Convertible e m, MonadEffects m, MonadThunk (NValue m) (NThunk m) m) => FromNix NixString m (NValue m) where
|
||||||
instance Convertible e m => FromNix ByteString m (NValueNF m) where
|
instance Convertible e m => FromNix ByteString m (NValueNF m) where
|
||||||
|
@ -512,13 +451,6 @@ instance (Convertible e m, FromValue a m (NValueNF m), Show a) => FromNix [a] m
|
||||||
instance Convertible e m => FromNix (HashMap Text (NValueNF m)) m (NValueNF m) where
|
instance Convertible e m => FromNix (HashMap Text (NValueNF m)) m (NValueNF m) where
|
||||||
instance Convertible e m => FromNix (HashMap Text (NValueNF m), HashMap Text SourcePos) m (NValueNF m) where
|
instance Convertible e m => FromNix (HashMap Text (NValueNF m), HashMap Text SourcePos) m (NValueNF m) where
|
||||||
instance Convertible e m => FromNix (HashMap Text (NThunk m), HashMap Text SourcePos) m (NValue m) where
|
instance Convertible e m => FromNix (HashMap Text (NThunk m), HashMap Text SourcePos) m (NValue m) where
|
||||||
instance (Convertible e m, MonadEffects m, MonadThunk (NValue m) (NThunk m) m) => FromNix A.Value m (NValueNF m) where
|
|
||||||
|
|
||||||
instance (Convertible e m, MonadEffects m,
|
|
||||||
MonadThunk (NValue m) (NThunk m) m)
|
|
||||||
=> FromNix A.Value m (NValue m) where
|
|
||||||
fromNixMay = fromNixMay <=< normalForm
|
|
||||||
fromNix = fromNix <=< normalForm
|
|
||||||
|
|
||||||
instance (Monad m, FromNix a m v) => FromNix a m (m v) where
|
instance (Monad m, FromNix a m v) => FromNix a m (m v) where
|
||||||
fromNixMay = (>>= fromNixMay)
|
fromNixMay = (>>= fromNixMay)
|
||||||
|
@ -563,8 +495,6 @@ instance Applicative m => ToNix Integer m (NValueNF m) where
|
||||||
instance Applicative m => ToNix Integer m (NValue m) where
|
instance Applicative m => ToNix Integer m (NValue m) where
|
||||||
instance Applicative m => ToNix Float m (NValueNF m) where
|
instance Applicative m => ToNix Float m (NValueNF m) where
|
||||||
instance Applicative m => ToNix Float m (NValue m) where
|
instance Applicative m => ToNix Float m (NValue m) where
|
||||||
instance Applicative m => ToNix Text m (NValueNF m) where
|
|
||||||
instance Applicative m => ToNix Text m (NValue m) where
|
|
||||||
instance Applicative m => ToNix NixString m (NValueNF m) where
|
instance Applicative m => ToNix NixString m (NValueNF m) where
|
||||||
instance Applicative m => ToNix NixString m (NValue m) where
|
instance Applicative m => ToNix NixString m (NValue m) where
|
||||||
instance Applicative m => ToNix ByteString m (NValueNF m) where
|
instance Applicative m => ToNix ByteString m (NValueNF m) where
|
||||||
|
@ -574,7 +504,6 @@ instance Applicative m => ToNix Path m (NValue m) where
|
||||||
instance Applicative m => ToNix (HashMap Text (NValueNF m)) m (NValueNF m) where
|
instance Applicative m => ToNix (HashMap Text (NValueNF m)) m (NValueNF m) where
|
||||||
instance Applicative m => ToNix (HashMap Text (NValueNF m), HashMap Text SourcePos) m (NValueNF m) where
|
instance Applicative m => ToNix (HashMap Text (NValueNF m), HashMap Text SourcePos) m (NValueNF m) where
|
||||||
instance Applicative m => ToNix (HashMap Text (NThunk m), HashMap Text SourcePos) m (NValue m) where
|
instance Applicative m => ToNix (HashMap Text (NThunk m), HashMap Text SourcePos) m (NValue m) where
|
||||||
instance (Convertible e m, MonadThunk (NValue m) (NThunk m) m) => ToNix A.Value m (NValue m) where
|
|
||||||
instance Applicative m => ToNix Bool m (NExprF r) where
|
instance Applicative m => ToNix Bool m (NExprF r) where
|
||||||
instance Applicative m => ToNix () m (NExprF r) where
|
instance Applicative m => ToNix () m (NExprF r) where
|
||||||
|
|
||||||
|
|
|
@ -394,8 +394,8 @@ execBinaryOp scope span op lval rarg = do
|
||||||
_ -> nverr $ ErrorCall $ unsupportedTypes lval rval
|
_ -> nverr $ ErrorCall $ unsupportedTypes lval rval
|
||||||
|
|
||||||
(NVPath p, NVStr ns) -> case op of
|
(NVPath p, NVStr ns) -> case op of
|
||||||
NEq -> toBool $ Just p == fmap Text.unpack (hackyGetStringNoContext ns)
|
NEq -> toBool False -- From eqValues in nix/src/libexpr/eval.cc
|
||||||
NNEq -> toBool $ Just p /= fmap Text.unpack (hackyGetStringNoContext ns)
|
NNEq -> toBool True
|
||||||
NPlus -> bin nvPathP <$> makeAbsolutePath (p `mappend` Text.unpack (hackyStringIgnoreContext ns))
|
NPlus -> bin nvPathP <$> makeAbsolutePath (p `mappend` Text.unpack (hackyStringIgnoreContext ns))
|
||||||
_ -> nverr $ ErrorCall $ unsupportedTypes lval rval
|
_ -> nverr $ ErrorCall $ unsupportedTypes lval rval
|
||||||
|
|
||||||
|
@ -478,9 +478,9 @@ coerceToString ctsm clevel = go
|
||||||
where
|
where
|
||||||
t = Text.pack $ unStorePath sp
|
t = Text.pack $ unStorePath sp
|
||||||
|
|
||||||
fromStringNoContext :: MonadNix e m => m (NValue m) -> m Text
|
fromStringNoContext :: MonadNix e m => NixString -> m Text
|
||||||
fromStringNoContext =
|
fromStringNoContext ns =
|
||||||
fromValue >=> \s -> case principledGetStringNoContext s of
|
case principledGetStringNoContext ns of
|
||||||
Just str -> return str
|
Just str -> return str
|
||||||
Nothing -> throwError $ ErrorCall
|
Nothing -> throwError $ ErrorCall
|
||||||
"expected string with no context"
|
"expected string with no context"
|
||||||
|
@ -591,10 +591,13 @@ instance (MonadFix m, MonadCatch m, MonadFile m, MonadStore m, MonadVar m,
|
||||||
mapMaybeM op = foldr f (return [])
|
mapMaybeM op = foldr f (return [])
|
||||||
where f x xs = op x >>= (<$> xs) . (++) . maybeToList
|
where f x xs = op x >>= (<$> xs) . (++) . maybeToList
|
||||||
|
|
||||||
|
--handleEntry :: Bool -> (Text, NThunk (Lazy m)) -> Lazy m (Maybe (Text, NThunk (Lazy m)))
|
||||||
handleEntry ignoreNulls (k, v) = fmap (k,) <$> case k of
|
handleEntry ignoreNulls (k, v) = fmap (k,) <$> case k of
|
||||||
-- The `args' attribute is special: it supplies the command-line
|
-- The `args' attribute is special: it supplies the command-line
|
||||||
-- arguments to the builder.
|
-- arguments to the builder.
|
||||||
"args" -> Just <$> convertNix @[Text] v
|
-- TODO This use of coerceToString is probably not right and may
|
||||||
|
-- not have the right arguments.
|
||||||
|
"args" -> force v (\v2 -> Just <$> coerceNix v2)
|
||||||
"__ignoreNulls" -> pure Nothing
|
"__ignoreNulls" -> pure Nothing
|
||||||
_ -> force v $ \case
|
_ -> force v $ \case
|
||||||
NVConstant NNull | ignoreNulls -> pure Nothing
|
NVConstant NNull | ignoreNulls -> pure Nothing
|
||||||
|
@ -662,8 +665,11 @@ findPathBy finder l name = do
|
||||||
case M.lookup "prefix" s of
|
case M.lookup "prefix" s of
|
||||||
Nothing -> tryPath path Nothing
|
Nothing -> tryPath path Nothing
|
||||||
Just pf -> force pf $ fromValueMay >=> \case
|
Just pf -> force pf $ fromValueMay >=> \case
|
||||||
Just (pfx :: Text) | not (Text.null pfx) ->
|
Just (nsPfx :: NixString) ->
|
||||||
tryPath path (Just (Text.unpack pfx))
|
let pfx = hackyStringIgnoreContext nsPfx
|
||||||
|
in if not (Text.null pfx)
|
||||||
|
then tryPath path (Just (Text.unpack pfx))
|
||||||
|
else tryPath path Nothing
|
||||||
_ -> tryPath path Nothing
|
_ -> tryPath path Nothing
|
||||||
|
|
||||||
tryPath p (Just n) | n':ns <- splitDirectories name, n == n' =
|
tryPath p (Just n) | n':ns <- splitDirectories name, n == n' =
|
||||||
|
@ -778,10 +784,11 @@ fetchTarball v = v >>= \case
|
||||||
fetch uri Nothing =
|
fetch uri Nothing =
|
||||||
nixInstantiateExpr $ "builtins.fetchTarball \"" ++
|
nixInstantiateExpr $ "builtins.fetchTarball \"" ++
|
||||||
Text.unpack uri ++ "\""
|
Text.unpack uri ++ "\""
|
||||||
fetch url (Just m) = fromValue m >>= \sha ->
|
fetch url (Just m) = fromValue m >>= \nsSha ->
|
||||||
nixInstantiateExpr $ "builtins.fetchTarball { "
|
let sha = hackyStringIgnoreContext nsSha
|
||||||
++ "url = \"" ++ Text.unpack url ++ "\"; "
|
in nixInstantiateExpr $ "builtins.fetchTarball { "
|
||||||
++ "sha256 = \"" ++ Text.unpack sha ++ "\"; }"
|
++ "url = \"" ++ Text.unpack url ++ "\"; "
|
||||||
|
++ "sha256 = \"" ++ Text.unpack sha ++ "\"; }"
|
||||||
|
|
||||||
exec :: (MonadExec m, Framed e m, MonadThrow m, Alternative m, MonadCatch m, MonadFix m, MonadEffects m, GEq (Ref m), MonadAtomicRef m, Typeable m, Has e Options, Has e SrcSpan, Scoped (NThunk m) m) => [String] -> m (NValue m)
|
exec :: (MonadExec m, Framed e m, MonadThrow m, Alternative m, MonadCatch m, MonadFix m, MonadEffects m, GEq (Ref m), MonadAtomicRef m, Typeable m, Has e Options, Has e SrcSpan, Scoped (NThunk m) m) => [String] -> m (NValue m)
|
||||||
exec args = either throwError evalExprLoc =<< exec' args
|
exec args = either throwError evalExprLoc =<< exec' args
|
||||||
|
|
38
src/Nix/Json.hs
Normal file
38
src/Nix/Json.hs
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
{-# LANGUAGE FlexibleContexts #-}
|
||||||
|
|
||||||
|
module Nix.Json where
|
||||||
|
|
||||||
|
import qualified Data.Aeson as A
|
||||||
|
import qualified Data.HashSet as HS
|
||||||
|
import qualified Data.Text as Text
|
||||||
|
import qualified Data.Vector as V
|
||||||
|
import Nix.Atoms
|
||||||
|
import Nix.Effects
|
||||||
|
import Nix.Exec
|
||||||
|
import Nix.Frames
|
||||||
|
import Nix.String
|
||||||
|
import Nix.Thunk
|
||||||
|
import Nix.Value
|
||||||
|
|
||||||
|
nvalueToJSON
|
||||||
|
:: MonadNix e m
|
||||||
|
=> NValue m
|
||||||
|
-> m (HS.HashSet StringContext, A.Value)
|
||||||
|
nvalueToJSON v = case v of
|
||||||
|
NVConstant a -> retEmpty $ case a of
|
||||||
|
NInt n -> A.toJSON n
|
||||||
|
NFloat n -> A.toJSON n
|
||||||
|
NBool b -> A.toJSON b
|
||||||
|
NNull -> A.Null
|
||||||
|
NVStr ns -> pure (principledGetContext ns, A.toJSON $ principledStringIgnoreContext ns)
|
||||||
|
NVList l -> do
|
||||||
|
(ctxs, vals) <- unzip <$> traverse (`force` nvalueToJSON) l
|
||||||
|
return (HS.unions ctxs, A.Array $ V.fromList vals)
|
||||||
|
NVSet m _ ->
|
||||||
|
fmap A.Object . sequence <$> traverse (`force` nvalueToJSON) m
|
||||||
|
NVPath p -> do
|
||||||
|
fp <- unStorePath <$> addPath p
|
||||||
|
return (HS.singleton $ StringContext (Text.pack fp) DirectPath, A.toJSON fp)
|
||||||
|
_ -> throwError $ CoercionToJson v
|
||||||
|
where
|
||||||
|
retEmpty a = pure (mempty, a)
|
|
@ -153,7 +153,9 @@ renderValueFrame level = fmap (:[]) . \case
|
||||||
desc | level <= Error = "Cannot coerce "
|
desc | level <= Error = "Cannot coerce "
|
||||||
| otherwise = "While coercing "
|
| otherwise = "While coercing "
|
||||||
|
|
||||||
CoercionToJsonNF _v -> pure "CoercionToJsonNF"
|
CoercionToJson v -> do
|
||||||
|
v' <- renderValue level "" "" v
|
||||||
|
pure $ "CoercionToJson " <> v'
|
||||||
CoercionFromJson _j -> pure "CoercionFromJson"
|
CoercionFromJson _j -> pure "CoercionFromJson"
|
||||||
ExpectationNF _t _v -> pure "ExpectationNF"
|
ExpectationNF _t _v -> pure "ExpectationNF"
|
||||||
Expectation t v -> do
|
Expectation t v -> do
|
||||||
|
|
|
@ -4,6 +4,8 @@
|
||||||
{-# OPTIONS_GHC -Wno-unused-top-binds #-}
|
{-# OPTIONS_GHC -Wno-unused-top-binds #-}
|
||||||
module Nix.String (
|
module Nix.String (
|
||||||
NixString
|
NixString
|
||||||
|
, principledGetContext
|
||||||
|
, principledMakeNixString
|
||||||
, principledMempty
|
, principledMempty
|
||||||
, StringContext(..)
|
, StringContext(..)
|
||||||
, ContextFlavor(..)
|
, ContextFlavor(..)
|
||||||
|
@ -57,6 +59,9 @@ data NixString = NixString
|
||||||
|
|
||||||
instance Hashable NixString
|
instance Hashable NixString
|
||||||
|
|
||||||
|
principledGetContext :: NixString -> S.HashSet StringContext
|
||||||
|
principledGetContext = nsContext
|
||||||
|
|
||||||
-- | Combine two NixStrings using mappend
|
-- | Combine two NixStrings using mappend
|
||||||
principledMempty :: NixString
|
principledMempty :: NixString
|
||||||
principledMempty = NixString "" mempty
|
principledMempty = NixString "" mempty
|
||||||
|
@ -111,7 +116,7 @@ principledGetStringNoContext (NixString s c) | null c = Just s
|
||||||
principledStringIgnoreContext :: NixString -> Text
|
principledStringIgnoreContext :: NixString -> Text
|
||||||
principledStringIgnoreContext (NixString s _) = s
|
principledStringIgnoreContext (NixString s _) = s
|
||||||
|
|
||||||
-- | Extract the string contents from a NixString even if the NixString has an associated context
|
-- | Extract the string contents from a NixString even if the NixString has an associated context
|
||||||
hackyStringIgnoreContext :: NixString -> Text
|
hackyStringIgnoreContext :: NixString -> Text
|
||||||
hackyStringIgnoreContext (NixString s _) = s
|
hackyStringIgnoreContext (NixString s _) = s
|
||||||
|
|
||||||
|
@ -127,7 +132,7 @@ hackyMakeNixStringWithoutContext = flip NixString mempty
|
||||||
principledMakeNixStringWithoutContext :: Text -> NixString
|
principledMakeNixStringWithoutContext :: Text -> NixString
|
||||||
principledMakeNixStringWithoutContext = flip NixString mempty
|
principledMakeNixStringWithoutContext = flip NixString mempty
|
||||||
|
|
||||||
-- | Modify the string part of the NixString -- ignores the context
|
-- | Modify the string part of the NixString, leaving the context unchanged
|
||||||
principledModifyNixContents :: (Text -> Text) -> NixString -> NixString
|
principledModifyNixContents :: (Text -> Text) -> NixString -> NixString
|
||||||
principledModifyNixContents f (NixString s c) = NixString (f s) c
|
principledModifyNixContents f (NixString s c) = NixString (f s) c
|
||||||
|
|
||||||
|
@ -135,6 +140,10 @@ principledModifyNixContents f (NixString s c) = NixString (f s) c
|
||||||
principledMakeNixStringWithSingletonContext :: Text -> StringContext -> NixString
|
principledMakeNixStringWithSingletonContext :: Text -> StringContext -> NixString
|
||||||
principledMakeNixStringWithSingletonContext s c = NixString s (S.singleton c)
|
principledMakeNixStringWithSingletonContext s c = NixString s (S.singleton c)
|
||||||
|
|
||||||
|
-- | Create a NixString from a Text and context
|
||||||
|
principledMakeNixString :: Text -> S.HashSet StringContext -> NixString
|
||||||
|
principledMakeNixString s c = NixString s c
|
||||||
|
|
||||||
-- | A monad for accumulating string context while producing a result string.
|
-- | A monad for accumulating string context while producing a result string.
|
||||||
newtype WithStringContext a = WithStringContext (Writer (S.HashSet StringContext) a)
|
newtype WithStringContext a = WithStringContext (Writer (S.HashSet StringContext) a)
|
||||||
deriving (Functor, Applicative, Monad, MonadWriter (S.HashSet StringContext))
|
deriving (Functor, Applicative, Monad, MonadWriter (S.HashSet StringContext))
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
{-# LANGUAGE FlexibleInstances #-}
|
{-# LANGUAGE FlexibleInstances #-}
|
||||||
{-# LANGUAGE LambdaCase #-}
|
{-# LANGUAGE LambdaCase #-}
|
||||||
{-# LANGUAGE MultiParamTypeClasses #-}
|
{-# LANGUAGE MultiParamTypeClasses #-}
|
||||||
|
{-# LANGUAGE OverloadedStrings #-}
|
||||||
{-# LANGUAGE RankNTypes #-}
|
{-# LANGUAGE RankNTypes #-}
|
||||||
{-# LANGUAGE ScopedTypeVariables #-}
|
{-# LANGUAGE ScopedTypeVariables #-}
|
||||||
{-# LANGUAGE TupleSections #-}
|
{-# LANGUAGE TupleSections #-}
|
||||||
|
@ -13,6 +14,9 @@ import Control.Monad
|
||||||
import Control.Monad.Fix
|
import Control.Monad.Fix
|
||||||
import qualified Data.Aeson as A
|
import qualified Data.Aeson as A
|
||||||
import qualified Data.Aeson.Encoding as A
|
import qualified Data.Aeson.Encoding as A
|
||||||
|
import Data.Bits
|
||||||
|
import Data.ByteString (ByteString)
|
||||||
|
import qualified Data.ByteString as B
|
||||||
import Data.Fix
|
import Data.Fix
|
||||||
import Data.HashMap.Lazy (HashMap)
|
import Data.HashMap.Lazy (HashMap)
|
||||||
import qualified Data.HashMap.Lazy as M
|
import qualified Data.HashMap.Lazy as M
|
||||||
|
@ -123,3 +127,26 @@ uriAwareSplit = go where
|
||||||
let ((suffix, _):path) = go (Text.drop 3 e2)
|
let ((suffix, _):path) = go (Text.drop 3 e2)
|
||||||
in (e1 <> Text.pack "://" <> suffix, PathEntryURI) : path
|
in (e1 <> Text.pack "://" <> suffix, PathEntryURI) : path
|
||||||
| otherwise -> (e1, PathEntryPath) : go (Text.drop 1 e2)
|
| otherwise -> (e1, PathEntryPath) : go (Text.drop 1 e2)
|
||||||
|
|
||||||
|
printHash32 :: ByteString -> Text
|
||||||
|
printHash32 bs = go (base32Len bs - 1) ""
|
||||||
|
where
|
||||||
|
go n s
|
||||||
|
| n >= 0 = go (n-1) (Text.snoc s $ nextCharHash32 bs n)
|
||||||
|
| otherwise = s
|
||||||
|
|
||||||
|
nextCharHash32 :: ByteString -> Int -> Char
|
||||||
|
nextCharHash32 bs n = Text.index base32Chars (c .&. 0x1f)
|
||||||
|
where
|
||||||
|
b = n * 5
|
||||||
|
i = b `div` 8
|
||||||
|
j = b `mod` 8
|
||||||
|
c = fromIntegral $ shiftR (B.index bs i) j .|. mask
|
||||||
|
mask = if i >= B.length bs - 1
|
||||||
|
then 0
|
||||||
|
else shiftL (B.index bs (i+1)) (8 - j)
|
||||||
|
-- e, o, u, and t are omitted (see base32Chars in nix/src/libutil/hash.cc)
|
||||||
|
base32Chars = "0123456789abcdfghijklmnpqrsvwxyz"
|
||||||
|
|
||||||
|
base32Len :: ByteString -> Int
|
||||||
|
base32Len bs = ((B.length bs * 8 - 1) `div` 5) + 1
|
||||||
|
|
|
@ -260,8 +260,6 @@ valueEq :: MonadThunk (NValue m) (NThunk m) m
|
||||||
valueEq = curry $ \case
|
valueEq = curry $ \case
|
||||||
(NVConstant lc, NVConstant rc) -> pure $ lc == rc
|
(NVConstant lc, NVConstant rc) -> pure $ lc == rc
|
||||||
(NVStr ls, NVStr rs) -> pure $ principledStringIgnoreContext ls == principledStringIgnoreContext rs
|
(NVStr ls, NVStr rs) -> pure $ principledStringIgnoreContext ls == principledStringIgnoreContext rs
|
||||||
(NVStr ns, NVConstant NNull) -> pure (hackyGetStringNoContext ns == Just "")
|
|
||||||
(NVConstant NNull, NVStr ns) -> pure (Just "" == hackyGetStringNoContext ns)
|
|
||||||
(NVList ls, NVList rs) -> alignEqM thunkEq ls rs
|
(NVList ls, NVList rs) -> alignEqM thunkEq ls rs
|
||||||
(NVSet lm _, NVSet rm _) -> do
|
(NVSet lm _, NVSet rm _) -> do
|
||||||
let compareAttrs = alignEqM thunkEq lm rm
|
let compareAttrs = alignEqM thunkEq lm rm
|
||||||
|
@ -357,7 +355,7 @@ data ValueFrame m
|
||||||
| Multiplication (NValue m) (NValue m)
|
| Multiplication (NValue m) (NValue m)
|
||||||
| Division (NValue m) (NValue m)
|
| Division (NValue m) (NValue m)
|
||||||
| Coercion ValueType ValueType
|
| Coercion ValueType ValueType
|
||||||
| CoercionToJsonNF (NValueNF m)
|
| CoercionToJson (NValue m)
|
||||||
| CoercionFromJson A.Value
|
| CoercionFromJson A.Value
|
||||||
| ExpectationNF ValueType (NValueNF m)
|
| ExpectationNF ValueType (NValueNF m)
|
||||||
| Expectation ValueType (NValue m)
|
| Expectation ValueType (NValue m)
|
||||||
|
|
18
tests/eval-compare/builtins.replaceStrings-01.nix
Normal file
18
tests/eval-compare/builtins.replaceStrings-01.nix
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
with builtins;
|
||||||
|
|
||||||
|
let a1 = toFile "foo" "foo contents"; # /nix/store/pqwdc5m06lxl8gmzcd26ifwsdhq9fj7k-foo
|
||||||
|
a2 = toFile "bar" "bar contents"; # /nix/store/4q6kxj1ym13yfp1bcdrzrwa1la6dqgp5-bar
|
||||||
|
b = dirOf a1;
|
||||||
|
c = substring 3 1 b;
|
||||||
|
d = replaceStrings ["b"] [c] "abc";
|
||||||
|
e = replaceStrings ["k"] [c] "abc";
|
||||||
|
f = replaceStrings ["y"] [c] (dirOf a2);
|
||||||
|
g = replaceStrings ["s"] [c] (dirOf a2);
|
||||||
|
h = replaceStrings ["y"] ["z"] "abc";
|
||||||
|
in [ b c d e f g h # TODO Add a1 here when we have correct store hashing working
|
||||||
|
(hasContext d)
|
||||||
|
(hasContext e)
|
||||||
|
(hasContext f)
|
||||||
|
(hasContext g)
|
||||||
|
(hasContext h)
|
||||||
|
]
|
8
tests/eval-compare/builtins.toJSON.nix
Normal file
8
tests/eval-compare/builtins.toJSON.nix
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
with builtins;
|
||||||
|
|
||||||
|
let f = toFile "foo" "foo contents"; # /nix/store/pqwdc5m06lxl8gmzcd26ifwsdhq9fj7k-foo
|
||||||
|
objA = { a = 15; b = substring 1 3 (dirOf f); };
|
||||||
|
objB = { a = 42; b = "hello"; };
|
||||||
|
in [ (hasContext (toJSON objA))
|
||||||
|
(hasContext (toJSON objB))
|
||||||
|
]
|
1
tests/eval-compare/paths-01.nix
Normal file
1
tests/eval-compare/paths-01.nix
Normal file
|
@ -0,0 +1 @@
|
||||||
|
baseNameOf foo/bar
|
1
tests/eval-compare/placeholder.nix
Normal file
1
tests/eval-compare/placeholder.nix
Normal file
|
@ -0,0 +1 @@
|
||||||
|
builtins.placeholder "foo"
|
Loading…
Reference in a new issue